|
@@ -37,32 +37,42 @@ class Transaction
|
|
|
|
|
|
public function getOperations()
|
|
|
{
|
|
|
- $installMeansUpdateMap = array();
|
|
|
+ $installMeansUpdateMap = $this->findUpdates();
|
|
|
|
|
|
- foreach ($this->installedMap as $packageId => $void) {
|
|
|
- if ($this->decisions->undecided($packageId)) {
|
|
|
- $this->decisions->decide(-$packageId, 1, null);
|
|
|
- }
|
|
|
- }
|
|
|
+ $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
|
|
|
- if ($literal <= 0 && isset($this->installedMap[$package->getId()])) {
|
|
|
- $updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
|
|
|
+ // wanted & installed || !wanted & !installed
|
|
|
+ if (($literal > 0) == (isset($this->installedMap[$package->getId()]))) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- $literals = array($package->getId());
|
|
|
+ if ($literal > 0) {
|
|
|
+ if (isset($installMeansUpdateMap[abs($literal)]) && !$package instanceof AliasPackage) {
|
|
|
|
|
|
- foreach ($updates as $update) {
|
|
|
- $literals[] = $update->getId();
|
|
|
- }
|
|
|
+ $source = $installMeansUpdateMap[abs($literal)];
|
|
|
|
|
|
- foreach ($literals as $updateLiteral) {
|
|
|
- if ($updateLiteral !== $literal) {
|
|
|
- $installMeansUpdateMap[abs($updateLiteral)] = $package;
|
|
|
- }
|
|
|
+ $updateMap[$package->getId()] = array(
|
|
|
+ 'package' => $package,
|
|
|
+ 'source' => $source,
|
|
|
+ 'reason' => $reason,
|
|
|
+ );
|
|
|
+
|
|
|
+ // avoid updates to one package from multiple origins
|
|
|
+ unset($installMeansUpdateMap[abs($literal)]);
|
|
|
+ $ignoreRemove[$source->getId()] = true;
|
|
|
+ } else {
|
|
|
+ $installMap[$package->getId()] = array(
|
|
|
+ 'package' => $package,
|
|
|
+ 'reason' => $reason,
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -71,47 +81,127 @@ class Transaction
|
|
|
$literal = $decision[Decisions::DECISION_LITERAL];
|
|
|
$package = $this->pool->literalToPackage($literal);
|
|
|
|
|
|
- // wanted & installed || !wanted & !installed
|
|
|
- if (($literal > 0) == (isset($this->installedMap[$package->getId()]))) {
|
|
|
- continue;
|
|
|
+ if ($literal <= 0 &&
|
|
|
+ isset($this->installedMap[$package->getId()]) &&
|
|
|
+ !isset($ignoreRemove[$package->getId()])) {
|
|
|
+ $uninstallMap[$package->getId()] = 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->getId();
|
|
|
+
|
|
|
+ if (!isset($visited[$packageId])) {
|
|
|
+ array_push($queue, $package);
|
|
|
|
|
|
- if ($literal > 0) {
|
|
|
if ($package instanceof AliasPackage) {
|
|
|
- $this->markAliasInstalled($package, $decision[Decisions::DECISION_REASON]);
|
|
|
- continue;
|
|
|
+ array_push($queue, $package->getAliasOf());
|
|
|
+ } else {
|
|
|
+ foreach ($package->getRequires() as $link) {
|
|
|
+ $possibleRequires = $this->pool->whatProvides($link->getTarget(), $link->getConstraint());
|
|
|
+
|
|
|
+ foreach ($possibleRequires as $require) {
|
|
|
+ array_push($queue, $require);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (isset($installMeansUpdateMap[abs($literal)])) {
|
|
|
+ $visited[$package->getId()] = 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]);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $source = $installMeansUpdateMap[abs($literal)];
|
|
|
+ foreach ($uninstallMap as $uninstall) {
|
|
|
+ $this->uninstall($uninstall['package'], $uninstall['reason']);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- $this->update($source, $package, $decision[Decisions::DECISION_REASON]);
|
|
|
+ protected function findRootPackages($installMap, $updateMap)
|
|
|
+ {
|
|
|
+ $packages = $installMap + $updateMap;
|
|
|
+ $roots = $packages;
|
|
|
|
|
|
- // avoid updates to one package from multiple origins
|
|
|
- unset($installMeansUpdateMap[abs($literal)]);
|
|
|
- $ignoreRemove[$source->getId()] = true;
|
|
|
- } else {
|
|
|
- $this->install($package, $decision[Decisions::DECISION_REASON]);
|
|
|
+ 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) {
|
|
|
+ unset($roots[$require->getId()]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ return $roots;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected function findUpdates()
|
|
|
+ {
|
|
|
+ $installMeansUpdateMap = array();
|
|
|
+
|
|
|
foreach ($this->decisions as $i => $decision) {
|
|
|
$literal = $decision[Decisions::DECISION_LITERAL];
|
|
|
$package = $this->pool->literalToPackage($literal);
|
|
|
|
|
|
- // wanted & installed || !wanted & !installed
|
|
|
- if (($literal > 0) == (isset($this->installedMap[$package->getId()]))) {
|
|
|
- continue;
|
|
|
- }
|
|
|
+ // !wanted & installed
|
|
|
+ if ($literal <= 0 && isset($this->installedMap[$package->getId()])) {
|
|
|
+ $updates = $this->policy->findUpdatePackages($this->pool, $this->installedMap, $package);
|
|
|
+
|
|
|
+ $literals = array($package->getId());
|
|
|
|
|
|
- if ($literal <= 0 && !isset($ignoreRemove[$package->getId()])) {
|
|
|
- $this->uninstall($package, $decision[Decisions::DECISION_REASON]);
|
|
|
+ foreach ($updates as $update) {
|
|
|
+ $literals[] = $update->getId();
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach ($literals as $updateLiteral) {
|
|
|
+ if ($updateLiteral !== $literal) {
|
|
|
+ $installMeansUpdateMap[abs($updateLiteral)] = $package;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return $this->transaction;
|
|
|
+ return $installMeansUpdateMap;
|
|
|
}
|
|
|
|
|
|
protected function install($package, $reason)
|