2012-03-31 22:39:43 +00:00
< ? php
/*
* This file is part of Composer .
*
* ( c ) Nils Adermann < naderman @ naderman . de >
* Jordi Boggiano < j . boggiano @ seld . be >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Composer\Command ;
use Symfony\Component\Console\Input\InputInterface ;
use Symfony\Component\Console\Input\InputArgument ;
use Symfony\Component\Console\Input\InputOption ;
use Symfony\Component\Console\Output\OutputInterface ;
2012-05-26 12:45:19 +00:00
use Composer\Factory ;
2012-05-26 13:17:52 +00:00
use Composer\Installer ;
2012-03-31 22:39:43 +00:00
use Composer\Json\JsonFile ;
2012-05-26 12:45:19 +00:00
use Composer\Json\JsonManipulator ;
2013-08-26 11:29:47 +00:00
use Composer\Package\Version\VersionParser ;
2013-09-05 12:30:03 +00:00
use Composer\Plugin\CommandEvent ;
use Composer\Plugin\PluginEvents ;
2012-03-31 22:39:43 +00:00
/**
* @ author Jérémy Romey < jeremy @ free - agent . fr >
2012-05-26 12:45:19 +00:00
* @ author Jordi Boggiano < j . boggiano @ seld . be >
2012-03-31 22:39:43 +00:00
*/
class RequireCommand extends InitCommand
{
protected function configure ()
{
$this
-> setName ( 'require' )
2012-05-26 13:17:52 +00:00
-> setDescription ( 'Adds required packages to your composer.json and installs them' )
2012-03-31 22:39:43 +00:00
-> setDefinition ( array (
2012-05-26 12:45:19 +00:00
new InputArgument ( 'packages' , InputArgument :: IS_ARRAY | InputArgument :: OPTIONAL , 'Required package with a version constraint, e.g. foo/bar:1.0.0 or foo/bar=1.0.0 or "foo/bar 1.0.0"' ),
new InputOption ( 'dev' , null , InputOption :: VALUE_NONE , 'Add requirement to require-dev.' ),
2012-05-26 13:17:52 +00:00
new InputOption ( 'prefer-source' , null , InputOption :: VALUE_NONE , 'Forces installation from package sources when possible, including VCS information.' ),
2012-10-02 11:42:07 +00:00
new InputOption ( 'prefer-dist' , null , InputOption :: VALUE_NONE , 'Forces installation from package dist even for dev versions.' ),
2012-12-11 14:30:09 +00:00
new InputOption ( 'no-progress' , null , InputOption :: VALUE_NONE , 'Do not output download progress.' ),
2012-07-19 15:17:08 +00:00
new InputOption ( 'no-update' , null , InputOption :: VALUE_NONE , 'Disables the automatic update of the dependencies.' ),
2014-02-10 20:24:46 +00:00
new InputOption ( 'update-with-dependencies' , null , InputOption :: VALUE_NONE , 'Allows inherited dependencies to be updated with explicit dependencies.' ),
2012-03-31 22:39:43 +00:00
))
-> setHelp ( <<< EOT
2012-05-26 13:17:52 +00:00
The require command adds required packages to your composer . json and installs them
2012-03-31 22:39:43 +00:00
2012-07-19 15:17:08 +00:00
If you do not want to install the new dependencies immediately you can call it with -- no - update
2012-03-31 22:39:43 +00:00
EOT
)
;
}
protected function execute ( InputInterface $input , OutputInterface $output )
{
2012-12-03 00:24:39 +00:00
$file = Factory :: getComposerFile ();
2012-03-31 22:39:43 +00:00
2013-01-13 15:02:50 +00:00
if ( ! file_exists ( $file ) && ! file_put_contents ( $file , " { \n } \n " )) {
2013-01-13 14:57:03 +00:00
$output -> writeln ( '<error>' . $file . ' could not be created.</error>' );
2012-05-28 14:38:52 +00:00
2012-03-31 22:39:43 +00:00
return 1 ;
}
if ( ! is_readable ( $file )) {
$output -> writeln ( '<error>' . $file . ' is not readable.</error>' );
2012-05-28 14:38:52 +00:00
2012-03-31 22:39:43 +00:00
return 1 ;
}
2013-02-02 09:49:32 +00:00
if ( ! is_writable ( $file )) {
$output -> writeln ( '<error>' . $file . ' is not writable.</error>' );
return 1 ;
}
2012-03-31 22:39:43 +00:00
2012-05-26 12:45:19 +00:00
$json = new JsonFile ( $file );
$composer = $json -> read ();
2013-02-01 09:24:05 +00:00
$composerBackup = file_get_contents ( $json -> getPath ());
2012-03-31 22:39:43 +00:00
2012-05-26 12:45:19 +00:00
$requirements = $this -> determineRequirements ( $input , $output , $input -> getArgument ( 'packages' ));
2012-03-31 22:39:43 +00:00
2012-05-26 12:45:19 +00:00
$requireKey = $input -> getOption ( 'dev' ) ? 'require-dev' : 'require' ;
$baseRequirements = array_key_exists ( $requireKey , $composer ) ? $composer [ $requireKey ] : array ();
2012-05-27 21:21:10 +00:00
$requirements = $this -> formatRequirements ( $requirements );
2012-03-31 22:39:43 +00:00
2013-08-26 11:29:47 +00:00
// validate requirements format
$versionParser = new VersionParser ();
foreach ( $requirements as $constraint ) {
$versionParser -> parseConstraints ( $constraint );
}
2012-05-26 12:45:19 +00:00
if ( ! $this -> updateFileCleanly ( $json , $baseRequirements , $requirements , $requireKey )) {
foreach ( $requirements as $package => $version ) {
2012-03-31 22:39:43 +00:00
$baseRequirements [ $package ] = $version ;
}
2012-05-26 12:45:19 +00:00
$composer [ $requireKey ] = $baseRequirements ;
$json -> write ( $composer );
2012-03-31 22:39:43 +00:00
}
2012-05-26 12:45:19 +00:00
$output -> writeln ( '<info>' . $file . ' has been updated</info>' );
2012-05-26 13:17:52 +00:00
2012-07-19 15:17:08 +00:00
if ( $input -> getOption ( 'no-update' )) {
return 0 ;
}
2012-05-26 13:17:52 +00:00
// Update packages
$composer = $this -> getComposer ();
2012-12-11 14:30:09 +00:00
$composer -> getDownloadManager () -> setOutputProgress ( ! $input -> getOption ( 'no-progress' ));
2012-05-26 13:17:52 +00:00
$io = $this -> getIO ();
2013-09-05 12:30:03 +00:00
$commandEvent = new CommandEvent ( PluginEvents :: COMMAND , 'require' , $input , $output );
$composer -> getEventDispatcher () -> dispatch ( $commandEvent -> getName (), $commandEvent );
2012-05-26 13:17:52 +00:00
$install = Installer :: create ( $io , $composer );
$install
-> setVerbose ( $input -> getOption ( 'verbose' ))
-> setPreferSource ( $input -> getOption ( 'prefer-source' ))
2012-10-02 11:42:07 +00:00
-> setPreferDist ( $input -> getOption ( 'prefer-dist' ))
2013-03-10 12:44:54 +00:00
-> setDevMode ( true )
2012-05-26 13:17:52 +00:00
-> setUpdate ( true )
2014-02-10 20:24:46 +00:00
-> setUpdateWhitelist ( array_keys ( $requirements ))
-> setWhitelistDependencies ( $input -> getOption ( 'update-with-dependencies' ));
2012-05-26 13:17:52 +00:00
;
2013-11-22 15:17:02 +00:00
$status = $install -> run ();
if ( $status !== 0 ) {
2013-02-01 09:24:05 +00:00
$output -> writeln ( " \n " . '<error>Installation failed, reverting ' . $file . ' to its original content.</error>' );
file_put_contents ( $json -> getPath (), $composerBackup );
}
2013-02-12 09:14:44 +00:00
2013-11-22 15:17:02 +00:00
return $status ;
2012-05-26 12:45:19 +00:00
}
private function updateFileCleanly ( $json , array $base , array $new , $requireKey )
{
$contents = file_get_contents ( $json -> getPath ());
2012-03-31 22:39:43 +00:00
2012-05-26 12:45:19 +00:00
$manipulator = new JsonManipulator ( $contents );
2012-03-31 22:39:43 +00:00
2012-05-26 12:45:19 +00:00
foreach ( $new as $package => $constraint ) {
if ( ! $manipulator -> addLink ( $requireKey , $package , $constraint )) {
return false ;
}
}
file_put_contents ( $json -> getPath (), $manipulator -> getContents ());
return true ;
2012-03-31 22:39:43 +00:00
}
protected function interact ( InputInterface $input , OutputInterface $output )
{
return ;
}
}