Merge pull request #7936 from naderman/solve-without-installed
Separate Install & Update code, no longer use vendor dir as input to solverpull/8424/head
commit
8810c6467d
|
@ -293,7 +293,7 @@ EOT
|
|||
throw new \InvalidArgumentException('Invalid stability provided ('.$stability.'), must be one of: '.implode(', ', array_keys(BasePackage::$stabilities)));
|
||||
}
|
||||
|
||||
$repositorySet = new RepositorySet(array(), $stability);
|
||||
$repositorySet = new RepositorySet(array(), array(), $stability);
|
||||
$repositorySet->addRepository($sourceRepo);
|
||||
|
||||
$phpVersion = null;
|
||||
|
|
|
@ -668,7 +668,7 @@ EOT
|
|||
$key = $minimumStability ?: 'default';
|
||||
|
||||
if (!isset($this->repositorySets[$key])) {
|
||||
$this->repositorySets[$key] = $repositorySet = new RepositorySet(array(), $minimumStability ?: $this->getMinimumStability($input));
|
||||
$this->repositorySets[$key] = $repositorySet = new RepositorySet(array(), array(), $minimumStability ?: $this->getMinimumStability($input));
|
||||
$repositorySet->addRepository($this->getRepos());
|
||||
}
|
||||
|
||||
|
|
|
@ -544,7 +544,7 @@ EOT
|
|||
$constraint = is_string($version) ? $this->versionParser->parseConstraints($version) : $version;
|
||||
|
||||
$policy = new DefaultPolicy();
|
||||
$repositorySet = new RepositorySet(array(), 'dev');
|
||||
$repositorySet = new RepositorySet(array(), array(), 'dev');
|
||||
$repositorySet->addRepository($repos);
|
||||
|
||||
$matchedPackage = null;
|
||||
|
@ -1009,7 +1009,7 @@ EOT
|
|||
private function getRepositorySet(Composer $composer)
|
||||
{
|
||||
if (!$this->repositorySet) {
|
||||
$this->repositorySet = new RepositorySet(array(), $composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags());
|
||||
$this->repositorySet = new RepositorySet(array(), array(), $composer->getPackage()->getMinimumStability(), $composer->getPackage()->getStabilityFlags());
|
||||
$this->repositorySet->addRepository(new CompositeRepository($composer->getRepositoryManager()->getRepositories()));
|
||||
}
|
||||
|
||||
|
|
|
@ -121,6 +121,19 @@ EOT
|
|||
}
|
||||
}
|
||||
|
||||
// the arguments lock/nothing/mirrors are not package names but trigger a mirror update instead
|
||||
// they are further mutually exclusive with listing actual package names
|
||||
$filteredPackages = array_filter($packages, function ($package) {
|
||||
return !in_array($package, array('lock', 'nothing', 'mirrors'), true);
|
||||
});
|
||||
$updateMirrors = $input->getOption('lock') || count($filteredPackages) != count($packages);
|
||||
$packages = $filteredPackages;
|
||||
|
||||
if ($updateMirrors && !empty($packages)) {
|
||||
$io->writeError('<error>You cannot simultaneously update only a selection of packages and regenerate the lock file metadata.</error>');
|
||||
return -1;
|
||||
}
|
||||
|
||||
$commandEvent = new CommandEvent(PluginEvents::COMMAND, 'update', $input, $output);
|
||||
$composer->getEventDispatcher()->dispatch($commandEvent->getName(), $commandEvent);
|
||||
|
||||
|
@ -146,7 +159,8 @@ EOT
|
|||
->setClassMapAuthoritative($authoritative)
|
||||
->setApcuAutoloader($apcu)
|
||||
->setUpdate(true)
|
||||
->setUpdateWhitelist($input->getOption('lock') ? array('lock') : $packages)
|
||||
->setUpdateMirrors($updateMirrors)
|
||||
->setUpdateWhitelist($packages)
|
||||
->setWhitelistTransitiveDependencies($input->getOption('with-dependencies'))
|
||||
->setWhitelistAllDependencies($input->getOption('with-all-dependencies'))
|
||||
->setIgnorePlatformRequirements($input->getOption('ignore-platform-reqs'))
|
||||
|
|
|
@ -44,7 +44,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
return $constraint->matchSpecific($version, true);
|
||||
}
|
||||
|
||||
public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package, $mustMatchName = false)
|
||||
public function findUpdatePackages(Pool $pool, PackageInterface $package, $mustMatchName = false)
|
||||
{
|
||||
$packages = array();
|
||||
|
||||
|
@ -57,36 +57,34 @@ class DefaultPolicy implements PolicyInterface
|
|||
return $packages;
|
||||
}
|
||||
|
||||
public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null)
|
||||
public function selectPreferredPackages(Pool $pool, array $literals, $requiredPackage = null)
|
||||
{
|
||||
$packages = $this->groupLiteralsByNamePreferInstalled($pool, $installedMap, $literals);
|
||||
$packages = $this->groupLiteralsByName($pool, $literals);
|
||||
|
||||
foreach ($packages as &$literals) {
|
||||
foreach ($packages as &$nameLiterals) {
|
||||
$policy = $this;
|
||||
usort($literals, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
|
||||
return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
|
||||
usort($nameLiterals, function ($a, $b) use ($policy, $pool, $requiredPackage) {
|
||||
return $policy->compareByPriority($pool, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
|
||||
});
|
||||
}
|
||||
|
||||
foreach ($packages as &$literals) {
|
||||
$literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
|
||||
|
||||
$literals = $this->pruneToBestVersion($pool, $literals);
|
||||
|
||||
$literals = $this->pruneRemoteAliases($pool, $literals);
|
||||
foreach ($packages as &$sortedLiterals) {
|
||||
$sortedLiterals = $this->pruneToHighestPriority($pool, $sortedLiterals);
|
||||
$sortedLiterals = $this->pruneToBestVersion($pool, $sortedLiterals);
|
||||
$sortedLiterals = $this->pruneRemoteAliases($pool, $sortedLiterals);
|
||||
}
|
||||
|
||||
$selected = call_user_func_array('array_merge', $packages);
|
||||
|
||||
// now sort the result across all packages to respect replaces across packages
|
||||
usort($selected, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
|
||||
return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
|
||||
usort($selected, function ($a, $b) use ($policy, $pool, $requiredPackage) {
|
||||
return $policy->compareByPriority($pool, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
|
||||
});
|
||||
|
||||
return $selected;
|
||||
}
|
||||
|
||||
protected function groupLiteralsByNamePreferInstalled(Pool $pool, array $installedMap, $literals)
|
||||
protected function groupLiteralsByName(Pool $pool, $literals)
|
||||
{
|
||||
$packages = array();
|
||||
foreach ($literals as $literal) {
|
||||
|
@ -95,12 +93,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
if (!isset($packages[$packageName])) {
|
||||
$packages[$packageName] = array();
|
||||
}
|
||||
|
||||
if (isset($installedMap[abs($literal)])) {
|
||||
array_unshift($packages[$packageName], $literal);
|
||||
} else {
|
||||
$packages[$packageName][] = $literal;
|
||||
}
|
||||
$packages[$packageName][] = $literal;
|
||||
}
|
||||
|
||||
return $packages;
|
||||
|
@ -109,7 +102,7 @@ class DefaultPolicy implements PolicyInterface
|
|||
/**
|
||||
* @protected
|
||||
*/
|
||||
public function compareByPriorityPreferInstalled(Pool $pool, array $installedMap, PackageInterface $a, PackageInterface $b, $requiredPackage = null, $ignoreReplace = false)
|
||||
public function compareByPriority(Pool $pool, PackageInterface $a, PackageInterface $b, $requiredPackage = null, $ignoreReplace = false)
|
||||
{
|
||||
if ($a->getRepository() === $b->getRepository()) {
|
||||
// prefer aliases to the original package
|
||||
|
@ -155,14 +148,6 @@ class DefaultPolicy implements PolicyInterface
|
|||
return ($a->id < $b->id) ? -1 : 1;
|
||||
}
|
||||
|
||||
if (isset($installedMap[$a->id])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (isset($installedMap[$b->id])) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return ($pool->getPriority($a->id) > $pool->getPriority($b->id)) ? -1 : 1;
|
||||
}
|
||||
|
||||
|
@ -214,9 +199,9 @@ class DefaultPolicy implements PolicyInterface
|
|||
}
|
||||
|
||||
/**
|
||||
* Assumes that installed packages come first and then all highest priority packages
|
||||
* Assumes that highest priority packages come first
|
||||
*/
|
||||
protected function pruneToHighestPriorityOrInstalled(Pool $pool, array $installedMap, array $literals)
|
||||
protected function pruneToHighestPriority(Pool $pool, array $literals)
|
||||
{
|
||||
$selected = array();
|
||||
|
||||
|
@ -225,11 +210,6 @@ class DefaultPolicy implements PolicyInterface
|
|||
foreach ($literals as $literal) {
|
||||
$package = $pool->literalToPackage($literal);
|
||||
|
||||
if (isset($installedMap[$package->id])) {
|
||||
$selected[] = $literal;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (null === $priority) {
|
||||
$priority = $pool->getPriority($package->id);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
|
||||
use Composer\DependencyResolver\Operation\UninstallOperation;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class LocalRepoTransaction extends Transaction
|
||||
{
|
||||
public function __construct(RepositoryInterface $lockedRepository, $localRepository)
|
||||
{
|
||||
parent::__construct(
|
||||
$localRepository->getPackages(),
|
||||
$lockedRepository->getPackages()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Composer.
|
||||
*
|
||||
* (c) Nils Adermann <naderman@naderman.de>
|
||||
* Jordi Boggiano <j.boggiano@seld.be>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\RootAliasPackage;
|
||||
use Composer\Package\RootPackageInterface;
|
||||
use Composer\Repository\ArrayRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Test\Repository\ArrayRepositoryTest;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class LockTransaction extends Transaction
|
||||
{
|
||||
/**
|
||||
* packages in current lock file, platform repo or otherwise present
|
||||
* @var array
|
||||
*/
|
||||
protected $presentMap;
|
||||
|
||||
/**
|
||||
* Packages which cannot be mapped, platform repo, root package, other fixed repos
|
||||
* @var array
|
||||
*/
|
||||
protected $unlockableMap;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $resultPackages;
|
||||
|
||||
public function __construct(Pool $pool, $presentMap, $unlockableMap, $decisions)
|
||||
{
|
||||
$this->presentMap = $presentMap;
|
||||
$this->unlockableMap = $unlockableMap;
|
||||
|
||||
$this->setResultPackages($pool, $decisions);
|
||||
parent::__construct($this->presentMap, $this->resultPackages['all']);
|
||||
|
||||
}
|
||||
|
||||
// TODO make this a bit prettier instead of the two text indexes?
|
||||
public function setResultPackages(Pool $pool, Decisions $decisions)
|
||||
{
|
||||
$this->resultPackages = array('all' => array(), 'non-dev' => array(), 'dev' => array());
|
||||
foreach ($decisions as $i => $decision) {
|
||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||
|
||||
if ($literal > 0) {
|
||||
$package = $pool->literalToPackage($literal);
|
||||
$this->resultPackages['all'][] = $package;
|
||||
if (!isset($this->unlockableMap[$package->id])) {
|
||||
$this->resultPackages['non-dev'][] = $package;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function setNonDevPackages(LockTransaction $extractionResult)
|
||||
{
|
||||
$packages = $extractionResult->getNewLockPackages(false);
|
||||
|
||||
$this->resultPackages['dev'] = $this->resultPackages['non-dev'];
|
||||
$this->resultPackages['non-dev'] = array();
|
||||
|
||||
foreach ($packages as $package) {
|
||||
foreach ($this->resultPackages['dev'] as $i => $resultPackage) {
|
||||
// TODO this comparison is probably insufficient, aliases, what about modified versions? I guess they aren't possible?
|
||||
if ($package->getName() == $resultPackage->getName()) {
|
||||
$this->resultPackages['non-dev'][] = $resultPackage;
|
||||
unset($this->resultPackages['dev'][$i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO additionalFixedRepository needs to be looked at here as well?
|
||||
public function getNewLockPackages($devMode, $updateMirrors = false)
|
||||
{
|
||||
$packages = array();
|
||||
foreach ($this->resultPackages[$devMode ? 'dev' : 'non-dev'] as $package) {
|
||||
if (!($package instanceof AliasPackage) && !($package instanceof RootAliasPackage)) {
|
||||
// if we're just updating mirrors we need to reset references to the same as currently "present" packages' references to keep the lock file as-is
|
||||
// we do not reset references if the currently present package didn't have any, or if the type of VCS has changed
|
||||
if ($updateMirrors && !isset($this->presentMap[spl_object_hash($package)])) {
|
||||
foreach ($this->presentMap as $presentPackage) {
|
||||
if ($package->getName() == $presentPackage->getName() &&
|
||||
$package->getVersion() == $presentPackage->getVersion() &&
|
||||
$presentPackage->getSourceReference() &&
|
||||
$presentPackage->getSourceType() === $package->getSourceType()
|
||||
) {
|
||||
$package->setSourceDistReferences($presentPackage->getSourceReference());
|
||||
}
|
||||
}
|
||||
}
|
||||
$packages[] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
return $packages;
|
||||
}
|
||||
}
|
|
@ -56,11 +56,19 @@ class InstallOperation extends SolverOperation
|
|||
return 'install';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function show($lock)
|
||||
{
|
||||
return ($lock ? 'Locking ' : 'Installing ').$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'Installing '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
|
||||
return $this->show(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,16 @@ class MarkAliasInstalledOperation extends SolverOperation
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
public function show($lock)
|
||||
{
|
||||
return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as installed, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->show(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,8 +60,16 @@ class MarkAliasUninstalledOperation extends SolverOperation
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
public function show($lock)
|
||||
{
|
||||
return 'Marking '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).') as uninstalled, alias of '.$this->package->getAliasOf()->getPrettyName().' ('.$this->formatVersion($this->package->getAliasOf()).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->show(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,14 @@ interface OperationInterface
|
|||
*/
|
||||
public function getReason();
|
||||
|
||||
/**
|
||||
* Serializes the operation in a human readable format
|
||||
*
|
||||
* @param $lock bool Whether this is an operation on the lock file
|
||||
* @return string
|
||||
*/
|
||||
public function show($lock);
|
||||
|
||||
/**
|
||||
* Serializes the operation in a human readable format
|
||||
*
|
||||
|
|
|
@ -43,6 +43,12 @@ abstract class SolverOperation implements OperationInterface
|
|||
return $this->reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $lock bool Whether this is an operation on the lock file
|
||||
* @return string
|
||||
*/
|
||||
abstract public function show($lock);
|
||||
|
||||
protected function formatVersion(PackageInterface $package)
|
||||
{
|
||||
return $package->getFullPrettyVersion();
|
||||
|
|
|
@ -59,8 +59,16 @@ class UninstallOperation extends SolverOperation
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
public function show($lock)
|
||||
{
|
||||
return 'Uninstalling '.$this->package->getPrettyName().' ('.$this->formatVersion($this->package).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->show(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,9 +72,17 @@ class UpdateOperation extends SolverOperation
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
public function show($lock)
|
||||
{
|
||||
return 'Updating '.$this->initialPackage->getPrettyName().' ('.$this->formatVersion($this->initialPackage).') to '.
|
||||
$this->targetPackage->getPrettyName(). ' ('.$this->formatVersion($this->targetPackage).')';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->show(false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ interface PolicyInterface
|
|||
{
|
||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
||||
|
||||
public function findUpdatePackages(Pool $pool, array $installedMap, PackageInterface $package);
|
||||
public function findUpdatePackages(Pool $pool, PackageInterface $package);
|
||||
|
||||
public function selectPreferredPackages(Pool $pool, array $installedMap, array $literals, $requiredPackage = null);
|
||||
public function selectPreferredPackages(Pool $pool, array $literals, $requiredPackage = null);
|
||||
}
|
||||
|
|
|
@ -12,18 +12,11 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Package\BasePackage;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\Version\VersionParser;
|
||||
use Composer\Repository\RepositorySet;
|
||||
use Composer\Semver\Constraint\ConstraintInterface;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Composer\Semver\Constraint\EmptyConstraint;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\ComposerRepository;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Package\PackageInterface;
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,11 +14,11 @@ namespace Composer\DependencyResolver;
|
|||
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\BasePackage;
|
||||
use Composer\Package\Package;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\AsyncRepositoryInterface;
|
||||
use Composer\Repository\ComposerRepository;
|
||||
use Composer\Repository\InstalledRepositoryInterface;
|
||||
use Composer\Repository\LockArrayRepository;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
use Composer\Semver\Constraint\MultiConstraint;
|
||||
|
@ -31,6 +31,7 @@ class PoolBuilder
|
|||
private $isPackageAcceptableCallable;
|
||||
private $filterRequires;
|
||||
private $rootAliases;
|
||||
private $rootReferences;
|
||||
|
||||
private $aliasMap = array();
|
||||
private $nameConstraints = array();
|
||||
|
@ -46,22 +47,45 @@ class PoolBuilder
|
|||
$this->filterRequires = $filterRequires;
|
||||
}
|
||||
|
||||
public function buildPool(array $repositories, array $rootAliases, Request $request)
|
||||
public function buildPool(array $repositories, array $rootAliases, array $rootReferences, Request $request)
|
||||
{
|
||||
$pool = new Pool($this->filterRequires);
|
||||
$this->rootAliases = $rootAliases;
|
||||
$this->rootReferences = $rootReferences;
|
||||
|
||||
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
||||
$loadNames = array();
|
||||
foreach ($request->getFixedPackages() as $package) {
|
||||
// TODO can actually use very specific constraint
|
||||
$loadNames[$package->getName()] = null;
|
||||
}
|
||||
|
||||
foreach ($request->getJobs() as $job) {
|
||||
switch ($job['cmd']) {
|
||||
case 'install':
|
||||
$loadNames[$job['packageName']] = $job['constraint'];
|
||||
$this->nameConstraints[$job['packageName']] = $job['constraint'] ? new MultiConstraint(array($job['constraint']), false) : null;
|
||||
// TODO currently lock above is always NULL if we adjust that, this needs to merge constraints
|
||||
// TODO does it really make sense that we can have install requests for the same package that is actively locked with non-matching constraints?
|
||||
// also see the solver-problems.test test case
|
||||
$constraint = array_key_exists($job['packageName'], $loadNames) ? null : $job['constraint'];
|
||||
$loadNames[$job['packageName']] = $constraint;
|
||||
$this->nameConstraints[$job['packageName']] = $constraint ? new MultiConstraint(array($constraint), false) : null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// packages from the locked repository only get loaded if they are explicitly fixed
|
||||
foreach ($repositories as $key => $repository) {
|
||||
if ($repository === $request->getLockedRepository()) {
|
||||
foreach ($repository->getPackages() as $lockedPackage) {
|
||||
foreach ($request->getFixedPackages() as $package) {
|
||||
if ($package === $lockedPackage) {
|
||||
$loadNames += $this->loadPackage($request, $package, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!empty($loadNames)) {
|
||||
$loadIds = array();
|
||||
foreach ($repositories as $key => $repository) {
|
||||
|
@ -76,7 +100,7 @@ class PoolBuilder
|
|||
|
||||
$newLoadNames = array();
|
||||
foreach ($repositories as $key => $repository) {
|
||||
if ($repository instanceof PlatformRepository || $repository instanceof InstalledRepositoryInterface) {
|
||||
if ($repository instanceof PlatformRepository || $repository instanceof InstalledRepositoryInterface || $repository === $request->getLockedRepository()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -90,7 +114,7 @@ class PoolBuilder
|
|||
|
||||
foreach ($packages as $package) {
|
||||
if (call_user_func($this->isPackageAcceptableCallable, $package->getNames(), $package->getStability())) {
|
||||
$newLoadNames += $this->loadPackage($package, $key);
|
||||
$newLoadNames += $this->loadPackage($request, $package, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +123,7 @@ class PoolBuilder
|
|||
}
|
||||
|
||||
foreach ($this->packages as $i => $package) {
|
||||
// we check all alias related packages at once, so no need ot check individual aliases
|
||||
// we check all alias related packages at once, so no need to check individual aliases
|
||||
// isset also checks non-null value
|
||||
if (!$package instanceof AliasPackage && isset($this->nameConstraints[$package->getName()])) {
|
||||
$constraint = $this->nameConstraints[$package->getName()];
|
||||
|
@ -128,7 +152,7 @@ class PoolBuilder
|
|||
if ($repository instanceof PlatformRepository ||
|
||||
$repository instanceof InstalledRepositoryInterface) {
|
||||
foreach ($repository->getPackages() as $package) {
|
||||
$this->loadPackage($package, $key);
|
||||
$this->loadPackage($request, $package, $key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +166,7 @@ class PoolBuilder
|
|||
return $pool;
|
||||
}
|
||||
|
||||
private function loadPackage(PackageInterface $package, $repoIndex)
|
||||
private function loadPackage(Request $request, PackageInterface $package, $repoIndex)
|
||||
{
|
||||
$index = count($this->packages);
|
||||
$this->packages[] = $package;
|
||||
|
@ -152,8 +176,18 @@ class PoolBuilder
|
|||
$this->aliasMap[spl_object_hash($package->getAliasOf())][$index] = $package;
|
||||
}
|
||||
|
||||
// handle root package aliases
|
||||
$name = $package->getName();
|
||||
|
||||
// we're simply setting the root references on all versions for a name here and rely on the solver to pick the
|
||||
// right version. It'd be more work to figure out which versions and which aliases of those versions this may
|
||||
// apply to
|
||||
if (isset($this->rootReferences[$name])) {
|
||||
// do not modify the references on already locked packages
|
||||
if (!$request->isFixedPackage($package)) {
|
||||
$package->setSourceDistReferences($this->rootReferences[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($this->rootAliases[$name][$package->getVersion()])) {
|
||||
$alias = $this->rootAliases[$name][$package->getVersion()];
|
||||
if ($package instanceof AliasPackage) {
|
||||
|
@ -183,6 +217,7 @@ class PoolBuilder
|
|||
// TODO addConstraint function?
|
||||
$this->nameConstraints[$require] = new MultiConstraint(array_merge(array($linkConstraint), $this->nameConstraints[$require]->getConstraints()), false);
|
||||
}
|
||||
// else it is null and should stay null
|
||||
} else {
|
||||
$this->nameConstraints[$require] = null;
|
||||
}
|
||||
|
|
|
@ -68,7 +68,7 @@ class Problem
|
|||
/**
|
||||
* A human readable textual representation of the problem's reasons
|
||||
*
|
||||
* @param array $installedMap A map of all installed packages
|
||||
* @param array $installedMap A map of all present packages
|
||||
* @return string
|
||||
*/
|
||||
public function getPrettyString(array $installedMap = array(), array $learnedPool = array())
|
||||
|
@ -90,7 +90,7 @@ class Problem
|
|||
$packages = array();
|
||||
}
|
||||
|
||||
if ($job && $job['cmd'] === 'install' && empty($packages)) {
|
||||
if ($job && ($job['cmd'] === 'install' || $job['cmd'] === 'fix') && empty($packages)) {
|
||||
|
||||
// handle php/hhvm
|
||||
if ($packageName === 'php' || $packageName === 'php-64bit' || $packageName === 'hhvm') {
|
||||
|
@ -208,6 +208,13 @@ class Problem
|
|||
$packageName = $job['packageName'];
|
||||
$constraint = $job['constraint'];
|
||||
switch ($job['cmd']) {
|
||||
case 'fix':
|
||||
$package = $job['package'];
|
||||
if ($job['lockable']) {
|
||||
return $package->getPrettyName().' is locked to version '.$package->getPrettyVersion().' and an update of this package was not requested.';
|
||||
}
|
||||
|
||||
return $package->getPrettyName().' is present at version '.$package->getPrettyVersion() . ' and cannot be modified by Composer';
|
||||
case 'install':
|
||||
$packages = $this->pool->whatProvides($packageName, $constraint);
|
||||
if (!$packages) {
|
||||
|
@ -224,7 +231,7 @@ class Problem
|
|||
if (isset($constraint)) {
|
||||
$packages = $this->pool->whatProvides($packageName, $constraint);
|
||||
} else {
|
||||
$packages = array();
|
||||
$packages = $this->pool->whatProvides($job['packageName'], null);
|
||||
}
|
||||
|
||||
return 'Job(cmd='.$job['cmd'].', target='.$packageName.', packages=['.$this->getPackageList($packages).'])';
|
||||
|
|
|
@ -12,6 +12,10 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Package\Package;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\RootAliasPackage;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Semver\Constraint\ConstraintInterface;
|
||||
|
||||
/**
|
||||
|
@ -19,11 +23,14 @@ use Composer\Semver\Constraint\ConstraintInterface;
|
|||
*/
|
||||
class Request
|
||||
{
|
||||
protected $jobs;
|
||||
protected $lockedRepository;
|
||||
protected $jobs = array();
|
||||
protected $fixedPackages = array();
|
||||
protected $unlockables = array();
|
||||
|
||||
public function __construct()
|
||||
public function __construct(RepositoryInterface $lockedRepository = null)
|
||||
{
|
||||
$this->jobs = array();
|
||||
$this->lockedRepository = $lockedRepository;
|
||||
}
|
||||
|
||||
public function install($packageName, ConstraintInterface $constraint = null)
|
||||
|
@ -31,11 +38,6 @@ class Request
|
|||
$this->addJob($packageName, 'install', $constraint);
|
||||
}
|
||||
|
||||
public function update($packageName, ConstraintInterface $constraint = null)
|
||||
{
|
||||
$this->addJob($packageName, 'update', $constraint);
|
||||
}
|
||||
|
||||
public function remove($packageName, ConstraintInterface $constraint = null)
|
||||
{
|
||||
$this->addJob($packageName, 'remove', $constraint);
|
||||
|
@ -43,18 +45,21 @@ class Request
|
|||
|
||||
/**
|
||||
* Mark an existing package as being installed and having to remain installed
|
||||
*
|
||||
* These jobs will not be tempered with by the solver
|
||||
*
|
||||
* @param string $packageName
|
||||
* @param ConstraintInterface|null $constraint
|
||||
*/
|
||||
public function fix($packageName, ConstraintInterface $constraint = null)
|
||||
public function fixPackage(PackageInterface $package, $lockable = true)
|
||||
{
|
||||
$this->addJob($packageName, 'install', $constraint, true);
|
||||
if ($package instanceof RootAliasPackage) {
|
||||
$package = $package->getAliasOf();
|
||||
}
|
||||
|
||||
$this->fixedPackages[spl_object_hash($package)] = $package;
|
||||
|
||||
if (!$lockable) {
|
||||
$this->unlockables[] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
protected function addJob($packageName, $cmd, ConstraintInterface $constraint = null, $fixed = false)
|
||||
protected function addJob($packageName, $cmd, ConstraintInterface $constraint = null)
|
||||
{
|
||||
$packageName = strtolower($packageName);
|
||||
|
||||
|
@ -62,17 +67,56 @@ class Request
|
|||
'cmd' => $cmd,
|
||||
'packageName' => $packageName,
|
||||
'constraint' => $constraint,
|
||||
'fixed' => $fixed,
|
||||
);
|
||||
}
|
||||
|
||||
public function updateAll()
|
||||
{
|
||||
$this->jobs[] = array('cmd' => 'update-all');
|
||||
}
|
||||
|
||||
public function getJobs()
|
||||
{
|
||||
return $this->jobs;
|
||||
}
|
||||
|
||||
public function getFixedPackages()
|
||||
{
|
||||
return $this->fixedPackages;
|
||||
}
|
||||
|
||||
public function isFixedPackage(PackageInterface $package)
|
||||
{
|
||||
return isset($this->fixedPackages[spl_object_hash($package)]);
|
||||
}
|
||||
|
||||
// TODO look into removing the packageIds option, the only place true is used is for the installed map in the solver problems
|
||||
// some locked packages may not be in the pool so they have a package->id of -1
|
||||
public function getPresentMap($packageIds = false)
|
||||
{
|
||||
$presentMap = array();
|
||||
|
||||
if ($this->lockedRepository) {
|
||||
foreach ($this->lockedRepository->getPackages() as $package) {
|
||||
$presentMap[$packageIds ? $package->id : spl_object_hash($package)] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->fixedPackages as $package) {
|
||||
$presentMap[$packageIds ? $package->id : spl_object_hash($package)] = $package;
|
||||
}
|
||||
|
||||
return $presentMap;
|
||||
}
|
||||
|
||||
public function getUnlockableMap()
|
||||
{
|
||||
$unlockableMap = array();
|
||||
|
||||
foreach ($this->unlockables as $package) {
|
||||
$unlockableMap[$package->id] = $package;
|
||||
}
|
||||
|
||||
return $unlockableMap;
|
||||
}
|
||||
|
||||
public function getLockedRepository()
|
||||
{
|
||||
return $this->lockedRepository;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ abstract class Rule
|
|||
case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
|
||||
return $ruleText;
|
||||
case self::RULE_PACKAGE_SAME_NAME:
|
||||
return 'Can only install one of: ' . $this->formatPackagesUnique($pool, $literals) . '.';
|
||||
return 'Same name, can only install one of: ' . $this->formatPackagesUnique($pool, $literals) . '.';
|
||||
case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
|
||||
return $ruleText;
|
||||
case self::RULE_LEARNED:
|
||||
|
|
|
@ -12,9 +12,11 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\Package\LinkConstraint\VersionConstraint;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
|
@ -24,8 +26,6 @@ class RuleSetGenerator
|
|||
protected $policy;
|
||||
protected $pool;
|
||||
protected $rules;
|
||||
protected $jobs;
|
||||
protected $installedMap;
|
||||
protected $addedMap;
|
||||
protected $conflictAddedMap;
|
||||
protected $addedPackages;
|
||||
|
@ -222,8 +222,6 @@ class RuleSetGenerator
|
|||
}
|
||||
|
||||
// check obsoletes and implicit obsoletes of a package
|
||||
$isInstalled = isset($this->installedMap[$package->id]);
|
||||
|
||||
foreach ($package->getReplaces() as $link) {
|
||||
if (!isset($this->addedPackagesByNames[$link->getTarget()])) {
|
||||
continue;
|
||||
|
@ -236,7 +234,7 @@ class RuleSetGenerator
|
|||
}
|
||||
|
||||
if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
|
||||
$reason = $isInstalled ? Rule::RULE_INSTALLED_PACKAGE_OBSOLETES : Rule::RULE_PACKAGE_OBSOLETES;
|
||||
$reason = Rule::RULE_PACKAGE_OBSOLETES;
|
||||
$this->addRule(RuleSet::TYPE_PACKAGE, $this->createRule2Literals($package, $provider, $reason, $link));
|
||||
}
|
||||
}
|
||||
|
@ -258,21 +256,39 @@ class RuleSetGenerator
|
|||
return $impossible;
|
||||
}
|
||||
|
||||
protected function addRulesForJobs($ignorePlatformReqs)
|
||||
protected function addRulesForRequest(Request $request, $ignorePlatformReqs)
|
||||
{
|
||||
foreach ($this->jobs as $job) {
|
||||
$unlockableMap = $request->getUnlockableMap();
|
||||
|
||||
foreach ($request->getFixedPackages() as $package) {
|
||||
if ($package->id == -1) {
|
||||
throw new \RuntimeException("Fixed package ".$package->getName()." ".$package->getVersion().($package instanceof AliasPackage ? " (alias)" : "")." was not added to solver pool.");
|
||||
}
|
||||
|
||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||
|
||||
$rule = $this->createInstallOneOfRule(array($package), Rule::RULE_JOB_INSTALL, array(
|
||||
'cmd' => 'fix',
|
||||
'packageName' => $package->getName(),
|
||||
'constraint' => null,
|
||||
'package' => $package,
|
||||
'lockable' => !isset($unlockableMap[$package->id]),
|
||||
'fixed' => true
|
||||
));
|
||||
$this->addRule(RuleSet::TYPE_JOB, $rule);
|
||||
}
|
||||
|
||||
foreach ($request->getJobs() as $job) {
|
||||
switch ($job['cmd']) {
|
||||
case 'install':
|
||||
if (!$job['fixed'] && $ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
|
||||
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
|
||||
break;
|
||||
}
|
||||
|
||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||
if ($packages) {
|
||||
foreach ($packages as $package) {
|
||||
if (!isset($this->installedMap[$package->id])) {
|
||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||
}
|
||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||
}
|
||||
|
||||
$rule = $this->createInstallOneOfRule($packages, Rule::RULE_JOB_INSTALL, $job);
|
||||
|
@ -292,21 +308,16 @@ class RuleSetGenerator
|
|||
}
|
||||
}
|
||||
|
||||
public function getRulesFor($jobs, $installedMap, $ignorePlatformReqs = false)
|
||||
public function getRulesFor(Request $request, $ignorePlatformReqs = false)
|
||||
{
|
||||
$this->jobs = $jobs;
|
||||
$this->rules = new RuleSet;
|
||||
$this->installedMap = $installedMap;
|
||||
|
||||
$this->addedMap = array();
|
||||
$this->conflictAddedMap = array();
|
||||
$this->addedPackages = array();
|
||||
$this->addedPackagesByNames = array();
|
||||
foreach ($this->installedMap as $package) {
|
||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||
}
|
||||
|
||||
$this->addRulesForJobs($ignorePlatformReqs);
|
||||
$this->addRulesForRequest($request, $ignorePlatformReqs);
|
||||
|
||||
$this->addConflictRules($ignorePlatformReqs);
|
||||
|
||||
|
|
|
@ -30,23 +30,18 @@ class Solver
|
|||
protected $policy;
|
||||
/** @var Pool */
|
||||
protected $pool = null;
|
||||
/** @var RepositoryInterface */
|
||||
protected $installed;
|
||||
|
||||
/** @var RuleSet */
|
||||
protected $rules;
|
||||
/** @var RuleSetGenerator */
|
||||
protected $ruleSetGenerator;
|
||||
/** @var array */
|
||||
protected $jobs;
|
||||
|
||||
/** @var int[] */
|
||||
protected $updateMap = array();
|
||||
/** @var RuleWatchGraph */
|
||||
protected $watchGraph;
|
||||
/** @var Decisions */
|
||||
protected $decisions;
|
||||
/** @var PackageInterface[] */
|
||||
protected $installedMap;
|
||||
protected $fixedMap;
|
||||
|
||||
/** @var int */
|
||||
protected $propagateIndex;
|
||||
|
@ -68,15 +63,13 @@ class Solver
|
|||
/**
|
||||
* @param PolicyInterface $policy
|
||||
* @param Pool $pool
|
||||
* @param RepositoryInterface $installed
|
||||
* @param IOInterface $io
|
||||
*/
|
||||
public function __construct(PolicyInterface $policy, Pool $pool, RepositoryInterface $installed, IOInterface $io)
|
||||
public function __construct(PolicyInterface $policy, Pool $pool, IOInterface $io)
|
||||
{
|
||||
$this->io = $io;
|
||||
$this->policy = $policy;
|
||||
$this->pool = $pool;
|
||||
$this->installed = $installed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -154,7 +147,6 @@ class Solver
|
|||
if (abs($literal) !== abs($assertRuleLiteral)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$problem->addRule($assertRule);
|
||||
$this->disableProblem($assertRule);
|
||||
}
|
||||
|
@ -165,36 +157,22 @@ class Solver
|
|||
}
|
||||
}
|
||||
|
||||
protected function setupInstalledMap()
|
||||
protected function setupFixedMap(Request $request)
|
||||
{
|
||||
$this->installedMap = array();
|
||||
foreach ($this->installed->getPackages() as $package) {
|
||||
$this->installedMap[$package->id] = $package;
|
||||
$this->fixedMap = array();
|
||||
foreach ($request->getFixedPackages() as $package) {
|
||||
$this->fixedMap[$package->id] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param bool $ignorePlatformReqs
|
||||
*/
|
||||
protected function checkForRootRequireProblems($ignorePlatformReqs)
|
||||
protected function checkForRootRequireProblems($request, $ignorePlatformReqs)
|
||||
{
|
||||
foreach ($this->jobs as $job) {
|
||||
foreach ($request->getJobs() as $job) {
|
||||
switch ($job['cmd']) {
|
||||
case 'update':
|
||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||
foreach ($packages as $package) {
|
||||
if (isset($this->installedMap[$package->id])) {
|
||||
$this->updateMap[$package->id] = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'update-all':
|
||||
foreach ($this->installedMap as $package) {
|
||||
$this->updateMap[$package->id] = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'install':
|
||||
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
|
||||
break;
|
||||
|
@ -213,18 +191,16 @@ class Solver
|
|||
/**
|
||||
* @param Request $request
|
||||
* @param bool $ignorePlatformReqs
|
||||
* @return array
|
||||
* @return LockTransaction
|
||||
*/
|
||||
public function solve(Request $request, $ignorePlatformReqs = false)
|
||||
{
|
||||
$this->jobs = $request->getJobs();
|
||||
|
||||
$this->setupInstalledMap();
|
||||
$this->setupFixedMap($request);
|
||||
|
||||
$this->io->writeError('Generating rules', true, IOInterface::DEBUG);
|
||||
$this->ruleSetGenerator = new RuleSetGenerator($this->policy, $this->pool);
|
||||
$this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs);
|
||||
$this->checkForRootRequireProblems($ignorePlatformReqs);
|
||||
$this->rules = $this->ruleSetGenerator->getRulesFor($request, $ignorePlatformReqs);
|
||||
$this->checkForRootRequireProblems($request, $ignorePlatformReqs);
|
||||
$this->decisions = new Decisions($this->pool);
|
||||
$this->watchGraph = new RuleWatchGraph;
|
||||
|
||||
|
@ -241,20 +217,11 @@ class Solver
|
|||
$this->io->writeError('', true, IOInterface::DEBUG);
|
||||
$this->io->writeError(sprintf('Dependency resolution completed in %.3f seconds', microtime(true) - $before), true, IOInterface::VERBOSE);
|
||||
|
||||
// decide to remove everything that's installed and undecided
|
||||
foreach ($this->installedMap as $packageId => $void) {
|
||||
if ($this->decisions->undecided($packageId)) {
|
||||
$this->decisions->decide(-$packageId, 1, null);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->problems) {
|
||||
throw new SolverProblemsException($this->problems, $this->installedMap, $this->learnedPool);
|
||||
throw new SolverProblemsException($this->problems, $request->getPresentMap(true), $this->learnedPool);
|
||||
}
|
||||
|
||||
$transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisions);
|
||||
|
||||
return $transaction->getOperations();
|
||||
return new LockTransaction($this->pool, $request->getPresentMap(), $request->getUnlockableMap(), $this->decisions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -393,7 +360,7 @@ class Solver
|
|||
private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
|
||||
{
|
||||
// choose best package to install from decisionQueue
|
||||
$literals = $this->policy->selectPreferredPackages($this->pool, $this->installedMap, $decisionQueue, $rule->getRequiredPackage());
|
||||
$literals = $this->policy->selectPreferredPackages($this->pool, $decisionQueue, $rule->getRequiredPackage());
|
||||
|
||||
$selectedLiteral = array_shift($literals);
|
||||
|
||||
|
@ -729,19 +696,14 @@ class Solver
|
|||
}
|
||||
|
||||
if ($noneSatisfied && count($decisionQueue)) {
|
||||
// prune all update packages until installed version
|
||||
// except for requested updates
|
||||
if (count($this->installed) != count($this->updateMap)) {
|
||||
$prunedQueue = array();
|
||||
foreach ($decisionQueue as $literal) {
|
||||
if (isset($this->installedMap[abs($literal)])) {
|
||||
$prunedQueue[] = $literal;
|
||||
if (isset($this->updateMap[abs($literal)])) {
|
||||
$prunedQueue = $decisionQueue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if any of the options in the decision queue are fixed, only use those
|
||||
$prunedQueue = array();
|
||||
foreach ($decisionQueue as $literal) {
|
||||
if (isset($this->fixedMap[abs($literal)])) {
|
||||
$prunedQueue[] = $literal;
|
||||
}
|
||||
}
|
||||
if (!empty($prunedQueue)) {
|
||||
$decisionQueue = $prunedQueue;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,162 +12,209 @@
|
|||
|
||||
namespace Composer\DependencyResolver;
|
||||
|
||||
use Composer\DependencyResolver\Operation\MarkAliasUninstalledOperation;
|
||||
use Composer\DependencyResolver\Operation\UninstallOperation;
|
||||
use Composer\Package\AliasPackage;
|
||||
use Composer\Package\Link;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Repository\PlatformRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Semver\Constraint\Constraint;
|
||||
|
||||
/**
|
||||
* @author Nils Adermann <naderman@naderman.de>
|
||||
*/
|
||||
class Transaction
|
||||
{
|
||||
protected $policy;
|
||||
protected $pool;
|
||||
protected $installedMap;
|
||||
protected $decisions;
|
||||
protected $transaction;
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $operations;
|
||||
|
||||
public function __construct($policy, $pool, $installedMap, $decisions)
|
||||
/**
|
||||
* Packages present at the beginning of the transaction
|
||||
* @var array
|
||||
*/
|
||||
protected $presentPackages;
|
||||
|
||||
/**
|
||||
* Package set resulting from this transaction
|
||||
* @var array
|
||||
*/
|
||||
protected $resultPackageMap;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $resultPackagesByName = array();
|
||||
|
||||
public function __construct($presentPackages, $resultPackages)
|
||||
{
|
||||
$this->policy = $policy;
|
||||
$this->pool = $pool;
|
||||
$this->installedMap = $installedMap;
|
||||
$this->decisions = $decisions;
|
||||
$this->transaction = array();
|
||||
$this->presentPackages = $presentPackages;
|
||||
$this->setResultPackageMaps($resultPackages);
|
||||
$this->operations = $this->calculateOperations();
|
||||
}
|
||||
|
||||
public function getOperations()
|
||||
{
|
||||
$installMeansUpdateMap = $this->findUpdates();
|
||||
return $this->operations;
|
||||
}
|
||||
|
||||
$updateMap = array();
|
||||
$installMap = array();
|
||||
$uninstallMap = array();
|
||||
private function setResultPackageMaps($resultPackages)
|
||||
{
|
||||
$packageSort = function (PackageInterface $a, PackageInterface $b) {
|
||||
// sort alias packages by the same name behind their non alias version
|
||||
if ($a->getName() == $b->getName() && $a instanceof AliasPackage != $b instanceof AliasPackage) {
|
||||
return $a instanceof AliasPackage ? -1 : 1;
|
||||
}
|
||||
return strcmp($b->getName(), $a->getName());
|
||||
};
|
||||
|
||||
foreach ($this->decisions as $i => $decision) {
|
||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||
$reason = $decision[Decisions::DECISION_REASON];
|
||||
$this->resultPackageMap = array();
|
||||
foreach ($resultPackages as $package) {
|
||||
$this->resultPackageMap[spl_object_hash($package)] = $package;
|
||||
foreach ($package->getNames() as $name) {
|
||||
$this->resultPackagesByName[$name][] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
$package = $this->pool->literalToPackage($literal);
|
||||
uasort($this->resultPackageMap, $packageSort);
|
||||
foreach ($this->resultPackagesByName as $name => $packages) {
|
||||
uasort($this->resultPackagesByName[$name], $packageSort);
|
||||
}
|
||||
}
|
||||
|
||||
// wanted & installed || !wanted & !installed
|
||||
if (($literal > 0) == isset($this->installedMap[$package->id])) {
|
||||
protected function calculateOperations()
|
||||
{
|
||||
$operations = array();
|
||||
|
||||
$presentPackageMap = array();
|
||||
$removeMap = array();
|
||||
$presentAliasMap = array();
|
||||
$removeAliasMap = array();
|
||||
foreach ($this->presentPackages as $package) {
|
||||
if ($package instanceof AliasPackage) {
|
||||
$presentAliasMap[$package->getName().'::'.$package->getVersion()] = $package;
|
||||
$removeAliasMap[$package->getName().'::'.$package->getVersion()] = $package;
|
||||
} else {
|
||||
$presentPackageMap[$package->getName()] = $package;
|
||||
$removeMap[$package->getName()] = $package;
|
||||
}
|
||||
}
|
||||
|
||||
$stack = $this->getRootPackages();
|
||||
|
||||
$visited = array();
|
||||
$processed = array();
|
||||
|
||||
while (!empty($stack)) {
|
||||
$package = array_pop($stack);
|
||||
|
||||
if (isset($processed[spl_object_hash($package)])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($literal > 0) {
|
||||
if (isset($installMeansUpdateMap[abs($literal)]) && !$package instanceof AliasPackage) {
|
||||
$source = $installMeansUpdateMap[abs($literal)];
|
||||
|
||||
$updateMap[$package->id] = array(
|
||||
'package' => $package,
|
||||
'source' => $source,
|
||||
'reason' => $reason,
|
||||
);
|
||||
|
||||
// avoid updates to one package from multiple origins
|
||||
unset($installMeansUpdateMap[abs($literal)]);
|
||||
$ignoreRemove[$source->id] = true;
|
||||
} else {
|
||||
$installMap[$package->id] = array(
|
||||
'package' => $package,
|
||||
'reason' => $reason,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->decisions as $i => $decision) {
|
||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||
$reason = $decision[Decisions::DECISION_REASON];
|
||||
$package = $this->pool->literalToPackage($literal);
|
||||
|
||||
if ($literal <= 0 &&
|
||||
isset($this->installedMap[$package->id]) &&
|
||||
!isset($ignoreRemove[$package->id])) {
|
||||
$uninstallMap[$package->id] = array(
|
||||
'package' => $package,
|
||||
'reason' => $reason,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$this->transactionFromMaps($installMap, $updateMap, $uninstallMap);
|
||||
|
||||
return $this->transaction;
|
||||
}
|
||||
|
||||
protected function transactionFromMaps($installMap, $updateMap, $uninstallMap)
|
||||
{
|
||||
$queue = array_map(
|
||||
function ($operation) {
|
||||
return $operation['package'];
|
||||
},
|
||||
$this->findRootPackages($installMap, $updateMap)
|
||||
);
|
||||
|
||||
$visited = array();
|
||||
|
||||
while (!empty($queue)) {
|
||||
$package = array_pop($queue);
|
||||
$packageId = $package->id;
|
||||
|
||||
if (!isset($visited[$packageId])) {
|
||||
$queue[] = $package;
|
||||
if (!isset($visited[spl_object_hash($package)])) {
|
||||
$visited[spl_object_hash($package)] = true;
|
||||
|
||||
$stack[] = $package;
|
||||
if ($package instanceof AliasPackage) {
|
||||
$queue[] = $package->getAliasOf();
|
||||
$stack[] = $package->getAliasOf();
|
||||
} else {
|
||||
foreach ($package->getRequires() as $link) {
|
||||
$possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
||||
$possibleRequires = $this->getProvidersInResult($link);
|
||||
|
||||
foreach ($possibleRequires as $require) {
|
||||
$queue[] = $require;
|
||||
$stack[] = $require;
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif (!isset($processed[spl_object_hash($package)])) {
|
||||
$processed[spl_object_hash($package)] = true;
|
||||
|
||||
$visited[$package->id] = true;
|
||||
} else {
|
||||
if (isset($installMap[$packageId])) {
|
||||
$this->install(
|
||||
$installMap[$packageId]['package'],
|
||||
$installMap[$packageId]['reason']
|
||||
);
|
||||
unset($installMap[$packageId]);
|
||||
}
|
||||
if (isset($updateMap[$packageId])) {
|
||||
$this->update(
|
||||
$updateMap[$packageId]['source'],
|
||||
$updateMap[$packageId]['package'],
|
||||
$updateMap[$packageId]['reason']
|
||||
);
|
||||
unset($updateMap[$packageId]);
|
||||
if ($package instanceof AliasPackage) {
|
||||
$aliasKey = $package->getName().'::'.$package->getVersion();
|
||||
if (isset($presentAliasMap[$aliasKey])) {
|
||||
unset($removeAliasMap[$aliasKey]);
|
||||
} else {
|
||||
$operations[] = new Operation\MarkAliasInstalledOperation($package);
|
||||
}
|
||||
} else {
|
||||
if (isset($presentPackageMap[$package->getName()])) {
|
||||
$source = $presentPackageMap[$package->getName()];
|
||||
|
||||
// do we need to update?
|
||||
// TODO different for lock?
|
||||
if ($package->getVersion() != $presentPackageMap[$package->getName()]->getVersion()) {
|
||||
$operations[] = new Operation\UpdateOperation($source, $package);
|
||||
} elseif ($package->isDev() && $package->getSourceReference() !== $presentPackageMap[$package->getName()]->getSourceReference()) {
|
||||
$operations[] = new Operation\UpdateOperation($source, $package);
|
||||
}
|
||||
unset($removeMap[$package->getName()]);
|
||||
} else {
|
||||
$operations[] = new Operation\InstallOperation($package);
|
||||
unset($removeMap[$package->getName()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($uninstallMap as $uninstall) {
|
||||
$this->uninstall($uninstall['package'], $uninstall['reason']);
|
||||
foreach ($removeMap as $name => $package) {
|
||||
array_unshift($operations, new Operation\UninstallOperation($package, null));
|
||||
}
|
||||
foreach ($removeAliasMap as $nameVersion => $package) {
|
||||
$operations[] = new Operation\MarkAliasUninstalledOperation($package, null);
|
||||
}
|
||||
|
||||
$operations = $this->movePluginsToFront($operations);
|
||||
// TODO fix this:
|
||||
// we have to do this again here even though the above stack code did it because moving plugins moves them before uninstalls
|
||||
$operations = $this->moveUninstallsToFront($operations);
|
||||
|
||||
// TODO skip updates which don't update? is this needed? we shouldn't schedule this update in the first place?
|
||||
/*
|
||||
if ('update' === $jobType) {
|
||||
$targetPackage = $operation->getTargetPackage();
|
||||
if ($targetPackage->isDev()) {
|
||||
$initialPackage = $operation->getInitialPackage();
|
||||
if ($targetPackage->getVersion() === $initialPackage->getVersion()
|
||||
&& (!$targetPackage->getSourceReference() || $targetPackage->getSourceReference() === $initialPackage->getSourceReference())
|
||||
&& (!$targetPackage->getDistReference() || $targetPackage->getDistReference() === $initialPackage->getDistReference())
|
||||
) {
|
||||
$this->io->writeError(' - Skipping update of ' . $targetPackage->getPrettyName() . ' to the same reference-locked version', true, IOInterface::DEBUG);
|
||||
$this->io->writeError('', true, IOInterface::DEBUG);
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return $this->operations = $operations;
|
||||
}
|
||||
|
||||
protected function findRootPackages($installMap, $updateMap)
|
||||
/**
|
||||
* Determine which packages in the result are not required by any other packages in it.
|
||||
*
|
||||
* These serve as a starting point to enumerate packages in a topological order despite potential cycles.
|
||||
* If there are packages with a cycle on the top level the package with the lowest name gets picked
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getRootPackages()
|
||||
{
|
||||
$packages = $installMap + $updateMap;
|
||||
$roots = $packages;
|
||||
$roots = $this->resultPackageMap;
|
||||
|
||||
foreach ($packages as $packageId => $operation) {
|
||||
$package = $operation['package'];
|
||||
|
||||
if (!isset($roots[$packageId])) {
|
||||
foreach ($this->resultPackageMap as $packageHash => $package) {
|
||||
if (!isset($roots[$packageHash])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($package->getRequires() as $link) {
|
||||
$possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
||||
$possibleRequires = $this->getProvidersInResult($link);
|
||||
|
||||
foreach ($possibleRequires as $require) {
|
||||
if ($require !== $package) {
|
||||
unset($roots[$require->id]);
|
||||
unset($roots[spl_object_hash($require)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -176,69 +223,87 @@ class Transaction
|
|||
return $roots;
|
||||
}
|
||||
|
||||
protected function findUpdates()
|
||||
protected function getProvidersInResult(Link $link)
|
||||
{
|
||||
$installMeansUpdateMap = array();
|
||||
if (!isset($this->resultPackagesByName[$link->getTarget()])) {
|
||||
return array();
|
||||
}
|
||||
return $this->resultPackagesByName[$link->getTarget()];
|
||||
}
|
||||
|
||||
foreach ($this->decisions as $i => $decision) {
|
||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||
$package = $this->pool->literalToPackage($literal);
|
||||
/**
|
||||
* Workaround: if your packages depend on plugins, we must be sure
|
||||
* that those are installed / updated first; else it would lead to packages
|
||||
* being installed multiple times in different folders, when running Composer
|
||||
* twice.
|
||||
*
|
||||
* While this does not fix the root-causes of https://github.com/composer/composer/issues/1147,
|
||||
* it at least fixes the symptoms and makes usage of composer possible (again)
|
||||
* in such scenarios.
|
||||
*
|
||||
* @param Operation\OperationInterface[] $operations
|
||||
* @return Operation\OperationInterface[] reordered operation list
|
||||
*/
|
||||
private function movePluginsToFront(array $operations)
|
||||
{
|
||||
$pluginsNoDeps = array();
|
||||
$pluginsWithDeps = array();
|
||||
$pluginRequires = array();
|
||||
|
||||
if ($package instanceof AliasPackage) {
|
||||
foreach (array_reverse($operations, true) as $idx => $op) {
|
||||
if ($op instanceof Operation\InstallOperation) {
|
||||
$package = $op->getPackage();
|
||||
} elseif ($op instanceof Operation\UpdateOperation) {
|
||||
$package = $op->getTargetPackage();
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// !wanted & installed
|
||||
if ($literal <= 0 && isset($this->installedMap[$package->id])) {
|
||||
$updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
|
||||
// is this package a plugin?
|
||||
$isPlugin = $package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer';
|
||||
|
||||
$literals = array($package->id);
|
||||
// is this a plugin or a dependency of a plugin?
|
||||
if ($isPlugin || count(array_intersect($package->getNames(), $pluginRequires))) {
|
||||
// get the package's requires, but filter out any platform requirements or 'composer-plugin-api'
|
||||
$requires = array_filter(array_keys($package->getRequires()), function ($req) {
|
||||
return $req !== 'composer-plugin-api' && !preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $req);
|
||||
});
|
||||
|
||||
foreach ($updates as $update) {
|
||||
$literals[] = $update->id;
|
||||
// is this a plugin with no meaningful dependencies?
|
||||
if ($isPlugin && !count($requires)) {
|
||||
// plugins with no dependencies go to the very front
|
||||
array_unshift($pluginsNoDeps, $op);
|
||||
} else {
|
||||
// capture the requirements for this package so those packages will be moved up as well
|
||||
$pluginRequires = array_merge($pluginRequires, $requires);
|
||||
// move the operation to the front
|
||||
array_unshift($pluginsWithDeps, $op);
|
||||
}
|
||||
|
||||
foreach ($literals as $updateLiteral) {
|
||||
if ($updateLiteral !== $literal) {
|
||||
$installMeansUpdateMap[abs($updateLiteral)] = $package;
|
||||
}
|
||||
}
|
||||
unset($operations[$idx]);
|
||||
}
|
||||
}
|
||||
|
||||
return $installMeansUpdateMap;
|
||||
return array_merge($pluginsNoDeps, $pluginsWithDeps, $operations);
|
||||
}
|
||||
|
||||
protected function install($package, $reason)
|
||||
/**
|
||||
* Removals of packages should be executed before installations in
|
||||
* case two packages resolve to the same path (due to custom installers)
|
||||
*
|
||||
* @param Operation\OperationInterface[] $operations
|
||||
* @return Operation\OperationInterface[] reordered operation list
|
||||
*/
|
||||
private function moveUninstallsToFront(array $operations)
|
||||
{
|
||||
if ($package instanceof AliasPackage) {
|
||||
return $this->markAliasInstalled($package, $reason);
|
||||
$uninstOps = array();
|
||||
foreach ($operations as $idx => $op) {
|
||||
if ($op instanceof UninstallOperation) {
|
||||
$uninstOps[] = $op;
|
||||
unset($operations[$idx]);
|
||||
}
|
||||
}
|
||||
|
||||
$this->transaction[] = new Operation\InstallOperation($package, $reason);
|
||||
}
|
||||
|
||||
protected function update($from, $to, $reason)
|
||||
{
|
||||
$this->transaction[] = new Operation\UpdateOperation($from, $to, $reason);
|
||||
}
|
||||
|
||||
protected function uninstall($package, $reason)
|
||||
{
|
||||
if ($package instanceof AliasPackage) {
|
||||
return $this->markAliasUninstalled($package, $reason);
|
||||
}
|
||||
|
||||
$this->transaction[] = new Operation\UninstallOperation($package, $reason);
|
||||
}
|
||||
|
||||
protected function markAliasInstalled($package, $reason)
|
||||
{
|
||||
$this->transaction[] = new Operation\MarkAliasInstalledOperation($package, $reason);
|
||||
}
|
||||
|
||||
protected function markAliasUninstalled($package, $reason)
|
||||
{
|
||||
$this->transaction[] = new Operation\MarkAliasUninstalledOperation($package, $reason);
|
||||
return array_merge($uninstOps, $operations);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ use Composer\IO\IOInterface;
|
|||
use Composer\Composer;
|
||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||
use Composer\Repository\CompositeRepository;
|
||||
use Composer\Repository\RepositoryInterface;
|
||||
use Composer\Repository\RepositorySet;
|
||||
use Composer\Script;
|
||||
use Composer\Installer\PackageEvent;
|
||||
|
@ -130,9 +131,9 @@ class EventDispatcher
|
|||
* @return int return code of the executed script if any, for php scripts a false return
|
||||
* value is changed to 1, anything else to 0
|
||||
*/
|
||||
public function dispatchInstallerEvent($eventName, $devMode, PolicyInterface $policy, RepositorySet $repositorySet, CompositeRepository $installedRepo, Request $request, array $operations = array())
|
||||
public function dispatchInstallerEvent($eventName, $devMode, PolicyInterface $policy, RepositorySet $repositorySet, RepositoryInterface $lockedRepo, Request $request, array $operations = array())
|
||||
{
|
||||
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $policy, $repositorySet, $installedRepo, $request, $operations));
|
||||
return $this->doDispatch(new InstallerEvent($eventName, $this->composer, $this->io, $devMode, $policy, $repositorySet, $lockedRepo, $request, $operations));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -96,21 +96,21 @@ class SuggestedPackagesReporter
|
|||
* @param RepositoryInterface $installedRepo Installed packages
|
||||
* @return SuggestedPackagesReporter
|
||||
*/
|
||||
public function output(RepositoryInterface $installedRepo = null)
|
||||
public function output(RepositoryInterface $lockedRepo = null)
|
||||
{
|
||||
$suggestedPackages = $this->getPackages();
|
||||
$installedPackages = array();
|
||||
if (null !== $installedRepo && ! empty($suggestedPackages)) {
|
||||
foreach ($installedRepo->getPackages() as $package) {
|
||||
$installedPackages = array_merge(
|
||||
$installedPackages,
|
||||
$lockedPackages = array();
|
||||
if (null !== $lockedRepo && ! empty($suggestedPackages)) {
|
||||
foreach ($lockedRepo->getPackages() as $package) {
|
||||
$lockedPackages = array_merge(
|
||||
$lockedPackages,
|
||||
$package->getNames()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($suggestedPackages as $suggestion) {
|
||||
if (in_array($suggestion['target'], $installedPackages)) {
|
||||
if (in_array($suggestion['target'], $lockedPackages)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -411,4 +411,9 @@ class AliasPackage extends BasePackage implements CompletePackageInterface
|
|||
{
|
||||
return $this->aliasOf->setDistType($type);
|
||||
}
|
||||
|
||||
public function setSourceDistReferences($reference)
|
||||
{
|
||||
return $this->aliasOf->setSourceDistReferences($reference);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ class Locker
|
|||
/** @var ProcessExecutor */
|
||||
private $process;
|
||||
private $lockDataCache;
|
||||
private $virtualFileWritten;
|
||||
|
||||
/**
|
||||
* Initializes packages locker.
|
||||
|
@ -112,7 +113,7 @@ class Locker
|
|||
*/
|
||||
public function isLocked()
|
||||
{
|
||||
if (!$this->lockFile->exists()) {
|
||||
if (!$this->virtualFileWritten && !$this->lockFile->exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -161,7 +162,7 @@ class Locker
|
|||
if (isset($lockData['packages-dev'])) {
|
||||
$lockedPackages = array_merge($lockedPackages, $lockData['packages-dev']);
|
||||
} else {
|
||||
throw new \RuntimeException('The lock file does not contain require-dev information, run install with the --no-dev option or run update to install those packages.');
|
||||
throw new \RuntimeException('The lock file does not contain require-dev information, run install with the --no-dev option or delete it and run composer update to generate a new lock file.');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -170,8 +171,24 @@ class Locker
|
|||
}
|
||||
|
||||
if (isset($lockedPackages[0]['name'])) {
|
||||
$packageByName = array();
|
||||
foreach ($lockedPackages as $info) {
|
||||
$packages->addPackage($this->loader->load($info));
|
||||
$package = $this->loader->load($info);
|
||||
$packages->addPackage($package);
|
||||
$packageByName[$package->getName()] = $package;
|
||||
|
||||
if ($package instanceof AliasPackage) {
|
||||
$packages->addPackage($package->getAliasOf());
|
||||
$packageByName[$package->getAliasOf()->getName()] = $package->getAliasOf();
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($lockData['aliases'])) {
|
||||
foreach ($lockData['aliases'] as $alias) {
|
||||
if (isset($packageByName[$alias['package']])) {
|
||||
$packages->addPackage(new AliasPackage($packageByName[$alias['package']], $alias['alias_normalized'], $alias['alias']));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $packages;
|
||||
|
@ -286,10 +303,11 @@ class Locker
|
|||
* @param bool $preferStable
|
||||
* @param bool $preferLowest
|
||||
* @param array $platformOverrides
|
||||
* @param bool $write Whether to actually write data to disk, useful in tests and for --dry-run
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest, array $platformOverrides)
|
||||
public function setLockData(array $packages, $devPackages, array $platformReqs, $platformDevReqs, array $aliases, $minimumStability, array $stabilityFlags, $preferStable, $preferLowest, array $platformOverrides, $write = true)
|
||||
{
|
||||
$lock = array(
|
||||
'_readme' => array('This file locks the dependencies of your project to a known state',
|
||||
|
@ -329,7 +347,11 @@ class Locker
|
|||
|
||||
if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) {
|
||||
if ($this->lockFile->exists()) {
|
||||
unlink($this->lockFile->getPath());
|
||||
if ($write) {
|
||||
unlink($this->lockFile->getPath());
|
||||
} else {
|
||||
$this->virtualFileWritten = false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -341,8 +363,15 @@ class Locker
|
|||
$isLocked = false;
|
||||
}
|
||||
if (!$isLocked || $lock !== $this->getLockData()) {
|
||||
$this->lockFile->write($lock);
|
||||
$this->lockDataCache = null;
|
||||
if ($write) {
|
||||
$this->lockFile->write($lock);
|
||||
// $this->lockDataCache = JsonFile::parseJson(JsonFile::encode($lock, 448 & JsonFile::JSON_PRETTY_PRINT));
|
||||
$this->lockDataCache = null;
|
||||
$this->virtualFileWritten = false;
|
||||
} else {
|
||||
$this->virtualFileWritten = true;
|
||||
$this->lockDataCache = JsonFile::parseJson(JsonFile::encode($lock, 448 & JsonFile::JSON_PRETTY_PRINT));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -569,6 +569,23 @@ class Package extends BasePackage
|
|||
return $this->archiveExcludes;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function setSourceDistReferences($reference)
|
||||
{
|
||||
$this->setSourceReference($reference);
|
||||
|
||||
// only bitbucket, github and gitlab have auto generated dist URLs that easily allow replacing the reference in the dist URL
|
||||
// TODO generalize this a bit for self-managed/on-prem versions? Some kind of replace token in dist urls which allow this?
|
||||
if (preg_match('{^https?://(?:(?:www\.)?bitbucket\.org|(api\.)?github\.com|(?:www\.)?gitlab\.com)/}i', $this->getDistUrl())) {
|
||||
$this->setDistReference($reference);
|
||||
$this->setDistUrl(preg_replace('{(?<=/|sha=)[a-f0-9]{40}(?=/|$)}i', $reference, $this->getDistUrl()));
|
||||
} elseif ($this->getDistReference()) { // update the dist reference if there was one, but if none was provided ignore it
|
||||
$this->setDistReference($reference);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces current version and pretty version with passed values.
|
||||
* It also sets stability.
|
||||
|
|
|
@ -386,4 +386,13 @@ interface PackageInterface
|
|||
* @return void
|
||||
*/
|
||||
public function setDistReference($reference);
|
||||
|
||||
/**
|
||||
* Set dist and source references and update dist URL for ones that contain a reference
|
||||
*
|
||||
* @param string $reference
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSourceDistReferences($reference);
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ class PluginManager
|
|||
$localRepo = $this->composer->getRepositoryManager()->getLocalRepository();
|
||||
$globalRepo = $this->globalComposer ? $this->globalComposer->getRepositoryManager()->getLocalRepository() : null;
|
||||
|
||||
$repositorySet = new RepositorySet(array(), 'dev');
|
||||
$repositorySet = new RepositorySet(array(), array(), 'dev');
|
||||
$repositorySet->addRepository($localRepo);
|
||||
if ($globalRepo) {
|
||||
$repositorySet->addRepository($globalRepo);
|
||||
|
|
|
@ -29,6 +29,8 @@ class RepositorySet
|
|||
{
|
||||
/** @var array */
|
||||
private $rootAliases;
|
||||
/** @var array */
|
||||
private $rootReferences;
|
||||
|
||||
/** @var RepositoryInterface[] */
|
||||
private $repositories = array();
|
||||
|
@ -40,9 +42,10 @@ class RepositorySet
|
|||
/** @var Pool */
|
||||
private $pool;
|
||||
|
||||
public function __construct(array $rootAliases = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
|
||||
public function __construct(array $rootAliases = array(), array $rootReferences = array(), $minimumStability = 'stable', array $stabilityFlags = array(), array $filterRequires = array())
|
||||
{
|
||||
$this->rootAliases = $rootAliases;
|
||||
$this->rootReferences = $rootReferences;
|
||||
|
||||
$this->acceptableStabilities = array();
|
||||
foreach (BasePackage::$stabilities as $stability => $value) {
|
||||
|
@ -101,6 +104,8 @@ class RepositorySet
|
|||
/**
|
||||
* Find packages providing or matching a name and optionally meeting a constraint in all repositories
|
||||
*
|
||||
* Returned in the order of repositories, matching priority
|
||||
*
|
||||
* @param string $name
|
||||
* @param ConstraintInterface|null $constraint
|
||||
* @param bool $exactMatch
|
||||
|
@ -149,7 +154,7 @@ class RepositorySet
|
|||
{
|
||||
$poolBuilder = new PoolBuilder(array($this, 'isPackageAcceptable'), $this->filterRequires);
|
||||
|
||||
return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $request);
|
||||
return $this->pool = $poolBuilder->buildPool($this->repositories, $this->rootAliases, $this->rootReferences, $request);
|
||||
}
|
||||
|
||||
// TODO unify this with above in some simpler version without "request"?
|
||||
|
|
|
@ -29,15 +29,15 @@ class DefaultPolicyTest extends TestCase
|
|||
/** @var ArrayRepository */
|
||||
protected $repo;
|
||||
/** @var ArrayRepository */
|
||||
protected $repoInstalled;
|
||||
protected $repoLocked;
|
||||
/** @var DefaultPolicy */
|
||||
protected $policy;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->repositorySet = new RepositorySet(array(), 'dev');
|
||||
$this->repositorySet = new RepositorySet(array(), array(), 'dev');
|
||||
$this->repo = new ArrayRepository;
|
||||
$this->repoInstalled = new ArrayRepository;
|
||||
$this->repoLocked = new ArrayRepository;
|
||||
|
||||
$this->policy = new DefaultPolicy;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA->getId());
|
||||
$expected = array($packageA->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||
$expected = array($packageA2->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||
$expected = array($packageA2->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$expected = array($packageA1->getId());
|
||||
|
||||
$policy = new DefaultPolicy(true);
|
||||
$selected = $policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -117,24 +117,24 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||
$expected = array($packageA2->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
||||
public function testSelectNewestOverInstalled()
|
||||
public function testSelectNewestOverLocked()
|
||||
{
|
||||
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
|
||||
$this->repoInstalled->addPackage($packageAInstalled = $this->getPackage('A', '1.0'));
|
||||
$this->repositorySet->addRepository($this->repoInstalled);
|
||||
$this->repoLocked->addPackage($packageAInstalled = $this->getPackage('A', '1.0'));
|
||||
$this->repositorySet->addRepository($this->repo);
|
||||
$this->repositorySet->addRepository($this->repoLocked);
|
||||
|
||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||
|
||||
$literals = array($packageA->getId(), $packageAInstalled->getId());
|
||||
$expected = array($packageA->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $this->mapFromRepo($this->repoInstalled), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -146,16 +146,16 @@ class DefaultPolicyTest extends TestCase
|
|||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$otherRepository->addPackage($packageAImportant = $this->getPackage('A', '1.0'));
|
||||
|
||||
$this->repositorySet->addRepository($this->repoInstalled);
|
||||
$this->repositorySet->addRepository($otherRepository);
|
||||
$this->repositorySet->addRepository($this->repo);
|
||||
$this->repositorySet->addRepository($this->repoLocked);
|
||||
|
||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||
|
||||
$literals = array($packageA->getId(), $packageAImportant->getId());
|
||||
$expected = array($packageAImportant->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -177,18 +177,18 @@ class DefaultPolicyTest extends TestCase
|
|||
|
||||
$literals = array($package1->getId(), $package2->getId(), $package3->getId(), $package4->getId());
|
||||
$expected = array($package2->getId());
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
|
||||
$this->repositorySet = new RepositorySet(array(), 'dev');
|
||||
$this->repositorySet = new RepositorySet(array(), array(), 'dev');
|
||||
$this->repositorySet->addRepository($repo2);
|
||||
$this->repositorySet->addRepository($repo1);
|
||||
|
||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||
|
||||
$expected = array($package4->getId());
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -205,9 +205,9 @@ class DefaultPolicyTest extends TestCase
|
|||
$repoImportant->addPackage($packageA2AliasImportant = new AliasPackage($packageA2Important, '2.1.9999999.9999999-dev', '2.1.x-dev'));
|
||||
$packageAAliasImportant->setRootPackageAlias(true);
|
||||
|
||||
$this->repositorySet->addRepository($this->repoInstalled);
|
||||
$this->repositorySet->addRepository($repoImportant);
|
||||
$this->repositorySet->addRepository($this->repo);
|
||||
$this->repositorySet->addRepository($this->repoLocked);
|
||||
|
||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||
|
||||
|
@ -219,7 +219,7 @@ class DefaultPolicyTest extends TestCase
|
|||
|
||||
$expected = array($packageAAliasImportant->getId());
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA->getId(), $packageB->getId());
|
||||
$expected = $literals;
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -258,7 +258,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA->getId(), $packageB->getId());
|
||||
$expected = $literals;
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
@ -279,7 +279,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA->getId(), $packageB->getId());
|
||||
$expected = $literals;
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals, 'vendor-a/package');
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals, 'vendor-a/package');
|
||||
$this->assertEquals($expected, $selected);
|
||||
|
||||
// test with reversed order in repo
|
||||
|
@ -287,7 +287,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$repo->addPackage($packageA = clone $packageA);
|
||||
$repo->addPackage($packageB = clone $packageB);
|
||||
|
||||
$repositorySet = new RepositorySet(array(), 'dev');
|
||||
$repositorySet = new RepositorySet(array(), array(), 'dev');
|
||||
$repositorySet->addRepository($this->repo);
|
||||
|
||||
$pool = $this->repositorySet->createPoolForPackages(array('vendor-a/replacer', 'vendor-b/replacer'));
|
||||
|
@ -295,20 +295,10 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA->getId(), $packageB->getId());
|
||||
$expected = $literals;
|
||||
|
||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals, 'vendor-a/package');
|
||||
$selected = $this->policy->selectPreferredPackages($pool, $literals, 'vendor-a/package');
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
||||
protected function mapFromRepo(RepositoryInterface $repo)
|
||||
{
|
||||
$map = array();
|
||||
foreach ($repo->getPackages() as $package) {
|
||||
$map[$package->getId()] = true;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
public function testSelectLowest()
|
||||
{
|
||||
$policy = new DefaultPolicy(false, true);
|
||||
|
@ -322,7 +312,7 @@ class DefaultPolicyTest extends TestCase
|
|||
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||
$expected = array($packageA1->getId());
|
||||
|
||||
$selected = $policy->selectPreferredPackages($pool, array(), $literals);
|
||||
$selected = $policy->selectPreferredPackages($pool, $literals);
|
||||
|
||||
$this->assertSame($expected, $selected);
|
||||
}
|
||||
|
|
|
@ -31,14 +31,12 @@ class RequestTest extends TestCase
|
|||
|
||||
$request = new Request();
|
||||
$request->install('foo');
|
||||
$request->fix('bar');
|
||||
$request->remove('foobar');
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null, 'fixed' => false),
|
||||
array('cmd' => 'install', 'packageName' => 'bar', 'constraint' => null, 'fixed' => true),
|
||||
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null, 'fixed' => false),
|
||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
|
||||
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null),
|
||||
),
|
||||
$request->getJobs()
|
||||
);
|
||||
|
@ -60,21 +58,9 @@ class RequestTest extends TestCase
|
|||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint, 'fixed' => false),
|
||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint),
|
||||
),
|
||||
$request->getJobs()
|
||||
);
|
||||
}
|
||||
|
||||
public function testUpdateAll()
|
||||
{
|
||||
$request = new Request();
|
||||
|
||||
$request->updateAll();
|
||||
|
||||
$this->assertEquals(
|
||||
array(array('cmd' => 'update-all')),
|
||||
$request->getJobs()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ class SolverTest extends TestCase
|
|||
{
|
||||
protected $repoSet;
|
||||
protected $repo;
|
||||
protected $repoInstalled;
|
||||
protected $repoLocked;
|
||||
protected $request;
|
||||
protected $policy;
|
||||
protected $solver;
|
||||
|
@ -38,9 +38,9 @@ class SolverTest extends TestCase
|
|||
{
|
||||
$this->repoSet = new RepositorySet(array());
|
||||
$this->repo = new ArrayRepository;
|
||||
$this->repoInstalled = new InstalledArrayRepository;
|
||||
$this->repoLocked = new ArrayRepository;
|
||||
|
||||
$this->request = new Request();
|
||||
$this->request = new Request($this->repoLocked);
|
||||
$this->policy = new DefaultPolicy;
|
||||
}
|
||||
|
||||
|
@ -56,9 +56,9 @@ class SolverTest extends TestCase
|
|||
));
|
||||
}
|
||||
|
||||
public function testSolverRemoveIfNotInstalled()
|
||||
public function testSolverRemoveIfNotRequested()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
|
@ -93,7 +93,6 @@ class SolverTest extends TestCase
|
|||
$repo1->addPackage($foo1 = $this->getPackage('foo', '1'));
|
||||
$repo2->addPackage($foo2 = $this->getPackage('foo', '1'));
|
||||
|
||||
$this->repoSet->addRepository($this->repoInstalled);
|
||||
$this->repoSet->addRepository($repo1);
|
||||
$this->repoSet->addRepository($repo2);
|
||||
|
||||
|
@ -175,30 +174,30 @@ class SolverTest extends TestCase
|
|||
));
|
||||
}
|
||||
|
||||
public function testSolverInstallInstalled()
|
||||
public function testSolverFixLocked()
|
||||
{
|
||||
$this->repoInstalled->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->fixPackage($packageA);
|
||||
|
||||
$this->checkSolverResult(array());
|
||||
}
|
||||
|
||||
public function testSolverInstallInstalledWithAlternative()
|
||||
public function testSolverFixLockedWithAlternative()
|
||||
{
|
||||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->fixPackage($packageA);
|
||||
|
||||
$this->checkSolverResult(array());
|
||||
}
|
||||
|
||||
public function testSolverRemoveSingle()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->remove('A');
|
||||
|
@ -220,17 +219,15 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateDoesOnlyUpdate()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||
$this->reposComplete();
|
||||
|
||||
$packageA->setRequires(array('b' => new Link('A', 'B', $this->getVersionConstraint('>=', '1.0.0.0'), 'requires')));
|
||||
|
||||
$this->request->install('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
$this->request->fixPackage($packageA);
|
||||
$this->request->install('B', $this->getVersionConstraint('=', '1.1.0.0'));
|
||||
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
$this->request->update('B', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $packageB, 'to' => $newPackageB),
|
||||
|
@ -239,12 +236,11 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateSingle()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.1'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $packageA, 'to' => $newPackageA),
|
||||
|
@ -253,8 +249,8 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateAll()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.1'));
|
||||
$this->repo->addPackage($newPackageB = $this->getPackage('B', '1.1'));
|
||||
|
||||
|
@ -264,7 +260,6 @@ class SolverTest extends TestCase
|
|||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->updateAll();
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $packageB, 'to' => $newPackageB),
|
||||
|
@ -274,28 +269,26 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateCurrent()
|
||||
{
|
||||
$this->repoInstalled->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($this->getPackage('A', '1.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array());
|
||||
}
|
||||
|
||||
public function testSolverUpdateOnlyUpdatesSelectedPackage()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repo->addPackage($packageAnewer = $this->getPackage('A', '1.1'));
|
||||
$this->repo->addPackage($packageBnewer = $this->getPackage('B', '1.1'));
|
||||
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A');
|
||||
$this->request->install('B');
|
||||
$this->request->update('A');
|
||||
$this->request->fixPackage($packageB);
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $packageA, 'to' => $packageAnewer),
|
||||
|
@ -304,13 +297,12 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateConstrained()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||
$this->request->update('A');
|
||||
|
||||
$this->checkSolverResult(array(array(
|
||||
'job' => 'update',
|
||||
|
@ -321,13 +313,12 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateFullyConstrained()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
|
||||
$this->checkSolverResult(array(array(
|
||||
'job' => 'update',
|
||||
|
@ -338,32 +329,31 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverUpdateFullyConstrainedPrunesInstalledPackages()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoInstalled->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$this->repo->addPackage($newPackageA = $this->getPackage('A', '1.2'));
|
||||
$this->repo->addPackage($this->getPackage('A', '2.0'));
|
||||
$this->reposComplete();
|
||||
|
||||
$this->request->install('A', $this->getVersionConstraint('<', '2.0.0.0'));
|
||||
$this->request->update('A', $this->getVersionConstraint('=', '1.0.0.0'));
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array(
|
||||
'job' => 'remove',
|
||||
'package' => $packageB,
|
||||
),
|
||||
array(
|
||||
'job' => 'update',
|
||||
'from' => $packageA,
|
||||
'to' => $newPackageA,
|
||||
),
|
||||
array(
|
||||
'job' => 'remove',
|
||||
'package' => $packageB,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
public function testSolverAllJobs()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||
$this->repoInstalled->addPackage($oldPackageC = $this->getPackage('C', '1.0'));
|
||||
$this->repoLocked->addPackage($packageD = $this->getPackage('D', '1.0'));
|
||||
$this->repoLocked->addPackage($oldPackageC = $this->getPackage('C', '1.0'));
|
||||
|
||||
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
|
||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
|
@ -376,14 +366,13 @@ class SolverTest extends TestCase
|
|||
|
||||
$this->request->install('A');
|
||||
$this->request->install('C');
|
||||
$this->request->update('C');
|
||||
$this->request->remove('D');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $oldPackageC, 'to' => $packageC),
|
||||
array('job' => 'remove', 'package' => $packageD),
|
||||
array('job' => 'install', 'package' => $packageB),
|
||||
array('job' => 'install', 'package' => $packageA),
|
||||
array('job' => 'remove', 'package' => $packageD),
|
||||
array('job' => 'update', 'from' => $oldPackageC, 'to' => $packageC),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -408,7 +397,7 @@ class SolverTest extends TestCase
|
|||
|
||||
public function testSolverObsolete()
|
||||
{
|
||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repoLocked->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||
$this->repo->addPackage($packageB = $this->getPackage('B', '1.0'));
|
||||
$packageB->setReplaces(array('a' => new Link('B', 'A', new MultiConstraint(array()))));
|
||||
|
||||
|
@ -417,7 +406,8 @@ class SolverTest extends TestCase
|
|||
$this->request->install('B');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'update', 'from' => $packageA, 'to' => $packageB),
|
||||
array('job' => 'remove', 'package' => $packageA),
|
||||
array('job' => 'install', 'package' => $packageB),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -581,9 +571,9 @@ class SolverTest extends TestCase
|
|||
$this->request->install('C');
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'install', 'package' => $packageB),
|
||||
array('job' => 'install', 'package' => $packageA),
|
||||
array('job' => 'install', 'package' => $packageC),
|
||||
array('job' => 'install', 'package' => $packageB),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -763,7 +753,7 @@ class SolverTest extends TestCase
|
|||
$msg .= " - C 1.0 requires d >= 1.0 -> satisfiable by D[1.0].\n";
|
||||
$msg .= " - D 1.0 requires b < 1.0 -> satisfiable by B[0.9].\n";
|
||||
$msg .= " - B 1.0 requires c >= 1.0 -> satisfiable by C[1.0].\n";
|
||||
$msg .= " - Can only install one of: B[0.9, 1.0].\n";
|
||||
$msg .= " - Same name, can only install one of: B[0.9, 1.0].\n";
|
||||
$msg .= " - A 1.0 requires b >= 1.0 -> satisfiable by B[1.0].\n";
|
||||
$msg .= " - Installation request for a -> satisfiable by A[1.0].\n";
|
||||
$this->assertEquals($msg, $e->getMessage());
|
||||
|
@ -817,8 +807,8 @@ class SolverTest extends TestCase
|
|||
$this->request->install('A', $this->getVersionConstraint('==', '1.1.0.0'));
|
||||
|
||||
$this->checkSolverResult(array(
|
||||
array('job' => 'install', 'package' => $packageA2),
|
||||
array('job' => 'install', 'package' => $packageB),
|
||||
array('job' => 'install', 'package' => $packageA2),
|
||||
array('job' => 'install', 'package' => $packageA2Alias),
|
||||
));
|
||||
}
|
||||
|
@ -921,13 +911,13 @@ class SolverTest extends TestCase
|
|||
|
||||
protected function reposComplete()
|
||||
{
|
||||
$this->repoSet->addRepository($this->repoInstalled);
|
||||
$this->repoSet->addRepository($this->repo);
|
||||
$this->repoSet->addRepository($this->repoLocked);
|
||||
}
|
||||
|
||||
protected function createSolver()
|
||||
{
|
||||
$this->solver = new Solver($this->policy, $this->repoSet->createPool($this->request), $this->repoInstalled, new NullIO());
|
||||
$this->solver = new Solver($this->policy, $this->repoSet->createPool($this->request), new NullIO());
|
||||
}
|
||||
|
||||
protected function checkSolverResult(array $expected)
|
||||
|
@ -936,7 +926,7 @@ class SolverTest extends TestCase
|
|||
$transaction = $this->solver->solve($this->request);
|
||||
|
||||
$result = array();
|
||||
foreach ($transaction as $operation) {
|
||||
foreach ($transaction->getOperations() as $operation) {
|
||||
if ('update' === $operation->getJobType()) {
|
||||
$result[] = array(
|
||||
'job' => 'update',
|
||||
|
|
|
@ -22,14 +22,18 @@ Abandoned packages are flagged
|
|||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
update
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Updating dependencies
|
||||
Lock file operations: 2 installs, 0 updates, 0 removals
|
||||
- Locking a/a (1.0.0)
|
||||
- Locking c/c (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
<warning>Package a/a is abandoned, you should avoid using it. No replacement was suggested.</warning>
|
||||
<warning>Package c/c is abandoned, you should avoid using it. Use b/b instead.</warning>
|
||||
Writing lock file
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -43,6 +43,45 @@ Aliases take precedence over default package even if default is selected
|
|||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"require": { "a/req": "dev-master" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "a/b", "version": "dev-master",
|
||||
"require": { "a/req": "dev-master" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "a/req", "version": "dev-feature-foo",
|
||||
"source": { "reference": "feat.f", "type": "git", "url": "" },
|
||||
"type": "library"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [
|
||||
{
|
||||
"alias": "dev-master",
|
||||
"alias_normalized": "9999999-dev",
|
||||
"version": "dev-feature-foo",
|
||||
"package": "a/req"
|
||||
}
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"a/a": 20,
|
||||
"a/b": 20,
|
||||
"a/req": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
--EXPECT--
|
||||
|
|
|
@ -51,6 +51,6 @@ install
|
|||
Installing a/c (dev-feature-foo feat.f)
|
||||
Marking a/c (dev-master feat.f) as installed, alias of a/c (dev-feature-foo feat.f)
|
||||
Installing a/b (dev-master forked)
|
||||
Marking a/b (1.0.x-dev forked) as installed, alias of a/b (dev-master forked)
|
||||
Installing a/a (dev-master master)
|
||||
Marking a/a (1.0.x-dev master) as installed, alias of a/a (dev-master master)
|
||||
Marking a/b (1.0.x-dev forked) as installed, alias of a/b (dev-master forked)
|
||||
|
|
|
@ -19,10 +19,10 @@ Broken dependencies should not lead to a replacer being installed which is not m
|
|||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
update
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Updating dependencies
|
||||
Your requirements could not be resolved to an installable set of packages.
|
||||
|
||||
Problem 1
|
||||
|
|
|
@ -32,5 +32,5 @@ Circular dependencies are possible between packages
|
|||
--RUN--
|
||||
update -v
|
||||
--EXPECT--
|
||||
Installing require/itself (1.0.0)
|
||||
Installing regular/pkg (1.0.0)
|
||||
Installing require/itself (1.0.0)
|
||||
|
|
|
@ -28,11 +28,11 @@ Present a clear error message when config.platform.php version results in a conf
|
|||
}
|
||||
|
||||
--RUN--
|
||||
install
|
||||
update
|
||||
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Updating dependencies
|
||||
Your requirements could not be resolved to an installable set of packages.
|
||||
|
||||
Problem 1
|
||||
|
|
|
@ -29,15 +29,37 @@ that are also a root package, when that root package is also explicitly whitelis
|
|||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
|
||||
]
|
||||
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "a/a", "version": "1.0.0"
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" }
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update a/a b/b --with-dependencies
|
||||
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 0 installs, 2 updates, 0 removals
|
||||
Updating dependencies
|
||||
Lock file operations: 0 installs, 2 updates, 0 removals
|
||||
- Updating a/a (1.0.0) to a/a (1.1.0)
|
||||
- Updating b/b (1.0.0) to b/b (1.1.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 0 installs, 2 updates, 0 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -30,15 +30,32 @@ dependency of one the requirements that is whitelisted for update.
|
|||
{ "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
|
||||
]
|
||||
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update b/b --with-dependencies
|
||||
|
||||
--EXPECT-OUTPUT--
|
||||
<warning>Dependency "a/a" is also a root requirement, but is not explicitly whitelisted. Ignoring.</warning>
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Nothing to install or update
|
||||
Updating dependencies
|
||||
Nothing to modify in lock file
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Nothing to install, update or remove
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -32,5 +32,5 @@ install
|
|||
--EXPECT--
|
||||
Installing b/b (dev-foo)
|
||||
Marking b/b (dev-master) as installed, alias of b/b (dev-foo)
|
||||
Installing a/a (dev-master)
|
||||
Marking b/b (1.0.x-dev) as installed, alias of b/b (dev-foo)
|
||||
Installing a/a (dev-master)
|
||||
|
|
|
@ -21,7 +21,7 @@ Requirements from the composer file are not installed if the lock file is presen
|
|||
"packages": [
|
||||
{ "name": "required", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
|
@ -31,4 +31,4 @@ Requirements from the composer file are not installed if the lock file is presen
|
|||
--RUN--
|
||||
install
|
||||
--EXPECT--
|
||||
Installing required (1.0.0)
|
||||
Installing required (1.0.0)
|
||||
|
|
|
@ -25,7 +25,7 @@ Install from a lock file that deleted a package
|
|||
{ "name": "whitelisted", "version": "1.1.0" },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
|
|
|
@ -29,7 +29,7 @@ Installing an old alias that doesn't exist anymore from a lock is possible
|
|||
"type": "library"
|
||||
}
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
|
|
|
@ -53,7 +53,7 @@ update c/uptodate
|
|||
"packages": [
|
||||
{ "name": "a/old", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "b/unstable", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "c/uptodate", "version": "2.0.0", "type": "library" },
|
||||
{ "name": "c/uptodate", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "d/removed", "version": "1.0.0", "type": "library" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
@ -66,6 +66,7 @@ update c/uptodate
|
|||
"platform-dev": []
|
||||
}
|
||||
--EXPECT--
|
||||
Updating b/unstable (1.1.0-alpha) to b/unstable (1.0.0)
|
||||
Updating a/old (0.9.0) to a/old (1.0.0)
|
||||
Updating b/unstable (1.1.0-alpha) to b/unstable (1.0.0)
|
||||
Updating c/uptodate (2.0.0) to c/uptodate (1.0.0)
|
||||
Installing d/removed (1.0.0)
|
||||
|
|
|
@ -74,8 +74,8 @@ update b/unstable
|
|||
"platform-dev": []
|
||||
}
|
||||
--EXPECT--
|
||||
Updating b/unstable (1.1.0-alpha) to b/unstable (1.0.0)
|
||||
Updating a/old (0.9.0) to a/old (1.0.0)
|
||||
Updating b/unstable (1.1.0-alpha) to b/unstable (1.0.0)
|
||||
Updating c/uptodate (2.0.0) to c/uptodate (1.0.0)
|
||||
Installing d/removed (1.0.0)
|
||||
Installing e/newreq (1.0.0)
|
||||
|
|
|
@ -98,8 +98,8 @@ update b/b
|
|||
}
|
||||
--EXPECT--
|
||||
Updating a/a (dev-master oldmaster-a) to a/a (dev-master newmaster-a)
|
||||
Updating b/b (dev-master oldmaster-b) to b/b (dev-master newmaster-b2)
|
||||
Marking a/a (2.2.x-dev newmaster-a) as installed, alias of a/a (dev-master newmaster-a)
|
||||
Updating b/b (dev-master oldmaster-b) to b/b (dev-master newmaster-b2)
|
||||
Marking b/b (2.3.x-dev newmaster-b2) as installed, alias of b/b (dev-master newmaster-b2)
|
||||
Marking b/b (2.1.x-dev oldmaster-b) as uninstalled, alias of b/b (dev-master oldmaster-b)
|
||||
Marking a/a (2.1.x-dev oldmaster-a) as uninstalled, alias of a/a (dev-master oldmaster-a)
|
||||
Marking b/b (2.1.x-dev oldmaster-b) as uninstalled, alias of b/b (dev-master oldmaster-b)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
--TEST--
|
||||
Partial update without lock file should update everything whitelisted, remove overly unstable packages
|
||||
Partial update without lock file should error
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
|
@ -30,22 +30,8 @@ Partial update without lock file should update everything whitelisted, remove ov
|
|||
]
|
||||
--RUN--
|
||||
update b/unstable
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "a/old", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "b/unstable", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "c/uptodate", "version": "1.0.0", "type": "library" },
|
||||
{ "name": "d/removed", "version": "1.0.0", "type": "library" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--EXPECT-OUTPUT--
|
||||
Cannot update only a partial set of packages without a lock file present.
|
||||
--EXPECT-EXIT-CODE--
|
||||
1
|
||||
--EXPECT--
|
||||
Updating b/unstable (1.1.0-alpha) to b/unstable (1.0.0)
|
||||
|
|
|
@ -23,7 +23,7 @@ The locked version will not get overwritten by an install
|
|||
{ "name": "foo/bar", "version": "1.0.0" },
|
||||
{ "name": "foo/baz", "version": "2.0.0" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
|
|
|
@ -30,6 +30,21 @@ Test the error output of solver problems.
|
|||
{ "name": "stable-requiree-excluded/pkg", "version": "1.0.0" }
|
||||
]
|
||||
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "stable-requiree-excluded/pkg", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
|
||||
--RUN--
|
||||
update unstable/package requirer/pkg dependency/pkg
|
||||
|
||||
|
@ -38,7 +53,7 @@ update unstable/package requirer/pkg dependency/pkg
|
|||
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Updating dependencies
|
||||
Your requirements could not be resolved to an installable set of packages.
|
||||
|
||||
Problem 1
|
||||
|
@ -46,12 +61,12 @@ Your requirements could not be resolved to an installable set of packages.
|
|||
Problem 2
|
||||
- The requested package bogus/pkg could not be found in any version, there may be a typo in the package name.
|
||||
Problem 3
|
||||
- The requested package stable-requiree-excluded/pkg 1.0.1 exists as stable-requiree-excluded/pkg[1.0.0] but these are rejected by your constraint.
|
||||
Problem 4
|
||||
- The requested package stable-requiree-excluded/pkg (installed at 1.0.0, required as 1.0.1) is satisfiable by stable-requiree-excluded/pkg[1.0.0] but these conflict with your requirements or minimum-stability.
|
||||
Problem 5
|
||||
- Installation request for requirer/pkg 1.* -> satisfiable by requirer/pkg[1.0.0].
|
||||
- requirer/pkg 1.0.0 requires dependency/pkg 1.0.0 -> no matching package found.
|
||||
Problem 4
|
||||
- stable-requiree-excluded/pkg is locked to version 1.0.0 and an update of this package was not requested.
|
||||
- Same name, can only install one of: stable-requiree-excluded/pkg[1.0.1, 1.0.0].
|
||||
- Installation request for stable-requiree-excluded/pkg 1.0.1 -> satisfiable by stable-requiree-excluded/pkg[1.0.1].
|
||||
|
||||
Potential causes:
|
||||
- A typo in the package name
|
||||
|
|
|
@ -17,12 +17,16 @@ Suggestions are not displayed for installed packages
|
|||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
update
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
Updating dependencies
|
||||
Lock file operations: 2 installs, 0 updates, 0 removals
|
||||
- Locking a/a (1.0.0)
|
||||
- Locking b/b (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -17,10 +17,14 @@ Suggestions are not displayed in non-dev mode
|
|||
--RUN--
|
||||
install --no-dev
|
||||
--EXPECT-OUTPUT--
|
||||
<warning>No lock file found. Updating dependencies instead of installing from lock file. Use composer update over composer install if you do not have a lock file.</warning>
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies
|
||||
Package operations: 1 install, 0 updates, 0 removals
|
||||
Lock file operations: 1 install, 0 updates, 0 removals
|
||||
- Locking a/a (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file
|
||||
Package operations: 1 install, 0 updates, 0 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -17,12 +17,16 @@ Suggestions are not displayed for packages if they are replaced
|
|||
}
|
||||
}
|
||||
--RUN--
|
||||
install
|
||||
update
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
Updating dependencies
|
||||
Lock file operations: 2 installs, 0 updates, 0 removals
|
||||
- Locking c/c (1.0.0)
|
||||
- Locking a/a (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 2 installs, 0 updates, 0 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -17,11 +17,15 @@ Suggestions are displayed
|
|||
--RUN--
|
||||
install
|
||||
--EXPECT-OUTPUT--
|
||||
<warning>No lock file found. Updating dependencies instead of installing from lock file. Use composer update over composer install if you do not have a lock file.</warning>
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Updating dependencies
|
||||
Lock file operations: 1 install, 0 updates, 0 removals
|
||||
- Locking a/a (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 1 install, 0 updates, 0 removals
|
||||
a/a suggests installing b/b (an obscure reason)
|
||||
Writing lock file
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -29,20 +29,6 @@ Update aliased package does not mess up the lock file
|
|||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
--LOCK--
|
||||
{
|
||||
"_": "outdated lock file, should not have to be loaded in an update",
|
||||
"packages": [
|
||||
{ "package": "a/a", "version": "dev-master", "source-reference": "1234" },
|
||||
{ "package": "a/a", "version": "dev-master", "alias-pretty-version": "1.0.x-dev", "alias-version": "1.0.9999999.9999999-dev" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{
|
||||
|
|
|
@ -3,10 +3,10 @@ Update updates URLs for updated packages if they have changed
|
|||
|
||||
a/a is dev and gets everything updated as it updates to a new ref
|
||||
b/b is a tag and gets everything updated by updating the package URL directly
|
||||
c/c is a tag and not whitelisted and gets the new URL but keeps its old ref
|
||||
c/c is a tag and not whitelisted and remains unchanged
|
||||
d/d is dev but with a #ref so it should get URL updated but not the reference
|
||||
e/e is dev and newly installed with a #ref so it should get the correct URL but with the #111 ref
|
||||
e/e is dev but not whitelisted and gets the new URL but keeps its old ref
|
||||
f/f is dev but not whitelisted and remains unchanged
|
||||
g/g is dev and installed in a different ref than the #ref, so it gets updated and gets the new URL but not the new ref
|
||||
--COMPOSER--
|
||||
{
|
||||
|
@ -98,6 +98,57 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
|
|||
"transport-options": { "foo": "bar" }
|
||||
}
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/a", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/a/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "2.0.3",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/b", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/b/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "d/d", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/d", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/d/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library",
|
||||
"transport-options": { "foo": "bar" }
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
"source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/g", "type": "git" },
|
||||
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library",
|
||||
"transport-options": { "foo": "bar" }
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
|
@ -115,8 +166,8 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
|
|||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/newc", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/tarball/1111111111111111111111111111111111111111", "type": "tar", "shasum": "newsum" },
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
|
@ -133,10 +184,10 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
|
|||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/newf", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/tarball/1111111111111111111111111111111111111111", "type": "tar", "shasum": "newsum" },
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip", "shasum": "oldsum" },
|
||||
"type": "library",
|
||||
"transport-options": { "foo": "bar2" }
|
||||
"transport-options": { "foo": "bar" }
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
|
@ -163,6 +214,6 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
|
|||
--RUN--
|
||||
update a/a b/b d/d g/g
|
||||
--EXPECT--
|
||||
Installing e/e (dev-master 1111111)
|
||||
Updating a/a (dev-master 1111111) to a/a (dev-master 2222222)
|
||||
Installing e/e (dev-master 1111111)
|
||||
Updating g/g (dev-master 0000000) to g/g (dev-master 1111111)
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
--TEST--
|
||||
Update mirrors updates URLs for all packages if they have changed without updating versions
|
||||
|
||||
a/a is dev and gets everything updated as it updates to a new ref
|
||||
b/b is a tag and gets everything updated by updating the package URL directly
|
||||
c/c is a tag and not whitelisted and gets the new URL but keeps its old ref
|
||||
d/d is dev but with a #ref so it should get URL updated but not the reference
|
||||
e/e is dev and newly installed with a #ref so it should get the correct URL but with the #111 ref
|
||||
e/e is dev but not whitelisted and gets the new URL but keeps its old ref
|
||||
g/g is dev and installed in a different ref than the #ref, so it gets updated and gets the new URL but not the new ref
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/a/newa", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/a/newa/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "2.0.3",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/b/newb", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/b/newb/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/c/newc", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/c/newc/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "d/d", "version": "dev-master",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/d/newd", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/d/newd/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "e/e", "version": "dev-master",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/e/newe", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/e/newe/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/f/newf", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/f/newf/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
"source": { "reference": "2222222222222222222222222222222222222222", "url": "https://github.com/g/newg", "type": "git" },
|
||||
"dist": { "reference": "2222222222222222222222222222222222222222", "url": "https://api.github.com/repos/g/newg/zipball/2222222222222222222222222222222222222222", "type": "zip" }
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"a/a": "dev-master",
|
||||
"b/b": "2.0.3",
|
||||
"c/c": "1.0.0",
|
||||
"d/d": "dev-master#1111111111111111111111111111111111111111",
|
||||
"e/e": "dev-master#1111111111111111111111111111111111111111",
|
||||
"f/f": "dev-master",
|
||||
"g/g": "dev-master#1111111111111111111111111111111111111111"
|
||||
}
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/a", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/a/zipball/1111111111111111111111111111111111111111", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "2.0.3",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/b", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/b/zipball/1111111111111111111111111111111111111111", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "d/d", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/d", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/d/zipball/1111111111111111111111111111111111111111", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip" }
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
"source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/g", "type": "git" },
|
||||
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip" }
|
||||
}
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/a", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/a/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "2.0.3",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/b", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/b/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/c", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/c/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "d/d", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/d", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/d/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/f", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/f/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
"source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/g", "type": "git" },
|
||||
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip" },
|
||||
"type": "library"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{
|
||||
"name": "a/a", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/a/newa", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/a/newa/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "b/b", "version": "2.0.3",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/b/newb", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/b/newb/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "c/c", "version": "1.0.0",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/c/newc", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/c/newc/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "d/d", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/d/newd", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/d/newd/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "f/f", "version": "dev-master",
|
||||
"source": { "reference": "1111111111111111111111111111111111111111", "url": "https://github.com/f/newf", "type": "git" },
|
||||
"dist": { "reference": "1111111111111111111111111111111111111111", "url": "https://api.github.com/repos/f/newf/zipball/1111111111111111111111111111111111111111", "type": "zip" },
|
||||
"type": "library"
|
||||
},
|
||||
{
|
||||
"name": "g/g", "version": "dev-master",
|
||||
"source": { "reference": "0000000000000000000000000000000000000000", "url": "https://github.com/g/newg", "type": "git" },
|
||||
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/newg/zipball/0000000000000000000000000000000000000000", "type": "zip" },
|
||||
"type": "library"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": {
|
||||
"a/a": 20,
|
||||
"d/d": 20,
|
||||
"e/e": 20,
|
||||
"f/f": 20,
|
||||
"g/g": 20
|
||||
},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update mirrors
|
||||
--EXPECT--
|
|
@ -62,7 +62,7 @@ update --no-dev
|
|||
--EXPECT--
|
||||
Uninstalling a/b (1.0.0)
|
||||
Updating a/a (1.0.0) to a/a (1.0.1)
|
||||
Updating dev/pkg (dev-master old) to dev/pkg (dev-master new)
|
||||
Installing a/c (1.0.0)
|
||||
Updating dev/pkg (dev-master old) to dev/pkg (dev-master new)
|
||||
Marking dev/pkg (1.1.x-dev new) as installed, alias of dev/pkg (dev-master new)
|
||||
Marking dev/pkg (1.0.x-dev old) as uninstalled, alias of dev/pkg (dev-master old)
|
||||
|
|
|
@ -31,10 +31,18 @@ Converting from one VCS type to another (including an URL change) should update
|
|||
"name": "a/a", "version": "1.0.0",
|
||||
"source": { "reference": "old-hg-ref", "type": "hg", "url": "old-hg-url" }
|
||||
}
|
||||
]
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update
|
||||
update mirrors
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
--TEST--
|
||||
A composer update should remove unused locked dependencies from the lock file and remove unused installed deps from disk
|
||||
--COMPOSER--
|
||||
{
|
||||
"repositories": [
|
||||
{
|
||||
"type": "package",
|
||||
"package": [
|
||||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0" }
|
||||
]
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"a/a": "*"
|
||||
}
|
||||
}
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--INSTALLED--
|
||||
[
|
||||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0" },
|
||||
{ "name": "c/c", "version": "1.0.0" }
|
||||
]
|
||||
--RUN--
|
||||
update
|
||||
--EXPECT-LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "a/a", "version": "1.0.0", "type": "library" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies
|
||||
Lock file operations: 0 installs, 0 updates, 1 removal
|
||||
- Uninstalling b/b (1.0.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 0 installs, 0 updates, 2 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
Uninstalling c/c (1.0.0)
|
||||
Uninstalling b/b (1.0.0)
|
|
@ -29,6 +29,23 @@ Update with a package whitelist only updates those packages if they are not pres
|
|||
{ "name": "fixed-dependency", "version": "1.0.0", "require": { "fixed-sub-dependency": "1.*" } },
|
||||
{ "name": "fixed-sub-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "dependency": "1.0.0", "fixed-dependency": "1.*" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0", "require": { "fixed-sub-dependency": "1.*" } },
|
||||
{ "name": "fixed-sub-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted dependency
|
||||
--EXPECT--
|
||||
|
|
|
@ -38,6 +38,25 @@ Update with a package whitelist pattern and all-dependencies flag updates packag
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component1", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted-* --with-all-dependencies
|
||||
--EXPECT--
|
||||
|
|
|
@ -41,6 +41,24 @@ Update with a package whitelist only updates those packages and their dependenci
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component1", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "root-dependency", "version": "1.0.0" },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted-* --with-dependencies
|
||||
--EXPECT--
|
||||
|
|
|
@ -47,6 +47,28 @@ Update with a package whitelist only updates those packages and their dependenci
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component1", "version": "1.0.0", "require": { "whitelisted-component2": "1.0.0" } },
|
||||
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "whitelisted-component3", "version": "1.0.0", "require": { "whitelisted-component4": "1.0.0" } },
|
||||
{ "name": "whitelisted-component4", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component5", "version": "1.0.0" },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted-* --with-dependencies
|
||||
--EXPECT--
|
||||
|
|
|
@ -37,6 +37,23 @@ Update with a package whitelist only updates those packages matching the pattern
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component1", "version": "1.0.0" },
|
||||
{ "name": "whitelisted-component2", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted-*
|
||||
--EXPECT--
|
||||
|
|
|
@ -39,10 +39,31 @@ Update with a package whitelist only updates those corresponding to the pattern
|
|||
{ "name": "another/another", "version": "1.0" },
|
||||
{ "name": "no/regexp", "version": "1.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "vendor/Test-Package", "version": "1.0" },
|
||||
{ "name": "vendor/NotMe", "version": "1.0" },
|
||||
{ "name": "exact/Test-Package", "version": "1.0" },
|
||||
{ "name": "notexact/TestPackage", "version": "1.0" },
|
||||
{ "name": "all/Package1", "version": "1.0" },
|
||||
{ "name": "all/Package2", "version": "1.0" },
|
||||
{ "name": "another/another", "version": "1.0" },
|
||||
{ "name": "no/regexp", "version": "1.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update vendor/Test* exact/Test-Package notexact/Test all/* no/reg?xp
|
||||
--EXPECT--
|
||||
Updating vendor/Test-Package (1.0) to vendor/Test-Package (2.0)
|
||||
Updating exact/Test-Package (1.0) to exact/Test-Package (2.0)
|
||||
Updating all/Package1 (1.0) to all/Package1 (2.0)
|
||||
Updating all/Package2 (1.0) to all/Package2 (2.0)
|
||||
Updating exact/Test-Package (1.0) to exact/Test-Package (2.0)
|
||||
Updating vendor/Test-Package (1.0) to vendor/Test-Package (2.0)
|
||||
|
|
|
@ -28,7 +28,7 @@ Limited update takes rules from lock if available, and not from the installed re
|
|||
{ "name": "toupdate/installed", "version": "1.0.0" },
|
||||
{ "name": "toupdate/notinstalled", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "stable",
|
||||
"stability-flags": [],
|
||||
|
@ -43,6 +43,6 @@ Limited update takes rules from lock if available, and not from the installed re
|
|||
--RUN--
|
||||
update toupdate/installed
|
||||
--EXPECT--
|
||||
Updating toupdate/installed (1.0.0) to toupdate/installed (1.1.0)
|
||||
Updating old/installed (0.9.0) to old/installed (1.0.0)
|
||||
Updating toupdate/installed (1.0.0) to toupdate/installed (1.1.0)
|
||||
Installing toupdate/notinstalled (1.0.0)
|
||||
|
|
|
@ -25,6 +25,22 @@ Update with a package whitelist removes unused packages
|
|||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "old-dependency": "1.0.0", "fixed-dependency": "1.0.0" } },
|
||||
{ "name": "fixed-dependency", "version": "1.0.0" },
|
||||
{ "name": "old-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update --with-dependencies whitelisted
|
||||
--EXPECT--
|
||||
|
|
|
@ -33,6 +33,22 @@ Update with a package whitelist only updates those packages and their dependenci
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted --with-dependencies
|
||||
--EXPECT--
|
||||
|
|
|
@ -33,6 +33,22 @@ Update with a package whitelist only updates whitelisted packages if no dependen
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "dependency": "1.0.0" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted
|
||||
--EXPECT--
|
||||
|
|
|
@ -33,6 +33,24 @@ Update with a package whitelist only updates those packages listed as command ar
|
|||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
]
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "fixed", "version": "1.0.0" },
|
||||
{ "name": "whitelisted", "version": "1.0.0", "require": { "dependency": "1.*" } },
|
||||
{ "name": "dependency", "version": "1.0.0" },
|
||||
{ "name": "unrelated", "version": "1.0.0", "require": { "unrelated-dependency": "1.*" } },
|
||||
{ "name": "unrelated-dependency", "version": "1.0.0" }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update whitelisted
|
||||
--EXPECT--
|
||||
|
|
|
@ -28,15 +28,33 @@ When `--with-all-dependencies` is used, Composer\Installer::whitelistUpdateDepen
|
|||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
|
||||
]
|
||||
|
||||
--LOCK--
|
||||
{
|
||||
"packages": [
|
||||
{ "name": "a/a", "version": "1.0.0" },
|
||||
{ "name": "b/b", "version": "1.0.0", "require": { "a/a": "~1.0" } }
|
||||
],
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
"prefer-stable": false,
|
||||
"prefer-lowest": false,
|
||||
"platform": [],
|
||||
"platform-dev": []
|
||||
}
|
||||
--RUN--
|
||||
update b/b --with-all-dependencies
|
||||
|
||||
--EXPECT-OUTPUT--
|
||||
Loading composer repositories with package information
|
||||
Updating dependencies (including require-dev)
|
||||
Package operations: 0 installs, 2 updates, 0 removals
|
||||
Updating dependencies
|
||||
Lock file operations: 0 installs, 2 updates, 0 removals
|
||||
- Updating a/a (1.0.0) to a/a (1.1.0)
|
||||
- Updating b/b (1.0.0) to b/b (1.1.0)
|
||||
Writing lock file
|
||||
Installing dependencies from lock file (including require-dev)
|
||||
Package operations: 0 installs, 2 updates, 0 removals
|
||||
Generating autoload files
|
||||
|
||||
--EXPECT--
|
||||
|
|
|
@ -16,7 +16,7 @@ Installing locked dev packages should remove old dependencies
|
|||
"require": {}
|
||||
}
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": [],
|
||||
|
|
|
@ -28,7 +28,7 @@ Updating a dev package for new reference updates the url and reference
|
|||
"dist": { "reference": "oldref", "url": "oldurl", "type": "zip", "shasum": "" }
|
||||
}
|
||||
],
|
||||
"packages-dev": null,
|
||||
"packages-dev": [],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {"a/a":20},
|
||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Installer;
|
|||
use Composer\Console\Application;
|
||||
use Composer\IO\BufferIO;
|
||||
use Composer\Json\JsonFile;
|
||||
use Composer\Package\Dumper\ArrayDumper;
|
||||
use Composer\Util\Filesystem;
|
||||
use Composer\Repository\ArrayRepository;
|
||||
use Composer\Repository\RepositoryManager;
|
||||
|
@ -74,10 +75,30 @@ class InstallerTest extends TestCase
|
|||
foreach ($repositories as $repository) {
|
||||
$repositoryManager->addRepository($repository);
|
||||
}
|
||||
|
||||
$locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
|
||||
$installationManager = new InstallationManagerMock();
|
||||
|
||||
// emulate a writable lock file
|
||||
$lockData = null;
|
||||
$lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('read')
|
||||
->will($this->returnCallback(function() use (&$lockData) {
|
||||
return json_decode($lockData, true);
|
||||
}));
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('exists')
|
||||
->will($this->returnCallback(function () use (&$lockData) {
|
||||
return $lockData !== null;
|
||||
}));
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('write')
|
||||
->will($this->returnCallback(function ($value, $options = 0) use (&$lockData) {
|
||||
$lockData = json_encode($value, JsonFile::JSON_PRETTY_PRINT);
|
||||
}));
|
||||
|
||||
$tempLockData = null;
|
||||
$locker = new Locker($io, $lockJsonMock, $installationManager, '{}');
|
||||
|
||||
$autoloadGenerator = $this->getMockBuilder('Composer\Autoload\AutoloadGenerator')->disableOriginalConstructor()->getMock();
|
||||
|
||||
$installer = new Installer($io, $config, clone $rootPackage, $downloadManager, $repositoryManager, $locker, $installationManager, $eventDispatcher, $autoloadGenerator);
|
||||
|
@ -91,7 +112,7 @@ class InstallerTest extends TestCase
|
|||
$expectedUninstalled = isset($options['uninstall']) ? $options['uninstall'] : array();
|
||||
|
||||
$installed = $installationManager->getInstalledPackages();
|
||||
$this->assertSame($expectedInstalled, $installed);
|
||||
$this->assertEquals($this->makePackagesComparable($expectedInstalled), $this->makePackagesComparable($installed));
|
||||
|
||||
$updated = $installationManager->getUpdatedPackages();
|
||||
$this->assertSame($expectedUpdated, $updated);
|
||||
|
@ -100,6 +121,17 @@ class InstallerTest extends TestCase
|
|||
$this->assertSame($expectedUninstalled, $uninstalled);
|
||||
}
|
||||
|
||||
protected function makePackagesComparable($packages)
|
||||
{
|
||||
$dumper = new ArrayDumper();
|
||||
|
||||
$comparable = array();
|
||||
foreach ($packages as $package) {
|
||||
$comparable[] = $dumper->dump($package);
|
||||
}
|
||||
return $comparable;
|
||||
}
|
||||
|
||||
public function provideInstaller()
|
||||
{
|
||||
$cases = array();
|
||||
|
@ -109,11 +141,11 @@ class InstallerTest extends TestCase
|
|||
|
||||
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
||||
$a->setRequires(array(
|
||||
new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
|
||||
'b' => new Link('A', 'B', $v = $this->getVersionConstraint('=', '1.0.0'), 'requires', $v->getPrettyString()),
|
||||
));
|
||||
$b = $this->getPackage('B', '1.0.0');
|
||||
$b->setRequires(array(
|
||||
new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
|
||||
'a' => new Link('B', 'A', $v = $this->getVersionConstraint('=', '1.0.0'), 'requires', $v->getPrettyString()),
|
||||
));
|
||||
|
||||
$cases[] = array(
|
||||
|
@ -129,11 +161,11 @@ class InstallerTest extends TestCase
|
|||
|
||||
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
||||
$a->setRequires(array(
|
||||
new Link('A', 'B', $this->getVersionConstraint('=', '1.0.0')),
|
||||
'b' => new Link('A', 'B', $v = $this->getVersionConstraint('=', '1.0.0'), 'requires', $v->getPrettyString()),
|
||||
));
|
||||
$b = $this->getPackage('B', '1.0.0');
|
||||
$b->setRequires(array(
|
||||
new Link('B', 'A', $this->getVersionConstraint('=', '1.0.0')),
|
||||
'a' => new Link('B', 'A', $v = $this->getVersionConstraint('=', '1.0.0'), 'requires', $v->getPrettyString()),
|
||||
));
|
||||
|
||||
$cases[] = array(
|
||||
|
@ -144,6 +176,7 @@ class InstallerTest extends TestCase
|
|||
),
|
||||
);
|
||||
|
||||
// TODO why are there not more cases with uninstall/update?
|
||||
return $cases;
|
||||
}
|
||||
|
||||
|
@ -182,13 +215,24 @@ class InstallerTest extends TestCase
|
|||
$repositoryManager = $composer->getRepositoryManager();
|
||||
$repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock));
|
||||
|
||||
// emulate a writable lock file
|
||||
$lockData = $lock ? json_encode($lock, JsonFile::JSON_PRETTY_PRINT): null;
|
||||
$lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('read')
|
||||
->will($this->returnValue($lock));
|
||||
->will($this->returnCallback(function() use (&$lockData) {
|
||||
return json_decode($lockData, true);
|
||||
}));
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('exists')
|
||||
->will($this->returnValue(true));
|
||||
->will($this->returnCallback(function () use (&$lockData) {
|
||||
return $lockData !== null;
|
||||
}));
|
||||
$lockJsonMock->expects($this->any())
|
||||
->method('write')
|
||||
->will($this->returnCallback(function ($value, $options = 0) use (&$lockData) {
|
||||
$lockData = json_encode($value, JsonFile::JSON_PRETTY_PRINT);
|
||||
}));
|
||||
|
||||
if ($expectLock) {
|
||||
$actualLock = array();
|
||||
|
@ -228,11 +272,19 @@ class InstallerTest extends TestCase
|
|||
});
|
||||
|
||||
$application->get('update')->setCode(function ($input, $output) use ($installer) {
|
||||
$packages = $input->getArgument('packages');
|
||||
$filteredPackages = array_filter($packages, function ($package) {
|
||||
return !in_array($package, array('lock', 'nothing', 'mirrors'), true);
|
||||
});
|
||||
$updateMirrors = $input->getOption('lock') || count($filteredPackages) != count($packages);
|
||||
$packages = $filteredPackages;
|
||||
|
||||
$installer
|
||||
->setDevMode(!$input->getOption('no-dev'))
|
||||
->setUpdate(true)
|
||||
->setDryRun($input->getOption('dry-run'))
|
||||
->setUpdateWhitelist($input->getArgument('packages'))
|
||||
->setUpdateMirrors($updateMirrors)
|
||||
->setUpdateWhitelist($packages)
|
||||
->setWhitelistTransitiveDependencies($input->getOption('with-dependencies'))
|
||||
->setWhitelistAllDependencies($input->getOption('with-all-dependencies'))
|
||||
->setPreferStable($input->getOption('prefer-stable'))
|
||||
|
@ -248,7 +300,7 @@ class InstallerTest extends TestCase
|
|||
|
||||
$application->setAutoExit(false);
|
||||
$appOutput = fopen('php://memory', 'w+');
|
||||
$input = new StringInput($run);
|
||||
$input = new StringInput($run.' -vvv');
|
||||
$input->setInteractive(false);
|
||||
$result = $application->run($input, new StreamOutput($appOutput));
|
||||
fseek($appOutput, 0);
|
||||
|
|
Loading…
Reference in New Issue