1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-09 03:56:01 +01:00
This commit is contained in:
John Ericson 2025-11-06 18:56:30 +00:00 committed by GitHub
commit 61393b3fcb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
156 changed files with 3897 additions and 1464 deletions

View file

@ -37,6 +37,7 @@ mkMesonDerivation (finalAttrs: {
(fileset.unions [
../../.version
# For example JSON
../../src/libutil-tests/data/memory-source-accessor
../../src/libutil-tests/data/hash
../../src/libstore-tests/data/content-address
../../src/libstore-tests/data/store-path
@ -44,6 +45,7 @@ mkMesonDerivation (finalAttrs: {
../../src/libstore-tests/data/derived-path
../../src/libstore-tests/data/path-info
../../src/libstore-tests/data/nar-info
../../src/libstore-tests/data/build-result
# Too many different types of files to filter for now
../../doc/manual
./.

View file

@ -120,6 +120,7 @@
- [Architecture and Design](architecture/architecture.md)
- [Formats and Protocols](protocols/index.md)
- [JSON Formats](protocols/json/index.md)
- [File System Object](protocols/json/file-system-object.md)
- [Hash](protocols/json/hash.md)
- [Content Address](protocols/json/content-address.md)
- [Store Path](protocols/json/store-path.md)
@ -127,6 +128,7 @@
- [Derivation](protocols/json/derivation.md)
- [Deriving Path](protocols/json/deriving-path.md)
- [Build Trace Entry](protocols/json/build-trace-entry.md)
- [Build Result](protocols/json/build-result.md)
- [Serving Tarball Flakes](protocols/tarball-fetcher.md)
- [Store Path Specification](protocols/store-path.md)
- [Nix Archive (NAR) Format](protocols/nix-archive/index.md)

View file

@ -0,0 +1,21 @@
{{#include build-result-v1-fixed.md}}
## Examples
### Successful build
```json
{{#include schema/build-result-v1/success.json}}
```
### Failed build (output rejected)
```json
{{#include schema/build-result-v1/output-rejected.json}}
```
### Failed build (non-deterministic)
```json
{{#include schema/build-result-v1/not-deterministic.json}}
```

View file

@ -0,0 +1,21 @@
{{#include file-system-object-v1-fixed.md}}
## Examples
### Simple
```json
{{#include schema/file-system-object-v1/simple.json}}
```
### Complex
```json
{{#include schema/file-system-object-v1/complex.json}}
```
<!-- need to convert YAML to JSON first
## Raw Schema
[JSON Schema for File System Object v1](schema/file-system-object-v1.json)
-->

View file

@ -11,6 +11,7 @@ s/\\`/`/g
#
# As we have more such relative links, more replacements of this nature
# should appear below.
s^#/\$defs/\(regular\|symlink\|directory\)^In this schema^g
s^\(./hash-v1.yaml\)\?#/$defs/algorithm^[JSON format for `Hash`](./hash.html#algorithm)^g
s^\(./hash-v1.yaml\)^[JSON format for `Hash`](./hash.html)^g
s^\(./content-address-v1.yaml\)\?#/$defs/method^[JSON format for `ContentAddress`](./content-address.html#method)^g

View file

@ -9,6 +9,7 @@ json_schema_for_humans = find_program('generate-schema-doc', required : false)
json_schema_config = files('json-schema-for-humans-config.yaml')
schemas = [
'file-system-object-v1',
'hash-v1',
'content-address-v1',
'store-path-v1',
@ -16,6 +17,7 @@ schemas = [
'derivation-v3',
'deriving-path-v1',
'build-trace-entry-v1',
'build-result-v1',
]
schema_files = files()

View file

@ -0,0 +1 @@
../../../../../../src/libstore-tests/data/build-result

View file

@ -0,0 +1,136 @@
"$schema": "http://json-schema.org/draft-04/schema"
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/build-result-v1.json"
title: Build Result
description: |
This schema describes the JSON representation of Nix's `BuildResult` type, which represents the result of building a derivation or substituting store paths.
Build results can represent either successful builds (with built outputs) or various types of failures.
oneOf:
- "$ref": "#/$defs/success"
- "$ref": "#/$defs/failure"
type: object
required:
- success
- status
properties:
timesBuilt:
type: integer
minimum: 0
title: Times built
description: |
How many times this build was performed.
startTime:
type: integer
minimum: 0
title: Start time
description: |
The start time of the build (or one of the rounds, if it was repeated), as a Unix timestamp.
stopTime:
type: integer
minimum: 0
title: Stop time
description: |
The stop time of the build (or one of the rounds, if it was repeated), as a Unix timestamp.
cpuUser:
type: integer
minimum: 0
title: User CPU time
description: |
User CPU time the build took, in microseconds.
cpuSystem:
type: integer
minimum: 0
title: System CPU time
description: |
System CPU time the build took, in microseconds.
"$defs":
success:
type: object
title: Successful Build Result
description: |
Represents a successful build with built outputs.
required:
- success
- status
- builtOutputs
properties:
success:
const: true
title: Success indicator
description: |
Always true for successful build results.
status:
type: string
title: Success status
description: |
Status string for successful builds.
enum:
- "Built"
- "Substituted"
- "AlreadyValid"
- "ResolvesToAlreadyValid"
builtOutputs:
type: object
title: Built outputs
description: |
A mapping from output names to their build trace entries.
additionalProperties:
"$ref": "build-trace-entry-v1.yaml"
failure:
type: object
title: Failed Build Result
description: |
Represents a failed build with error information.
required:
- success
- status
- errorMsg
properties:
success:
const: false
title: Success indicator
description: |
Always false for failed build results.
status:
type: string
title: Failure status
description: |
Status string for failed builds.
enum:
- "PermanentFailure"
- "InputRejected"
- "OutputRejected"
- "TransientFailure"
- "CachedFailure"
- "TimedOut"
- "MiscFailure"
- "DependencyFailed"
- "LogLimitExceeded"
- "NotDeterministic"
- "NoSubstituters"
- "HashMismatch"
errorMsg:
type: string
title: Error message
description: |
Information about the error if the build failed.
isNonDeterministic:
type: boolean
title: Non-deterministic flag
description: |
If timesBuilt > 1, whether some builds did not produce the same result.
Note that 'isNonDeterministic = false' does not mean the build is deterministic,
just that we don't have evidence of non-determinism.

View file

@ -0,0 +1 @@
../../../../../../src/libutil-tests/data/memory-source-accessor

View file

@ -0,0 +1,65 @@
"$schema": http://json-schema.org/draft-04/schema#
"$id": https://nix.dev/manual/nix/latest/protocols/json/schema/file-system-object-v1.json
title: File System Object
description: |
This schema describes the JSON representation of Nix's [File System Object](@docroot@/store/file-system-object.md).
The schema is recursive because file system objects contain other file system objects.
type: object
required: ["type"]
properties:
type:
type: string
enum: ["regular", "symlink", "directory"]
# Enforce conditional structure based on `type`
anyOf:
- $ref: "#/$defs/regular"
required: ["type", "contents"]
- $ref: "#/$defs/symlink"
required: ["type", "target"]
- $ref: "#/$defs/directory"
required: ["type", "contents"]
"$defs":
regular:
title: Regular File
required: ["contents"]
properties:
type:
const: "regular"
contents:
type: string
description: Base64-encoded file contents
executable:
type: boolean
description: Whether the file is executable.
default: false
additionalProperties: false
symlink:
title: Symbolic Link
required: ["target"]
properties:
type:
const: "symlink"
target:
type: string
description: Target path of the symlink.
additionalProperties: false
directory:
title: Directory
required: ["contents"]
properties:
type:
const: "directory"
contents:
type: object
description: |
Map of names to nested file system objects (for type=directory)
additionalProperties:
$ref: "#"
additionalProperties: false

View file

@ -0,0 +1 @@
../../src/libstore-tests/data/build-result

View file

@ -0,0 +1 @@
../../src/libutil-tests/data/memory-source-accessor

View file

@ -20,6 +20,14 @@ schema_dir = meson.current_source_dir() / 'schema'
# Get all example files
schemas = [
{
'stem' : 'file-system-object',
'schema' : schema_dir / 'file-system-object-v1.yaml',
'files' : [
'simple.json',
'complex.json',
],
},
{
'stem' : 'hash',
'schema' : schema_dir / 'hash-v1.yaml',
@ -150,6 +158,15 @@ schemas += [
'impure.json',
],
},
{
'stem' : 'build-result',
'schema' : schema_dir / 'build-result-v1.yaml',
'files' : [
'success.json',
'output-rejected.json',
'not-deterministic.json',
],
},
# Match exact variant
{
'stem' : 'store-object-info',

View file

@ -20,6 +20,7 @@ mkMesonDerivation (finalAttrs: {
fileset = lib.fileset.unions [
../../.version
../../doc/manual/source/protocols/json/schema
../../src/libutil-tests/data/memory-source-accessor
../../src/libutil-tests/data/hash
../../src/libstore-tests/data/content-address
../../src/libstore-tests/data/store-path
@ -28,6 +29,7 @@ mkMesonDerivation (finalAttrs: {
../../src/libstore-tests/data/derived-path
../../src/libstore-tests/data/path-info
../../src/libstore-tests/data/nar-info
../../src/libstore-tests/data/build-result
./.
];

View file

@ -108,20 +108,16 @@ RealisedPath::Set BuiltPath::toRealisedPaths(Store & store) const
overloaded{
[&](const BuiltPath::Opaque & p) { res.insert(p.path); },
[&](const BuiltPath::Built & p) {
auto drvHashes = staticOutputHashes(store, store.readDerivation(p.drvPath->outPath()));
for (auto & [outputName, outputPath] : p.outputs) {
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
auto drvOutput = get(drvHashes, outputName);
if (!drvOutput)
throw Error(
"the derivation '%s' has unrealised output '%s' (derived-path.cc/toRealisedPaths)",
store.printStorePath(p.drvPath->outPath()),
outputName);
DrvOutput key{*drvOutput, outputName};
DrvOutput key{
.drvPath = p.drvPath->outPath(),
.outputName = outputName,
};
auto thisRealisation = store.queryRealisation(key);
assert(thisRealisation); // Weve built it, so we must
// have the realisation
res.insert(Realisation{*thisRealisation, std::move(key)});
// Weve built it, so we must have the realisation.
assert(thisRealisation);
res.insert(Realisation{*thisRealisation, key});
} else {
res.insert(outputPath);
}

View file

@ -1718,28 +1718,7 @@ static void derivationStrictInternal(EvalState & state, std::string_view drvName
drv.outputs.insert_or_assign(i, DerivationOutput::Deferred{});
}
auto hashModulo = hashDerivationModulo(*state.store, Derivation(drv), true);
switch (hashModulo.kind) {
case DrvHash::Kind::Regular:
for (auto & i : outputs) {
auto h = get(hashModulo.hashes, i);
if (!h)
state.error<AssertionError>("derivation produced no hash for output '%s'", i).atPos(v).debugThrow();
auto outPath = state.store->makeOutputPath(i, *h, drvName);
drv.env[i] = state.store->printStorePath(outPath);
drv.outputs.insert_or_assign(
i,
DerivationOutput::InputAddressed{
.path = std::move(outPath),
});
}
break;
;
case DrvHash::Kind::Deferred:
for (auto & i : outputs) {
drv.outputs.insert_or_assign(i, DerivationOutput::Deferred{});
}
}
resolveInputAddressed(*state.store, drv);
}
/* Write the resulting term into the Nix store directory. */

View file

@ -109,7 +109,8 @@ std::pair<FlakeRef, std::string> parsePathFlakeRefWithFragment(
std::smatch match;
auto succeeds = std::regex_match(url, match, pathFlakeRegex);
assert(succeeds);
if (!succeeds)
throw Error("invalid flakeref '%s'", url);
auto path = match[1].str();
auto query = decodeQuery(match[3].str(), /*lenient=*/true);
auto fragment = percentDecode(match[5].str());

View file

@ -6,6 +6,7 @@
#include "nix/store/tests/libstore.hh"
#include "nix/util/tests/characterization.hh"
#include "nix/util/tests/json-characterization.hh"
namespace nix {
@ -16,12 +17,30 @@ class ProtoTest : public CharacterizationTest
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / (std::string{testStem + ".bin"});
return unitTestData / testStem;
}
public:
Path storeDir = "/nix/store";
StoreDirConfig store{storeDir};
/**
* Golden test for `T` JSON reading
*/
template<typename T>
void readJsonTest(PathView testStem, const T & expected)
{
nix::readJsonTest(*this, testStem, expected);
}
/**
* Golden test for `T` JSON write
*/
template<typename T>
void writeJsonTest(PathView testStem, const T & decoded)
{
nix::writeJsonTest(*this, testStem, decoded);
}
};
template<class Proto, const char * protocolDir>
@ -34,7 +53,7 @@ public:
template<typename T>
void readProtoTest(PathView testStem, typename Proto::Version version, T expected)
{
CharacterizationTest::readTest(testStem, [&](const auto & encoded) {
CharacterizationTest::readTest(std::string{testStem + ".bin"}, [&](const auto & encoded) {
T got = ({
StringSource from{encoded};
Proto::template Serialise<T>::read(
@ -55,7 +74,7 @@ public:
template<typename T>
void writeProtoTest(PathView testStem, typename Proto::Version version, const T & decoded)
{
CharacterizationTest::writeTest(testStem, [&]() {
CharacterizationTest::writeTest(std::string{testStem + ".bin"}, [&]() {
StringSink to;
Proto::template Serialise<T>::write(
this->store,
@ -69,14 +88,31 @@ public:
}
};
#define VERSIONED_CHARACTERIZATION_TEST(FIXTURE, NAME, STEM, VERSION, VALUE) \
TEST_F(FIXTURE, NAME##_read) \
{ \
readProtoTest(STEM, VERSION, VALUE); \
} \
TEST_F(FIXTURE, NAME##_write) \
{ \
writeProtoTest(STEM, VERSION, VALUE); \
#define VERSIONED_READ_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
TEST_F(FIXTURE, NAME##_read) \
{ \
readProtoTest(STEM, VERSION, VALUE); \
}
#define VERSIONED_WRITE_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
TEST_F(FIXTURE, NAME##_write) \
{ \
writeProtoTest(STEM, VERSION, VALUE); \
}
#define VERSIONED_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
VERSIONED_READ_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
VERSIONED_WRITE_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE)
#define VERSIONED_CHARACTERIZATION_TEST(FIXTURE, NAME, STEM, VERSION, VALUE) \
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(FIXTURE, NAME, STEM, VERSION, VALUE) \
TEST_F(FIXTURE, NAME##_json_read) \
{ \
readJsonTest(STEM, VALUE); \
} \
TEST_F(FIXTURE, NAME##_json_write) \
{ \
writeJsonTest(STEM, VALUE); \
}
} // namespace nix

View file

@ -0,0 +1,108 @@
#include <gtest/gtest.h>
#include "nix/store/build-result.hh"
#include "nix/util/tests/json-characterization.hh"
namespace nix {
class BuildResultTest : public virtual CharacterizationTest
{
std::filesystem::path unitTestData = getUnitTestData() / "build-result";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
};
using nlohmann::json;
struct BuildResultJsonTest : BuildResultTest,
JsonCharacterizationTest<BuildResult>,
::testing::WithParamInterface<std::pair<std::string_view, BuildResult>>
{};
TEST_P(BuildResultJsonTest, from_json)
{
auto & [name, expected] = GetParam();
readJsonTest(name, expected);
}
TEST_P(BuildResultJsonTest, to_json)
{
auto & [name, value] = GetParam();
writeJsonTest(name, value);
}
using namespace std::literals::chrono_literals;
INSTANTIATE_TEST_SUITE_P(
BuildResultJSON,
BuildResultJsonTest,
::testing::Values(
std::pair{
"not-deterministic",
BuildResult{
.inner{BuildResult::Failure{
.status = BuildResult::Failure::NotDeterministic,
.errorMsg = "no idea why",
.isNonDeterministic = false, // Note: This field is separate from the status
}},
.timesBuilt = 1,
},
},
std::pair{
"output-rejected",
BuildResult{
.inner{BuildResult::Failure{
.status = BuildResult::Failure::OutputRejected,
.errorMsg = "no idea why",
.isNonDeterministic = false,
}},
.timesBuilt = 3,
.startTime = 30,
.stopTime = 50,
},
},
std::pair{
"success",
BuildResult{
.inner{BuildResult::Success{
.status = BuildResult::Success::Built,
.builtOutputs{
{
"foo",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
},
},
{
"bar",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
},
},
},
}},
.timesBuilt = 3,
.startTime = 30,
.stopTime = 50,
.cpuUser = std::chrono::microseconds(500s),
.cpuSystem = std::chrono::microseconds(604s),
},
}));
} // namespace nix

View file

@ -3,6 +3,7 @@
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include "nix/util/json-utils.hh"
#include "nix/store/common-protocol.hh"
#include "nix/store/common-protocol-impl.hh"
#include "nix/store/build-result.hh"
@ -22,7 +23,7 @@ public:
template<typename T>
void readProtoTest(PathView testStem, const T & expected)
{
CharacterizationTest::readTest(testStem, [&](const auto & encoded) {
CharacterizationTest::readTest(std::string{testStem + ".bin"}, [&](const auto & encoded) {
T got = ({
StringSource from{encoded};
CommonProto::Serialise<T>::read(store, CommonProto::ReadConn{.from = from});
@ -38,7 +39,7 @@ public:
template<typename T>
void writeProtoTest(PathView testStem, const T & decoded)
{
CharacterizationTest::writeTest(testStem, [&]() -> std::string {
CharacterizationTest::writeTest(std::string{testStem + ".bin"}, [&]() -> std::string {
StringSink to;
CommonProto::Serialise<T>::write(store, CommonProto::WriteConn{.to = to}, decoded);
return to.s;
@ -46,16 +47,30 @@ public:
}
};
#define CHARACTERIZATION_TEST(NAME, STEM, VALUE) \
TEST_F(CommonProtoTest, NAME##_read) \
{ \
readProtoTest(STEM, VALUE); \
} \
TEST_F(CommonProtoTest, NAME##_write) \
{ \
writeProtoTest(STEM, VALUE); \
#define READ_CHARACTERIZATION_TEST(NAME, STEM, VALUE) \
TEST_F(CommonProtoTest, NAME##_read) \
{ \
readProtoTest(STEM, VALUE); \
} \
TEST_F(CommonProtoTest, NAME##_json_read) \
{ \
readJsonTest(STEM, VALUE); \
}
#define WRITE_CHARACTERIZATION_TEST(NAME, STEM, VALUE) \
TEST_F(CommonProtoTest, NAME##_write) \
{ \
writeProtoTest(STEM, VALUE); \
} \
TEST_F(CommonProtoTest, NAME##_json_write) \
{ \
writeJsonTest(STEM, VALUE); \
}
#define CHARACTERIZATION_TEST(NAME, STEM, VALUE) \
READ_CHARACTERIZATION_TEST(NAME, STEM, VALUE) \
WRITE_CHARACTERIZATION_TEST(NAME, STEM, VALUE)
CHARACTERIZATION_TEST(
string,
"string",
@ -93,71 +108,6 @@ CHARACTERIZATION_TEST(
},
}))
CHARACTERIZATION_TEST(
drvOutput,
"drv-output",
(std::tuple<DrvOutput, DrvOutput>{
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "quux",
},
}))
CHARACTERIZATION_TEST(
realisation,
"realisation",
(std::tuple<Realisation, Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
}))
CHARACTERIZATION_TEST(
realisation_with_deps,
"realisation-with-deps",
(std::tuple<Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
.dependentRealisations =
{
{
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "quux",
},
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
}))
CHARACTERIZATION_TEST(
vector,
"vector",

View file

@ -0,0 +1,9 @@
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "NotDeterministic",
"stopTime": 0,
"success": false,
"timesBuilt": 1
}

View file

@ -0,0 +1,9 @@
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 30,
"status": "OutputRejected",
"stopTime": 50,
"success": false,
"timesBuilt": 3
}

View file

@ -0,0 +1,23 @@
{
"builtOutputs": {
"bar": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!bar",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"signatures": []
},
"foo": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
},
"cpuSystem": 604000000,
"cpuUser": 500000000,
"startTime": 30,
"status": "Built",
"stopTime": 50,
"success": true,
"timesBuilt": 3
}

View file

@ -0,0 +1,26 @@
[
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0="
},
"method": "text"
},
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
},
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
},
"method": "nar"
}
]

View file

@ -0,0 +1,4 @@
[
"sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux"
]

View file

@ -0,0 +1,11 @@
[
null,
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
}
]

View file

@ -0,0 +1,4 @@
[
null,
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,22 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
},
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"bar",
"foo"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -0,0 +1,4 @@
[
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,7 @@
[
"",
"hi",
"white rabbit",
"大白兔",
"oh no "
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"foo",
"bar"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -0,0 +1,46 @@
{
"additionalSandboxProfile": "sandcastle",
"allowLocalNetworking": true,
"allowSubstitutes": false,
"exportReferencesGraph": {
"refs1": [
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
],
"refs2": [
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
]
},
"impureEnvVars": [
"UNICORN"
],
"impureHostDeps": [
"/usr/bin/ditto"
],
"noChroot": true,
"outputChecks": {
"forAllOutputs": {
"allowedReferences": [
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
],
"allowedRequisites": [
"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"
],
"disallowedReferences": [
"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"
],
"disallowedRequisites": [
"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"
],
"ignoreSelfRefs": true,
"maxClosureSize": null,
"maxSize": null
}
},
"passAsFile": [],
"preferLocalBuild": true,
"requiredSystemFeatures": [
"rainbow",
"uid-range"
],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,66 @@
{
"additionalSandboxProfile": "sandcastle",
"allowLocalNetworking": true,
"allowSubstitutes": false,
"exportReferencesGraph": {
"refs1": [
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
],
"refs2": [
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
]
},
"impureEnvVars": [
"UNICORN"
],
"impureHostDeps": [
"/usr/bin/ditto"
],
"noChroot": true,
"outputChecks": {
"perOutput": {
"bin": {
"allowedReferences": null,
"allowedRequisites": null,
"disallowedReferences": [
"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"
],
"disallowedRequisites": [
"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"
],
"ignoreSelfRefs": false,
"maxClosureSize": null,
"maxSize": null
},
"dev": {
"allowedReferences": null,
"allowedRequisites": null,
"disallowedReferences": [],
"disallowedRequisites": [],
"ignoreSelfRefs": false,
"maxClosureSize": 5909,
"maxSize": 789
},
"out": {
"allowedReferences": [
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"
],
"allowedRequisites": [
"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"
],
"disallowedReferences": [],
"disallowedRequisites": [],
"ignoreSelfRefs": false,
"maxClosureSize": null,
"maxSize": null
}
}
},
"passAsFile": [],
"preferLocalBuild": true,
"requiredSystemFeatures": [
"rainbow",
"uid-range"
],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,46 @@
{
"additionalSandboxProfile": "sandcastle",
"allowLocalNetworking": true,
"allowSubstitutes": false,
"exportReferencesGraph": {
"refs1": [
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
],
"refs2": [
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
]
},
"impureEnvVars": [
"UNICORN"
],
"impureHostDeps": [
"/usr/bin/ditto"
],
"noChroot": true,
"outputChecks": {
"forAllOutputs": {
"allowedReferences": [
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
],
"allowedRequisites": [
"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"
],
"disallowedReferences": [
"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"
],
"disallowedRequisites": [
"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"
],
"ignoreSelfRefs": true,
"maxClosureSize": null,
"maxSize": null
}
},
"passAsFile": [],
"preferLocalBuild": true,
"requiredSystemFeatures": [
"rainbow",
"uid-range"
],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,24 @@
{
"additionalSandboxProfile": "",
"allowLocalNetworking": false,
"allowSubstitutes": true,
"exportReferencesGraph": {},
"impureEnvVars": [],
"impureHostDeps": [],
"noChroot": false,
"outputChecks": {
"forAllOutputs": {
"allowedReferences": null,
"allowedRequisites": null,
"disallowedReferences": [],
"disallowedRequisites": [],
"ignoreSelfRefs": true,
"maxClosureSize": null,
"maxSize": null
}
},
"passAsFile": [],
"preferLocalBuild": false,
"requiredSystemFeatures": [],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,66 @@
{
"additionalSandboxProfile": "sandcastle",
"allowLocalNetworking": true,
"allowSubstitutes": false,
"exportReferencesGraph": {
"refs1": [
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
],
"refs2": [
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
]
},
"impureEnvVars": [
"UNICORN"
],
"impureHostDeps": [
"/usr/bin/ditto"
],
"noChroot": true,
"outputChecks": {
"perOutput": {
"bin": {
"allowedReferences": null,
"allowedRequisites": null,
"disallowedReferences": [
"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"
],
"disallowedRequisites": [
"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"
],
"ignoreSelfRefs": false,
"maxClosureSize": null,
"maxSize": null
},
"dev": {
"allowedReferences": null,
"allowedRequisites": null,
"disallowedReferences": [],
"disallowedRequisites": [],
"ignoreSelfRefs": false,
"maxClosureSize": 5909,
"maxSize": 789
},
"out": {
"allowedReferences": [
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"
],
"allowedRequisites": [
"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"
],
"disallowedReferences": [],
"disallowedRequisites": [],
"ignoreSelfRefs": false,
"maxClosureSize": null,
"maxSize": null
}
}
},
"passAsFile": [],
"preferLocalBuild": true,
"requiredSystemFeatures": [
"rainbow",
"uid-range"
],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,16 @@
{
"additionalSandboxProfile": "",
"allowLocalNetworking": false,
"allowSubstitutes": true,
"exportReferencesGraph": {},
"impureEnvVars": [],
"impureHostDeps": [],
"noChroot": false,
"outputChecks": {
"perOutput": {}
},
"passAsFile": [],
"preferLocalBuild": false,
"requiredSystemFeatures": [],
"unsafeDiscardReferences": {}
}

View file

@ -0,0 +1,6 @@
{
"build-trace": {},
"contents": {},
"derivations": {},
"store-dir": "/nix/store"
}

View file

@ -0,0 +1,18 @@
{
"build-trace": {},
"contents": {},
"derivations": {
"rlqjbbb65ggcx9hy577hvnn929wz1aj0-foo.drv": {
"args": [],
"builder": "",
"env": {},
"inputDrvs": {},
"inputSrcs": [],
"name": "foo",
"outputs": {},
"system": "",
"version": 4
}
},
"store-dir": "/nix/store"
}

View file

@ -0,0 +1,35 @@
{
"build-trace": {},
"contents": {
"5hizn7xyyrhxr0k2magvxl5ccvk0ci9n-my-file": {
"contents": {
"contents": "asdf",
"executable": false,
"type": "regular"
},
"info": {
"ca": {
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "f1eduuSIYC1BofXA1tycF79Ai2NSMJQtUErx5DxLYSU="
},
"method": "nar"
},
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "f1eduuSIYC1BofXA1tycF79Ai2NSMJQtUErx5DxLYSU="
},
"narSize": 120,
"references": [],
"registrationTime": null,
"signatures": [],
"ultimate": false
}
}
},
"derivations": {},
"store-dir": "/nix/store"
}

View file

@ -1,6 +1,10 @@
{
"dependentRealisations": {},
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
"signatures": []
"key": {
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputName": "foo"
},
"value": {
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
}

View file

@ -1,8 +1,12 @@
{
"dependentRealisations": {},
"id": "sha256:ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
"signatures": [
"asdfasdfasdf"
]
"key": {
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputName": "foo"
},
"value": {
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdfasdfasdf"
]
}
}

View file

@ -0,0 +1,28 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "not deterministic",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"builtOutputs": {},
"startTime": 0,
"status": "built",
"stopTime": 0,
"success": true,
"timesBuilt": 0
}
]

View file

@ -0,0 +1,28 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "not deterministic",
"stopTime": 50,
"success": false,
"timesBuilt": 3
},
{
"builtOutputs": {},
"startTime": 30,
"status": "built",
"stopTime": 50,
"success": true,
"timesBuilt": 0
}
]

View file

@ -0,0 +1,41 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "not deterministic",
"stopTime": 50,
"success": false,
"timesBuilt": 3
},
{
"builtOutputs": {
"bar": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!bar",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"signatures": []
},
"foo": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
},
"startTime": 30,
"status": "built",
"stopTime": 50,
"success": true,
"timesBuilt": 1
}
]

View file

@ -0,0 +1,26 @@
[
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0="
},
"method": "text"
},
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
},
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
},
"method": "nar"
}
]

View file

@ -0,0 +1,4 @@
[
"sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux"
]

View file

@ -0,0 +1,11 @@
[
null,
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
}
]

View file

@ -0,0 +1,4 @@
[
null,
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,22 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
},
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"bar",
"foo"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -0,0 +1,4 @@
[
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,7 @@
[
"",
"hi",
"white rabbit",
"大白兔",
"oh no "
]

View file

@ -0,0 +1,32 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},
"narSize": 34878,
"references": [],
"registrationTime": null,
"signatures": [],
"ultimate": false
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": null,
"signatures": [],
"ultimate": false
}
]

View file

@ -0,0 +1,45 @@
[
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": null,
"signatures": [],
"ultimate": false
},
{
"ca": {
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
},
"method": "nar"
},
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"registrationTime": null,
"signatures": [
"fake-sig-1",
"fake-sig-2"
],
"ultimate": false
}
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"foo",
"bar"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -0,0 +1,5 @@
[
0,
1,
2
]

View file

@ -0,0 +1,28 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "not deterministic",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"builtOutputs": {},
"startTime": 0,
"status": "built",
"stopTime": 0,
"success": true,
"timesBuilt": 0
}
]

View file

@ -0,0 +1,41 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "not deterministic",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"builtOutputs": {
"bar": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!bar",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"signatures": []
},
"foo": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
},
"startTime": 0,
"status": "built",
"stopTime": 0,
"success": true,
"timesBuilt": 0
}
]

View file

@ -0,0 +1,41 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "not deterministic",
"stopTime": 50,
"success": false,
"timesBuilt": 3
},
{
"builtOutputs": {
"bar": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!bar",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"signatures": []
},
"foo": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
},
"startTime": 30,
"status": "built",
"stopTime": 50,
"success": true,
"timesBuilt": 1
}
]

View file

@ -0,0 +1,43 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "not deterministic",
"stopTime": 50,
"success": false,
"timesBuilt": 3
},
{
"builtOutputs": {
"bar": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!bar",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"signatures": []
},
"foo": {
"dependentRealisations": {},
"id": "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!foo",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
}
},
"cpuSystem": 604000000,
"cpuUser": 500000000,
"startTime": 30,
"status": "built",
"stopTime": 50,
"success": true,
"timesBuilt": 1
}
]

View file

@ -0,0 +1,26 @@
[
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "+Xc9Ll6mcPltwaewrk/BAQ56Y3G5T//wzhKUc0zrYu0="
},
"method": "text"
},
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
},
{
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
},
"method": "nar"
}
]

View file

@ -0,0 +1,16 @@
[
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
{
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"*"
]
},
{
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"x",
"y"
]
}
]

View file

@ -0,0 +1,17 @@
[
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv",
{
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"*"
]
},
{
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"x",
"y"
]
}
]

View file

@ -0,0 +1,4 @@
[
"sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux"
]

View file

@ -0,0 +1,27 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-xxx",
"startTime": 0,
"status": "output rejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"path": {
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"out"
]
},
"startTime": 30,
"status": "not deterministic",
"stopTime": 50,
"success": false,
"timesBuilt": 3
}
]

View file

@ -0,0 +1,11 @@
[
null,
{
"hash": {
"algorithm": "sha1",
"format": "base64",
"hash": "gGemBoenViNZM3hiwqns/Fgzqwo="
},
"method": "flat"
}
]

View file

@ -0,0 +1,4 @@
[
null,
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,5 @@
[
null,
true,
false
]

View file

@ -0,0 +1,22 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
},
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"bar",
"foo"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -0,0 +1,4 @@
[
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar"
]

View file

@ -0,0 +1,7 @@
[
"",
"hi",
"white rabbit",
"大白兔",
"oh no "
]

View file

@ -0,0 +1,32 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": false
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": 23423,
"signatures": [],
"ultimate": false
}
]

View file

@ -0,0 +1,35 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": false
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo"
],
"registrationTime": 23423,
"signatures": [],
"ultimate": false
}
]

