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-08 14:35:44 +01:00 committed by GitHub
commit b8d8e9829c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 1288 additions and 143 deletions

View file

@ -22,7 +22,15 @@ The store path info JSON format has been updated from version 1 to version 2:
- New: `"ca": {"method": "nar", "hash": {"algorithm": "sha256", "format": "base64", "hash": "EMIJ+giQ..."}}`
- Still `null` values for input-addressed store objects
Version 1 format is still accepted when reading for backward compatibility.
- **Structured hash fields**:
Hash values (`narHash` and `downloadHash`) are now structured JSON objects instead of strings:
- Old: `"narHash": "sha256:FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="`
- New: `"narHash": {"algorithm": "sha256", "format": "base64", "hash": "FePFYIlM..."}`
- Same structure applies to `downloadHash` in NAR info contexts
Nix currently only produces, and doesn't consume this format.
**Affected command**: `nix path-info --json`

View file

@ -71,7 +71,7 @@ $defs:
Note: This field may not be present in all contexts, such as when the path is used as the key and the the store object info the value in map.
narHash:
type: string
"$ref": "./hash-v1.yaml"
title: NAR Hash
description: |
Hash of the [file system object](@docroot@/store/file-system-object.md) part of the store object when serialized as a [Nix Archive](@docroot@/store/file-system-object/content-address.md#serial-nix-archive).
@ -229,7 +229,7 @@ $defs:
> This is an impure "`.narinfo`" field that may not be included in certain contexts.
downloadHash:
type: string
"$ref": "./hash-v1.yaml"
title: Download Hash
description: |
A digest for the compressed archive itself, as opposed to the data contained within.

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,25 @@ 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_CHARACTERIZATION_TEST_NO_JSON(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_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

@ -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;
@ -54,6 +55,14 @@ public:
TEST_F(CommonProtoTest, NAME##_write) \
{ \
writeProtoTest(STEM, VALUE); \
} \
TEST_F(CommonProtoTest, NAME##_json_read) \
{ \
readJsonTest(STEM, VALUE); \
} \
TEST_F(CommonProtoTest, NAME##_json_write) \
{ \
writeJsonTest(STEM, VALUE); \
}
CHARACTERIZATION_TEST(

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,13 @@
[
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,17 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
},
{
"dependentRealisations": {},
"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

@ -9,9 +9,17 @@
},
"compression": "xz",
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"downloadHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"downloadHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"downloadSize": 4029176,
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -7,7 +7,11 @@
},
"method": "nar"
},
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -1,7 +1,11 @@
{
"ca": null,
"deriver": null,
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 0,
"references": [],
"registrationTime": null,

View file

@ -1,6 +1,10 @@
{
"ca": null,
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 0,
"references": [],
"version": 2

View file

@ -8,7 +8,11 @@
"method": "nar"
},
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -7,7 +7,11 @@
},
"method": "nar"
},
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",

View file

@ -0,0 +1,28 @@
[
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "NotDeterministic",
"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,13 @@
[
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,17 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
},
{
"dependentRealisations": {},
"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,34 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},
"narSize": 34878,
"references": [],
"registrationTime": null,
"signatures": [],
"ultimate": false,
"version": 2
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": null,
"signatures": [],
"ultimate": false,
"version": 2
}
]

View file

@ -0,0 +1,47 @@
[
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": null,
"signatures": [],
"ultimate": false,
"version": 2
},
{
"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,
"version": 2
}
]

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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": false,
"startTime": 0,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"startTime": 30,
"status": "NotDeterministic",
"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": "OutputRejected",
"stopTime": 0,
"success": false,
"timesBuilt": 0
},
{
"errorMsg": "no idea why",
"isNonDeterministic": true,
"path": {
"drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"outputs": [
"out"
]
},
"startTime": 30,
"status": "NotDeterministic",
"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,13 @@
[
{
"dependentRealisations": {
"sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo"
},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": [
"asdf",
"qwer"
]
}
]

