about summary refs log tree commit diff
path: root/src/libstore
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstore')
-rw-r--r--src/libstore/misc.cc5
-rw-r--r--src/libstore/normalise.cc59
-rw-r--r--src/libstore/store.cc10
-rw-r--r--src/libstore/store.hh2
-rw-r--r--src/libstore/storeexpr-ast.def1
-rw-r--r--src/libstore/storeexpr.cc37
-rw-r--r--src/libstore/storeexpr.hh22
7 files changed, 103 insertions, 33 deletions
diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc
index d7c32336e4cd..6dc054fb43d7 100644
--- a/src/libstore/misc.cc
+++ b/src/libstore/misc.cc
@@ -20,8 +20,9 @@ PathSet storeExprRoots(const Path & nePath)
     if (ne.type == StoreExpr::neClosure)
         paths.insert(ne.closure.roots.begin(), ne.closure.roots.end());
     else if (ne.type == StoreExpr::neDerivation)
-        paths.insert(ne.derivation.outputs.begin(),
-            ne.derivation.outputs.end());
+        for (DerivationOutputs::iterator i = ne.derivation.outputs.begin();
+             i != ne.derivation.outputs.end(); ++i)
+            paths.insert(i->second.path);
     else abort();
 
     return paths;
diff --git a/src/libstore/normalise.cc b/src/libstore/normalise.cc
index 7907325a97eb..b016d8d354e6 100644
--- a/src/libstore/normalise.cc
+++ b/src/libstore/normalise.cc
@@ -702,6 +702,29 @@ static void drain(int fd)
 }
 
 
+PathSet outputPaths(const DerivationOutputs & outputs)
+{
+    PathSet paths;
+    for (DerivationOutputs::const_iterator i = outputs.begin();
+         i != outputs.end(); ++i)
+        paths.insert(i->second.path);
+    return paths;
+}
+
+
+string showPaths(const PathSet & paths)
+{
+    string s;
+    for (PathSet::const_iterator i = paths.begin();
+         i != paths.end(); ++i)
+    {
+        if (s.size() != 0) s += ", ";
+        s += *i;
+    }
+    return s;
+}
+
+
 NormalisationGoal::HookReply NormalisationGoal::tryBuildHook()
 {
     Path buildHook = getEnv("NIX_BUILD_HOOK");
@@ -786,7 +809,7 @@ NormalisationGoal::HookReply NormalisationGoal::tryBuildHook()
         }
 
         printMsg(lvlInfo, format("running hook to build path `%1%'")
-            % *expr.derivation.outputs.begin());
+            % showPaths(outputPaths(expr.derivation.outputs)));
         
         /* Write the information that the hook needs to perform the
            build, i.e., the set of input paths (including closure
@@ -807,9 +830,9 @@ NormalisationGoal::HookReply NormalisationGoal::tryBuildHook()
         writeStringToFile(inputListFN, s);
         
         s = "";
-        for (PathSet::iterator i = expr.derivation.outputs.begin();
+        for (DerivationOutputs::iterator i = expr.derivation.outputs.begin();
              i != expr.derivation.outputs.end(); ++i)
-            s += *i + "\n";
+            s += i->second.path + "\n";
         writeStringToFile(outputListFN, s);
         
         s = "";
@@ -848,7 +871,7 @@ bool NormalisationGoal::prepareBuild()
     /* Obtain locks on all output paths.  The locks are automatically
        released when we exit this function or Nix crashes. */
     /* !!! BUG: this could block, which is not allowed. */
-    outputLocks.lockPaths(expr.derivation.outputs);
+    outputLocks.lockPaths(outputPaths(expr.derivation.outputs));
 
     /* Now check again whether there is a successor.  This is because
        another process may have started building in parallel.  After
@@ -870,11 +893,11 @@ bool NormalisationGoal::prepareBuild()
        running the build hook. */
     
     /* The outputs are referenceable paths. */
