Skip to content

Commit 147e183

Browse files
authored
Merge pull request #14426 from obsidiansystems/json-schema-build-result
JSON Impl and schema for BuildResult
2 parents 52b2909 + 389bcba commit 147e183

File tree

16 files changed

+467
-0
lines changed

16 files changed

+467
-0
lines changed

doc/manual/package.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ mkMesonDerivation (finalAttrs: {
4444
../../src/libstore-tests/data/derived-path
4545
../../src/libstore-tests/data/path-info
4646
../../src/libstore-tests/data/nar-info
47+
../../src/libstore-tests/data/build-result
4748
# Too many different types of files to filter for now
4849
../../doc/manual
4950
./.

doc/manual/source/SUMMARY.md.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
- [Derivation](protocols/json/derivation.md)
128128
- [Deriving Path](protocols/json/deriving-path.md)
129129
- [Build Trace Entry](protocols/json/build-trace-entry.md)
130+
- [Build Result](protocols/json/build-result.md)
130131
- [Serving Tarball Flakes](protocols/tarball-fetcher.md)
131132
- [Store Path Specification](protocols/store-path.md)
132133
- [Nix Archive (NAR) Format](protocols/nix-archive/index.md)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{{#include build-result-v1-fixed.md}}
2+
3+
## Examples
4+
5+
### Successful build
6+
7+
```json
8+
{{#include schema/build-result-v1/success.json}}
9+
```
10+
11+
### Failed build (output rejected)
12+
13+
```json
14+
{{#include schema/build-result-v1/output-rejected.json}}
15+
```
16+
17+
### Failed build (non-deterministic)
18+
19+
```json
20+
{{#include schema/build-result-v1/not-deterministic.json}}
21+
```

doc/manual/source/protocols/json/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ schemas = [
1616
'derivation-v3',
1717
'deriving-path-v1',
1818
'build-trace-entry-v1',
19+
'build-result-v1',
1920
]
2021

2122
schema_files = files()
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../../../../../src/libstore-tests/data/build-result
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"$schema": "http://json-schema.org/draft-04/schema"
2+
"$id": "https://nix.dev/manual/nix/latest/protocols/json/schema/build-result-v1.json"
3+
title: Build Result
4+
description: |
5+
This schema describes the JSON representation of Nix's `BuildResult` type, which represents the result of building a derivation or substituting store paths.
6+
7+
Build results can represent either successful builds (with built outputs) or various types of failures.
8+
9+
oneOf:
10+
- "$ref": "#/$defs/success"
11+
- "$ref": "#/$defs/failure"
12+
type: object
13+
required:
14+
- success
15+
- status
16+
properties:
17+
timesBuilt:
18+
type: integer
19+
minimum: 0
20+
title: Times built
21+
description: |
22+
How many times this build was performed.
23+
24+
startTime:
25+
type: integer
26+
minimum: 0
27+
title: Start time
28+
description: |
29+
The start time of the build (or one of the rounds, if it was repeated), as a Unix timestamp.
30+
31+
stopTime:
32+
type: integer
33+
minimum: 0
34+
title: Stop time
35+
description: |
36+
The stop time of the build (or one of the rounds, if it was repeated), as a Unix timestamp.
37+
38+
cpuUser:
39+
type: integer
40+
minimum: 0
41+
title: User CPU time
42+
description: |
43+
User CPU time the build took, in microseconds.
44+
45+
cpuSystem:
46+
type: integer
47+
minimum: 0
48+
title: System CPU time
49+
description: |
50+
System CPU time the build took, in microseconds.
51+
52+
"$defs":
53+
success:
54+
type: object
55+
title: Successful Build Result
56+
description: |
57+
Represents a successful build with built outputs.
58+
required:
59+
- success
60+
- status
61+
- builtOutputs
62+
properties:
63+
success:
64+
const: true
65+
title: Success indicator
66+
description: |
67+
Always true for successful build results.
68+
69+
status:
70+
type: string
71+
title: Success status
72+
description: |
73+
Status string for successful builds.
74+
enum:
75+
- "Built"
76+
- "Substituted"
77+
- "AlreadyValid"
78+
- "ResolvesToAlreadyValid"
79+
80+
builtOutputs:
81+
type: object
82+
title: Built outputs
83+
description: |
84+
A mapping from output names to their build trace entries.
85+
additionalProperties:
86+
"$ref": "build-trace-entry-v1.yaml"
87+
88+
failure:
89+
type: object
90+
title: Failed Build Result
91+
description: |
92+
Represents a failed build with error information.
93+
required:
94+
- success
95+
- status
96+
- errorMsg
97+
properties:
98+
success:
99+
const: false
100+
title: Success indicator
101+
description: |
102+
Always false for failed build results.
103+
104+
status:
105+
type: string
106+
title: Failure status
107+
description: |
108+
Status string for failed builds.
109+
enum:
110+
- "PermanentFailure"
111+
- "InputRejected"
112+
- "OutputRejected"
113+
- "TransientFailure"
114+
- "CachedFailure"
115+
- "TimedOut"
116+
- "MiscFailure"
117+
- "DependencyFailed"
118+
- "LogLimitExceeded"
119+
- "NotDeterministic"
120+
- "NoSubstituters"
121+
- "HashMismatch"
122+
123+
errorMsg:
124+
type: string
125+
title: Error message
126+
description: |
127+
Information about the error if the build failed.
128+
129+
isNonDeterministic:
130+
type: boolean
131+
title: Non-deterministic flag
132+
description: |
133+
If timesBuilt > 1, whether some builds did not produce the same result.
134+
135+
Note that 'isNonDeterministic = false' does not mean the build is deterministic,
136+
just that we don't have evidence of non-determinism.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../src/libstore-tests/data/build-result

src/json-schema-checks/meson.build

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ schemas += [
150150
'impure.json',
151151
],
152152
},
153+
{
154+
'stem' : 'build-result',
155+
'schema' : schema_dir / 'build-result-v1.yaml',
156+
'files' : [
157+
'success.json',
158+
'output-rejected.json',
159+
'not-deterministic.json',
160+
],
161+
},
153162
# Match exact variant
154163
{
155164
'stem' : 'store-object-info',

src/json-schema-checks/package.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mkMesonDerivation (finalAttrs: {
2828
../../src/libstore-tests/data/derived-path
2929
../../src/libstore-tests/data/path-info
3030
../../src/libstore-tests/data/nar-info
31+
../../src/libstore-tests/data/build-result
3132
./.
3233
];
3334

src/libstore-tests/build-result.cc

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
#include <gtest/gtest.h>
2+
3+
#include "nix/store/build-result.hh"
4+
#include "nix/util/tests/json-characterization.hh"
5+
6+
namespace nix {
7+
8+
class BuildResultTest : public virtual CharacterizationTest
9+
{
10+
std::filesystem::path unitTestData = getUnitTestData() / "build-result";
11+
12+
public:
13+
std::filesystem::path goldenMaster(std::string_view testStem) const override
14+
{
15+
return unitTestData / testStem;
16+
}
17+
};
18+
19+
using nlohmann::json;
20+
21+
struct BuildResultJsonTest : BuildResultTest,
22+
JsonCharacterizationTest<BuildResult>,
23+
::testing::WithParamInterface<std::pair<std::string_view, BuildResult>>
24+
{};
25+
26+
TEST_P(BuildResultJsonTest, from_json)
27+
{
28+
auto & [name, expected] = GetParam();
29+
readJsonTest(name, expected);
30+
}
31+
32+
TEST_P(BuildResultJsonTest, to_json)
33+
{
34+
auto & [name, value] = GetParam();
35+
writeJsonTest(name, value);
36+
}
37+
38+
using namespace std::literals::chrono_literals;
39+
40+
INSTANTIATE_TEST_SUITE_P(
41+
BuildResultJSON,
42+
BuildResultJsonTest,
43+
::testing::Values(
44+
std::pair{
45+
"not-deterministic",
46+
BuildResult{
47+
.inner{BuildResult::Failure{
48+
.status = BuildResult::Failure::NotDeterministic,
49+
.errorMsg = "no idea why",
50+
.isNonDeterministic = false, // Note: This field is separate from the status
51+
}},
52+
.timesBuilt = 1,
53+
},
54+
},
55+
std::pair{
56+
"output-rejected",
57+
BuildResult{
58+
.inner{BuildResult::Failure{
59+
.status = BuildResult::Failure::OutputRejected,
60+
.errorMsg = "no idea why",
61+
.isNonDeterministic = false,
62+
}},
63+
.timesBuilt = 3,
64+
.startTime = 30,
65+
.stopTime = 50,
66+
},
67+
},
68+
std::pair{
69+
"success",
70+
BuildResult{
71+
.inner{BuildResult::Success{
72+
.status = BuildResult::Success::Built,
73+
.builtOutputs{
74+
{
75+
"foo",
76+
{
77+
{
78+
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"},
79+
},
80+
DrvOutput{
81+
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
82+
.outputName = "foo",
83+
},
84+
},
85+
},
86+
{
87+
"bar",
88+
{
89+
{
90+
.outPath = StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar"},
91+
},
92+
DrvOutput{
93+
.drvHash = Hash::parseSRI("sha256-b4afnqKCO9oWXgYHb9DeQ2berSwOjS27rSd9TxXDc/U="),
94+
.outputName = "bar",
95+
},
96+
},
97+
},
98+
},
99+
}},
100+
.timesBuilt = 3,
101+
.startTime = 30,
102+
.stopTime = 50,
103+
.cpuUser = std::chrono::microseconds(500s),
104+
.cpuSystem = std::chrono::microseconds(604s),
105+
},
106+
}));
107+
108+
} // namespace nix

0 commit comments

Comments
 (0)