1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-12-11 19:41:04 +01:00

Make storeDir a part of UnkeyedValidPathInfo

The previous commit hacked it into the output of `nix path-info --json`,
this cleans that up my making it an actual field of that data type, and
part of the canonical JSON serializers for it (and `ValidPathInfo` and
`NarInfo`).

Beyond cleaning up the JSON code, this also opens the doors to things
like:

- Binary caches that contain store objects that don't all belong in the
  same store directory

- Relocatable store objects which carefully don't mention any store
  directory by absolute path, and instead use relative paths for
  anything. (#9549)
This commit is contained in:
John Ericson 2025-12-03 20:20:21 -05:00
parent 1ad13a1423
commit f9089deb20
36 changed files with 111 additions and 29 deletions

View file

@ -46,6 +46,7 @@ $defs:
- narSize
- references
- ca
- storeDir
properties:
version:
type: integer
@ -101,6 +102,12 @@ $defs:
If the store object is [content-addressed](@docroot@/store/store-object/content-address.md),
this is the content address of this store object's file system object, used to compute its store path.
Otherwise (i.e. if it is [input-addressed](@docroot@/glossary.md#gloss-input-addressed-store-object)), this is `null`.
storeDir:
type: string
title: Store Directory
description: |
The [store directory](@docroot@/store/store-path.md#store-directory) this store object belongs to (e.g. `/nix/store`).
additionalProperties: false
impure:
@ -115,6 +122,7 @@ $defs:
- narSize
- references
- ca
- storeDir
# impure
- deriver
- registrationTime
@ -127,6 +135,7 @@ $defs:
narSize: { $ref: "#/$defs/base/properties/narSize" }
references: { $ref: "#/$defs/base/properties/references" }
ca: { $ref: "#/$defs/base/properties/ca" }
storeDir: { $ref: "#/$defs/base/properties/storeDir" }
deriver:
oneOf:
- "$ref": "./store-path-v1.yaml"
@ -192,6 +201,7 @@ $defs:
- narSize
- references
- ca
- storeDir
# impure
- deriver
- registrationTime
@ -209,6 +219,7 @@ $defs:
narSize: { $ref: "#/$defs/base/properties/narSize" }
references: { $ref: "#/$defs/base/properties/references" }
ca: { $ref: "#/$defs/base/properties/ca" }
storeDir: { $ref: "#/$defs/base/properties/storeDir" }
deriver: { $ref: "#/$defs/impure/properties/deriver" }
registrationTime: { $ref: "#/$defs/impure/properties/registrationTime" }
ultimate: { $ref: "#/$defs/impure/properties/ultimate" }

View file

@ -29,6 +29,7 @@
"references": [],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -15,6 +15,7 @@
"asdf",
"qwer"
],
"storeDir": "/nix/store",
"ultimate": true,
"url": "nar/1w1fff338fvdw53sqgamddn1b2xgds473pv6y13gizdbqjv4i5p3.nar.xz",
"version": 1

View file

@ -6,5 +6,6 @@
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"/nix/store/n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"storeDir": "/nix/store",
"version": 1
}

View file

@ -30,6 +30,7 @@
"asdf",
"qwer"
],
"storeDir": "/nix/store",
"ultimate": true,
"url": "nar/1w1fff338fvdw53sqgamddn1b2xgds473pv6y13gizdbqjv4i5p3.nar.xz",
"version": 2

View file

@ -17,5 +17,6 @@
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"storeDir": "/nix/store",
"version": 2
}

View file

@ -6,6 +6,7 @@
"references": [],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 1
}

View file

@ -3,5 +3,6 @@
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
"narSize": 0,
"references": [],
"storeDir": "/nix/store",
"version": 1
}

View file

@ -12,6 +12,7 @@
"asdf",
"qwer"
],
"storeDir": "/nix/store",
"ultimate": true,
"version": 1
}

View file

@ -6,5 +6,6 @@
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"/nix/store/n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"storeDir": "/nix/store",
"version": 1
}

View file

@ -10,6 +10,7 @@
"references": [],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -7,5 +7,6 @@
},
"narSize": 0,
"references": [],
"storeDir": "/nix/store",
"version": 2
}

View file

@ -23,6 +23,7 @@
"asdf",
"qwer"
],
"storeDir": "/nix/store",
"ultimate": true,
"version": 2
}

View file

@ -17,5 +17,6 @@
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
"n5wkd9frr45pa74if5gpz9j7mifg27fh-foo"
],
"storeDir": "/nix/store",
"version": 2
}

View file

