1 #include "derivations.hh"
2 #include "store-api.hh"
11 void DerivationOutput::parseHashInfo(bool & recursive
, HashType
& hashType
, Hash
& hash
) const
14 string algo
= hashAlgo
;
16 if (string(algo
, 0, 2) == "r:") {
18 algo
= string(algo
, 2);
21 hashType
= parseHashType(algo
);
22 if (hashType
== htUnknown
)
23 throw Error(format("unknown hash algorithm `%1%'") % algo
);
25 hash
= parseHash(hashType
, this->hash
);
29 Path
writeDerivation(StoreAPI
& store
,
30 const Derivation
& drv
, const string
& name
, bool repair
)
33 references
.insert(drv
.inputSrcs
.begin(), drv
.inputSrcs
.end());
34 foreach (DerivationInputs::const_iterator
, i
, drv
.inputDrvs
)
35 references
.insert(i
->first
);
36 /* Note that the outputs of a derivation are *not* references
37 (that can be missing (of course) and should not necessarily be
38 held during a garbage collection). */
39 string suffix
= name
+ drvExtension
;
40 string contents
= unparseDerivation(drv
);
41 return settings
.readOnlyMode
42 ? computeStorePathForText(suffix
, contents
, references
)
43 : store
.addTextToStore(suffix
, contents
, references
, repair
);
47 static Path
parsePath(std::istream
& str
)
49 string s
= parseString(str
);
50 if (s
.size() == 0 || s
[0] != '/')
51 throw FormatError(format("bad path `%1%' in derivation") % s
);
56 static StringSet
parseStrings(std::istream
& str
, bool arePaths
)
59 while (!endOfList(str
))
60 res
.insert(arePaths
? parsePath(str
) : parseString(str
));
65 static Derivation
parseDerivation(const string
& s
)
68 std::istringstream
str(s
);
69 expect(str
, "Derive([");
71 /* Parse the list of outputs. */
72 while (!endOfList(str
)) {
74 expect(str
, "("); string id
= parseString(str
);
75 expect(str
, ","); out
.path
= parsePath(str
);
76 expect(str
, ","); out
.hashAlgo
= parseString(str
);
77 expect(str
, ","); out
.hash
= parseString(str
);
79 drv
.outputs
[id
] = out
;
82 /* Parse the list of input derivations. */
84 while (!endOfList(str
)) {
86 Path drvPath
= parsePath(str
);
88 drv
.inputDrvs
[drvPath
] = parseStrings(str
, false);
92 expect(str
, ",["); drv
.inputSrcs
= parseStrings(str
, true);
93 expect(str
, ","); drv
.platform
= parseString(str
);
94 expect(str
, ","); drv
.builder
= parseString(str
);
96 /* Parse the builder arguments. */
98 while (!endOfList(str
))
99 drv
.args
.push_back(parseString(str
));
101 /* Parse the environment variables. */
103 while (!endOfList(str
)) {
104 expect(str
, "("); string name
= parseString(str
);
105 expect(str
, ","); string value
= parseString(str
);
107 drv
.env
[name
] = value
;
115 Derivation
readDerivation(const Path
& drvPath
)
118 return parseDerivation(readFile(drvPath
));
119 } catch (FormatError
& e
) {
120 throw Error(format("error parsing derivation `%1%': %2%") % drvPath
% e
.msg());
125 static void printString(string
& res
, const string
& s
)
128 for (const char * i
= s
.c_str(); *i
; i
++)
129 if (*i
== '\"' || *i
== '\\') { res
+= "\\"; res
+= *i
; }
130 else if (*i
== '\n') res
+= "\\n";
131 else if (*i
== '\r') res
+= "\\r";
132 else if (*i
== '\t') res
+= "\\t";
138 template<class ForwardIterator
>
139 static void printStrings(string
& res
, ForwardIterator i
, ForwardIterator j
)
143 for ( ; i
!= j
; ++i
) {
144 if (first
) first
= false; else res
+= ',';
145 printString(res
, *i
);
151 string
unparseDerivation(const Derivation
& drv
)
158 foreach (DerivationOutputs::const_iterator
, i
, drv
.outputs
) {
159 if (first
) first
= false; else s
+= ',';
160 s
+= '('; printString(s
, i
->first
);
161 s
+= ','; printString(s
, i
->second
.path
);
162 s
+= ','; printString(s
, i
->second
.hashAlgo
);
163 s
+= ','; printString(s
, i
->second
.hash
);
169 foreach (DerivationInputs::const_iterator
, i
, drv
.inputDrvs
) {
170 if (first
) first
= false; else s
+= ',';
171 s
+= '('; printString(s
, i
->first
);
172 s
+= ','; printStrings(s
, i
->second
.begin(), i
->second
.end());
177 printStrings(s
, drv
.inputSrcs
.begin(), drv
.inputSrcs
.end());
179 s
+= ','; printString(s
, drv
.platform
);
180 s
+= ','; printString(s
, drv
.builder
);
181 s
+= ','; printStrings(s
, drv
.args
.begin(), drv
.args
.end());
185 foreach (StringPairs::const_iterator
, i
, drv
.env
) {
186 if (first
) first
= false; else s
+= ',';
187 s
+= '('; printString(s
, i
->first
);
188 s
+= ','; printString(s
, i
->second
);
198 bool isDerivation(const string
& fileName
)
200 return hasSuffix(fileName
, drvExtension
);
204 bool isFixedOutputDrv(const Derivation
& drv
)
206 return drv
.outputs
.size() == 1 &&
207 drv
.outputs
.begin()->first
== "out" &&
208 drv
.outputs
.begin()->second
.hash
!= "";
215 /* Returns the hash of a derivation modulo fixed-output
216 subderivations. A fixed-output derivation is a derivation with one
217 output (`out') for which an expected hash and hash algorithm are
218 specified (using the `outputHash' and `outputHashAlgo'
219 attributes). We don't want changes to such derivations to
220 propagate upwards through the dependency graph, changing output
223 For instance, if we change the url in a call to the `fetchurl'
224 function, we do not want to rebuild everything depending on it
225 (after all, (the hash of) the file being downloaded is unchanged).
226 So the *output paths* should not change. On the other hand, the
227 *derivation paths* should change to reflect the new dependency
230 That's what this function does: it returns a hash which is just the
231 hash of the derivation ATerm, except that any input derivation
232 paths have been replaced by the result of a recursive call to this
233 function, and that for fixed-output derivations we return a hash of
235 Hash
hashDerivationModulo(StoreAPI
& store
, Derivation drv
)
237 /* Return a fixed hash for fixed-output derivations. */
238 if (isFixedOutputDrv(drv
)) {
239 DerivationOutputs::const_iterator i
= drv
.outputs
.begin();
240 return hashString(htSHA256
, "fixed:out:"
241 + i
->second
.hashAlgo
+ ":"
242 + i
->second
.hash
+ ":"
246 /* For other derivations, replace the inputs paths with recursive
247 calls to this function.*/
248 DerivationInputs inputs2
;
249 foreach (DerivationInputs::const_iterator
, i
, drv
.inputDrvs
) {
250 Hash h
= drvHashes
[i
->first
];
251 if (h
.type
== htUnknown
) {
252 assert(store
.isValidPath(i
->first
));
253 Derivation drv2
= readDerivation(i
->first
);
254 h
= hashDerivationModulo(store
, drv2
);
255 drvHashes
[i
->first
] = h
;
257 inputs2
[printHash(h
)] = i
->second
;
259 drv
.inputDrvs
= inputs2
;
261 return hashString(htSHA256
, unparseDerivation(drv
));
265 DrvPathWithOutputs
parseDrvPathWithOutputs(const string
& s
)
267 size_t n
= s
.find("!");
269 ? DrvPathWithOutputs(s
, std::set
<string
>())
270 : DrvPathWithOutputs(string(s
, 0, n
), tokenizeString
<std::set
<string
> >(string(s
, n
+ 1), ","));
274 Path
makeDrvPathWithOutputs(const Path
& drvPath
, const std::set
<string
> & outputs
)
276 return outputs
.empty()
278 : drvPath
+ "!" + concatStringsSep(",", outputs
);
282 bool wantOutput(const string
& output
, const std::set
<string
> & wanted
)
284 return wanted
.empty() || wanted
.find(output
) != wanted
.end();
288 PathSet
outputPaths(const Derivation
& drv
)
291 for (auto & i
: drv
.outputs
)
292 paths
.insert(i
.second
.path
);