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