about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/nix.cc116
-rwxr-xr-xtest/build/aterm-build.sh2
-rwxr-xr-xtest/register18
3 files changed, 115 insertions, 21 deletions
diff --git a/src/nix.cc b/src/nix.cc
index c9091ef7ac79..d446479282dd 100644
--- a/src/nix.cc
+++ b/src/nix.cc
@@ -35,6 +35,7 @@ using namespace std;
 
 static string dbRefs = "refs";
 static string dbInstPkgs = "pkginst";
+static string dbPrebuilts = "prebuilts";
 
 
 static string prog;
@@ -307,6 +308,14 @@ string getFromEnv(const Environment & env, const string & key)
 }
 
 
+string queryPkgId(const string & hash)
+{
+    Params pkgImports, fileImports, arguments;
+    readPkgDescr(hash, pkgImports, fileImports, arguments);
+    return getFromEnv(arguments, "id");
+}
+
+
 void installPkg(string hash)
 {
     string pkgfile;
@@ -321,8 +330,10 @@ void installPkg(string hash)
 
     builder = getFromEnv(env, "build");
 
+    string id = getFromEnv(env, "id");
+
     /* Construct a path for the installed package. */
-    path = pkgHome + "/" + hash;
+    path = pkgHome + "/" + id + "-" + hash;
 
     /* Create the path. */
     if (mkdir(path.c_str(), 0777))
@@ -341,10 +352,33 @@ void installPkg(string hash)
 
             /* Go to the build directory. */
             if (chdir(path.c_str())) {
-                cout << "unable to chdir to package directory\n";
+                cerr << "unable to chdir to package directory\n";
                 _exit(1);
             }
 
+            /* Try to use a prebuilt. */
+            string prebuiltHash, prebuiltFile;
+            if (queryDB(dbPrebuilts, hash, prebuiltHash) &&
+                queryDB(dbRefs, prebuiltHash, prebuiltFile)) 
+            {
+                cerr << "substituting prebuilt " << prebuiltFile << endl;
+
+                if (hashFile(prebuiltFile) != prebuiltHash) {
+                    cerr << "prebuilt " + prebuiltFile + " is stale\n";
+                    goto build;
+                }
+
+                int res = system(("tar xvfj " + prebuiltFile).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);
+            }
+
+build:
+
             /* Fill in the environment.  We don't bother freeing the
                strings, since we'll exec or die soon anyway. */
             const char * env2[env.size() + 1];
@@ -357,9 +391,9 @@ void installPkg(string hash)
             /* Execute the builder.  This should not return. */
             execle(builder.c_str(), builder.c_str(), 0, env2);
 
-            cout << strerror(errno) << endl;
+            cerr << strerror(errno) << endl;
 
-            cout << "unable to execute builder\n";
+            cerr << "unable to execute builder\n";
             _exit(1); }
 
         }
@@ -427,7 +461,7 @@ void runPkg(string hash, const vector<string> & args)
     /* Execute the runner.  This should not return. */
     execv(runner.c_str(), (char * *) args2);
 
-    cout << strerror(errno) << endl;
+    cerr << strerror(errno) << endl;
     throw Error("unable to execute runner");
 }
 
@@ -446,6 +480,50 @@ void ensurePkg(string hash)
 }
 
 
