about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/fix.cc30
-rw-r--r--src/fstate.cc148
-rw-r--r--src/fstate.hh13
-rw-r--r--src/nix.cc90
-rw-r--r--src/util.cc12
-rw-r--r--src/util.hh2
6 files changed, 198 insertions, 97 deletions
diff --git a/src/fix.cc b/src/fix.cc
index 87ce7c775a10..508a441167bc 100644
--- a/src/fix.cc
+++ b/src/fix.cc
@@ -13,29 +13,6 @@ typedef ATerm Expr;
 static Expr evalFile(string fileName);
 
 
-static bool isFState(Expr e, string & path)
-{
-    char * s1, * s2, * s3;
-    Expr e1, e2;
-    if (ATmatch(e, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2)) {
-        path = s1;
-        return true;
-    }
-    else if (ATmatch(e, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
-                   &s1, &s2, &e1, &s3, &e2))
-    {
-        path = s3;
-        return true;
-    }
-    else if (ATmatch(e, "Include(<str>)", &s1))
-    {
-        string fn = queryPathByHash(parseHash(s1));
-        return isFState(evalFile(fn), path);
-    }
-    else return false;
-}
-
-
 static Expr substExpr(string x, Expr rep, Expr e)
 {
     char * s;
@@ -113,8 +90,7 @@ static Expr evalExpr(Expr e)
         ATmatch(e, "Function([<list>], <term>)", &e1, &e2))
         return e;
 
