1 : #include "dotgraph.hh"
2 : #include "util.hh"
3 : #include "store-api.hh"
4 :
5 : #include <iostream>
6 :
7 :
8 : using std::cout;
9 :
10 : namespace nix {
11 :
12 :
13 42 : static string dotQuote(const string & s)
14 : {
15 42 : return "\"" + s + "\"";
16 : }
17 :
18 :
19 6 : static string nextColour()
20 : {
21 : static int n = 0;
22 : static string colours[] =
23 : { "black", "red", "green", "blue"
24 8 : , "magenta", "burlywood" };
25 6 : return colours[n++ % (sizeof(colours) / sizeof(string))];
26 : }
27 :
28 :
29 6 : static string makeEdge(const string & src, const string & dst)
30 : {
31 : format f = format("%1% -> %2% [color = %3%];\n")
32 6 : % dotQuote(src) % dotQuote(dst) % dotQuote(nextColour());
33 12 : return f.str();
34 : }
35 :
36 :
37 : static string makeNode(const string & id, const string & label,
38 8 : const string & colour)
39 : {
40 : format f = format("%1% [label = %2%, shape = box, "
41 : "style = filled, fillcolor = %3%];\n")
42 8 : % dotQuote(id) % dotQuote(label) % dotQuote(colour);
43 16 : return f.str();
44 : }
45 :
46 :
47 8 : static string symbolicName(const string & path)
48 : {
49 8 : string p = baseNameOf(path);
50 8 : int dash = p.find('-');
51 8 : return string(p, dash + 1);
52 : }
53 :
54 :
55 0 : string pathLabel(const Path & nePath, const string & elemPath)
56 : {
57 0 : return (string) nePath + "-" + elemPath;
58 : }
59 :
60 :
61 : #if 0
62 : void printClosure(const Path & nePath, const StoreExpr & fs)
63 : {
64 : PathSet workList(fs.closure.roots);
65 : PathSet doneSet;
66 :
67 : for (PathSet::iterator i = workList.begin(); i != workList.end(); ++i) {
68 : cout << makeEdge(pathLabel(nePath, *i), nePath);
69 : }
70 :
71 : while (!workList.empty()) {
72 : Path path = *(workList.begin());
73 : workList.erase(path);
74 :
75 : if (doneSet.find(path) == doneSet.end()) {
76 : doneSet.insert(path);
77 :
78 : ClosureElems::const_iterator elem = fs.closure.elems.find(path);
79 : if (elem == fs.closure.elems.end())
80 : throw Error(format("bad closure, missing path `%1%'") % path);
81 :
82 : for (StringSet::const_iterator i = elem->second.refs.begin();
83 : i != elem->second.refs.end(); ++i)
84 : {
85 : workList.insert(*i);
86 : cout << makeEdge(pathLabel(nePath, *i), pathLabel(nePath, path));
87 : }
88 :
89 : cout << makeNode(pathLabel(nePath, path),
90 : symbolicName(path), "#ff0000");
91 : }
92 : }
93 : }
94 : #endif
95 :
96 :
97 2 : void printDotGraph(const PathSet & roots)
98 : {
99 2 : PathSet workList(roots);
100 2 : PathSet doneSet;
101 :
102 2 : cout << "digraph G {\n";
103 :
104 20 : while (!workList.empty()) {
105 8 : Path path = *(workList.begin());
106 8 : workList.erase(path);
107 :
108 8 : if (doneSet.find(path) != doneSet.end()) continue;
109 8 : doneSet.insert(path);
110 :
111 8 : cout << makeNode(path, symbolicName(path), "#ff0000");
112 :
113 8 : PathSet references;
114 8 : store->queryReferences(path, references);
115 :
116 15 : for (PathSet::iterator i = references.begin();
117 : i != references.end(); ++i)
118 : {
119 7 : if (*i != path) {
120 6 : workList.insert(*i);
121 6 : cout << makeEdge(*i, path);
122 : }
123 : }
124 :
125 :
126 : #if 0
127 : StoreExpr ne = storeExprFromPath(path);
128 :
129 : string label, colour;
130 :
131 : if (ne.type == StoreExpr::neDerivation) {
132 : for (PathSet::iterator i = ne.derivation.inputs.begin();
133 : i != ne.derivation.inputs.end(); ++i)
134 : {
135 : workList.insert(*i);
136 : cout << makeEdge(*i, path);
137 : }
138 :
139 : label = "derivation";
140 : colour = "#00ff00";
141 : for (StringPairs::iterator i = ne.derivation.env.begin();
142 : i != ne.derivation.env.end(); ++i)
143 : if (i->first == "name") label = i->second;
144 : }
145 :
146 : else if (ne.type == StoreExpr::neClosure) {
147 : label = "<closure>";
148 : colour = "#00ffff";
149 : printClosure(path, ne);
150 : }
151 :
152 : else abort();
153 :
154 : cout << makeNode(path, label, colour);
155 : #endif
156 : }
157 :
158 2 : cout << "}\n";
159 2 : }
160 :
161 0 :
162 414 : }
|