/** * 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; }
/** * @param bool $ignorePlatformReqs */ protected function checkForRootRequireProblems($ignorePlatformReqs) { foreach ($this->jobs as $job) { switch ($job['cmd']) { case 'update': $packages = $this->pool->whatProvides($job['packageName'], $job['constraint']); foreach ($packages as $package) { if (isset($this->installedMap[$package->id])) { $this->updateMap[$package->id] = true; } } break; case 'update-all': foreach ($this->installedMap as $package) { $this->updateMap[$package->id] = true; } break; case 'install': if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) { break; } if (!$this->pool->whatProvides($job['packageName'], $job['constraint'])) { $problem = new Problem($this->pool); $problem->addRule(new Rule(array(), null, null, $job)); $this->problems[] = $problem; } break; } } }
public function testSelectLocalReposFirst() { $repoImportant = new ArrayRepository; $this->repo->addPackage($packageA = $this->getPackage('A', 'dev-master')); $this->repo->addPackage($packageAAlias = new AliasPackage($packageA, '2.1.9999999.9999999-dev', '2.1.x-dev')); $repoImportant->addPackage($packageAImportant = $this->getPackage('A', 'dev-feature-a')); $repoImportant->addPackage($packageAAliasImportant = new AliasPackage($packageAImportant, '2.1.9999999.9999999-dev', '2.1.x-dev')); $repoImportant->addPackage($packageA2Important = $this->getPackage('A', 'dev-master')); $repoImportant->addPackage($packageA2AliasImportant = new AliasPackage($packageA2Important, '2.1.9999999.9999999-dev', '2.1.x-dev')); $packageAAliasImportant->setRootPackageAlias(true); $this->pool->addRepository($this->repoInstalled); $this->pool->addRepository($repoImportant); $this->pool->addRepository($this->repo); $packages = $this->pool->whatProvides('a', new Constraint('=', '2.1.9999999.9999999-dev')); $literals = array(); foreach ($packages as $package) { $literals[] = $package->getId(); } $expected = array($packageAAliasImportant->getId()); $selected = $this->policy->selectPreferredPackages($this->pool, array(), $literals); $this->assertSame($expected, $selected); }
/** * 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()); } }
public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package, $mustMatchName = false) { $packages = array(); foreach ($pool->whatProvides($package->getName(), null, $mustMatchName) as $candidate) { if ($candidate !== $package) { $packages[] = $candidate; } } return $packages; }
public function findUpdatePackages(Solver $solver, Pool $pool, array $installedMap, PackageInterface $package) { $packages = array(); foreach ($pool->whatProvides($package->getName()) as $candidate) { if ($candidate !== $package) { $packages[] = $candidate; } } return $packages; }
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); }
/** * 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; } }
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>'); } }
/** * 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; }
/** * 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; }
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); }
/** * Sets the list of packages to build. * * @param Composer $composer The Composer instance * @param bool $verbose Output infos if true * * @throws \InvalidArgumentException * * @return PackageInterface[] */ public function select(Composer $composer, $verbose) { // run over all packages and store matching ones $this->output->writeln('<info>Scanning packages</info>'); $repos = $composer->getRepositoryManager()->getRepositories(); $pool = new Pool($this->minimumStability); if ($this->hasRepositoryFilter()) { $repos = $this->filterRepositories($repos); } foreach ($repos as $repo) { try { $pool->addRepository($repo); } catch (\Exception $exception) { if (!$this->skipErrors) { throw $exception; } $this->output->writeln(sprintf("<error>Skipping Exception '%s'.</error>", $exception->getMessage())); } } if ($this->hasRepositoryFilter()) { if (count($repos) === 0) { throw new \InvalidArgumentException(sprintf('Specified repository url "%s" does not exist.', $this->repositoryFilter)); } elseif (count($repos) > 1) { throw new \InvalidArgumentException(sprintf('Found more than one repository for url "%s".', $this->repositoryFilter)); } } $links = $this->requireAll ? $this->getAllLinks($repos, $this->minimumStability, $verbose) : $this->getFilteredLinks($composer); // process links if any $depsLinks = array(); $i = 0; while (isset($links[$i])) { $link = $links[$i]; ++$i; $name = $link->getTarget(); $matches = $pool->whatProvides($name, $link->getConstraint(), true); foreach ($matches as $index => $package) { // skip aliases if ($package instanceof AliasPackage) { $package = $package->getAliasOf(); } // add matching package if not yet selected if (!isset($this->selected[$package->getUniqueName()])) { if ($verbose) { $this->output->writeln('Selected ' . $package->getPrettyName() . ' (' . $package->getPrettyVersion() . ')'); } $this->selected[$package->getUniqueName()] = $package; if (!$this->requireAll) { $required = $this->getRequired($package); // append non-platform dependencies foreach ($required as $dependencyLink) { $target = $dependencyLink->getTarget(); if (!preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $target)) { $linkId = $target . ' ' . $dependencyLink->getConstraint(); // prevent loading multiple times the same link if (!isset($depsLinks[$linkId])) { $links[] = $dependencyLink; $depsLinks[$linkId] = true; } } } } } } if (!$matches) { $this->output->writeln('<error>The ' . $name . ' ' . $link->getPrettyConstraint() . ' requirement did not match any package</error>'); } } $this->setSelectedAsAbandoned(); ksort($this->selected, SORT_STRING); return $this->selected; }
/** * 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); } } } } }
private function selectPackages(Composer $composer, OutputInterface $output, $verbose, $requireAll, $requireDependencies, $requireDevDependencies, $minimumStability, $skipErrors, array $packagesFilter = array()) { $selected = array(); // run over all packages and store matching ones $output->writeln('<info>Scanning packages</info>'); $repos = $composer->getRepositoryManager()->getRepositories(); $pool = new Pool($minimumStability); foreach ($repos as $repo) { try { $pool->addRepository($repo); } catch (\Exception $exception) { if (!$skipErrors) { throw $exception; } $output->writeln(sprintf("<error>Skipping Exception '%s'.</error>", $exception->getMessage())); } } if ($requireAll) { $links = array(); $filterForPackages = count($packagesFilter) > 0; foreach ($repos as $repo) { // collect links for composer repos with providers if ($repo instanceof ComposerRepository && $repo->hasProviders()) { foreach ($repo->getProviderNames() as $name) { $links[] = new Link('__root__', $name, new MultiConstraint(array()), 'requires', '*'); } } else { $packages = array(); if ($filterForPackages) { // apply package filter if defined foreach ($packagesFilter as $filter) { $packages += $repo->findPackages($filter); } } else { // process other repos directly $packages = $repo->getPackages(); } foreach ($packages as $package) { // skip aliases if ($package instanceof AliasPackage) { continue; } if ($package->getStability() > BasePackage::$stabilities[$minimumStability]) { continue; } // add matching package if not yet selected if (!isset($selected[$package->getUniqueName()])) { if ($verbose) { $output->writeln('Selected ' . $package->getPrettyName() . ' (' . $package->getPrettyVersion() . ')'); } $selected[$package->getUniqueName()] = $package; } } } } } else { $links = array_values($composer->getPackage()->getRequires()); // only pick up packages in our filter, if a filter has been set. if (count($packagesFilter) > 0) { $links = array_filter($links, function (Link $link) use($packagesFilter) { return in_array($link->getTarget(), $packagesFilter); }); } $links = array_values($links); } // process links if any $depsLinks = array(); $i = 0; while (isset($links[$i])) { $link = $links[$i]; $i++; $name = $link->getTarget(); $matches = $pool->whatProvides($name, $link->getConstraint(), true); foreach ($matches as $index => $package) { // skip aliases if ($package instanceof AliasPackage) { $package = $package->getAliasOf(); } // add matching package if not yet selected if (!isset($selected[$package->getUniqueName()])) { if ($verbose) { $output->writeln('Selected ' . $package->getPrettyName() . ' (' . $package->getPrettyVersion() . ')'); } $selected[$package->getUniqueName()] = $package; if (!$requireAll) { $required = array(); if ($requireDependencies) { $required = $package->getRequires(); } if ($requireDevDependencies) { $required = array_merge($required, $package->getDevRequires()); } // append non-platform dependencies foreach ($required as $dependencyLink) { $target = $dependencyLink->getTarget(); if (!preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $target)) { $linkId = $target . ' ' . $dependencyLink->getConstraint(); // prevent loading multiple times the same link if (!isset($depsLinks[$linkId])) { $links[] = $dependencyLink; $depsLinks[$linkId] = true; } } } } } } if (!$matches) { $output->writeln('<error>The ' . $name . ' ' . $link->getPrettyConstraint() . ' requirement did not match any package</error>'); } } ksort($selected, SORT_STRING); return $selected; }
/** * 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); } } } } }
/** * 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); } } } } }
/** * Resolves a package link to a package in the installed pool * * Since dependencies are already installed this should always find one. * * @param Pool $pool Pool of installed packages only * @param Link $link Package link to look up * * @return PackageInterface|null The found package */ private function lookupInstalledPackage(Pool $pool, Link $link) { $packages = $pool->whatProvides($link->getTarget(), $link->getConstraint()); return !empty($packages) ? $packages[0] : null; }
protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null) { $name = strtolower($name); $constraint = null; if ($version) { $constraint = $this->versionParser->parseConstraints($version); } $policy = new DefaultPolicy(); $pool = new Pool('dev'); $pool->addRepository($repos); $matchedPackage = null; $versions = array(); $matches = $pool->whatProvides($name, $constraint); foreach ($matches as $index => $package) { // skip providers/replacers if ($package->getName() !== $name) { unset($matches[$index]); continue; } // select an exact match if it is in the installed repo and no specific version was required if (null === $version && $installedRepo->hasPackage($package)) { $matchedPackage = $package; } $versions[$package->getPrettyVersion()] = $package->getVersion(); $matches[$index] = $package->getId(); } // select prefered package according to policy rules if (!$matchedPackage && $matches && ($prefered = $policy->selectPreferedPackages($pool, array(), $matches))) { $matchedPackage = $pool->literalToPackage($prefered[0]); } return array($matchedPackage, $versions); }
public function testWhatProvidesWhenPackageCannotBeFound() { $pool = new Pool(); $this->assertEquals(array(), $pool->whatProvides('foo')); }
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); }
/** * @param string $packageName * @param ConstraintInterface|NULL $constraint * @return \Composer\Package\PackageInterface[] */ private function getVersions($packageName, ConstraintInterface $constraint = NULL) { return $this->pool->whatProvides($packageName, $constraint, TRUE); }
protected function installRootPackage(IOInterface $io, $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)) { $sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl, new RemoteFilesystem($io))); } 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(); $candidates = array(); $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); $constraint = $packageVersion ? $parser->parseConstraints($packageVersion) : null; $candidates = $pool->whatProvides($name, $constraint); foreach ($candidates as $key => $candidate) { if ($candidate->getName() !== $name) { unset($candidates[$key]); } } if (!$candidates) { 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); } $package = reset($candidates); foreach ($candidates as $candidate) { if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) { $package = $candidate; } } unset($candidates); $io->write('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>'); if ($disablePlugins) { $io->write('<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->write('<info>Created project in ' . $directory . '</info>'); chdir($directory); putenv('COMPOSER_ROOT_VERSION=' . $package->getPrettyVersion()); return $installedFromVcs; }
private function selectPackages(Composer $composer, OutputInterface $output, $verbose, $requireAll, $requireDependencies) { $selected = array(); // run over all packages and store matching ones $output->writeln('<info>Scanning packages</info>'); $repos = $composer->getRepositoryManager()->getRepositories(); $pool = new Pool('dev'); foreach ($repos as $repo) { $pool->addRepository($repo); } if ($requireAll) { $links = array(); foreach ($repos as $repo) { // collect links for composer repos with providers if ($repo instanceof ComposerRepository && $repo->hasProviders()) { foreach ($repo->getProviderNames() as $name) { $links[] = new Link('__root__', $name, new MultiConstraint(array()), 'requires', '*'); } } else { // process other repos directly foreach ($repo->getPackages() as $package) { // skip aliases if ($package instanceof AliasPackage) { continue; } // add matching package if not yet selected if (!isset($selected[$package->getUniqueName()])) { if ($verbose) { $output->writeln('Selected ' . $package->getPrettyName() . ' (' . $package->getPrettyVersion() . ')'); } $selected[$package->getUniqueName()] = $package; } } } } } else { $links = array_values($composer->getPackage()->getRequires()); } // process links if any $depsLinks = array(); $i = 0; while (isset($links[$i])) { $link = $links[$i]; $i++; $name = $link->getTarget(); $matches = $pool->whatProvides($name, $link->getConstraint()); foreach ($matches as $index => $package) { // skip aliases if ($package instanceof AliasPackage) { $package = $package->getAliasOf(); } // add matching package if not yet selected if (!isset($selected[$package->getUniqueName()])) { if ($verbose) { $output->writeln('Selected ' . $package->getPrettyName() . ' (' . $package->getPrettyVersion() . ')'); } $selected[$package->getUniqueName()] = $package; if (!$requireAll && $requireDependencies) { // append non-platform dependencies foreach ($package->getRequires() as $dependencyLink) { $target = $dependencyLink->getTarget(); if (!preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $target)) { $linkId = $target . ' ' . $dependencyLink->getConstraint(); // prevent loading multiple times the same link if (!isset($depsLinks[$linkId])) { $links[] = $dependencyLink; $depsLinks[$linkId] = true; } } } } } } if (!$matches) { $output->writeln('<error>The ' . $name . ' ' . $link->getPrettyConstraint() . ' requirement did not match any package</error>'); } } ksort($selected, SORT_STRING); return $selected; }
public function installProject(IOInterface $io, $packageName, $directory = null, $packageVersion = null, $stability = 'stable', $preferSource = false, $preferDist = false, $installDevPackages = false, $repositoryUrl = null, $disableCustomInstallers = false, $noScripts = false, $keepVcs = false) { $config = Factory::createConfig(); $stability = strtolower($stability); if ($stability === 'rc') { $stability = 'RC'; } if (!isset(BasePackage::$stabilities[$stability])) { throw new \InvalidArgumentException('Invalid stability provided (' . $stability . '), must be one of: ' . implode(', ', array_keys(BasePackage::$stabilities))); } if (null === $repositoryUrl) { $sourceRepo = new CompositeRepository(Factory::createDefaultRepositories($io, $config)); } elseif ("json" === pathinfo($repositoryUrl, PATHINFO_EXTENSION)) { $sourceRepo = new FilesystemRepository(new JsonFile($repositoryUrl, new RemoteFilesystem($io))); } 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(); $candidates = array(); $requirements = $parser->parseNameVersionPairs(array($packageName)); $name = strtolower($requirements[0]['name']); if (!$packageVersion && isset($requirements[0]['version'])) { $packageVersion = $requirements[0]['version']; } $pool = new Pool($packageVersion ? 'dev' : $stability); $pool->addRepository($sourceRepo); $constraint = $packageVersion ? new VersionConstraint('=', $parser->normalize($packageVersion)) : null; $candidates = $pool->whatProvides($name, $constraint); foreach ($candidates as $key => $candidate) { if ($candidate->getName() !== $name) { unset($candidates[$key]); } } if (!$candidates) { 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); } // select highest version if we have many $package = $candidates[0]; foreach ($candidates as $candidate) { if (version_compare($package->getVersion(), $candidate->getVersion(), '<')) { $package = $candidate; } } unset($candidates); $io->write('<info>Installing ' . $package->getName() . ' (' . VersionParser::formatVersion($package, false) . ')</info>'); if ($disableCustomInstallers) { $io->write('<info>Custom installers 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); $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->write('<info>Created project in ' . $directory . '</info>'); chdir($directory); putenv('COMPOSER_ROOT_VERSION=' . $package->getPrettyVersion()); // clean up memory unset($dm, $im, $config, $projectInstaller, $sourceRepo, $package); // install dependencies of the created project $composer = Factory::create($io); $installer = Installer::create($io, $composer); $installer->setPreferSource($preferSource)->setPreferDist($preferDist)->setDevMode($installDevPackages)->setRunScripts(!$noScripts); if ($disableCustomInstallers) { $installer->disableCustomInstallers(); } if (!$installer->run()) { return 1; } if (!$keepVcs && $installedFromVcs && (!$io->isInteractive() || $io->askConfirmation('<info>Do you want to remove the existing VCS (.git, .svn..) history?</info> [<comment>Y,n</comment>]? ', true))) { $finder = new Finder(); $finder->depth(0)->directories()->in(getcwd())->ignoreVCS(false)->ignoreDotFiles(false); foreach (array('.svn', '_svn', 'CVS', '_darcs', '.arch-params', '.monotone', '.bzr', '.git', '.hg') as $vcsName) { $finder->name($vcsName); } try { $fs = new Filesystem(); $dirs = iterator_to_array($finder); unset($finder); foreach ($dirs as $dir) { if (!$fs->removeDirectory($dir)) { throw new \RuntimeException('Could not remove ' . $dir); } } } catch (\Exception $e) { $io->write('<error>An error occurred while removing the VCS metadata: ' . $e->getMessage() . '</error>'); } } return 0; }
/** * Finds a package by name and version if provided. * * @param RepositoryInterface $installedRepo * @param RepositoryInterface $repos * @param string $name * @param string|null $version * * @throws \InvalidArgumentException * * @return array [CompletePackageInterface, array of versions] */ protected function getPackage(RepositoryInterface $installedRepo, RepositoryInterface $repos, $name, $version = null) { $name = strtolower($name); $constraint = null; if ($version !== null) { $constraint = $this->versionParser->parseConstraints($version); } $policy = new DefaultPolicy(); $pool = new Pool('dev'); $pool->addRepository($repos); $matchedPackage = null; $versions = []; $matches = $pool->whatProvides($name, $constraint); foreach ($matches as $index => $package) { // Skip providers/replacers. if ($package->getName() !== $name) { unset($matches[$index]); continue; } // Select an exact match if it is in the installed repo and no specific version was required. if ($version === null && $installedRepo->hasPackage($package)) { $matchedPackage = $package; } $versions[$package->getPrettyVersion()] = $package->getVersion(); $matches[$index] = $package->getId(); } // Select prefered package according to policy rules. if (!$matchedPackage && !empty($matches) && ($prefered = $policy->selectPreferredPackages($pool, [], $matches))) { $matchedPackage = $pool->literalToPackage($prefered[0]); } // If we have package result, return them. if ($matchedPackage) { return [$matchedPackage->getName() => ['package' => $matchedPackage, 'versions' => $versions]]; } return null; }
public function checkUpdates(Event $event) { $root = $this->composer->getPackage(); $output = $event->getIO(); $repoManager = $this->composer->getRepositoryManager(); $output->write(''); $output->write('Checking for available updates'); $platformRepo = new PlatformRepository(); $globalPool = new Pool($root->getMinimumStability(), $root->getStabilityFlags()); $globalPool->addRepository($platformRepo); foreach ($repoManager->getRepositories() as $repo) { $globalPool->addRepository($repo); } $localPool = new Pool($root->getMinimumStability(), $root->getStabilityFlags()); $localRepo = $repoManager->getLocalRepository(); $localPool->addRepository($platformRepo); if ($localRepo) { $localPool->addRepository($repoManager->getLocalRepository()); } else { foreach ($repoManager->getRepositories() as $repo) { $localPool->addRepository($repo); } } $output->write(str_repeat('-', 80)); $this->writeRow($output, 'Package', 'Require', 'Current', 'Update', 'Latest', $color = false); $output->write(str_repeat('-', 80)); foreach ($this->getRequires() as $require) { $constraint = $require->getConstraint(); $packagesCurrent = $localPool->whatProvides($require->getTarget(), $constraint, $mustMatchName = true); if (!$packagesCurrent) { $output->write(sprintf('<fg=red>!!!</> <info>%s</info> package not found', $require->getTarget())); continue; } $packageCurrent = $packagesCurrent ? $packagesCurrent[0] : null; $packagesConstrained = $globalPool->whatProvides($require->getTarget(), $constraint, $mustMatchName = true); if (!$packagesConstrained) { $output->write(sprintf('<fg=red>!!!</> <info>%s</info> global package not found (constrained)', $require->getTarget())); continue; } $this->sortPackages($packagesConstrained); $packageConstrained = end($packagesConstrained); $packagesLatest = $globalPool->whatProvides($require->getTarget(), null, $mustMatchName = true); if (!$packagesLatest) { $output->write(sprintf('<fg=red>!!!</> <info>%s</info> global package not found (un-constrained)', $require->getTarget())); continue; } $this->sortPackages($packagesLatest); $packageLatest = end($packagesLatest); $requiredVersion = $constraint->getPrettyString(); $currentVersion = $packageCurrent->getPrettyVersion(); $constrainedVersion = $packageConstrained->getPrettyVersion(); $latestVersion = $packageLatest->getPrettyVersion(); if ($packageCurrent->isDev()) { $currentVersion = substr($packageCurrent->getDistReference(), 0, 10); $constrainedVersion = substr($packageConstrained->getDistReference(), 0, 10); $latestVersion = substr($packageLatest->getDistReference(), 0, 10); } $this->writeRow($output, $require->getTarget(), $requiredVersion, $currentVersion, $constrainedVersion, $latestVersion); } $output->write(''); }