Pretty-print 'nix why-depends' / 'nix-store -q --tree' output

Extracted from 678301072f.
This commit is contained in:
Eelco Dolstra 2020-03-24 14:17:10 +01:00
parent 4260a22a55
commit 7a8de57d3e
4 changed files with 44 additions and 20 deletions

View file

@ -451,6 +451,13 @@ void ignoreException();
#define ANSI_BLUE "\e[34;1m" #define ANSI_BLUE "\e[34;1m"
/* Tree formatting. */
constexpr char treeConn[] = "├───";
constexpr char treeLast[] = "└───";
constexpr char treeLine[] = "";
constexpr char treeNull[] = " ";
/* Truncate a string to 'width' printable characters. If 'filterAll' /* Truncate a string to 'width' printable characters. If 'filterAll'
is true, all ANSI escape sequences are filtered out. Otherwise, is true, all ANSI escape sequences are filtered out. Otherwise,
some escape sequences (such as colour setting) are copied but not some escape sequences (such as colour setting) are copied but not
@ -576,4 +583,31 @@ extern PathFilter defaultPathFilter;
AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode); AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode);
// A Rust/Python-like enumerate() iterator adapter.
// Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17.
template <typename T,
typename TIter = decltype(std::begin(std::declval<T>())),
typename = decltype(std::end(std::declval<T>()))>
constexpr auto enumerate(T && iterable)
{
struct iterator
{
size_t i;
TIter iter;
bool operator != (const iterator & other) const { return iter != other.iter; }
void operator ++ () { ++i; ++iter; }
auto operator * () const { return std::tie(i, *iter); }
};
struct iterable_wrapper
{
T iterable;
auto begin() { return iterator{ 0, std::begin(iterable) }; }
auto end() { return iterator{ 0, std::end(iterable) }; }
};
return iterable_wrapper{ std::forward<T>(iterable) };
}
} }

View file

@ -229,12 +229,6 @@ static StorePathSet maybeUseOutputs(const StorePath & storePath, bool useOutput,
/* Some code to print a tree representation of a derivation dependency /* Some code to print a tree representation of a derivation dependency
graph. Topological sorting is used to keep the tree relatively graph. Topological sorting is used to keep the tree relatively
flat. */ flat. */
const string treeConn = "+---";
const string treeLine = "| ";
const string treeNull = " ";
static void printTree(const StorePath & path, static void printTree(const StorePath & path,
const string & firstPad, const string & tailPad, StorePathSet & done) const string & firstPad, const string & tailPad, StorePathSet & done)
{ {
@ -254,10 +248,11 @@ static void printTree(const StorePath & path,
auto sorted = store->topoSortPaths(info->references); auto sorted = store->topoSortPaths(info->references);
reverse(sorted.begin(), sorted.end()); reverse(sorted.begin(), sorted.end());
for (auto i = sorted.begin(); i != sorted.end(); ++i) { for (const auto &[n, i] : enumerate(sorted)) {
auto j = i; ++j; bool last = n + 1 == sorted.size();
printTree(*i, tailPad + treeConn, printTree(i,
j == sorted.end() ? tailPad + treeNull : tailPad + treeLine, tailPad + (last ? treeLast : treeConn),
tailPad + (last ? treeNull : treeLine),
done); done);
} }
} }

View file

@ -143,11 +143,6 @@ struct CmdWhyDepends : SourceExprCommand
and `dependency`. */ and `dependency`. */
std::function<void(Node &, const string &, const string &)> printNode; std::function<void(Node &, const string &, const string &)> printNode;
const string treeConn = "╠═══";
const string treeLast = "╚═══";
const string treeLine = "";
const string treeNull = " ";
struct BailOut { }; struct BailOut { };
printNode = [&](Node & node, const string & firstPad, const string & tailPad) { printNode = [&](Node & node, const string & firstPad, const string & tailPad) {
@ -157,7 +152,7 @@ struct CmdWhyDepends : SourceExprCommand
std::cout << fmt("%s%s%s%s" ANSI_NORMAL "\n", std::cout << fmt("%s%s%s%s" ANSI_NORMAL "\n",
firstPad, firstPad,
node.visited ? "\e[38;5;244m" : "", node.visited ? "\e[38;5;244m" : "",
firstPad != "" ? "=> " : "", firstPad != "" ? " " : "",
pathS); pathS);
if (node.path == dependencyPath && !all if (node.path == dependencyPath && !all

View file

@ -6,7 +6,7 @@ drvPath=$(nix-instantiate dependencies.nix)
echo "derivation is $drvPath" echo "derivation is $drvPath"
nix-store -q --tree "$drvPath" | grep ' +---.*builder1.sh' nix-store -q --tree "$drvPath" | grep '───.*builder1.sh'
# Test Graphviz graph generation. # Test Graphviz graph generation.
nix-store -q --graph "$drvPath" > $TEST_ROOT/graph nix-store -q --graph "$drvPath" > $TEST_ROOT/graph
@ -24,7 +24,7 @@ if test -n "$dot"; then
$dot < $TEST_ROOT/graph $dot < $TEST_ROOT/graph
fi fi
nix-store -q --tree "$outPath" | grep '+---.*dependencies-input-2' nix-store -q --tree "$outPath" | grep '───.*dependencies-input-2'
echo "output path is $outPath" echo "output path is $outPath"