-    string dummy;
-    if (isFState(e, dummy)) return e;
+    if (fstatePath(e) != "") return e; /* !!! hack */
 
     /* Application. */
     if (ATmatch(e, "App(<term>, [<list>])", &e1, &e2)) {
@@ -165,8 +141,8 @@ static Expr evalExpr(Expr e)
             string key = it->first;
             ATerm value = it->second;
 
-            string path;
-            if (isFState(value, path)) {
+            string path = fstatePath(value);
+            if (path != "") {
                 ins = ATinsert(ins, value);
                 env = ATinsert(env, ATmake("(<str>, <str>)",
                     key.c_str(), path.c_str()));
diff --git a/src/fstate.cc b/src/fstate.cc
index 2e3ffd639c56..fa677a257a14 100644
--- a/src/fstate.cc
+++ b/src/fstate.cc
@@ -1,4 +1,5 @@
 #include <map>
+#include <set>
 #include <iostream>
 
 #include <sys/types.h>
@@ -17,17 +18,20 @@
 typedef map<string, string> Environment;
 
 
-/* Return true iff the given path exists. */
-bool pathExists(const string & path)
+class AutoDelete
 {
-    int res;
-    struct stat st;
-    res = stat(path.c_str(), &st);
-    if (!res) return true;
-    if (errno != ENOENT)
-        throw SysError(format("getting status of %1%") % path);
-    return false;
-}
+    string path;
+public:
+
+    AutoDelete(const string & p) : path(p) 
+    {
+    }
+
+    ~AutoDelete()
+    {
+        deletePath(path);
+    }
+};
 
 
 /* Run a program. */
@@ -36,9 +40,19 @@ static void runProgram(const string & program, Environment env)
     /* Create a log file. */
     string logFileName = nixLogDir + "/run.log";
     /* !!! auto-pclose on exit */
-    FILE * logFile = popen(("tee " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
+    FILE * logFile = popen(("tee -a " + logFileName + " >&2").c_str(), "w"); /* !!! escaping */
     if (!logFile)
-        throw SysError(format("unable to create log file %1%") % logFileName);
+        throw SysError(format("creating log file `%1%'") % logFileName);
+
+    /* Create a temporary directory where the build will take
+       place. */
+    static int counter = 0;
+    string tmpDir = (format("/tmp/nix-%1%-%2%") % getpid() % counter++).str();
+
+    if (mkdir(tmpDir.c_str(), 0777) == -1)
+        throw SysError(format("creating directory `%1%'") % tmpDir);
+
+    AutoDelete delTmpDir(tmpDir);
 
     /* Fork a child to build the package. */
     pid_t pid;
@@ -51,31 +65,8 @@ static void runProgram(const string & program, Environment env)
 
         try { /* child */
 
-#if 0
-            /* Try to use a prebuilt. */
-            string prebuiltHashS, prebuiltFile;
-            if (queryDB(nixDB, dbPrebuilts, hash, prebuiltHashS)) {
-
-                try {
-                    prebuiltFile = getFile(parseHash(prebuiltHashS));
-                } catch (Error e) {
-                    cerr << "cannot obtain prebuilt (ignoring): " << e.what() << endl;
-                    goto build;
-                }
-                
-                cerr << "substituting prebuilt " << prebuiltFile << endl;
-
-                int res = system(("tar xfj " + prebuiltFile + " 1>&2").c_str()); // !!! escaping
-                if (WEXITSTATUS(res) != 0)
-                    /* This is a fatal error, because path may now
-                       have clobbered. */
-                    throw Error("cannot unpack " + prebuiltFile);
-
-                _exit(0);
-            }
-#endif
-
-            //             build:
+            if (chdir(tmpDir.c_str()) == -1)
+                throw SysError(format("changing into to `%1%'") % tmpDir);
 
             /* Fill in the environment.  We don't bother freeing
                the strings, since we'll exec or die soon
@@ -157,15 +148,7 @@ Hash hashTerm(ATerm t)
 }
 
 
-struct RStatus
-{
-    /* !!! the comparator of this hash should match the semantics of
-       the file system */
-//     map<string, Hash> paths;
-};
-
-
-static ATerm termFromHash(const Hash & hash)
+ATerm termFromHash(const Hash & hash)
 {
     string path = queryPathByHash(hash);
     ATerm t = ATreadFromNamedFile(path.c_str());
@@ -188,7 +171,7 @@ Hash writeTerm(ATerm t)
 }
 
 
-static FState realise(RStatus & status, FState fs)
+static FState realise(FState fs)
 {
     char * s1, * s2, * s3;
     Content content;
@@ -212,7 +195,7 @@ static FState realise(RStatus & status, FState fs)
     /* Fall through. */
 
     if (ATmatch(fs, "Include(<str>)", &s1)) {
-        return realise(status, termFromHash(parseHash(s1)));
+        return realise(termFromHash(parseHash(s1)));
     }
     
     else if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &content, &refs)) {
@@ -227,7 +210,7 @@ static FState realise(RStatus & status, FState fs)
         /* Realise referenced paths. */
         ATermList refs2 = ATempty;
         while (!ATisEmpty(refs)) {
-            refs2 = ATinsert(refs2, realise(status, ATgetFirst(refs)));
+            refs2 = ATinsert(refs2, realise(ATgetFirst(refs)));
             refs = ATgetNext(refs);
         }
         refs2 = ATreverse(refs2);
@@ -278,7 +261,7 @@ static FState realise(RStatus & status, FState fs)
         /* Realise inputs. */
         ATermList ins2 = ATempty;
         while (!ATisEmpty(ins)) {
-            ins2 = ATinsert(ins2, realise(status, ATgetFirst(ins)));
+            ins2 = ATinsert(ins2, realise(ATgetFirst(ins)));
             ins = ATgetNext(ins);
         }
         ins2 = ATreverse(ins2);
@@ -335,6 +318,67 @@ static FState realise(RStatus & status, FState fs)
 
 FState realiseFState(FState fs)
 {
-    RStatus status;
-    return realise(status, fs);
+    return realise(fs);
+}
+
+
+string fstatePath(FState fs)
+{
+    char * s1, * s2, * s3;
+    FState e1, e2;
+    if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &e2))
+        return s1;
+    else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])",
+                   &s1, &s2, &e1, &s3, &e2))
+        return s3;
+    else if (ATmatch(fs, "Include(<str>)", &s1))
+        return fstatePath(termFromHash(parseHash(s1)));
+    else
+        return "";
+}
+
+
+typedef set<string> StringSet;
+
+
+void fstateRefs2(FState fs, StringSet & paths)
+{
+    char * s1, * s2, * s3;
+    FState e1, e2;
+    ATermList refs, ins;
+
+    if (ATmatch(fs, "Path(<str>, <term>, [<list>])", &s1, &e1, &refs)) {
+        paths.insert(s1);
+
+        while (!ATisEmpty(refs)) {
+            fstateRefs2(ATgetFirst(refs), paths);
+            refs = ATgetNext(refs);
+        }
+    }
+
+    else if (ATmatch(fs, "Derive(<str>, <str>, [<list>], <str>, [<list>])", 
+            &s1, &s2, &ins, &s3, &e2))
+    {
+        paths.insert(s3);
+
+        while (!ATisEmpty(ins)) {
+            fstateRefs2(ATgetFirst(ins), paths);
+            ins = ATgetNext(ins);
+        }
+    }
+
+    else if (ATmatch(fs, "Include(<str>)", &s1))
+        fstateRefs2(termFromHash(parseHash(s1)), paths);
+
+    else throw badTerm("bad fstate expression", fs);
+}
+
+
+Strings fstateRefs(FState fs)
+{
+    StringSet paths;
+    fstateRefs2(fs, paths);
+    Strings paths2(paths.size());
+    copy(paths.begin(), paths.end(), paths2.begin());
+    return paths2;
 }
