From 9c04c629e5e39c7ec55bbaf3590bf3b553faa2c2 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 6 Nov 2025 16:51:19 -0500 Subject: [PATCH 1/4] `UnkeyedValidPathInfo::fromJSON` Remove support for older version It turns out this code path is only used for unit tests (to ensure our JSON formats are possible to parse by other code, elsewhere). No user-facing functionality consumes this format. Therefore, let's drop the old version parsing support. --- doc/manual/rl-next/json-format-changes.md | 2 +- src/libstore/derivation-options.cc | 9 ------- src/libstore/path-info.cc | 30 ++++++++-------------- src/libutil/include/nix/util/json-utils.hh | 9 +++++++ 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/doc/manual/rl-next/json-format-changes.md b/doc/manual/rl-next/json-format-changes.md index c5518ee1b..ef442c27e 100644 --- a/doc/manual/rl-next/json-format-changes.md +++ b/doc/manual/rl-next/json-format-changes.md @@ -22,7 +22,7 @@ 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. +Nix currently only produces, and doesn't consume this format. **Affected command**: `nix path-info --json` diff --git a/src/libstore/derivation-options.cc b/src/libstore/derivation-options.cc index 75313841c..265f28e80 100644 --- a/src/libstore/derivation-options.cc +++ b/src/libstore/derivation-options.cc @@ -423,15 +423,6 @@ void adl_serializer::to_json(json & json, const DerivationOpt json["allowSubstitutes"] = o.allowSubstitutes; } -template -static inline std::optional ptrToOwned(const json * ptr) -{ - if (ptr) - return std::optional{*ptr}; - else - return std::nullopt; -} - DerivationOptions::OutputChecks adl_serializer::from_json(const json & json_) { auto & json = getObject(json_); diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc index c535d08f4..7d8bf4911 100644 --- a/src/libstore/path-info.cc +++ b/src/libstore/path-info.cc @@ -192,13 +192,10 @@ 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); @@ -213,19 +210,12 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store 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::max(): - res.ca = *rawCa; - break; - } + try { + res.ca = ptrToOwned(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)) diff --git a/src/libutil/include/nix/util/json-utils.hh b/src/libutil/include/nix/util/json-utils.hh index 7a3fe4f36..ec513ca25 100644 --- a/src/libutil/include/nix/util/json-utils.hh +++ b/src/libutil/include/nix/util/json-utils.hh @@ -114,4 +114,13 @@ struct adl_serializer> } }; +template +static inline std::optional ptrToOwned(const json * ptr) +{ + if (ptr) + return std::optional{*ptr}; + else + return std::nullopt; +} + } // namespace nlohmann From 4f1c8f62c38c5f9325eaa342cc0e625d45703a35 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 6 Nov 2025 17:07:15 -0500 Subject: [PATCH 2/4] Futher cleans up store object info JSON v2 Since we haven't released v2 yet (2.32 has v1) we can just update this in-place and avoid version churn. Note that as a nice side effect of using the standard `Hash` JSON impl, we don't neeed this `hashFormat` parameter anymore. --- doc/manual/rl-next/json-format-changes.md | 8 +++++ .../json/schema/store-object-info-v2.yaml | 4 +-- src/libstore-tests/data/nar-info/impure.json | 12 +++++-- src/libstore-tests/data/nar-info/pure.json | 6 +++- .../data/path-info/empty_impure.json | 6 +++- .../data/path-info/empty_pure.json | 6 +++- src/libstore-tests/data/path-info/impure.json | 6 +++- src/libstore-tests/data/path-info/pure.json | 6 +++- src/libstore-tests/nar-info.cc | 36 +++++++++---------- src/libstore-tests/path-info.cc | 2 +- src/libstore/include/nix/store/nar-info.hh | 2 +- src/libstore/include/nix/store/path-info.hh | 2 +- src/libstore/nar-info.cc | 22 ++++++------ src/libstore/path-info.cc | 7 ++-- src/nix/path-info.cc | 2 +- tests/functional/path-info.sh | 12 +++++-- 16 files changed, 91 insertions(+), 48 deletions(-) diff --git a/doc/manual/rl-next/json-format-changes.md b/doc/manual/rl-next/json-format-changes.md index ef442c27e..bd7e11243 100644 --- a/doc/manual/rl-next/json-format-changes.md +++ b/doc/manual/rl-next/json-format-changes.md @@ -22,6 +22,14 @@ 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 +- **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` diff --git a/doc/manual/source/protocols/json/schema/store-object-info-v2.yaml b/doc/manual/source/protocols/json/schema/store-object-info-v2.yaml index 4f442e0c3..44d9e5eae 100644 --- a/doc/manual/source/protocols/json/schema/store-object-info-v2.yaml +++ b/doc/manual/source/protocols/json/schema/store-object-info-v2.yaml @@ -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. diff --git a/src/libstore-tests/data/nar-info/impure.json b/src/libstore-tests/data/nar-info/impure.json index f35ff990b..13cfa8639 100644 --- a/src/libstore-tests/data/nar-info/impure.json +++ b/src/libstore-tests/data/nar-info/impure.json @@ -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", diff --git a/src/libstore-tests/data/nar-info/pure.json b/src/libstore-tests/data/nar-info/pure.json index 2c5cb3bde..470f92da9 100644 --- a/src/libstore-tests/data/nar-info/pure.json +++ b/src/libstore-tests/data/nar-info/pure.json @@ -7,7 +7,11 @@ }, "method": "nar" }, - "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=", + "narHash": { + "algorithm": "sha256", + "format": "base64", + "hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=" + }, "narSize": 34878, "references": [ "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", diff --git a/src/libstore-tests/data/path-info/empty_impure.json b/src/libstore-tests/data/path-info/empty_impure.json index 381acaa03..2fcd2078c 100644 --- a/src/libstore-tests/data/path-info/empty_impure.json +++ b/src/libstore-tests/data/path-info/empty_impure.json @@ -1,7 +1,11 @@ { "ca": null, "deriver": null, - "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=", + "narHash": { + "algorithm": "sha256", + "format": "base64", + "hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=" + }, "narSize": 0, "references": [], "registrationTime": null, diff --git a/src/libstore-tests/data/path-info/empty_pure.json b/src/libstore-tests/data/path-info/empty_pure.json index 6d3fa646b..365e2f646 100644 --- a/src/libstore-tests/data/path-info/empty_pure.json +++ b/src/libstore-tests/data/path-info/empty_pure.json @@ -1,6 +1,10 @@ { "ca": null, - "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=", + "narHash": { + "algorithm": "sha256", + "format": "base64", + "hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=" + }, "narSize": 0, "references": [], "version": 2 diff --git a/src/libstore-tests/data/path-info/impure.json b/src/libstore-tests/data/path-info/impure.json index 141b38a16..5e9944e5a 100644 --- a/src/libstore-tests/data/path-info/impure.json +++ b/src/libstore-tests/data/path-info/impure.json @@ -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", diff --git a/src/libstore-tests/data/path-info/pure.json b/src/libstore-tests/data/path-info/pure.json index 2c5cb3bde..470f92da9 100644 --- a/src/libstore-tests/data/path-info/pure.json +++ b/src/libstore-tests/data/path-info/pure.json @@ -7,7 +7,11 @@ }, "method": "nar" }, - "narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=", + "narHash": { + "algorithm": "sha256", + "format": "base64", + "hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=" + }, "narSize": 34878, "references": [ "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar", diff --git a/src/libstore-tests/nar-info.cc b/src/libstore-tests/nar-info.cc index 751c5e305..41faa9274 100644 --- a/src/libstore-tests/nar-info.cc +++ b/src/libstore-tests/nar-info.cc @@ -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); \ + 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); }, \ + [](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) diff --git a/src/libstore-tests/path-info.cc b/src/libstore-tests/path-info.cc index 63310c1c3..a40b26149 100644 --- a/src/libstore-tests/path-info.cc +++ b/src/libstore-tests/path-info.cc @@ -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"); }); \ } diff --git a/src/libstore/include/nix/store/nar-info.hh b/src/libstore/include/nix/store/nar-info.hh index 1684837c6..34606a89b 100644 --- a/src/libstore/include/nix/store/nar-info.hh +++ b/src/libstore/include/nix/store/nar-info.hh @@ -42,7 +42,7 @@ struct NarInfo : ValidPathInfo std::string to_string(const StoreDirConfig & store) const; - nlohmann::json toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const override; + nlohmann::json toJSON(const StoreDirConfig & store, bool includeImpureInfo) const override; static NarInfo fromJSON(const StoreDirConfig & store, const StorePath & path, const nlohmann::json & json); }; diff --git a/src/libstore/include/nix/store/path-info.hh b/src/libstore/include/nix/store/path-info.hh index cbc5abdb4..0f00a14b7 100644 --- a/src/libstore/include/nix/store/path-info.hh +++ b/src/libstore/include/nix/store/path-info.hh @@ -117,7 +117,7 @@ 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; + virtual nlohmann::json toJSON(const StoreDirConfig & store, bool includeImpureInfo) const; static UnkeyedValidPathInfo fromJSON(const StoreDirConfig & store, const nlohmann::json & json); }; diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc index 6f1abb273..4d4fb7de2 100644 --- a/src/libstore/nar-info.cc +++ b/src/libstore/nar-info.cc @@ -130,11 +130,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 NarInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo) const { using nlohmann::json; - auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo, hashFormat); + auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo); if (includeImpureInfo) { if (!url.empty()) @@ -142,7 +142,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; } @@ -161,17 +161,17 @@ NarInfo NarInfo::fromJSON(const StoreDirConfig & store, const StorePath & path, 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; } diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc index 7d8bf4911..811c397a4 100644 --- a/src/libstore/path-info.cc +++ b/src/libstore/path-info.cc @@ -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,7 +157,7 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInf jsonObject["version"] = 2; - jsonObject["narHash"] = narHash.to_string(hashFormat, true); + jsonObject["narHash"] = narHash; jsonObject["narSize"] = narSize; { @@ -198,7 +197,7 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store 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 { diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc index 146b775e5..697b73e5c 100644 --- a/src/nix/path-info.cc +++ b/src/nix/path-info.cc @@ -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; diff --git a/tests/functional/path-info.sh b/tests/functional/path-info.sh index 463ac6214..70ad1a7aa 100755 --- a/tests/functional/path-info.sh +++ b/tests/functional/path-info.sh @@ -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 From 94712c11dbb8c3776fef77f3fc367bd08bea38e0 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Sat, 13 Sep 2025 08:43:21 -0400 Subject: [PATCH 3/4] Make `ValidPathInfo`, `NarInfo` JSON instances, but don't yet use in the CLI Make instances for them that share code with `nix path-info`, but do a slightly different format without store paths containing store dirs (matching the other latest JSON formats). Progress on #13570. If we depend on the store dir, our JSON serializers/deserializers take extra arguements, and that interfaces with the likes of various frameworks for associating these with types (e.g. nlohmann in C++, Serde in Rust, and Aeson in Haskell). For now, `nix path-info` still uses the previous format, with store dirs. We may yet decide to "rip of the band-aid", and just switch it over, but that is left as a future PR. --- src/libstore-tests/nar-info.cc | 4 +-- src/libstore-tests/path-info.cc | 4 +-- src/libstore/include/nix/store/nar-info.hh | 32 ++++++++++++++++----- src/libstore/include/nix/store/path-info.hh | 18 ++++++++---- src/libstore/nar-info.cc | 31 ++++++++++++++------ src/libstore/path-info.cc | 30 +++++++++++++++---- src/nix/path-info.cc | 2 +- 7 files changed, 89 insertions(+), 32 deletions(-) diff --git a/src/libstore-tests/nar-info.cc b/src/libstore-tests/nar-info.cc index 41faa9274..1add98053 100644 --- a/src/libstore-tests/nar-info.cc +++ b/src/libstore-tests/nar-info.cc @@ -65,7 +65,7 @@ static NarInfo makeNarInfo(const Store & store, bool includeImpureInfo) readTest(#STEM, [&](const auto & encoded_) { \ auto encoded = json::parse(encoded_); \ auto expected = makeNarInfo(*store, PURE); \ - NarInfo got = NarInfo::fromJSON(*store, expected.path, encoded); \ + auto got = UnkeyedNarInfo::fromJSON(&*store, encoded); \ ASSERT_EQ(got, expected); \ }); \ } \ @@ -74,7 +74,7 @@ static NarInfo makeNarInfo(const Store & store, bool includeImpureInfo) { \ writeTest( \ #STEM, \ - [&]() -> json { return makeNarInfo(*store, PURE).toJSON(*store, PURE); }, \ + [&]() -> 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"); }); \ } diff --git a/src/libstore-tests/path-info.cc b/src/libstore-tests/path-info.cc index a40b26149..8c02bf403 100644 --- a/src/libstore-tests/path-info.cc +++ b/src/libstore-tests/path-info.cc @@ -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); }, \ + [&]() -> 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"); }); \ } diff --git a/src/libstore/include/nix/store/nar-info.hh b/src/libstore/include/nix/store/nar-info.hh index 34606a89b..92af0b7d5 100644 --- a/src/libstore/include/nix/store/nar-info.hh +++ b/src/libstore/include/nix/store/nar-info.hh @@ -9,17 +9,38 @@ namespace nix { struct StoreDirConfig; -struct NarInfo : ValidPathInfo +struct UnkeyedNarInfo : virtual UnkeyedValidPathInfo { std::string url; std::string compression; std::optional 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(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) const override; - static NarInfo fromJSON(const StoreDirConfig & store, const StorePath & path, const nlohmann::json & json); }; } // namespace nix + +JSON_IMPL(nix::UnkeyedNarInfo) diff --git a/src/libstore/include/nix/store/path-info.hh b/src/libstore/include/nix/store/path-info.hh index 0f00a14b7..8f6115b73 100644 --- a/src/libstore/include/nix/store/path-info.hh +++ b/src/libstore/include/nix/store/path-info.hh @@ -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) 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,5 @@ static_assert(std::is_move_constructible_v); using ValidPathInfos = std::map; } // namespace nix + +JSON_IMPL(nix::UnkeyedValidPathInfo) diff --git a/src/libstore/nar-info.cc b/src/libstore/nar-info.cc index 4d4fb7de2..2dbcee325 100644 --- a/src/libstore/nar-info.cc +++ b/src/libstore/nar-info.cc @@ -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(*this)) // FIXME: hack + , UnkeyedNarInfo(static_cast(*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) const +nlohmann::json UnkeyedNarInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const { using nlohmann::json; - auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo); + auto jsonObject = UnkeyedValidPathInfo::toJSON(store, includeImpureInfo); if (includeImpureInfo) { if (!url.empty()) @@ -150,14 +152,11 @@ 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); @@ -177,3 +176,19 @@ NarInfo NarInfo::fromJSON(const StoreDirConfig & store, const StorePath & path, } } // namespace nix + +namespace nlohmann { + +using namespace nix; + +UnkeyedNarInfo adl_serializer::from_json(const json & json) +{ + return UnkeyedNarInfo::fromJSON(nullptr, json); +} + +void adl_serializer::to_json(json & json, const UnkeyedNarInfo & c) +{ + json = c.toJSON(nullptr, true); +} + +} // namespace nlohmann diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc index 811c397a4..d56ba9475 100644 --- a/src/libstore/path-info.cc +++ b/src/libstore/path-info.cc @@ -149,7 +149,7 @@ ValidPathInfo ValidPathInfo::makeFromCA( return res; } -nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo) const +nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const { using nlohmann::json; @@ -163,13 +163,15 @@ nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool i { auto & jsonRefs = jsonObject["references"] = json::array(); for (auto & ref : references) - jsonRefs.emplace_back(store.printStorePath(ref)); + jsonRefs.emplace_back(store ? static_cast(store->printStorePath(ref)) : static_cast(ref)); } jsonObject["ca"] = ca; if (includeImpureInfo) { - jsonObject["deriver"] = deriver ? (std::optional{store.printStorePath(*deriver)}) : std::nullopt; + jsonObject["deriver"] = deriver ? (store ? static_cast(std::optional{store->printStorePath(*deriver)}) + : static_cast(std::optional{*deriver})) + : static_cast(std::optional{}); jsonObject["registrationTime"] = registrationTime ? (std::optional{registrationTime}) : std::nullopt; @@ -183,7 +185,7 @@ nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool i 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), @@ -203,7 +205,7 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store try { auto references = getStringList(valueAt(json, "references")); for (auto & input : references) - res.references.insert(store.parseStorePath(static_cast(input))); + res.references.insert(store ? store->parseStorePath(getString(input)) : static_cast(input)); } catch (Error & e) { e.addTrace({}, "while reading key 'references'"); throw; @@ -218,7 +220,7 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store 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(*rawDeriver); if (auto * rawRegistrationTime0 = optionalValueAt(json, "registrationTime")) if (auto * rawRegistrationTime = getNullable(*rawRegistrationTime0)) @@ -234,3 +236,19 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store } } // namespace nix + +namespace nlohmann { + +using namespace nix; + +UnkeyedValidPathInfo adl_serializer::from_json(const json & json) +{ + return UnkeyedValidPathInfo::fromJSON(nullptr, json); +} + +void adl_serializer::to_json(json & json, const UnkeyedValidPathInfo & c) +{ + json = c.toJSON(nullptr, true); +} + +} // namespace nlohmann diff --git a/src/nix/path-info.cc b/src/nix/path-info.cc index 697b73e5c..74921126b 100644 --- a/src/nix/path-info.cc +++ b/src/nix/path-info.cc @@ -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); + jsonObject = info->toJSON(&store, true); if (showClosureSize) { StorePathSet closure; From 8dbd43b5d4f873605d3a2de05f99f550cae0df56 Mon Sep 17 00:00:00 2001 From: John Ericson Date: Thu, 30 Oct 2025 14:47:05 -0400 Subject: [PATCH 4/4] JSON alongside binary proto serialization test data This makes the proto serializer characterisation test data be accompanied by JSON data. This is arguably useful for a reasons: - The JSON data is human-readable while the binary data is not, so it provides some indication of what the test data means beyond the C++ literals. - The JSON data is language-agnostic, and so can be used to quickly rig up tests for implementation in other languages, without having source code literals at all (just go back and forth between the JSON and the binary). - Even though we have no concrete plans to place the binary protocol 1-1 or with JSON, it is still nice to ensure that the JSON serializers and binary protocols have (near) equal coverage over data types, to help ensure we didn't forget a JSON (de)serializer. --- .../include/nix/store/tests/protocol.hh | 52 +++++++++++---- src/libstore-tests/common-protocol.cc | 13 +++- .../data/common-protocol/content-address.json | 26 ++++++++ .../data/common-protocol/drv-output.json | 4 ++ .../optional-content-address.json | 11 ++++ .../common-protocol/optional-store-path.json | 4 ++ .../realisation-with-deps.json | 13 ++++ .../data/common-protocol/realisation.json | 17 +++++ .../data/common-protocol/set.json | 22 +++++++ .../data/common-protocol/store-path.json | 4 ++ .../data/common-protocol/string.json | 7 ++ .../data/common-protocol/vector.json | 22 +++++++ .../data/serve-protocol/build-result-2.2.json | 28 ++++++++ .../data/serve-protocol/build-result-2.3.json | 28 ++++++++ .../data/serve-protocol/build-result-2.6.json | 41 ++++++++++++ .../data/serve-protocol/content-address.json | 26 ++++++++ .../data/serve-protocol/drv-output.json | 4 ++ .../optional-content-address.json | 11 ++++ .../serve-protocol/optional-store-path.json | 4 ++ .../serve-protocol/realisation-with-deps.json | 13 ++++ .../data/serve-protocol/realisation.json | 17 +++++ .../data/serve-protocol/set.json | 22 +++++++ .../data/serve-protocol/store-path.json | 4 ++ .../data/serve-protocol/string.json | 7 ++ .../unkeyed-valid-path-info-2.3.json | 34 ++++++++++ .../unkeyed-valid-path-info-2.4.json | 47 +++++++++++++ .../data/serve-protocol/vector.json | 22 +++++++ .../data/worker-protocol/build-mode.json | 5 ++ .../worker-protocol/build-result-1.27.json | 28 ++++++++ .../worker-protocol/build-result-1.28.json | 41 ++++++++++++ .../worker-protocol/build-result-1.29.json | 41 ++++++++++++ .../worker-protocol/build-result-1.37.json | 43 ++++++++++++ .../data/worker-protocol/content-address.json | 26 ++++++++ .../worker-protocol/derived-path-1.29.json | 16 +++++ .../worker-protocol/derived-path-1.30.json | 17 +++++ .../data/worker-protocol/drv-output.json | 4 ++ .../keyed-build-result-1.29.json | 27 ++++++++ .../optional-content-address.json | 11 ++++ .../worker-protocol/optional-store-path.json | 4 ++ .../optional-trusted-flag.json | 5 ++ .../realisation-with-deps.json | 13 ++++ .../data/worker-protocol/realisation.json | 17 +++++ .../data/worker-protocol/set.json | 22 +++++++ .../data/worker-protocol/store-path.json | 4 ++ .../data/worker-protocol/string.json | 7 ++ .../unkeyed-valid-path-info-1.15.json | 34 ++++++++++ .../worker-protocol/valid-path-info-1.15.json | 37 +++++++++++ .../worker-protocol/valid-path-info-1.16.json | 66 +++++++++++++++++++ .../data/worker-protocol/vector.json | 22 +++++++ src/libstore-tests/serve-protocol.cc | 17 ++--- src/libstore-tests/worker-protocol.cc | 15 +++-- src/libstore/build-result.cc | 16 +++++ .../include/nix/store/build-result.hh | 1 + src/libstore/include/nix/store/path-info.hh | 1 + src/libstore/include/nix/store/realisation.hh | 1 + src/libstore/include/nix/store/store-api.hh | 6 ++ src/libstore/misc.cc | 17 +++++ src/libstore/path-info.cc | 16 +++++ src/libstore/realisation.cc | 14 +++- .../nix/util/tests/json-characterization.hh | 42 ++++++++---- 60 files changed, 1097 insertions(+), 42 deletions(-) create mode 100644 src/libstore-tests/data/common-protocol/content-address.json create mode 100644 src/libstore-tests/data/common-protocol/drv-output.json create mode 100644 src/libstore-tests/data/common-protocol/optional-content-address.json create mode 100644 src/libstore-tests/data/common-protocol/optional-store-path.json create mode 100644 src/libstore-tests/data/common-protocol/realisation-with-deps.json create mode 100644 src/libstore-tests/data/common-protocol/realisation.json create mode 100644 src/libstore-tests/data/common-protocol/set.json create mode 100644 src/libstore-tests/data/common-protocol/store-path.json create mode 100644 src/libstore-tests/data/common-protocol/string.json create mode 100644 src/libstore-tests/data/common-protocol/vector.json create mode 100644 src/libstore-tests/data/serve-protocol/build-result-2.2.json create mode 100644 src/libstore-tests/data/serve-protocol/build-result-2.3.json create mode 100644 src/libstore-tests/data/serve-protocol/build-result-2.6.json create mode 100644 src/libstore-tests/data/serve-protocol/content-address.json create mode 100644 src/libstore-tests/data/serve-protocol/drv-output.json create mode 100644 src/libstore-tests/data/serve-protocol/optional-content-address.json create mode 100644 src/libstore-tests/data/serve-protocol/optional-store-path.json create mode 100644 src/libstore-tests/data/serve-protocol/realisation-with-deps.json create mode 100644 src/libstore-tests/data/serve-protocol/realisation.json create mode 100644 src/libstore-tests/data/serve-protocol/set.json create mode 100644 src/libstore-tests/data/serve-protocol/store-path.json create mode 100644 src/libstore-tests/data/serve-protocol/string.json create mode 100644 src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.3.json create mode 100644 src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.4.json create mode 100644 src/libstore-tests/data/serve-protocol/vector.json create mode 100644 src/libstore-tests/data/worker-protocol/build-mode.json create mode 100644 src/libstore-tests/data/worker-protocol/build-result-1.27.json create mode 100644 src/libstore-tests/data/worker-protocol/build-result-1.28.json create mode 100644 src/libstore-tests/data/worker-protocol/build-result-1.29.json create mode 100644 src/libstore-tests/data/worker-protocol/build-result-1.37.json create mode 100644 src/libstore-tests/data/worker-protocol/content-address.json create mode 100644 src/libstore-tests/data/worker-protocol/derived-path-1.29.json create mode 100644 src/libstore-tests/data/worker-protocol/derived-path-1.30.json create mode 100644 src/libstore-tests/data/worker-protocol/drv-output.json create mode 100644 src/libstore-tests/data/worker-protocol/keyed-build-result-1.29.json create mode 100644 src/libstore-tests/data/worker-protocol/optional-content-address.json create mode 100644 src/libstore-tests/data/worker-protocol/optional-store-path.json create mode 100644 src/libstore-tests/data/worker-protocol/optional-trusted-flag.json create mode 100644 src/libstore-tests/data/worker-protocol/realisation-with-deps.json create mode 100644 src/libstore-tests/data/worker-protocol/realisation.json create mode 100644 src/libstore-tests/data/worker-protocol/set.json create mode 100644 src/libstore-tests/data/worker-protocol/store-path.json create mode 100644 src/libstore-tests/data/worker-protocol/string.json create mode 100644 src/libstore-tests/data/worker-protocol/unkeyed-valid-path-info-1.15.json create mode 100644 src/libstore-tests/data/worker-protocol/valid-path-info-1.15.json create mode 100644 src/libstore-tests/data/worker-protocol/valid-path-info-1.16.json create mode 100644 src/libstore-tests/data/worker-protocol/vector.json diff --git a/src/libstore-test-support/include/nix/store/tests/protocol.hh b/src/libstore-test-support/include/nix/store/tests/protocol.hh index 5b57c6585..0f774df0e 100644 --- a/src/libstore-test-support/include/nix/store/tests/protocol.hh +++ b/src/libstore-test-support/include/nix/store/tests/protocol.hh @@ -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 + void readJsonTest(PathView testStem, const T & expected) + { + nix::readJsonTest(*this, testStem, expected); + } + + /** + * Golden test for `T` JSON write + */ + template + void writeJsonTest(PathView testStem, const T & decoded) + { + nix::writeJsonTest(*this, testStem, decoded); + } }; template @@ -34,7 +53,7 @@ public: template 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::read( @@ -55,7 +74,7 @@ public: template 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::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 diff --git a/src/libstore-tests/common-protocol.cc b/src/libstore-tests/common-protocol.cc index 7c40e8cdb..fa676eb7f 100644 --- a/src/libstore-tests/common-protocol.cc +++ b/src/libstore-tests/common-protocol.cc @@ -3,6 +3,7 @@ #include #include +#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 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::read(store, CommonProto::ReadConn{.from = from}); @@ -38,7 +39,7 @@ public: template void writeProtoTest(PathView testStem, const T & decoded) { - CharacterizationTest::writeTest(testStem, [&]() -> std::string { + CharacterizationTest::writeTest(std::string{testStem + ".bin"}, [&]() -> std::string { StringSink to; CommonProto::Serialise::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( diff --git a/src/libstore-tests/data/common-protocol/content-address.json b/src/libstore-tests/data/common-protocol/content-address.json new file mode 100644 index 000000000..9a0d57154 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/content-address.json @@ -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" + } +] diff --git a/src/libstore-tests/data/common-protocol/drv-output.json b/src/libstore-tests/data/common-protocol/drv-output.json new file mode 100644 index 000000000..2668d70c9 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/drv-output.json @@ -0,0 +1,4 @@ +[ + "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux" +] diff --git a/src/libstore-tests/data/common-protocol/optional-content-address.json b/src/libstore-tests/data/common-protocol/optional-content-address.json new file mode 100644 index 000000000..6cdaa59a5 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/optional-content-address.json @@ -0,0 +1,11 @@ +[ + null, + { + "hash": { + "algorithm": "sha1", + "format": "base64", + "hash": "gGemBoenViNZM3hiwqns/Fgzqwo=" + }, + "method": "flat" + } +] diff --git a/src/libstore-tests/data/common-protocol/optional-store-path.json b/src/libstore-tests/data/common-protocol/optional-store-path.json new file mode 100644 index 000000000..58519a4d2 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/optional-store-path.json @@ -0,0 +1,4 @@ +[ + null, + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/common-protocol/realisation-with-deps.json b/src/libstore-tests/data/common-protocol/realisation-with-deps.json new file mode 100644 index 000000000..77148d14c --- /dev/null +++ b/src/libstore-tests/data/common-protocol/realisation-with-deps.json @@ -0,0 +1,13 @@ +[ + { + "dependentRealisations": { + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo" + }, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/common-protocol/realisation.json b/src/libstore-tests/data/common-protocol/realisation.json new file mode 100644 index 000000000..f9ff09dbb --- /dev/null +++ b/src/libstore-tests/data/common-protocol/realisation.json @@ -0,0 +1,17 @@ +[ + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [] + }, + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/common-protocol/set.json b/src/libstore-tests/data/common-protocol/set.json new file mode 100644 index 000000000..acd123082 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/set.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "bar", + "foo" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/data/common-protocol/store-path.json b/src/libstore-tests/data/common-protocol/store-path.json new file mode 100644 index 000000000..16459245b --- /dev/null +++ b/src/libstore-tests/data/common-protocol/store-path.json @@ -0,0 +1,4 @@ +[ + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/common-protocol/string.json b/src/libstore-tests/data/common-protocol/string.json new file mode 100644 index 000000000..d3db4f3b4 --- /dev/null +++ b/src/libstore-tests/data/common-protocol/string.json @@ -0,0 +1,7 @@ +[ + "", + "hi", + "white rabbit", + "大白兔", + "oh no " +] diff --git a/src/libstore-tests/data/common-protocol/vector.json b/src/libstore-tests/data/common-protocol/vector.json new file mode 100644 index 000000000..2b8cc1b3a --- /dev/null +++ b/src/libstore-tests/data/common-protocol/vector.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "foo", + "bar" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/data/serve-protocol/build-result-2.2.json b/src/libstore-tests/data/serve-protocol/build-result-2.2.json new file mode 100644 index 000000000..029bcb5a8 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/build-result-2.2.json @@ -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 + } +] diff --git a/src/libstore-tests/data/serve-protocol/build-result-2.3.json b/src/libstore-tests/data/serve-protocol/build-result-2.3.json new file mode 100644 index 000000000..be14b0947 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/build-result-2.3.json @@ -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 + } +] diff --git a/src/libstore-tests/data/serve-protocol/build-result-2.6.json b/src/libstore-tests/data/serve-protocol/build-result-2.6.json new file mode 100644 index 000000000..30a8e82e9 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/build-result-2.6.json @@ -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 + } +] diff --git a/src/libstore-tests/data/serve-protocol/content-address.json b/src/libstore-tests/data/serve-protocol/content-address.json new file mode 100644 index 000000000..9a0d57154 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/content-address.json @@ -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" + } +] diff --git a/src/libstore-tests/data/serve-protocol/drv-output.json b/src/libstore-tests/data/serve-protocol/drv-output.json new file mode 100644 index 000000000..2668d70c9 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/drv-output.json @@ -0,0 +1,4 @@ +[ + "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux" +] diff --git a/src/libstore-tests/data/serve-protocol/optional-content-address.json b/src/libstore-tests/data/serve-protocol/optional-content-address.json new file mode 100644 index 000000000..6cdaa59a5 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/optional-content-address.json @@ -0,0 +1,11 @@ +[ + null, + { + "hash": { + "algorithm": "sha1", + "format": "base64", + "hash": "gGemBoenViNZM3hiwqns/Fgzqwo=" + }, + "method": "flat" + } +] diff --git a/src/libstore-tests/data/serve-protocol/optional-store-path.json b/src/libstore-tests/data/serve-protocol/optional-store-path.json new file mode 100644 index 000000000..58519a4d2 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/optional-store-path.json @@ -0,0 +1,4 @@ +[ + null, + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/serve-protocol/realisation-with-deps.json b/src/libstore-tests/data/serve-protocol/realisation-with-deps.json new file mode 100644 index 000000000..77148d14c --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/realisation-with-deps.json @@ -0,0 +1,13 @@ +[ + { + "dependentRealisations": { + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo" + }, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/serve-protocol/realisation.json b/src/libstore-tests/data/serve-protocol/realisation.json new file mode 100644 index 000000000..f9ff09dbb --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/realisation.json @@ -0,0 +1,17 @@ +[ + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [] + }, + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/serve-protocol/set.json b/src/libstore-tests/data/serve-protocol/set.json new file mode 100644 index 000000000..acd123082 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/set.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "bar", + "foo" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/data/serve-protocol/store-path.json b/src/libstore-tests/data/serve-protocol/store-path.json new file mode 100644 index 000000000..16459245b --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/store-path.json @@ -0,0 +1,4 @@ +[ + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/serve-protocol/string.json b/src/libstore-tests/data/serve-protocol/string.json new file mode 100644 index 000000000..d3db4f3b4 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/string.json @@ -0,0 +1,7 @@ +[ + "", + "hi", + "white rabbit", + "大白兔", + "oh no " +] diff --git a/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.3.json b/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.3.json new file mode 100644 index 000000000..b8d914380 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.3.json @@ -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 + } +] diff --git a/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.4.json b/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.4.json new file mode 100644 index 000000000..725880590 --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/unkeyed-valid-path-info-2.4.json @@ -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 + } +] diff --git a/src/libstore-tests/data/serve-protocol/vector.json b/src/libstore-tests/data/serve-protocol/vector.json new file mode 100644 index 000000000..2b8cc1b3a --- /dev/null +++ b/src/libstore-tests/data/serve-protocol/vector.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "foo", + "bar" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/data/worker-protocol/build-mode.json b/src/libstore-tests/data/worker-protocol/build-mode.json new file mode 100644 index 000000000..2ef158f87 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/build-mode.json @@ -0,0 +1,5 @@ +[ + 0, + 1, + 2 +] diff --git a/src/libstore-tests/data/worker-protocol/build-result-1.27.json b/src/libstore-tests/data/worker-protocol/build-result-1.27.json new file mode 100644 index 000000000..029bcb5a8 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/build-result-1.27.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/build-result-1.28.json b/src/libstore-tests/data/worker-protocol/build-result-1.28.json new file mode 100644 index 000000000..d02845b7f --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/build-result-1.28.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/build-result-1.29.json b/src/libstore-tests/data/worker-protocol/build-result-1.29.json new file mode 100644 index 000000000..30a8e82e9 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/build-result-1.29.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/build-result-1.37.json b/src/libstore-tests/data/worker-protocol/build-result-1.37.json new file mode 100644 index 000000000..61cddd2ca --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/build-result-1.37.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/content-address.json b/src/libstore-tests/data/worker-protocol/content-address.json new file mode 100644 index 000000000..9a0d57154 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/content-address.json @@ -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" + } +] diff --git a/src/libstore-tests/data/worker-protocol/derived-path-1.29.json b/src/libstore-tests/data/worker-protocol/derived-path-1.29.json new file mode 100644 index 000000000..f0efe4a35 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/derived-path-1.29.json @@ -0,0 +1,16 @@ +[ + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + { + "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", + "outputs": [ + "*" + ] + }, + { + "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", + "outputs": [ + "x", + "y" + ] + } +] diff --git a/src/libstore-tests/data/worker-protocol/derived-path-1.30.json b/src/libstore-tests/data/worker-protocol/derived-path-1.30.json new file mode 100644 index 000000000..7a67e4761 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/derived-path-1.30.json @@ -0,0 +1,17 @@ +[ + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv", + { + "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", + "outputs": [ + "*" + ] + }, + { + "drvPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv", + "outputs": [ + "x", + "y" + ] + } +] diff --git a/src/libstore-tests/data/worker-protocol/drv-output.json b/src/libstore-tests/data/worker-protocol/drv-output.json new file mode 100644 index 000000000..2668d70c9 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/drv-output.json @@ -0,0 +1,4 @@ +[ + "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux" +] diff --git a/src/libstore-tests/data/worker-protocol/keyed-build-result-1.29.json b/src/libstore-tests/data/worker-protocol/keyed-build-result-1.29.json new file mode 100644 index 000000000..c15d47aa3 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/keyed-build-result-1.29.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/optional-content-address.json b/src/libstore-tests/data/worker-protocol/optional-content-address.json new file mode 100644 index 000000000..6cdaa59a5 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/optional-content-address.json @@ -0,0 +1,11 @@ +[ + null, + { + "hash": { + "algorithm": "sha1", + "format": "base64", + "hash": "gGemBoenViNZM3hiwqns/Fgzqwo=" + }, + "method": "flat" + } +] diff --git a/src/libstore-tests/data/worker-protocol/optional-store-path.json b/src/libstore-tests/data/worker-protocol/optional-store-path.json new file mode 100644 index 000000000..58519a4d2 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/optional-store-path.json @@ -0,0 +1,4 @@ +[ + null, + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/worker-protocol/optional-trusted-flag.json b/src/libstore-tests/data/worker-protocol/optional-trusted-flag.json new file mode 100644 index 000000000..2f3c092f8 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/optional-trusted-flag.json @@ -0,0 +1,5 @@ +[ + null, + true, + false +] diff --git a/src/libstore-tests/data/worker-protocol/realisation-with-deps.json b/src/libstore-tests/data/worker-protocol/realisation-with-deps.json new file mode 100644 index 000000000..77148d14c --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/realisation-with-deps.json @@ -0,0 +1,13 @@ +[ + { + "dependentRealisations": { + "sha256:6f869f9ea2823bda165e06076fd0de4366dead2c0e8d2dbbad277d4f15c373f5!quux": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo" + }, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/worker-protocol/realisation.json b/src/libstore-tests/data/worker-protocol/realisation.json new file mode 100644 index 000000000..f9ff09dbb --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/realisation.json @@ -0,0 +1,17 @@ +[ + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [] + }, + { + "dependentRealisations": {}, + "id": "sha256:15e3c560894cbb27085cf65b5a2ecb18488c999497f4531b6907a7581ce6d527!baz", + "outPath": "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "signatures": [ + "asdf", + "qwer" + ] + } +] diff --git a/src/libstore-tests/data/worker-protocol/set.json b/src/libstore-tests/data/worker-protocol/set.json new file mode 100644 index 000000000..acd123082 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/set.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "bar", + "foo" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/data/worker-protocol/store-path.json b/src/libstore-tests/data/worker-protocol/store-path.json new file mode 100644 index 000000000..16459245b --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/store-path.json @@ -0,0 +1,4 @@ +[ + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo", + "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo-bar" +] diff --git a/src/libstore-tests/data/worker-protocol/string.json b/src/libstore-tests/data/worker-protocol/string.json new file mode 100644 index 000000000..d3db4f3b4 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/string.json @@ -0,0 +1,7 @@ +[ + "", + "hi", + "white rabbit", + "大白兔", + "oh no " +] diff --git a/src/libstore-tests/data/worker-protocol/unkeyed-valid-path-info-1.15.json b/src/libstore-tests/data/worker-protocol/unkeyed-valid-path-info-1.15.json new file mode 100644 index 000000000..0d78d3875 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/unkeyed-valid-path-info-1.15.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/valid-path-info-1.15.json b/src/libstore-tests/data/worker-protocol/valid-path-info-1.15.json new file mode 100644 index 000000000..6d153ee1c --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/valid-path-info-1.15.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/valid-path-info-1.16.json b/src/libstore-tests/data/worker-protocol/valid-path-info-1.16.json new file mode 100644 index 000000000..9e2806824 --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/valid-path-info-1.16.json @@ -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 + } +] diff --git a/src/libstore-tests/data/worker-protocol/vector.json b/src/libstore-tests/data/worker-protocol/vector.json new file mode 100644 index 000000000..2b8cc1b3a --- /dev/null +++ b/src/libstore-tests/data/worker-protocol/vector.json @@ -0,0 +1,22 @@ +[ + [], + [ + "" + ], + [ + "", + "foo", + "bar" + ], + [ + [], + [ + "" + ], + [ + "", + "1", + "2" + ] + ] +] diff --git a/src/libstore-tests/serve-protocol.cc b/src/libstore-tests/serve-protocol.cc index a7b69821c..e04d89e3d 100644 --- a/src/libstore-tests/serve-protocol.cc +++ b/src/libstore-tests/serve-protocol.cc @@ -4,6 +4,7 @@ #include #include +#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; diff --git a/src/libstore-tests/worker-protocol.cc b/src/libstore-tests/worker-protocol.cc index 8f70e937b..1e0ede81c 100644 --- a/src/libstore-tests/worker-protocol.cc +++ b/src/libstore-tests/worker-protocol.cc @@ -4,6 +4,7 @@ #include #include +#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; diff --git a/src/libstore/build-result.cc b/src/libstore/build-result.cc index e3d9e9085..f4bc8ab33 100644 --- a/src/libstore/build-result.cc +++ b/src/libstore/build-result.cc @@ -153,4 +153,20 @@ BuildResult adl_serializer::from_json(const json & _json) return br; } +KeyedBuildResult adl_serializer::from_json(const json & json0) +{ + auto json = getObject(json0); + + return KeyedBuildResult{ + adl_serializer::from_json(json0), + valueAt(json, "path"), + }; +} + +void adl_serializer::to_json(json & json, const KeyedBuildResult & kbr) +{ + adl_serializer::to_json(json, kbr); + json["path"] = kbr.path; +} + } // namespace nlohmann diff --git a/src/libstore/include/nix/store/build-result.hh b/src/libstore/include/nix/store/build-result.hh index 4739232f8..96134791b 100644 --- a/src/libstore/include/nix/store/build-result.hh +++ b/src/libstore/include/nix/store/build-result.hh @@ -178,3 +178,4 @@ struct KeyedBuildResult : BuildResult } // namespace nix JSON_IMPL(nix::BuildResult) +JSON_IMPL(nix::KeyedBuildResult) diff --git a/src/libstore/include/nix/store/path-info.hh b/src/libstore/include/nix/store/path-info.hh index 8f6115b73..a64e8458d 100644 --- a/src/libstore/include/nix/store/path-info.hh +++ b/src/libstore/include/nix/store/path-info.hh @@ -197,3 +197,4 @@ using ValidPathInfos = std::map; } // namespace nix JSON_IMPL(nix::UnkeyedValidPathInfo) +JSON_IMPL(nix::ValidPathInfo) diff --git a/src/libstore/include/nix/store/realisation.hh b/src/libstore/include/nix/store/realisation.hh index e8a71862e..af0e4aefd 100644 --- a/src/libstore/include/nix/store/realisation.hh +++ b/src/libstore/include/nix/store/realisation.hh @@ -182,5 +182,6 @@ public: } // namespace nix +JSON_IMPL(nix::DrvOutput) JSON_IMPL(nix::UnkeyedRealisation) JSON_IMPL(nix::Realisation) diff --git a/src/libstore/include/nix/store/store-api.hh b/src/libstore/include/nix/store/store-api.hh index c57eff1f0..4c0b156fa 100644 --- a/src/libstore/include/nix/store/store-api.hh +++ b/src/libstore/include/nix/store/store-api.hh @@ -1004,4 +1004,10 @@ const ContentAddress * getDerivationCA(const BasicDerivation & drv); std::map drvOutputReferences(Store & store, const Derivation & drv, const StorePath & outputPath, Store * evalStore = nullptr); +template<> +struct json_avoids_null : std::true_type +{}; + } // namespace nix + +JSON_IMPL(nix::TrustedFlag) diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 8b2a7287e..ea0c8a3c2 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -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 @@ -479,3 +480,19 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd) } } // namespace nix + +namespace nlohmann { + +using namespace nix; + +TrustedFlag adl_serializer::from_json(const json & json) +{ + return getBoolean(json) ? TrustedFlag::Trusted : TrustedFlag::NotTrusted; +} + +void adl_serializer::to_json(json & json, const TrustedFlag & trustedFlag) +{ + json = static_cast(trustedFlag); +} + +} // namespace nlohmann diff --git a/src/libstore/path-info.cc b/src/libstore/path-info.cc index d56ba9475..6b7469e33 100644 --- a/src/libstore/path-info.cc +++ b/src/libstore/path-info.cc @@ -251,4 +251,20 @@ void adl_serializer::to_json(json & json, const UnkeyedVal json = c.toJSON(nullptr, true); } +ValidPathInfo adl_serializer::from_json(const json & json0) +{ + auto json = getObject(json0); + + return ValidPathInfo{ + valueAt(json, "path"), + adl_serializer::from_json(json0), + }; +} + +void adl_serializer::to_json(json & json, const ValidPathInfo & v) +{ + adl_serializer::to_json(json, v); + json["path"] = v.path; +} + } // namespace nlohmann diff --git a/src/libstore/realisation.cc b/src/libstore/realisation.cc index a7f3b98d6..4aeb05874 100644 --- a/src/libstore/realisation.cc +++ b/src/libstore/realisation.cc @@ -144,6 +144,16 @@ namespace nlohmann { using namespace nix; +DrvOutput adl_serializer::from_json(const json & json) +{ + return DrvOutput::parse(getString(json)); +} + +void adl_serializer::to_json(json & json, const DrvOutput & drvOutput) +{ + json = drvOutput.to_string(); +} + UnkeyedRealisation adl_serializer::from_json(const json & json0) { auto json = getObject(json0); @@ -182,14 +192,14 @@ Realisation adl_serializer::from_json(const json & json0) return Realisation{ static_cast(json0), - DrvOutput::parse(valueAt(json, "id")), + valueAt(json, "id"), }; } void adl_serializer::to_json(json & json, const Realisation & r) { json = static_cast(r); - json["id"] = r.id.to_string(); + json["id"] = r.id; } } // namespace nlohmann diff --git a/src/libutil-test-support/include/nix/util/tests/json-characterization.hh b/src/libutil-test-support/include/nix/util/tests/json-characterization.hh index d713c615b..0ee6fd2fd 100644 --- a/src/libutil-test-support/include/nix/util/tests/json-characterization.hh +++ b/src/libutil-test-support/include/nix/util/tests/json-characterization.hh @@ -11,6 +11,34 @@ namespace nix { +/** + * Golden test for JSON reading + */ +template +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::from_json(encoded, args...); + ASSERT_EQ(decoded, expected); + }); +} + +/** + * Golden test for JSON writing + */ +template +void writeJsonTest(CharacterizationTest & test, PathView testStem, const T & value) +{ + using namespace nlohmann; + test.writeTest( + Path{testStem} + ".json", + [&]() -> json { return static_cast(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::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(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); } };