about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fstate.cc6
-rw-r--r--src/fstate.hh2
-rw-r--r--src/nix.cc25
-rw-r--r--src/store.cc45
-rw-r--r--src/store.hh4
5 files changed, 73 insertions, 9 deletions
diff --git a/src/fstate.cc b/src/fstate.cc
index fdd43d1b1384..97532c162c1f 100644
--- a/src/fstate.cc
+++ b/src/fstate.cc
@@ -147,6 +147,12 @@ Hash hashTerm(ATerm t)
 }
 
 
+FState hash2fstate(Hash hash)
+{
+    return ATmake("Include(<str>)", ((string) hash).c_str());
+}
+
+
 ATerm termFromHash(const Hash & hash, string * p)
 {
     string path = expandHash(hash);
diff --git a/src/fstate.hh b/src/fstate.hh
index 159c7ba46338..8a873a5acd22 100644
--- a/src/fstate.hh
+++ b/src/fstate.hh
@@ -85,6 +85,8 @@ Error badTerm(const format & f, ATerm t);
 /* Hash an aterm. */
 Hash hashTerm(ATerm t);
 
+FState hash2fstate(Hash hash);
+
 /* Read an aterm from disk, given its hash. */
 ATerm termFromHash(const Hash & hash, string * p = 0);
 
diff --git a/src/nix.cc b/src/nix.cc
index 4721563fdff5..53057328dd57 100644
--- a/src/nix.cc
+++ b/src/nix.cc
@@ -26,6 +26,8 @@ static ArgType argType = atpUnknown;
      --add / -A: copy a path to the Nix store
      --query / -q: query information
 
+     --substitute: register a substitute expression
+
      --dump: dump a path as a Nix archive
      --restore: restore a path from a Nix archive
 
@@ -87,12 +89,6 @@ static Hash argToHash(const string & arg)
 }
 
 
-static FState hash2fstate(Hash hash)
-{
-    return ATmake("Include(<str>)", ((string) hash).c_str());
-}
-
-
 /* Realise (or install) paths from the given Nix fstate
    expressions. */
 static void opInstall(Strings opFlags, Strings opArgs)
@@ -187,6 +183,21 @@ static void opQuery(Strings opFlags, Strings opArgs)
 }
 
 
+static void opSubstitute(Strings opFlags, Strings opArgs)
+{
+    if (!opFlags.empty()) throw UsageError("unknown flag");
+    if (opArgs.size() % 2) throw UsageError("expecting even number of arguments");
+    
+    for (Strings::iterator i = opArgs.begin();
+         i != opArgs.end(); )
+    {
+        Hash srcHash = parseHash(*i++);
+        Hash subHash = parseHash(*i++);
+        registerSubstitute(srcHash, subHash);
+    }
+}
+
+
 /* A sink that writes dump output to stdout. */
 struct StdoutSink : DumpSink
 {
@@ -277,6 +288,8 @@ void run(Strings args)
             op = opAdd;
         else if (arg == "--query" || arg == "-q")
             op = opQuery;
+        else if (arg == "--substitute")
+            op = opSubstitute;
         else if (arg == "--dump")
             op = opDump;
         else if (arg == "--restore")
diff --git a/src/store.cc b/src/store.cc
index 5a3a4e0678fe..435ac5cc69ce 100644
--- a/src/store.cc
+++ b/src/store.cc
@@ -7,6 +7,7 @@
 #include "globals.hh"
 #include "db.hh"
 #include "archive.hh"
+#include "fstate.hh"
 
 
 struct CopySink : DumpSink
@@ -83,6 +84,20 @@ void copyPath(string src, string dst)
 }
 
 
+void registerSubstitute(const Hash & srcHash, const Hash & subHash)
+{
+    Strings subs;
+    queryListDB(nixDB, dbSubstitutes, srcHash, subs); /* non-existence = ok */
+
+    for (Strings::iterator it = subs.begin(); it != subs.end(); it++)
+        if (parseHash(*it) == subHash) return;
+    
+    subs.push_back(subHash);
+    
+    setListDB(nixDB, dbSubstitutes, srcHash, subs);
+}
+
+
 Hash registerPath(const string & _path, Hash hash)
 {
     string path(canonPath(_path));
@@ -139,8 +154,7 @@ string expandHash(const Hash & hash, const string & target,
     if (!target.empty() && !isInPrefix(target, prefix))
         abort();
 
-    if (!queryListDB(nixDB, dbHash2Paths, hash, paths))
-        throw Error(format("no paths known with hash `%1%'") % (string) hash);
+    queryListDB(nixDB, dbHash2Paths, hash, paths);
 
     /* !!! we shouldn't check for staleness by default --- too slow */
 
@@ -181,8 +195,32 @@ string expandHash(const Hash & hash, const string & target,
             /* try next one */
         }
     }
+
+    /* Try to realise the substitutes. */
+
+    Strings subs;
+    queryListDB(nixDB, dbSubstitutes, hash, subs); /* non-existence = ok */
+
+    for (Strings::iterator it = subs.begin(); it != subs.end(); it++) {
+        StringSet dummy;
+        FState nf = realiseFState(hash2fstate(parseHash(*it)), dummy);
+        string path = fstatePath(nf);
+
+        if (hashPath(path) != hash)
+            throw Error(format("bad substitute in `%1%'") % (string) path);
+
+        if (target.empty())
+            return path; /* !!! prefix */
+        else {
+            if (path != target) {
+                copyPath(path, target);
+                registerPath(target, hash);
+            }
+            return target;
+        }
+    }
     
-    throw Error(format("all paths with hash `%1%' are stale") % (string) hash);
+    throw Error(format("cannot expand hash `%1%'") % (string) hash);
 }
 
     
@@ -193,6 +231,7 @@ void addToStore(string srcPath, string & dstPath, Hash & hash)
     hash = hashPath(srcPath);
 
     try {
+        /* !!! should not use the substitutes! */
         dstPath = expandHash(hash, "", nixStore);
         return;
     } catch (...) {
diff --git a/src/store.hh b/src/store.hh
index 8b02cba99681..8b41478a24af 100644
--- a/src/store.hh
+++ b/src/store.hh
@@ -8,8 +8,12 @@
 using namespace std;
 
 
+/* Copy a path recursively. */
 void copyPath(string src, string dst);
 
+/* Register a substitute. */
+void registerSubstitute(const Hash & srcHash, const Hash & subHash);
+
 /* Register a path keyed on its hash. */
 Hash registerPath(const string & path, Hash hash = Hash());