Refactor Installer class into separate install and update processes
- Introduce separate Lock and LocalRepo transactions, one for changes to the lock file, one for changes to locally installed packages based on lock file - Remove various hacks to keep dev dependencies updated and incorporated the functionality into the transaction classes - Remove installed repo, there are now local repo, locked repo and platform repo - Remove access to local repo from solver, only supply locked packages - Update can now be run to modify the lock file but not install packages to local repopull/7936/head
parent
1211ba1d51
commit
10ada7bf82
|
@ -44,7 +44,7 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return $constraint->matchSpecific($version, true);
|
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();
|
$packages = array();
|
||||||
|
|
||||||
|
@ -57,36 +57,34 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return $packages;
|
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;
|
$policy = $this;
|
||||||
usort($literals, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
|
usort($nameLiterals, function ($a, $b) use ($policy, $pool, $requiredPackage) {
|
||||||
return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
|
return $policy->compareByPriority($pool, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage, true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($packages as &$literals) {
|
foreach ($packages as &$sortedLiterals) {
|
||||||
$literals = $this->pruneToHighestPriorityOrInstalled($pool, $installedMap, $literals);
|
$sortedLiterals = $this->pruneToHighestPriority($pool, $sortedLiterals);
|
||||||
|
$sortedLiterals = $this->pruneToBestVersion($pool, $sortedLiterals);
|
||||||
$literals = $this->pruneToBestVersion($pool, $literals);
|
$sortedLiterals = $this->pruneRemoteAliases($pool, $sortedLiterals);
|
||||||
|
|
||||||
$literals = $this->pruneRemoteAliases($pool, $literals);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$selected = call_user_func_array('array_merge', $packages);
|
$selected = call_user_func_array('array_merge', $packages);
|
||||||
|
|
||||||
// now sort the result across all packages to respect replaces across packages
|
// now sort the result across all packages to respect replaces across packages
|
||||||
usort($selected, function ($a, $b) use ($policy, $pool, $installedMap, $requiredPackage) {
|
usort($selected, function ($a, $b) use ($policy, $pool, $requiredPackage) {
|
||||||
return $policy->compareByPriorityPreferInstalled($pool, $installedMap, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
|
return $policy->compareByPriority($pool, $pool->literalToPackage($a), $pool->literalToPackage($b), $requiredPackage);
|
||||||
});
|
});
|
||||||
|
|
||||||
return $selected;
|
return $selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function groupLiteralsByNamePreferInstalled(Pool $pool, array $installedMap, $literals)
|
protected function groupLiteralsByName(Pool $pool, $literals)
|
||||||
{
|
{
|
||||||
$packages = array();
|
$packages = array();
|
||||||
foreach ($literals as $literal) {
|
foreach ($literals as $literal) {
|
||||||
|
@ -95,12 +93,7 @@ class DefaultPolicy implements PolicyInterface
|
||||||
if (!isset($packages[$packageName])) {
|
if (!isset($packages[$packageName])) {
|
||||||
$packages[$packageName] = array();
|
$packages[$packageName] = array();
|
||||||
}
|
}
|
||||||
|
$packages[$packageName][] = $literal;
|
||||||
if (isset($installedMap[abs($literal)])) {
|
|
||||||
array_unshift($packages[$packageName], $literal);
|
|
||||||
} else {
|
|
||||||
$packages[$packageName][] = $literal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $packages;
|
return $packages;
|
||||||
|
@ -109,7 +102,7 @@ class DefaultPolicy implements PolicyInterface
|
||||||
/**
|
/**
|
||||||
* @protected
|
* @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()) {
|
if ($a->getRepository() === $b->getRepository()) {
|
||||||
// prefer aliases to the original package
|
// prefer aliases to the original package
|
||||||
|
@ -155,14 +148,6 @@ class DefaultPolicy implements PolicyInterface
|
||||||
return ($a->id < $b->id) ? -1 : 1;
|
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;
|
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();
|
$selected = array();
|
||||||
|
|
||||||
|
@ -225,11 +210,6 @@ class DefaultPolicy implements PolicyInterface
|
||||||
foreach ($literals as $literal) {
|
foreach ($literals as $literal) {
|
||||||
$package = $pool->literalToPackage($literal);
|
$package = $pool->literalToPackage($literal);
|
||||||
|
|
||||||
if (isset($installedMap[$package->id])) {
|
|
||||||
$selected[] = $literal;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (null === $priority) {
|
if (null === $priority) {
|
||||||
$priority = $pool->getPriority($package->id);
|
$priority = $pool->getPriority($package->id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,185 @@
|
||||||
|
<?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\Package\AliasPackage;
|
||||||
|
use Composer\Repository\PlatformRepository;
|
||||||
|
use Composer\Repository\RepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
|
*/
|
||||||
|
class LocalRepoTransaction
|
||||||
|
{
|
||||||
|
/** @var RepositoryInterface */
|
||||||
|
protected $lockedRepository;
|
||||||
|
|
||||||
|
/** @var RepositoryInterface */
|
||||||
|
protected $localRepository;
|
||||||
|
|
||||||
|
public function __construct($lockedRepository, $localRepository)
|
||||||
|
{
|
||||||
|
$this->lockedRepository = $lockedRepository;
|
||||||
|
$this->localRepository = $localRepository;
|
||||||
|
|
||||||
|
$this->operations = $this->calculateOperations();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOperations()
|
||||||
|
{
|
||||||
|
return $this->operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function calculateOperations()
|
||||||
|
{
|
||||||
|
$operations = array();
|
||||||
|
|
||||||
|
$localPackageMap = array();
|
||||||
|
$removeMap = array();
|
||||||
|
foreach ($this->localRepository->getPackages() as $package) {
|
||||||
|
if (isset($localPackageMap[$package->getName()])) {
|
||||||
|
die("Alias?");
|
||||||
|
}
|
||||||
|
$localPackageMap[$package->getName()] = $package;
|
||||||
|
$removeMap[$package->getName()] = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lockedPackages = array();
|
||||||
|
foreach ($this->lockedRepository->getPackages() as $package) {
|
||||||
|
if (isset($localPackageMap[$package->getName()])) {
|
||||||
|
$source = $localPackageMap[$package->getName()];
|
||||||
|
|
||||||
|
// do we need to update?
|
||||||
|
if ($package->getVersion() != $localPackageMap[$package->getName()]->getVersion()) {
|
||||||
|
$operations[] = new Operation\UpdateOperation($source, $package);
|
||||||
|
} else {
|
||||||
|
// TODO do we need to update metadata? force update based on reference?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$operations[] = new Operation\InstallOperation($package);
|
||||||
|
unset($removeMap[$package->getName()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
if (isset($lockedPackages[$package->getName()])) {
|
||||||
|
die("Alias?");
|
||||||
|
}
|
||||||
|
$lockedPackages[$package->getName()] = $package;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($removeMap as $name => $package) {
|
||||||
|
$operations[] = new Operation\UninstallOperation($package, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
$operations = $this->movePluginsToFront($operations);
|
||||||
|
$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 $operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// is this package a plugin?
|
||||||
|
$isPlugin = $package->getType() === 'composer-plugin' || $package->getType() === 'composer-installer';
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($operations[$idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($pluginsNoDeps, $pluginsWithDeps, $operations);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
$uninstOps = array();
|
||||||
|
foreach ($operations as $idx => $op) {
|
||||||
|
if ($op instanceof UninstallOperation) {
|
||||||
|
$uninstOps[] = $op;
|
||||||
|
unset($operations[$idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_merge($uninstOps, $operations);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,167 @@
|
||||||
|
<?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\RepositoryInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Nils Adermann <naderman@naderman.de>
|
||||||
|
*/
|
||||||
|
class LockTransaction
|
||||||
|
{
|
||||||
|
protected $policy;
|
||||||
|
/** @var Pool */
|
||||||
|
protected $pool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
protected $decisions;
|
||||||
|
protected $transaction;
|
||||||
|
|
||||||
|
public function __construct($policy, $pool, $presentMap, $unlockableMap, $decisions)
|
||||||
|
{
|
||||||
|
$this->policy = $policy;
|
||||||
|
$this->pool = $pool;
|
||||||
|
$this->presentMap = $presentMap;
|
||||||
|
$this->unlockableMap = $unlockableMap;
|
||||||
|
$this->decisions = $decisions;
|
||||||
|
|
||||||
|
$this->operations = $this->calculateOperations();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return OperationInterface[]
|
||||||
|
*/
|
||||||
|
public function getOperations()
|
||||||
|
{
|
||||||
|
return $this->operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function calculateOperations()
|
||||||
|
{
|
||||||
|
$operations = array();
|
||||||
|
$lockMeansUpdateMap = $this->findPotentialUpdates();
|
||||||
|
|
||||||
|
foreach ($this->decisions as $i => $decision) {
|
||||||
|
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||||
|
$reason = $decision[Decisions::DECISION_REASON];
|
||||||
|
|
||||||
|
$package = $this->pool->literalToPackage($literal);
|
||||||
|
|
||||||
|
// wanted & !present
|
||||||
|
if ($literal > 0 && !isset($this->presentMap[$package->id])) {
|
||||||
|
if (isset($lockMeansUpdateMap[abs($literal)]) && !$package instanceof AliasPackage) {
|
||||||
|
$operations[] = new Operation\UpdateOperation($lockMeansUpdateMap[abs($literal)], $package, $reason);
|
||||||
|
|
||||||
|
// avoid updates to one package from multiple origins
|
||||||
|
unset($lockMeansUpdateMap[abs($literal)]);
|
||||||
|
$ignoreRemove[$source->id] = true;
|
||||||
|
} else {
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$operations[] = new Operation\MarkAliasInstalledOperation($package, $reason);
|
||||||
|
} else {
|
||||||
|
$operations[] = new Operation\InstallOperation($package, $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->presentMap[$package->id]) && !isset($ignoreRemove[$package->id])) {
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
$operations[] = new Operation\MarkAliasUninstalledOperation($package, $reason);
|
||||||
|
} else {
|
||||||
|
$operations[] = new Operation\UninstallOperation($package, $reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $operations;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO additionalFixedRepository needs to be looked at here as well?
|
||||||
|
public function getNewLockNonDevPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
foreach ($this->decisions as $i => $decision) {
|
||||||
|
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||||
|
|
||||||
|
if ($literal > 0) {
|
||||||
|
$package = $this->pool->literalToPackage($literal);
|
||||||
|
if (!isset($this->unlockableMap[$package->id]) && !($package instanceof AliasPackage) && !($package instanceof RootAliasPackage)) {
|
||||||
|
$packages[] = $package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getNewLockDevPackages()
|
||||||
|
{
|
||||||
|
$packages = array();
|
||||||
|
return $packages;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function findPotentialUpdates()
|
||||||
|
{
|
||||||
|
$lockMeansUpdateMap = array();
|
||||||
|
|
||||||
|
foreach ($this->decisions as $i => $decision) {
|
||||||
|
$literal = $decision[Decisions::DECISION_LITERAL];
|
||||||
|
$package = $this->pool->literalToPackage($literal);
|
||||||
|
|
||||||
|
if ($package instanceof AliasPackage) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// !wanted & present
|
||||||
|
if ($literal <= 0 && isset($this->presentMap[$package->id])) {
|
||||||
|
// TODO can't we just look at existing rules?
|
||||||
|
$updates = $this->policy->findUpdatePackages($this->pool, $package);
|
||||||
|
|
||||||
|
$literals = array($package->id);
|
||||||
|
|
||||||
|
foreach ($updates as $update) {
|
||||||
|
$literals[] = $update->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($literals as $updateLiteral) {
|
||||||
|
if ($updateLiteral !== $literal && !isset($lockMeansUpdateMap[$updateLiteral])) {
|
||||||
|
$lockMeansUpdateMap[$updateLiteral] = $package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $lockMeansUpdateMap;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ interface PolicyInterface
|
||||||
{
|
{
|
||||||
public function versionCompare(PackageInterface $a, PackageInterface $b, $operator);
|
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;
|
namespace Composer\DependencyResolver;
|
||||||
|
|
||||||
use Composer\Package\BasePackage;
|
|
||||||
use Composer\Package\AliasPackage;
|
use Composer\Package\AliasPackage;
|
||||||
use Composer\Package\Version\VersionParser;
|
use Composer\Package\Version\VersionParser;
|
||||||
use Composer\Repository\RepositorySet;
|
|
||||||
use Composer\Semver\Constraint\ConstraintInterface;
|
use Composer\Semver\Constraint\ConstraintInterface;
|
||||||
use Composer\Semver\Constraint\Constraint;
|
use Composer\Semver\Constraint\Constraint;
|
||||||
use Composer\Semver\Constraint\EmptyConstraint;
|
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;
|
use Composer\Package\PackageInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -53,6 +53,10 @@ class PoolBuilder
|
||||||
|
|
||||||
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
// TODO do we really want the request here? kind of want a root requirements thingy instead
|
||||||
$loadNames = array();
|
$loadNames = array();
|
||||||
|
foreach ($request->getFixedPackages() as $package) {
|
||||||
|
// TODO can actually use very specific constraint
|
||||||
|
$loadNames[$package->getname()] = null;
|
||||||
|
}
|
||||||
foreach ($request->getJobs() as $job) {
|
foreach ($request->getJobs() as $job) {
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'install':
|
case 'install':
|
||||||
|
@ -99,7 +103,7 @@ class PoolBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($this->packages as $i => $package) {
|
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
|
// isset also checks non-null value
|
||||||
if (!$package instanceof AliasPackage && isset($this->nameConstraints[$package->getName()])) {
|
if (!$package instanceof AliasPackage && isset($this->nameConstraints[$package->getName()])) {
|
||||||
$constraint = $this->nameConstraints[$package->getName()];
|
$constraint = $this->nameConstraints[$package->getName()];
|
||||||
|
|
|
@ -220,7 +220,7 @@ class Problem
|
||||||
if (isset($job['constraint'])) {
|
if (isset($job['constraint'])) {
|
||||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||||
} else {
|
} else {
|
||||||
$packages = array();
|
$packages = $this->pool->whatProvides($job['packageName'], null);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])';
|
return 'Job(cmd='.$job['cmd'].', target='.$job['packageName'].', packages=['.$this->getPackageList($packages).'])';
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
|
|
||||||
namespace Composer\DependencyResolver;
|
namespace Composer\DependencyResolver;
|
||||||
|
|
||||||
|
use Composer\Package\Package;
|
||||||
|
use Composer\Package\PackageInterface;
|
||||||
|
use Composer\Package\RootAliasPackage;
|
||||||
|
use Composer\Repository\RepositoryInterface;
|
||||||
use Composer\Semver\Constraint\ConstraintInterface;
|
use Composer\Semver\Constraint\ConstraintInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,11 +23,14 @@ use Composer\Semver\Constraint\ConstraintInterface;
|
||||||
*/
|
*/
|
||||||
class Request
|
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)
|
public function install($packageName, ConstraintInterface $constraint = null)
|
||||||
|
@ -31,11 +38,6 @@ class Request
|
||||||
$this->addJob($packageName, 'install', $constraint);
|
$this->addJob($packageName, 'install', $constraint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function update($packageName, ConstraintInterface $constraint = null)
|
|
||||||
{
|
|
||||||
$this->addJob($packageName, 'update', $constraint);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function remove($packageName, ConstraintInterface $constraint = null)
|
public function remove($packageName, ConstraintInterface $constraint = null)
|
||||||
{
|
{
|
||||||
$this->addJob($packageName, 'remove', $constraint);
|
$this->addJob($packageName, 'remove', $constraint);
|
||||||
|
@ -43,18 +45,21 @@ class Request
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark an existing package as being installed and having to remain installed
|
* 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[] = $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);
|
$packageName = strtolower($packageName);
|
||||||
|
|
||||||
|
@ -62,17 +67,48 @@ class Request
|
||||||
'cmd' => $cmd,
|
'cmd' => $cmd,
|
||||||
'packageName' => $packageName,
|
'packageName' => $packageName,
|
||||||
'constraint' => $constraint,
|
'constraint' => $constraint,
|
||||||
'fixed' => $fixed,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function updateAll()
|
|
||||||
{
|
|
||||||
$this->jobs[] = array('cmd' => 'update-all');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getJobs()
|
public function getJobs()
|
||||||
{
|
{
|
||||||
return $this->jobs;
|
return $this->jobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFixedPackages()
|
||||||
|
{
|
||||||
|
return $this->fixedPackages;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPresentMap()
|
||||||
|
{
|
||||||
|
$presentMap = array();
|
||||||
|
|
||||||
|
if ($this->lockedRepository) {
|
||||||
|
foreach ($this->lockedRepository as $package) {
|
||||||
|
$presentMap[$package->id] = $package;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->fixedPackages as $package) {
|
||||||
|
$presentMap[$package->id] = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $presentMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUnlockableMap()
|
||||||
|
{
|
||||||
|
$unlockableMap = array();
|
||||||
|
|
||||||
|
foreach ($this->unlockables as $package) {
|
||||||
|
$unlockableMap[$package->id] = $package;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $unlockableMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLockMap()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,7 +231,7 @@ abstract class Rule
|
||||||
case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
|
case self::RULE_INSTALLED_PACKAGE_OBSOLETES:
|
||||||
return $ruleText;
|
return $ruleText;
|
||||||
case self::RULE_PACKAGE_SAME_NAME:
|
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:
|
case self::RULE_PACKAGE_IMPLICIT_OBSOLETES:
|
||||||
return $ruleText;
|
return $ruleText;
|
||||||
case self::RULE_LEARNED:
|
case self::RULE_LEARNED:
|
||||||
|
|
|
@ -24,8 +24,6 @@ class RuleSetGenerator
|
||||||
protected $policy;
|
protected $policy;
|
||||||
protected $pool;
|
protected $pool;
|
||||||
protected $rules;
|
protected $rules;
|
||||||
protected $jobs;
|
|
||||||
protected $installedMap;
|
|
||||||
protected $addedMap;
|
protected $addedMap;
|
||||||
protected $conflictAddedMap;
|
protected $conflictAddedMap;
|
||||||
protected $addedPackages;
|
protected $addedPackages;
|
||||||
|
@ -218,8 +216,6 @@ class RuleSetGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
// check obsoletes and implicit obsoletes of a package
|
// check obsoletes and implicit obsoletes of a package
|
||||||
$isInstalled = isset($this->installedMap[$package->id]);
|
|
||||||
|
|
||||||
foreach ($package->getReplaces() as $link) {
|
foreach ($package->getReplaces() as $link) {
|
||||||
if (!isset($this->addedPackagesByNames[$link->getTarget()])) {
|
if (!isset($this->addedPackagesByNames[$link->getTarget()])) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -232,7 +228,7 @@ class RuleSetGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->obsoleteImpossibleForAlias($package, $provider)) {
|
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));
|
$this->addRule(RuleSet::TYPE_PACKAGE, $this->createRule2Literals($package, $provider, $reason, $link));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,21 +250,31 @@ class RuleSetGenerator
|
||||||
return $impossible;
|
return $impossible;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addRulesForJobs($ignorePlatformReqs)
|
protected function addRulesForRequest($request, $ignorePlatformReqs)
|
||||||
{
|
{
|
||||||
foreach ($this->jobs as $job) {
|
foreach ($request->getFixedPackages() as $package) {
|
||||||
|
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
||||||
|
|
||||||
|
$rule = $this->createInstallOneOfRule(array($package), Rule::RULE_JOB_INSTALL, array(
|
||||||
|
'cmd' => 'fix',
|
||||||
|
'packageName' => $package->getName(),
|
||||||
|
'constraint' => null,
|
||||||
|
'fixed' => true
|
||||||
|
));
|
||||||
|
$this->addRule(RuleSet::TYPE_JOB, $rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($request->getJobs() as $job) {
|
||||||
switch ($job['cmd']) {
|
switch ($job['cmd']) {
|
||||||
case 'install':
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
$packages = $this->pool->whatProvides($job['packageName'], $job['constraint']);
|
||||||
if ($packages) {
|
if ($packages) {
|
||||||
foreach ($packages as $package) {
|
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);
|
$rule = $this->createInstallOneOfRule($packages, Rule::RULE_JOB_INSTALL, $job);
|
||||||
|
@ -288,21 +294,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->rules = new RuleSet;
|
||||||
$this->installedMap = $installedMap;
|
|
||||||
|
|
||||||
$this->addedMap = array();
|
$this->addedMap = array();
|
||||||
$this->conflictAddedMap = array();
|
$this->conflictAddedMap = array();
|
||||||
$this->addedPackages = array();
|
$this->addedPackages = array();
|
||||||
$this->addedPackagesByNames = array();
|
$this->addedPackagesByNames = array();
|
||||||
foreach ($this->installedMap as $package) {
|
|
||||||
$this->addRulesForPackage($package, $ignorePlatformReqs);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->addRulesForJobs($ignorePlatformReqs);
|
$this->addRulesForRequest($request, $ignorePlatformReqs);
|
||||||
|
|
||||||
$this->addConflictRules();
|
$this->addConflictRules();
|
||||||
|
|
||||||
|
|
|
@ -29,23 +29,18 @@ class Solver
|
||||||
protected $policy;
|
protected $policy;
|
||||||
/** @var Pool */
|
/** @var Pool */
|
||||||
protected $pool = null;
|
protected $pool = null;
|
||||||
/** @var RepositoryInterface */
|
|
||||||
protected $installed;
|
|
||||||
/** @var RuleSet */
|
/** @var RuleSet */
|
||||||
protected $rules;
|
protected $rules;
|
||||||
/** @var RuleSetGenerator */
|
/** @var RuleSetGenerator */
|
||||||
protected $ruleSetGenerator;
|
protected $ruleSetGenerator;
|
||||||
/** @var array */
|
|
||||||
protected $jobs;
|
|
||||||
|
|
||||||
/** @var int[] */
|
|
||||||
protected $updateMap = array();
|
|
||||||
/** @var RuleWatchGraph */
|
/** @var RuleWatchGraph */
|
||||||
protected $watchGraph;
|
protected $watchGraph;
|
||||||
/** @var Decisions */
|
/** @var Decisions */
|
||||||
protected $decisions;
|
protected $decisions;
|
||||||
/** @var int[] */
|
/** @var Package[] */
|
||||||
protected $installedMap;
|
protected $fixedMap;
|
||||||
|
|
||||||
/** @var int */
|
/** @var int */
|
||||||
protected $propagateIndex;
|
protected $propagateIndex;
|
||||||
|
@ -67,15 +62,13 @@ class Solver
|
||||||
/**
|
/**
|
||||||
* @param PolicyInterface $policy
|
* @param PolicyInterface $policy
|
||||||
* @param Pool $pool
|
* @param Pool $pool
|
||||||
* @param RepositoryInterface $installed
|
|
||||||
* @param IOInterface $io
|
* @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->io = $io;
|
||||||
$this->policy = $policy;
|
$this->policy = $policy;
|
||||||
$this->pool = $pool;
|
$this->pool = $pool;
|
||||||
$this->installed = $installed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,36 +157,22 @@ class Solver
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function setupInstalledMap()
|
protected function setupFixedMap(Request $request)
|
||||||
{
|
{
|
||||||
$this->installedMap = array();
|
$this->fixedMap = array();
|
||||||
foreach ($this->installed->getPackages() as $package) {
|
foreach ($request->getFixedPackages() as $package) {
|
||||||
$this->installedMap[$package->id] = $package;
|
$this->fixedMap[$package->id] = $package;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param Request $request
|
||||||
* @param bool $ignorePlatformReqs
|
* @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']) {
|
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':
|
case 'install':
|
||||||
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
|
if ($ignorePlatformReqs && preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $job['packageName'])) {
|
||||||
break;
|
break;
|
||||||
|
@ -212,18 +191,16 @@ class Solver
|
||||||
/**
|
/**
|
||||||
* @param Request $request
|
* @param Request $request
|
||||||
* @param bool $ignorePlatformReqs
|
* @param bool $ignorePlatformReqs
|
||||||
* @return array
|
* @return LockTransaction
|
||||||
*/
|
*/
|
||||||
public function solve(Request $request, $ignorePlatformReqs = false)
|
public function solve(Request $request, $ignorePlatformReqs = false)
|
||||||
{
|
{
|
||||||
$this->jobs = $request->getJobs();
|
$this->setupFixedMap($request);
|
||||||
|
|
||||||
$this->setupInstalledMap();
|
|
||||||
|
|
||||||
$this->io->writeError('Generating rules', true, IOInterface::DEBUG);
|
$this->io->writeError('Generating rules', true, IOInterface::DEBUG);
|
||||||
$this->ruleSetGenerator = new RuleSetGenerator($this->policy, $this->pool);
|
$this->ruleSetGenerator = new RuleSetGenerator($this->policy, $this->pool);
|
||||||
$this->rules = $this->ruleSetGenerator->getRulesFor($this->jobs, $this->installedMap, $ignorePlatformReqs);
|
$this->rules = $this->ruleSetGenerator->getRulesFor($request, $ignorePlatformReqs);
|
||||||
$this->checkForRootRequireProblems($ignorePlatformReqs);
|
$this->checkForRootRequireProblems($request, $ignorePlatformReqs);
|
||||||
$this->decisions = new Decisions($this->pool);
|
$this->decisions = new Decisions($this->pool);
|
||||||
$this->watchGraph = new RuleWatchGraph;
|
$this->watchGraph = new RuleWatchGraph;
|
||||||
|
|
||||||
|
@ -240,20 +217,11 @@ class Solver
|
||||||
$this->io->writeError('', true, IOInterface::DEBUG);
|
$this->io->writeError('', true, IOInterface::DEBUG);
|
||||||
$this->io->writeError(sprintf('Dependency resolution completed in %.3f seconds', microtime(true) - $before), true, IOInterface::VERBOSE);
|
$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) {
|
if ($this->problems) {
|
||||||
throw new SolverProblemsException($this->problems, $this->installedMap, $this->learnedPool);
|
throw new SolverProblemsException($this->problems, $request->getPresentMap(), $this->learnedPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
$transaction = new Transaction($this->policy, $this->pool, $this->installedMap, $this->decisions);
|
return new LockTransaction($this->policy, $this->pool, $request->getPresentMap(), $request->getUnlockableMap(), $this->decisions);
|
||||||
|
|
||||||
return $transaction->getOperations();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -392,7 +360,7 @@ class Solver
|
||||||
private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
|
private function selectAndInstall($level, array $decisionQueue, $disableRules, Rule $rule)
|
||||||
{
|
{
|
||||||
// choose best package to install from decisionQueue
|
// 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);
|
$selectedLiteral = array_shift($literals);
|
||||||
|
|
||||||
|
@ -728,19 +696,14 @@ class Solver
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($noneSatisfied && count($decisionQueue)) {
|
if ($noneSatisfied && count($decisionQueue)) {
|
||||||
// prune all update packages until installed version
|
// if any of the options in the decision queue are fixed, only use those
|
||||||
// except for requested updates
|
$prunedQueue = array();
|
||||||
if (count($this->installed) != count($this->updateMap)) {
|
foreach ($decisionQueue as $literal) {
|
||||||
$prunedQueue = array();
|
if (isset($this->fixedMap[abs($literal)])) {
|
||||||
foreach ($decisionQueue as $literal) {
|
$prunedQueue[] = $literal;
|
||||||
if (isset($this->installedMap[abs($literal)])) {
|
|
||||||
$prunedQueue[] = $literal;
|
|
||||||
if (isset($this->updateMap[abs($literal)])) {
|
|
||||||
$prunedQueue = $decisionQueue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (!empty($prunedQueue)) {
|
||||||
$decisionQueue = $prunedQueue;
|
$decisionQueue = $prunedQueue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,244 +0,0 @@
|
||||||
<?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\Package\AliasPackage;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Nils Adermann <naderman@naderman.de>
|
|
||||||
*/
|
|
||||||
class Transaction
|
|
||||||
{
|
|
||||||
protected $policy;
|
|
||||||
protected $pool;
|
|
||||||
protected $installedMap;
|
|
||||||
protected $decisions;
|
|
||||||
protected $transaction;
|
|
||||||
|
|
||||||
public function __construct($policy, $pool, $installedMap, $decisions)
|
|
||||||
{
|
|
||||||
$this->policy = $policy;
|
|
||||||
$this->pool = $pool;
|
|
||||||
$this->installedMap = $installedMap;
|
|
||||||
$this->decisions = $decisions;
|
|
||||||
$this->transaction = array();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOperations()
|
|
||||||
{
|
|
||||||
$installMeansUpdateMap = $this->findUpdates();
|
|
||||||
|
|
||||||
$updateMap = array();
|
|
||||||
$installMap = array();
|
|
||||||
$uninstallMap = array();
|
|
||||||
|
|
||||||
foreach ($this->decisions as $i => $decision) {
|
|
||||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
|
||||||
$reason = $decision[Decisions::DECISION_REASON];
|
|
||||||
|
|
||||||
$package = $this->pool->literalToPackage($literal);
|
|
||||||
|
|
||||||
// wanted & installed || !wanted & !installed
|
|
||||||
if (($literal > 0) == isset($this->installedMap[$package->id])) {
|
|
||||||
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 ($package instanceof AliasPackage) {
|
|
||||||
$queue[] = $package->getAliasOf();
|
|
||||||
} else {
|
|
||||||
foreach ($package->getRequires() as $link) {
|
|
||||||
$possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
|
||||||
|
|
||||||
foreach ($possibleRequires as $require) {
|
|
||||||
$queue[] = $require;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$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]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($uninstallMap as $uninstall) {
|
|
||||||
$this->uninstall($uninstall['package'], $uninstall['reason']);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findRootPackages($installMap, $updateMap)
|
|
||||||
{
|
|
||||||
$packages = $installMap + $updateMap;
|
|
||||||
$roots = $packages;
|
|
||||||
|
|
||||||
foreach ($packages as $packageId => $operation) {
|
|
||||||
$package = $operation['package'];
|
|
||||||
|
|
||||||
if (!isset($roots[$packageId])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($package->getRequires() as $link) {
|
|
||||||
$possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
|
||||||
|
|
||||||
foreach ($possibleRequires as $require) {
|
|
||||||
if ($require !== $package) {
|
|
||||||
unset($roots[$require->id]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $roots;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findUpdates()
|
|
||||||
{
|
|
||||||
$installMeansUpdateMap = array();
|
|
||||||
|
|
||||||
foreach ($this->decisions as $i => $decision) {
|
|
||||||
$literal = $decision[Decisions::DECISION_LITERAL];
|
|
||||||
$package = $this->pool->literalToPackage($literal);
|
|
||||||
|
|
||||||
if ($package instanceof AliasPackage) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// !wanted & installed
|
|
||||||
if ($literal <= 0 && isset($this->installedMap[$package->id])) {
|
|
||||||
$updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
|
|
||||||
|
|
||||||
$literals = array($package->id);
|
|
||||||
|
|
||||||
foreach ($updates as $update) {
|
|
||||||
$literals[] = $update->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($literals as $updateLiteral) {
|
|
||||||
if ($updateLiteral !== $literal) {
|
|
||||||
$installMeansUpdateMap[abs($updateLiteral)] = $package;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $installMeansUpdateMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function install($package, $reason)
|
|
||||||
{
|
|
||||||
if ($package instanceof AliasPackage) {
|
|
||||||
return $this->markAliasInstalled($package, $reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
$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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,6 +19,7 @@ use Composer\IO\IOInterface;
|
||||||
use Composer\Composer;
|
use Composer\Composer;
|
||||||
use Composer\DependencyResolver\Operation\OperationInterface;
|
use Composer\DependencyResolver\Operation\OperationInterface;
|
||||||
use Composer\Repository\CompositeRepository;
|
use Composer\Repository\CompositeRepository;
|
||||||
|
use Composer\Repository\RepositoryInterface;
|
||||||
use Composer\Repository\RepositorySet;
|
use Composer\Repository\RepositorySet;
|
||||||
use Composer\Script;
|
use Composer\Script;
|
||||||
use Composer\Installer\PackageEvent;
|
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
|
* @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
|
* 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
|
* @param RepositoryInterface $installedRepo Installed packages
|
||||||
* @return SuggestedPackagesReporter
|
* @return SuggestedPackagesReporter
|
||||||
*/
|
*/
|
||||||
public function output(RepositoryInterface $installedRepo = null)
|
public function output(RepositoryInterface $lockedRepo = null)
|
||||||
{
|
{
|
||||||
$suggestedPackages = $this->getPackages();
|
$suggestedPackages = $this->getPackages();
|
||||||
$installedPackages = array();
|
$lockedPackages = array();
|
||||||
if (null !== $installedRepo && ! empty($suggestedPackages)) {
|
if (null !== $lockedRepo && ! empty($suggestedPackages)) {
|
||||||
foreach ($installedRepo->getPackages() as $package) {
|
foreach ($lockedRepo->getPackages() as $package) {
|
||||||
$installedPackages = array_merge(
|
$lockedPackages = array_merge(
|
||||||
$installedPackages,
|
$lockedPackages,
|
||||||
$package->getNames()
|
$package->getNames()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($suggestedPackages as $suggestion) {
|
foreach ($suggestedPackages as $suggestion) {
|
||||||
if (in_array($suggestion['target'], $installedPackages)) {
|
if (in_array($suggestion['target'], $lockedPackages)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Locker
|
||||||
private $dumper;
|
private $dumper;
|
||||||
private $process;
|
private $process;
|
||||||
private $lockDataCache;
|
private $lockDataCache;
|
||||||
|
private $virtualFileWritten;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes packages locker.
|
* Initializes packages locker.
|
||||||
|
@ -108,7 +109,7 @@ class Locker
|
||||||
*/
|
*/
|
||||||
public function isLocked()
|
public function isLocked()
|
||||||
{
|
{
|
||||||
if (!$this->lockFile->exists()) {
|
if (!$this->virtualFileWritten && !$this->lockFile->exists()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,10 +283,11 @@ class Locker
|
||||||
* @param bool $preferStable
|
* @param bool $preferStable
|
||||||
* @param bool $preferLowest
|
* @param bool $preferLowest
|
||||||
* @param array $platformOverrides
|
* @param array $platformOverrides
|
||||||
|
* @param bool $write Whether to actually write data to disk, useful in tests and for --dry-run
|
||||||
*
|
*
|
||||||
* @return bool
|
* @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(
|
$lock = array(
|
||||||
'_readme' => array('This file locks the dependencies of your project to a known state',
|
'_readme' => array('This file locks the dependencies of your project to a known state',
|
||||||
|
@ -325,7 +327,11 @@ class Locker
|
||||||
|
|
||||||
if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) {
|
if (empty($lock['packages']) && empty($lock['packages-dev']) && empty($lock['platform']) && empty($lock['platform-dev'])) {
|
||||||
if ($this->lockFile->exists()) {
|
if ($this->lockFile->exists()) {
|
||||||
unlink($this->lockFile->getPath());
|
if ($write) {
|
||||||
|
unlink($this->lockFile->getPath());
|
||||||
|
} else {
|
||||||
|
$this->virtualFileWritten = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -337,8 +343,15 @@ class Locker
|
||||||
$isLocked = false;
|
$isLocked = false;
|
||||||
}
|
}
|
||||||
if (!$isLocked || $lock !== $this->getLockData()) {
|
if (!$isLocked || $lock !== $this->getLockData()) {
|
||||||
$this->lockFile->write($lock);
|
if ($write) {
|
||||||
$this->lockDataCache = null;
|
$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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
/** @var ArrayRepository */
|
/** @var ArrayRepository */
|
||||||
protected $repo;
|
protected $repo;
|
||||||
/** @var ArrayRepository */
|
/** @var ArrayRepository */
|
||||||
protected $repoInstalled;
|
protected $repoLocked;
|
||||||
/** @var DefaultPolicy */
|
/** @var DefaultPolicy */
|
||||||
protected $policy;
|
protected $policy;
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
{
|
{
|
||||||
$this->repositorySet = new RepositorySet(array(), 'dev');
|
$this->repositorySet = new RepositorySet(array(), 'dev');
|
||||||
$this->repo = new ArrayRepository;
|
$this->repo = new ArrayRepository;
|
||||||
$this->repoInstalled = new ArrayRepository;
|
$this->repoLocked = new ArrayRepository;
|
||||||
|
|
||||||
$this->policy = new DefaultPolicy;
|
$this->policy = new DefaultPolicy;
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA->getId());
|
$literals = array($packageA->getId());
|
||||||
$expected = array($packageA->getId());
|
$expected = array($packageA->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA1->getId(), $packageA2->getId());
|
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||||
$expected = array($packageA2->getId());
|
$expected = array($packageA2->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA1->getId(), $packageA2->getId());
|
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||||
$expected = array($packageA2->getId());
|
$expected = array($packageA2->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$expected = array($packageA1->getId());
|
$expected = array($packageA1->getId());
|
||||||
|
|
||||||
$policy = new DefaultPolicy(true);
|
$policy = new DefaultPolicy(true);
|
||||||
$selected = $policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -117,24 +117,24 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA1->getId(), $packageA2->getId());
|
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||||
$expected = array($packageA2->getId());
|
$expected = array($packageA2->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testSelectNewestOverInstalled()
|
public function testSelectNewestOverLocked()
|
||||||
{
|
{
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '2.0'));
|
||||||
$this->repoInstalled->addPackage($packageAInstalled = $this->getPackage('A', '1.0'));
|
$this->repoLocked->addPackage($packageAInstalled = $this->getPackage('A', '1.0'));
|
||||||
$this->repositorySet->addRepository($this->repoInstalled);
|
|
||||||
$this->repositorySet->addRepository($this->repo);
|
$this->repositorySet->addRepository($this->repo);
|
||||||
|
$this->repositorySet->addRepository($this->repoLocked);
|
||||||
|
|
||||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||||
|
|
||||||
$literals = array($packageA->getId(), $packageAInstalled->getId());
|
$literals = array($packageA->getId(), $packageAInstalled->getId());
|
||||||
$expected = array($packageA->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);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -146,16 +146,16 @@ class DefaultPolicyTest extends TestCase
|
||||||
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repo->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
$otherRepository->addPackage($packageAImportant = $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($otherRepository);
|
||||||
$this->repositorySet->addRepository($this->repo);
|
$this->repositorySet->addRepository($this->repo);
|
||||||
|
$this->repositorySet->addRepository($this->repoLocked);
|
||||||
|
|
||||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||||
|
|
||||||
$literals = array($packageA->getId(), $packageAImportant->getId());
|
$literals = array($packageA->getId(), $packageAImportant->getId());
|
||||||
$expected = array($packageAImportant->getId());
|
$expected = array($packageAImportant->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -177,7 +177,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
|
|
||||||
$literals = array($package1->getId(), $package2->getId(), $package3->getId(), $package4->getId());
|
$literals = array($package1->getId(), $package2->getId(), $package3->getId(), $package4->getId());
|
||||||
$expected = array($package2->getId());
|
$expected = array($package2->getId());
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||||
|
|
||||||
$expected = array($package4->getId());
|
$expected = array($package4->getId());
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$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'));
|
$repoImportant->addPackage($packageA2AliasImportant = new AliasPackage($packageA2Important, '2.1.9999999.9999999-dev', '2.1.x-dev'));
|
||||||
$packageAAliasImportant->setRootPackageAlias(true);
|
$packageAAliasImportant->setRootPackageAlias(true);
|
||||||
|
|
||||||
$this->repositorySet->addRepository($this->repoInstalled);
|
|
||||||
$this->repositorySet->addRepository($repoImportant);
|
$this->repositorySet->addRepository($repoImportant);
|
||||||
$this->repositorySet->addRepository($this->repo);
|
$this->repositorySet->addRepository($this->repo);
|
||||||
|
$this->repositorySet->addRepository($this->repoLocked);
|
||||||
|
|
||||||
$pool = $this->repositorySet->createPoolForPackage('A');
|
$pool = $this->repositorySet->createPoolForPackage('A');
|
||||||
|
|
||||||
|
@ -219,7 +219,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
|
|
||||||
$expected = array($packageAAliasImportant->getId());
|
$expected = array($packageAAliasImportant->getId());
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -239,7 +239,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA->getId(), $packageB->getId());
|
$literals = array($packageA->getId(), $packageB->getId());
|
||||||
$expected = $literals;
|
$expected = $literals;
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA->getId(), $packageB->getId());
|
$literals = array($packageA->getId(), $packageB->getId());
|
||||||
$expected = $literals;
|
$expected = $literals;
|
||||||
|
|
||||||
$selected = $this->policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $this->policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA->getId(), $packageB->getId());
|
$literals = array($packageA->getId(), $packageB->getId());
|
||||||
$expected = $literals;
|
$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);
|
$this->assertEquals($expected, $selected);
|
||||||
|
|
||||||
// test with reversed order in repo
|
// test with reversed order in repo
|
||||||
|
@ -295,20 +295,10 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA->getId(), $packageB->getId());
|
$literals = array($packageA->getId(), $packageB->getId());
|
||||||
$expected = $literals;
|
$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);
|
$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()
|
public function testSelectLowest()
|
||||||
{
|
{
|
||||||
$policy = new DefaultPolicy(false, true);
|
$policy = new DefaultPolicy(false, true);
|
||||||
|
@ -322,7 +312,7 @@ class DefaultPolicyTest extends TestCase
|
||||||
$literals = array($packageA1->getId(), $packageA2->getId());
|
$literals = array($packageA1->getId(), $packageA2->getId());
|
||||||
$expected = array($packageA1->getId());
|
$expected = array($packageA1->getId());
|
||||||
|
|
||||||
$selected = $policy->selectPreferredPackages($pool, array(), $literals);
|
$selected = $policy->selectPreferredPackages($pool, $literals);
|
||||||
|
|
||||||
$this->assertSame($expected, $selected);
|
$this->assertSame($expected, $selected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,12 @@ class RequestTest extends TestCase
|
||||||
|
|
||||||
$request = new Request();
|
$request = new Request();
|
||||||
$request->install('foo');
|
$request->install('foo');
|
||||||
$request->fix('bar');
|
|
||||||
$request->remove('foobar');
|
$request->remove('foobar');
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array(
|
array(
|
||||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null, 'fixed' => false),
|
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => null),
|
||||||
array('cmd' => 'install', 'packageName' => 'bar', 'constraint' => null, 'fixed' => true),
|
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null),
|
||||||
array('cmd' => 'remove', 'packageName' => 'foobar', 'constraint' => null, 'fixed' => false),
|
|
||||||
),
|
),
|
||||||
$request->getJobs()
|
$request->getJobs()
|
||||||
);
|
);
|
||||||
|
@ -60,21 +58,9 @@ class RequestTest extends TestCase
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array(
|
array(
|
||||||
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint, 'fixed' => false),
|
array('cmd' => 'install', 'packageName' => 'foo', 'constraint' => $constraint),
|
||||||
),
|
),
|
||||||
$request->getJobs()
|
$request->getJobs()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testUpdateAll()
|
|
||||||
{
|
|
||||||
$request = new Request();
|
|
||||||
|
|
||||||
$request->updateAll();
|
|
||||||
|
|
||||||
$this->assertEquals(
|
|
||||||
array(array('cmd' => 'update-all')),
|
|
||||||
$request->getJobs()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ class SolverTest extends TestCase
|
||||||
protected $repoSet;
|
protected $repoSet;
|
||||||
protected $repo;
|
protected $repo;
|
||||||
protected $repoInstalled;
|
protected $repoInstalled;
|
||||||
|
protected $repoLocked;
|
||||||
protected $request;
|
protected $request;
|
||||||
protected $policy;
|
protected $policy;
|
||||||
protected $solver;
|
protected $solver;
|
||||||
|
@ -39,6 +40,7 @@ class SolverTest extends TestCase
|
||||||
$this->repoSet = new RepositorySet(array());
|
$this->repoSet = new RepositorySet(array());
|
||||||
$this->repo = new ArrayRepository;
|
$this->repo = new ArrayRepository;
|
||||||
$this->repoInstalled = new InstalledArrayRepository;
|
$this->repoInstalled = new InstalledArrayRepository;
|
||||||
|
$this->repoLocked = new ArrayRepository;
|
||||||
|
|
||||||
$this->request = new Request($this->repoSet);
|
$this->request = new Request($this->repoSet);
|
||||||
$this->policy = new DefaultPolicy;
|
$this->policy = new DefaultPolicy;
|
||||||
|
@ -59,6 +61,7 @@ class SolverTest extends TestCase
|
||||||
public function testSolverRemoveIfNotInstalled()
|
public function testSolverRemoveIfNotInstalled()
|
||||||
{
|
{
|
||||||
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
$this->repoInstalled->addPackage($packageA = $this->getPackage('A', '1.0'));
|
||||||
|
$this->repoLocked->addPackage(clone $packageA);
|
||||||
$this->reposComplete();
|
$this->reposComplete();
|
||||||
|
|
||||||
$this->checkSolverResult(array(
|
$this->checkSolverResult(array(
|
||||||
|
@ -919,8 +922,8 @@ class SolverTest extends TestCase
|
||||||
|
|
||||||
protected function reposComplete()
|
protected function reposComplete()
|
||||||
{
|
{
|
||||||
$this->repoSet->addRepository($this->repoInstalled);
|
|
||||||
$this->repoSet->addRepository($this->repo);
|
$this->repoSet->addRepository($this->repo);
|
||||||
|
$this->repoSet->addRepository($this->repoLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createSolver()
|
protected function createSolver()
|
||||||
|
|
|
@ -95,6 +95,55 @@ g/g is dev and installed in a different ref than the #ref, so it gets updated an
|
||||||
"dist": { "reference": "0000000000000000000000000000000000000000", "url": "https://api.github.com/repos/g/g/zipball/0000000000000000000000000000000000000000", "type": "zip" }
|
"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--
|
--EXPECT-LOCK--
|
||||||
{
|
{
|
||||||
"packages": [
|
"packages": [
|
||||||
|
|
|
@ -16,6 +16,7 @@ use Composer\Installer;
|
||||||
use Composer\Console\Application;
|
use Composer\Console\Application;
|
||||||
use Composer\IO\BufferIO;
|
use Composer\IO\BufferIO;
|
||||||
use Composer\Json\JsonFile;
|
use Composer\Json\JsonFile;
|
||||||
|
use Composer\Package\Dumper\ArrayDumper;
|
||||||
use Composer\Util\Filesystem;
|
use Composer\Util\Filesystem;
|
||||||
use Composer\Repository\ArrayRepository;
|
use Composer\Repository\ArrayRepository;
|
||||||
use Composer\Repository\RepositoryManager;
|
use Composer\Repository\RepositoryManager;
|
||||||
|
@ -74,10 +75,30 @@ class InstallerTest extends TestCase
|
||||||
foreach ($repositories as $repository) {
|
foreach ($repositories as $repository) {
|
||||||
$repositoryManager->addRepository($repository);
|
$repositoryManager->addRepository($repository);
|
||||||
}
|
}
|
||||||
|
|
||||||
$locker = $this->getMockBuilder('Composer\Package\Locker')->disableOriginalConstructor()->getMock();
|
|
||||||
$installationManager = new InstallationManagerMock();
|
$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, JSON_PRETTY_PRINT);
|
||||||
|
}));
|
||||||
|
|
||||||
|
$tempLockData = null;
|
||||||
|
$locker = new Locker($io, $lockJsonMock, $repositoryManager, $installationManager, '{}');
|
||||||
|
|
||||||
$autoloadGenerator = $this->getMockBuilder('Composer\Autoload\AutoloadGenerator')->disableOriginalConstructor()->getMock();
|
$autoloadGenerator = $this->getMockBuilder('Composer\Autoload\AutoloadGenerator')->disableOriginalConstructor()->getMock();
|
||||||
|
|
||||||
$installer = new Installer($io, $config, clone $rootPackage, $downloadManager, $repositoryManager, $locker, $installationManager, $eventDispatcher, $autoloadGenerator);
|
$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();
|
$expectedUninstalled = isset($options['uninstall']) ? $options['uninstall'] : array();
|
||||||
|
|
||||||
$installed = $installationManager->getInstalledPackages();
|
$installed = $installationManager->getInstalledPackages();
|
||||||
$this->assertSame($expectedInstalled, $installed);
|
$this->assertEquals($this->makePackagesComparable($expectedInstalled), $this->makePackagesComparable($installed));
|
||||||
|
|
||||||
$updated = $installationManager->getUpdatedPackages();
|
$updated = $installationManager->getUpdatedPackages();
|
||||||
$this->assertSame($expectedUpdated, $updated);
|
$this->assertSame($expectedUpdated, $updated);
|
||||||
|
@ -100,6 +121,17 @@ class InstallerTest extends TestCase
|
||||||
$this->assertSame($expectedUninstalled, $uninstalled);
|
$this->assertSame($expectedUninstalled, $uninstalled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function makePackagesComparable($packages)
|
||||||
|
{
|
||||||
|
$dumper = new ArrayDumper();
|
||||||
|
|
||||||
|
$comparable = [];
|
||||||
|
foreach ($packages as $package) {
|
||||||
|
$comparable[] = $dumper->dump($package);
|
||||||
|
}
|
||||||
|
return $comparable;
|
||||||
|
}
|
||||||
|
|
||||||
public function provideInstaller()
|
public function provideInstaller()
|
||||||
{
|
{
|
||||||
$cases = array();
|
$cases = array();
|
||||||
|
@ -109,11 +141,11 @@ class InstallerTest extends TestCase
|
||||||
|
|
||||||
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
||||||
$a->setRequires(array(
|
$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 = $this->getPackage('B', '1.0.0');
|
||||||
$b->setRequires(array(
|
$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(
|
$cases[] = array(
|
||||||
|
@ -129,11 +161,11 @@ class InstallerTest extends TestCase
|
||||||
|
|
||||||
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
$a = $this->getPackage('A', '1.0.0', 'Composer\Package\RootPackage');
|
||||||
$a->setRequires(array(
|
$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 = $this->getPackage('B', '1.0.0');
|
||||||
$b->setRequires(array(
|
$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(
|
$cases[] = array(
|
||||||
|
@ -144,6 +176,7 @@ class InstallerTest extends TestCase
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// TODO why are there not more cases with uninstall/update?
|
||||||
return $cases;
|
return $cases;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,13 +215,24 @@ class InstallerTest extends TestCase
|
||||||
$repositoryManager = $composer->getRepositoryManager();
|
$repositoryManager = $composer->getRepositoryManager();
|
||||||
$repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock));
|
$repositoryManager->setLocalRepository(new InstalledFilesystemRepositoryMock($jsonMock));
|
||||||
|
|
||||||
|
// emulate a writable lock file
|
||||||
|
$lockData = $lock ? json_encode($lock, JSON_PRETTY_PRINT): null;
|
||||||
$lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
|
$lockJsonMock = $this->getMockBuilder('Composer\Json\JsonFile')->disableOriginalConstructor()->getMock();
|
||||||
$lockJsonMock->expects($this->any())
|
$lockJsonMock->expects($this->any())
|
||||||
->method('read')
|
->method('read')
|
||||||
->will($this->returnValue($lock));
|
->will($this->returnCallback(function() use (&$lockData) {
|
||||||
|
return json_decode($lockData, true);
|
||||||
|
}));
|
||||||
$lockJsonMock->expects($this->any())
|
$lockJsonMock->expects($this->any())
|
||||||
->method('exists')
|
->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, JSON_PRETTY_PRINT);
|
||||||
|
}));
|
||||||
|
|
||||||
if ($expectLock) {
|
if ($expectLock) {
|
||||||
$actualLock = array();
|
$actualLock = array();
|
||||||
|
@ -245,7 +289,7 @@ class InstallerTest extends TestCase
|
||||||
|
|
||||||
$application->setAutoExit(false);
|
$application->setAutoExit(false);
|
||||||
$appOutput = fopen('php://memory', 'w+');
|
$appOutput = fopen('php://memory', 'w+');
|
||||||
$input = new StringInput($run);
|
$input = new StringInput($run.' -vvv');
|
||||||
$input->setInteractive(false);
|
$input->setInteractive(false);
|
||||||
$result = $application->run($input, new StreamOutput($appOutput));
|
$result = $application->run($input, new StreamOutput($appOutput));
|
||||||
fseek($appOutput, 0);
|
fseek($appOutput, 0);
|
||||||
|
|
Loading…
Reference in New Issue