diff --git a/src/Composer/Command/DebugPackagesCommand.php b/src/Composer/Command/DebugPackagesCommand.php index d7c2acdfa..e3d196466 100644 --- a/src/Composer/Command/DebugPackagesCommand.php +++ b/src/Composer/Command/DebugPackagesCommand.php @@ -18,6 +18,7 @@ use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Operation; use Composer\Package\LinkConstraint\VersionConstraint; +use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; @@ -52,7 +53,7 @@ EOT // create local repo, this contains all packages that are installed in the local project $localRepo = $composer->getRepositoryManager()->getLocalRepository(); // create installed repo, this contains all local packages + platform packages (php & extensions) - $installedRepo = new PlatformRepository($localRepo); + $installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository())); if ($input->getOption('local')) { foreach ($localRepo->getPackages() as $package) { diff --git a/src/Composer/Command/InstallCommand.php b/src/Composer/Command/InstallCommand.php index 9e212af10..0bc45a0a9 100644 --- a/src/Composer/Command/InstallCommand.php +++ b/src/Composer/Command/InstallCommand.php @@ -15,13 +15,17 @@ namespace Composer\Command; use Composer\Script\ScriptEvents; use Composer\Script\EventDispatcher; use Composer\Autoload\AutoloadGenerator; +use Composer\Composer; use Composer\DependencyResolver; use Composer\DependencyResolver\Pool; use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Operation; +use Composer\Package\MemoryPackage; use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Package\PackageInterface; +use Composer\Repository\CompositeRepository; use Composer\Repository\PlatformRepository; +use Composer\Repository\RepositoryInterface; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -60,26 +64,40 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { - return $this->install($input, $output); - } - - public function install(InputInterface $input, OutputInterface $output, $update = false) - { - $preferSource = (Boolean) $input->getOption('dev'); - $dryRun = (Boolean) $input->getOption('dry-run'); - $verbose = $dryRun || $input->getOption('verbose'); $composer = $this->getComposer(); $io = $this->getApplication()->getIO(); - $dispatcher = new EventDispatcher($this->getComposer(), $io); + $eventDispatcher = new EventDispatcher($composer, $io); + return $this->install( + $composer, + $eventDispatcher, + $input, + $output, + false, + (Boolean)$input->getOption('dev'), + (Boolean)$input->getOption('dry-run'), + (Boolean)$input->getOption('verbose'), + (Boolean)$input->getOption('no-install-recommends'), + (Boolean)$input->getOption('install-suggests') + ); + } + + public function install(Composer $composer, EventDispatcher $eventDispatcher, InputInterface $input, OutputInterface $output, $update, $preferSource, $dryRun, $verbose, $noInstallRecommends, $installSuggests, RepositoryInterface $additionalInstalledRepository = null) + { + if ($dryRun) { + $verbose = true; + } if ($preferSource) { $composer->getDownloadManager()->setPreferSource(true); } // create local repo, this contains all packages that are installed in the local project - $localRepo = $composer->getRepositoryManager()->getLocalRepository(); + $localRepo = $composer->getRepositoryManager()->getLocalRepository(); // create installed repo, this contains all local packages + platform packages (php & extensions) - $installedRepo = new PlatformRepository($localRepo); + $installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository())); + if ($additionalInstalledRepository) { + $installedRepo->addRepository($additionalInstalledRepository); + } // creating repository pool $pool = new Pool; @@ -91,7 +109,7 @@ EOT // dispatch pre event if (!$dryRun) { $eventName = $update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; - $dispatcher->dispatchCommandEvent($eventName); + $eventDispatcher->dispatchCommandEvent($eventName); } // creating requirements request @@ -99,7 +117,7 @@ EOT if ($update) { $output->writeln('Updating dependencies'); $installedPackages = $installedRepo->getPackages(); - $links = $this->collectLinks($input, $composer->getPackage()); + $links = $this->collectLinks($input, $composer->getPackage(), $noInstallRecommends, $installSuggests); foreach ($links as $link) { foreach ($installedPackages as $package) { @@ -125,7 +143,7 @@ EOT } else { $output->writeln('Installing dependencies'); - $links = $this->collectLinks($input, $composer->getPackage()); + $links = $this->collectLinks($input, $composer->getPackage(), $noInstallRecommends, $installSuggests); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); @@ -177,9 +195,9 @@ EOT $output->writeln((string) $operation); } if (!$dryRun) { - $dispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation); + $eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType())), $operation); $installationManager->execute($operation); - $dispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation); + $eventDispatcher->dispatchPackageEvent(constant('Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType())), $operation); } } @@ -197,19 +215,19 @@ EOT // dispatch post event $eventName = $update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; - $dispatcher->dispatchCommandEvent($eventName); + $eventDispatcher->dispatchCommandEvent($eventName); } } - private function collectLinks(InputInterface $input, PackageInterface $package) + private function collectLinks(InputInterface $input, PackageInterface $package, $noInstallRecommends, $installSuggests) { $links = $package->getRequires(); - if (!$input->getOption('no-install-recommends')) { + if (!$noInstallRecommends) { $links = array_merge($links, $package->getRecommends()); } - if ($input->getOption('install-suggests')) { + if ($installSuggests) { $links = array_merge($links, $package->getSuggests()); } diff --git a/src/Composer/Command/SearchCommand.php b/src/Composer/Command/SearchCommand.php index c7c6ebd3d..4a937539d 100644 --- a/src/Composer/Command/SearchCommand.php +++ b/src/Composer/Command/SearchCommand.php @@ -12,7 +12,6 @@ namespace Composer\Command; -use Composer\Repository\PlatformRepository; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Composer/Command/UpdateCommand.php b/src/Composer/Command/UpdateCommand.php index 6b46199c0..faeeb33fc 100644 --- a/src/Composer/Command/UpdateCommand.php +++ b/src/Composer/Command/UpdateCommand.php @@ -19,6 +19,7 @@ use Composer\DependencyResolver\Request; use Composer\DependencyResolver\Operation; use Composer\Package\LinkConstraint\VersionConstraint; use Composer\Repository\PlatformRepository; +use Composer\Script\EventDispatcher; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; @@ -54,7 +55,21 @@ EOT protected function execute(InputInterface $input, OutputInterface $output) { $installCommand = $this->getApplication()->find('install'); + $composer = $this->getComposer(); + $io = $this->getApplication()->getIO(); + $eventDispatcher = new EventDispatcher($composer, $io); - return $installCommand->install($input, $output, true); + return $installCommand->install( + $composer, + $eventDispatcher, + $input, + $output, + true, + (Boolean)$input->getOption('dev'), + (Boolean)$input->getOption('dry-run'), + (Boolean)$input->getOption('verbose'), + (Boolean)$input->getOption('no-install-recommends'), + (Boolean)$input->getOption('install-suggests') + ); } } diff --git a/src/Composer/Command/ValidateCommand.php b/src/Composer/Command/ValidateCommand.php index 692b6a323..d862a2b61 100644 --- a/src/Composer/Command/ValidateCommand.php +++ b/src/Composer/Command/ValidateCommand.php @@ -12,7 +12,6 @@ namespace Composer\Command; -use Composer\Repository\PlatformRepository; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Output\OutputInterface; diff --git a/src/Composer/Repository/CompositeRepository.php b/src/Composer/Repository/CompositeRepository.php new file mode 100644 index 000000000..eccf5f230 --- /dev/null +++ b/src/Composer/Repository/CompositeRepository.php @@ -0,0 +1,115 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Repository; + +use Composer\Package\PackageInterface; + +/** + * Composite repository. + * + * @author Beau Simensen + */ +class CompositeRepository implements RepositoryInterface +{ + /** + * List of repositories + * @var array + */ + private $repositories; + + /** + * Constructor + * @param array $repositories + */ + public function __construct(array $repositories) + { + $this->repositories = $repositories; + } + + /** + * {@inheritdoc} + */ + public function hasPackage(PackageInterface $package) + { + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + if ($repository->hasPackage($package)) { + return true; + } + } + return false; + } + + /** + * {@inheritdoc} + */ + public function findPackage($name, $version) + { + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + $package = $repository->findPackage($name, $version); + if (null !== $package) { + return $package; + } + } + return null; + } + + /** + * {@inheritdoc} + */ + public function findPackagesByName($name) + { + $packages = array(); + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + $packages[] = $repository->findPackagesByName($name); + } + return call_user_func_array('array_merge', $packages); + } + + /** + * {@inheritdoc} + */ + public function getPackages() + { + $packages = array(); + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + $packages[] = $repository->getPackages(); + } + return call_user_func_array('array_merge', $packages); + } + + /** + * {@inheritdoc} + */ + public function count() + { + $total = 0; + foreach ($this->repositories as $repository) { + /* @var $repository RepositoryInterface */ + $total += $repository->count(); + } + return $total; + } + + /** + * Add a repository. + * @param RepositoryInterface $repository + */ + public function addRepository(RepositoryInterface $repository) + { + $this->repositories[] = $repository; + } +} \ No newline at end of file diff --git a/src/Composer/Repository/PlatformRepository.php b/src/Composer/Repository/PlatformRepository.php index b9747fb37..12d5a6aa8 100644 --- a/src/Composer/Repository/PlatformRepository.php +++ b/src/Composer/Repository/PlatformRepository.php @@ -20,12 +20,6 @@ use Composer\Package\Version\VersionParser; */ class PlatformRepository extends ArrayRepository { - private $localRepository; - - public function __construct(RepositoryInterface $localRepository) - { - $this->localRepository = $localRepository; - } protected function initialize() { @@ -62,9 +56,4 @@ class PlatformRepository extends ArrayRepository parent::addPackage($ext); } } - - public function getPackages() - { - return array_merge(parent::getPackages(), $this->localRepository->getPackages()); - } } diff --git a/tests/Composer/Test/Repository/CompositeRepositoryTest.php b/tests/Composer/Test/Repository/CompositeRepositoryTest.php new file mode 100644 index 000000000..49e017d18 --- /dev/null +++ b/tests/Composer/Test/Repository/CompositeRepositoryTest.php @@ -0,0 +1,128 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Test\Repository; + +use Composer\Repository\CompositeRepository; +use Composer\Repository\ArrayRepository; +use Composer\Test\TestCase; + +class CompositeRepositoryTest extends TestCase +{ + public function testHasPackage() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + + $repo = new CompositeRepository(array($arrayRepoOne, $arrayRepoTwo)); + + $this->assertTrue($repo->hasPackage($this->getPackage('foo', '1')), "Should have package 'foo/1'"); + $this->assertTrue($repo->hasPackage($this->getPackage('bar', '1')), "Should have package 'bar/1'"); + + $this->assertFalse($repo->hasPackage($this->getPackage('foo', '2')), "Should not have package 'foo/2'"); + $this->assertFalse($repo->hasPackage($this->getPackage('bar', '2')), "Should not have package 'bar/2'"); + } + + public function testFindPackage() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + + $repo = new CompositeRepository(array($arrayRepoOne, $arrayRepoTwo)); + + $this->assertEquals('foo', $repo->findPackage('foo', '1')->getName(), "Should find package 'foo/1' and get name of 'foo'"); + $this->assertEquals('1', $repo->findPackage('foo', '1')->getPrettyVersion(), "Should find package 'foo/1' and get pretty version of '1'"); + $this->assertEquals('bar', $repo->findPackage('bar', '1')->getName(), "Should find package 'bar/1' and get name of 'bar'"); + $this->assertEquals('1', $repo->findPackage('bar', '1')->getPrettyVersion(), "Should find package 'bar/1' and get pretty version of '1'"); + $this->assertNull($repo->findPackage('foo', '2'), "Should not find package 'foo/2'"); + } + + public function testFindPackagesByName() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + $arrayRepoOne->addPackage($this->getPackage('foo', '2')); + $arrayRepoOne->addPackage($this->getPackage('bat', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + $arrayRepoTwo->addPackage($this->getPackage('bar', '2')); + $arrayRepoTwo->addPackage($this->getPackage('foo', '3')); + + $repo = new CompositeRepository(array($arrayRepoOne, $arrayRepoTwo)); + + $bats = $repo->findPackagesByName('bat'); + $this->assertCount(1, $bats, "Should find one instance of 'bats' (defined in just one repository)"); + $this->assertEquals('bat', $bats[0]->getName(), "Should find packages named 'bat'"); + + $bars = $repo->findPackagesByName('bar'); + $this->assertCount(2, $bars, "Should find two instances of 'bar' (both defined in the same repository)"); + $this->assertEquals('bar', $bars[0]->getName(), "Should find packages named 'bar'"); + + $foos = $repo->findPackagesByName('foo'); + $this->assertCount(3, $foos, "Should find three instances of 'foo' (two defined in one repository, the third in the other)"); + $this->assertEquals('foo', $foos[0]->getName(), "Should find packages named 'foo'"); + } + + public function testGetPackages() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + + $repo = new CompositeRepository(array($arrayRepoOne, $arrayRepoTwo)); + + $packages = $repo->getPackages(); + $this->assertCount(2, $packages, "Should get two packages"); + $this->assertEquals("foo", $packages[0]->getName(), "First package should have name of 'foo'"); + $this->assertEquals("1", $packages[0]->getPrettyVersion(), "First package should have pretty version of '1'"); + $this->assertEquals("bar", $packages[1]->getName(), "Second package should have name of 'bar'"); + $this->assertEquals("1", $packages[1]->getPrettyVersion(), "Second package should have pretty version of '1'"); + } + + public function testAddRepository() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + $arrayRepoTwo->addPackage($this->getPackage('bar', '2')); + $arrayRepoTwo->addPackage($this->getPackage('bar', '3')); + + $repo = new CompositeRepository(array($arrayRepoOne)); + $this->assertCount(1, $repo, "Composite repository should have just one package before addRepository() is called"); + $repo->addRepository($arrayRepoTwo); + $this->assertCount(4, $repo, "Composite repository should have four packages after addRepository() is called"); + } + + public function testCount() + { + $arrayRepoOne = new ArrayRepository; + $arrayRepoOne->addPackage($this->getPackage('foo', '1')); + + $arrayRepoTwo = new ArrayRepository; + $arrayRepoTwo->addPackage($this->getPackage('bar', '1')); + + $repo = new CompositeRepository(array($arrayRepoOne, $arrayRepoTwo)); + + $this->assertEquals(2, count($repo), "Should return '2' for count(\$repo)"); + } +}