Merge pull request #2779 from LnL7/build-exit-codes
build: add exit code for hash and check mismatches
This commit is contained in:
commit
7e1c85c5fb
6 changed files with 111 additions and 12 deletions
|
@ -215,6 +215,48 @@ printed.)</para>
|
|||
|
||||
</variablelist>
|
||||
|
||||
<para>Special exit codes:</para>
|
||||
|
||||
<variablelist>
|
||||
|
||||
<varlistentry><term><literal>100</literal></term>
|
||||
<listitem><para>Generic build failure, the builder process
|
||||
returned with a non-zero exit code.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>101</literal></term>
|
||||
<listitem><para>Build timeout, the build was aborted because it
|
||||
did not complete within the specified <link
|
||||
linkend='conf-timeout'><literal>timeout</literal></link>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>102</literal></term>
|
||||
<listitem><para>Hash mismatch, the build output was rejected
|
||||
because it does not match the specified <link
|
||||
linkend="fixed-output-drvs"><varname>outputHash</varname></link>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>104</literal></term>
|
||||
<listitem><para>Not deterministic, the build succeeded in check
|
||||
mode but the resulting output is not binary reproducable.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>With the <option>--keep-going</option> flag it's possible for
|
||||
multiple failures to occur, in this case the 1xx status codes are or combined
|
||||
using binary or. <screen>
|
||||
1100100
|
||||
^^^^
|
||||
|||`- timeout
|
||||
||`-- output hash mismatch
|
||||
|`--- build failure
|
||||
`---- not deterministic
|
||||
</screen></para>
|
||||
|
||||
</refsection>
|
||||
|
||||
|
||||
|
|
|
@ -266,6 +266,12 @@ public:
|
|||
/* Set if at least one derivation had a timeout. */
|
||||
bool timedOut;
|
||||
|
||||
/* Set if at least one derivation fails with a hash mismatch. */
|
||||
bool hashMismatch;
|
||||
|
||||
/* Set if at least one derivation is not deterministic in check mode. */
|
||||
bool checkMismatch;
|
||||
|
||||
LocalStore & store;
|
||||
|
||||
std::unique_ptr<HookInstance> hook;
|
||||
|
@ -3213,6 +3219,7 @@ void DerivationGoal::registerOutputs()
|
|||
|
||||
/* Throw an error after registering the path as
|
||||
valid. */
|
||||
worker.hashMismatch = true;
|
||||
delayedException = std::make_exception_ptr(
|
||||
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
|
||||
dest, h.to_string(), h2.to_string()));
|
||||
|
@ -3255,6 +3262,7 @@ void DerivationGoal::registerOutputs()
|
|||
if (!worker.store.isValidPath(path)) continue;
|
||||
auto info = *worker.store.queryPathInfo(path);
|
||||
if (hash.first != info.narHash) {
|
||||
worker.checkMismatch = true;
|
||||
if (settings.runDiffHook || settings.keepFailed) {
|
||||
Path dst = worker.store.toRealPath(path + checkSuffix);
|
||||
deletePath(dst);
|
||||
|
@ -3266,10 +3274,10 @@ void DerivationGoal::registerOutputs()
|
|||
buildUser ? buildUser->getGID() : getgid(),
|
||||
path, dst, drvPath, tmpDir);
|
||||
|
||||
throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
|
||||
throw NotDeterministic(format("derivation '%1%' may not be deterministic: output '%2%' differs from '%3%'")
|
||||
% drvPath % path % dst);
|
||||
} else
|
||||
throw Error(format("derivation '%1%' may not be deterministic: output '%2%' differs")
|
||||
throw NotDeterministic(format("derivation '%1%' may not be deterministic: output '%2%' differs")
|
||||
% drvPath % path);
|
||||
}
|
||||
|
||||
|
@ -4101,6 +4109,8 @@ Worker::Worker(LocalStore & store)
|
|||
lastWokenUp = steady_time_point::min();
|
||||
permanentFailure = false;
|
||||
timedOut = false;
|
||||
hashMismatch = false;
|
||||
checkMismatch = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -4461,7 +4471,29 @@ void Worker::waitForInput()
|
|||
|
||||
unsigned int Worker::exitStatus()
|
||||
{
|
||||
return timedOut ? 101 : (permanentFailure ? 100 : 1);
|
||||
/*
|
||||
* 1100100
|
||||
* ^^^^
|
||||
* |||`- timeout
|
||||
* ||`-- output hash mismatch
|
||||
* |`--- build failure
|
||||
* `---- not deterministic
|
||||
*/
|
||||
unsigned int mask = 0;
|
||||
bool buildFailure = permanentFailure || timedOut || hashMismatch;
|
||||
if (buildFailure)
|
||||
mask |= 0x04; // 100
|
||||
if (timedOut)
|
||||
mask |= 0x01; // 101
|
||||
if (hashMismatch)
|
||||
mask |= 0x02; // 102
|
||||
if (checkMismatch) {
|
||||
mask |= 0x08; // 104
|
||||
}
|
||||
|
||||
if (mask)
|
||||
mask |= 0x60;
|
||||
return mask ? mask : 1;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -855,10 +855,11 @@ CachedDownloadResult Downloader::downloadCached(
|
|||
}
|
||||
|
||||
if (expectedStorePath != "" && storePath != expectedStorePath) {
|
||||
unsigned int statusCode = 102;
|
||||
Hash gotHash = request.unpack
|
||||
? hashPath(request.expectedHash.type, store->toRealPath(storePath)).first
|
||||
: hashFile(request.expectedHash.type, store->toRealPath(storePath));
|
||||
throw nix::Error("hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
|
||||
throw nix::Error(statusCode, "hash mismatch in file downloaded from '%s':\n wanted: %s\n got: %s",
|
||||
url, request.expectedHash.to_string(), gotHash.to_string());
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,11 @@ with import ./config.nix;
|
|||
'';
|
||||
};
|
||||
|
||||
hashmismatch = import <nix/fetchurl.nix> {
|
||||
url = "file://" + toString ./dummy;
|
||||
sha256 = "0mdqa9w1p6cmli6976v4wi0sw9r4p5prkj7lzfd1877wk11c9c73";
|
||||
};
|
||||
|
||||
fetchurl = import <nix/fetchurl.nix> {
|
||||
url = "file://" + toString ./lang/eval-okay-xml.exp.xml;
|
||||
sha256 = "0kg4sla7ihm8ijr8cb3117fhl99zrc2bwy1jrngsfmkh8bav4m0v";
|
||||
|
|
|
@ -6,14 +6,16 @@ nix-build dependencies.nix --no-out-link
|
|||
nix-build dependencies.nix --no-out-link --check
|
||||
|
||||
nix-build check.nix -A nondeterministic --no-out-link
|
||||
(! nix-build check.nix -A nondeterministic --no-out-link --check 2> $TEST_ROOT/log)
|
||||
nix-build check.nix -A nondeterministic --no-out-link --check 2> $TEST_ROOT/log || status=$?
|
||||
grep 'may not be deterministic' $TEST_ROOT/log
|
||||
[ "$status" = "104" ]
|
||||
|
||||
clearStore
|
||||
|
||||
nix-build dependencies.nix --no-out-link --repeat 3
|
||||
|
||||
(! nix-build check.nix -A nondeterministic --no-out-link --repeat 1 2> $TEST_ROOT/log)
|
||||
nix-build check.nix -A nondeterministic --no-out-link --repeat 1 2> $TEST_ROOT/log || status=$?
|
||||
[ "$status" = "1" ]
|
||||
grep 'differs from previous round' $TEST_ROOT/log
|
||||
|
||||
path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '')
|
||||
|
@ -23,10 +25,23 @@ echo foo > $path
|
|||
chmod -w $path
|
||||
|
||||
nix-build check.nix -A fetchurl --no-out-link --check --hashed-mirrors ''
|
||||
|
||||
# Note: "check" doesn't repair anything, it just compares to the hash stored in the database.
|
||||
[[ $(cat $path) = foo ]]
|
||||
|
||||
nix-build check.nix -A fetchurl --no-out-link --repair --hashed-mirrors ''
|
||||
|
||||
[[ $(cat $path) != foo ]]
|
||||
|
||||
nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors '' || status=$?
|
||||
[ "$status" = "102" ]
|
||||
|
||||
echo -n > ./dummy
|
||||
nix-build check.nix -A hashmismatch --no-out-link --hashed-mirrors ''
|
||||
echo 'Hello World' > ./dummy
|
||||
|
||||
nix-build check.nix -A hashmismatch --no-out-link --check --hashed-mirrors '' || status=$?
|
||||
[ "$status" = "102" ]
|
||||
|
||||
# Multiple failures with --keep-going
|
||||
nix-build check.nix -A nondeterministic --no-out-link
|
||||
nix-build check.nix -A nondeterministic -A hashmismatch --no-out-link --check --keep-going --hashed-mirrors '' || status=$?
|
||||
[ "$status" = "110" ]
|
||||
|
|
|
@ -2,10 +2,14 @@
|
|||
|
||||
source common.sh
|
||||
|
||||
failed=0
|
||||
messages="`nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1 || failed=1`"
|
||||
if [ $failed -ne 0 ]; then
|
||||
echo "error: 'nix-store' succeeded; should have timed out"
|
||||
|
||||
set +e
|
||||
messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1)
|
||||
status=$?
|
||||
set -e
|
||||
|
||||
if [ $status -ne 101 ]; then
|
||||
echo "error: 'nix-store' exited with '$status'; should have exited 101"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
Loading…
Reference in a new issue