From d367b8e7875161e655deaa96bf8a5dd0bcf8229e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Sun, 31 Jan 2016 12:06:45 +0100 Subject: [PATCH] Add build mode to compute fixed-output derivation hashes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For example, $ nix-build --hash -A nix-repl.src will build the fixed-output derivation nix-repl.src (a fetchFromGitHub call), but instead of *verifying* the hash given in the Nix expression, it prints out the resulting hash, and then moves the result to its content-addressed location in the Nix store. E.g build produced path ‘/nix/store/504a4k6zi69dq0yjc0bm12pa65bccxam-nix-repl-8a2f5f0607540ffe56b56d52db544373e1efb980-src’ with sha256 hash ‘0cjablz01i0g9smnavhf86imwx1f9mnh5flax75i615ml71gsr88’ The goal of this is to make all nix-prefetch-* scripts unnecessary: we can just let Nix run the real thing (i.e., the corresponding fetch* derivation). Another example: $ nix-build --hash -E 'with import {}; fetchgit { url = "https://github.com/NixOS/nix.git"; sha256 = "ffffffffffffffffffffffffffffffffffffffffffffffffffff"; }' ... git revision is 9e7c1a4bbdbe6129dd9dc385776612c307d3d1bb ... build produced path ‘/nix/store/gmsnh9i7x4mb7pyd2ns7n3c9l90jfsi1-nix’ with sha256 hash ‘1188xb621diw89n25rifqg9lxnzpz7nj5bfh4i1y3dnis0dmc0zp’ (Having to specify a fake sha256 hash is a bit annoying...) --- src/libstore/build.cc | 38 ++++++++++++++++++++++++++++++++------ src/libstore/store-api.hh | 2 +- src/nix-store/nix-store.cc | 1 + 3 files changed, 34 insertions(+), 7 deletions(-) diff --git a/src/libstore/build.cc b/src/libstore/build.cc index af068fc59..9b9621dc1 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1045,6 +1045,15 @@ void DerivationGoal::haveDerivation() for (auto & i : invalidOutputs) if (pathFailed(i)) return; + /* Reject doing a hash build of anything other than a fixed-output + derivation. */ + if (buildMode == bmHash) { + if (drv->outputs.size() != 1 || + drv->outputs.find("out") == drv->outputs.end() || + drv->outputs["out"].hashAlgo == "") + throw Error(format("cannot do a hash build of non-fixed-output derivation ‘%1%’") % drvPath); + } + /* We are first going to try to create the invalid output paths through substitutes. If that doesn't work, we'll build them. */ @@ -2727,12 +2736,29 @@ void DerivationGoal::registerOutputs() format("output path ‘%1%’ should be a non-executable regular file") % path); } - /* Check the hash. */ + /* Check the hash. In hash mode, move the path produced by + the derivation to its content-addressed location. */ Hash h2 = recursive ? hashPath(ht, actualPath).first : hashFile(ht, actualPath); - if (h != h2) - throw BuildError( - format("output path ‘%1%’ has %2% hash ‘%3%’ when ‘%4%’ was expected") - % path % i.second.hashAlgo % printHash16or32(h2) % printHash16or32(h)); + if (buildMode == bmHash) { + Path dest = makeFixedOutputPath(recursive, ht, h2, drv->env["name"]); + printMsg(lvlError, format("build produced path ‘%1%’ with %2% hash ‘%3%’") + % dest % printHashType(ht) % printHash16or32(h2)); + if (worker.store.isValidPath(dest)) + return; + if (actualPath != dest) { + PathLocks outputLocks({dest}); + if (pathExists(dest)) + deletePath(dest); + if (rename(actualPath.c_str(), dest.c_str()) == -1) + throw SysError(format("moving ‘%1%’ to ‘%2%’") % actualPath % dest); + } + path = actualPath = dest; + } else { + if (h != h2) + throw BuildError( + format("output path ‘%1%’ has %2% hash ‘%3%’ when ‘%4%’ was expected") + % path % i.second.hashAlgo % printHash16or32(h2) % printHash16or32(h)); + } } /* Get rid of all weird permissions. This also checks that @@ -2748,7 +2774,7 @@ void DerivationGoal::registerOutputs() PathSet references = scanForReferences(actualPath, allPaths, hash); if (buildMode == bmCheck) { - if (!store->isValidPath(path)) continue; + if (!worker.store.isValidPath(path)) continue; ValidPathInfo info = worker.store.queryPathInfo(path); if (hash.first != info.hash) { if (settings.keepFailed) { diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 9cc5fd45b..9fa137030 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -103,7 +103,7 @@ struct ValidPathInfo typedef list ValidPathInfos; -enum BuildMode { bmNormal, bmRepair, bmCheck }; +enum BuildMode { bmNormal, bmRepair, bmCheck, bmHash }; struct BuildResult diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index 22b3be27a..df6afd979 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -117,6 +117,7 @@ static void opRealise(Strings opFlags, Strings opArgs) if (i == "--dry-run") dryRun = true; else if (i == "--repair") buildMode = bmRepair; else if (i == "--check") buildMode = bmCheck; + else if (i == "--hash") buildMode = bmHash; else if (i == "--ignore-unknown") ignoreUnknown = true; else throw UsageError(format("unknown flag ‘%1%’") % i);