-    for (PathSet::iterator i = expr.derivation.outputs.begin();
+    for (DerivationOutputs::iterator i = expr.derivation.outputs.begin();
          i != expr.derivation.outputs.end(); ++i)
     {
-        debug(format("building path `%1%'") % *i);
-        allPaths.insert(*i);
+        debug(format("building path `%1%'") % i->second.path);
+        allPaths.insert(i->second.path);
     }
     
     /* Get information about the inputs (these all exist now). */
@@ -901,9 +924,9 @@ bool NormalisationGoal::prepareBuild()
     /* We can skip running the builder if all output paths are already
        valid. */
     bool fastBuild = true;
-    for (PathSet::iterator i = expr.derivation.outputs.begin();
+    for (DerivationOutputs::iterator i = expr.derivation.outputs.begin();
          i != expr.derivation.outputs.end(); ++i)
-        if (!isValidPath(*i)) { 
+        if (!isValidPath(i->second.path)) { 
             fastBuild = false;
             break;
         }
@@ -921,7 +944,7 @@ bool NormalisationGoal::prepareBuild()
 void NormalisationGoal::startBuilder()
 {
     startNest(nest, lvlInfo,
-        format("building path `%1%'") % *expr.derivation.outputs.begin());
+        format("building path `%1%'") % showPaths(outputPaths(expr.derivation.outputs)))
     
     /* Right platform? */
     if (expr.derivation.platform != thisSystem)
@@ -931,10 +954,10 @@ void NormalisationGoal::startBuilder()
 
     /* If any of the outputs already exist but are not registered,
        delete them. */
-    for (PathSet::iterator i = expr.derivation.outputs.begin(); 
+    for (DerivationOutputs::iterator i = expr.derivation.outputs.begin(); 
          i != expr.derivation.outputs.end(); ++i)
     {
-        Path path = *i;
+        Path path = i->second.path;
         if (isValidPath(path))
             throw Error(format("obstructed build: path `%1%' exists") % path);
         if (pathExists(path)) {
@@ -1054,10 +1077,10 @@ void NormalisationGoal::createClosure()
        output path to determine what other paths it references.  Also make all
        output paths read-only. */
     PathSet usedPaths;
-    for (PathSet::iterator i = expr.derivation.outputs.begin(); 
+    for (DerivationOutputs::iterator i = expr.derivation.outputs.begin(); 
          i != expr.derivation.outputs.end(); ++i)
     {
-        Path path = *i;
+        Path path = i->second.path;
         if (!pathExists(path)) {
             throw BuildError(
                 format("builder for `%1%' failed to produce output path `%2%'")
@@ -1084,6 +1107,7 @@ void NormalisationGoal::createClosure()
 	/* For each path referenced by this output path, add its id to the
 	   closure element and add the id to the `usedPaths' set (so that the
 	   elements referenced by *its* closure are added below). */
+        PathSet outputPaths = ::outputPaths(expr.derivation.outputs);
         for (Paths::iterator j = refPaths.begin();
 	     j != refPaths.end(); ++j)
 	{
@@ -1092,8 +1116,7 @@ void NormalisationGoal::createClosure()
 	    elem.refs.insert(path);
             if (inClosures.find(path) != inClosures.end())
                 usedPaths.insert(path);
-	    else if (expr.derivation.outputs.find(path) ==
-                expr.derivation.outputs.end())
+	    else if (outputPaths.find(path) == outputPaths.end())
 		abort();
         }
 
@@ -1147,9 +1170,9 @@ void NormalisationGoal::createClosure()
        by running the garbage collector. */
     Transaction txn;
     createStoreTransaction(txn);
-    for (PathSet::iterator i = expr.derivation.outputs.begin(); 
+    for (DerivationOutputs::iterator i = expr.derivation.outputs.begin(); 
          i != expr.derivation.outputs.end(); ++i)
-        registerValidPath(txn, *i);
+        registerValidPath(txn, i->second.path);
     registerSuccessor(txn, nePath, nfPath);
     txn.commit();
 
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index e490bf258195..0d89f7a5d7ae 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -412,14 +412,14 @@ static void invalidatePath(const Path & path, Transaction & txn)
 
 
 Path makeStorePath(const string & type,
-    Hash & hash, const string & suffix)
+    const Hash & hash, const string & suffix)
 {
     /* e.g., "source:sha256:1abc...:/nix/store:foo.tar.gz" */
     string s = type + ":sha256:" + printHash(hash) + ":"
         + nixStore + ":" + suffix;
 
     return nixStore + "/"
-        + printHash32(compressHash(hashString(s, htSHA256), 20))
+        + printHash32(compressHash(hashString(htSHA256, s), 20))
         + "-" + suffix;
 }
 
@@ -432,7 +432,7 @@ Path addToStore(const Path & _srcPath)
     Hash h(htSHA256);
     {
         SwitchToOriginalUser sw;
-        h = hashPath(srcPath, htSHA256);
+        h = hashPath(htSHA256, srcPath);
     }
 
     string baseName = baseNameOf(srcPath);
@@ -456,7 +456,7 @@ Path addToStore(const Path & _srcPath)
             
             copyPath(srcPath, dstPath);
 
-            Hash h2 = hashPath(dstPath, htSHA256);
+            Hash h2 = hashPath(htSHA256, dstPath);
             if (h != h2)
                 throw Error(format("contents of `%1%' changed while copying it to `%2%' (%3% -> %4%)")
                     % srcPath % dstPath % printHash(h) % printHash(h2));
@@ -477,7 +477,7 @@ Path addToStore(const Path & _srcPath)
 
 Path addTextToStore(const string & suffix, const string & s)
 {
-    Hash hash = hashString(s, htSHA256);
+    Hash hash = hashString(htSHA256, s);
 
     Path dstPath = makeStorePath("text", hash, suffix);
     
diff --git a/src/libstore/store.hh b/src/libstore/store.hh
index 25a6bc8b9669..c27918cbb4f9 100644
--- a/src/libstore/store.hh
+++ b/src/libstore/store.hh
@@ -83,7 +83,7 @@ bool isValidPath(const Path & path);
 
 /* Constructs a unique store path name. */
 Path makeStorePath(const string & type,
-    Hash & hash, const string & suffix);
+    const Hash & hash, const string & suffix);
     
 /* Copy the contents of a path to the store and register the validity
    the resulting path.  The resulting path is returned. */
diff --git a/src/libstore/storeexpr-ast.def b/src/libstore/storeexpr-ast.def
index 9d2433dbe4be..0c70948d4b6c 100644
--- a/src/libstore/storeexpr-ast.def
+++ b/src/libstore/storeexpr-ast.def
@@ -5,3 +5,4 @@ Derive | ATermList ATermList string string ATermList ATermList | ATerm |
 
 | string string | ATerm | EnvBinding |
 | string ATermList | ATerm | ClosureElem |
+| string string string string | ATerm | DerivationOutput |
diff --git a/src/libstore/storeexpr.cc b/src/libstore/storeexpr.cc
index de29959edf60..d8300a066a0e 100644
--- a/src/libstore/storeexpr.cc
+++ b/src/libstore/storeexpr.cc
@@ -8,7 +8,7 @@
 
 Hash hashTerm(ATerm t)
 {
-    return hashString(atPrint(t), htMD5);
+    return hashString(htSHA256, atPrint(t));
 }
 
 
@@ -20,14 +20,20 @@ Path writeTerm(ATerm t, const string & suffix)
 }
 
 
+void checkPath(const string & s)
+{
+    if (s.size() == 0 || s[0] != '/')
+        throw Error(format("bad path `%1%' in store expression") % s);
+}
+    
+
 static void parsePaths(ATermList paths, PathSet & out)
 {
     for (ATermIterator i(paths); i; ++i) {
         if (ATgetType(*i) != AT_APPL)
             throw badTerm("not a path", *i);
         string s = aterm2String(*i);
-        if (s.size() == 0 || s[0] != '/')
-            throw badTerm("not a path", *i);
+        checkPath(s);
         out.insert(s);
     }
 }
@@ -92,7 +98,18 @@ static bool parseDerivation(ATerm t, Derivation & derivation)
     if (!matchDerive(t, outs, ins, platform, builder, args, bnds))
         return false;
 
-    parsePaths(outs, derivation.outputs);
+    for (ATermIterator i(outs); i; ++i) {
+        ATerm id, path, hashAlgo, hash;
+        if (!matchDerivationOutput(*i, id, path, hashAlgo, hash))
+            return false;
+        DerivationOutput out;
+        out.path = aterm2String(path);
+        checkPath(out.path);
+        out.hashAlgo = aterm2String(hashAlgo);
+        out.hash = aterm2String(hash);
+        derivation.outputs[aterm2String(id)] = out;
+    }
+
     parsePaths(ins, derivation.inputs);
 
     derivation.builder = aterm2String(builder);
@@ -155,6 +172,16 @@ static ATerm unparseClosure(const Closure & closure)
 
 static ATerm unparseDerivation(const Derivation & derivation)
 {
+    ATermList outputs = ATempty;
+    for (DerivationOutputs::const_iterator i = derivation.outputs.begin();
+         i != derivation.outputs.end(); i++)
+        outputs = ATinsert(outputs,
+            makeDerivationOutput(
+                toATerm(i->first),
+                toATerm(i->second.path),
+                toATerm(i->second.hashAlgo),
+                toATerm(i->second.hash)));
+
     ATermList args = ATempty;
     for (Strings::const_iterator i = derivation.args.begin();
          i != derivation.args.end(); i++)
@@ -169,7 +196,7 @@ static ATerm unparseDerivation(const Derivation & derivation)
                 toATerm(i->second)));
 
     return makeDerive(
-        unparsePaths(derivation.outputs),
+        ATreverse(outputs),
         unparsePaths(derivation.inputs),
         toATerm(derivation.platform),
         toATerm(derivation.builder),
diff --git a/src/libstore/storeexpr.hh b/src/libstore/storeexpr.hh
index 07676c3ccedb..d8b8b2a96cbf 100644
--- a/src/libstore/storeexpr.hh
+++ b/src/libstore/storeexpr.hh
@@ -20,12 +20,30 @@ struct Closure
     ClosureElems elems;
 };
 
+
+struct DerivationOutput
+{
+    Path path;
+    string hashAlgo; /* hash used for expected hash computation */
+    string hash; /* expected hash, may be null */
+    DerivationOutput()
+    {
+    }
+    DerivationOutput(Path path, string hashAlgo, string hash)
+    {
+        this->path = path;
+        this->hashAlgo = hashAlgo;
+        this->hash = hash;
+    }
+};
+
+typedef map<string, DerivationOutput> DerivationOutputs;
 typedef map<string, string> StringPairs;
 
 struct Derivation
 {
-    PathSet outputs;
-    PathSet inputs; /* Store expressions, not actual inputs */
+    DerivationOutputs outputs; /* keyed on symbolic IDs */
+    PathSet inputs; /* store expressions, not actual inputs */
     string platform;
     Path builder;
     Strings args;