summaryrefslogtreecommitdiff
path: root/apt-pkg
diff options
context:
space:
mode:
authorJulian Andres Klode <jak@debian.org>2025-05-19 14:17:23 +0200
committerJulian Andres Klode <jak@debian.org>2025-05-19 15:20:09 +0000
commit7724d170751b3dc1717ba7a08881437cf7151996 (patch)
tree9f76923fbd5b856904a414fa615116940d2afff6 /apt-pkg
parent2ddc16b9f8edff1329f5ac3e46b0c0cf9bde661d (diff)
Introduce apt why, apt why-not
These are implemented somewhat differently from aptitudes why and why-not commands: They produce the actual solver trace for why a particular decision has been taken. For the why-not case, we need to explicitly discover our specified package, as if nothing else depends on it in our graph, it would otherwise always be undiscovered and conflicts not detected (see e.g. level-3 in the test).
Diffstat (limited to 'apt-pkg')
-rw-r--r--apt-pkg/solver3.cc20
-rw-r--r--apt-pkg/solver3.h3
2 files changed, 23 insertions, 0 deletions
diff --git a/apt-pkg/solver3.cc b/apt-pkg/solver3.cc
index 620156ac3..abc0af314 100644
--- a/apt-pkg/solver3.cc
+++ b/apt-pkg/solver3.cc
@@ -1267,3 +1267,23 @@ bool APT::Solver::ToDepCache(pkgDepCache &depcache) const
}
return true;
}
+
+// Command-line
+std::string APT::Solver::InternalCliWhy(pkgDepCache &cache, pkgCache::PkgIterator pkg, bool decision)
+{
+ APT::Solver solver(cache.GetCache(), cache.GetPolicy(), EDSP::Request::Flags(0));
+ // In case nothing has a positive dependency on pkg it may not actually be discovered in a `why-not`
+ // scenario, so make sure we discover it explicitly.
+ solver.Discover(Var(pkg));
+ if (not solver.FromDepCache(cache) || not solver.Solve())
+ return "";
+ std::unordered_set<Var> seen;
+ std::string buf;
+ if (solver[Var(pkg)].decision == Decision::NONE)
+ return strprintf(buf, "%s is undecided\n", pkg.FullName().c_str()), buf;
+ if (decision && solver[Var(pkg)].decision != Decision::MUST)
+ return strprintf(buf, "%s is not actually marked for install\n", pkg.FullName().c_str()), buf;
+ if (not decision && solver[Var(pkg)].decision == Decision::MUST)
+ return strprintf(buf, "%s is actually marked for install\n", pkg.FullName().c_str()), buf;
+ return solver.LongWhyStr(Var(pkg), decision, solver[Var(pkg)].reason, "", seen);
+}
diff --git a/apt-pkg/solver3.h b/apt-pkg/solver3.h
index 6810df426..43f6ec3a7 100644
--- a/apt-pkg/solver3.h
+++ b/apt-pkg/solver3.h
@@ -316,6 +316,9 @@ class Solver
* \param seen A set of seen objects such that the output does not repeat itself (not for safety, it is acyclic)
*/
std::string LongWhyStr(Var var, bool decision, const Clause *rclause, std::string prefix, std::unordered_set<Var> &seen) const;
+
+ // \brief Temporary internal API with external linkage for the `apt why` and `apt why-not` commands.
+ APT_PUBLIC static std::string InternalCliWhy(pkgDepCache &depcache, pkgCache::PkgIterator Pkg, bool decision);
};
}; // namespace APT