View file

@ -0,0 +1,63 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": true
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo"
],
"registrationTime": 23423,
"signatures": [
"fake-sig-1",
"fake-sig-2"
],
"ultimate": false
},
{
"ca": {
"hash": {
"algorithm": "sha256",
"format": "base64",
"hash": "EMIJ+giQ/gLIWoxmPKjno3zHZrxbGymgzGGyZvZBIdM="
},
"method": "nar"
},
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "n5wkd9frr45pa74if5gpz9j7mifg27fh-foo",
"references": [
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"registrationTime": 23423,
"signatures": [],
"ultimate": false
}
]

View file

@ -0,0 +1,22 @@
[
[],
[
""
],
[
"",
"foo",
"bar"
],
[
[],
[
""
],
[
"",
"1",
"2"
]
]
]

View file

@ -10,13 +10,15 @@
#include "nix/util/json-utils.hh"
#include "nix/store/tests/libstore.hh"
#include "nix/util/tests/characterization.hh"
#include "nix/util/tests/json-characterization.hh"
namespace nix {
using namespace nlohmann;
class DerivationAdvancedAttrsTest : public CharacterizationTest, public LibStoreTest
class DerivationAdvancedAttrsTest : public JsonCharacterizationTest<Derivation>,
public JsonCharacterizationTest<DerivationOptions>,
public LibStoreTest
{
protected:
std::filesystem::path unitTestData = getUnitTestData() / "derivation" / "ia";
@ -32,6 +34,33 @@ public:
* to worry about race conditions if the tests run concurrently.
*/
ExperimentalFeatureSettings mockXpSettings;
/**
* Helper function to test getRequiredSystemFeatures for a given derivation file
*/
void testRequiredSystemFeatures(const std::string & fileName, const StringSet & expectedFeatures)
{
this->readTest(fileName, [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedFeatures);
});
}
/**
* Helper function to test DerivationOptions parsing and comparison
*/
void testDerivationOptions(
const std::string & fileName, const DerivationOptions & expected, const StringSet & expectedSystemFeatures)
{
this->readTest(fileName, [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options, expected);
EXPECT_EQ(options.getRequiredSystemFeatures(got), expectedSystemFeatures);
});
}
};
class CaDerivationAdvancedAttrsTest : public DerivationAdvancedAttrsTest
@ -100,33 +129,35 @@ TEST_ATERM_JSON(advancedAttributes_structuredAttrs_defaults, "advanced-attribute
using ExportReferencesMap = decltype(DerivationOptions::exportReferencesGraph);
static const DerivationOptions advancedAttributes_defaults = {
.outputChecks =
DerivationOptions::OutputChecks{
.ignoreSelfRefs = true,
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph = {},
.additionalSandboxProfile = "",
.noChroot = false,
.impureHostDeps = {},
.impureEnvVars = {},
.allowLocalNetworking = false,
.requiredSystemFeatures = {},
.preferLocalBuild = false,
.allowSubstitutes = true,
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
{
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_TRUE(!got.structuredAttrs);
EXPECT_EQ(options.additionalSandboxProfile, "");
EXPECT_EQ(options.noChroot, false);
EXPECT_EQ(options.impureHostDeps, StringSet{});
EXPECT_EQ(options.impureEnvVars, StringSet{});
EXPECT_EQ(options.allowLocalNetworking, false);
EXPECT_EQ(options.exportReferencesGraph, ExportReferencesMap{});
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(options, advancedAttributes_defaults);
EXPECT_EQ(checksForAllOutputs.allowedReferences, std::nullopt);
EXPECT_EQ(checksForAllOutputs.allowedRequisites, std::nullopt);
EXPECT_EQ(checksForAllOutputs.disallowedReferences, StringSet{});
EXPECT_EQ(checksForAllOutputs.disallowedRequisites, StringSet{});
}
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
EXPECT_EQ(options.substitutesAllowed(), true);
@ -136,152 +167,124 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_defaults)
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
testRequiredSystemFeatures("advanced-attributes-defaults.drv", {});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_defaults)
{
this->readTest("advanced-attributes-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
testRequiredSystemFeatures("advanced-attributes-defaults.drv", {"ca-derivations"});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes)
{
DerivationOptions expected = {
.outputChecks =
DerivationOptions::OutputChecks{
.ignoreSelfRefs = true,
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_TRUE(!got.structuredAttrs);
EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
EXPECT_EQ(options.noChroot, true);
EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"});
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
// Reset fields that vary between test cases to enable whole-object comparison
options.outputChecks = DerivationOptions::OutputChecks{.ignoreSelfRefs = true};
options.exportReferencesGraph = {};
EXPECT_EQ(options, expected);
EXPECT_EQ(options.substitutesAllowed(), false);
EXPECT_EQ(options.useUidRange(got), true);
});
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes)
DerivationOptions advancedAttributes_ia = {
.outputChecks =
DerivationOptions::OutputChecks{
.ignoreSelfRefs = true,
.allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"},
.disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"},
.allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"},
.disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"},
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph{
{"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}},
{"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}},
},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_ia)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
testDerivationOptions("advanced-attributes.drv", advancedAttributes_ia, {"rainbow", "uid-range"});
};
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(
options.exportReferencesGraph,
(ExportReferencesMap{
{
"refs1",
{
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo",
},
},
{
"refs2",
{
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",
},
},
}));
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites,
StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ(
checksForAllOutputs.disallowedRequisites,
StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
}
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
DerivationOptions advancedAttributes_ca = {
.outputChecks =
DerivationOptions::OutputChecks{
.ignoreSelfRefs = true,
.allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"},
.disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"},
.allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"},
.disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"},
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph{
{"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}},
{"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}},
},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes)
{
this->readTest("advanced-attributes.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
testDerivationOptions("advanced-attributes.drv", advancedAttributes_ca, {"rainbow", "uid-range", "ca-derivations"});
};
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(
options.exportReferencesGraph,
(ExportReferencesMap{
{
"refs1",
{
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9",
},
},
{
"refs2",
{
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
},
},
}));
{
auto * checksForAllOutputs_ = std::get_if<0>(&options.outputChecks);
ASSERT_TRUE(checksForAllOutputs_ != nullptr);
auto & checksForAllOutputs = *checksForAllOutputs_;
EXPECT_EQ(
checksForAllOutputs.allowedReferences,
StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(
checksForAllOutputs.allowedRequisites,
StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
EXPECT_EQ(
checksForAllOutputs.disallowedReferences,
StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
checksForAllOutputs.disallowedRequisites,
StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
DerivationOptions advancedAttributes_structuredAttrs_defaults = {
.outputChecks = std::map<std::string, DerivationOptions::OutputChecks>{},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph = {},
.additionalSandboxProfile = "",
.noChroot = false,
.impureHostDeps = {},
.impureEnvVars = {},
.allowLocalNetworking = false,
.requiredSystemFeatures = {},
.preferLocalBuild = false,
.allowSubstitutes = true,
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_defaults)
@ -289,26 +292,11 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_TRUE(got.structuredAttrs);
EXPECT_EQ(options.additionalSandboxProfile, "");
EXPECT_EQ(options.noChroot, false);
EXPECT_EQ(options.impureHostDeps, StringSet{});
EXPECT_EQ(options.impureEnvVars, StringSet{});
EXPECT_EQ(options.allowLocalNetworking, false);
EXPECT_EQ(options.exportReferencesGraph, ExportReferencesMap{});
{
auto * checksPerOutput_ = std::get_if<1>(&options.outputChecks);
ASSERT_TRUE(checksPerOutput_ != nullptr);
auto & checksPerOutput = *checksPerOutput_;
EXPECT_EQ(checksPerOutput.size(), 0u);
}
EXPECT_EQ(options, advancedAttributes_structuredAttrs_defaults);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
@ -319,55 +307,61 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs_d
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{});
});
testRequiredSystemFeatures("advanced-attributes-structured-attrs-defaults.drv", {});
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs_defaults)
{
this->readTest("advanced-attributes-structured-attrs-defaults.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(options.getRequiredSystemFeatures(got), StringSet{"ca-derivations"});
});
testRequiredSystemFeatures("advanced-attributes-structured-attrs-defaults.drv", {"ca-derivations"});
};
TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)
{
DerivationOptions expected = {
.outputChecks =
std::map<std::string, DerivationOptions::OutputChecks>{
{"dev",
DerivationOptions::OutputChecks{
.maxSize = 789,
.maxClosureSize = 5909,
}},
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph = {},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_TRUE(got.structuredAttrs);
EXPECT_EQ(options.additionalSandboxProfile, "sandcastle");
EXPECT_EQ(options.noChroot, true);
EXPECT_EQ(options.impureHostDeps, StringSet{"/usr/bin/ditto"});
EXPECT_EQ(options.impureEnvVars, StringSet{"UNICORN"});
EXPECT_EQ(options.allowLocalNetworking, true);
// Reset fields that vary between test cases to enable whole-object comparison
{
auto output_ = get(std::get<1>(options.outputChecks), "dev");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.maxSize, 789);
EXPECT_EQ(output.maxClosureSize, 5909);
// Delete all keys but "dev" in options.outputChecks
auto * outputChecksMapP =
std::get_if<std::map<std::string, DerivationOptions::OutputChecks>>(&options.outputChecks);
ASSERT_TRUE(outputChecksMapP);
auto & outputChecksMap = *outputChecksMapP;
auto devEntry = outputChecksMap.find("dev");
ASSERT_TRUE(devEntry != outputChecksMap.end());
auto devChecks = devEntry->second;
outputChecksMap.clear();
outputChecksMap.emplace("dev", std::move(devChecks));
}
options.exportReferencesGraph = {};
EXPECT_EQ(options, expected);
EXPECT_EQ(options.canBuildLocally(*this->store, got), false);
EXPECT_EQ(options.willBuildLocally(*this->store, got), false);
@ -376,112 +370,109 @@ TYPED_TEST(DerivationAdvancedAttrsBothTest, advancedAttributes_structuredAttrs)
});
};
DerivationOptions advancedAttributes_structuredAttrs_ia = {
.outputChecks =
std::map<std::string, DerivationOptions::OutputChecks>{
{"out",
DerivationOptions::OutputChecks{
.allowedReferences = StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"},
.allowedRequisites = StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"},
}},
{"bin",
DerivationOptions::OutputChecks{
.disallowedReferences = StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"},
.disallowedRequisites = StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"},
}},
{"dev",
DerivationOptions::OutputChecks{
.maxSize = 789,
.maxClosureSize = 5909,
}},
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph =
{
{"refs1", {"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"}},
{"refs2", {"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"}},
},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
TEST_F(DerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(
options.exportReferencesGraph,
(ExportReferencesMap{
{
"refs1",
{
"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo",
},
},
{
"refs2",
{
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv",
},
},
}));
testDerivationOptions(
"advanced-attributes-structured-attrs.drv", advancedAttributes_structuredAttrs_ia, {"rainbow", "uid-range"});
};
DerivationOptions advancedAttributes_structuredAttrs_ca = {
.outputChecks =
std::map<std::string, DerivationOptions::OutputChecks>{
{"out",
DerivationOptions::OutputChecks{
.allowedReferences = StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"},
.allowedRequisites = StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"},
}},
{"bin",
DerivationOptions::OutputChecks{
.disallowedReferences = StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"},
.disallowedRequisites = StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"},
}},
{"dev",
DerivationOptions::OutputChecks{
.maxSize = 789,
.maxClosureSize = 5909,
}},
},
.unsafeDiscardReferences = {},
.passAsFile = {},
.exportReferencesGraph =
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/nix/store/p0hax2lzvjpfc2gwkk62xdglz0fcqfzn-foo"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/nix/store/z0rjzy29v9k5qa4nqpykrbzirj7sd43v-foo-dev"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.disallowedReferences, StringSet{"/nix/store/r5cff30838majxk5mp3ip2diffi8vpaj-bar"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/nix/store/9b61w26b4avv870dw0ymb6rw4r1hzpws-bar-dev"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
{"refs1", {"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"}},
{"refs2", {"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"}},
},
.additionalSandboxProfile = "sandcastle",
.noChroot = true,
.impureHostDeps = {"/usr/bin/ditto"},
.impureEnvVars = {"UNICORN"},
.allowLocalNetworking = true,
.requiredSystemFeatures = {"rainbow", "uid-range"},
.preferLocalBuild = true,
.allowSubstitutes = false,
};
TEST_F(CaDerivationAdvancedAttrsTest, advancedAttributes_structuredAttrs)
{
this->readTest("advanced-attributes-structured-attrs.drv", [&](auto encoded) {
auto got = parseDerivation(*this->store, std::move(encoded), "foo", this->mockXpSettings);
auto drvPath = writeDerivation(*this->store, got, NoRepair, true);
DerivationOptions options = DerivationOptions::fromStructuredAttrs(got.env, got.structuredAttrs);
EXPECT_EQ(
options.exportReferencesGraph,
(ExportReferencesMap{
{
"refs1",
{
"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9",
},
},
{
"refs2",
{
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv",
},
},
}));
{
{
auto output_ = get(std::get<1>(options.outputChecks), "out");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(output.allowedReferences, StringSet{"/164j69y6zir9z0339n8pjigg3rckinlr77bxsavzizdaaljb7nh9"});
EXPECT_EQ(output.allowedRequisites, StringSet{"/0nr45p69vn6izw9446wsh9bng9nndhvn19kpsm4n96a5mycw0s4z"});
}
{
auto output_ = get(std::get<1>(options.outputChecks), "bin");
ASSERT_TRUE(output_);
auto & output = *output_;
EXPECT_EQ(
output.disallowedReferences, StringSet{"/0nyw57wm2iicnm9rglvjmbci3ikmcp823czdqdzdcgsnnwqps71g"});
EXPECT_EQ(
output.disallowedRequisites, StringSet{"/07f301yqyz8c6wf6bbbavb2q39j4n8kmcly1s09xadyhgy6x2wr8"});
}
}
StringSet systemFeatures{"rainbow", "uid-range"};
systemFeatures.insert("ca-derivations");
EXPECT_EQ(options.getRequiredSystemFeatures(got), systemFeatures);
});
testDerivationOptions(
"advanced-attributes-structured-attrs.drv",
advancedAttributes_structuredAttrs_ca,
{"rainbow", "uid-range", "ca-derivations"});
};
#define TEST_JSON_OPTIONS(FIXUTURE, VAR, VAR2) \
TEST_F(FIXUTURE, DerivationOptions_##VAR##_from_json) \
{ \
this->JsonCharacterizationTest<DerivationOptions>::readJsonTest(#VAR, advancedAttributes_##VAR2); \
} \
TEST_F(FIXUTURE, DerivationOptions_##VAR##_to_json) \
{ \
this->JsonCharacterizationTest<DerivationOptions>::writeJsonTest(#VAR, advancedAttributes_##VAR2); \
}
TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, defaults, defaults)
TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, all_set, ia)
TEST_JSON_OPTIONS(CaDerivationAdvancedAttrsTest, all_set, ca)
TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, structuredAttrs_defaults, structuredAttrs_defaults)
TEST_JSON_OPTIONS(DerivationAdvancedAttrsTest, structuredAttrs_all_set, structuredAttrs_ia)
TEST_JSON_OPTIONS(CaDerivationAdvancedAttrsTest, structuredAttrs_all_set, structuredAttrs_ca)
#undef TEST_JSON_OPTIONS
} // namespace nix

View file

@ -1,11 +1,33 @@
#include <gtest/gtest.h>
#include <nlohmann/json.hpp>
#include "nix/util/bytes.hh"
#include "nix/util/memory-source-accessor.hh"
#include "nix/store/dummy-store-impl.hh"
#include "nix/store/globals.hh"
#include "nix/store/realisation.hh"
#include "nix/util/tests/json-characterization.hh"
namespace nix {
class DummyStoreTest : public virtual CharacterizationTest
{
std::filesystem::path unitTestData = getUnitTestData() / "dummy-store";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
static void SetUpTestSuite()
{
initLibStore(false);
}
};
TEST(DummyStore, realisation_read)
{
initLibStore(/*loadConfig=*/false);
@ -16,23 +38,94 @@ TEST(DummyStore, realisation_read)
return cfg->openDummyStore();
}();
auto drvHash = Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", HashAlgorithm::SHA256, HashFormat::Base16);
StorePath drvPath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv"};
auto outputName = "foo";
EXPECT_EQ(store->queryRealisation({drvHash, outputName}), nullptr);
EXPECT_EQ(store->queryRealisation({drvPath, outputName}), nullptr);
UnkeyedRealisation value{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
};
store->buildTrace.insert({drvHash, {{outputName, make_ref<UnkeyedRealisation>(value)}}});
store->buildTrace.insert({drvPath, {{outputName, make_ref<UnkeyedRealisation>(value)}}});
auto value2 = store->queryRealisation({drvHash, outputName});
auto value2 = store->queryRealisation({drvPath, outputName});
ASSERT_TRUE(value2);
EXPECT_EQ(*value2, value);
}
/* ----------------------------------------------------------------------------
* JSON
* --------------------------------------------------------------------------*/
using nlohmann::json;
struct DummyStoreJsonTest : DummyStoreTest,
JsonCharacterizationTest<ref<DummyStore>>,
::testing::WithParamInterface<std::pair<std::string_view, ref<DummyStore>>>
{};
TEST_P(DummyStoreJsonTest, from_json)
{
auto & [name, expected] = GetParam();
using namespace nlohmann;
/* Cannot use `readJsonTest` because need to dereference the stores
for equality. */
readTest(Path{name} + ".json", [&](const auto & encodedRaw) {
auto encoded = json::parse(encodedRaw);
ref<DummyStore> decoded = adl_serializer<ref<DummyStore>>::from_json(encoded);
ASSERT_EQ(*decoded, *expected);
});
}
TEST_P(DummyStoreJsonTest, to_json)
{
auto & [name, value] = GetParam();
writeJsonTest(name, value);
}
INSTANTIATE_TEST_SUITE_P(DummyStoreJSON, DummyStoreJsonTest, [] {
initLibStore(false);
auto writeCfg = make_ref<DummyStore::Config>(DummyStore::Config::Params{});
writeCfg->readOnly = false;
return ::testing::Values(
std::pair{
"empty",
make_ref<DummyStore::Config>(DummyStore::Config::Params{})->openDummyStore(),
},
std::pair{
"one-flat-file",
[&] {
auto store = writeCfg->openDummyStore();
store->addToStore(
"my-file",
SourcePath{
[] {
auto sc = make_ref<MemorySourceAccessor>();
sc->root = MemorySourceAccessor::File{MemorySourceAccessor::File::Regular{
.executable = false,
.contents = to_owned(as_bytes("asdf")),
}};
return sc;
}(),
},
ContentAddressMethod::Raw::NixArchive,
HashAlgorithm::SHA256);
return store;
}(),
},
std::pair{
"one-derivation",
[&] {
auto store = writeCfg->openDummyStore();
Derivation drv;
drv.name = "foo";
store->writeDerivation(drv);
return store;
}(),
});
}());
} // namespace nix

View file

@ -54,6 +54,7 @@ deps_private += gtest
subdir('nix-meson-build-support/common')
sources = files(
'build-result.cc',
'common-protocol.cc',
'content-address.cc',
'derivation-advanced-attrs.cc',

View file

@ -59,24 +59,24 @@ static NarInfo makeNarInfo(const Store & store, bool includeImpureInfo)
return info;
}
#define JSON_TEST(STEM, PURE) \
TEST_F(NarInfoTest, NarInfo_##STEM##_from_json) \
{ \
readTest(#STEM, [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
auto expected = makeNarInfo(*store, PURE); \
NarInfo got = NarInfo::fromJSON(*store, expected.path, encoded); \
ASSERT_EQ(got, expected); \
}); \
} \
\
TEST_F(NarInfoTest, NarInfo_##STEM##_to_json) \
{ \
writeTest( \
#STEM, \
[&]() -> json { return makeNarInfo(*store, PURE).toJSON(*store, PURE, HashFormat::SRI); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
#define JSON_TEST(STEM, PURE) \
TEST_F(NarInfoTest, NarInfo_##STEM##_from_json) \
{ \
readTest(#STEM, [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
auto expected = makeNarInfo(*store, PURE); \
auto got = UnkeyedNarInfo::fromJSON(&*store, encoded); \
ASSERT_EQ(got, expected); \
}); \
} \
\
TEST_F(NarInfoTest, NarInfo_##STEM##_to_json) \
{ \
writeTest( \
#STEM, \
[&]() -> json { return makeNarInfo(*store, PURE).toJSON(&*store, PURE); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
}
JSON_TEST(pure, false)

View file

@ -70,7 +70,7 @@ static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo
{ \
readTest(#STEM, [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
UnkeyedValidPathInfo got = UnkeyedValidPathInfo::fromJSON(*store, encoded); \
UnkeyedValidPathInfo got = UnkeyedValidPathInfo::fromJSON(&*store, encoded); \
auto expected = OBJ; \
ASSERT_EQ(got, expected); \
}); \
@ -80,7 +80,7 @@ static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo
{ \
writeTest( \
#STEM, \
[&]() -> json { return OBJ.toJSON(*store, PURE, HashFormat::SRI); }, \
[&]() -> json { return OBJ.toJSON(&*store, PURE); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
}

View file

@ -44,54 +44,30 @@ TEST_P(RealisationJsonTest, to_json)
writeJsonTest(name, value);
}
INSTANTIATE_TEST_SUITE_P(
RealisationJSON,
RealisationJsonTest,
([] {
Realisation simple{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
},
{
.drvHash = Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Base16),
.outputName = "foo",
},
};
return ::testing::Values(
std::pair{
"simple",
simple,
},
std::pair{
"with-signature",
[&] {
auto r = simple;
// FIXME actually sign properly
r.signatures = {"asdfasdfasdf"};
return r;
}()},
std::pair{
"with-dependent-realisations",
[&] {
auto r = simple;
r.dependentRealisations = {{
{
.drvHash = Hash::parseExplicitFormatUnprefixed(
"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
HashAlgorithm::SHA256,
HashFormat::Base16),
.outputName = "foo",
},
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
}};
return r;
}(),
});
}
()));
INSTANTIATE_TEST_SUITE_P(RealisationJSON, RealisationJsonTest, ([] {
Realisation simple{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
{
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv"},
.outputName = "foo",
},
};
return ::testing::Values(
std::pair{
"simple",
simple,
},
std::pair{
"with-signature",
[&] {
auto r = simple;
// FIXME actually sign properly
r.signatures = {"asdfasdfasdf"};
return r;
}(),
});
}()));
} // namespace nix

View file

@ -1,5 +1,6 @@
#include "nix/store/references.hh"
#include "nix/store/path-references.hh"
#include "nix/util/bytes.hh"
#include "nix/util/memory-source-accessor.hh"
#include <gtest/gtest.h>
@ -104,21 +105,21 @@ TEST(references, scanForReferencesDeep)
// file1.txt: contains hash1
"file1.txt",
File::Regular{
.contents = "This file references " + hash1 + " in its content",
.contents = to_owned(as_bytes("This file references " + hash1 + " in its content")),
},
},
{
// file2.txt: contains hash2 and hash3
"file2.txt",
File::Regular{
.contents = "Multiple refs: " + hash2 + " and also " + hash3,
.contents = to_owned(as_bytes("Multiple refs: " + hash2 + " and also " + hash3)),
},
},
{
// file3.txt: contains no references
"file3.txt",
File::Regular{
.contents = "This file has no store path references at all",
.contents = to_owned(as_bytes("This file has no store path references at all")),
},
},
{
@ -130,7 +131,7 @@ TEST(references, scanForReferencesDeep)
// subdir/file4.txt: contains hash1 again
"file4.txt",
File::Regular{
.contents = "Subdirectory file with " + hash1,
.contents = to_owned(as_bytes("Subdirectory file with " + hash1)),
},
},
},
@ -140,7 +141,7 @@ TEST(references, scanForReferencesDeep)
// link1: a symlink that contains a reference in its target
"link1",
File::Symlink{
.target = hash2 + "-target",
.target = to_owned(as_bytes(hash2 + "-target")),
},
},
},

View file

@ -4,6 +4,7 @@
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include "nix/util/json-utils.hh"
#include "nix/store/serve-protocol.hh"
#include "nix/store/serve-protocol-impl.hh"
#include "nix/store/serve-protocol-connection.hh"
@ -72,16 +73,16 @@ VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST(
ServeProtoTest,
drvOutput,
"drv-output",
defaultVersion,
drvOutput_2_8,
"drv-output-2.8",
2 << 8 | 8,
(std::tuple<DrvOutput, DrvOutput>{
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "baz",
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "quux",
},
}))
@ -90,56 +91,27 @@ VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST(
ServeProtoTest,
realisation,
"realisation",
defaultVersion,
(std::tuple<Realisation, Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
unkeyedRealisation_2_8,
"unkeyed-realisation-2.8",
2 << 8 | 8,
(UnkeyedRealisation{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
}))
VERSIONED_CHARACTERIZATION_TEST(
ServeProtoTest,
realisation_with_deps,
"realisation-with-deps",
defaultVersion,
(std::tuple<Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
.dependentRealisations =
{
{
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "quux",
},
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
realisation_2_8,
"realisation-2.8",
2 << 8 | 8,
(Realisation{
UnkeyedRealisation{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
},
{
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "baz",
},
}))
@ -189,7 +161,10 @@ VERSIONED_CHARACTERIZATION_TEST(ServeProtoTest, buildResult_2_3, "build-result-2
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
/* We now do a lossy read which does not allow us to faithfully right
back, since we changed the data type. We still however want to test
that this read works, and so for that we have a one-way test. */
VERSIONED_READ_CHARACTERIZATION_TEST(
ServeProtoTest, buildResult_2_6, "build-result-2.6", 2 << 8 | 6, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
@ -215,27 +190,65 @@ VERSIONED_CHARACTERIZATION_TEST(
{
"foo",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
}},
.timesBuilt = 1,
.startTime = 30,
.stopTime = 50,
#if 0
// These fields are not yet serialized.
// FIXME Include in next version of protocol or document
// why they are skipped.
.cpuUser = std::chrono::milliseconds(500s),
.cpuSystem = std::chrono::milliseconds(604s),
#endif
},
};
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
ServeProtoTest, buildResult_2_8, "build-result-2.8", 2 << 8 | 8, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
BuildResult{.inner{BuildResult::Failure{
.status = BuildResult::Failure::OutputRejected,
.errorMsg = "no idea why",
}}},
BuildResult{
.inner{BuildResult::Failure{
.status = BuildResult::Failure::NotDeterministic,
.errorMsg = "no idea why",
.isNonDeterministic = true,
}},
.timesBuilt = 3,
.startTime = 30,
.stopTime = 50,
},
BuildResult{
.inner{BuildResult::Success{
.status = BuildResult::Success::Built,
.builtOutputs =
{
{
"foo",
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
@ -334,7 +347,7 @@ VERSIONED_CHARACTERIZATION_TEST(
}),
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_1,
"build-options-2.1",
@ -344,7 +357,7 @@ VERSIONED_CHARACTERIZATION_TEST(
.buildTimeout = 6,
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_2,
"build-options-2.2",
@ -355,7 +368,7 @@ VERSIONED_CHARACTERIZATION_TEST(
.maxLogSize = 7,
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_3,
"build-options-2.3",
@ -368,7 +381,7 @@ VERSIONED_CHARACTERIZATION_TEST(
.enforceDeterminism = true,
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_7,
"build-options-2.7",

View file

@ -4,6 +4,7 @@
#include <nlohmann/json.hpp>
#include <gtest/gtest.h>
#include "nix/util/json-utils.hh"
#include "nix/store/worker-protocol.hh"
#include "nix/store/worker-protocol-connection.hh"
#include "nix/store/worker-protocol-impl.hh"
@ -128,71 +129,42 @@ VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST(
WorkerProtoTest,
drvOutput,
"drv-output",
defaultVersion,
"drv-output-1.39",
1 << 8 | 39,
(std::tuple<DrvOutput, DrvOutput>{
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "baz",
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "quux",
},
}))
VERSIONED_CHARACTERIZATION_TEST(
WorkerProtoTest,
realisation,
"realisation",
defaultVersion,
(std::tuple<Realisation, Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
},
unkeyedRealisation_1_39,
"unkeyed-realisation-1.39",
1 << 8 | 39,
(UnkeyedRealisation{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
}))
VERSIONED_CHARACTERIZATION_TEST(
WorkerProtoTest,
realisation_with_deps,
"realisation-with-deps",
defaultVersion,
(std::tuple<Realisation>{
Realisation{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
.dependentRealisations =
{
{
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "quux",
},
StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
},
{
.drvHash = Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
.outputName = "baz",
},
realisation_1_39,
"realisation-1.39",
1 << 8 | 39,
(Realisation{
UnkeyedRealisation{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
.signatures = {"asdf", "qwer"},
},
{
.drvPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"},
.outputName = "baz",
},
}))
@ -214,7 +186,10 @@ VERSIONED_CHARACTERIZATION_TEST(WorkerProtoTest, buildResult_1_27, "build-result
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
/* We now do a lossy read which does not allow us to faithfully right
back, since we changed the data type. We still however want to test
that this read works, and so for that we have a one-way test. */
VERSIONED_READ_CHARACTERIZATION_TEST(
WorkerProtoTest, buildResult_1_28, "build-result-1.28", 1 << 8 | 28, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
@ -233,25 +208,13 @@ VERSIONED_CHARACTERIZATION_TEST(
{
"foo",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
DrvOutput{
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
@ -260,7 +223,8 @@ VERSIONED_CHARACTERIZATION_TEST(
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
// See above note
VERSIONED_READ_CHARACTERIZATION_TEST(
WorkerProtoTest, buildResult_1_29, "build-result-1.29", 1 << 8 | 29, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
@ -286,27 +250,13 @@ VERSIONED_CHARACTERIZATION_TEST(
{
"foo",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
@ -319,7 +269,8 @@ VERSIONED_CHARACTERIZATION_TEST(
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
// See above note
VERSIONED_READ_CHARACTERIZATION_TEST(
WorkerProtoTest, buildResult_1_37, "build-result-1.37", 1 << 8 | 37, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
@ -345,27 +296,60 @@ VERSIONED_CHARACTERIZATION_TEST(
{
"foo",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "foo",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
DrvOutput{
.drvHash =
Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
.outputName = "bar",
},
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
}},
.timesBuilt = 1,
.startTime = 30,
.stopTime = 50,
.cpuUser = std::chrono::microseconds(500s),
.cpuSystem = std::chrono::microseconds(604s),
},
};
t;
}))
VERSIONED_CHARACTERIZATION_TEST(
WorkerProtoTest, buildResult_1_39, "build-result-1.39", 1 << 8 | 39, ({
using namespace std::literals::chrono_literals;
std::tuple<BuildResult, BuildResult, BuildResult> t{
BuildResult{.inner{BuildResult::Failure{
.status = BuildResult::Failure::OutputRejected,
.errorMsg = "no idea why",
}}},
BuildResult{
.inner{BuildResult::Failure{
.status = BuildResult::Failure::NotDeterministic,
.errorMsg = "no idea why",
.isNonDeterministic = true,
}},
.timesBuilt = 3,
.startTime = 30,
.stopTime = 50,
},
BuildResult{
.inner{BuildResult::Success{
.status = BuildResult::Success::Built,
.builtOutputs =
{
{
"foo",
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
},
},
{
"bar",
{
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
},
},
},
@ -649,7 +633,7 @@ VERSIONED_CHARACTERIZATION_TEST(
},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_30,
"client-handshake-info_1_30",
@ -658,7 +642,7 @@ VERSIONED_CHARACTERIZATION_TEST(
{},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_33,
"client-handshake-info_1_33",
@ -672,7 +656,7 @@ VERSIONED_CHARACTERIZATION_TEST(
},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_35,
"client-handshake-info_1_35",

View file

@ -514,7 +514,7 @@ StorePath BinaryCacheStore::addToStore(
std::string BinaryCacheStore::makeRealisationPath(const DrvOutput & id)
{
return realisationsPrefix + "/" + id.to_string() + ".doi";
return realisationsPrefix + "/" + id.drvPath.to_string() + "/" + id.outputName + ".doi";
}
void BinaryCacheStore::queryRealisationUncached(
@ -535,7 +535,10 @@ void BinaryCacheStore::queryRealisationUncached(
realisation = std::make_shared<const UnkeyedRealisation>(nlohmann::json::parse(*data));
} catch (Error & e) {
e.addTrace(
{}, "while parsing file '%s' as a realisation for key '%s'", outputInfoFilePath, id.to_string());
{},
"while parsing file '%s' as a build trace value for key '%s'",
outputInfoFilePath,
id.to_string());
throw;
}
return (*callbackPtr)(std::move(realisation));
@ -551,7 +554,10 @@ void BinaryCacheStore::registerDrvOutput(const Realisation & info)
{
if (diskCache)
diskCache->upsertRealisation(config.getReference().render(/*FIXME withParams=*/false), info);
upsertFile(makeRealisationPath(info.id), static_cast<nlohmann::json>(info).dump(), "application/json");
upsertFile(
makeRealisationPath(info.id),
static_cast<nlohmann::json>(static_cast<const UnkeyedRealisation &>(info)).dump(),
"application/json");
}
ref<RemoteFSAccessor> BinaryCacheStore::getRemoteFSAccessor(bool requireValidPath)

View file

@ -1,4 +1,6 @@
#include "nix/store/build-result.hh"
#include "nix/util/json-utils.hh"
#include <array>
namespace nix {
@ -11,4 +13,160 @@ std::strong_ordering BuildResult::Success::operator<=>(const BuildResult::Succes
bool BuildResult::Failure::operator==(const BuildResult::Failure &) const noexcept = default;
std::strong_ordering BuildResult::Failure::operator<=>(const BuildResult::Failure &) const noexcept = default;
static constexpr std::array<std::pair<BuildResult::Success::Status, std::string_view>, 4> successStatusStrings{{
#define ENUM_ENTRY(e) {BuildResult::Success::e, #e}
ENUM_ENTRY(Built),
ENUM_ENTRY(Substituted),
ENUM_ENTRY(AlreadyValid),
ENUM_ENTRY(ResolvesToAlreadyValid),
#undef ENUM_ENTRY
}};
static std::string_view successStatusToString(BuildResult::Success::Status status)
{
for (const auto & [enumVal, str] : successStatusStrings) {
if (enumVal == status)
return str;
}
throw Error("unknown success status: %d", static_cast<int>(status));
}
static BuildResult::Success::Status successStatusFromString(std::string_view str)
{
for (const auto & [enumVal, enumStr] : successStatusStrings) {
if (enumStr == str)
return enumVal;
}
throw Error("unknown built result success status '%s'", str);
}
static constexpr std::array<std::pair<BuildResult::Failure::Status, std::string_view>, 12> failureStatusStrings{{
#define ENUM_ENTRY(e) {BuildResult::Failure::e, #e}
ENUM_ENTRY(PermanentFailure),
ENUM_ENTRY(InputRejected),
ENUM_ENTRY(OutputRejected),
ENUM_ENTRY(TransientFailure),
ENUM_ENTRY(CachedFailure),
ENUM_ENTRY(TimedOut),
ENUM_ENTRY(MiscFailure),
ENUM_ENTRY(DependencyFailed),
ENUM_ENTRY(LogLimitExceeded),
ENUM_ENTRY(NotDeterministic),
ENUM_ENTRY(NoSubstituters),
ENUM_ENTRY(HashMismatch),
#undef ENUM_ENTRY
}};
static std::string_view failureStatusToString(BuildResult::Failure::Status status)
{
for (const auto & [enumVal, str] : failureStatusStrings) {
if (enumVal == status)
return str;
}
throw Error("unknown failure status: %d", static_cast<int>(status));
}
static BuildResult::Failure::Status failureStatusFromString(std::string_view str)
{
for (const auto & [enumVal, enumStr] : failureStatusStrings) {
if (enumStr == str)
return enumVal;
}
throw Error("unknown built result failure status '%s'", str);
}
} // namespace nix
namespace nlohmann {
using namespace nix;
void adl_serializer<BuildResult>::to_json(json & res, const BuildResult & br)
{
res = json::object();
// Common fields
res["timesBuilt"] = br.timesBuilt;
res["startTime"] = br.startTime;
res["stopTime"] = br.stopTime;
if (br.cpuUser.has_value()) {
res["cpuUser"] = br.cpuUser->count();
}
if (br.cpuSystem.has_value()) {
res["cpuSystem"] = br.cpuSystem->count();
}
// Handle success or failure variant
std::visit(
overloaded{
[&](const BuildResult::Success & success) {
res["success"] = true;
res["status"] = successStatusToString(success.status);
res["builtOutputs"] = success.builtOutputs;
},
[&](const BuildResult::Failure & failure) {
res["success"] = false;
res["status"] = failureStatusToString(failure.status);
res["errorMsg"] = failure.errorMsg;
res["isNonDeterministic"] = failure.isNonDeterministic;
},
},
br.inner);
}
BuildResult adl_serializer<BuildResult>::from_json(const json & _json)
{
auto & json = getObject(_json);
BuildResult br;
// Common fields
br.timesBuilt = getUnsigned(valueAt(json, "timesBuilt"));
br.startTime = getUnsigned(valueAt(json, "startTime"));
br.stopTime = getUnsigned(valueAt(json, "stopTime"));
if (auto cpuUser = optionalValueAt(json, "cpuUser")) {
br.cpuUser = std::chrono::microseconds(getUnsigned(*cpuUser));
}
if (auto cpuSystem = optionalValueAt(json, "cpuSystem")) {
br.cpuSystem = std::chrono::microseconds(getUnsigned(*cpuSystem));
}
// Determine success or failure based on success field
bool success = getBoolean(valueAt(json, "success"));
std::string statusStr = getString(valueAt(json, "status"));
if (success) {
BuildResult::Success s;
s.status = successStatusFromString(statusStr);
s.builtOutputs = valueAt(json, "builtOutputs");
br.inner = std::move(s);
} else {
BuildResult::Failure f;
f.status = failureStatusFromString(statusStr);
f.errorMsg = getString(valueAt(json, "errorMsg"));
f.isNonDeterministic = getBoolean(valueAt(json, "isNonDeterministic"));
br.inner = std::move(f);
}
return br;
}
KeyedBuildResult adl_serializer<KeyedBuildResult>::from_json(const json & json0)
{
auto json = getObject(json0);
return KeyedBuildResult{
adl_serializer<BuildResult>::from_json(json0),
valueAt(json, "path"),
};
}
void adl_serializer<KeyedBuildResult>::to_json(json & json, const KeyedBuildResult & kbr)
{
adl_serializer<BuildResult>::to_json(json, kbr);
json["path"] = kbr.path;
}
} // namespace nlohmann

View file

@ -212,9 +212,8 @@ Goal::Co DerivationBuildingGoal::tryToBuild()
given this information by the downstream goal, that cannot happen
anymore if the downstream goal only cares about one output, but
we care about all outputs. */
auto outputHashes = staticOutputHashes(worker.evalStore, *drv);
for (auto & [outputName, outputHash] : outputHashes) {
InitialOutput v{.outputHash = outputHash};
for (auto & [outputName, _] : drv->outputs) {
InitialOutput v;
/* TODO we might want to also allow randomizing the paths
for regular CA derivations, e.g. for sake of checking
@ -1106,7 +1105,7 @@ DerivationBuildingGoal::checkPathValidity(std::map<std::string, InitialOutput> &
: PathStatus::Corrupt,
};
}
auto drvOutput = DrvOutput{info.outputHash, i.first};
auto drvOutput = DrvOutput{drvPath, i.first};
if (experimentalFeatureSettings.isEnabled(Xp::CaDerivations)) {
if (auto real = worker.store.queryRealisation(drvOutput)) {
info.known = {

View file

@ -36,12 +36,6 @@ DerivationGoal::DerivationGoal(
, drvPath(drvPath)
, wantedOutput(wantedOutput)
, drv{std::make_unique<Derivation>(drv)}
, outputHash{[&] {
auto outputHashes = staticOutputHashes(worker.evalStore, drv);
if (auto * mOutputHash = get(outputHashes, wantedOutput))
return *mOutputHash;
throw Error("derivation '%s' does not have output '%s'", worker.store.printStorePath(drvPath), wantedOutput);
}()}
, buildMode(buildMode)
{
@ -100,7 +94,7 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
them. */
if (settings.useSubstitutes && drvOptions.substitutesAllowed()) {
if (!checkResult)
waitees.insert(upcast_goal(worker.makeDrvOutputSubstitutionGoal(DrvOutput{outputHash, wantedOutput})));
waitees.insert(upcast_goal(worker.makeDrvOutputSubstitutionGoal(DrvOutput{drvPath, wantedOutput})));
else {
auto * cap = getDerivationCA(*drv);
waitees.insert(upcast_goal(worker.makePathSubstitutionGoal(
@ -167,12 +161,7 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
// No `std::visit` for coroutines yet
if (auto * successP = resolvedResult.tryGetSuccess()) {
auto & success = *successP;
auto outputHashes = staticOutputHashes(worker.evalStore, *drv);
auto resolvedHashes = staticOutputHashes(worker.store, drvResolved);
auto outputHash = get(outputHashes, wantedOutput);
auto resolvedHash = get(resolvedHashes, wantedOutput);
if ((!outputHash) || (!resolvedHash))
if (!drv->outputs.contains(wantedOutput))
throw Error(
"derivation '%s' doesn't have expected output '%s' (derivation-goal.cc/resolve)",
worker.store.printStorePath(drvPath),
@ -181,7 +170,7 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
auto realisation = [&] {
auto take1 = get(success.builtOutputs, wantedOutput);
if (take1)
return static_cast<UnkeyedRealisation>(*take1);
return *take1;
/* The above `get` should work. But stateful tracking of
outputs in resolvedResult, this can get out of sync with the
@ -189,7 +178,7 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
check the store directly if it fails. */
auto take2 = worker.evalStore.queryRealisation(
DrvOutput{
.drvHash = *resolvedHash,
.drvPath = pathResolved,
.outputName = wantedOutput,
});
if (take2)
@ -205,15 +194,10 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
Realisation newRealisation{
realisation,
{
.drvHash = *outputHash,
.drvPath = drvPath,
.outputName = wantedOutput,
}};
newRealisation.signatures.clear();
if (!drv->type().isFixed()) {
auto & drvStore = worker.evalStore.isValidPath(drvPath) ? worker.evalStore : worker.store;
newRealisation.dependentRealisations =
drvOutputReferences(worker.store, *drv, realisation.outPath, &drvStore);
}
worker.store.signRealisation(newRealisation);
worker.store.registerDrvOutput(newRealisation);
}
@ -256,16 +240,7 @@ Goal::Co DerivationGoal::haveDerivation(bool storeDerivation)
/* In checking mode, the builder will not register any outputs.
So we want to make sure the ones that we wanted to check are
properly there. */
success.builtOutputs = {{
wantedOutput,
{
assertPathValidity(),
{
.drvHash = outputHash,
.outputName = wantedOutput,
},
},
}};
success.builtOutputs = {{wantedOutput, assertPathValidity()}};
} else {
/* Otherwise the builder will give us info for out output, but
also for other outputs. Filter down to just our output so as
@ -390,7 +365,7 @@ std::optional<std::pair<UnkeyedRealisation, PathStatus>> DerivationGoal::checkPa
if (drv->type().isImpure())
return std::nullopt;
auto drvOutput = DrvOutput{outputHash, wantedOutput};
auto drvOutput = DrvOutput{drvPath, wantedOutput};
std::optional<UnkeyedRealisation> mRealisation;
@ -430,7 +405,7 @@ std::optional<std::pair<UnkeyedRealisation, PathStatus>> DerivationGoal::checkPa
Realisation{
*mRealisation,
{
.drvHash = outputHash,
.drvPath = drvPath,
.outputName = wantedOutput,
},
});
@ -453,16 +428,7 @@ Goal::Done DerivationGoal::doneSuccess(BuildResult::Success::Status status, Unke
{
buildResult.inner = BuildResult::Success{
.status = status,
.builtOutputs = {{
wantedOutput,
{
std::move(builtOutput),
DrvOutput{
.drvHash = outputHash,
.outputName = wantedOutput,
},
},
}},
.builtOutputs = {{wantedOutput, std::move(builtOutput)}},
};
mcExpectedBuilds.reset();

View file

@ -12,7 +12,7 @@ DrvOutputSubstitutionGoal::DrvOutputSubstitutionGoal(const DrvOutput & id, Worke
: Goal(worker, init())
, id(id)
{
name = fmt("substitution of '%s'", id.to_string());
name = fmt("substitution of '%s'", id.render(worker.store));
trace("created");
}
@ -86,32 +86,8 @@ Goal::Co DrvOutputSubstitutionGoal::init()
if (!outputInfo)
continue;
bool failed = false;
Goals waitees;
for (const auto & [depId, depPath] : outputInfo->dependentRealisations) {
if (depId != id) {
if (auto localOutputInfo = worker.store.queryRealisation(depId);
localOutputInfo && localOutputInfo->outPath != depPath) {
warn(
"substituter '%s' has an incompatible realisation for '%s', ignoring.\n"
"Local: %s\n"
"Remote: %s",
sub->config.getHumanReadableURI(),
depId.to_string(),
worker.store.printStorePath(localOutputInfo->outPath),
worker.store.printStorePath(depPath));
failed = true;
break;
}
waitees.insert(worker.makeDrvOutputSubstitutionGoal(depId));
}
}
if (failed)
continue;
waitees.insert(worker.makePathSubstitutionGoal(outputInfo->outPath));
co_await await(std::move(waitees));
@ -131,7 +107,8 @@ Goal::Co DrvOutputSubstitutionGoal::init()
/* None left. Terminate this goal and let someone else deal
with it. */
debug("derivation output '%s' is required, but there is no substituter that can provide it", id.to_string());
debug(
"derivation output '%s' is required, but there is no substituter that can provide it", id.render(worker.store));
if (substituterFailed) {
worker.failedSubstitutions++;
@ -146,7 +123,7 @@ Goal::Co DrvOutputSubstitutionGoal::init()
std::string DrvOutputSubstitutionGoal::key()
{
return "a$" + std::string(id.to_string());
return "a$" + std::string(id.render(worker.store));
}
void DrvOutputSubstitutionGoal::handleEOF(Descriptor fd)

Some files were not shown because too many files have changed in this diff Show more