1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-14 22:42:41 +01:00

Make the JSON format for derivation use basename store paths

See #13570 for details --- the idea is that included the store dir in
store paths makes systematic JSON parting with e.g. Serde, Aeson,
nlohmann, or similiar harder.

After talking to Eelco, we are changing the `Derivation` format right
away because not only is `nix derivation` technically experimental, we think it is
also less widely used in practice than, say, `nix path-info`.

Progress on #13570
This commit is contained in:
John Ericson 2025-09-13 08:25:42 -04:00
parent 187520ce88
commit 9d7229a2a4
31 changed files with 275 additions and 140 deletions

View file

@ -21,5 +21,6 @@
"method": "nar"
}
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -32,5 +32,6 @@
],
"system": "my-system"
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -10,14 +10,14 @@
"out": "/1rz4g4znpzjwh1xymhjpm42vipw92pr73vdgl6xs1hycac8kf2n9"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
@ -26,7 +26,7 @@
}
},
"inputSrcs": [
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
],
"name": "advanced-attributes-structured-attrs",
"outputs": {
@ -100,5 +100,6 @@
],
"system": "my-system"
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -26,14 +26,14 @@
"system": "my-system"
},
"inputDrvs": {
"/nix/store/j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"j56sf12rxpcv5swr14vsjn5cwm6bj03h-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
@ -42,7 +42,7 @@
}
},
"inputSrcs": [
"/nix/store/qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
"qnml92yh97a6fbrs2m5qg5cqlc8vni58-bar.drv"
],
"name": "advanced-attributes",
"outputs": {
@ -51,5 +51,6 @@
"method": "nar"
}
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -19,5 +19,6 @@
"method": "nar"
}
},
"system": "x86_64-linux"
"system": "x86_64-linux",
"version": 3
}

View file

@ -8,7 +8,7 @@
"BIG_BAD": "WOLF"
},
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {
"cat": {
"dynamicOutputs": {},
@ -30,9 +30,10 @@
}
},
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"name": "dyn-dep-derivation",
"outputs": {},
"system": "wasm-sel4"
"system": "wasm-sel4",
"version": 3
}

View file

@ -15,8 +15,9 @@
"name": "advanced-attributes-defaults",
"outputs": {
"out": {
"path": "/nix/store/1qsc7svv43m4dw2prh6mvyf7cai5czji-advanced-attributes-defaults"
"path": "1qsc7svv43m4dw2prh6mvyf7cai5czji-advanced-attributes-defaults"
}
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -13,10 +13,10 @@
"name": "advanced-attributes-structured-attrs-defaults",
"outputs": {
"dev": {
"path": "/nix/store/8bazivnbipbyi569623skw5zm91z6kc2-advanced-attributes-structured-attrs-defaults-dev"
"path": "8bazivnbipbyi569623skw5zm91z6kc2-advanced-attributes-structured-attrs-defaults-dev"
},
"out": {
"path": "/nix/store/f8f8nvnx32bxvyxyx2ff7akbvwhwd9dw-advanced-attributes-structured-attrs-defaults"
"path": "f8f8nvnx32bxvyxyx2ff7akbvwhwd9dw-advanced-attributes-structured-attrs-defaults"
}
},
"structuredAttrs": {
@ -28,5 +28,6 @@
],
"system": "my-system"
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -10,14 +10,14 @@
"out": "/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
@ -26,18 +26,18 @@
}
},
"inputSrcs": [
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
],
"name": "advanced-attributes-structured-attrs",
"outputs": {
"bin": {
"path": "/nix/store/33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin"
"path": "33qms3h55wlaspzba3brlzlrm8m2239g-advanced-attributes-structured-attrs-bin"
},
"dev": {
"path": "/nix/store/wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev"
"path": "wyfgwsdi8rs851wmy1xfzdxy7y5vrg5l-advanced-attributes-structured-attrs-dev"
},
"out": {
"path": "/nix/store/7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs"
"path": "7cxy4zx1vqc885r4jl2l64pymqbdmhii-advanced-attributes-structured-attrs"
}
},
"structuredAttrs": {
@ -95,5 +95,6 @@
],
"system": "my-system"
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -24,14 +24,14 @@
"system": "my-system"
},
"inputDrvs": {
"/nix/store/afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"afc3vbjbzql750v2lp8gxgaxsajphzih-foo.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
"out"
]
},
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv": {
"dynamicOutputs": {},
"outputs": [
"dev",
@ -40,13 +40,14 @@
}
},
"inputSrcs": [
"/nix/store/vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
"vj2i49jm2868j2fmqvxm70vlzmzvgv14-bar.drv"
],
"name": "advanced-attributes",
"outputs": {
"out": {
"path": "/nix/store/wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes"
"path": "wyhpwd748pns4k7svh48wdrc8kvjk0ra-advanced-attributes"
}
},
"system": "my-system"
"system": "my-system",
"version": 3
}

