/** * Search for a given package version. * * Usage examples : Composition::has('php', '5.3.*') // PHP version * Composition::has('ext-memcache') // PHP extension * Composition::has('vendor/package', '>2.1') // Package version * * @param type $packageName The package name * @param type $prettyString An optional version constraint * * @return boolean Wether or not the package has been found. */ public static function has($packageName, $prettyString = '*') { if (null === self::$pool) { if (null === self::$rootDir) { self::$rootDir = getcwd(); if (!file_exists(self::$rootDir . '/composer.json')) { throw new \RuntimeException('Unable to guess the project root dir, please specify it manually using the Composition::setRootDir method.'); } } $minimumStability = 'dev'; $config = new Config(); $file = new JsonFile(self::$rootDir . '/composer.json'); if ($file->exists()) { $projectConfig = $file->read(); $config->merge($projectConfig); if (isset($projectConfig['minimum-stability'])) { $minimumStability = $projectConfig['minimum-stability']; } } $vendorDir = self::$rootDir . '/' . $config->get('vendor-dir'); $pool = new Pool($minimumStability); $pool->addRepository(new PlatformRepository()); $pool->addRepository(new InstalledFilesystemRepository(new JsonFile($vendorDir . '/composer/installed.json'))); $pool->addRepository(new InstalledFilesystemRepository(new JsonFile($vendorDir . '/composer/installed_dev.json'))); self::$pool = $pool; } $parser = new VersionParser(); $constraint = $parser->parseConstraints($prettyString); $packages = self::$pool->whatProvides($packageName, $constraint); return empty($packages) ? false : true; }
public function testRequestInstallSamePackageFromDifferentRepositories() { $pool = new Pool(); $repo1 = new ArrayRepository(); $repo2 = new ArrayRepository(); $foo1 = $this->getPackage('foo', '1'); $foo2 = $this->getPackage('foo', '1'); $repo1->addPackage($foo1); $repo2->addPackage($foo2); $pool->addRepository($repo1); $pool->addRepository($repo2); $request = new Request($pool); $request->install('foo', $constraint = $this->getVersionConstraint('=', '1')); $this->assertEquals(array(array('packages' => array($foo1, $foo2), 'cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint)), $request->getJobs()); }
protected function package($matches) { $hash = $matches['hash']; $name = $matches['name']; $filename = 'p/hash/' . substr($hash, 0, 2) . '/' . substr($hash, 2, 2) . '/' . $hash . hash('md5', $hash . $name) . '.json'; if (!file_exists($filename)) { $repos = $this->getRepos(); $pool = new Pool('dev'); foreach ($repos as $repo) { try { $pool->addRepository($repo); } catch (\RuntimeException $e) { } } $matches = $pool->whatProvides($name, null); if (!$matches) { return '{}'; } else { $match = $matches[0]; $repo = $match->getRepository(); $ref = new \ReflectionProperty($repo, 'cache'); $ref->setAccessible(true); $cache = $ref->getValue($repo); $cacheKey = 'provider-' . strtr($name, '/', '$') . '.json'; $packages = $cache->read($cacheKey); if (empty($packages)) { throw new \Exception("Cache should exists, please report this issue on github", 1); } mkdir(dirname($filename), 0755, true); file_put_contents($filename, $packages); } } return file_get_contents($filename); }
/** * Execute the command. * * @param InputInterface $input * @param OutputInterface $output * @param bool $inverted Whether to invert matching process (why-not vs why behaviour) * @return int|null Exit code of the operation. */ protected function doExecute(InputInterface $input, OutputInterface $output, $inverted = false) { // Emit command event on startup $composer = $this->getComposer(); $commandEvent = new CommandEvent(PluginEvents::COMMAND, $this->getName(), $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); // Prepare repositories and set up a pool $platformOverrides = $composer->getConfig()->get('platform') ?: array(); $repository = new CompositeRepository(array(new ArrayRepository(array($composer->getPackage())), $composer->getRepositoryManager()->getLocalRepository(), new PlatformRepository(array(), $platformOverrides))); $pool = new Pool(); $pool->addRepository($repository); // Parse package name and constraint list($needle, $textConstraint) = array_pad(explode(':', $input->getArgument(self::ARGUMENT_PACKAGE)), 2, $input->getArgument(self::ARGUMENT_CONSTRAINT)); // Find packages that are or provide the requested package first $packages = $pool->whatProvides($needle); if (empty($packages)) { throw new \InvalidArgumentException(sprintf('Could not find package "%s" in your project', $needle)); } // If the version we ask for is not installed then we need to locate it in remote repos and add it. // This is needed for why-not to resolve conflicts from an uninstalled version against installed packages. if (!$repository->findPackage($needle, $textConstraint)) { $defaultRepos = new CompositeRepository(RepositoryFactory::defaultRepos($this->getIO())); if ($match = $defaultRepos->findPackage($needle, $textConstraint)) { $repository->addRepository(new ArrayRepository(array(clone $match))); } } // Include replaced packages for inverted lookups as they are then the actual starting point to consider $needles = array($needle); if ($inverted) { foreach ($packages as $package) { $needles = array_merge($needles, array_map(function (Link $link) { return $link->getTarget(); }, $package->getReplaces())); } } // Parse constraint if one was supplied if ('*' !== $textConstraint) { $versionParser = new VersionParser(); $constraint = $versionParser->parseConstraints($textConstraint); } else { $constraint = null; } // Parse rendering options $renderTree = $input->getOption(self::OPTION_TREE); $recursive = $renderTree || $input->getOption(self::OPTION_RECURSIVE); // Resolve dependencies $results = $repository->getDependents($needles, $constraint, $inverted, $recursive); if (empty($results)) { $extra = null !== $constraint ? sprintf(' in versions %smatching %s', $inverted ? 'not ' : '', $textConstraint) : ''; $this->getIO()->writeError(sprintf('<info>There is no installed package depending on "%s"%s</info>', $needle, $extra)); } elseif ($renderTree) { $this->initStyles($output); $root = $packages[0]; $this->getIO()->write(sprintf('<info>%s</info> %s %s', $root->getPrettyName(), $root->getPrettyVersion(), $root->getDescription())); $this->printTree($results); } else { $this->printTable($output, $results); } return 0; }
protected function selectPackage(IOInterface $io, $packageName, $version = null) { $io->write('<info>Searching for the specified package.</info>'); if ($composer = $this->getComposer(false)) { $localRepo = $composer->getRepositoryManager()->getLocalRepository(); $repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories())); } else { $defaultRepos = Factory::createDefaultRepositories($this->getIO()); $io->write('No composer.json found in the current directory, searching packages from ' . implode(', ', array_keys($defaultRepos))); $repos = new CompositeRepository($defaultRepos); } $pool = new Pool(); $pool->addRepository($repos); $constraint = $version ? new VersionConstraint('>=', $version) : null; $packages = $pool->whatProvides($packageName, $constraint); if (count($packages) > 1) { $package = $packages[0]; $io->write('<info>Found multiple matches, selected ' . $package->getPrettyString() . '.</info>'); $io->write('Alternatives were ' . implode(', ', array_map(function ($p) { return $p->getPrettyString(); }, $packages)) . '.'); $io->write('<comment>Please use a more specific constraint to pick a different package.</comment>'); } elseif ($packages) { $package = $packages[0]; $io->write('<info>Found an exact match ' . $package->getPrettyString() . '.</info>'); } else { $io->write('<error>Could not find a package matching ' . $packageName . '.</error>'); return false; } return $package; }
/** * Test that the core bundles get correctly injected. * * @return void */ public function testInjectCoreBundles() { $inOut = $this->getMock('Composer\\IO\\IOInterface'); $factory = new Factory(); $composer = $factory->createComposer($inOut, $this->config); $plugin = new Plugin(); $local = $composer->getRepositoryManager()->getLocalRepository(); if ($core = $local->findPackages('contao/core')) { $this->fail('Contao core has already been injected, found version ' . $core[0]->getVersion()); } $plugin->activate($composer, $inOut); if (!($core = $local->findPackages('contao/core'))) { $this->fail('Contao core has not been injected.'); } $core = $core[0]; $constraint = new Constraint('=', $core->getVersion()); $pool = new Pool('dev'); $pool->addRepository($local); $this->assertNotNull($core = $pool->whatProvides('contao/core', $constraint)); // bundle names + 'contao-community-alliance/composer-client' $this->assertCount(8, $core[0]->getRequires()); foreach (array('contao/calendar-bundle', 'contao/comments-bundle', 'contao/core-bundle', 'contao/faq-bundle', 'contao/listing-bundle', 'contao/news-bundle', 'contao/newsletter-bundle') as $bundleName) { $this->assertNotNull($matches = $pool->whatProvides($bundleName, $constraint)); $this->assertCount(1, $matches); $this->assertEquals('metapackage', $matches[0]->getType()); } }
/** * Check if CakePHP version matches against a version * * @param string $matcher * @param string $version * @return bool */ protected function matchesCakeVersion($matcher, $version) { if (class_exists('Composer\\Semver\\Constraint\\MultiConstraint')) { $multiClass = 'Composer\\Semver\\Constraint\\MultiConstraint'; $constraintClass = 'Composer\\Semver\\Constraint\\Constraint'; } else { $multiClass = 'Composer\\Package\\LinkConstraint\\MultiConstraint'; $constraintClass = 'Composer\\Package\\LinkConstraint\\VersionConstraint'; } $repositoryManager = $this->composer->getRepositoryManager(); if ($repositoryManager) { $repos = $repositoryManager->getLocalRepository(); if (!$repos) { return false; } $cake3 = new $multiClass(array(new $constraintClass($matcher, $version), new $constraintClass('!=', '9999999-dev'))); $pool = new Pool('dev'); $pool->addRepository($repos); $packages = $pool->whatProvides('cakephp/cakephp'); foreach ($packages as $package) { $installed = new $constraintClass('=', $package->getVersion()); if ($cake3->matches($installed)) { return true; break; } } } return false; }
private function getPool(InputInterface $input) { if (!$this->pool) { $this->pool = new Pool($this->getMinimumStability($input)); $this->pool->addRepository($this->getRepos()); } return $this->pool; }
private function getPool(Composer $composer) { if (!$this->pool) { $this->pool = new Pool($composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags()); $this->pool->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories())); } return $this->pool; }
/** * Add repository instance. * * @param IOInterface $io The IO instance * @param RepositoryManager $rm The repository mamanger * @param array $repos The list of already repository added (passed by reference) * @param string $name The name of the new repository * @param RepositoryInterface $repo The repository instance * @param Pool|null $pool The pool */ public static function addRepositoryInstance(IOInterface $io, RepositoryManager $rm, array &$repos, $name, RepositoryInterface $repo, Pool $pool = null) { if (!isset($repos[$name])) { static::writeAddRepository($io, $name); $repos[$name] = $repo; $rm->addRepository($repo); if (null !== $pool) { $pool->addRepository($repo); } } }
private function getPackageMatches($repository, $name, $version = null) { $pool = new Pool('dev'); $pool->addRepository($repository); $constraint = null; if ($version) { $parser = new VersionParser(); $constraint = $parser->parseConstraints($version); } return $pool->whatProvides($name, $constraint); }
/** * Return a resolver pool that contains repositories, that provide packages. * * @return \Composer\DependencyResolver\Pool */ public function getPool() { if (!$this->pool) { $this->pool = new Pool($this->getMinimumStability()); // Add each of our configured repos to the pool, // or it defaults to packagist.org foreach ($this->getRepos() as $repo) { $this->pool->addRepository($repo); } } return $this->pool; }
public function testGetMaxId() { $pool = new Pool(); $repository = new ArrayRepository(); $firstPackage = $this->getPackage('foo', '1'); $secondPackage = $this->getPackage('foo1', '1'); $this->assertEquals(0, $pool->getMaxId()); $repository->addPackage($firstPackage); $repository->addPackage($secondPackage); $pool->addRepository($repository); $this->assertEquals(2, $pool->getMaxId()); }
/** * @param RepositoryManager $rm The repository mamanger * @param array $repos The list of already repository added (passed by reference) * @param string $name The name of the new repository * @param array $repoConfig The config of the new repository * @param Pool|null $pool The pool */ public static function addRepository(RepositoryManager $rm, array &$repos, $name, array $repoConfig, Pool $pool = null) { if (!isset($repos[$name])) { $repo = $rm->createRepository($repoConfig['type'], $repoConfig); $repos[$name] = $repo; $rm->addRepository($repo); if (null !== $pool) { $pool->addRepository($repo); } } }
/** * @return InstallOperation[] */ private function getOperations() { foreach ($this->aliases as $alias) { // we need to replace the version of aliased packages in the local // repository by their aliases in the root package (composer always // stores the actual installed version instead), otherwise the whole // dependency resolution below will fail. $aliased = $this->localRepo->findPackage($alias['package'], $alias['version']); $version = new \ReflectionProperty('Composer\\Package\\Package', 'version'); $version->setAccessible(true); $version->setValue($aliased, $alias['alias_normalized']); } $toRepo = new ArrayRepository(); $pool = new Pool(); $pool->addRepository($this->localRepo); $pool->addRepository(new PlatformRepository()); $request = new Request($pool); foreach ($this->localRepo->getCanonicalPackages() as $package) { $request->install($package->getName()); } $solver = new Solver(new DefaultPolicy(), $pool, $toRepo, new NullIO()); return $solver->solve($request); }
public function testSelectLowest() { $policy = new DefaultPolicy(false, true); $this->repo->addPackage($packageA1 = $this->getPackage('A', '1.0')); $this->repo->addPackage($packageA2 = $this->getPackage('A', '2.0')); $this->pool->addRepository($this->repo); $literals = array($packageA1->getId(), $packageA2->getId()); $expected = array($packageA1->getId()); $selected = $policy->selectPreferredPackages($this->pool, array(), $literals); $this->assertSame($expected, $selected); }
/** * finds a package by name * * @param RepositoryInterface $repos * @param string $name * @return CompletePackageInterface */ protected function getPackage(RepositoryInterface $repos, $name) { $name = strtolower($name); $pool = new Pool('dev'); $pool->addRepository($repos); $matches = $pool->whatProvides($name); foreach ($matches as $index => $package) { // skip providers/replacers if ($package->getName() !== $name) { unset($matches[$index]); continue; } return $package; } }
public function testRequestInstallAndRemove() { $pool = new Pool(); $repo = new ArrayRepository(); $foo = $this->getPackage('foo', '1'); $bar = $this->getPackage('bar', '1'); $foobar = $this->getPackage('foobar', '1'); $repo->addPackage($foo); $repo->addPackage($bar); $repo->addPackage($foobar); $pool->addRepository($repo); $request = new Request($pool); $request->install('foo'); $request->install('bar'); $request->remove('foobar'); $this->assertEquals(array(array('packages' => array($foo), 'cmd' => 'install', 'packageName' => 'foo'), array('packages' => array($bar), 'cmd' => 'install', 'packageName' => 'bar'), array('packages' => array($foobar), 'cmd' => 'remove', 'packageName' => 'foobar')), $request->getJobs()); }
protected function execute(InputInterface $input, OutputInterface $output) { $composer = $this->getComposer(); $commandEvent = new CommandEvent(PluginEvents::COMMAND, 'depends', $input, $output); $composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent); $repo = new CompositeRepository(array(new ArrayRepository(array($composer->getPackage())), $composer->getRepositoryManager()->getLocalRepository())); $needle = $input->getArgument('package'); $pool = new Pool(); $pool->addRepository($repo); $packages = $pool->whatProvides($needle); if (empty($packages)) { throw new \InvalidArgumentException('Could not find package "' . $needle . '" in your project.'); } $linkTypes = $this->linkTypes; $types = array_map(function ($type) use($linkTypes) { $type = rtrim($type, 's'); if (!isset($linkTypes[$type])) { throw new \InvalidArgumentException('Unexpected link type: ' . $type . ', valid types: ' . implode(', ', array_keys($linkTypes))); } return $type; }, $input->getOption('link-type')); $messages = array(); $outputPackages = array(); $io = $this->getIO(); /** @var PackageInterface $package */ foreach ($repo->getPackages() as $package) { foreach ($types as $type) { /** @var Link $link */ foreach ($package->{'get' . $linkTypes[$type][0]}() as $link) { if ($link->getTarget() === $needle) { if (!isset($outputPackages[$package->getName()])) { $messages[] = '<info>' . $package->getPrettyName() . '</info> ' . $linkTypes[$type][1] . ' ' . $needle . ' (<info>' . $link->getPrettyConstraint() . '</info>)'; $outputPackages[$package->getName()] = true; } } } } } if ($messages) { sort($messages); $io->write($messages); } else { $io->writeError('<info>There is no installed package depending on "' . $needle . '".</info>'); } }
protected function execute(InputInterface $input, OutputInterface $output) { $repos = $this->getComposer()->getRepositoryManager()->getLocalRepositories(); $needle = $input->getArgument('package'); $pool = new Pool(); foreach ($repos as $repo) { $pool->addRepository($repo); } $packages = $pool->whatProvides($needle); if (empty($packages)) { throw new \InvalidArgumentException('Could not find package "' . $needle . '" in your project.'); } $linkTypes = $this->linkTypes; $verbose = (bool) $input->getOption('verbose'); $types = array_map(function ($type) use($linkTypes) { $type = rtrim($type, 's'); if (!isset($linkTypes[$type])) { throw new \InvalidArgumentException('Unexpected link type: ' . $type . ', valid types: ' . implode(', ', array_keys($linkTypes))); } return $type; }, $input->getOption('link-type')); $dependsOnPackages = false; foreach ($repos as $repo) { $repo->filterPackages(function ($package) use($needle, $types, $linkTypes, $output, $verbose, &$dependsOnPackages) { static $outputPackages = array(); foreach ($types as $type) { foreach ($package->{'get' . $linkTypes[$type]}() as $link) { if ($link->getTarget() === $needle) { $dependsOnPackages = true; if ($verbose) { $output->writeln($package->getPrettyName() . ' ' . $package->getPrettyVersion() . ' <info>' . $type . '</info> ' . $link->getPrettyConstraint()); } elseif (!isset($outputPackages[$package->getName()])) { $output->writeln($package->getPrettyName()); $outputPackages[$package->getName()] = true; } } } } }); } if (!$dependsOnPackages) { $output->writeln('<info>There is no installed package depending on "' . $needle . '".</info>'); } }
/** * @return PackageInterface[] */ public function getInstalled() { $composer = Factory::create(new NullIO(), $this->config); $localRepo = $composer->getRepositoryManager()->getLocalRepository(); $repos = new CompositeRepository(array_merge(array($localRepo), $composer->getRepositoryManager()->getRepositories())); $pool = new Pool(); $pool->addRepository($repos); $vs = new VersionSelector($pool); $packages = []; foreach ($localRepo->getPackages() as $package) { if (!isset($packages[$package->getName()]) || !is_object($packages[$package->getName()]) || version_compare($packages[$package->getName()]->getVersion(), $package->getVersion(), '<')) { if ($package instanceof CompletePackageInterface) { $latestPackage = $vs->findBestCandidate($package->getName()); $package = new InstalledPackage($package, $latestPackage); } $packages[$package->getName()] = $package; } } return $packages; }
/** * Change the default plugin location when cakephp >= 3.0 */ public function getLocations() { $repositoryManager = $this->composer->getRepositoryManager(); if ($repositoryManager) { $repos = $repositoryManager->getLocalRepository(); if (!$repos) { return $this->locations; } $cake3 = new MultiConstraint(array(new VersionConstraint('>=', '3.0.0'), new VersionConstraint('!=', '9999999-dev'))); $pool = new Pool('dev'); $pool->addRepository($repos); $packages = $pool->whatProvides('cakephp/cakephp'); foreach ($packages as $package) { $installed = new VersionConstraint('=', $package->getVersion()); if ($cake3->matches($installed)) { $this->locations['plugin'] = 'plugins/{$name}/'; break; } } } return $this->locations; }
/** * Check if CakePHP version matches against a version * * @param string $matcher * @param string $version * @return bool */ protected function matchesCakeVersion($matcher, $version) { $repositoryManager = $this->composer->getRepositoryManager(); if ($repositoryManager) { $repos = $repositoryManager->getLocalRepository(); if (!$repos) { return false; } $cake3 = new MultiConstraint(array(new VersionConstraint($matcher, $version), new VersionConstraint('!=', '9999999-dev'))); $pool = new Pool('dev'); $pool->addRepository($repos); $packages = $pool->whatProvides('cakephp/cakephp'); foreach ($packages as $package) { $installed = new VersionConstraint('=', $package->getVersion()); if ($cake3->matches($installed)) { return true; break; } } } return false; }
public function package($info) { preg_match('{^(?<name>.*)\\$(?<hash>.*)\\.json$}i', $info, $matches); $hash = $matches['hash']; $name = $matches['name']; $filename = 'p/hash/' . substr($hash, 0, 2) . '/' . substr($hash, 2, 2) . '/' . hash('sha256', $hash . $name) . '.json'; if (!Storage::has($filename)) { $repos = $this->getRepos(); $installedRepo = new CompositeRepository($repos); $pool = new Pool('dev'); $pool->addRepository($installedRepo); $matches = $pool->whatProvides($name, null); if (!$matches) { return '{}'; } else { $match = $matches[0]; $repo = $match->getRepository(); $ref = new \ReflectionProperty($repo, 'providersUrl'); $ref->setAccessible(true); $providersUrl = $ref->getValue($repo); $ref = new \ReflectionProperty($repo, 'cache'); $ref->setAccessible(true); $cache = $ref->getValue($repo); $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $providersUrl); $cacheKey = 'provider-' . strtr($name, '/', '$') . '.json'; if ($cache->sha256($cacheKey) === $hash) { $packages = $cache->read($cacheKey); } if (!isset($packages) && empty($packages)) { throw new Exception("Cache should exists, please report this issue on github", 1); } Storage::put($filename, $packages); } } return Storage::get($filename); }
/** * Adds all dependencies of the update whitelist to the whitelist, too. * * Packages which are listed as requirements in the root package will be * skipped including their dependencies, unless they are listed in the * update whitelist themselves. * * @param RepositoryInterface $localRepo * @param boolean $devMode * @param array $rootRequires An array of links to packages in require of the root package * @param array $rootDevRequires An array of links to packages in require-dev of the root package */ private function whitelistUpdateDependencies($localRepo, $devMode, array $rootRequires, array $rootDevRequires) { if (!$this->updateWhitelist) { return; } if ($devMode) { $rootRequires = array_merge($rootRequires, $rootDevRequires); } $skipPackages = array(); foreach ($rootRequires as $require) { $skipPackages[$require->getTarget()] = true; } $pool = new Pool(); $pool->addRepository($localRepo); $seen = array(); foreach ($this->updateWhitelist as $packageName => $void) { $packageQueue = new \SplQueue(); foreach ($pool->whatProvides($packageName) as $depPackage) { $packageQueue->enqueue($depPackage); } while (!$packageQueue->isEmpty()) { $package = $packageQueue->dequeue(); if (isset($seen[$package->getId()])) { continue; } $seen[$package->getId()] = true; $this->updateWhitelist[$package->getName()] = true; $requires = $package->getRequires(); if ($devMode) { $requires = array_merge($requires, $package->getDevRequires()); } foreach ($requires as $require) { $requirePackages = $pool->whatProvides($require->getTarget()); foreach ($requirePackages as $requirePackage) { if (isset($skipPackages[$requirePackage->getName()])) { continue; } $packageQueue->enqueue($requirePackage); } } } } }
/** * Adds all dependencies of the update whitelist to the whitelist, too. * * Packages which are listed as requirements in the root package will be * skipped including their dependencies, unless they are listed in the * update whitelist themselves. * * @param RepositoryInterface $localRepo * @param boolean $devMode * @param array $rootRequires An array of links to packages in require of the root package * @param array $rootDevRequires An array of links to packages in require-dev of the root package */ private function whitelistUpdateDependencies($localRepo, $devMode, array $rootRequires, array $rootDevRequires) { if (!$this->updateWhitelist) { return; } $requiredPackageNames = array(); foreach (array_merge($rootRequires, $rootDevRequires) as $require) { $requiredPackageNames[] = $require->getTarget(); } if ($devMode) { $rootRequires = array_merge($rootRequires, $rootDevRequires); } $skipPackages = array(); foreach ($rootRequires as $require) { $skipPackages[$require->getTarget()] = true; } $pool = new Pool(); $pool->addRepository($localRepo); $seen = array(); $rootRequiredPackageNames = array_keys($rootRequires); foreach ($this->updateWhitelist as $packageName => $void) { $packageQueue = new \SplQueue(); $depPackages = $pool->whatProvides($packageName); $nameMatchesRequiredPackage = in_array($packageName, $requiredPackageNames, true); // check if the name is a glob pattern that did not match directly if (!$nameMatchesRequiredPackage) { $whitelistPatternRegexp = $this->packageNameToRegexp($packageName); foreach ($rootRequiredPackageNames as $rootRequiredPackageName) { if (preg_match($whitelistPatternRegexp, $rootRequiredPackageName)) { $nameMatchesRequiredPackage = true; break; } } } if (count($depPackages) == 0 && !$nameMatchesRequiredPackage && !in_array($packageName, array('nothing', 'lock'))) { $this->io->writeError('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.</warning>'); } foreach ($depPackages as $depPackage) { $packageQueue->enqueue($depPackage); } while (!$packageQueue->isEmpty()) { $package = $packageQueue->dequeue(); if (isset($seen[$package->getId()])) { continue; } $seen[$package->getId()] = true; $this->updateWhitelist[$package->getName()] = true; if (!$this->whitelistDependencies) { continue; } $requires = $package->getRequires(); foreach ($requires as $require) { $requirePackages = $pool->whatProvides($require->getTarget()); foreach ($requirePackages as $requirePackage) { if (isset($skipPackages[$requirePackage->getName()])) { continue; } $packageQueue->enqueue($requirePackage); } } } } }
protected function installRootPackage(IOInterface $io, Config $config, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disablePlugins = false, $noScripts = false, $keepVcs = false, $noProgress = false) { if (null === $repositoryUrl) { $sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config)); } elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION) && file_exists($repositoryUrl)) { $json = new JsonFile($repositoryUrl, new RemoteFilesystem($io, $config)); $data = $json->read(); if (!empty($data['packages']) || !empty($data['includes']) || !empty($data['provider-includes'])) { $sourceRepo = new ComposerRepository(array('url' => 'file://' . strtr(realpath($repositoryUrl), '\\', '/')), $io, $config); } else { $sourceRepo = new FilesystemRepository($json); } } elseif (0 === strpos($repositoryUrl, 'http')) { $sourceRepo = new ComposerRepository(array('url' => $repositoryUrl), $io, $config); } else { throw new \InvalidArgumentException("Invalid repository url given. Has to be a .json file or an http url."); } $parser = new VersionParser(); $requirements = $parser->parseNameVersionPairs(array($packageName)); $name = strtolower($requirements[0]['name']); if (!$packageVersion && isset($requirements[0]['version'])) { $packageVersion = $requirements[0]['version']; } if (null === $stability) { if (preg_match('{^[^,\\s]*?@(' . implode('|', array_keys(BasePackage::$stabilities)) . ')$}i', $packageVersion, $match)) { $stability = $match[1]; } else { $stability = VersionParser::parseStability($packageVersion); } } $stability = VersionParser::normalizeStability($stability); if (!isset(BasePackage::$stabilities[$stability])) { throw new \InvalidArgumentException('Invalid stability provided (' . $stability . '), must be one of: ' . implode(', ', array_keys(BasePackage::$stabilities))); } $pool = new Pool($stability); $pool->addRepository($sourceRepo); // find the latest version if there are multiple $versionSelector = new VersionSelector($pool); $package = $versionSelector->findBestCandidate($name, $packageVersion); if (!$package) { throw new \InvalidArgumentException("Could not find package {$name}" . ($packageVersion ? " with version {$packageVersion}." : " with stability {$stability}.")); } if (null === $directory) { $parts = explode("/", $name, 2); $directory = getcwd() . DIRECTORY_SEPARATOR . array_pop($parts); } // handler Ctrl+C for unix-like systems if (function_exists('pcntl_signal')) { declare (ticks=100); pcntl_signal(SIGINT, function () use($directory) { $fs = new Filesystem(); $fs->removeDirectory($directory); exit(130); }); } $io->writeError('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>'); if ($disablePlugins) { $io->writeError('<info>Plugins have been disabled.</info>'); } if (0 === strpos($package->getPrettyVersion(), 'dev-') && in_array($package->getSourceType(), array('git', 'hg'))) { $package->setSourceReference(substr($package->getPrettyVersion(), 4)); } $dm = $this->createDownloadManager($io, $config); $dm->setPreferSource($preferSource)->setPreferDist($preferDist)->setOutputProgress(!$noProgress); $projectInstaller = new ProjectInstaller($directory, $dm); $im = $this->createInstallationManager(); $im->addInstaller($projectInstaller); $im->install(new InstalledFilesystemRepository(new JsonFile('php://memory')), new InstallOperation($package)); $im->notifyInstalls(); $installedFromVcs = 'source' === $package->getInstallationSource(); $io->writeError('<info>Created project in ' . $directory . '</info>'); chdir($directory); $_SERVER['COMPOSER_ROOT_VERSION'] = $package->getPrettyVersion(); putenv('COMPOSER_ROOT_VERSION=' . $_SERVER['COMPOSER_ROOT_VERSION']); return $installedFromVcs; }
/** * Adds all dependencies of the update whitelist to the whitelist, too. * * Packages which are listed as requirements in the root package will be * skipped including their dependencies, unless they are listed in the * update whitelist themselves. * * @param RepositoryInterface $localRepo * @param boolean $devMode * @param array $rootRequires An array of links to packages in require of the root package * @param array $rootDevRequires An array of links to packages in require-dev of the root package */ private function whitelistUpdateDependencies($localRepo, $devMode, array $rootRequires, array $rootDevRequires) { if (!$this->updateWhitelist) { return; } $requiredPackageNames = array(); foreach (array_merge($rootRequires, $rootDevRequires) as $require) { $requiredPackageNames[] = $require->getTarget(); } if ($devMode) { $rootRequires = array_merge($rootRequires, $rootDevRequires); } $skipPackages = array(); foreach ($rootRequires as $require) { $skipPackages[$require->getTarget()] = true; } $pool = new Pool(); $pool->addRepository($localRepo); $seen = array(); foreach ($this->updateWhitelist as $packageName => $void) { $packageQueue = new \SplQueue(); $depPackages = $pool->whatProvides($packageName); if (count($depPackages) == 0 && !in_array($packageName, $requiredPackageNames) && !in_array($packageName, array('nothing', 'lock'))) { $this->io->write('<warning>Package "' . $packageName . '" listed for update is not installed. Ignoring.<warning>'); } foreach ($depPackages as $depPackage) { $packageQueue->enqueue($depPackage); } while (!$packageQueue->isEmpty()) { $package = $packageQueue->dequeue(); if (isset($seen[$package->getId()])) { continue; } $seen[$package->getId()] = true; $this->updateWhitelist[$package->getName()] = true; $requires = $package->getRequires(); if ($devMode) { $requires = array_merge($requires, $package->getDevRequires()); } foreach ($requires as $require) { $requirePackages = $pool->whatProvides($require->getTarget()); foreach ($requirePackages as $requirePackage) { if (isset($skipPackages[$requirePackage->getName()])) { continue; } $packageQueue->enqueue($requirePackage); } } } } }
/** * Register a plugin package, activate it etc. * * If it's of type composer-installer it is registered as an installer * instead for BC * * @param PackageInterface $package * @param bool $failOnMissingClasses By default this silently skips plugins that can not be found, but if set to true it fails with an exception * * @throws \UnexpectedValueException */ public function registerPackage(PackageInterface $package, $failOnMissingClasses = false) { if ($this->disablePlugins) { return; } if ($package->getType() === 'composer-plugin') { $requiresComposer = null; foreach ($package->getRequires() as $link) { /** @var Link $link */ if ('composer-plugin-api' === $link->getTarget()) { $requiresComposer = $link->getConstraint(); break; } } if (!$requiresComposer) { throw new \RuntimeException("Plugin " . $package->getName() . " is missing a require statement for a version of the composer-plugin-api package."); } $currentPluginApiVersion = $this->getPluginApiVersion(); $currentPluginApiConstraint = new Constraint('==', $this->versionParser->normalize($currentPluginApiVersion)); if ($requiresComposer->getPrettyString() === '1.0.0' && $this->getPluginApiVersion() === '1.0.0') { $this->io->writeError('<warning>The "' . $package->getName() . '" plugin requires composer-plugin-api 1.0.0, this *WILL* break in the future and it should be fixed ASAP (require ^1.0 for example).</warning>'); } elseif (!$requiresComposer->matches($currentPluginApiConstraint)) { $this->io->writeError('<warning>The "' . $package->getName() . '" plugin was skipped because it requires a Plugin API version ("' . $requiresComposer->getPrettyString() . '") that does not match your Composer installation ("' . $currentPluginApiVersion . '"). You may need to run composer update with the "--no-plugins" option.</warning>'); return; } } $oldInstallerPlugin = $package->getType() === 'composer-installer'; if (in_array($package->getName(), $this->registeredPlugins)) { return; } $extra = $package->getExtra(); if (empty($extra['class'])) { throw new \UnexpectedValueException('Error while installing ' . $package->getPrettyName() . ', composer-plugin packages should have a class defined in their extra key to be usable.'); } $classes = is_array($extra['class']) ? $extra['class'] : array($extra['class']); $localRepo = $this->composer->getRepositoryManager()->getLocalRepository(); $globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null; $pool = new Pool('dev'); $pool->addRepository($localRepo); if ($globalRepo) { $pool->addRepository($globalRepo); } $autoloadPackages = array($package->getName() => $package); $autoloadPackages = $this->collectDependencies($pool, $autoloadPackages, $package); $generator = $this->composer->getAutoloadGenerator(); $autoloads = array(); foreach ($autoloadPackages as $autoloadPackage) { $downloadPath = $this->getInstallPath($autoloadPackage, $globalRepo && $globalRepo->hasPackage($autoloadPackage)); $autoloads[] = array($autoloadPackage, $downloadPath); } $map = $generator->parseAutoloads($autoloads, new Package('dummy', '1.0.0.0', '1.0.0')); $classLoader = $generator->createLoader($map); $classLoader->register(); foreach ($classes as $class) { if (class_exists($class, false)) { $code = file_get_contents($classLoader->findFile($class)); $code = preg_replace('{^((?:final\\s+)?(?:\\s*))class\\s+(\\S+)}mi', '$1class $2_composer_tmp' . self::$classCounter, $code); eval('?>' . $code); $class .= '_composer_tmp' . self::$classCounter; self::$classCounter++; } if ($oldInstallerPlugin) { $installer = new $class($this->io, $this->composer); $this->composer->getInstallationManager()->addInstaller($installer); } elseif (class_exists($class)) { $plugin = new $class(); $this->addPlugin($plugin); $this->registeredPlugins[] = $package->getName(); } elseif ($failOnMissingClasses) { throw new \UnexpectedValueException('Plugin ' . $package->getName() . ' could not be initialized, class not found: ' . $class); } } }
public function testPreferReplacingPackageFromSameVendor() { // test with default order $this->repo->addPackage($packageB = $this->getPackage('vendor-b/replacer', '1.0')); $this->repo->addPackage($packageA = $this->getPackage('vendor-a/replacer', '1.0')); $packageA->setReplaces(array(new Link('vendor-a/replacer', 'vendor-a/package', new Constraint('==', '1.0'), 'replaces'))); $packageB->setReplaces(array(new Link('vendor-b/replacer', 'vendor-a/package', new Constraint('==', '1.0'), 'replaces'))); $this->pool->addRepository($this->repo); $literals = array($packageA->getId(), $packageB->getId()); $expected = $literals; $selected = $this->policy->selectPreferredPackages($this->pool, array(), $literals, 'vendor-a/package'); $this->assertEquals($expected, $selected); // test with reversed order in repo $repo = new ArrayRepository(); $repo->addPackage($packageA = clone $packageA); $repo->addPackage($packageB = clone $packageB); $pool = new Pool('dev'); $pool->addRepository($this->repo); $literals = array($packageA->getId(), $packageB->getId()); $expected = $literals; $selected = $this->policy->selectPreferredPackages($this->pool, array(), $literals, 'vendor-a/package'); $this->assertEquals($expected, $selected); }