about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-11-13T18·18+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-11-13T18·18+0000
commite2a70b7ec04db604e9eaadfa6446bd360473163a (patch)
treeae5929ad421d25040f1255136e064ae8fb41f535
parente40d4a5604a75540d94782d405dfff2000143f61 (diff)
* Magic attribute `exportReferencesGraph' that allows the references
  graph to be passed to a builder.  This attribute should be a list of
  pairs [name1 path1 name2 path2 ...].  The references graph of each
  `pathN' will be stored in a text file `nameN' in the temporary build
  directory.  The text files have the format used by `nix-store
  --register-validity'.  However, the deriver fields are left empty.

  `exportReferencesGraph' is useful for builders that want to do
  something with the closure of a store path.  Examples: the builders
  that make initrds and ISO images for NixOS.

  `exportReferencesGraph' is entirely pure.  It's necessary because
  otherwise the only way for a builder to get this information would
  be to call `nix-store' directly, which is not allowed (though
  unfortunately possible).

-rw-r--r--doc/manual/release-notes.xml6
-rw-r--r--src/libstore/build.cc76
-rw-r--r--src/libstore/store.cc4
3 files changed, 65 insertions, 21 deletions
diff --git a/doc/manual/release-notes.xml b/doc/manual/release-notes.xml
index 098e2a4497d8..00c8042098fb 100644
--- a/doc/manual/release-notes.xml
+++ b/doc/manual/release-notes.xml
@@ -30,8 +30,12 @@
   <listitem><para>TODO: now using Berkeley DB 4.5.</para></listitem>
 
 
-  <listitem><para>Option <option>--reregister</option> in
+  <listitem><para>TODO: option <option>--reregister</option> in
   <command>nix-store --register-validity</command>.</para></listitem>
+
+
+  <listitem><para>TODO: magic <varname>exportReferencesGraph</varname>
+  attribute.</para></listitem>
     
 
 </itemizedlist>
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index 43ac5cf53f84..82f713c8c8c7 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -901,6 +901,34 @@ string showPaths(const PathSet & paths)
 }
 
 
+/* Return a string accepted by `nix-store --register-validity' that
+   registers the specified paths as valid.  Note: it's the
+   responsibility of the caller to provide a closure. */
+static string makeValidityRegistration(const PathSet & paths,
+    bool showDerivers)
+{
+    string s = "";
+    
+    for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
+        s += *i + "\n";
+
+        Path deriver = showDerivers ? queryDeriver(noTxn, *i) : "";
+        s += deriver + "\n";
+
+        PathSet references;
+        queryReferences(noTxn, *i, references);
+
+        s += (format("%1%\n") % references.size()).str();
+            
+        for (PathSet::iterator j = references.begin();
+             j != references.end(); ++j)
+            s += *j + "\n";
+    }
+
+    return s;
+}
+
+
 DerivationGoal::HookReply DerivationGoal::tryBuildHook()
 {
     Path buildHook = getEnv("NIX_BUILD_HOOK");
@@ -1024,26 +1052,8 @@ DerivationGoal::HookReply DerivationGoal::tryBuildHook()
 
         /* The `references' file has exactly the format accepted by
            `nix-store --register-validity'. */
-        s = "";
-        for (PathSet::iterator i = allInputs.begin();
-             i != allInputs.end(); ++i)
-        {
-            s += *i + "\n";
-            
-            Path deriver = queryDeriver(noTxn, *i);
-            s += deriver + "\n";
-
-            PathSet references;
-            queryReferences(noTxn, *i, references);
-
-            s += (format("%1%\n") % references.size()).str();
-            
-            for (PathSet::iterator j = references.begin();
-                 j != references.end(); ++j)
-                s += *j + "\n";
-        }
-        
-        writeStringToFile(referencesFN, s);
+        writeStringToFile(referencesFN,
+            makeValidityRegistration(allInputs, true));
 
         /* Tell the hook to proceed. */ 
         writeLine(toHook.writeSide, "okay");
@@ -1235,6 +1245,32 @@ void DerivationGoal::startBuilder()
             env[*i] = getEnv(*i);
     }
 
+    /* The `exportReferencesGraph' feature allows the references graph
+       to be passed to a builder.  This attribute should be a list of
+       pairs [name1 path1 name2 path2 ...].  The references graph of
+       each `pathN' will be stored in a text file `nameN' in the
+       temporary build directory.  The text files have the format used
+       by `nix-store --register-validity'.  However, the deriver
+       fields are left empty. */
+    string s = drv.env["exportReferencesGraph"];
+    Strings ss = tokenizeString(s);
+    if (ss.size() % 2 != 0)
+        throw Error(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s);
+    for (Strings::iterator i = ss.begin(); i != ss.end(); ) {
+        string fileName = *i++;
+        Path storePath = *i++;
+        if (!isValidPath(storePath))
+            throw Error(format("`exportReferencesGraph' refers to an invalid path `%1%'")
+                % storePath);
+        checkStoreName(fileName); /* !!! abuse of this function */
+        PathSet refs;
+        computeFSClosure(storePath, refs);
+        /* !!! in secure Nix, the writing should be done on the
+           build uid for security (maybe). */
+        writeStringToFile(tmpDir + "/" + fileName,
+            makeValidityRegistration(refs, false));
+    }
+
     
     /* If we are running as root, and the `build-allow-root' setting
        is `false', then we have to build as one of the users listed in
diff --git a/src/libstore/store.cc b/src/libstore/store.cc
index f8441af9cb42..e073d64adaff 100644
--- a/src/libstore/store.cc
+++ b/src/libstore/store.cc
@@ -259,6 +259,10 @@ Path toStorePath(const Path & path)
 void checkStoreName(const string & name)
 {
     string validChars = "+-._?=";
+    /* Disallow names starting with a dot for possible security
+       reasons (e.g., "." and ".."). */
+    if (string(name, 0, 1) == ".")
+        throw Error(format("illegal name: `%1%'") % name);
     for (string::const_iterator i = name.begin(); i != name.end(); ++i)
         if (!((*i >= 'A' && *i <= 'Z') ||
               (*i >= 'a' && *i <= 'z') ||