* `nix-store -q --tree' shows a tree representing the dependency graph
of the given derivation. Useful for getting a quick overview of how something was built. E.g., to find out how the `baffle' program in your user environment was built, you can do $ nix-store -q --tree $(nix-store -qd $(which baffle)) Tree nesting depth is minimised (?) by topologically sorting paths under the relation A < B iff A \in closure(B).
This commit is contained in:
parent
74ab0695b5
commit
e0181f56be
2 changed files with 87 additions and 2 deletions
|
@ -30,7 +30,8 @@ Query flags:
|
||||||
--references: print all paths referenced by the given path
|
--references: print all paths referenced by the given path
|
||||||
--referers: print all paths directly refering to the given path
|
--referers: print all paths directly refering to the given path
|
||||||
--referers-closure: print all paths (in)directly refering to the given path
|
--referers-closure: print all paths (in)directly refering to the given path
|
||||||
--graph: print a dot graph rooted at given ids
|
--tree: print a tree showing the dependency graph of the given paths
|
||||||
|
--graph: print a dot graph rooted at given paths
|
||||||
|
|
||||||
Query switches (not applicable to all queries):
|
Query switches (not applicable to all queries):
|
||||||
|
|
||||||
|
|
|
@ -150,11 +150,86 @@ static void printPathSet(const PathSet & paths)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Some code to print a tree representation of a derivation dependency
|
||||||
|
graph. Topological sorting is used to keep the tree relatively
|
||||||
|
flat. */
|
||||||
|
|
||||||
|
const string treeConn = "+---";
|
||||||
|
const string treeLine = "| ";
|
||||||
|
const string treeNull = " ";
|
||||||
|
|
||||||
|
|
||||||
|
static void dfsVisit(const PathSet & paths, const Path & path,
|
||||||
|
PathSet & visited, Paths & sorted)
|
||||||
|
{
|
||||||
|
if (visited.find(path) != visited.end()) return;
|
||||||
|
visited.insert(path);
|
||||||
|
|
||||||
|
PathSet closure;
|
||||||
|
computeFSClosure(path, closure);
|
||||||
|
|
||||||
|
for (PathSet::iterator i = closure.begin();
|
||||||
|
i != closure.end(); ++i)
|
||||||
|
if (*i != path && paths.find(*i) != paths.end())
|
||||||
|
dfsVisit(paths, *i, visited, sorted);
|
||||||
|
|
||||||
|
sorted.push_front(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Paths topoSort(const PathSet & paths)
|
||||||
|
{
|
||||||
|
Paths sorted;
|
||||||
|
PathSet visited;
|
||||||
|
for (PathSet::const_iterator i = paths.begin(); i != paths.end(); ++i)
|
||||||
|
dfsVisit(paths, *i, visited, sorted);
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void printDrvTree(const Path & drvPath,
|
||||||
|
const string & firstPad, const string & tailPad, PathSet & done)
|
||||||
|
{
|
||||||
|
if (done.find(drvPath) != done.end()) {
|
||||||
|
cout << format("%1%%2% [...]\n") % firstPad % drvPath;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
done.insert(drvPath);
|
||||||
|
|
||||||
|
cout << format("%1%%2%\n") % firstPad % drvPath;
|
||||||
|
|
||||||
|
Derivation drv = derivationFromPath(drvPath);
|
||||||
|
|
||||||
|
for (PathSet::iterator i = drv.inputSrcs.begin();
|
||||||
|
i != drv.inputSrcs.end(); ++i)
|
||||||
|
cout << format("%1%%2%\n") % (tailPad + treeConn) % *i;
|
||||||
|
|
||||||
|
PathSet inputs;
|
||||||
|
for (DerivationInputs::iterator i = drv.inputDrvs.begin();
|
||||||
|
i != drv.inputDrvs.end(); ++i)
|
||||||
|
inputs.insert(i->first);
|
||||||
|
|
||||||
|
/* Topologically sorted under the relation A < B iff A \in
|
||||||
|
closure(B). That is, if derivation A is an (possibly indirect)
|
||||||
|
input of B, then A is printed first. This has the effect of
|
||||||
|
flattening the tree, preventing deeply nested structures. */
|
||||||
|
Paths sorted = topoSort(inputs);
|
||||||
|
reverse(sorted.begin(), sorted.end());
|
||||||
|
|
||||||
|
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i) {
|
||||||
|
Paths::iterator j = i; ++j;
|
||||||
|
printDrvTree(*i, tailPad + treeConn,
|
||||||
|
j == sorted.end() ? tailPad + treeNull : tailPad + treeLine,
|
||||||
|
done);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Perform various sorts of queries. */
|
/* Perform various sorts of queries. */
|
||||||
static void opQuery(Strings opFlags, Strings opArgs)
|
static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
{
|
{
|
||||||
enum { qOutputs, qRequisites, qReferences, qReferers,
|
enum { qOutputs, qRequisites, qReferences, qReferers,
|
||||||
qReferersClosure, qDeriver, qBinding, qGraph } query = qOutputs;
|
qReferersClosure, qDeriver, qBinding, qTree, qGraph } query = qOutputs;
|
||||||
bool useOutput = false;
|
bool useOutput = false;
|
||||||
bool includeOutputs = false;
|
bool includeOutputs = false;
|
||||||
bool forceRealise = false;
|
bool forceRealise = false;
|
||||||
|
@ -175,6 +250,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
opArgs.pop_front();
|
opArgs.pop_front();
|
||||||
query = qBinding;
|
query = qBinding;
|
||||||
}
|
}
|
||||||
|
else if (*i == "--tree") query = qTree;
|
||||||
else if (*i == "--graph") query = qGraph;
|
else if (*i == "--graph") query = qGraph;
|
||||||
else if (*i == "--use-output" || *i == "-u") useOutput = true;
|
else if (*i == "--use-output" || *i == "-u") useOutput = true;
|
||||||
else if (*i == "--force-realise" || *i == "-f") forceRealise = true;
|
else if (*i == "--force-realise" || *i == "-f") forceRealise = true;
|
||||||
|
@ -240,6 +316,14 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case qTree: {
|
||||||
|
PathSet done;
|
||||||
|
for (Strings::iterator i = opArgs.begin();
|
||||||
|
i != opArgs.end(); i++)
|
||||||
|
printDrvTree(fixPath(*i), "", "", done);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
case qGraph: {
|
case qGraph: {
|
||||||
PathSet roots;
|
PathSet roots;
|
||||||
|
|
Loading…
Reference in a new issue