+void delPkg(string hash)
+{
+    string path;
+    checkHash(hash);
+    if (queryDB(dbInstPkgs, hash, path)) {
+        int res = system(("rm -rf " + path).c_str()); // !!! escaping
+        delDB(dbInstPkgs, hash); // not a bug
+        if (WEXITSTATUS(res) != 0)
+            throw Error("cannot delete " + path);
+    }
+}
+
+
+void exportPkgs(string outDir, vector<string> hashes)
+{
+    for (vector<string>::iterator it = hashes.begin();
+         it != hashes.end(); it++)
+    {
+        string hash = *it;
+        string pkgDir = getPkg(hash);
+        string tmpFile = outDir + "/export_tmp";
+
+        int res = system(("cd " + pkgDir + " && tar cvfj " + tmpFile + " .").c_str()); // !!! escaping
+        if (WEXITSTATUS(res) != 0)
+            throw Error("cannot tar " + pkgDir);
+
+        string prebuiltHash = hashFile(tmpFile);
+        string pkgId = queryPkgId(hash);
+        string prebuiltFile = outDir + "/" +
+            pkgId + "-" + hash + "-" + prebuiltHash + ".tar.bz2";
+        
+        rename(tmpFile.c_str(), prebuiltFile.c_str());
+    }
+}
+
+
+void regPrebuilt(string pkgHash, string prebuiltHash)
+{
+    checkHash(pkgHash);
+    checkHash(prebuiltHash);
+    setDB(dbPrebuilts, pkgHash, prebuiltHash);
+}
+
+
 string absPath(string filename)
 {
     if (filename[0] != '/') {
@@ -481,6 +559,7 @@ void initDB()
 {
     openDB(dbRefs, false);
     openDB(dbInstPkgs, false);
+    openDB(dbPrebuilts, false);
 }
 
 
@@ -543,10 +622,8 @@ void printInfo(vector<string> hashes)
          it != hashes.end(); it++)
     {
         try {
-            Params pkgImports, fileImports, arguments;
-            readPkgDescr(*it, pkgImports, fileImports, arguments);
-            cout << *it << " " << getFromEnv(arguments, "id") << endl;
-        } catch (Error & e) {
+            cout << *it << " " << queryPkgId(*it) << endl;
+        } catch (Error & e) { // !!! more specific
             cout << *it << " (descriptor missing)\n";
         }
     }
@@ -642,12 +719,21 @@ void run(vector<string> args)
         if (args.size() != 1) throw argcError;
         string path = getPkg(args[0]);
         cout << path << endl;
+    } else if (cmd == "delpkg") {
+        if (args.size() != 1) throw argcError;
+        delPkg(args[0]);
     } else if (cmd == "run") {
         if (args.size() < 1) throw argcError;
         runPkg(args[0], vector<string>(args.begin() + 1, args.end()));
     } else if (cmd == "ensure") {
         if (args.size() != 1) throw argcError;
         ensurePkg(args[0]);
+    } else if (cmd == "export") {
+        if (args.size() < 1) throw argcError;
+        exportPkgs(args[0], vector<string>(args.begin() + 1, args.end()));
+    } else if (cmd == "regprebuilt") {
+        if (args.size() != 2) throw argcError;
+        regPrebuilt(args[0], args[1]);
     } else if (cmd == "regfile") {
         if (args.size() != 1) throw argcError;
         registerFile(args[0]);
@@ -688,9 +774,13 @@ Subcommands:
     Register an installed package.
 
   getpkg HASH
-    Ensure that the package referenced by HASH is installed. Prints
+    Ensure that the package referenced by HASH is installed. Print
     out the path of the package on stdout.
 
+  delpkg HASH
+    Uninstall the package referenced by HASH, disregarding any
+    dependencies that other packages may have on HASH.
+
   listinst
     Prints a list of installed packages.
 
@@ -701,6 +791,12 @@ Subcommands:
     Like getpkg, but if HASH refers to a run descriptor, fetch only
     the dependencies.
 
+  export DIR HASH...
+    Export installed packages to DIR.
+
+  regprebuilt HASH1 HASH2
+    Inform Nix that an export HASH2 can be used to fast-build HASH1.
+
   info HASH...
     Print information about the specified descriptors.
 
diff --git a/test/build/aterm-build.sh b/test/build/aterm-build.sh
index cfc83806b35b..f8cca71aa0bb 100755
--- a/test/build/aterm-build.sh
+++ b/test/build/aterm-build.sh
@@ -8,3 +8,5 @@ cd aterm-*
 ./configure --prefix=$top
 make
 make install
+cd ..
+rm -rf aterm-*
diff --git a/test/register b/test/register
index 60cabd292365..e03296495a92 100755
--- a/test/register
+++ b/test/register
@@ -1,23 +1,19 @@
 #! /bin/sh
 
-root=/home/eelco/Dev/nix/test
-cd $root
-
-mkdir -p db
-mkdir -p pkg
-mkdir -p descr
-mkdir -p netcache
+mkdir -p $NIX/db
+mkdir -p $NIX/pkg
+mkdir -p $NIX/descr
+mkdir -p $NIX/netcache
 
 nix init
 
-if ! nix-instantiate descr netcache tmpl/*.nix; then
+if ! nix-instantiate $NIX/descr $NIX/netcache tmpl/*.nix; then
     exit 1;
 fi
 
-for i in netcache/*; do nix regfile $i; done
+for i in $NIX/netcache/*; do nix regfile $i; done
 for i in build/*; do nix regfile $i; done
-for i in descr/*; do 
+for i in $NIX/descr/*; do 
     md5sum $i
     nix regfile $i
 done
-