diff --git a/bin/composer b/bin/composer index 304940f6d..95d3be44e 100755 --- a/bin/composer +++ b/bin/composer @@ -9,12 +9,15 @@ use Composer\Downloader\PearDownloader; use Composer\Downloader\ZipDownloader; use Composer\Command\InstallCommand; use Composer\Installer\LibraryInstaller; +use Composer\Console\Application; +// initialize composer $composer = new Composer(); $composer->addDownloader('git', new GitDownloader); $composer->addDownloader('pear', new PearDownloader); $composer->addDownloader('zip', new ZipDownloader); $composer->addInstaller('library', new LibraryInstaller); -$cmd = new InstallCommand(); -$cmd->install($composer); +// run the command application +$application = new Application($composer); +$application->run(); diff --git a/src/Composer/Command/Command.php b/src/Composer/Command/Command.php new file mode 100644 index 000000000..bb0a6a298 --- /dev/null +++ b/src/Composer/Command/Command.php @@ -0,0 +1,31 @@ + + * Jordi Boggiano + * + * 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\Command\Command as BaseCommand; + +/** + * Base class for Composer commands + * + * @author Ryan Weaver + */ +abstract class Command extends BaseCommand +{ + /** + * @return \Composer\Composer + */ + public function getComposer() + { + return $this->getApplication()->getComposer(); + } +} \ No newline at end of file diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index e92994a46..889d9ead7 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -20,27 +20,36 @@ use Composer\Repository\PlatformRepository; use Composer\Package\MemoryPackage; use Composer\Package\LinkConstraint\VersionConstraint; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; + + /** * @author Jordi Boggiano + * @author Ryan Weaver */ -class InstallCommand +class InstallCommand extends Command { - protected $composer; - - public function install($composer) + protected function configure() { - $this->composer = $composer; + $this + ->setName('install') + ->setDescription('Parses the composer.json file and downloads the needed dependencies.') + ; + } + protected function execute(InputInterface $input, OutputInterface $output) + { // TODO this needs a parameter to enable installing from source (i.e. git clone, instead of downloading archives) $sourceInstall = false; $config = $this->loadConfig(); - echo 'Loading repositories'.PHP_EOL; + $output->writeln('Loading repositories'); if (isset($config['repositories'])) { foreach ($config['repositories'] as $name => $spec) { - $composer->addRepository($name, $spec); + $this->getComposer()->addRepository($name, $spec); } } @@ -52,15 +61,15 @@ class InstallCommand // TODO check the lock file to see what's currently installed // $repoInstalled->addPackage(new MemoryPackage('$Package', '$Version')); - echo 'Loading package list'.PHP_EOL; + $output->writeln('Loading package list'); - foreach ($composer->getRepositories() as $repository) { + foreach ($this->getComposer()->getRepositories() as $repository) { $pool->addRepository($repository); } $request = new Request($pool); - echo 'Building up request'.PHP_EOL; + $output->writeln('Building up request'); // TODO there should be an update flag or dedicated update command // TODO check lock file to remove packages that disappeared from the requirements @@ -78,7 +87,7 @@ class InstallCommand } } - echo 'Solving dependencies'.PHP_EOL; + $output->writeln('Solving dependencies'); $policy = new DefaultPolicy; $solver = new Solver($policy, $pool, $repoInstalled); @@ -90,7 +99,7 @@ class InstallCommand switch ($task['job']) { case 'install': $package = $task['package']; - echo '> Installing '.$package->getName().PHP_EOL; + $output->writeln('> Installing '.$package->getName()); if ($sourceInstall) { // TODO } else { @@ -98,14 +107,14 @@ class InstallCommand $downloaderType = $package->getDistType(); $type = 'dist'; } elseif ($package->getSourceType()) { - echo 'Package '.$package->getName().' has no dist url, installing from source instead.'; + $output->writeln('Package '.$package->getName().' has no dist url, installing from source instead.'); $downloaderType = $package->getSourceType(); $type = 'source'; } else { throw new \UnexpectedValueException('Package '.$package->getName().' has no source or dist URL.'); } - $downloader = $composer->getDownloader($downloaderType); - $installer = $composer->getInstaller($package->getType()); + $downloader = $this->getComposer()->getDownloader($downloaderType); + $installer = $this->getComposer()->getInstaller($package->getType()); if (!$installer->install($package, $downloader, $type)) { throw new \LogicException($package->getName().' could not be installed.'); } @@ -116,9 +125,9 @@ class InstallCommand throw new \UnexpectedValueException('Unhandled job type : '.$task['job']); } } - echo '> Done'.PHP_EOL; + $output->writeln('> Done'); - $this->storeLockFile($lock); + $this->storeLockFile($lock, $output); } protected function loadConfig() @@ -153,10 +162,11 @@ class InstallCommand return $config; } - protected function storeLockFile(array $content) + protected function storeLockFile(array $content, OutputInterface $output) { file_put_contents('composer.lock', json_encode($content, JSON_FORCE_OBJECT)."\n"); - echo '> composer.lock dumped'.PHP_EOL; + $output->writeln('> composer.lock dumped'); + } protected function lowercase($str) diff --git a/src/Composer/Composer.php b/src/Composer/Composer.php index 0dc19e150..d568917cc 100644 --- a/src/Composer/Composer.php +++ b/src/Composer/Composer.php @@ -22,6 +22,8 @@ use Composer\Repository\PearRepository; */ class Composer { + const VERSION = '1.0.0-DEV'; + protected $repositories = array(); protected $downloaders = array(); protected $installers = array(); diff --git a/src/Composer/Console/Application.php b/src/Composer/Console/Application.php new file mode 100644 index 000000000..d4f380e82 --- /dev/null +++ b/src/Composer/Console/Application.php @@ -0,0 +1,80 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Console; + +use Symfony\Component\Console\Application as BaseApplication; +use Composer\Composer; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Finder\Finder; + +/** + * The console application that handles the commands + * + * @author Ryan Weaver + */ +class Application extends BaseApplication +{ + private $composer; + + public function __construct(Composer $composer) + { + parent::__construct('Composer', Composer::VERSION); + + $this->composer = $composer; + } + + /** + * Runs the current application. + * + * @param InputInterface $input An Input instance + * @param OutputInterface $output An Output instance + * + * @return integer 0 if everything went fine, or an error code + */ + public function doRun(InputInterface $input, OutputInterface $output) + { + $this->registerCommands(); + + return parent::doRun($input, $output); + } + + /** + * @return Composer + */ + public function getComposer() + { + return $this->composer; + } + + /** + * Looks for all *Command files in Composer's Command directory + */ + protected function registerCommands() + { + $dir = __DIR__.'/../Command'; + $finder = new Finder(); + $finder->files()->name('*Command.php')->in($dir); + + foreach ($finder as $file) { + $ns = 'Composer\\Command'; + if ($relativePath = $file->getRelativePath()) { + $ns .= '\\'.strtr($relativePath, '/', '\\'); + } + $r = new \ReflectionClass($ns.'\\'.$file->getBasename('.php')); + if ($r->isSubclassOf('Symfony\\Component\\Console\\Command\\Command') && !$r->isAbstract()) { + $this->add($r->newInstance()); + } + } + } +} \ No newline at end of file