View file

@ -1,6 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "sha256",
"method": "flat",
"path": "/nix/store/rhcg9h16sqvlbpsa6dqm57sbr2al6nzg-drv-name-output-name"
"method": "flat"
}

View file

@ -1,6 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "sha256",
"method": "nar",
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
"method": "nar"
}

View file

@ -1,6 +1,5 @@
{
"hash": "894517c9163c896ec31a2adbd33c0681fd5f45b2c0ef08a64c92a03fb97f390f",
"hashAlgo": "sha256",
"method": "text",
"path": "/nix/store/6s1zwabh956jvhv4w9xcdb5jiyanyxg1-drv-name-output-name"
"method": "text"
}

View file

@ -1,3 +1,3 @@
{
"path": "/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
"path": "c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-drv-name-output-name"
}

View file

@ -8,7 +8,7 @@
"BIG_BAD": "WOLF"
},
"inputDrvs": {
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep2.drv": {
"dynamicOutputs": {},
"outputs": [
"cat",
@ -17,9 +17,10 @@
}
},
"inputSrcs": [
"/nix/store/c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
"c015dhfh5l0lp6wxyvdn7bmwhbbr6hr9-dep1"
],
"name": "simple-derivation",
"outputs": {},
"system": "wasm-sel4"
"system": "wasm-sel4",
"version": 3
}

View file

@ -0,0 +1 @@
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"

View file

