aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/build.cc
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2016-01-31 12:06:45 +0100
committerEelco Dolstra <eelco.dolstra@logicblox.com>2016-01-31 12:18:09 +0100
commitd367b8e7875161e655deaa96bf8a5dd0bcf8229e (patch)
tree9a4a7c0e60d1f1070c3dc35aed84e50a714cd9b7 /src/libstore/build.cc
parent9e7c1a4bbdbe6129dd9dc385776612c307d3d1bb (diff)
Add build mode to compute fixed-output derivation hashes
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 <nixpkgs> {}; 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...)
Diffstat (limited to 'src/libstore/build.cc')
-rw-r--r--src/libstore/build.cc38
1 files changed, 32 insertions, 6 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) {