]> git.saurik.com Git - apt.git/commitdiff
edsp: warn if unexpected stanzas appear in the solution
authorDavid Kalnischkies <david@kalnischkies.de>
Thu, 12 May 2016 14:21:10 +0000 (16:21 +0200)
committerDavid Kalnischkies <david@kalnischkies.de>
Thu, 12 May 2016 14:21:10 +0000 (16:21 +0200)
Unexpected are for examples removal requests for versions which aren't
installed, installations of already installed versions & requests to
install and remove a package at the same time.

apt-pkg/edsp.cc
doc/external-dependency-solver-protocol.txt
test/integration/test-external-dependency-solver-protocol

index e54f0d1df0d659af0bbfba74c148b5943221c913..8414c6a23058a17c6272fb07e99b2c6a86a6f43d 100644 (file)
@@ -320,6 +320,7 @@ bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progres
        pkgTagFile response(&in, 100);
        pkgTagSection section;
 
+       std::set<decltype(Cache.PkgBegin()->ID)> seenOnce;
        while (response.Step(section) == true) {
                std::string type;
                if (section.Exists("Install") == true)
@@ -362,18 +363,29 @@ bool EDSP::ReadResponse(int const input, pkgDepCache &Cache, OpProgress *Progres
                }
 
                pkgCache::VerIterator Ver(Cache.GetCache(), Cache.GetCache().VerP + VerIdx[id]);
-               Cache.SetCandidateVersion(Ver);
-               if (type == "Install")
-               {
-                       pkgCache::PkgIterator const P = Ver.ParentPkg();
-                       if (Cache[P].Mode != pkgDepCache::ModeInstall)
-                               Cache.MarkInstall(P, false, 0, false);
-               }
-               else if (type == "Remove")
-                       Cache.MarkDelete(Ver.ParentPkg(), false);
-               else if (type == "Autoremove") {
-                       Cache[Ver.ParentPkg()].Marked = false;
-                       Cache[Ver.ParentPkg()].Garbage = true;
+               auto const Pkg = Ver.ParentPkg();
+               if (type == "Autoremove") {
+                       Cache[Pkg].Marked = false;
+                       Cache[Pkg].Garbage = true;
+               } else if (seenOnce.emplace(Pkg->ID).second == false) {
+                       _error->Warning("Ignoring %s stanza received for package %s which already had a previous stanza effecting it!", type.c_str(), Pkg.FullName(false).c_str());
+               } else if (type == "Install") {
+                       if (Pkg.CurrentVer() == Ver) {
+                               _error->Warning("Ignoring Install stanza received for version %s of package %s which is already installed!",
+                                     Ver.VerStr(), Pkg.FullName(false).c_str());
+                       } else {
+                               Cache.SetCandidateVersion(Ver);
+                               Cache.MarkInstall(Pkg, false, 0, false);
+                       }
+               } else if (type == "Remove") {
+                       if (Pkg->CurrentVer == 0)
+                               _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't installed!",
+                                     Ver.VerStr(), Pkg.FullName(false).c_str());
+                       else if (Pkg.CurrentVer() != Ver)
+                               _error->Warning("Ignoring Remove stanza received for version %s of package %s which isn't the installed version %s!",
+                                     Ver.VerStr(), Pkg.FullName(false).c_str(), Pkg.CurrentVer().VerStr());
+                       else
+                               Cache.MarkDelete(Ver.ParentPkg(), false);
                }
        }
        return true;
index d914db30930008b1a98c92711e674c974176f687..9b9073346c08c3dd1324de2f58b58d826846f461 100644 (file)
@@ -289,10 +289,15 @@ this protocol makes no assumption on the fact that a subsequent
 invocation of an Autoremove action will actually remove the very same
 packages indicated by Autoremove stanzas in the former solution.
 
-The package identifiers of install, remove and autoremove stanzas from a single
-solution are unique. That is, a package identifier does not occur more than
-once in the solution. Every package identifier is only associated with a single
-action (either install, remove or autoremove).
+A package can't be installed in multiple versions at the same time, so
+for each package there can at most one version be selected either for
+installation or removal. This especially means that a solver is neither
+allowed to represent package upgrades as a remove of the installed
+version and the installation of another (the remove is implicit and must
+be omitted from the solution) nor is it supported to revert previous
+actions in the solution with later actions. APT is allowed to show
+warnings and might even misbehave in earlier versions if a solver is
+violating this assumption.
 
 In terms of expressivity, install and remove stanzas can carry one
 single field each, as APT-IDs are enough to pinpoint packages to be
index 32c5fc3540fe7ca3e612d2b0a56a32d8450c12e8..e22684ec572d1075be0e1432f3039da2cebfec0b 100755 (executable)
@@ -113,7 +113,7 @@ The following package was automatically installed and is no longer required:
 Use '$AUTOREMOVE' to remove it.
 The following packages will be REMOVED:
   cool* somestuff*
-0 upgraded, 0 newly installed, 2 to remove and 0 not upgraded.
+0 upgraded, 0 newly installed, 2 to remove and 1 not upgraded.
 Purg somestuff [1]
 Purg cool [1]" aptget purge --solver apt cool -s
 
@@ -194,3 +194,53 @@ Priority: optional
 Section: other
 APT-Pin: 100
 ' aptinternalsolver scenario stuff
+
+cat > rootdir/usr/lib/apt/solvers/explicitremove << EOF
+#!/bin/sh
+set -e
+while read line; do
+       if [ "APT-ID" = "\${line%:*}" ]; then
+               cat << APT
+Install: \${line#*:}
+
+Remove: \${line#*:}
+
+APT
+       fi
+done
+EOF
+chmod +x rootdir/usr/lib/apt/solvers/explicitremove
+testfailure apt full-upgrade -s --solver explicitremove
+testsuccess grep 'had a previous stanza' rootdir/tmp/testfailure.output
+
+cat > rootdir/usr/lib/apt/solvers/removeall << EOF
+#!/bin/sh
+set -e
+while read line; do
+       if [ "APT-ID" = "\${line%:*}" ]; then
+               cat << APT
+Remove: \${line#*:}
+
+APT
+       fi
+done
+EOF
+chmod +x rootdir/usr/lib/apt/solvers/removeall
+testwarning apt full-upgrade -s --solver removeall
+testsuccess grep "which isn't installed!" rootdir/tmp/testwarning.output
+
+cat > rootdir/usr/lib/apt/solvers/installall << EOF
+#!/bin/sh
+set -e
+while read line; do
+       if [ "APT-ID" = "\${line%:*}" ]; then
+               cat << APT
+Install: \${line#*:}
+
+APT
+       fi
+done
+EOF
+chmod +x rootdir/usr/lib/apt/solvers/installall
+testfailure apt full-upgrade -s --solver installall
+testsuccess grep "is already installed!" rootdir/tmp/testfailure.output