/** * @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); }
/** * {@inheritdoc} * * @SuppressWarnings(PHPMD.LongVariable) */ public function handle(\Input $input) { $packageName = $input->get('solve'); $version = base64_decode(rawurldecode($input->get('version'))); if ($input->post('mark') || $input->post('install')) { // make a backup copy(TL_ROOT . '/' . $this->configPathname, TL_ROOT . '/' . $this->configPathname . '~'); // update requires $json = new JsonFile(TL_ROOT . '/' . $this->configPathname); $config = $json->read(); if (!array_key_exists('require', $config)) { $config['require'] = array(); } $config['require'][$packageName] = $version; $json->write($config); Messages::addInfo(sprintf($GLOBALS['TL_LANG']['composer_client']['added_candidate'], $packageName, $version)); $_SESSION['COMPOSER_OUTPUT'] .= $this->io->getOutput(); if ($input->post('install')) { $this->redirect('contao/main.php?do=composer&update=packages'); } $this->redirect('contao/main.php?do=composer'); } /** @var RootPackage $rootPackage */ $rootPackage = $this->composer->getPackage(); $installedRootPackage = clone $rootPackage; $installedRootPackage->setRequires(array()); $installedRootPackage->setDevRequires(array()); $repositoryManager = $this->getRepositoryManager(); $localRepository = $repositoryManager->getLocalRepository(); $platformRepo = new PlatformRepository(); $installedRepository = new CompositeRepository(array($localRepository, new InstalledArrayRepository(array($installedRootPackage)), $platformRepo)); $versionParser = new VersionParser(); $constraint = $versionParser->parseConstraints($version); $stability = $versionParser->parseStability($version); $aliases = $this->getRootAliases($rootPackage); $this->aliasPlatformPackages($platformRepo, $aliases); $stabilityFlags = $rootPackage->getStabilityFlags(); $stabilityFlags[$packageName] = BasePackage::$stabilities[$stability]; $pool = $this->getPool($rootPackage->getMinimumStability(), $stabilityFlags); $pool->addRepository($installedRepository, $aliases); $policy = new DefaultPolicy($rootPackage->getPreferStable()); $request = new Request($pool); // add root package $rootPackageConstraint = $this->createConstraint('=', $rootPackage->getVersion()); $rootPackageConstraint->setPrettyString($rootPackage->getPrettyVersion()); $request->install($rootPackage->getName(), $rootPackageConstraint); // add requirements $links = $rootPackage->getRequires(); /** @var Link $link */ foreach ($links as $link) { if ($link->getTarget() != $packageName) { $request->install($link->getTarget(), $link->getConstraint()); } } /** @var PackageInterface $package */ foreach ($installedRepository->getPackages() as $package) { $request->install($package->getName(), $this->createConstraint('=', $package->getVersion())); } $operations = array(); try { $solver = new Solver($policy, $pool, $installedRepository); $beforeOperations = $solver->solve($request); $request->install($packageName, $constraint); $operations = $solver->solve($request); /** @var \Composer\DependencyResolver\Operation\SolverOperation $beforeOperation */ foreach ($beforeOperations as $beforeOperation) { /** @var \Composer\DependencyResolver\Operation\InstallOperation $operation */ foreach ($operations as $index => $operation) { if ($operation->getPackage()->getName() != $packageName && $beforeOperation->__toString() == $operation->__toString()) { unset($operations[$index]); } } } } catch (SolverProblemsException $e) { Messages::addError(sprintf('<span style="white-space: pre-line">%s</span>', trim($e->getMessage()))); } $template = new \BackendTemplate('be_composer_client_solve'); $template->composer = $this->composer; $template->packageName = $packageName; $template->packageVersion = $version; $template->operations = $operations; return $template->parse(); }
protected function doInstall($localRepo, $installedRepo, $aliases, $devMode = false) { $minimumStability = $this->package->getMinimumStability(); $stabilityFlags = $this->package->getStabilityFlags(); // init vars $lockedRepository = null; $repositories = null; // initialize locker to create aliased packages $installFromLock = false; if (!$this->update && $this->locker->isLocked($devMode)) { $installFromLock = true; $lockedRepository = $this->locker->getLockedRepository($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 $policy = new DefaultPolicy(); $pool = new Pool($minimumStability, $stabilityFlags); $pool->addRepository($installedRepo, $aliases); if ($installFromLock) { $pool->addRepository($lockedRepository, $aliases); } if (!$installFromLock || !$this->locker->isCompleteFormat($devMode)) { $repositories = $this->repositoryManager->getRepositories(); foreach ($repositories as $repository) { $pool->addRepository($repository, $aliases); } } // creating requirements request $request = new Request($pool); $constraint = new VersionConstraint('=', $this->package->getVersion()); $constraint->setPrettyString($this->package->getPrettyVersion()); $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 ($installFromLock) { $this->io->write('<info>Installing ' . ($devMode ? 'dev ' : '') . 'dependencies from lock file</info>'); if (!$this->locker->isCompleteFormat($devMode)) { $this->io->write('<warning>Warning: Your lock file is in a deprecated format. It will most likely take a *long* time for composer to install dependencies, and may cause dependency solving issues.</warning>'); } if (!$this->locker->isFresh() && !$devMode) { $this->io->write('<warning>Warning: The lock file is not up to date with the latest changes in composer.json, you may be getting outdated dependencies, run update to update them.</warning>'); } foreach ($lockedRepository->getPackages() as $package) { $version = $package->getVersion(); if (isset($aliases[$package->getName()][$version])) { $version = $aliases[$package->getName()][$version]['alias_normalized']; } $constraint = new VersionConstraint('=', $version); $constraint->setPrettyString($package->getPrettyVersion()); $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()); $constraint->setPrettyString($package->getPrettyVersion()); $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->getLockedRepository($devMode)->getPackages(); } 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); } } } } // force dev packages to have the latest links if we update or install from a (potentially new) lock $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links'); // solve dependencies $solver = new Solver($policy, $pool, $installedRepo); 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; } if ($devMode) { // remove bogus operations that the solver creates for stuff that was force-updated in the non-dev pass // TODO this should not be necessary ideally, but it seems to work around the problem quite well foreach ($operations as $index => $op) { if ('update' === $op->getJobType() && $op->getInitialPackage()->getUniqueName() === $op->getTargetPackage()->getUniqueName() && $op->getInitialPackage()->getSourceReference() === $op->getTargetPackage()->getSourceReference() && $op->getInitialPackage()->getDistReference() === $op->getTargetPackage()->getDistReference()) { unset($operations[$index]); } } } // force dev packages to be updated if we update or install from a (potentially new) lock $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations); // 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), $this->devMode, $operation); } // not installing from lock, force dev packages' references if they're in root package refs if (!$installFromLock) { $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()]); $package->setDistReference($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), $this->devMode, $operation); } if (!$this->dryRun) { $localRepo->write(); } } return true; }
protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases, $withDevReqs) { // init vars $lockedRepository = null; $repositories = null; // initialize locker to create aliased packages $installFromLock = false; if (!$this->update && $this->locker->isLocked()) { $installFromLock = true; try { $lockedRepository = $this->locker->getLockedRepository($withDevReqs); } catch (\RuntimeException $e) { // if there are dev requires, then we really can not install if ($this->package->getDevRequires()) { throw $e; } // no require-dev in composer.json and the lock file was created with no dev info, so skip them $lockedRepository = $this->locker->getLockedRepository(); } } $this->whitelistUpdateDependencies($localRepo, $withDevReqs, $this->package->getRequires(), $this->package->getDevRequires()); $this->io->writeError('<info>Loading composer repositories with package information</info>'); // creating repository pool $policy = $this->createPolicy(); $pool = $this->createPool($withDevReqs, $lockedRepository); $pool->addRepository($installedRepo, $aliases); if ($installFromLock) { $pool->addRepository($lockedRepository, $aliases); } if (!$installFromLock) { $repositories = $this->repositoryManager->getRepositories(); foreach ($repositories as $repository) { $pool->addRepository($repository, $aliases); } } // creating requirements request $request = $this->createRequest($pool, $this->package, $platformRepo); if (!$installFromLock) { // remove unstable packages from the localRepo if they don't match the current stability settings $removedUnstablePackages = array(); foreach ($localRepo->getPackages() as $package) { if (!$pool->isPackageAcceptable($package->getNames(), $package->getStability()) && $this->installationManager->isPackageInstalled($localRepo, $package)) { $removedUnstablePackages[$package->getName()] = true; $request->remove($package->getName(), new VersionConstraint('=', $package->getVersion())); } } } if ($this->update) { $this->io->writeError('<info>Updating dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . '</info>'); $request->updateAll(); if ($withDevReqs) { $links = array_merge($this->package->getRequires(), $this->package->getDevRequires()); } else { $links = $this->package->getRequires(); } foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } // 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->updateWhitelist) { if ($this->locker->isLocked()) { try { $currentPackages = $this->locker->getLockedRepository($withDevReqs)->getPackages(); } catch (\RuntimeException $e) { // fetch only non-dev packages from lock if doing a dev update fails due to a previously incomplete lock file $currentPackages = $this->locker->getLockedRepository()->getPackages(); } } else { $currentPackages = $installedRepo->getPackages(); } // collect packages to fixate from root requirements 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) && !isset($removedUnstablePackages[$curPackage->getName()])) { $constraint = new VersionConstraint('=', $curPackage->getVersion()); $request->install($curPackage->getName(), $constraint); } break; } } } } } elseif ($installFromLock) { $this->io->writeError('<info>Installing dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . ' from lock file</info>'); if (!$this->locker->isFresh()) { $this->io->writeError('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.</warning>'); } foreach ($lockedRepository->getPackages() as $package) { $version = $package->getVersion(); if (isset($aliases[$package->getName()][$version])) { $version = $aliases[$package->getName()][$version]['alias_normalized']; } $constraint = new VersionConstraint('=', $version); $constraint->setPrettyString($package->getPrettyVersion()); $request->install($package->getName(), $constraint); } foreach ($this->locker->getPlatformRequirements($withDevReqs) as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } else { $this->io->writeError('<info>Installing dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . '</info>'); if ($withDevReqs) { $links = array_merge($this->package->getRequires(), $this->package->getDevRequires()); } else { $links = $this->package->getRequires(); } foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } // force dev packages to have the latest links if we update or install from a (potentially new) lock $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links'); // solve dependencies $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo); try { $operations = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, $this->devMode, $policy, $pool, $installedRepo, $request, $operations); } catch (SolverProblemsException $e) { $this->io->writeError('<error>Your requirements could not be resolved to an installable set of packages.</error>'); $this->io->writeError($e->getMessage()); return max(1, $e->getCode()); } // force dev packages to be updated if we update or install from a (potentially new) lock $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations); // execute operations if (!$operations) { $this->io->writeError('Nothing to install or update'); } $operations = $this->movePluginsToFront($operations); $operations = $this->moveUninstallsToFront($operations); 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); } } // not installing from lock, force dev packages' references if they're in root package refs if (!$installFromLock) { $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()]); $package->setDistReference($references[$package->getName()]); } } if ('update' === $operation->getJobType() && $operation->getTargetPackage()->isDev() && $operation->getTargetPackage()->getVersion() === $operation->getInitialPackage()->getVersion() && $operation->getTargetPackage()->getSourceReference() === $operation->getInitialPackage()->getSourceReference()) { if ($this->io->isDebug()) { $this->io->writeError(' - Skipping update of ' . $operation->getTargetPackage()->getPrettyName() . ' to the same reference-locked version'); $this->io->writeError(''); } continue; } } $event = 'Composer\\Installer\\PackageEvents::PRE_PACKAGE_' . strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation); } // output non-alias ops in dry run, output alias ops in debug verbosity if ($this->dryRun && false === strpos($operation->getJobType(), 'Alias')) { $this->io->writeError(' - ' . $operation); $this->io->writeError(''); } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) { $this->io->writeError(' - ' . $operation); $this->io->writeError(''); } $this->installationManager->execute($localRepo, $operation); // output reasons why the operation was ran, only for install/update operations if ($this->verbose && $this->io->isVeryVerbose() && in_array($operation->getJobType(), array('install', 'update'))) { $reason = $operation->getReason(); if ($reason instanceof Rule) { switch ($reason->getReason()) { case Rule::RULE_JOB_INSTALL: $this->io->writeError(' REASON: Required by root: ' . $reason->getPrettyString($pool)); $this->io->writeError(''); break; case Rule::RULE_PACKAGE_REQUIRES: $this->io->writeError(' REASON: ' . $reason->getPrettyString($pool)); $this->io->writeError(''); break; } } } $event = 'Composer\\Installer\\PackageEvents::POST_PACKAGE_' . strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $policy, $pool, $installedRepo, $request, $operations, $operation); } if (!$this->dryRun) { $localRepo->write(); } } return 0; }
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; }
/** * Extracts the dev packages out of the localRepo * * This works by faking the operations so we can see what the dev packages * would be at the end of the operation execution. This lets us then remove * the dev packages from the list of operations accordingly if we are in a * --no-dev install or update. * * @return array */ private function extractDevPackages(array $operations, RepositoryInterface $localRepo, PlatformRepository $platformRepo, array $aliases) { if (!$this->package->getDevRequires()) { return array(); } // fake-apply all operations to this clone of the local repo so we see the complete set of package we would end up with $tempLocalRepo = clone $localRepo; foreach ($operations as $operation) { switch ($operation->getJobType()) { case 'install': case 'markAliasInstalled': if (!$tempLocalRepo->hasPackage($operation->getPackage())) { $tempLocalRepo->addPackage(clone $operation->getPackage()); } break; case 'uninstall': case 'markAliasUninstalled': $tempLocalRepo->removePackage($operation->getPackage()); break; case 'update': $tempLocalRepo->removePackage($operation->getInitialPackage()); if (!$tempLocalRepo->hasPackage($operation->getTargetPackage())) { $tempLocalRepo->addPackage(clone $operation->getTargetPackage()); } break; default: throw new \LogicException('Unknown type: ' . $operation->getJobType()); } } // we have to reload the local repo to handle aliases properly // but as it is not persisted on disk we use a loader/dumper // to reload it in memory $localRepo = new InstalledArrayRepository(array()); $loader = new ArrayLoader(null, true); $dumper = new ArrayDumper(); foreach ($tempLocalRepo->getCanonicalPackages() as $pkg) { $localRepo->addPackage($loader->load($dumper->dump($pkg))); } unset($tempLocalRepo, $loader, $dumper); $policy = $this->createPolicy(); $pool = $this->createPool(); $installedRepo = $this->createInstalledRepo($localRepo, $platformRepo); $pool->addRepository($installedRepo, $aliases); // creating requirements request without dev requirements $request = $this->createRequest($this->package, $platformRepo); $request->updateAll(); foreach ($this->package->getRequires() as $link) { $request->install($link->getTarget(), $link->getConstraint()); } // solve deps to see which get removed $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::PRE_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request); $solver = new Solver($policy, $pool, $installedRepo, $this->io); $ops = $solver->solve($request, $this->ignorePlatformReqs); $this->eventDispatcher->dispatchInstallerEvent(InstallerEvents::POST_DEPENDENCIES_SOLVING, false, $policy, $pool, $installedRepo, $request, $ops); $devPackages = array(); foreach ($ops as $op) { if ($op->getJobType() === 'uninstall') { $devPackages[] = $op->getPackage(); } } return $devPackages; }
public function resolve_package(RootPackageInterface $package) { $policy = $this->create_policy($package); $pool = $this->create_pool($package, WP_DEBUG); $packages = array(); $localRepo = new InstalledArrayRepository($this->plugins); $platformRepo = new PlatformRepository(); $repos = array($localRepo, $platformRepo, $this->get_available_repo()); $installedRepo = new CompositeRepository($repos); $pool->addRepository($installedRepo); // $repositories = $this->repositoryManager->getRepositories(); // foreach ($repositories as $repository) { // $pool->addRepository($repository); // } $request = $this->handle_request($package, $pool, $localRepo, $platformRepo); // solve dependencies $solver = new Solver($policy, $pool, $installedRepo); $operations = $solver->solve($request); foreach ($operations as $op) { var_dump($op->getJobType(), $op->getPackage()); } exit; }
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; }
public function install(IOInterface $io, Composer $composer, EventDispatcher $eventDispatcher, $preferSource = false, $dryRun = false, $verbose = false, $noInstallRecommends = false, $installSuggests = false, $update = false, RepositoryInterface $additionalInstalledRepository = null) { if ($dryRun) { $verbose = true; } if ($preferSource) { $composer->getDownloadManager()->setPreferSource(true); } // create local repo, this contains all packages that are installed in the local project $localRepo = $composer->getRepositoryManager()->getLocalRepository(); // create installed repo, this contains all local packages + platform packages (php & extensions) $installedRepo = new CompositeRepository(array($localRepo, new PlatformRepository())); if ($additionalInstalledRepository) { $installedRepo->addRepository($additionalInstalledRepository); } // creating repository pool $pool = new Pool(); $pool->addRepository($installedRepo); foreach ($composer->getRepositoryManager()->getRepositories() as $repository) { $pool->addRepository($repository); } // dispatch pre event if (!$dryRun) { $eventName = $update ? ScriptEvents::PRE_UPDATE_CMD : ScriptEvents::PRE_INSTALL_CMD; $eventDispatcher->dispatchCommandEvent($eventName); } // creating requirements request $installFromLock = false; $request = new Request($pool); if ($update) { $io->write('<info>Updating dependencies</info>'); $installedPackages = $installedRepo->getPackages(); $links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests); $request->updateAll(); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } elseif ($composer->getLocker()->isLocked()) { $installFromLock = true; $io->write('<info>Installing from lock file</info>'); if (!$composer->getLocker()->isFresh()) { $io->write('<warning>Your lock file is out of sync with your composer.json, run "composer.phar update" to update dependencies</warning>'); } foreach ($composer->getLocker()->getLockedPackages() as $package) { $constraint = new VersionConstraint('=', $package->getVersion()); $request->install($package->getName(), $constraint); } } else { $io->write('<info>Installing dependencies</info>'); $links = $this->collectLinks($composer->getPackage(), $noInstallRecommends, $installSuggests); foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } // prepare solver $installationManager = $composer->getInstallationManager(); $policy = new DependencyResolver\DefaultPolicy(); $solver = new DependencyResolver\Solver($policy, $pool, $installedRepo); // solve dependencies $operations = $solver->solve($request); // execute operations if (!$operations) { $io->write('<info>Nothing to install/update</info>'); } // force dev packages to be updated to latest reference on update if ($update) { 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() && $package === $operation->getInitialPackage() || 'uninstall' === $operation->getJobType() && $package === $operation->getPackage()) { continue 2; } } // force update $newPackage = $composer->getRepositoryManager()->findPackage($package->getName(), $package->getVersion()); if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) { $operations[] = new UpdateOperation($package, $newPackage); } } } foreach ($operations as $operation) { if ($verbose) { $io->write((string) $operation); } if (!$dryRun) { $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 = $composer->getLocker()->getLockData(); foreach ($lockData['packages'] as $lockedPackage) { if (!empty($lockedPackage['source-reference']) && strtolower($lockedPackage['package']) === $package->getName()) { $package->setSourceReference($lockedPackage['source-reference']); break; } } } } $installationManager->execute($operation); $eventDispatcher->dispatchPackageEvent(constant('Composer\\Script\\ScriptEvents::POST_PACKAGE_' . strtoupper($operation->getJobType())), $operation); } } if (!$dryRun) { if ($update || !$composer->getLocker()->isLocked()) { $composer->getLocker()->lockPackages($localRepo->getPackages()); $io->write('<info>Writing lock file</info>'); } $localRepo->write(); $io->write('<info>Generating autoload files</info>'); $generator = new AutoloadGenerator(); $generator->dump($localRepo, $composer->getPackage(), $installationManager, $installationManager->getVendorPath() . '/.composer'); // dispatch post event $eventName = $update ? ScriptEvents::POST_UPDATE_CMD : ScriptEvents::POST_INSTALL_CMD; $eventDispatcher->dispatchCommandEvent($eventName); } }
protected function doInstall($localRepo, $installedRepo, $platformRepo, $aliases, $withDevReqs) { $lockedRepository = null; $repositories = null; $installFromLock = false; if (!$this->update && $this->locker->isLocked()) { $installFromLock = true; try { $lockedRepository = $this->locker->getLockedRepository($withDevReqs); } catch (\RuntimeException $e) { if ($this->package->getDevRequires()) { throw $e; } $lockedRepository = $this->locker->getLockedRepository(); } } $this->whitelistUpdateDependencies($localRepo, $withDevReqs, $this->package->getRequires(), $this->package->getDevRequires()); $this->io->write('<info>Loading composer repositories with package information</info>'); $policy = $this->createPolicy(); $pool = $this->createPool($withDevReqs); $pool->addRepository($installedRepo, $aliases); if ($installFromLock) { $pool->addRepository($lockedRepository, $aliases); } if (!$installFromLock) { $repositories = $this->repositoryManager->getRepositories(); foreach ($repositories as $repository) { $pool->addRepository($repository, $aliases); } } $request = $this->createRequest($pool, $this->package, $platformRepo); if (!$installFromLock) { $removedUnstablePackages = array(); foreach ($localRepo->getPackages() as $package) { if (!$pool->isPackageAcceptable($package->getNames(), $package->getStability()) && $this->installationManager->isPackageInstalled($localRepo, $package)) { $removedUnstablePackages[$package->getName()] = true; $request->remove($package->getName(), new VersionConstraint('=', $package->getVersion())); } } } if ($this->update) { $this->io->write('<info>Updating dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . '</info>'); $request->updateAll(); if ($withDevReqs) { $links = array_merge($this->package->getRequires(), $this->package->getDevRequires()); } else { $links = $this->package->getRequires(); } foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } if ($this->updateWhitelist) { if ($this->locker->isLocked()) { try { $currentPackages = $this->locker->getLockedRepository($withDevReqs)->getPackages(); } catch (\RuntimeException $e) { $currentPackages = $this->locker->getLockedRepository()->getPackages(); } } else { $currentPackages = $installedRepo->getPackages(); } $candidates = array(); foreach ($links as $link) { $candidates[$link->getTarget()] = true; } foreach ($localRepo->getPackages() as $package) { $candidates[$package->getName()] = true; } foreach ($candidates as $candidate => $dummy) { foreach ($currentPackages as $curPackage) { if ($curPackage->getName() === $candidate) { if (!$this->isUpdateable($curPackage) && !isset($removedUnstablePackages[$curPackage->getName()])) { $constraint = new VersionConstraint('=', $curPackage->getVersion()); $request->install($curPackage->getName(), $constraint); } break; } } } } } elseif ($installFromLock) { $this->io->write('<info>Installing dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . ' from lock file</info>'); if (!$this->locker->isFresh()) { $this->io->write('<warning>Warning: The lock file is not up to date with the latest changes in composer.json. You may be getting outdated dependencies. Run update to update them.</warning>'); } foreach ($lockedRepository->getPackages() as $package) { $version = $package->getVersion(); if (isset($aliases[$package->getName()][$version])) { $version = $aliases[$package->getName()][$version]['alias_normalized']; } $constraint = new VersionConstraint('=', $version); $constraint->setPrettyString($package->getPrettyVersion()); $request->install($package->getName(), $constraint); } foreach ($this->locker->getPlatformRequirements($withDevReqs) as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } else { $this->io->write('<info>Installing dependencies' . ($withDevReqs ? ' (including require-dev)' : '') . '</info>'); if ($withDevReqs) { $links = array_merge($this->package->getRequires(), $this->package->getDevRequires()); } else { $links = $this->package->getRequires(); } foreach ($links as $link) { $request->install($link->getTarget(), $link->getConstraint()); } } $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links'); $solver = new Solver($policy, $pool, $installedRepo); 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 max(1, $e->getCode()); } $operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations); if (!$operations) { $this->io->write('Nothing to install or update'); } $operations = $this->movePluginsToFront($operations); foreach ($operations as $operation) { 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), $this->devMode, $operation); } if (!$installFromLock) { $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()]); $package->setDistReference($references[$package->getName()]); } } } if ($this->dryRun && false === strpos($operation->getJobType(), 'Alias')) { $this->io->write(' - ' . $operation); $this->io->write(''); } elseif ($this->io->isDebug() && false !== strpos($operation->getJobType(), 'Alias')) { $this->io->write(' - ' . $operation); $this->io->write(''); } $this->installationManager->execute($localRepo, $operation); if ($this->verbose && $this->io->isVeryVerbose() && in_array($operation->getJobType(), array('install', 'update'))) { $reason = $operation->getReason(); if ($reason instanceof Rule) { switch ($reason->getReason()) { case Rule::RULE_JOB_INSTALL: $this->io->write(' REASON: Required by root: ' . $reason->getRequiredPackage()); $this->io->write(''); break; case Rule::RULE_PACKAGE_REQUIRES: $this->io->write(' REASON: ' . $reason->getPrettyString()); $this->io->write(''); break; } } } $event = 'Composer\\Script\\ScriptEvents::POST_PACKAGE_' . strtoupper($operation->getJobType()); if (defined($event) && $this->runScripts) { $this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation); } if (!$this->dryRun) { $localRepo->write(); } } return 0; }