Remove nix-build --hash

Instead, if a fixed-output derivation produces has an incorrect output
hash, we now unconditionally move the outputs to the path
corresponding with the actual hash and register it as valid. Thus,
after correcting the hash in the Nix expression (e.g. in a fetchurl
call), the fixed-output derivation doesn't have to be built again.

It would still be good to have a command for reporting the actual hash
of a fixed-output derivation (instead of throwing an error), but
"nix-build --hash" didn't do that.
This commit is contained in:
Eelco Dolstra 2018-02-03 10:04:29 +01:00
parent de96daf54f
commit 84722d67d2
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
6 changed files with 43 additions and 33 deletions

View file

@ -99,11 +99,11 @@
</listitem> </listitem>
<listitem> <listitem>
<para>New build mode <command>nix-build --hash</command> that <para>If a fixed-output derivation produces a result with an
builds a derivation, computes the hash of the output, and moves incorrect hash, the output path will be moved to the location
the output to the store path corresponding to what a fixed-output corresponding to the actual hash and registered as valid. Thus, a
derivation with that hash would produce. subsequent build of the fixed-output derivation with the correct
(Add docs and examples; see d367b8e7875161e655deaa96bf8a5dd0bcf8229e)</para> hash is unnecessary.</para>
</listitem> </listitem>
<listitem> <listitem>

View file

@ -1124,11 +1124,6 @@ void DerivationGoal::haveDerivation()
return; return;
} }
/* Reject doing a hash build of anything other than a fixed-output
derivation. */
if (buildMode == bmHash && !drv->isFixedOutput())
throw Error("cannot do a hash build of non-fixed-output derivation '%1%'", drvPath);
/* We are first going to try to create the invalid output paths /* We are first going to try to create the invalid output paths
through substitutes. If that doesn't work, we'll build through substitutes. If that doesn't work, we'll build
them. */ them. */
@ -1320,9 +1315,7 @@ void DerivationGoal::inputsRealised()
allPaths.insert(inputPaths.begin(), inputPaths.end()); allPaths.insert(inputPaths.begin(), inputPaths.end());
/* Is this a fixed-output derivation? */ /* Is this a fixed-output derivation? */
fixedOutput = true; fixedOutput = drv->isFixedOutput();
for (auto & i : drv->outputs)
if (i.second.hash == "") fixedOutput = false;
/* Don't repeat fixed-output derivations since they're already /* Don't repeat fixed-output derivations since they're already
verified by their output hash.*/ verified by their output hash.*/
@ -3019,6 +3012,8 @@ void DerivationGoal::registerOutputs()
bool runDiffHook = settings.runDiffHook; bool runDiffHook = settings.runDiffHook;
bool keepPreviousRound = settings.keepFailed || runDiffHook; bool keepPreviousRound = settings.keepFailed || runDiffHook;
std::exception_ptr delayedException;
/* Check whether the output paths were created, and grep each /* Check whether the output paths were created, and grep each
output path to determine what other paths it references. Also make all output path to determine what other paths it references. Also make all
output paths read-only. */ output paths read-only. */
@ -3093,7 +3088,7 @@ void DerivationGoal::registerOutputs()
/* Check that fixed-output derivations produced the right /* Check that fixed-output derivations produced the right
outputs (i.e., the content hash should match the specified outputs (i.e., the content hash should match the specified
hash). */ hash). */
if (i.second.hash != "") { if (fixedOutput) {
bool recursive; Hash h; bool recursive; Hash h;
i.second.parseHashInfo(recursive, h); i.second.parseHashInfo(recursive, h);
@ -3109,27 +3104,34 @@ void DerivationGoal::registerOutputs()
/* Check the hash. In hash mode, move the path produced by /* Check the hash. In hash mode, move the path produced by
the derivation to its content-addressed location. */ the derivation to its content-addressed location. */
Hash h2 = recursive ? hashPath(h.type, actualPath).first : hashFile(h.type, actualPath); Hash h2 = recursive ? hashPath(h.type, actualPath).first : hashFile(h.type, actualPath);
if (buildMode == bmHash) {
Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]); Path dest = worker.store.makeFixedOutputPath(recursive, h2, drv->env["name"]);
printError(format("build produced path '%1%' with %2% hash '%3%'")
% dest % printHashType(h.type) % printHash16or32(h2)); if (h != h2) {
if (worker.store.isValidPath(dest))
return; /* Throw an error after registering the path as
valid. */
delayedException = std::make_exception_ptr(
BuildError("fixed-output derivation produced path '%s' with %s hash '%s' instead of the expected hash '%s'",
dest, printHashType(h.type), printHash16or32(h2), printHash16or32(h)));
Path actualDest = worker.store.toRealPath(dest); Path actualDest = worker.store.toRealPath(dest);
if (worker.store.isValidPath(dest))
std::rethrow_exception(delayedException);
if (actualPath != actualDest) { if (actualPath != actualDest) {
PathLocks outputLocks({actualDest}); PathLocks outputLocks({actualDest});
deletePath(actualDest); deletePath(actualDest);
if (rename(actualPath.c_str(), actualDest.c_str()) == -1) if (rename(actualPath.c_str(), actualDest.c_str()) == -1)
throw SysError(format("moving '%1%' to '%2%'") % actualPath % dest); throw SysError(format("moving '%1%' to '%2%'") % actualPath % dest);
} }
path = dest; path = dest;
actualPath = actualDest; actualPath = actualDest;
} 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));
} }
else
assert(path == dest);
info.ca = makeFixedOutputCA(recursive, h2); info.ca = makeFixedOutputCA(recursive, h2);
} }
@ -3306,6 +3308,11 @@ void DerivationGoal::registerOutputs()
paths referenced by each of them. If there are cycles in the paths referenced by each of them. If there are cycles in the
outputs, this will fail. */ outputs, this will fail. */
worker.store.registerValidPaths(infos); worker.store.registerValidPaths(infos);
/* In case of a fixed-output derivation hash mismatch, throw an
exception now that we have registered the output as valid. */
if (delayedException)
std::rethrow_exception(delayedException);
} }

