diff --git a/src/nix.cc b/src/nix.cc index c9091ef7a..d44647928 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 & 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 hashes) +{ + for (vector::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 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 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(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(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 cfc83806b..f8cca71aa 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 60cabd292..e03296495 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 -