123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298 |
- #include "derivations.hh"
- #include "store-api.hh"
- #include "globals.hh"
- #include "util.hh"
- #include "misc.hh"
- namespace nix {
- void DerivationOutput::parseHashInfo(bool & recursive, HashType & hashType, Hash & hash) const
- {
- recursive = false;
- string algo = hashAlgo;
- if (string(algo, 0, 2) == "r:") {
- recursive = true;
- algo = string(algo, 2);
- }
- hashType = parseHashType(algo);
- if (hashType == htUnknown)
- throw Error(format("unknown hash algorithm `%1%'") % algo);
- hash = parseHash(hashType, this->hash);
- }
- Path writeDerivation(StoreAPI & store,
- const Derivation & drv, const string & name, bool repair)
- {
- PathSet references;
- references.insert(drv.inputSrcs.begin(), drv.inputSrcs.end());
- foreach (DerivationInputs::const_iterator, i, drv.inputDrvs)
- references.insert(i->first);
- /* Note that the outputs of a derivation are *not* references
- (that can be missing (of course) and should not necessarily be
- held during a garbage collection). */
- string suffix = name + drvExtension;
- string contents = unparseDerivation(drv);
- return settings.readOnlyMode
- ? computeStorePathForText(suffix, contents, references)
- : store.addTextToStore(suffix, contents, references, repair);
- }
- static Path parsePath(std::istream & str)
- {
- string s = parseString(str);
- if (s.size() == 0 || s[0] != '/')
- throw FormatError(format("bad path `%1%' in derivation") % s);
- return s;
- }
- static StringSet parseStrings(std::istream & str, bool arePaths)
- {
- StringSet res;
- while (!endOfList(str))
- res.insert(arePaths ? parsePath(str) : parseString(str));
- return res;
- }
- static Derivation parseDerivation(const string & s)
- {
- Derivation drv;
- std::istringstream str(s);
- expect(str, "Derive([");
- /* Parse the list of outputs. */
- while (!endOfList(str)) {
- DerivationOutput out;
- expect(str, "("); string id = parseString(str);
- expect(str, ","); out.path = parsePath(str);
- expect(str, ","); out.hashAlgo = parseString(str);
- expect(str, ","); out.hash = parseString(str);
- expect(str, ")");
- drv.outputs[id] = out;
- }
- /* Parse the list of input derivations. */
- expect(str, ",[");
- while (!endOfList(str)) {
- expect(str, "(");
- Path drvPath = parsePath(str);
- expect(str, ",[");
- drv.inputDrvs[drvPath] = parseStrings(str, false);
- expect(str, ")");
- }
- expect(str, ",["); drv.inputSrcs = parseStrings(str, true);
- expect(str, ","); drv.platform = parseString(str);
- expect(str, ","); drv.builder = parseString(str);
- /* Parse the builder arguments. */
- expect(str, ",[");
- while (!endOfList(str))
- drv.args.push_back(parseString(str));
- /* Parse the environment variables. */
- expect(str, ",[");
- while (!endOfList(str)) {
- expect(str, "("); string name = parseString(str);
- expect(str, ","); string value = parseString(str);
- expect(str, ")");
- drv.env[name] = value;
- }
- expect(str, ")");
- return drv;
- }
- Derivation readDerivation(const Path & drvPath)
- {
- try {
- return parseDerivation(readFile(drvPath));
- } catch (FormatError & e) {
- throw Error(format("error parsing derivation `%1%': %2%") % drvPath % e.msg());
- }
- }
- static void printString(string & res, const string & s)
- {
- res += '"';
- for (const char * i = s.c_str(); *i; i++)
- if (*i == '\"' || *i == '\\') { res += "\\"; res += *i; }
- else if (*i == '\n') res += "\\n";
- else if (*i == '\r') res += "\\r";
- else if (*i == '\t') res += "\\t";
- else res += *i;
- res += '"';
- }
- template<class ForwardIterator>
- static void printStrings(string & res, ForwardIterator i, ForwardIterator j)
- {
- res += '[';
- bool first = true;
- for ( ; i != j; ++i) {
- if (first) first = false; else res += ',';
- printString(res, *i);
- }
- res += ']';
- }
- string unparseDerivation(const Derivation & drv)
- {
- string s;
- s.reserve(65536);
- s += "Derive([";
- bool first = true;
- foreach (DerivationOutputs::const_iterator, i, drv.outputs) {
- if (first) first = false; else s += ',';
- s += '('; printString(s, i->first);
- s += ','; printString(s, i->second.path);
- s += ','; printString(s, i->second.hashAlgo);
- s += ','; printString(s, i->second.hash);
- s += ')';
- }
- s += "],[";
- first = true;
- foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
- if (first) first = false; else s += ',';
- s += '('; printString(s, i->first);
- s += ','; printStrings(s, i->second.begin(), i->second.end());
- s += ')';
- }
- s += "],";
- printStrings(s, drv.inputSrcs.begin(), drv.inputSrcs.end());
- s += ','; printString(s, drv.platform);
- s += ','; printString(s, drv.builder);
- s += ','; printStrings(s, drv.args.begin(), drv.args.end());
- s += ",[";
- first = true;
- foreach (StringPairs::const_iterator, i, drv.env) {
- if (first) first = false; else s += ',';
- s += '('; printString(s, i->first);
- s += ','; printString(s, i->second);
- s += ')';
- }
- s += "])";
- return s;
- }
- bool isDerivation(const string & fileName)
- {
- return hasSuffix(fileName, drvExtension);
- }
- bool isFixedOutputDrv(const Derivation & drv)
- {
- return drv.outputs.size() == 1 &&
- drv.outputs.begin()->first == "out" &&
- drv.outputs.begin()->second.hash != "";
- }
- DrvHashes drvHashes;
- /* Returns the hash of a derivation modulo fixed-output
- subderivations. A fixed-output derivation is a derivation with one
- output (`out') for which an expected hash and hash algorithm are
- specified (using the `outputHash' and `outputHashAlgo'
- attributes). We don't want changes to such derivations to
- propagate upwards through the dependency graph, changing output
- paths everywhere.
- For instance, if we change the url in a call to the `fetchurl'
- function, we do not want to rebuild everything depending on it
- (after all, (the hash of) the file being downloaded is unchanged).
- So the *output paths* should not change. On the other hand, the
- *derivation paths* should change to reflect the new dependency
- graph.
- That's what this function does: it returns a hash which is just the
- hash of the derivation ATerm, except that any input derivation
- paths have been replaced by the result of a recursive call to this
- function, and that for fixed-output derivations we return a hash of
- its output path. */
- Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
- {
- /* Return a fixed hash for fixed-output derivations. */
- if (isFixedOutputDrv(drv)) {
- DerivationOutputs::const_iterator i = drv.outputs.begin();
- return hashString(htSHA256, "fixed:out:"
- + i->second.hashAlgo + ":"
- + i->second.hash + ":"
- + i->second.path);
- }
- /* For other derivations, replace the inputs paths with recursive
- calls to this function.*/
- DerivationInputs inputs2;
- foreach (DerivationInputs::const_iterator, i, drv.inputDrvs) {
- Hash h = drvHashes[i->first];
- if (h.type == htUnknown) {
- assert(store.isValidPath(i->first));
- Derivation drv2 = readDerivation(i->first);
- h = hashDerivationModulo(store, drv2);
- drvHashes[i->first] = h;
- }
- inputs2[printHash(h)] = i->second;
- }
- drv.inputDrvs = inputs2;
- return hashString(htSHA256, unparseDerivation(drv));
- }
- DrvPathWithOutputs parseDrvPathWithOutputs(const string & s)
- {
- size_t n = s.find("!");
- return n == s.npos
- ? DrvPathWithOutputs(s, std::set<string>())
- : DrvPathWithOutputs(string(s, 0, n), tokenizeString<std::set<string> >(string(s, n + 1), ","));
- }
- Path makeDrvPathWithOutputs(const Path & drvPath, const std::set<string> & outputs)
- {
- return outputs.empty()
- ? drvPath
- : drvPath + "!" + concatStringsSep(",", outputs);
- }
- bool wantOutput(const string & output, const std::set<string> & wanted)
- {
- return wanted.empty() || wanted.find(output) != wanted.end();
- }
- PathSet outputPaths(const Derivation & drv)
- {
- PathSet paths;
- for (auto & i : drv.outputs)
- paths.insert(i.second.path);
- return paths;
- }
- }
|