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>
|
</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>
|
</refsection>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -266,6 +266,12 @@ public:
|
||||||
/* Set if at least one derivation had a timeout. */
|
/* Set if at least one derivation had a timeout. */
|
||||||
bool timedOut;
|
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;
|
LocalStore & store;
|
||||||
|
|
||||||
std::unique_ptr<HookInstance> hook;
|
std::unique_ptr<HookInstance> hook;
|
||||||
|
@ -3213,6 +3219,7 @@ void DerivationGoal::registerOutputs()
|
||||||
|
|
||||||
/* Throw an error after registering the path as
|
/* Throw an error after registering the path as
|
||||||
valid. */
|
valid. */
|
||||||
|
worker.hashMismatch = true;
|
||||||
delayedException = std::make_exception_ptr(
|
delayedException = std::make_exception_ptr(
|
||||||
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
|
BuildError("hash mismatch in fixed-output derivation '%s':\n wanted: %s\n got: %s",
|
||||||
dest, h.to_string(), h2.to_string()));
|
dest, h.to_string(), h2.to_string()));
|
||||||
|
@ -3255,6 +3262,7 @@ void DerivationGoal::registerOutputs()
|
||||||
if (!worker.store.isValidPath(path)) continue;
|
if (!worker.store.isValidPath(path)) continue;
|
||||||
auto info = *worker.store.queryPathInfo(path);
|
auto info = *worker.store.queryPathInfo(path);
|
||||||
if (hash.first != info.narHash) {
|
if (hash.first != info.narHash) {
|
||||||
|
worker.checkMismatch = true;
|
||||||
if (settings.runDiffHook || settings.keepFailed) {
|
if (settings.runDiffHook || settings.keepFailed) {
|
||||||
Path dst = worker.store.toRealPath(path + checkSuffix);
|
Path dst = worker.store.toRealPath(path + checkSuffix);
|
||||||
deletePath(dst);
|
deletePath(dst);
|
||||||
|
@ -3266,10 +3274,10 @@ void DerivationGoal::registerOutputs()
|
||||||
buildUser ? buildUser->getGID() : getgid(),
|
buildUser ? buildUser->getGID() : getgid(),
|
||||||
path, dst, drvPath, tmpDir);
|
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);
|
% drvPath % path % dst);
|
||||||
} else
|
} 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);
|
% drvPath % path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4101,6 +4109,8 @@ Worker::Worker(LocalStore & store)
|
||||||
lastWokenUp = steady_time_point::min();
|
lastWokenUp = steady_time_point::min();
|
||||||
permanentFailure = false;
|
permanentFailure = false;
|
||||||
timedOut = false;
|
timedOut = false;
|
||||||
|
hashMismatch = false;
|
||||||
|
checkMismatch = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -4461,7 +4471,29 @@ void Worker::waitForInput()
|
||||||
|
|
||||||
unsigned int Worker::exitStatus()
|
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) {
|
if (expectedStorePath != "" && storePath != expectedStorePath) {
|
||||||
|
unsigned int statusCode = 102;
|
||||||
Hash gotHash = request.unpack
|
Hash gotHash = request.unpack
|
||||||
? hashPath(request.expectedHash.type, store->toRealPath(storePath)).first
|
? hashPath(request.expectedHash.type, store->toRealPath(storePath)).first
|
||||||
: hashFile(request.expectedHash.type, store->toRealPath(storePath));
|
: 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());
|
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> {
|
fetchurl = import <nix/fetchurl.nix> {
|
||||||
url = "file://" + toString ./lang/eval-okay-xml.exp.xml;
|
url = "file://" + toString ./lang/eval-okay-xml.exp.xml;
|
||||||
sha256 = "0kg4sla7ihm8ijr8cb3117fhl99zrc2bwy1jrngsfmkh8bav4m0v";
|
sha256 = "0kg4sla7ihm8ijr8cb3117fhl99zrc2bwy1jrngsfmkh8bav4m0v";
|
||||||
|
|
|
@ -6,14 +6,16 @@ nix-build dependencies.nix --no-out-link
|
||||||
nix-build dependencies.nix --no-out-link --check
|
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
|
||||||
(! 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
|
grep 'may not be deterministic' $TEST_ROOT/log
|
||||||
|
[ "$status" = "104" ]
|
||||||
|
|
||||||
clearStore
|
clearStore
|
||||||
|
|
||||||
nix-build dependencies.nix --no-out-link --repeat 3
|
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
|
grep 'differs from previous round' $TEST_ROOT/log
|
||||||
|
|
||||||
path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '')
|
path=$(nix-build check.nix -A fetchurl --no-out-link --hashed-mirrors '')
|
||||||
|
@ -23,10 +25,23 @@ echo foo > $path
|
||||||
chmod -w $path
|
chmod -w $path
|
||||||
|
|
||||||
nix-build check.nix -A fetchurl --no-out-link --check --hashed-mirrors ''
|
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.
|
# Note: "check" doesn't repair anything, it just compares to the hash stored in the database.
|
||||||
[[ $(cat $path) = foo ]]
|
[[ $(cat $path) = foo ]]
|
||||||
|
|
||||||
nix-build check.nix -A fetchurl --no-out-link --repair --hashed-mirrors ''
|
nix-build check.nix -A fetchurl --no-out-link --repair --hashed-mirrors ''
|
||||||
|
|
||||||
[[ $(cat $path) != foo ]]
|
[[ $(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
|
source common.sh
|
||||||
|
|
||||||
failed=0
|
|
||||||
messages="`nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1 || failed=1`"
|
set +e
|
||||||
if [ $failed -ne 0 ]; then
|
messages=$(nix-build -Q timeout.nix -A infiniteLoop --timeout 2 2>&1)
|
||||||
echo "error: 'nix-store' succeeded; should have timed out"
|
status=$?
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ $status -ne 101 ]; then
|
||||||
|
echo "error: 'nix-store' exited with '$status'; should have exited 101"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue