Fix updates when dev packages have new dependencies (no more double updates needed), fixes #1105

main
Jordi Boggiano 12 years ago
parent b641f9ea68
commit f1f1ddb66b

@ -239,6 +239,10 @@ class Installer
$minimumStability = $this->package->getMinimumStability();
$stabilityFlags = $this->package->getStabilityFlags();
// init vars
$lockedRepository = null;
$repositories = null;
// initialize locker to create aliased packages
$installFromLock = false;
if (!$this->update && $this->locker->isLocked($devMode)) {
@ -258,6 +262,7 @@ class Installer
$this->io->write('<info>Loading composer repositories with package information</info>');
// creating repository pool
$policy = new DefaultPolicy();
$pool = new Pool($minimumStability, $stabilityFlags);
$pool->addRepository($installedRepo, $aliases);
if ($installFromLock) {
@ -364,11 +369,11 @@ class Installer
}
}
// prepare solver
$policy = new DefaultPolicy();
$solver = new Solver($policy, $pool, $installedRepo);
// force dev packages to have the latest links if we update or install from a (potentially new) lock
$this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-links');
// solve dependencies
$solver = new Solver($policy, $pool, $installedRepo);
try {
$operations = $solver->solve($request);
} catch (SolverProblemsException $e) {
@ -392,6 +397,76 @@ class Installer
}
// force dev packages to be updated if we update or install from a (potentially new) lock
$operations = $this->processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, 'force-updates', $operations);
// execute operations
if (!$operations) {
$this->io->write('Nothing to install or update');
}
foreach ($operations as $operation) {
// collect suggestions
if ('install' === $operation->getJobType()) {
foreach ($operation->getPackage()->getSuggests() as $target => $reason) {
$this->suggestedPackages[] = array(
'source' => $operation->getPackage()->getPrettyName(),
'target' => $target,
'reason' => $reason,
);
}
}
$event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
if (defined($event) && $this->runScripts) {
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
}
// not installing from lock, force dev packages' references if they're in root package refs
if (!$installFromLock) {
$package = null;
if ('update' === $operation->getJobType()) {
$package = $operation->getTargetPackage();
} elseif ('install' === $operation->getJobType()) {
$package = $operation->getPackage();
}
if ($package && $package->isDev()) {
$references = $this->package->getReferences();
if (isset($references[$package->getName()])) {
$package->setSourceReference($references[$package->getName()]);
$package->setDistReference($references[$package->getName()]);
}
}
}
// output alias operations in verbose mode, or all ops in dry run
if ($this->dryRun || ($this->verbose && false !== strpos($operation->getJobType(), 'Alias'))) {
$this->io->write(' - ' . $operation);
}
$this->installationManager->execute($localRepo, $operation);
$event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
if (defined($event) && $this->runScripts) {
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
}
if (!$this->dryRun) {
$localRepo->write();
}
}
return true;
}
private function processDevPackages($localRepo, $pool, $policy, $repositories, $lockedRepository, $installFromLock, $task, array $operations = null)
{
if ($task === 'force-updates' && null === $operations) {
throw new \InvalidArgumentException('Missing operations argument');
}
if ($task === 'force-links') {
$operations = array();
}
foreach ($localRepo->getPackages() as $package) {
// skip non-dev packages
if (!$package->isDev()) {
@ -414,14 +489,19 @@ class Installer
// force update to locked version if it does not match the installed version
if ($installFromLock) {
foreach ($lockedRepository->findPackages($package->getName()) as $lockedPackage) {
if (
$lockedPackage->isDev()
&& (
($lockedPackage->getSourceReference() && $lockedPackage->getSourceReference() !== $package->getSourceReference())
|| ($lockedPackage->getDistReference() && $lockedPackage->getDistReference() !== $package->getDistReference())
)
) {
$operations[] = new UpdateOperation($package, $lockedPackage);
if ($lockedPackage->isDev() && $lockedPackage->getVersion() === $package->getVersion()) {
if ($task === 'force-links') {
$package->setRequires($lockedPackage->getRequires());
$package->setConflicts($lockedPackage->getConflicts());
$package->setProvides($lockedPackage->getProvides());
$package->setReplaces($lockedPackage->getReplaces());
} elseif ($task === 'force-updates') {
if (($lockedPackage->getSourceReference() && $lockedPackage->getSourceReference() !== $package->getSourceReference())
|| ($lockedPackage->getDistReference() && $lockedPackage->getDistReference() !== $package->getDistReference())
) {
$operations[] = new UpdateOperation($package, $lockedPackage);
}
}
break;
}
@ -456,79 +536,36 @@ class Installer
if ($matches && $matches = $policy->selectPreferedPackages($pool, array(), $matches)) {
$newPackage = $pool->literalToPackage($matches[0]);
if ($newPackage && $newPackage->getSourceReference() !== $package->getSourceReference()) {
if ($task === 'force-links' && $newPackage) {
$package->setRequires($newPackage->getRequires());
$package->setConflicts($newPackage->getConflicts());
$package->setProvides($newPackage->getProvides());
$package->setReplaces($newPackage->getReplaces());
}
if ($task === 'force-updates' && $newPackage && (
(($newPackage->getSourceReference() && $newPackage->getSourceReference() !== $package->getSourceReference())
|| ($newPackage->getDistReference() && $newPackage->getDistReference() !== $package->getDistReference())
)
)) {
$operations[] = new UpdateOperation($package, $newPackage);
}
}
}
// force installed package to update to referenced version if it does not match the installed version
$references = $this->package->getReferences();
if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
// changing the source ref to update to will be handled in the operations loop below
$operations[] = new UpdateOperation($package, clone $package);
}
}
}
// execute operations
if (!$operations) {
$this->io->write('Nothing to install or update');
}
foreach ($operations as $operation) {
// collect suggestions
if ('install' === $operation->getJobType()) {
foreach ($operation->getPackage()->getSuggests() as $target => $reason) {
$this->suggestedPackages[] = array(
'source' => $operation->getPackage()->getPrettyName(),
'target' => $target,
'reason' => $reason,
);
}
}
$event = 'Composer\Script\ScriptEvents::PRE_PACKAGE_'.strtoupper($operation->getJobType());
if (defined($event) && $this->runScripts) {
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
}
// not installing from lock, force dev packages' references if they're in root package refs
if (!$installFromLock) {
$package = null;
if ('update' === $operation->getJobType()) {
$package = $operation->getTargetPackage();
} elseif ('install' === $operation->getJobType()) {
$package = $operation->getPackage();
}
if ($package && $package->isDev()) {
if ($task === 'force-updates') {
// force installed package to update to referenced version if it does not match the installed version
$references = $this->package->getReferences();
if (isset($references[$package->getName()])) {
$package->setSourceReference($references[$package->getName()]);
$package->setDistReference($references[$package->getName()]);
if (isset($references[$package->getName()]) && $references[$package->getName()] !== $package->getSourceReference()) {
// changing the source ref to update to will be handled in the operations loop below
$operations[] = new UpdateOperation($package, clone $package);
}
}
}
// output alias operations in verbose mode, or all ops in dry run
if ($this->dryRun || ($this->verbose && false !== strpos($operation->getJobType(), 'Alias'))) {
$this->io->write(' - ' . $operation);
}
$this->installationManager->execute($localRepo, $operation);
$event = 'Composer\Script\ScriptEvents::POST_PACKAGE_'.strtoupper($operation->getJobType());
if (defined($event) && $this->runScripts) {
$this->eventDispatcher->dispatchPackageEvent(constant($event), $this->devMode, $operation);
}
if (!$this->dryRun) {
$localRepo->write();
}
}
return true;
return $operations;
}
private function getRootAliases()

@ -0,0 +1,41 @@
--TEST--
Updating a dev package to its latest ref should pick up new dependencies
--COMPOSER--
{
"repositories": [
{
"type": "package",
"package": [
{
"name": "a/devpackage", "version": "dev-master",
"source": { "reference": "newref", "url": "", "type": "git" },
"require": {
"a/dependency": "*"
}
},
{
"name": "a/dependency", "version": "dev-master",
"source": { "reference": "ref", "url": "", "type": "git" },
"require": {}
}
]
}
],
"require": {
"a/devpackage": "dev-master"
},
"minimum-stability": "dev"
}
--INSTALLED--
[
{
"name": "a/devpackage", "version": "dev-master",
"source": { "reference": "oldref", "url": "", "type": "git" },
"require": {}
}
]
--RUN--
update
--EXPECT--
Installing a/dependency (dev-master ref)
Updating a/devpackage (dev-master oldref) to a/devpackage (dev-master newref)

@ -0,0 +1,43 @@
--TEST--
Installing locked dev packages should remove old dependencies
--COMPOSER--
{
"require": {
"a/devpackage": "dev-master"
},
"minimum-stability": "dev"
}
--LOCK--
{
"packages": [
{
"name": "a/devpackage", "version": "dev-master",
"source": { "reference": "newref", "url": "", "type": "git" },
"require": {}
}
],
"packages-dev": null,
"aliases": [],
"minimum-stability": "dev",
"stability-flags": []
}
--INSTALLED--
[
{
"name": "a/devpackage", "version": "dev-master",
"source": { "reference": "oldref", "url": "", "type": "git" },
"require": {
"a/dependency": "*"
}
},
{
"name": "a/dependency", "version": "dev-master",
"source": { "reference": "ref", "url": "", "type": "git" },
"require": {}
}
]
--RUN--
install
--EXPECT--
Uninstalling a/dependency (dev-master ref)
Updating a/devpackage (dev-master oldref) to a/devpackage (dev-master newref)
Loading…
Cancel
Save