diff --git a/src/fstate.hh b/src/fstate.hh
index b04588e7b35b..de6303dca1e4 100644
--- a/src/fstate.hh
+++ b/src/fstate.hh
@@ -60,9 +60,17 @@ typedef ATerm FState;
 typedef ATerm Content;
 
 
-/* Realise a $f$-normalised expression in the file system. */
+/* Realise an fstate expression in the file system.  This requires
+   execution of all Derive() nodes. */
 FState realiseFState(FState fs);
 
+/* Return the path of an fstate expression.  An empty string is
+   returned if the term is not a valid fstate expression. (!!!) */
+string fstatePath(FState fs);
+
+/* Return the paths referenced by fstate expression. */
+Strings fstateRefs(FState fs);
+
 /* Return a canonical textual representation of an expression. */
 string printTerm(ATerm t);
 
@@ -73,6 +81,9 @@ Error badTerm(const format & f, ATerm t);
 /* Hash an aterm. */
 Hash hashTerm(ATerm t);
 
+/* Read an aterm from disk, given its hash. */
+ATerm termFromHash(const Hash & hash);
+
 /* Write an aterm to the Nix store directory, and return its hash. */
 Hash writeTerm(ATerm t);
 
diff --git a/src/nix.cc b/src/nix.cc
index 0e515457243b..ec4c91788efd 100644
--- a/src/nix.cc
+++ b/src/nix.cc
@@ -21,9 +21,10 @@ static ArgType argType = atpUnknown;
 
    Operations:
 
-     --install / -i: realise a Nix expression
+     --install / -i: realise an fstate
      --delete / -d: delete paths from the Nix store
      --add / -A: copy a path to the Nix store
+     --query / -q: query information
 
      --dump: dump a path as a Nix archive
      --restore: restore a path from a Nix archive
@@ -39,6 +40,11 @@ static ArgType argType = atpUnknown;
      --file / -f: by file name
      --hash / -h: by hash
 
+   Query flags:
+
+     --path / -p: query the path of an fstate 
+     --refs / -r: query paths referenced by an fstate
+
    Options:
 
      --verbose / -v: verbose operation
@@ -54,10 +60,8 @@ static void getArgType(Strings & flags)
     {
         string arg = *it;
         ArgType tp;
-        if (arg == "--hash" || arg == "-h")
-            tp = atpHash;
-        else if (arg == "--file" || arg == "-f")
-            tp = atpPath;
+        if (arg == "--hash" || arg == "-h") tp = atpHash;
+        else if (arg == "--file" || arg == "-f") tp = atpPath;
         else { it++; continue; }
         if (argType != atpUnknown)
             throw UsageError("only one argument type specified may be specified");
@@ -69,6 +73,20 @@ static void getArgType(Strings & flags)
 }
 
 