View file

@ -0,0 +1,17 @@
[
{
"dependentRealisations": {},
"id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz",
"outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo",
"signatures": []
},
{
"dependentRealisations": {},
"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,34 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": false,
"version": 2
},
{
"ca": null,
"deriver": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"references": [
"g1w7hyyyy1w7hy3qg1w7hy3qgqqqqy3q-foo.drv"
],
"registrationTime": 23423,
"signatures": [],
"ultimate": false,
"version": 2
}
]

View file

@ -0,0 +1,37 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": false,
"version": 2
},
{
"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,
"version": 2
}
]

View file

@ -0,0 +1,66 @@
[
{
"ca": null,
"deriver": null,
"narHash": {
"algorithm": "sha256",
"format": "base64",
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
},
"narSize": 34878,
"path": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"references": [],
"registrationTime": 23423,
"signatures": [],
"ultimate": true,
"version": 2
},
{
"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,
"version": 2
},
{
"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,
"version": 2
}
]

View file

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

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

@ -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"
@ -334,7 +335,7 @@ VERSIONED_CHARACTERIZATION_TEST(
}),
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_1,
"build-options-2.1",
@ -344,7 +345,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 +356,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 +369,7 @@ VERSIONED_CHARACTERIZATION_TEST(
.enforceDeterminism = true,
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
ServeProtoTest,
build_options_2_7,
"build-options-2.7",
@ -439,7 +440,7 @@ VERSIONED_CHARACTERIZATION_TEST(
TEST_F(ServeProtoTest, handshake_log)
{
CharacterizationTest::writeTest("handshake-to-client", [&]() -> std::string {
CharacterizationTest::writeTest("handshake-to-client.bin", [&]() -> std::string {
StringSink toClientLog;
Pipe toClient, toServer;
@ -475,7 +476,7 @@ struct NullBufferedSink : BufferedSink
TEST_F(ServeProtoTest, handshake_client_replay)
{
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](std::string toClientLog) {
NullBufferedSink nullSink;
StringSource in{toClientLog};
@ -487,7 +488,7 @@ TEST_F(ServeProtoTest, handshake_client_replay)
TEST_F(ServeProtoTest, handshake_client_truncated_replay_throws)
{
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](std::string toClientLog) {
for (size_t len = 0; len < toClientLog.size(); ++len) {
NullBufferedSink nullSink;
auto substring = toClientLog.substr(0, len);
@ -505,7 +506,7 @@ TEST_F(ServeProtoTest, handshake_client_truncated_replay_throws)
TEST_F(ServeProtoTest, handshake_client_corrupted_throws)
{
CharacterizationTest::readTest("handshake-to-client", [&](const std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](const std::string toClientLog) {
for (size_t idx = 0; idx < toClientLog.size(); ++idx) {
// corrupt a copy
std::string toClientLogCorrupt = toClientLog;

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"
@ -649,7 +650,7 @@ VERSIONED_CHARACTERIZATION_TEST(
},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_30,
"client-handshake-info_1_30",
@ -658,7 +659,7 @@ VERSIONED_CHARACTERIZATION_TEST(
{},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_33,
"client-handshake-info_1_33",
@ -672,7 +673,7 @@ VERSIONED_CHARACTERIZATION_TEST(
},
}))
VERSIONED_CHARACTERIZATION_TEST(
VERSIONED_CHARACTERIZATION_TEST_NO_JSON(
WorkerProtoTest,
clientHandshakeInfo_1_35,
"client-handshake-info_1_35",
@ -690,7 +691,7 @@ VERSIONED_CHARACTERIZATION_TEST(
TEST_F(WorkerProtoTest, handshake_log)
{
CharacterizationTest::writeTest("handshake-to-client", [&]() -> std::string {
CharacterizationTest::writeTest("handshake-to-client.bin", [&]() -> std::string {
StringSink toClientLog;
Pipe toClient, toServer;
@ -751,7 +752,7 @@ struct NullBufferedSink : BufferedSink
TEST_F(WorkerProtoTest, handshake_client_replay)
{
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](std::string toClientLog) {
NullBufferedSink nullSink;
StringSource in{toClientLog};
@ -764,7 +765,7 @@ TEST_F(WorkerProtoTest, handshake_client_replay)
TEST_F(WorkerProtoTest, handshake_client_truncated_replay_throws)
{
CharacterizationTest::readTest("handshake-to-client", [&](std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](std::string toClientLog) {
for (size_t len = 0; len < toClientLog.size(); ++len) {
NullBufferedSink nullSink;
auto substring = toClientLog.substr(0, len);
@ -782,7 +783,7 @@ TEST_F(WorkerProtoTest, handshake_client_truncated_replay_throws)
TEST_F(WorkerProtoTest, handshake_client_corrupted_throws)
{
CharacterizationTest::readTest("handshake-to-client", [&](const std::string toClientLog) {
CharacterizationTest::readTest("handshake-to-client.bin", [&](const std::string toClientLog) {
for (size_t idx = 0; idx < toClientLog.size(); ++idx) {
// corrupt a copy
std::string toClientLogCorrupt = toClientLog;

View file

@ -153,4 +153,20 @@ BuildResult adl_serializer<BuildResult>::from_json(const json & _json)
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

@ -423,15 +423,6 @@ void adl_serializer<DerivationOptions>::to_json(json & json, const DerivationOpt
json["allowSubstitutes"] = o.allowSubstitutes;
}
template<typename T>
static inline std::optional<T> ptrToOwned(const json * ptr)
{
if (ptr)
return std::optional{*ptr};
else
return std::nullopt;
}
DerivationOptions::OutputChecks adl_serializer<DerivationOptions::OutputChecks>::from_json(const json & json_)
{
auto & json = getObject(json_);

View file

@ -178,3 +178,4 @@ struct KeyedBuildResult : BuildResult
} // namespace nix
JSON_IMPL(nix::BuildResult)
JSON_IMPL(nix::KeyedBuildResult)

View file

@ -9,17 +9,38 @@ namespace nix {
struct StoreDirConfig;
struct NarInfo : ValidPathInfo
struct UnkeyedNarInfo : virtual UnkeyedValidPathInfo
{
std::string url;
std::string compression;
std::optional<Hash> fileHash;
uint64_t fileSize = 0;
UnkeyedNarInfo(UnkeyedValidPathInfo info)
: UnkeyedValidPathInfo(std::move(info))
{
}
bool operator==(const UnkeyedNarInfo &) const = default;
// TODO libc++ 16 (used by darwin) missing `std::optional::operator <=>`, can't do yet
// auto operator <=>(const NarInfo &) const = default;
nlohmann::json toJSON(const StoreDirConfig * store, bool includeImpureInfo) const override;
static UnkeyedNarInfo fromJSON(const StoreDirConfig * store, const nlohmann::json & json);
};
/**
* Key and the extra NAR fields
*/
struct NarInfo : ValidPathInfo, UnkeyedNarInfo
{
NarInfo() = delete;
NarInfo(ValidPathInfo info)
: ValidPathInfo{std::move(info)}
: UnkeyedValidPathInfo(std::move(static_cast<UnkeyedValidPathInfo &&>(info)))
// later moves will be partially ignored
, ValidPathInfo(std::move(info))
, UnkeyedNarInfo(std::move(info))
{
}
@ -37,13 +58,10 @@ struct NarInfo : ValidPathInfo
NarInfo(const StoreDirConfig & store, const std::string & s, const std::string & whence);
bool operator==(const NarInfo &) const = default;
// TODO libc++ 16 (used by darwin) missing `std::optional::operator <=>`, can't do yet
// auto operator <=>(const NarInfo &) const = default;
std::string to_string(const StoreDirConfig & store) const;
nlohmann::json toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const override;
static NarInfo fromJSON(const StoreDirConfig & store, const StorePath & path, const nlohmann::json & json);
};
} // namespace nix
JSON_IMPL(nix::UnkeyedNarInfo)

View file

@ -117,11 +117,11 @@ struct UnkeyedValidPathInfo
* @param includeImpureInfo If true, variable elements such as the
* registration time are included.
*/
virtual nlohmann::json toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const;
static UnkeyedValidPathInfo fromJSON(const StoreDirConfig & store, const nlohmann::json & json);
virtual nlohmann::json toJSON(const StoreDirConfig * store, bool includeImpureInfo) const;
static UnkeyedValidPathInfo fromJSON(const StoreDirConfig * store, const nlohmann::json & json);
};
struct ValidPathInfo : UnkeyedValidPathInfo
struct ValidPathInfo : virtual UnkeyedValidPathInfo
{
StorePath path;
@ -174,10 +174,14 @@ struct ValidPathInfo : UnkeyedValidPathInfo
ValidPathInfo(StorePath && path, UnkeyedValidPathInfo info)
: UnkeyedValidPathInfo(info)
, path(std::move(path)) {};
, path(std::move(path))
{
}
ValidPathInfo(const StorePath & path, UnkeyedValidPathInfo info)
: UnkeyedValidPathInfo(info)
, path(path) {};
: ValidPathInfo(StorePath{path}, std::move(info))
{
}
static ValidPathInfo
makeFromCA(const StoreDirConfig & store, std::string_view name, ContentAddressWithReferences && ca, Hash narHash);
@ -191,3 +195,6 @@ static_assert(std::is_move_constructible_v<ValidPathInfo>);
using ValidPathInfos = std::map<StorePath, ValidPathInfo>;
} // namespace nix
JSON_IMPL(nix::UnkeyedValidPathInfo)
JSON_IMPL(nix::ValidPathInfo)

View file

@ -182,5 +182,6 @@ public:
} // namespace nix
JSON_IMPL(nix::DrvOutput)
JSON_IMPL(nix::UnkeyedRealisation)
JSON_IMPL(nix::Realisation)

View file

@ -1004,4 +1004,10 @@ const ContentAddress * getDerivationCA(const BasicDerivation & drv);
std::map<DrvOutput, StorePath>
drvOutputReferences(Store & store, const Derivation & drv, const StorePath & outputPath, Store * evalStore = nullptr);
template<>
struct json_avoids_null<TrustedFlag> : std::true_type
{};
} // namespace nix
JSON_IMPL(nix::TrustedFlag)

View file

@ -10,6 +10,7 @@
#include "nix/util/closure.hh"
#include "nix/store/filetransfer.hh"
#include "nix/util/strings.hh"
#include "nix/util/json-utils.hh"
#include <boost/unordered/unordered_flat_set.hpp>
@ -479,3 +480,19 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd)
}
} // namespace nix
namespace nlohmann {
using namespace nix;
TrustedFlag adl_serializer<TrustedFlag>::from_json(const json & json)
{
return getBoolean(json) ? TrustedFlag::Trusted : TrustedFlag::NotTrusted;
}
void adl_serializer<TrustedFlag>::to_json(json & json, const TrustedFlag & trustedFlag)
{
json = static_cast<bool>(trustedFlag);
}
} // namespace nlohmann

View file

@ -7,7 +7,9 @@
namespace nix {
NarInfo::NarInfo(const StoreDirConfig & store, const std::string & s, const std::string & whence)
: ValidPathInfo(StorePath(StorePath::dummy), Hash(Hash::dummy)) // FIXME: hack
: UnkeyedValidPathInfo(Hash::dummy) // FIXME: hack
, ValidPathInfo(StorePath::dummy, static_cast<const UnkeyedValidPathInfo &>(*this)) // FIXME: hack
, UnkeyedNarInfo(static_cast<const UnkeyedValidPathInfo &>(*this))
{
unsigned line = 1;
@ -130,11 +132,11 @@ std::string NarInfo::to_string(const StoreDirConfig & store) const
return res;
}
nlohmann::json NarInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const
nlohmann::json UnkeyedNarInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const
{
using nlohmann::json;
auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo, hashFormat);
auto jsonObject = UnkeyedValidPathInfo::toJSON(store, includeImpureInfo);
if (includeImpureInfo) {
if (!url.empty())
@ -142,7 +144,7 @@ nlohmann::json NarInfo::toJSON(const StoreDirConfig & store, bool includeImpureI
if (!compression.empty())
jsonObject["compression"] = compression;
if (fileHash)
jsonObject["downloadHash"] = fileHash->to_string(hashFormat, true);
jsonObject["downloadHash"] = *fileHash;
if (fileSize)
jsonObject["downloadSize"] = fileSize;
}
@ -150,30 +152,43 @@ nlohmann::json NarInfo::toJSON(const StoreDirConfig & store, bool includeImpureI
return jsonObject;
}
NarInfo NarInfo::fromJSON(const StoreDirConfig & store, const StorePath & path, const nlohmann::json & json)
UnkeyedNarInfo UnkeyedNarInfo::fromJSON(const StoreDirConfig * store, const nlohmann::json & json)
{
using nlohmann::detail::value_t;
NarInfo res{ValidPathInfo{
path,
UnkeyedValidPathInfo::fromJSON(store, json),
}};
UnkeyedNarInfo res{UnkeyedValidPathInfo::fromJSON(store, json)};
auto & obj = getObject(json);
if (json.contains("url"))
res.url = getString(valueAt(obj, "url"));
if (auto * url = get(obj, "url"))
res.url = getString(*url);
if (json.contains("compression"))
res.compression = getString(valueAt(obj, "compression"));
if (auto * compression = get(obj, "compression"))
res.compression = getString(*compression);
if (json.contains("downloadHash"))
res.fileHash = Hash::parseAny(getString(valueAt(obj, "downloadHash")), std::nullopt);
if (auto * downloadHash = get(obj, "downloadHash"))
res.fileHash = *downloadHash;
if (json.contains("downloadSize"))
res.fileSize = getUnsigned(valueAt(obj, "downloadSize"));
if (auto * downloadSize = get(obj, "downloadSize"))
res.fileSize = getUnsigned(*downloadSize);
return res;
}
} // namespace nix
namespace nlohmann {
using namespace nix;
UnkeyedNarInfo adl_serializer<UnkeyedNarInfo>::from_json(const json & json)
{
return UnkeyedNarInfo::fromJSON(nullptr, json);
}
void adl_serializer<UnkeyedNarInfo>::to_json(json & json, const UnkeyedNarInfo & c)
{
json = c.toJSON(nullptr, true);
}
} // namespace nlohmann

View file

@ -149,8 +149,7 @@ ValidPathInfo ValidPathInfo::makeFromCA(
return res;
}
nlohmann::json
UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const
nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const
{
using nlohmann::json;
@ -158,19 +157,21 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInf
jsonObject["version"] = 2;
jsonObject["narHash"] = narHash.to_string(hashFormat, true);
jsonObject["narHash"] = narHash;
jsonObject["narSize"] = narSize;
{
auto & jsonRefs = jsonObject["references"] = json::array();
for (auto & ref : references)
jsonRefs.emplace_back(store.printStorePath(ref));
jsonRefs.emplace_back(store ? static_cast<json>(store->printStorePath(ref)) : static_cast<json>(ref));
}
jsonObject["ca"] = ca;
if (includeImpureInfo) {
jsonObject["deriver"] = deriver ? (std::optional{store.printStorePath(*deriver)}) : std::nullopt;
jsonObject["deriver"] = deriver ? (store ? static_cast<json>(std::optional{store->printStorePath(*deriver)})
: static_cast<json>(std::optional{*deriver}))
: static_cast<json>(std::optional<StorePath>{});
jsonObject["registrationTime"] = registrationTime ? (std::optional{registrationTime}) : std::nullopt;
@ -184,7 +185,7 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInf
return jsonObject;
}
UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store, const nlohmann::json & _json)
UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig * store, const nlohmann::json & _json)
{
UnkeyedValidPathInfo res{
Hash(Hash::dummy),
@ -192,44 +193,34 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store
auto & json = getObject(_json);
// Check version (optional for backward compatibility)
nlohmann::json::number_unsigned_t version = 1;
if (json.contains("version")) {
version = getUnsigned(valueAt(json, "version"));
if (version != 1 && version != 2) {
throw Error("Unsupported path info JSON format version %d, expected 1 through 2", version);
}
{
auto version = getUnsigned(valueAt(json, "version"));
if (version != 2)
throw Error("Unsupported path info JSON format version %d, only version 2 is currently supported", version);
}
res.narHash = Hash::parseAny(getString(valueAt(json, "narHash")), std::nullopt);
res.narHash = valueAt(json, "narHash");
res.narSize = getUnsigned(valueAt(json, "narSize"));
try {
auto references = getStringList(valueAt(json, "references"));
for (auto & input : references)
res.references.insert(store.parseStorePath(static_cast<const std::string &>(input)));
res.references.insert(store ? store->parseStorePath(getString(input)) : static_cast<StorePath>(input));
} catch (Error & e) {
e.addTrace({}, "while reading key 'references'");
throw;
}
// New format as this as nullable but mandatory field; handling
// missing is for back-compat.
if (auto * rawCa0 = optionalValueAt(json, "ca"))
if (auto * rawCa = getNullable(*rawCa0))
switch (version) {
case 1:
// old string format also used in SQLite DB and .narinfo
res.ca = ContentAddress::parse(getString(*rawCa));
break;
case 2 ... std::numeric_limits<decltype(version)>::max():
res.ca = *rawCa;
break;
}
try {
res.ca = ptrToOwned<ContentAddress>(getNullable(valueAt(json, "ca")));
} catch (Error & e) {
e.addTrace({}, "while reading key 'ca'");
throw;
}
if (auto * rawDeriver0 = optionalValueAt(json, "deriver"))
if (auto * rawDeriver = getNullable(*rawDeriver0))
res.deriver = store.parseStorePath(getString(*rawDeriver));
res.deriver = store ? store->parseStorePath(getString(*rawDeriver)) : static_cast<StorePath>(*rawDeriver);
if (auto * rawRegistrationTime0 = optionalValueAt(json, "registrationTime"))
if (auto * rawRegistrationTime = getNullable(*rawRegistrationTime0))
@ -245,3 +236,35 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store
}
} // namespace nix
namespace nlohmann {
using namespace nix;
UnkeyedValidPathInfo adl_serializer<UnkeyedValidPathInfo>::from_json(const json & json)
{
return UnkeyedValidPathInfo::fromJSON(nullptr, json);
}
void adl_serializer<UnkeyedValidPathInfo>::to_json(json & json, const UnkeyedValidPathInfo & c)
{
json = c.toJSON(nullptr, true);
}
ValidPathInfo adl_serializer<ValidPathInfo>::from_json(const json & json0)
{
auto json = getObject(json0);
return ValidPathInfo{
valueAt(json, "path"),
adl_serializer<UnkeyedValidPathInfo>::from_json(json0),
};
}
void adl_serializer<ValidPathInfo>::to_json(json & json, const ValidPathInfo & v)
{
adl_serializer<UnkeyedValidPathInfo>::to_json(json, v);
json["path"] = v.path;
}
} // namespace nlohmann

View file

@ -144,6 +144,16 @@ namespace nlohmann {
using namespace nix;
DrvOutput adl_serializer<DrvOutput>::from_json(const json & json)
{
return DrvOutput::parse(getString(json));
}
void adl_serializer<DrvOutput>::to_json(json & json, const DrvOutput & drvOutput)
{
json = drvOutput.to_string();
}
UnkeyedRealisation adl_serializer<UnkeyedRealisation>::from_json(const json & json0)
{
auto json = getObject(json0);
@ -182,14 +192,14 @@ Realisation adl_serializer<Realisation>::from_json(const json & json0)
return Realisation{
static_cast<UnkeyedRealisation>(json0),
DrvOutput::parse(valueAt(json, "id")),
valueAt(json, "id"),
};
}
void adl_serializer<Realisation>::to_json(json & json, const Realisation & r)
{
json = static_cast<const UnkeyedRealisation &>(r);
json["id"] = r.id.to_string();
json["id"] = r.id;
}
} // namespace nlohmann

View file

@ -11,6 +11,34 @@
namespace nix {
/**
* Golden test for JSON reading
*/
template<typename T>
void readJsonTest(CharacterizationTest & test, PathView testStem, const T & expected, auto... args)
{
using namespace nlohmann;
test.readTest(Path{testStem} + ".json", [&](const auto & encodedRaw) {
auto encoded = json::parse(encodedRaw);
T decoded = adl_serializer<T>::from_json(encoded, args...);
ASSERT_EQ(decoded, expected);
});
}
/**
* Golden test for JSON writing
*/
template<typename T>
void writeJsonTest(CharacterizationTest & test, PathView testStem, const T & value)
{
using namespace nlohmann;
test.writeTest(
Path{testStem} + ".json",
[&]() -> json { return static_cast<json>(value); },
[](const auto & file) { return json::parse(readFile(file)); },
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); });
}
/**
* Mixin class for writing characterization tests for `nlohmann::json`
* conversions for a given type.
@ -26,12 +54,7 @@ struct JsonCharacterizationTest : virtual CharacterizationTest
*/
void readJsonTest(PathView testStem, const T & expected, auto... args)
{
using namespace nlohmann;
readTest(Path{testStem} + ".json", [&](const auto & encodedRaw) {
auto encoded = json::parse(encodedRaw);
T decoded = adl_serializer<T>::from_json(encoded, args...);
ASSERT_EQ(decoded, expected);
});
nix::readJsonTest(*this, testStem, expected, args...);
}
/**
@ -42,12 +65,7 @@ struct JsonCharacterizationTest : virtual CharacterizationTest
*/
void writeJsonTest(PathView testStem, const T & value)
{
using namespace nlohmann;
writeTest(
Path{testStem} + ".json",
[&]() -> json { return static_cast<json>(value); },
[](const auto & file) { return json::parse(readFile(file)); },
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); });
nix::writeJsonTest(*this, testStem, value);
}
};

View file

@ -114,4 +114,13 @@ struct adl_serializer<std::optional<T>>
}
};
template<typename T>
static inline std::optional<T> ptrToOwned(const json * ptr)
{
if (ptr)
return std::optional{*ptr};
else
return std::nullopt;
}
} // namespace nlohmann

View file

@ -51,7 +51,7 @@ static json pathInfoToJSON(Store & store, const StorePathSet & storePaths, bool
// know the name yet until we've read the NAR info.
printedStorePath = store.printStorePath(info->path);
jsonObject = info->toJSON(store, true, HashFormat::SRI);
jsonObject = info->toJSON(&store, true);
if (showClosureSize) {
StorePathSet closure;

View file

@ -17,8 +17,16 @@ diff --unified --color=always \
jq --sort-keys 'map_values(.narHash)') \
<(jq --sort-keys <<-EOF
{
"$foo": "sha256-QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA=",
"$bar": "sha256-9fhYGu9fqxcQC2Kc81qh2RMo1QcLBUBo8U+pPn+jthQ=",
"$foo": {
"algorithm": "sha256",
"format": "base64",
"hash": "QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA="
},
"$bar": {
"algorithm": "sha256",
"format": "base64",
"hash": "9fhYGu9fqxcQC2Kc81qh2RMo1QcLBUBo8U+pPn+jthQ="
},
"$baz": null
}
EOF