2017-09-10 20:36:59 +00:00
|
|
|
#include "command.hh"
|
|
|
|
#include "store-api.hh"
|
|
|
|
#include "progress-bar.hh"
|
|
|
|
#include "fs-accessor.hh"
|
2018-07-03 10:49:12 +00:00
|
|
|
#include "shared.hh"
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
#include <queue>
|
|
|
|
|
2017-09-10 20:36:59 +00:00
|
|
|
using namespace nix;
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
static std::string hilite(const std::string & s, size_t pos, size_t len,
|
|
|
|
const std::string & colour = ANSI_RED)
|
2017-09-10 20:36:59 +00:00
|
|
|
{
|
|
|
|
return
|
|
|
|
std::string(s, 0, pos)
|
2017-09-11 14:21:27 +00:00
|
|
|
+ colour
|
2017-09-10 20:36:59 +00:00
|
|
|
+ std::string(s, pos, len)
|
|
|
|
+ ANSI_NORMAL
|
|
|
|
+ std::string(s, pos + len);
|
|
|
|
}
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
static std::string filterPrintable(const std::string & s)
|
|
|
|
{
|
|
|
|
std::string res;
|
|
|
|
for (char c : s)
|
|
|
|
res += isprint(c) ? c : '.';
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-09-10 20:36:59 +00:00
|
|
|
struct CmdWhyDepends : SourceExprCommand
|
|
|
|
{
|
|
|
|
std::string _package, _dependency;
|
2017-09-11 14:21:27 +00:00
|
|
|
bool all = false;
|
2022-01-19 13:15:45 +00:00
|
|
|
bool precise = false;
|
2017-09-10 20:36:59 +00:00
|
|
|
|
|
|
|
CmdWhyDepends()
|
|
|
|
{
|
2021-12-20 18:57:48 +00:00
|
|
|
expectArgs({
|
|
|
|
.label = "package",
|
|
|
|
.handler = {&_package},
|
|
|
|
.completer = {[&](size_t, std::string_view prefix) {
|
|
|
|
completeInstallable(prefix);
|
|
|
|
}}
|
|
|
|
});
|
|
|
|
|
|
|
|
expectArgs({
|
|
|
|
.label = "dependency",
|
|
|
|
.handler = {&_dependency},
|
|
|
|
.completer = {[&](size_t, std::string_view prefix) {
|
|
|
|
completeInstallable(prefix);
|
|
|
|
}}
|
|
|
|
});
|
2017-09-11 14:21:27 +00:00
|
|
|
|
2020-05-04 20:40:19 +00:00
|
|
|
addFlag({
|
|
|
|
.longName = "all",
|
|
|
|
.shortName = 'a',
|
2021-01-13 13:18:04 +00:00
|
|
|
.description = "Show all edges in the dependency graph leading from *package* to *dependency*, rather than just a shortest path.",
|
2020-05-04 20:40:19 +00:00
|
|
|
.handler = {&all, true},
|
|
|
|
});
|
2022-01-19 13:15:45 +00:00
|
|
|
|
|
|
|
addFlag({
|
|
|
|
.longName = "precise",
|
2022-01-21 08:52:40 +00:00
|
|
|
.description = "For each edge in the dependency graph, show the files in the parent that cause the dependency.",
|
2022-01-19 13:15:45 +00:00
|
|
|
.handler = {&precise, true},
|
|
|
|
});
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string description() override
|
|
|
|
{
|
|
|
|
return "show why a package has another package in its closure";
|
|
|
|
}
|
|
|
|
|
2020-12-09 19:33:53 +00:00
|
|
|
std::string doc() override
|
2017-09-10 20:36:59 +00:00
|
|
|
{
|
2020-12-09 19:33:53 +00:00
|
|
|
return
|
|
|
|
#include "why-depends.md"
|
|
|
|
;
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
|
2020-05-05 13:18:23 +00:00
|
|
|
Category category() override { return catSecondary; }
|
|
|
|
|
2017-09-10 20:36:59 +00:00
|
|
|
void run(ref<Store> store) override
|
|
|
|
{
|
2019-04-08 14:11:17 +00:00
|
|
|
auto package = parseInstallable(store, _package);
|
2022-03-02 12:54:08 +00:00
|
|
|
auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
|
2022-11-23 17:06:47 +00:00
|
|
|
|
|
|
|
/* We don't need to build `dependency`. We try to get the store
|
|
|
|
* path if it's already known, and if not, then it's not a dependency.
|
|
|
|
*
|
|
|
|
* Why? If `package` does depends on `dependency`, then getting the
|
|
|
|
* store path of `package` above necessitated having the store path
|
|
|
|
* of `dependency`. The contrapositive is, if the store path of
|
|
|
|
* `dependency` is not already known at this point (i.e. it's a CA
|
|
|
|
* derivation which hasn't been built), then `package` did not need it
|
|
|
|
* to build.
|
|
|
|
*/
|
2019-04-08 14:11:17 +00:00
|
|
|
auto dependency = parseInstallable(store, _dependency);
|
2022-11-23 16:39:50 +00:00
|
|
|
auto derivedDependency = dependency->toDerivedPath();
|
|
|
|
auto optDependencyPath = std::visit(overloaded {
|
|
|
|
[](const DerivedPath::Opaque & nodrv) -> std::optional<StorePath> {
|
|
|
|
return { nodrv.path };
|
|
|
|
},
|
|
|
|
[&](const DerivedPath::Built & hasdrv) -> std::optional<StorePath> {
|
|
|
|
if (hasdrv.outputs.size() != 1) {
|
|
|
|
throw Error("argument '%s' should evaluate to one store path", dependency->what());
|
|
|
|
}
|
|
|
|
auto outputMap = store->queryPartialDerivationOutputMap(hasdrv.drvPath);
|
|
|
|
auto maybePath = outputMap.find(*hasdrv.outputs.begin());
|
|
|
|
if (maybePath == outputMap.end()) {
|
|
|
|
throw Error("unexpected end of iterator");
|
|
|
|
}
|
|
|
|
return maybePath->second;
|
|
|
|
},
|
|
|
|
}, derivedDependency.raw());
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePathSet closure;
|
2017-09-10 20:36:59 +00:00
|
|
|
store->computeFSClosure({packagePath}, closure, false, false);
|
|
|
|
|
2022-11-23 16:39:50 +00:00
|
|
|
if (!optDependencyPath.has_value() || !closure.count(*optDependencyPath)) {
|
|
|
|
printError("'%s' does not depend on '%s'", package->what(), dependency->what());
|
2017-09-10 20:36:59 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-11-23 16:39:50 +00:00
|
|
|
auto dependencyPath = *optDependencyPath;
|
|
|
|
auto dependencyPathHash = dependencyPath.hashPart();
|
|
|
|
|
2017-09-10 20:36:59 +00:00
|
|
|
stopProgressBar(); // FIXME
|
|
|
|
|
|
|
|
auto accessor = store->getFSAccessor();
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
auto const inf = std::numeric_limits<size_t>::max();
|
|
|
|
|
|
|
|
struct Node
|
|
|
|
{
|
2019-12-05 18:11:09 +00:00
|
|
|
StorePath path;
|
|
|
|
StorePathSet refs;
|
|
|
|
StorePathSet rrefs;
|
2017-09-11 14:21:27 +00:00
|
|
|
size_t dist = inf;
|
|
|
|
Node * prev = nullptr;
|
|
|
|
bool queued = false;
|
|
|
|
bool visited = false;
|
|
|
|
};
|
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
std::map<StorePath, Node> graph;
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
for (auto & path : closure)
|
2020-07-15 19:08:46 +00:00
|
|
|
graph.emplace(path, Node {
|
|
|
|
.path = path,
|
|
|
|
.refs = store->queryPathInfo(path)->references,
|
|
|
|
.dist = path == dependencyPath ? 0 : inf
|
|
|
|
});
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
// Transpose the graph.
|
|
|
|
for (auto & node : graph)
|
|
|
|
for (auto & ref : node.second.refs)
|
2020-06-16 20:20:18 +00:00
|
|
|
graph.find(ref)->second.rrefs.insert(node.first);
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
/* Run Dijkstra's shortest path algorithm to get the distance
|
|
|
|
of every path in the closure to 'dependency'. */
|
|
|
|
std::priority_queue<Node *> queue;
|
|
|
|
|
|
|
|
queue.push(&graph.at(dependencyPath));
|
|
|
|
|
|
|
|
while (!queue.empty()) {
|
|
|
|
auto & node = *queue.top();
|
|
|
|
queue.pop();
|
|
|
|
|
|
|
|
for (auto & rref : node.rrefs) {
|
|
|
|
auto & node2 = graph.at(rref);
|
|
|
|
auto dist = node.dist + 1;
|
|
|
|
if (dist < node2.dist) {
|
|
|
|
node2.dist = dist;
|
|
|
|
node2.prev = &node;
|
|
|
|
if (!node2.queued) {
|
|
|
|
node2.queued = true;
|
|
|
|
queue.push(&node2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
/* Print the subgraph of nodes that have 'dependency' in their
|
|
|
|
closure (i.e., that have a non-infinite distance to
|
|
|
|
'dependency'). Print every edge on a path between `package`
|
|
|
|
and `dependency`. */
|
2022-02-25 15:00:00 +00:00
|
|
|
std::function<void(Node &, const std::string &, const std::string &)> printNode;
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
struct BailOut { };
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2022-02-25 15:00:00 +00:00
|
|
|
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
|
2019-12-05 18:11:09 +00:00
|
|
|
auto pathS = store->printStorePath(node.path);
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
assert(node.dist != inf);
|
2022-01-19 13:15:45 +00:00
|
|
|
if (precise) {
|
|
|
|
logger->cout("%s%s%s%s" ANSI_NORMAL,
|
|
|
|
firstPad,
|
|
|
|
node.visited ? "\e[38;5;244m" : "",
|
|
|
|
firstPad != "" ? "→ " : "",
|
|
|
|
pathS);
|
|
|
|
}
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-14 09:17:32 +00:00
|
|
|
if (node.path == dependencyPath && !all
|
|
|
|
&& packagePath != dependencyPath)
|
|
|
|
throw BailOut();
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
if (node.visited) return;
|
nix/why-depends: fix output when not using `--precise`
On Nix 2.6 the output of `nix why-depends --all` seems to be somewhat
off:
$ nix why-depends /nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv /nix/store/srn5jbs1q30jpybdmxqrwskyny659qgc-nix-2.6.drv --derivation --extra-experimental-features nix-command --all
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
│ └───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
Please note that `[...]-system-units.drv` is supposed to be a direct
child of `[...]-etc.drv`.
The reason for that is that each new level printed by `printNode` is
four spaces off in comparison to `nix why-depends --precise` because the
recursive `printNode()` only prints the path and not the `tree*`-chars in
the case of `--precise` and in this format the path is four spaces further
indented, i.e. on a newline, but on the same level as the path's children, i.e.
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/: …1-p8.drv",["out"]),("/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv",["out"]),("/nix/store/…
→ /nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
As you can see `[...]-etc.drv` is a direct child of the root, but four
spaces indented. This logic was directly applied to the code-path with
`precise=false` which resulted in `tree*` being printed four spaces too
deep.
In case of no `--precise`, `hits[hash]` is empty and the path itself
should be printed rather than hits using the same logic as for `hits[hash]`.
With this fix, the output looks correct now:
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
├───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
2022-02-10 13:12:06 +00:00
|
|
|
if (precise) node.visited = true;
|
2017-09-10 20:36:59 +00:00
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
/* Sort the references by distance to `dependency` to
|
|
|
|
ensure that the shortest path is printed first. */
|
|
|
|
std::multimap<size_t, Node *> refs;
|
|
|
|
std::set<std::string> hashes;
|
|
|
|
|
|
|
|
for (auto & ref : node.refs) {
|
2017-09-14 09:17:32 +00:00
|
|
|
if (ref == node.path && packagePath != dependencyPath) continue;
|
2017-09-11 14:21:27 +00:00
|
|
|
auto & node2 = graph.at(ref);
|
|
|
|
if (node2.dist == inf) continue;
|
|
|
|
refs.emplace(node2.dist, &node2);
|
2020-06-16 12:16:39 +00:00
|
|
|
hashes.insert(std::string(node2.path.hashPart()));
|
2017-09-11 14:21:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* For each reference, find the files and symlinks that
|
|
|
|
contain the reference. */
|
|
|
|
std::map<std::string, Strings> hits;
|
|
|
|
|
|
|
|
std::function<void(const Path &)> visitPath;
|
|
|
|
|
|
|
|
visitPath = [&](const Path & p) {
|
2017-09-10 20:36:59 +00:00
|
|
|
auto st = accessor->stat(p);
|
|
|
|
|
2019-12-05 18:11:09 +00:00
|
|
|
auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
auto getColour = [&](const std::string & hash) {
|
|
|
|
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
|
|
|
|
};
|
2017-09-10 20:36:59 +00:00
|
|
|
|
|
|
|
if (st.type == FSAccessor::Type::tDirectory) {
|
|
|
|
auto names = accessor->readDirectory(p);
|
|
|
|
for (auto & name : names)
|
2017-09-11 14:21:27 +00:00
|
|
|
visitPath(p + "/" + name);
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
else if (st.type == FSAccessor::Type::tRegular) {
|
|
|
|
auto contents = accessor->readFile(p);
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
for (auto & hash : hashes) {
|
|
|
|
auto pos = contents.find(hash);
|
|
|
|
if (pos != std::string::npos) {
|
2017-09-25 14:59:16 +00:00
|
|
|
size_t margin = 32;
|
2017-09-11 14:21:27 +00:00
|
|
|
auto pos2 = pos >= margin ? pos - margin : 0;
|
|
|
|
hits[hash].emplace_back(fmt("%s: …%s…\n",
|
|
|
|
p2,
|
|
|
|
hilite(filterPrintable(
|
|
|
|
std::string(contents, pos2, pos - pos2 + hash.size() + margin)),
|
2020-06-16 12:16:39 +00:00
|
|
|
pos - pos2, StorePath::HashLen,
|
2017-09-11 14:21:27 +00:00
|
|
|
getColour(hash))));
|
|
|
|
}
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (st.type == FSAccessor::Type::tSymlink) {
|
|
|
|
auto target = accessor->readLink(p);
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
for (auto & hash : hashes) {
|
|
|
|
auto pos = target.find(hash);
|
|
|
|
if (pos != std::string::npos)
|
|
|
|
hits[hash].emplace_back(fmt("%s -> %s\n", p2,
|
2020-06-16 12:16:39 +00:00
|
|
|
hilite(target, pos, StorePath::HashLen, getColour(hash))));
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-09-14 11:22:32 +00:00
|
|
|
// FIXME: should use scanForReferences().
|
|
|
|
|
2022-01-19 13:15:45 +00:00
|
|
|
if (precise) visitPath(pathS);
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
for (auto & ref : refs) {
|
2020-06-16 12:16:39 +00:00
|
|
|
std::string hash(ref.second->path.hashPart());
|
2017-09-11 14:21:27 +00:00
|
|
|
|
|
|
|
bool last = all ? ref == *refs.rbegin() : true;
|
|
|
|
|
|
|
|
for (auto & hit : hits[hash]) {
|
|
|
|
bool first = hit == *hits[hash].begin();
|
2017-09-25 14:59:16 +00:00
|
|
|
std::cout << tailPad
|
2017-09-11 14:21:27 +00:00
|
|
|
<< (first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine))
|
|
|
|
<< hit;
|
|
|
|
if (!all) break;
|
|
|
|
}
|
|
|
|
|
nix/why-depends: fix output when not using `--precise`
On Nix 2.6 the output of `nix why-depends --all` seems to be somewhat
off:
$ nix why-depends /nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv /nix/store/srn5jbs1q30jpybdmxqrwskyny659qgc-nix-2.6.drv --derivation --extra-experimental-features nix-command --all
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
│ └───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
Please note that `[...]-system-units.drv` is supposed to be a direct
child of `[...]-etc.drv`.
The reason for that is that each new level printed by `printNode` is
four spaces off in comparison to `nix why-depends --precise` because the
recursive `printNode()` only prints the path and not the `tree*`-chars in
the case of `--precise` and in this format the path is four spaces further
indented, i.e. on a newline, but on the same level as the path's children, i.e.
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/: …1-p8.drv",["out"]),("/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv",["out"]),("/nix/store/…
→ /nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
As you can see `[...]-etc.drv` is a direct child of the root, but four
spaces indented. This logic was directly applied to the code-path with
`precise=false` which resulted in `tree*` being printed four spaces too
deep.
In case of no `--precise`, `hits[hash]` is empty and the path itself
should be printed rather than hits using the same logic as for `hits[hash]`.
With this fix, the output looks correct now:
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
├───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
2022-02-10 13:12:06 +00:00
|
|
|
if (!precise) {
|
|
|
|
auto pathS = store->printStorePath(ref.second->path);
|
|
|
|
logger->cout("%s%s%s%s" ANSI_NORMAL,
|
|
|
|
firstPad,
|
|
|
|
ref.second->visited ? "\e[38;5;244m" : "",
|
|
|
|
last ? treeLast : treeConn,
|
|
|
|
pathS);
|
|
|
|
node.visited = true;
|
|
|
|
}
|
|
|
|
|
2017-09-11 14:21:27 +00:00
|
|
|
printNode(*ref.second,
|
|
|
|
tailPad + (last ? treeNull : treeLine),
|
|
|
|
tailPad + (last ? treeNull : treeLine));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-14 12:41:45 +00:00
|
|
|
RunPager pager;
|
2017-09-11 14:21:27 +00:00
|
|
|
try {
|
nix/why-depends: fix output when not using `--precise`
On Nix 2.6 the output of `nix why-depends --all` seems to be somewhat
off:
$ nix why-depends /nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv /nix/store/srn5jbs1q30jpybdmxqrwskyny659qgc-nix-2.6.drv --derivation --extra-experimental-features nix-command --all
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
│ └───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
Please note that `[...]-system-units.drv` is supposed to be a direct
child of `[...]-etc.drv`.
The reason for that is that each new level printed by `printNode` is
four spaces off in comparison to `nix why-depends --precise` because the
recursive `printNode()` only prints the path and not the `tree*`-chars in
the case of `--precise` and in this format the path is four spaces further
indented, i.e. on a newline, but on the same level as the path's children, i.e.
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/: …1-p8.drv",["out"]),("/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv",["out"]),("/nix/store/…
→ /nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
As you can see `[...]-etc.drv` is a direct child of the root, but four
spaces indented. This logic was directly applied to the code-path with
`precise=false` which resulted in `tree*` being printed four spaces too
deep.
In case of no `--precise`, `hits[hash]` is empty and the path itself
should be printed rather than hits using the same logic as for `hits[hash]`.
With this fix, the output looks correct now:
/nix/store/kn47hayxab8gc01jhr98dwyywbx561aq-nixos-system-roflmayr-21.11.20220207.6c202a9.drv
└───/nix/store/g8bpgfjhh5vxrdq0w6r6s64f9kkm9z6c-etc.drv
├───/nix/store/hm0jmhp8shbf3cl846a685nv4f5cp3fy-nspawn-inst.drv
| [...]
└───/nix/store/2d6q3ygiim9ijl5d4h0qqx6vnjgxywyr-system-units.drv
└───/nix/store/dil014y1b8qyjhhhf5fpaah5fzdf0bzs-unit-systemd-nspawn-hydra.service.drv
└───/nix/store/a9r72wwx8qrxyp7hjydyg0gsrwnn26zb-activate.drv
└───/nix/store/99hlc7i4gl77wq087lbhag4hkf3kvssj-nixos-system-hydra-21.11pre-git.drv
2022-02-10 13:12:06 +00:00
|
|
|
if (!precise) {
|
|
|
|
logger->cout("%s", store->printStorePath(graph.at(packagePath).path));
|
|
|
|
}
|
2017-09-11 14:21:27 +00:00
|
|
|
printNode(graph.at(packagePath), "", "");
|
|
|
|
} catch (BailOut & ) { }
|
2017-09-10 20:36:59 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-06 11:36:55 +00:00
|
|
|
static auto rCmdWhyDepends = registerCommand<CmdWhyDepends>("why-depends");
|