+static Hash argToHash(const string & arg)
+{
+    if (argType == atpHash)
+        return parseHash(arg);
+    else if (argType == atpPath) {
+        string path;
+        Hash hash;
+        addToStore(arg, path, hash);
+        return hash;
+    }
+    else abort();
+}
+
+
 /* Realise (or install) paths from the given Nix fstate
    expressions. */
 static void opInstall(Strings opFlags, Strings opArgs)
@@ -78,20 +96,11 @@ static void opInstall(Strings opFlags, Strings opArgs)
 
     for (Strings::iterator it = opArgs.begin();
          it != opArgs.end(); it++)
-    {
-        Hash hash;
-        if (argType == atpHash)
-            hash = parseHash(*it);
-        else if (argType == atpPath) {
-            string path;
-            addToStore(*it, path, hash);
-        }
-        FState fs = ATmake("Include(<str>)", ((string) hash).c_str());
-        realiseFState(fs);
-    }
+        realiseFState(termFromHash(argToHash(*it)));
 }
 
 
+/* Delete a path in the Nix store directory. */
 static void opDelete(Strings opFlags, Strings opArgs)
 {
     if (!opFlags.empty()) throw UsageError("unknown flag");
@@ -120,6 +129,51 @@ static void opAdd(Strings opFlags, Strings opArgs)
 }
 
 
+/* Perform various sorts of queries. */
+static void opQuery(Strings opFlags, Strings opArgs)
+{
+    enum { qPath, qRefs, qUnknown } query = qPath;
+
+    for (Strings::iterator it = opFlags.begin();
+         it != opFlags.end(); )
+    {
+        string arg = *it;
+        if (arg == "--path" || arg == "-p") query = qPath;
+        else if (arg == "--refs" || arg == "-r") query = qRefs;
+        else { it++; continue; }
+        it = opFlags.erase(it);
+    }
+
+    getArgType(opFlags);
+    if (!opFlags.empty()) throw UsageError("unknown flag");
+
+    for (Strings::iterator it = opArgs.begin();
+         it != opArgs.end(); it++)
+    {
+        Hash hash = argToHash(*it);
+
+        switch (query) {
+
+        case qPath:
+            cout << format("%s\n") % 
+                (string) fstatePath(termFromHash(hash));
+            break;
+
+        case qRefs: {
+            Strings refs = fstateRefs(termFromHash(hash));
+            for (Strings::iterator j = refs.begin(); 
+                 j != refs.end(); j++)
+                cout << format("%s\n") % *j;
+            break;
+        }
+
+        default:
+            abort();
+        }
+    }
+}
+
+
 /* A sink that writes dump output to stdout. */
 struct StdoutSink : DumpSink
 {
@@ -208,8 +262,10 @@ void run(Strings args)
             op = opInstall;
         else if (arg == "--delete" || arg == "-d")
             op = opDelete;
-        else if (arg == "--add")
+        else if (arg == "--add" || arg == "-A")
             op = opAdd;
+        else if (arg == "--query" || arg == "-q")
+            op = opQuery;
         else if (arg == "--dump")
             op = opDump;
         else if (arg == "--restore")
diff --git a/src/util.cc b/src/util.cc
index 2f9c43e55ce5..8ccd3c1524d8 100644
--- a/src/util.cc
+++ b/src/util.cc
@@ -66,6 +66,18 @@ string baseNameOf(string path)
 }
 
 
+bool pathExists(const string & path)
+{
+    int res;
+    struct stat st;
+    res = stat(path.c_str(), &st);
+    if (!res) return true;
+    if (errno != ENOENT)
+        throw SysError(format("getting status of %1%") % path);
+    return false;
+}
+
+
 void deletePath(string path)
 {
     struct stat st;
diff --git a/src/util.hh b/src/util.hh
index a8f801b30c5d..684bafbb55d6 100644
--- a/src/util.hh
+++ b/src/util.hh
@@ -60,6 +60,8 @@ string dirOf(string path);
    the final `/'. */
 string baseNameOf(string path);
 
+/* Return true iff the given path exists. */
+bool pathExists(const string & path);
 
 /* Delete a path; i.e., in the case of a directory, it is deleted
    recursively.  Don't use this at home, kids. */