@ -11,6 +11,7 @@
"references": [],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
},
@ -28,6 +29,7 @@
],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -13,6 +13,7 @@
],
"registrationTime": null,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
},
@ -41,6 +42,7 @@
"fake-sig-1",
"fake-sig-2"
],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -11,6 +11,7 @@
"references": [],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
},
@ -28,6 +29,7 @@
],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -12,6 +12,7 @@
"references": [],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
},
@ -31,6 +32,7 @@
],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -12,6 +12,7 @@
"references": [],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": true,
"version": 2
},
@ -34,6 +35,7 @@
"fake-sig-1",
"fake-sig-2"
],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
},
@ -60,6 +62,7 @@
],
"registrationTime": 23423,
"signatures": [],
"storeDir": "/nix/store",
"ultimate": false,
"version": 2
}

View file

@ -33,6 +33,7 @@ class PathInfoTestV2 : public CharacterizationTest, public LibStoreTest
static UnkeyedValidPathInfo makeEmpty()
{
return {
"/nix/store",
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
};
}

View file

@ -17,6 +17,8 @@ namespace nix {
const char serveProtoDir[] = "serve-protocol";
static constexpr std::string_view defaultStoreDir = "/nix/store";
struct ServeProtoTest : VersionedProtoTest<ServeProto, serveProtoDir>
{
/**
@ -263,12 +265,12 @@ VERSIONED_CHARACTERIZATION_TEST(
2 << 8 | 3,
(std::tuple<UnkeyedValidPathInfo, UnkeyedValidPathInfo>{
({
UnkeyedValidPathInfo info{Hash::dummy};
UnkeyedValidPathInfo info{std::string{defaultStoreDir}, Hash::dummy};
info.narSize = 34878;
info;
}),
({
UnkeyedValidPathInfo info{Hash::dummy};
UnkeyedValidPathInfo info{std::string{defaultStoreDir}, Hash::dummy};
info.deriver = StorePath{
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
};
@ -290,6 +292,7 @@ VERSIONED_CHARACTERIZATION_TEST(
(std::tuple<UnkeyedValidPathInfo, UnkeyedValidPathInfo>{
({
UnkeyedValidPathInfo info{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
};
info.deriver = StorePath{

View file

@ -17,6 +17,8 @@ namespace nix {
const char workerProtoDir[] = "worker-protocol";
static constexpr std::string_view defaultStoreDir = "/nix/store";
struct WorkerProtoTest : VersionedProtoTest<WorkerProto, workerProtoDir>
{
/**
@ -426,6 +428,7 @@ VERSIONED_CHARACTERIZATION_TEST(
(std::tuple<UnkeyedValidPathInfo, UnkeyedValidPathInfo>{
({
UnkeyedValidPathInfo info{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
};
info.registrationTime = 23423;
@ -434,6 +437,7 @@ VERSIONED_CHARACTERIZATION_TEST(
}),
({
UnkeyedValidPathInfo info{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
};
info.deriver = StorePath{
@ -462,6 +466,7 @@ VERSIONED_CHARACTERIZATION_TEST(
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
},
UnkeyedValidPathInfo{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
},
};
@ -475,6 +480,7 @@ VERSIONED_CHARACTERIZATION_TEST(
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
},
UnkeyedValidPathInfo{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
},
};
@ -509,6 +515,7 @@ VERSIONED_CHARACTERIZATION_TEST(
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
},
UnkeyedValidPathInfo{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
},
};
@ -523,6 +530,7 @@ VERSIONED_CHARACTERIZATION_TEST(
"g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
},
UnkeyedValidPathInfo{
std::string{defaultStoreDir},
Hash::parseSRI("sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="),
},
};

View file

@ -905,7 +905,7 @@ static void performOp(
auto path = WorkerProto::Serialise<StorePath>::read(*store, rconn);
auto deriver = WorkerProto::Serialise<std::optional<StorePath>>::read(*store, rconn);
auto narHash = Hash::parseAny(readString(conn.from), HashAlgorithm::SHA256);
ValidPathInfo info{path, narHash};
ValidPathInfo info{path, {*store, narHash}};
info.deriver = std::move(deriver);
info.references = WorkerProto::Serialise<StorePathSet>::read(*store, rconn);
conn.from >> info.registrationTime >> info.narSize >> info.ultimate;

View file

@ -154,7 +154,7 @@ struct DummyStoreImpl : DummyStore
/* compute path info on demand */
auto narHash =
hashPath({accessor, CanonPath::root}, FileSerialisationMethod::NixArchive, HashAlgorithm::SHA256);
auto info = std::make_shared<ValidPathInfo>(path, UnkeyedValidPathInfo{narHash.hash});
auto info = std::make_shared<ValidPathInfo>(path, UnkeyedValidPathInfo{*this, narHash.hash});
info->narSize = narHash.numBytesDigested;
info->ca = ContentAddress{
.method = ContentAddressMethod::Raw::Text,

View file

@ -75,7 +75,7 @@ StorePaths importPaths(Store & store, Source & source, CheckSigsFlag checkSigs)
auto deriver = readString(source);
auto narHash = hashString(HashAlgorithm::SHA256, saved.s);
ValidPathInfo info{path, narHash};
ValidPathInfo info{path, {store, narHash}};
if (deriver != "")
info.deriver = store.parseStorePath(deriver);
info.references = references;

View file

@ -49,8 +49,13 @@ struct NarInfo : ValidPathInfo, UnkeyedNarInfo
{
}
NarInfo(StorePath path, Hash narHash)
: NarInfo{ValidPathInfo{std::move(path), UnkeyedValidPathInfo(narHash)}}
NarInfo(const StoreDirConfig & store, StorePath path, Hash narHash)
: NarInfo{ValidPathInfo{std::move(path), UnkeyedValidPathInfo{store, narHash}}}
{
}
NarInfo(std::string storeDir, StorePath path, Hash narHash)
: NarInfo{ValidPathInfo{std::move(path), UnkeyedValidPathInfo{std::move(storeDir), narHash}}}
{
}

View file

@ -54,6 +54,14 @@ using SubstitutablePathInfos = std::map<StorePath, SubstitutablePathInfo>;
*/
struct UnkeyedValidPathInfo
{
/**
* The store directory this store object belongs to.
*
* This supports relocatable store objects where different objects
* may have different store directories.
*/
std::string storeDir;
/**
* Path to derivation that produced this store object, if known.
*/
@ -110,15 +118,20 @@ struct UnkeyedValidPathInfo
* path then implies the contents.)
*
* Ideally, the content-addressability assertion would just be a Boolean,
* and the store path would be computed from the name component, narHash
* and references. However, we support many types of content addresses.
* and the store path would be computed from the name component, 'narHash'
* and 'references'. However, we support many types of content addresses.
*/
std::optional<ContentAddress> ca;
UnkeyedValidPathInfo(const UnkeyedValidPathInfo & other) = default;
UnkeyedValidPathInfo(Hash narHash)
: narHash(narHash) {};
UnkeyedValidPathInfo(const StoreDirConfig & store, Hash narHash);
UnkeyedValidPathInfo(std::string storeDir, Hash narHash)
: storeDir(std::move(storeDir))
, narHash(std::move(narHash))
{
}
bool operator==(const UnkeyedValidPathInfo &) const noexcept;

View file

@ -758,7 +758,7 @@ std::shared_ptr<const ValidPathInfo> LocalStore::queryPathInfoInternal(State & s
throw Error("invalid-path entry for '%s': %s", printStorePath(path), e.what());
}
auto info = std::make_shared<ValidPathInfo>(path, narHash);
auto info = std::make_shared<ValidPathInfo>(path, UnkeyedValidPathInfo(*this, narHash));
info->id = id;

View file

@ -264,8 +264,8 @@ public:
return {oInvalid, 0};
auto namePart = queryNAR.getStr(1);
auto narInfo =
make_ref<NarInfo>(StorePath(hashPart + "-" + namePart), Hash::parseAnyPrefixed(queryNAR.getStr(6)));
auto narInfo = make_ref<NarInfo>(
cache.storeDir, StorePath(hashPart + "-" + namePart), Hash::parseAnyPrefixed(queryNAR.getStr(6)));
narInfo->url = queryNAR.getStr(2);
narInfo->compression = queryNAR.getStr(3);
if (!queryNAR.isNull(4))

View file

@ -7,7 +7,7 @@
namespace nix {
NarInfo::NarInfo(const StoreDirConfig & store, const std::string & s, const std::string & whence)
: UnkeyedValidPathInfo(Hash::dummy) // FIXME: hack
: UnkeyedValidPathInfo(store, Hash::dummy) // FIXME: hack
, ValidPathInfo(StorePath::dummy, static_cast<const UnkeyedValidPathInfo &>(*this)) // FIXME: hack
, UnkeyedNarInfo(static_cast<const UnkeyedValidPathInfo &>(*this))
{

View file

@ -20,10 +20,16 @@ PathInfoJsonFormat parsePathInfoJsonFormat(uint64_t version)
}
}
UnkeyedValidPathInfo::UnkeyedValidPathInfo(const StoreDirConfig & store, Hash narHash)
: UnkeyedValidPathInfo{store.storeDir, narHash}
{
}
GENERATE_CMP_EXT(
,
std::weak_ordering,
UnkeyedValidPathInfo,
me->storeDir,
me->deriver,
me->narHash,
me->references,
@ -141,7 +147,7 @@ ValidPathInfo ValidPathInfo::makeFromCA(
{
ValidPathInfo res{
store.makeFixedOutputPathFromCA(name, ca),
narHash,
UnkeyedValidPathInfo(store, narHash),
};
res.ca = ContentAddress{
.method = ca.getMethod(),
@ -173,6 +179,8 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInf
jsonObject["version"] = format;
jsonObject["storeDir"] = storeDir;
jsonObject["narHash"] = format == PathInfoJsonFormat::V1
? static_cast<json>(narHash.to_string(HashFormat::SRI, true))
: static_cast<json>(narHash);
@ -213,10 +221,6 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInf
UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig * store, const nlohmann::json & _json)
{
UnkeyedValidPathInfo res{
Hash(Hash::dummy),
};
auto & json = getObject(_json);
PathInfoJsonFormat format = PathInfoJsonFormat::V1;
@ -226,10 +230,20 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig * store
if (format == PathInfoJsonFormat::V1)
assert(store);
if (format == PathInfoJsonFormat::V1)
res.narHash = Hash::parseSRI(getString(valueAt(json, "narHash")));
else
res.narHash = valueAt(json, "narHash");
UnkeyedValidPathInfo res{
[&] {
if (auto * rawStoreDir = optionalValueAt(json, "storeDir"))
return getString(*rawStoreDir);
else if (format == PathInfoJsonFormat::V1)
return store->storeDir;
else
throw Error("'storeDir' field is required in path info JSON format version 2");
}(),
[&] {
return format == PathInfoJsonFormat::V1 ? Hash::parseSRI(getString(valueAt(json, "narHash")))
: Hash(valueAt(json, "narHash"));
}(),
};
res.narSize = getUnsigned(valueAt(json, "narSize"));

View file

@ -78,7 +78,7 @@ UnkeyedValidPathInfo ServeProto::Serialise<UnkeyedValidPathInfo>::read(const Sto
{
/* Hash should be set below unless very old `nix-store --serve`.
Caller should assert that it did set it. */
UnkeyedValidPathInfo info{Hash::dummy};
UnkeyedValidPathInfo info{store, Hash::dummy};
auto deriver = readString(conn.from);
if (deriver != "")

View file

@ -1095,7 +1095,7 @@ decodeValidPathInfo(const Store & store, std::istream & str, std::optional<HashR
throw Error("number expected");
hashGiven = {narHash, *narSize};
}
ValidPathInfo info(store.parseStorePath(path), hashGiven->hash);
ValidPathInfo info(store.parseStorePath(path), {store, hashGiven->hash});
info.narSize = hashGiven->numBytesDigested;
std::string deriver;
getline(str, deriver);

View file

@ -1686,7 +1686,7 @@ SingleDrvOutputs DerivationBuilderImpl::registerOutputs()
{getFSSourceAccessor(), CanonPath(actualPath)},
FileSerialisationMethod::NixArchive,
HashAlgorithm::SHA256);
ValidPathInfo newInfo0{requiredFinalPath, narHashAndSize.hash};
ValidPathInfo newInfo0{requiredFinalPath, {store, narHashAndSize.hash}};
newInfo0.narSize = narHashAndSize.numBytesDigested;
auto refs = rewriteRefs();
newInfo0.references = std::move(refs.others);

View file

@ -253,7 +253,7 @@ UnkeyedValidPathInfo WorkerProto::Serialise<UnkeyedValidPathInfo>::read(const St
{
auto deriver = WorkerProto::Serialise<std::optional<StorePath>>::read(store, conn);
auto narHash = Hash::parseAny(readString(conn.from), HashAlgorithm::SHA256);
UnkeyedValidPathInfo info(narHash);
UnkeyedValidPathInfo info(store, narHash);
info.deriver = std::move(deriver);
info.references = WorkerProto::Serialise<StorePathSet>::read(store, conn);
conn.from >> info.registrationTime >> info.narSize;

View file

@ -1057,7 +1057,10 @@ static void opServe(Strings opFlags, Strings opArgs)
auto deriver = readString(in);
ValidPathInfo info{
store->parseStorePath(path),
Hash::parseAny(readString(in), HashAlgorithm::SHA256),
{
*store,
Hash::parseAny(readString(in), HashAlgorithm::SHA256),
},
};
if (deriver != "")
info.deriver = store->parseStorePath(deriver);