View file

@ -192,7 +192,7 @@ struct ValidPathInfo
typedef list<ValidPathInfo> ValidPathInfos; typedef list<ValidPathInfo> ValidPathInfos;
enum BuildMode { bmNormal, bmRepair, bmCheck, bmHash }; enum BuildMode { bmNormal, bmRepair, bmCheck };
struct BuildResult struct BuildResult

View file

@ -167,9 +167,6 @@ void mainWrapped(int argc, char * * argv)
buildMode = bmRepair; buildMode = bmRepair;
} }
else if (*arg == "--hash")
buildMode = bmHash;
else if (*arg == "--run-env") // obsolete else if (*arg == "--run-env") // obsolete
runEnv = true; runEnv = true;

View file

@ -122,7 +122,6 @@ static void opRealise(Strings opFlags, Strings opArgs)
if (i == "--dry-run") dryRun = true; if (i == "--dry-run") dryRun = true;
else if (i == "--repair") buildMode = bmRepair; else if (i == "--repair") buildMode = bmRepair;
else if (i == "--check") buildMode = bmCheck; else if (i == "--check") buildMode = bmCheck;
else if (i == "--hash") buildMode = bmHash;
else if (i == "--ignore-unknown") ignoreUnknown = true; else if (i == "--ignore-unknown") ignoreUnknown = true;
else throw UsageError(format("unknown flag '%1%'") % i); else throw UsageError(format("unknown flag '%1%'") % i);

View file

@ -5,15 +5,22 @@ clearStore
export IMPURE_VAR1=foo export IMPURE_VAR1=foo
export IMPURE_VAR2=bar export IMPURE_VAR2=bar
path=$(nix-store -q $(nix-instantiate fixed.nix -A good.0))
echo 'testing bad...'
nix-build fixed.nix -A bad --no-out-link && fail "should fail"
# Building with the bad hash should produce the "good" output path as
# a side-effect.
[[ -e $path ]]
nix path-info --json $path | grep fixed:md5:2qk15sxzzjlnpjk9brn7j8ppcd
echo 'testing good...' echo 'testing good...'
nix-build fixed.nix -A good --no-out-link nix-build fixed.nix -A good --no-out-link
echo 'testing good2...' echo 'testing good2...'
nix-build fixed.nix -A good2 --no-out-link nix-build fixed.nix -A good2 --no-out-link
echo 'testing bad...'
nix-build fixed.nix -A bad --no-out-link && fail "should fail"
echo 'testing reallyBad...' echo 'testing reallyBad...'
nix-instantiate fixed.nix -A reallyBad && fail "should fail" nix-instantiate fixed.nix -A reallyBad && fail "should fail"