/** * @param PackageInterface $package * @param bool $allowDevMaster * * @return \string[] */ public function validatePackage(PackageInterface $package, $allowDevMaster = false) { $errors = []; $versionParser = new VersionParser(); /** @noinspection ExceptionsAnnotatingAndHandlingInspection */ $devMaster = new Constraint('==', $versionParser->normalize('dev-master')); foreach ($package->getRequires() as $link) { $linkConstraint = $link->getConstraint(); if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $link->getTarget())) { continue; } if ($linkConstraint->matches($devMaster)) { if ($allowDevMaster) { continue; } $errors[] = sprintf('Package "%s" is required with branch constraint %s', $link->getTarget(), $linkConstraint->getPrettyString()); } $constraints = [$linkConstraint]; if ($linkConstraint instanceof MultiConstraint) { $constraints = (new ConstraintAccessor($linkConstraint))->getConstraints(); } foreach ($constraints as $constraint) { if ('dev-' === substr($constraint->getPrettyString(), 0, 4)) { $errors[] = sprintf('Package "%s" is required with branch constraint %s', $link->getTarget(), $linkConstraint->getPrettyString()); } } } return $errors; }
private function collectLinks($noInstallRecommends, $installSuggests) { $links = $this->package->getRequires(); if (!$noInstallRecommends) { $links = array_merge($links, $this->package->getRecommends()); } if ($installSuggests) { $links = array_merge($links, $this->package->getSuggests()); } return $links; }
/** * @param \Composer\IO\IOInterface $io * @param \Composer\Package\PackageInterface $package * @return bool */ public static function checkDependencies(IOInterface $io, PackageInterface $package) { $search = 'wp-cli/wp-cli'; $requires = $package->getRequires(); $requiresDev = $package->getDevRequires(); if (isset($requires[$search]) or isset($requiresDev[$search])) { return true; } $io->writeError('<info>This package is a dependency of `wp-cli/wp-cli`. Skipping.</info>'); return false; }
protected function collectDependencies(Pool $pool, array $collected, PackageInterface $package) { $requires = array_merge($package->getRequires(), $package->getDevRequires()); foreach ($requires as $requireLink) { $requiredPackage = $this->lookupInstalledPackage($pool, $requireLink); if ($requiredPackage && !isset($collected[$requiredPackage->getName()])) { $collected[$requiredPackage->getName()] = $requiredPackage; $collected = $this->collectDependencies($pool, $collected, $requiredPackage); } } return $collected; }
private function filterRequiredPackages(RepositoryInterface $repo, PackageInterface $package, $bucket = array()) { $requires = array_keys($package->getRequires()); $packageListNames = array_keys($bucket); $packages = array_filter($repo->getPackages(), function ($package) use($requires, $packageListNames) { return in_array($package->getName(), $requires) && !in_array($package->getName(), $packageListNames); }); $bucket = $this->appendPackages($packages, $bucket); foreach ($packages as $package) { $bucket = $this->filterRequiredPackages($repo, $package, $bucket); } return $bucket; }
/** * Indicate whether a package has the target package as a dependency * * @param PackageInterface $package * @param bool $devMode * @return bool */ private function isDependentPackage(PackageInterface $package, $devMode = false) { $packages = $package->getRequires(); if ($devMode) { $packages = array_merge($packages, $package->getDevRequires()); } foreach ($packages as $link) { /** @var \Composer\Package\Link $link */ if ($this->targetPackage === $link->getTarget()) { return true; } } return false; }
/** * Build the dependency graph with installed packages. * * @param RepositoryInterface $repository * @param PackageInterface $package * @param array $dependencyGraph */ protected function buildDependencyGraph(array $localPackages, RepositoryInterface $repository, PackageInterface $package, $requiredFrom, $requiredConstraint, array &$dependencyGraph, $isLast, $parents = 0, $stack = array()) { $current = (object) array('package' => $package, 'required' => (object) array('from' => $requiredFrom, 'constraint' => $requiredConstraint, 'parents' => $parents), 'lastInLevel' => $isLast ? $parents - 1 : -1); if (in_array($package->getName(), $stack)) { $current->recursion = true; $dependencyGraph[] = $current; return; } $dependencyGraph[] = $current; $stack[] = $package->getName(); $requires = $package->getRequires(); $requiresCount = count($requires); $index = 0; /** @var string $requireName */ /** @var \Composer\Package\Link $requireLink */ foreach ($requires as $requireName => $requireLink) { if (isset($localPackages[$requireName])) { $this->buildDependencyGraph($localPackages, $repository, $localPackages[$requireName], $package, $requireLink->getPrettyConstraint(), $dependencyGraph, ++$index == $requiresCount, $parents + 1, $stack); } else { $dependencyGraph[] = (object) array('package' => $requireName, 'required' => (object) array('from' => $package, 'constraint' => $requireLink->getPrettyConstraint(), 'parents' => $parents + 1), 'lastInLevel' => ++$index == $requiresCount ? $parents : -1); } } }
/** * Returns true if the supplied package requires the Composer Grunt bridge. * * @param PackageInterface $package The package to inspect. * @param boolean|null $includeDevDependencies True if the dev dependencies should also be inspected. * * @return boolean True if the package requires the bridge. */ public function isDependantPackage(PackageInterface $package, $includeDevDependencies = null) { if (null === $includeDevDependencies) { $includeDevDependencies = false; } foreach ($package->getRequires() as $link) { if ('johnpbloch/composer-grunt-bridge' === $link->getTarget()) { return true; } } if ($includeDevDependencies) { foreach ($package->getDevRequires() as $link) { if ('johnpbloch/composer-grunt-bridge' === $link->getTarget()) { return true; } } } return false; }
/** * Search for dependencies in this package. * * @param PackageInterface $package The package to search in. * * @return void */ private function searchInPackage(PackageInterface $package) { $this->progress->advance(); if ($package instanceof AliasPackage || $this->searchInDevReleases && !$package->isDev() || $this->searchInReleases && $package->isDev()) { return; } $this->progress->setMessage($package->getName()); $requires = $package->getRequires(); $this->searchInRequires($package, 'prod', $requires); $requires = $package->getDevRequires(); $this->searchInRequires($package, 'dev', $requires); }
protected function doInstall($localRepo, $installedRepo, $aliases, $devMode = false) { $minimumStability = $this->package->getMinimumStability(); $stabilityFlags = $this->package->getStabilityFlags(); // initialize locker to create aliased packages if (!$this->update && $this->locker->isLocked($devMode)) { $lockedPackages = $this->locker->getLockedPackages($devMode); $minimumStability = $this->locker->getMinimumStability(); $stabilityFlags = $this->locker->getStabilityFlags(); } $this->whitelistUpdateDependencies($localRepo, $devMode, $this->package->getRequires(), $this->package->getDevRequires()); $this->io->write('<info>Loading composer repositories with package information</info>'); // creating repository pool $pool = new Pool($minimumStability, $stabilityFlags); $pool->addRepository($installedRepo); foreach ($this->repositoryManager->getRepositories() as $repository) { $pool->addRepository($repository); } // creating requirements request $installFromLock = false; $request = new Request($pool); $constraint = new VersionConstraint('=', $this->package->getVersion()); $request->install($this->package->getName(), $constraint); if ($this->update) { $this->io->write('<info>Updating ' . ($devMode ? 'dev ' : '') . 'dependencies</info>'); $request->updateAll(); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } elseif ($this->locker->isLocked($devMode)) { $installFromLock = true; $this->io->write('<info>Installing ' . ($devMode ? 'dev ' : '') . 'dependencies from lock file</info>'); if (!$this->locker->isFresh() && !$devMode) { $this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>'); } foreach ($lockedPackages as $package) { $version = $package->getVersion(); foreach ($aliases as $alias) { if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) { $version = $alias['alias_normalized']; break; } } $constraint = new VersionConstraint('=', $version); $request->install($package->getName(), $constraint); } } else { $this->io->write('<info>Installing ' . ($devMode ? 'dev ' : '') . 'dependencies</info>'); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } // fix the version of all installed packages (+ platform) that are not // in the current local repo to prevent rogue updates (e.g. non-dev // updating when in dev) foreach ($installedRepo->getPackages() as $package) { if ($package->getRepository() === $localRepo) { continue; } $constraint = new VersionConstraint('=', $package->getVersion()); $request->install($package->getName(), $constraint); } // if the updateWhitelist is enabled, packages not in it are also fixed // to the version specified in the lock, or their currently installed version if ($this->update && $this->updateWhitelist) { if ($this->locker->isLocked($devMode)) { $currentPackages = $this->locker->getLockedPackages($devMode); } else { $currentPackages = $installedRepo->getPackages(); } // collect links from composer as well as installed packages $candidates = array(); foreach ($links as $link) { $candidates[$link->getTarget()] = true; } foreach ($localRepo->getPackages() as $package) { $candidates[$package->getName()] = true; } // fix them to the version in lock (or currently installed) if they are not updateable foreach ($candidates as $candidate => $dummy) { foreach ($currentPackages as $curPackage) { if ($curPackage->getName() === $candidate) { if ($this->isUpdateable($curPackage)) { break; } $constraint = new VersionConstraint('=', $curPackage->getVersion()); $request->install($curPackage->getName(), $constraint); } } } } // prepare solver $policy = new DefaultPolicy(); $solver = new Solver($policy, $pool, $installedRepo); // solve dependencies try { $operations = $solver->solve($request); } catch (SolverProblemsException $e) { $this->io->write('<error>Your requirements could not be resolved to an installable set of packages.</error>'); $this->io->write($e->getMessage()); return false; } // force dev packages to be updated if we update or install from a (potentially new) lock foreach ($localRepo->getPackages() as $package) { // skip non-dev packages if (!$package->isDev()) { continue; } // skip packages that will be updated/uninstalled foreach ($operations as $operation) { if ('update' === $operation->getJobType() && $operation->getInitialPackage()->equals($package) || 'uninstall' === $operation->getJobType() && $operation->getPackage()->equals($package)) { continue 2; } } // force update to locked version if it does not match the installed version if ($installFromLock) { $lockData = $this->locker->getLockData(); unset($lockedReference); foreach ($lockData['packages'] as $lockedPackage) { if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { $lockedReference = $lockedPackage['source-reference']; break; } } if (isset($lockedReference) && $lockedReference !== $package->getSourceReference()) { // changing the source ref to update to will be handled in the operations loop below $operations[] = new UpdateOperation($package, clone $package); } } else { // force update to latest on update if ($this->update) { // skip package if the whitelist is enabled and it is not in it if ($this->updateWhitelist && !$this->isUpdateable($package)) { continue; } $newPackage = $this->repositoryManager->findPackage($package->getName(), $package->getVersion()); if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) { $operations[] = new UpdateOperation($package, $newPackage); } } // force installed package to update to referenced version if it does not match the installed version $references = $this->package->getReferences(); if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) { // changing the source ref to update to will be handled in the operations loop below $operations[] = new UpdateOperation($package, clone $package); } } } // execute operations if (!$operations) { $this->io->write('Nothing to install or update'); } foreach ($operations as $operation) { // collect suggestions if ('install' === $operation->getJobType()) { foreach ($operation->getPackage()->getSuggests() as $target => $reason) { $this->suggestedPackages[] = array('source' => $operation->getPackage()->getPrettyName(), 'target' => $target, 'reason' => $reason); } } $event = 'Composer\\Script\\ScriptEvents::PRE_PACKAGE_' . strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { $this->eventDispatcher->dispatchPackageEvent(constant($event), $operation); } // if installing from lock, restore dev packages' references to their locked state if ($installFromLock) { $package = null; if ('update' === $operation->getJobType()) { $package = $operation->getTargetPackage(); } elseif ('install' === $operation->getJobType()) { $package = $operation->getPackage(); } if ($package && $package->isDev()) { $lockData = $this->locker->getLockData(); foreach ($lockData['packages'] as $lockedPackage) { if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { // update commit date to allow recovery in case the commit disappeared if (!empty($lockedPackage['commit-date'])) { $package->setReleaseDate(new \DateTime('@' . $lockedPackage['commit-date'])); } $package->setSourceReference($lockedPackage['source-reference']); break; } } } } else { // not installing from lock, force dev packages' references if they're in root package refs $package = null; if ('update' === $operation->getJobType()) { $package = $operation->getTargetPackage(); } elseif ('install' === $operation->getJobType()) { $package = $operation->getPackage(); } if ($package && $package->isDev()) { $references = $this->package->getReferences(); if (isset($references[$package->getName()])) { $package->setSourceReference($references[$package->getName()]); } } } // output alias operations in verbose mode, or all ops in dry run if ($this->dryRun || $this->verbose && false !== strpos($operation->getJobType(), 'Alias')) { $this->io->write(' - ' . $operation); } $this->installationManager->execute($localRepo, $operation); $event = 'Composer\\Script\\ScriptEvents::POST_PACKAGE_' . strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { $this->eventDispatcher->dispatchPackageEvent(constant($event), $operation); } if (!$this->dryRun) { $localRepo->write(); } } return true; }
/** * Gets the required Links if needed. * * @param PackageInterface $package A package * * @return Link[] */ private function getRequired(PackageInterface $package) { $required = array(); if ($this->requireDependencies) { $required = $package->getRequires(); } if ($this->requireDevDependencies) { $required = array_merge($required, $package->getDevRequires()); } return $required; }
protected function doInstall($localRepo, $installedRepo, $aliases, $devMode = false) { // creating repository pool $pool = new Pool(); $pool->addRepository($installedRepo); foreach ($this->repositoryManager->getRepositories() as $repository) { $pool->addRepository($repository); } // creating requirements request $installFromLock = false; $request = new Request($pool); if ($this->update) { $this->io->write('<info>Updating ' . ($devMode ? 'dev ' : '') . 'dependencies</info>'); $request->updateAll(); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } elseif ($this->locker->isLocked($devMode)) { $installFromLock = true; $this->io->write('<info>Installing ' . ($devMode ? 'dev ' : '') . 'dependencies from lock file</info>'); if (!$this->locker->isFresh() && !$devMode) { $this->io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>'); } foreach ($this->locker->getLockedPackages($devMode) as $package) { $version = $package->getVersion(); foreach ($aliases as $alias) { if ($alias['package'] === $package->getName() && $alias['version'] === $package->getVersion()) { $version = $alias['alias']; break; } } $constraint = new VersionConstraint('=', $version); $request->install($package->getName(), $constraint); } } else { $this->io->write('<info>Installing ' . ($devMode ? 'dev ' : '') . 'dependencies</info>'); $links = $devMode ? $this->package->getDevRequires() : $this->package->getRequires(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } // fix the version all installed packages that are not in the current local repo to prevent rogue updates foreach ($installedRepo->getPackages() as $package) { if ($package->getRepository() === $localRepo || $package->getRepository() instanceof PlatformRepository) { continue; } $constraint = new VersionConstraint('=', $package->getVersion()); $request->install($package->getName(), $constraint); } // prepare solver $policy = new DefaultPolicy(); $solver = new Solver($policy, $pool, $installedRepo); // solve dependencies try { $operations = $solver->solve($request); } catch (SolverProblemsException $e) { $this->io->write('<error>Your requirements could not be solved to an installable set of packages.</error>'); $this->io->write($e->getMessage()); return false; } // force dev packages to be updated if we update or install from a (potentially new) lock if ($this->update || $installFromLock) { foreach ($localRepo->getPackages() as $package) { // skip non-dev packages if (!$package->isDev()) { continue; } // skip packages that will be updated/uninstalled foreach ($operations as $operation) { if ('update' === $operation->getJobType() && $operation->getInitialPackage()->equals($package) || 'uninstall' === $operation->getJobType() && $operation->getPackage()->equals($package)) { continue 2; } } // force update to latest on update if ($this->update) { $newPackage = $this->repositoryManager->findPackage($package->getName(), $package->getVersion()); if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) { $operations[] = new UpdateOperation($package, $newPackage); } } elseif ($installFromLock) { // force update to locked version if it does not match the installed version $lockData = $this->locker->getLockData(); unset($lockedReference); foreach ($lockData['packages'] as $lockedPackage) { if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { $lockedReference = $lockedPackage['source-reference']; break; } } if (isset($lockedReference) && $lockedReference !== $package->getSourceReference()) { // changing the source ref to update to will be handled in the operations loop below $operations[] = new UpdateOperation($package, $package); } } } } // anti-alias local repository to allow updates to work fine foreach ($localRepo->getPackages() as $package) { if ($package instanceof AliasPackage) { $package->getRepository()->addPackage(clone $package->getAliasOf()); $package->getRepository()->removePackage($package); } } // execute operations if (!$operations) { $this->io->write('Nothing to install or update'); } foreach ($operations as $operation) { if ($this->verbose) { $this->io->write((string) $operation); } // collect suggestions if ('install' === $operation->getJobType()) { foreach ($operation->getPackage()->getSuggests() as $target => $reason) { $this->suggestedPackages[] = array('source' => $operation->getPackage()->getPrettyName(), 'target' => $target, 'reason' => $reason); } } if (!$this->dryRun) { $this->eventDispatcher->dispatchPackageEvent(constant('Composer\\Script\\ScriptEvents::PRE_PACKAGE_' . strtoupper($operation->getJobType())), $operation); // if installing from lock, restore dev packages' references to their locked state if ($installFromLock) { $package = null; if ('update' === $operation->getJobType()) { $package = $operation->getTargetPackage(); } elseif ('install' === $operation->getJobType()) { $package = $operation->getPackage(); } if ($package && $package->isDev()) { $lockData = $this->locker->getLockData(); foreach ($lockData['packages'] as $lockedPackage) { if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { $package->setSourceReference($lockedPackage['source-reference']); break; } } } } $this->installationManager->execute($localRepo, $operation); $this->eventDispatcher->dispatchPackageEvent(constant('Composer\\Script\\ScriptEvents::POST_PACKAGE_' . strtoupper($operation->getJobType())), $operation); $localRepo->write(); } } // reload local repository for the dev pass to work ok with aliases since it was anti-aliased above if (!$devMode) { $localRepo->reload(); } return true; }
/** * Returns true if the supplied package requires the Composer NPM bridge. * * @param PackageInterface $package The package to inspect. * @param boolean $includeDevDependencies True if the dev dependencies should also be inspected. * * @return boolean True if the package requires the bridge. */ public function isDependantPackage(PackageInterface $package, $includeDevDependencies = false) { foreach ($package->getRequires() as $link) { if ('eloquent/composer-npm-bridge' === $link->getTarget()) { return true; } } if ($includeDevDependencies) { foreach ($package->getDevRequires() as $link) { if ('eloquent/composer-npm-bridge' === $link->getTarget()) { return true; } } } return false; }
/** * Fill the dependency graph with installed packages. * * @param RepositoryInterface $repository * @param PackageInterface $package * @param array $dependencyMap */ protected function fillDependencyMap(PackageInterface $package, array &$dependencyMap, $inverted) { /** @var \Composer\Package\Link $requireLink */ foreach ($package->getRequires() as $requireLink) { if ($inverted) { $dependencyMap[$package->getName()][$requireLink->getTarget()] = $requireLink->getPrettyConstraint(); } else { $dependencyMap[$requireLink->getTarget()][$package->getName()] = $requireLink->getPrettyConstraint(); } } }
/** * {@inheritdoc} */ public function getRequires() { return $this->package->getRequires(); }
/** * Returns true if the supplied package requires the Composer NPM bridge. * * @param PackageInterface $package The package to inspect. * @param bool|null $dev_mode True if the dev dependencies should also be inspected. * * @return bool True if the package requires the bridge. */ public function isDependantPackage(PackageInterface $package, $dev_mode = null) { if ($package->getName() === 'apishka/easy-extend') { return true; } foreach ($package->getRequires() as $link) { if ($link->getTarget() === 'apishka/easy-extend') { return true; } } if ($dev_mode) { foreach ($package->getDevRequires() as $link) { if ($link->getTarget() === 'apishka/easy-extend') { return true; } } } return false; }
/** * Builds a package map * * The package map is an array of packages to their installation sources and destinations. * This will resolve any globs for external integration packages. An external integration * package *cannot* handle installation of a package it does not depend on, so it looks * through the requires to determine this. * * @access private * @param PackageInterface $package The package to build a map for * @return array The package map */ private function buildPackageMap($package) { $package_map = array(); $requirements = $package->getRequires(); $extra = $package->getExtra(); $mappings = $extra[self::NAME][$this->framework]; foreach ($mappings as $element => $value) { if (is_array($value)) { // // Check for external mapping support // if ($element != $package->getName() && !$this->externalMapping) { throw new \Exception(sprintf('Cannot perform external mapping for %s, disabled', $element)); } if (strpos($element, '*') !== FALSE) { $parts = explode('*', $element); $parts = array_map(function ($v) { return preg_quote($v, '#'); }, $parts); $element = implode('(.*)', $parts); } foreach ($requirements as $link) { if (preg_match('#' . $element . '#', $link->getTarget())) { $package_map[$link->getTarget()] = $value; } } $package_map[$element] = $value; } elseif (is_string($value)) { if (!isset($package_map[$package->getName()])) { $package_map[$package->getName()] = array(); } $package_map[$package->getName()][$element] = $value; } else { throw new \Exception(sprintf('Ivalid element %s of type %s', $element, gettype($value))); } } return $package_map; }