1 : #include "get-drvs.hh"
2 : #include "nixexpr-ast.hh"
3 : #include "util.hh"
4 :
5 :
6 : namespace nix {
7 :
8 :
9 : string DrvInfo::queryDrvPath(EvalState & state) const
10 86 : {
11 86 : if (drvPath == "") {
12 66 : Expr a = attrs->get(toATerm("drvPath"));
13 66 : (string &) drvPath = a ? evalPath(state, a) : "";
14 : }
15 84 : return drvPath;
16 : }
17 :
18 :
19 : string DrvInfo::queryOutPath(EvalState & state) const
20 95 : {
21 95 : if (outPath == "") {
22 31 : Expr a = attrs->get(toATerm("outPath"));
23 31 : if (!a) throw TypeError("output path missing");
24 31 : (string &) outPath = evalPath(state, a);
25 : }
26 95 : return outPath;
27 : }
28 :
29 :
30 : MetaInfo DrvInfo::queryMetaInfo(EvalState & state) const
31 5 : {
32 5 : MetaInfo meta;
33 :
34 5 : Expr a = attrs->get(toATerm("meta"));
35 5 : if (!a) return meta; /* fine, empty meta information */
36 :
37 5 : ATermMap attrs2(16); /* !!! */
38 5 : queryAllAttrs(evalExpr(state, a), attrs2);
39 :
40 10 : for (ATermMap::const_iterator i = attrs2.begin(); i != attrs2.end(); ++i) {
41 5 : ATerm s = coerceToString(evalExpr(state, i->value));
42 5 : if (s)
43 5 : meta[aterm2String(i->key)] = aterm2String(s);
44 : /* For future compatibility, ignore attribute values that are
45 : not strings. */
46 : }
47 :
48 5 : return meta;
49 : }
50 :
51 :
52 : /* Cache for already evaluated derivations. Usually putting ATerms in
53 : a STL container is unsafe (they're not scanning for GC roots), but
54 : here it doesn't matter; everything in this set is reachable from
55 : the stack as well. */
56 : typedef set<Expr> Exprs;
57 :
58 :
59 : /* Evaluate expression `e'. If it evaluates to an attribute set of
60 : type `derivation', then put information about it in `drvs' (unless
61 : it's already in `doneExprs'). The result boolean indicates whether
62 : it makes sense for the caller to recursively search for derivations
63 : in `e'. */
64 : static bool getDerivation(EvalState & state, Expr e,
65 : const string & attrPath, DrvInfos & drvs, Exprs & doneExprs)
66 184 : {
67 184 : try {
68 :
69 184 : ATermList es;
70 184 : e = evalExpr(state, e);
71 184 : if (!matchAttrs(e, es)) return true;
72 :
73 134 : boost::shared_ptr<ATermMap> attrs(new ATermMap(32)); /* !!! */
74 134 : queryAllAttrs(e, *attrs, false);
75 :
76 134 : Expr a = attrs->get(toATerm("type"));
77 134 : if (!a || evalString(state, a) != "derivation") return true;
78 :
79 : /* Remove spurious duplicates (e.g., an attribute set like
80 : `rec { x = derivation {...}; y = x;}'. */
81 134 : if (doneExprs.find(e) != doneExprs.end()) return false;
82 134 : doneExprs.insert(e);
83 :
84 250 : DrvInfo drv;
85 :
86 134 : a = attrs->get(toATerm("name"));
87 : /* !!! We really would like to have a decent back trace here. */
88 134 : if (!a) throw TypeError("derivation name missing");
89 134 : drv.name = evalString(state, a);
90 :
91 134 : a = attrs->get(toATerm("system"));
92 134 : if (!a)
93 0 : drv.system = "unknown";
94 : else
95 134 : drv.system = evalString(state, a);
96 :
97 134 : drv.attrs = attrs;
98 :
99 134 : drv.attrPath = attrPath;
100 :
101 134 : drvs.push_back(drv);
102 134 : return false;
103 :
104 0 : } catch (AssertionError & e) {
105 0 : return false;
106 : }
107 : }
108 :
109 :
110 : bool getDerivation(EvalState & state, Expr e, DrvInfo & drv)
111 16 : {
112 756 : Exprs doneExprs;
113 16 : DrvInfos drvs;
114 16 : getDerivation(state, e, "", drvs, doneExprs);
115 16 : if (drvs.size() != 1) return false;
116 86 : drv = drvs.front();
117 16 : return true;
118 : }
119 :
120 :
121 : static string addToPath(const string & s1, const string & s2)
122 99 : {
123 99 : return s1.empty() ? s2 : s1 + "." + s2;
124 : }
125 :
126 :
127 : static void getDerivations(EvalState & state, Expr e,
128 : const string & pathPrefix, const ATermMap & autoArgs,
129 : DrvInfos & drvs, Exprs & doneExprs)
130 69 : {
131 69 : e = evalExpr(state, autoCallFunction(evalExpr(state, e), autoArgs));
132 :
133 : /* Process the expression. */
134 69 : ATermList es;
135 69 : DrvInfo drv;
136 :
137 69 : if (!getDerivation(state, e, pathPrefix, drvs, doneExprs))
138 19 : return;
139 :
140 50 : if (matchAttrs(e, es)) {
141 0 : ATermMap drvMap(ATgetLength(es));
142 0 : queryAllAttrs(e, drvMap);
143 :
144 0 : for (ATermMap::const_iterator i = drvMap.begin(); i != drvMap.end(); ++i) {
145 0 : startNest(nest, lvlDebug,
146 : format("evaluating attribute `%1%'") % aterm2String(i->key));
147 0 : string pathPrefix2 = addToPath(pathPrefix, aterm2String(i->key));
148 0 : if (getDerivation(state, i->value, pathPrefix2, drvs, doneExprs)) {
149 : /* If the value of this attribute is itself an
150 : attribute set, should we recurse into it? => Only
151 : if it has a `recurseForDerivations = true'
152 : attribute. */
153 0 : ATermList es;
154 0 : Expr e = evalExpr(state, i->value);
155 0 : if (matchAttrs(e, es)) {
156 0 : ATermMap attrs(ATgetLength(es));
157 0 : queryAllAttrs(e, attrs, false);
158 0 : Expr e2 = attrs.get(toATerm("recurseForDerivations"));
159 0 : if (e2 && evalBool(state, e2))
160 0 : getDerivations(state, e, pathPrefix2, autoArgs, drvs, doneExprs);
161 : }
162 : }
163 : }
164 :
165 0 : return;
166 : }
167 :
168 50 : if (matchList(e, es)) {
169 50 : int n = 0;
170 149 : for (ATermIterator i(es); i; ++i, ++n) {
171 99 : startNest(nest, lvlDebug,
172 : format("evaluating list element"));
173 99 : string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str());
174 99 : if (getDerivation(state, *i, pathPrefix2, drvs, doneExprs))
175 0 : getDerivations(state, *i, pathPrefix2, autoArgs, drvs, doneExprs);
176 : }
177 50 : return;
178 : }
179 :
180 0 : throw TypeError("expression does not evaluate to a derivation (or a set or list of those)");
181 : }
182 :
183 :
184 : void getDerivations(EvalState & state, Expr e, const string & pathPrefix,
185 : const ATermMap & autoArgs, DrvInfos & drvs)
186 69 : {
187 69 : Exprs doneExprs;
188 69 : getDerivations(state, e, pathPrefix, autoArgs, drvs, doneExprs);
189 : }
190 :
191 :
192 : }
|