@ -51,45 +51,44 @@ using BothFixtures = ::testing::Types<DerivationAdvancedAttrsTest, CaDerivationA
TYPED_TEST_SUITE(DerivationAdvancedAttrsBothTest, BothFixtures);
#define TEST_ATERM_JSON(STEM, NAME) \
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_json) \
{ \
this->readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings); \
Derivation got = Derivation::fromJSON(*this->store, encoded, this->mockXpSettings); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_to_json) \
{ \
this->writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
return parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings) \
.toJSON(*this->store); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_aterm) \
{ \
this->readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(this->goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(*this->store, json, this->mockXpSettings); \
auto got = parseDerivation(*this->store, std::move(encoded), NAME, this->mockXpSettings); \
EXPECT_EQ(got.toJSON(*this->store), expected.toJSON(*this->store)); \
EXPECT_EQ(got, expected); \
}); \
} \
\
#define TEST_ATERM_JSON(STEM, NAME) \
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_json) \
{ \
this->readTest(NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
auto expected = parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings); \
Derivation got = Derivation::fromJSON(encoded, this->mockXpSettings); \
EXPECT_EQ(got, expected); \
}); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_to_json) \
{ \
this->writeTest( \
NAME ".json", \
[&]() -> json { \
/* Use DRV file instead of C++ literal as source of truth. */ \
auto aterm = readFile(this->goldenMaster(NAME ".drv")); \
return parseDerivation(*this->store, std::move(aterm), NAME, this->mockXpSettings).toJSON(); \
}, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
} \
\
TYPED_TEST(DerivationAdvancedAttrsBothTest, Derivation_##STEM##_from_aterm) \
{ \
this->readTest(NAME ".drv", [&](auto encoded) { \
/* Use JSON file instead of C++ literal as source of truth. */ \
auto json = json::parse(readFile(this->goldenMaster(NAME ".json"))); \
auto expected = Derivation::fromJSON(json, this->mockXpSettings); \
auto got = parseDerivation(*this->store, std::move(encoded), NAME, this->mockXpSettings); \
EXPECT_EQ(got.toJSON(), expected.toJSON()); \
EXPECT_EQ(got, expected); \
}); \
} \
\
/* No corresponding write test, because we need to read the drv to write the json file */
TEST_ATERM_JSON(advancedAttributes, "advanced-attributes-defaults");

View file

@ -66,24 +66,24 @@ TEST_F(DynDerivationTest, BadATerm_oldVersionDynDeps)
FormatError);
}
#define TEST_JSON(FIXTURE, NAME, VAL, DRV_NAME, OUTPUT_NAME) \
TEST_F(FIXTURE, DerivationOutput_##NAME##_from_json) \
{ \
readTest("output-" #NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
DerivationOutput got = DerivationOutput::fromJSON(*store, DRV_NAME, OUTPUT_NAME, encoded, mockXpSettings); \
DerivationOutput expected{VAL}; \
ASSERT_EQ(got, expected); \
}); \
} \
\
TEST_F(FIXTURE, DerivationOutput_##NAME##_to_json) \
{ \
writeTest( \
"output-" #NAME ".json", \
[&]() -> json { return DerivationOutput{(VAL)}.toJSON(*store, (DRV_NAME), (OUTPUT_NAME)); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
#define TEST_JSON(FIXTURE, NAME, VAL, DRV_NAME, OUTPUT_NAME) \
TEST_F(FIXTURE, DerivationOutput_##NAME##_from_json) \
{ \
readTest("output-" #NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
DerivationOutput got = DerivationOutput::fromJSON(DRV_NAME, OUTPUT_NAME, encoded, mockXpSettings); \
DerivationOutput expected{VAL}; \
ASSERT_EQ(got, expected); \
}); \
} \
\
TEST_F(FIXTURE, DerivationOutput_##NAME##_to_json) \
{ \
writeTest( \
"output-" #NAME ".json", \
[&]() -> json { return DerivationOutput{(VAL)}.toJSON((DRV_NAME), (OUTPUT_NAME)); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
}
TEST_JSON(
@ -164,7 +164,7 @@ TEST_JSON(
readTest(#NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
Derivation expected{VAL}; \
Derivation got = Derivation::fromJSON(*store, encoded, mockXpSettings); \
Derivation got = Derivation::fromJSON(encoded, mockXpSettings); \
ASSERT_EQ(got, expected); \
}); \
} \
@ -173,7 +173,7 @@ TEST_JSON(
{ \
writeTest( \
#NAME ".json", \
[&]() -> json { return Derivation{VAL}.toJSON(*store); }, \
[&]() -> json { return Derivation{VAL}.toJSON(); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
}
@ -184,7 +184,7 @@ TEST_JSON(
readTest(#NAME ".drv", [&](auto encoded) { \
Derivation expected{VAL}; \
auto got = parseDerivation(*store, std::move(encoded), DRV_NAME, mockXpSettings); \
ASSERT_EQ(got.toJSON(*store), expected.toJSON(*store)); \
ASSERT_EQ(got.toJSON(), expected.toJSON()); \
ASSERT_EQ(got, expected); \
}); \
} \

View file

@ -7,7 +7,7 @@
#include "nix/store/path-regex.hh"
#include "nix/store/store-api.hh"
#include "nix/util/tests/hash.hh"
#include "nix/util/tests/characterization.hh"
#include "nix/store/tests/libstore.hh"
#include "nix/store/tests/path.hh"
@ -16,8 +16,17 @@ namespace nix {
#define STORE_DIR "/nix/store/"
#define HASH_PART "g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q"
class StorePathTest : public LibStoreTest
{};
class StorePathTest : public CharacterizationTest, public LibStoreTest
{
std::filesystem::path unitTestData = getUnitTestData() / "store-path";
public:
std::filesystem::path goldenMaster(std::string_view testStem) const override
{
return unitTestData / testStem;
}
};
static std::regex nameRegex{std::string{nameRegexStr}};
@ -134,4 +143,33 @@ RC_GTEST_FIXTURE_PROP(StorePathTest, prop_check_regex_eq_parse, ())
#endif
/* ----------------------------------------------------------------------------
* JSON
* --------------------------------------------------------------------------*/
using nlohmann::json;
#define TEST_JSON(FIXTURE, NAME, VAL) \
static const StorePath NAME = VAL; \
\
TEST_F(FIXTURE, NAME##_from_json) \
{ \
readTest(#NAME ".json", [&](const auto & encoded_) { \
auto encoded = json::parse(encoded_); \
StorePath got = static_cast<StorePath>(encoded); \
ASSERT_EQ(got, NAME); \
}); \
} \
\
TEST_F(FIXTURE, NAME##_to_json) \
{ \
writeTest( \
#NAME ".json", \
[&]() -> json { return static_cast<json>(NAME); }, \
[](const auto & file) { return json::parse(readFile(file)); }, \
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
}
TEST_JSON(StorePathTest, simple, StorePath{"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-foo.drv"});
} // namespace nix