public function testGetLockedPackages() { $json = $this->createJsonFileMock(); $repo = $this->createRepositoryManagerMock(); $inst = $this->createInstallationManagerMock(); $locker = new Locker(new NullIO, $json, $repo, $inst, $this->getJsonContent()); $json ->expects($this->once()) ->method('exists') ->will($this->returnValue(true)); $json ->expects($this->once()) ->method('read') ->will($this->returnValue(array( 'packages' => array( array('name' => 'pkg1', 'version' => '1.0.0-beta'), array('name' => 'pkg2', 'version' => '0.1.10') ) ))); $repo = $locker->getLockedRepository(); $this->assertNotNull($repo->findPackage('pkg1', '1.0.0-beta')); $this->assertNotNull($repo->findPackage('pkg2', '0.1.10')); }
/** * Collect required packages and types from root composer.lock file * * @return array */ public function getRootRequiredPackageTypesByName() { $packages = []; /** @var PackageInterface $package */ foreach ($this->locker->getLockedRepository()->getPackages() as $package) { $packages[$package->getName()] = $package->getType(); } return $packages; }
/** * Collect all installed Magento packages from composer.lock * * @return array */ public function getInstalledMagentoPackages() { $packages = []; /** @var CompletePackageInterface $package */ foreach ($this->locker->getLockedRepository()->getPackages() as $package) { if (in_array($package->getType(), self::$packageTypes) && !$this->isSystemPackage($package->getPrettyName())) { $packages[$package->getName()] = ['name' => $package->getName(), 'type' => $package->getType(), 'version' => $package->getPrettyVersion()]; } } return $packages; }
/** * Loads the most "current" list of packages that are installed meaning from lock ideally or from installed repo as fallback * @param RepositoryInterface $installedRepo * @return array */ private function getCurrentPackages($installedRepo) { if ($this->locker->isLocked()) { try { return $this->locker->getLockedRepository(true)->getPackages(); } catch (\RuntimeException $e) { // fetch only non-dev packages from lock if doing a dev update fails due to a previously incomplete lock file return $this->locker->getLockedRepository()->getPackages(); } } return $installedRepo->getPackages(); }
/** * Retrieve list of required extensions * * Collect required extensions from composer.lock file * * @return array * @throws \Exception If attributes are missing in composer.lock file. */ public function getRequiredExtensions() { $requiredExtensions = []; $allPlatformReqs = array_keys($this->locker->getPlatformRequirements(true)); if (!$this->isMagentoRoot()) { /** @var \Composer\Package\CompletePackage $package */ foreach ($this->locker->getLockedRepository()->getPackages() as $package) { $requires = array_keys($package->getRequires()); $requires = array_merge($requires, array_keys($package->getDevRequires())); $allPlatformReqs = array_merge($allPlatformReqs, $requires); } } foreach ($allPlatformReqs as $reqIndex) { if (substr($reqIndex, 0, 4) === 'ext-') { $requiredExtensions[] = substr($reqIndex, 4); } } return array_unique($requiredExtensions); }
public function testGetPackagesWithoutRepo() { $json = $this->createJsonFileMock(); $repo = $this->createRepositoryManagerMock(); $inst = $this->createInstallationManagerMock(); $locker = new Locker($json, $repo, $inst, 'md5'); $json ->expects($this->once()) ->method('exists') ->will($this->returnValue(true)); $json ->expects($this->once()) ->method('read') ->will($this->returnValue(array( 'packages' => array( array('package' => 'pkg1', 'version' => '1.0.0-beta'), array('package' => 'pkg2', 'version' => '0.1.10') ) ))); $package1 = $this->createPackageMock(); $package2 = $this->createPackageMock(); $repo->getLocalRepository() ->expects($this->exactly(2)) ->method('findPackage') ->with($this->logicalOr('pkg1', 'pkg2'), $this->logicalOr('1.0.0-beta', '0.1.10')) ->will($this->onConsecutiveCalls($package1, null)); $this->setExpectedException('LogicException'); $locker->getLockedRepository(); }
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; }