2017-09-10 23:36:59 +03:00
|
|
|
#include "command.hh"
|
|
|
|
#include "store-api.hh"
|
|
|
|
#include "progress-bar.hh"
|
|
|
|
#include "fs-accessor.hh"
|
2018-07-03 13:49:12 +03:00
|
|
|
#include "shared.hh"
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
#include <queue>
|
|
|
|
|
2017-09-10 23:36:59 +03:00
|
|
|
using namespace nix;
|
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
static std::string hilite(const std::string & s, size_t pos, size_t len,
|
|
|
|
const std::string & colour = ANSI_RED)
|
2017-09-10 23:36:59 +03:00
|
|
|
{
|
|
|
|
return
|
|
|
|
std::string(s, 0, pos)
|
2017-09-11 17:21:27 +03:00
|
|
|
+ colour
|
2017-09-10 23:36:59 +03:00
|
|
|
+ std::string(s, pos, len)
|
|
|
|
+ ANSI_NORMAL
|
|
|
|
+ std::string(s, pos + len);
|
|
|
|
}
|
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
static std::string filterPrintable(const std::string & s)
|
|
|
|
{
|
|
|
|
std::string res;
|
|
|
|
for (char c : s)
|
|
|
|
res += isprint(c) ? c : '.';
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2023-02-05 01:27:17 +02:00
|
|
|
struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
|
2017-09-10 23:36:59 +03:00
|
|
|
{
|
|
|
|
std::string _package, _dependency;
|
2017-09-11 17:21:27 +03:00
|
|
|
bool all = false;
|
2022-01-19 15:15:45 +02:00
|
|
|
bool precise = false;
|
2017-09-10 23:36:59 +03:00
|
|
|
|
|
|
|
CmdWhyDepends()
|
|
|
|
{
|
2021-12-20 20:57:48 +02:00
|
|
|
expectArgs({
|
|
|
|
.label = "package",
|
|
|
|
.handler = {&_package},
|
Overhaul completions, redo #6693 (#8131)
As I complained in
https://github.com/NixOS/nix/pull/6784#issuecomment-1421777030 (a
comment on the wrong PR, sorry again!), #6693 introduced a second
completions mechanism to fix a bug. Having two completion mechanisms
isn't so nice.
As @thufschmitt also pointed out, it was a bummer to go from `FlakeRef`
to `std::string` when collecting flake refs. Now it is `FlakeRefs`
again.
The underlying issue that sought to work around was that completion of
arguments not at the end can still benefit from the information from
latter arguments.
To fix this better, we rip out that change and simply defer all
completion processing until after all the (regular, already-complete)
arguments have been passed.
In addition, I noticed the original completion logic used some global
variables. I do not like global variables, because even if they save
lines of code, they also obfuscate the architecture of the code.
I got rid of them moved them to a new `RootArgs` class, which now has
`parseCmdline` instead of `Args`. The idea is that we have many argument
parsers from subcommands and what-not, but only one root args that owns
the other per actual parsing invocation. The state that was global is
now part of the root args instead.
This did, admittedly, add a bunch of new code. And I do feel bad about
that. So I went and added a lot of API docs to try to at least make the
current state of things clear to the next person.
--
This is needed for RFC 134 (tracking issue #7868). It was very hard to
modularize `Installable` parsing when there were two completion
arguments. I wouldn't go as far as to say it is *easy* now, but at least
it is less hard (and the completions test finally passed).
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-10-23 16:03:11 +03:00
|
|
|
.completer = getCompleteInstallable(),
|
2021-12-20 20:57:48 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
expectArgs({
|
|
|
|
.label = "dependency",
|
|
|
|
.handler = {&_dependency},
|
Overhaul completions, redo #6693 (#8131)
As I complained in
https://github.com/NixOS/nix/pull/6784#issuecomment-1421777030 (a
comment on the wrong PR, sorry again!), #6693 introduced a second
completions mechanism to fix a bug. Having two completion mechanisms
isn't so nice.
As @thufschmitt also pointed out, it was a bummer to go from `FlakeRef`
to `std::string` when collecting flake refs. Now it is `FlakeRefs`
again.
The underlying issue that sought to work around was that completion of
arguments not at the end can still benefit from the information from
latter arguments.
To fix this better, we rip out that change and simply defer all
completion processing until after all the (regular, already-complete)
arguments have been passed.
In addition, I noticed the original completion logic used some global
variables. I do not like global variables, because even if they save
lines of code, they also obfuscate the architecture of the code.
I got rid of them moved them to a new `RootArgs` class, which now has
`parseCmdline` instead of `Args`. The idea is that we have many argument
parsers from subcommands and what-not, but only one root args that owns
the other per actual parsing invocation. The state that was global is
now part of the root args instead.
This did, admittedly, add a bunch of new code. And I do feel bad about
that. So I went and added a lot of API docs to try to at least make the
current state of things clear to the next person.
--
This is needed for RFC 134 (tracking issue #7868). It was very hard to
modularize `Installable` parsing when there were two completion
arguments. I wouldn't go as far as to say it is *easy* now, but at least
it is less hard (and the completions test finally passed).
Co-authored-by: Valentin Gagarin <valentin.gagarin@tweag.io>
2023-10-23 16:03:11 +03:00
|
|
|
.completer = getCompleteInstallable(),
|
2021-12-20 20:57:48 +02:00
|
|
|
});
|
2017-09-11 17:21:27 +03:00
|
|
|
|
2020-05-04 23:40:19 +03:00
|
|
|
addFlag({
|
|
|
|
.longName = "all",
|
|
|
|
.shortName = 'a',
|
2021-01-13 15:18:04 +02:00
|
|
|
.description = "Show all edges in the dependency graph leading from *package* to *dependency*, rather than just a shortest path.",
|
2020-05-04 23:40:19 +03:00
|
|
|
.handler = {&all, true},
|
|
|
|
});
|
2022-01-19 15:15:45 +02:00
|
|
|
|
|
|
|
addFlag({
|
|
|
|
.longName = "precise",
|
2022-01-21 10:52:40 +02:00
|
|
|
.description = "For each edge in the dependency graph, show the files in the parent that cause the dependency.",
|
2022-01-19 15:15:45 +02:00
|
|
|
.handler = {&precise, true},
|
|
|
|
});
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string description() override
|
|
|
|
{
|
|
|
|
return "show why a package has another package in its closure";
|
|
|
|
}
|
|
|
|
|
2020-12-09 21:33:53 +02:00
|
|
|
std::string doc() override
|
2017-09-10 23:36:59 +03:00
|
|
|
{
|
2020-12-09 21:33:53 +02:00
|
|
|
return
|
|
|
|
#include "why-depends.md"
|
|
|
|
;
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
|
2020-05-05 16:18:23 +03:00
|
|
|
Category category() override { return catSecondary; }
|
|
|
|
|
2017-09-10 23:36:59 +03:00
|
|
|
void run(ref<Store> store) override
|
|
|
|
{
|
2019-04-08 17:11:17 +03:00
|
|
|
auto package = parseInstallable(store, _package);
|
2022-03-02 14:54:08 +02:00
|
|
|
auto packagePath = Installable::toStorePath(getEvalStore(), store, Realise::Outputs, operateOn, package);
|
2022-11-23 19:06:47 +02: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 17:11:17 +03:00
|
|
|
auto dependency = parseInstallable(store, _dependency);
|
2023-01-02 18:35:48 +02:00
|
|
|
auto optDependencyPath = [&]() -> std::optional<StorePath> {
|
|
|
|
try {
|
|
|
|
return {Installable::toStorePath(getEvalStore(), store, Realise::Derivation, operateOn, dependency)};
|
|
|
|
} catch (MissingRealisation &) {
|
|
|
|
return std::nullopt;
|
|
|
|
}
|
|
|
|
}();
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePathSet closure;
|
2017-09-10 23:36:59 +03:00
|
|
|
store->computeFSClosure({packagePath}, closure, false, false);
|
|
|
|
|
2023-01-02 18:35:48 +02:00
|
|
|
if (!optDependencyPath.has_value() || !closure.count(*optDependencyPath)) {
|
|
|
|
printError("'%s' does not depend on '%s'", package->what(), dependency->what());
|
2017-09-10 23:36:59 +03:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-01-02 18:35:48 +02:00
|
|
|
auto dependencyPath = *optDependencyPath;
|
|
|
|
auto dependencyPathHash = dependencyPath.hashPart();
|
|
|
|
|
2017-09-10 23:36:59 +03:00
|
|
|
stopProgressBar(); // FIXME
|
|
|
|
|
|
|
|
auto accessor = store->getFSAccessor();
|
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
auto const inf = std::numeric_limits<size_t>::max();
|
|
|
|
|
|
|
|
struct Node
|
|
|
|
{
|
2019-12-05 20:11:09 +02:00
|
|
|
StorePath path;
|
|
|
|
StorePathSet refs;
|
|
|
|
StorePathSet rrefs;
|
2017-09-11 17:21:27 +03:00
|
|
|
size_t dist = inf;
|
|
|
|
Node * prev = nullptr;
|
|
|
|
bool queued = false;
|
|
|
|
bool visited = false;
|
|
|
|
};
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
std::map<StorePath, Node> graph;
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
for (auto & path : closure)
|
2020-07-15 22:08:46 +03:00
|
|
|
graph.emplace(path, Node {
|
|
|
|
.path = path,
|
|
|
|
.refs = store->queryPathInfo(path)->references,
|
|
|
|
.dist = path == dependencyPath ? 0 : inf
|
|
|
|
});
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
// Transpose the graph.
|
|
|
|
for (auto & node : graph)
|
|
|
|
for (auto & ref : node.second.refs)
|
2020-06-16 23:20:18 +03:00
|
|
|
graph.find(ref)->second.rrefs.insert(node.first);
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03: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 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03: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 17:00:00 +02:00
|
|
|
std::function<void(Node &, const std::string &, const std::string &)> printNode;
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
struct BailOut { };
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2022-02-25 17:00:00 +02:00
|
|
|
printNode = [&](Node & node, const std::string & firstPad, const std::string & tailPad) {
|
2019-12-05 20:11:09 +02:00
|
|
|
auto pathS = store->printStorePath(node.path);
|
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
assert(node.dist != inf);
|
2022-01-19 15:15:45 +02:00
|
|
|
if (precise) {
|
|
|
|
logger->cout("%s%s%s%s" ANSI_NORMAL,
|
|
|
|
firstPad,
|
|
|
|
node.visited ? "\e[38;5;244m" : "",
|
|
|
|
firstPad != "" ? "→ " : "",
|
|
|
|
pathS);
|
|
|
|
}
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-14 12:17:32 +03:00
|
|
|
if (node.path == dependencyPath && !all
|
|
|
|
&& packagePath != dependencyPath)
|
|
|
|
throw BailOut();
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03: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 15:12:06 +02:00
|
|
|
if (precise) node.visited = true;
|
2017-09-10 23:36:59 +03:00
|
|
|
|
2017-09-11 17:21:27 +03: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 12:17:32 +03:00
|
|
|
if (ref == node.path && packagePath != dependencyPath) continue;
|
2017-09-11 17:21:27 +03:00
|
|
|
auto & node2 = graph.at(ref);
|
|
|
|
if (node2.dist == inf) continue;
|
|
|
|
refs.emplace(node2.dist, &node2);
|
2020-06-16 15:16:39 +03:00
|
|
|
hashes.insert(std::string(node2.path.hashPart()));
|
2017-09-11 17:21:27 +03: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 23:36:59 +03:00
|
|
|
auto st = accessor->stat(p);
|
|
|
|
|
2019-12-05 20:11:09 +02:00
|
|
|
auto p2 = p == pathS ? "/" : std::string(p, pathS.size() + 1);
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
auto getColour = [&](const std::string & hash) {
|
|
|
|
return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
|
|
|
|
};
|
2017-09-10 23:36:59 +03:00
|
|
|
|
|
|
|
if (st.type == FSAccessor::Type::tDirectory) {
|
|
|
|
auto names = accessor->readDirectory(p);
|
|
|
|
for (auto & name : names)
|
2017-09-11 17:21:27 +03:00
|
|
|
visitPath(p + "/" + name);
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
else if (st.type == FSAccessor::Type::tRegular) {
|
|
|
|
auto contents = accessor->readFile(p);
|
|
|
|
|
2017-09-11 17:21:27 +03:00
|
|
|
for (auto & hash : hashes) {
|
|
|
|
auto pos = contents.find(hash);
|
|
|
|
if (pos != std::string::npos) {
|
2017-09-25 17:59:16 +03:00
|
|
|
size_t margin = 32;
|
2017-09-11 17:21:27 +03:00
|
|
|
auto pos2 = pos >= margin ? pos - margin : 0;
|
2023-08-05 00:11:08 +03:00
|
|
|
hits[hash].emplace_back(fmt("%s: …%s…",
|
2017-09-11 17:21:27 +03:00
|
|
|
p2,
|
|
|
|
hilite(filterPrintable(
|
|
|
|
std::string(contents, pos2, pos - pos2 + hash.size() + margin)),
|
2020-06-16 15:16:39 +03:00
|
|
|
pos - pos2, StorePath::HashLen,
|
2017-09-11 17:21:27 +03:00
|
|
|
getColour(hash))));
|
|
|
|
}
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (st.type == FSAccessor::Type::tSymlink) {
|
|
|
|
auto target = accessor->readLink(p);
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
for (auto & hash : hashes) {
|
|
|
|
auto pos = target.find(hash);
|
|
|
|
if (pos != std::string::npos)
|
2023-08-05 00:11:08 +03:00
|
|
|
hits[hash].emplace_back(fmt("%s -> %s", p2,
|
2020-06-16 15:16:39 +03:00
|
|
|
hilite(target, pos, StorePath::HashLen, getColour(hash))));
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-09-14 14:22:32 +03:00
|
|
|
// FIXME: should use scanForReferences().
|
|
|
|
|
2022-01-19 15:15:45 +02:00
|
|
|
if (precise) visitPath(pathS);
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
for (auto & ref : refs) {
|
2020-06-16 15:16:39 +03:00
|
|
|
std::string hash(ref.second->path.hashPart());
|
2017-09-11 17:21:27 +03:00
|
|
|
|
|
|
|
bool last = all ? ref == *refs.rbegin() : true;
|
|
|
|
|
|
|
|
for (auto & hit : hits[hash]) {
|
|
|
|
bool first = hit == *hits[hash].begin();
|
2023-08-05 00:11:08 +03:00
|
|
|
logger->cout("%s%s%s", tailPad,
|
|
|
|
(first ? (last ? treeLast : treeConn) : (last ? treeNull : treeLine)),
|
|
|
|
hit);
|
2017-09-11 17:21:27 +03:00
|
|
|
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 15:12:06 +02: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 17:21:27 +03:00
|
|
|
printNode(*ref.second,
|
|
|
|
tailPad + (last ? treeNull : treeLine),
|
|
|
|
tailPad + (last ? treeNull : treeLine));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-14 14:41:45 +02:00
|
|
|
RunPager pager;
|
2017-09-11 17:21:27 +03: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 15:12:06 +02:00
|
|
|
if (!precise) {
|
|
|
|
logger->cout("%s", store->printStorePath(graph.at(packagePath).path));
|
|
|
|
}
|
2017-09-11 17:21:27 +03:00
|
|
|
printNode(graph.at(packagePath), "", "");
|
|
|
|
} catch (BailOut & ) { }
|
2017-09-10 23:36:59 +03:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2020-10-06 14:36:55 +03:00
|
|
|
static auto rCmdWhyDepends = registerCommand<CmdWhyDepends>("why-depends");
|