mirror of
https://github.com/NixOS/nix.git
synced 2025-11-09 12:06:01 +01:00
Merge 4f1c8f62c3 into 479b6b73a9
This commit is contained in:
commit
1de4e0e70a
18 changed files with 111 additions and 78 deletions
|
|
@ -22,7 +22,15 @@ The store path info JSON format has been updated from version 1 to version 2:
|
||||||
- New: `"ca": {"method": "nar", "hash": {"algorithm": "sha256", "format": "base64", "hash": "EMIJ+giQ..."}}`
|
- New: `"ca": {"method": "nar", "hash": {"algorithm": "sha256", "format": "base64", "hash": "EMIJ+giQ..."}}`
|
||||||
- Still `null` values for input-addressed store objects
|
- Still `null` values for input-addressed store objects
|
||||||
|
|
||||||
Version 1 format is still accepted when reading for backward compatibility.
|
- **Structured hash fields**:
|
||||||
|
|
||||||
|
Hash values (`narHash` and `downloadHash`) are now structured JSON objects instead of strings:
|
||||||
|
|
||||||
|
- Old: `"narHash": "sha256:FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="`
|
||||||
|
- New: `"narHash": {"algorithm": "sha256", "format": "base64", "hash": "FePFYIlM..."}`
|
||||||
|
- Same structure applies to `downloadHash` in NAR info contexts
|
||||||
|
|
||||||
|
Nix currently only produces, and doesn't consume this format.
|
||||||
|
|
||||||
**Affected command**: `nix path-info --json`
|
**Affected command**: `nix path-info --json`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
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:
|
narHash:
|
||||||
type: string
|
"$ref": "./hash-v1.yaml"
|
||||||
title: NAR Hash
|
title: NAR Hash
|
||||||
description: |
|
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).
|
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.
|
> This is an impure "`.narinfo`" field that may not be included in certain contexts.
|
||||||
|
|
||||||
downloadHash:
|
downloadHash:
|
||||||
type: string
|
"$ref": "./hash-v1.yaml"
|
||||||
title: Download Hash
|
title: Download Hash
|
||||||
description: |
|
description: |
|
||||||
A digest for the compressed archive itself, as opposed to the data contained within.
|
A digest for the compressed archive itself, as opposed to the data contained within.
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,17 @@
|
||||||
},
|
},
|
||||||
"compression": "xz",
|
"compression": "xz",
|
||||||
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
|
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
|
||||||
"downloadHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"downloadHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"downloadSize": 4029176,
|
"downloadSize": 4029176,
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 34878,
|
"narSize": 34878,
|
||||||
"references": [
|
"references": [
|
||||||
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,11 @@
|
||||||
},
|
},
|
||||||
"method": "nar"
|
"method": "nar"
|
||||||
},
|
},
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 34878,
|
"narSize": 34878,
|
||||||
"references": [
|
"references": [
|
||||||
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,11 @@
|
||||||
{
|
{
|
||||||
"ca": null,
|
"ca": null,
|
||||||
"deriver": null,
|
"deriver": null,
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 0,
|
"narSize": 0,
|
||||||
"references": [],
|
"references": [],
|
||||||
"registrationTime": null,
|
"registrationTime": null,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
{
|
{
|
||||||
"ca": null,
|
"ca": null,
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 0,
|
"narSize": 0,
|
||||||
"references": [],
|
"references": [],
|
||||||
"version": 2
|
"version": 2
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,11 @@
|
||||||
"method": "nar"
|
"method": "nar"
|
||||||
},
|
},
|
||||||
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
|
"deriver": "/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar.drv",
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 34878,
|
"narSize": 34878,
|
||||||
"references": [
|
"references": [
|
||||||
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,11 @@
|
||||||
},
|
},
|
||||||
"method": "nar"
|
"method": "nar"
|
||||||
},
|
},
|
||||||
"narHash": "sha256-FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc=",
|
"narHash": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "FePFYIlMuycIXPZbWi7LGEiMmZSX9FMbaQenWBzm1Sc="
|
||||||
|
},
|
||||||
"narSize": 34878,
|
"narSize": 34878,
|
||||||
"references": [
|
"references": [
|
||||||
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
"/nix/store/g1w7hy3qg1w7hy3qg1w7hy3qg1w7hy3q-bar",
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ static NarInfo makeNarInfo(const Store & store, bool includeImpureInfo)
|
||||||
{ \
|
{ \
|
||||||
writeTest( \
|
writeTest( \
|
||||||
#STEM, \
|
#STEM, \
|
||||||
[&]() -> json { return makeNarInfo(*store, PURE).toJSON(*store, PURE, HashFormat::SRI); }, \
|
[&]() -> json { return makeNarInfo(*store, PURE).toJSON(*store, PURE); }, \
|
||||||
[](const auto & file) { return json::parse(readFile(file)); }, \
|
[](const auto & file) { return json::parse(readFile(file)); }, \
|
||||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ static UnkeyedValidPathInfo makeFull(const Store & store, bool includeImpureInfo
|
||||||
{ \
|
{ \
|
||||||
writeTest( \
|
writeTest( \
|
||||||
#STEM, \
|
#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) { return json::parse(readFile(file)); }, \
|
||||||
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
[](const auto & file, const auto & got) { return writeFile(file, got.dump(2) + "\n"); }); \
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -423,15 +423,6 @@ void adl_serializer<DerivationOptions>::to_json(json & json, const DerivationOpt
|
||||||
json["allowSubstitutes"] = o.allowSubstitutes;
|
json["allowSubstitutes"] = o.allowSubstitutes;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
static inline std::optional<T> ptrToOwned(const json * ptr)
|
|
||||||
{
|
|
||||||
if (ptr)
|
|
||||||
return std::optional{*ptr};
|
|
||||||
else
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
DerivationOptions::OutputChecks adl_serializer<DerivationOptions::OutputChecks>::from_json(const json & json_)
|
DerivationOptions::OutputChecks adl_serializer<DerivationOptions::OutputChecks>::from_json(const json & json_)
|
||||||
{
|
{
|
||||||
auto & json = getObject(json_);
|
auto & json = getObject(json_);
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ struct NarInfo : ValidPathInfo
|
||||||
|
|
||||||
std::string to_string(const StoreDirConfig & store) const;
|
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);
|
static NarInfo fromJSON(const StoreDirConfig & store, const StorePath & path, const nlohmann::json & json);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,7 +117,7 @@ struct UnkeyedValidPathInfo
|
||||||
* @param includeImpureInfo If true, variable elements such as the
|
* @param includeImpureInfo If true, variable elements such as the
|
||||||
* registration time are included.
|
* 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);
|
static UnkeyedValidPathInfo fromJSON(const StoreDirConfig & store, const nlohmann::json & json);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,11 +130,11 @@ std::string NarInfo::to_string(const StoreDirConfig & store) const
|
||||||
return res;
|
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;
|
using nlohmann::json;
|
||||||
|
|
||||||
auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo, hashFormat);
|
auto jsonObject = ValidPathInfo::toJSON(store, includeImpureInfo);
|
||||||
|
|
||||||
if (includeImpureInfo) {
|
if (includeImpureInfo) {
|
||||||
if (!url.empty())
|
if (!url.empty())
|
||||||
|
|
@ -142,7 +142,7 @@ nlohmann::json NarInfo::toJSON(const StoreDirConfig & store, bool includeImpureI
|
||||||
if (!compression.empty())
|
if (!compression.empty())
|
||||||
jsonObject["compression"] = compression;
|
jsonObject["compression"] = compression;
|
||||||
if (fileHash)
|
if (fileHash)
|
||||||
jsonObject["downloadHash"] = fileHash->to_string(hashFormat, true);
|
jsonObject["downloadHash"] = *fileHash;
|
||||||
if (fileSize)
|
if (fileSize)
|
||||||
jsonObject["downloadSize"] = fileSize;
|
jsonObject["downloadSize"] = fileSize;
|
||||||
}
|
}
|
||||||
|
|
@ -161,17 +161,17 @@ NarInfo NarInfo::fromJSON(const StoreDirConfig & store, const StorePath & path,
|
||||||
|
|
||||||
auto & obj = getObject(json);
|
auto & obj = getObject(json);
|
||||||
|
|
||||||
if (json.contains("url"))
|
if (auto * url = get(obj, "url"))
|
||||||
res.url = getString(valueAt(obj, "url"));
|
res.url = getString(*url);
|
||||||
|
|
||||||
if (json.contains("compression"))
|
if (auto * compression = get(obj, "compression"))
|
||||||
res.compression = getString(valueAt(obj, "compression"));
|
res.compression = getString(*compression);
|
||||||
|
|
||||||
if (json.contains("downloadHash"))
|
if (auto * downloadHash = get(obj, "downloadHash"))
|
||||||
res.fileHash = Hash::parseAny(getString(valueAt(obj, "downloadHash")), std::nullopt);
|
res.fileHash = *downloadHash;
|
||||||
|
|
||||||
if (json.contains("downloadSize"))
|
if (auto * downloadSize = get(obj, "downloadSize"))
|
||||||
res.fileSize = getUnsigned(valueAt(obj, "downloadSize"));
|
res.fileSize = getUnsigned(*downloadSize);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,7 @@ ValidPathInfo ValidPathInfo::makeFromCA(
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
nlohmann::json
|
nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo) const
|
||||||
UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInfo, HashFormat hashFormat) const
|
|
||||||
{
|
{
|
||||||
using nlohmann::json;
|
using nlohmann::json;
|
||||||
|
|
||||||
|
|
@ -158,7 +157,7 @@ UnkeyedValidPathInfo::toJSON(const StoreDirConfig & store, bool includeImpureInf
|
||||||
|
|
||||||
jsonObject["version"] = 2;
|
jsonObject["version"] = 2;
|
||||||
|
|
||||||
jsonObject["narHash"] = narHash.to_string(hashFormat, true);
|
jsonObject["narHash"] = narHash;
|
||||||
jsonObject["narSize"] = narSize;
|
jsonObject["narSize"] = narSize;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
@ -192,16 +191,13 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store
|
||||||
|
|
||||||
auto & json = getObject(_json);
|
auto & json = getObject(_json);
|
||||||
|
|
||||||
// Check version (optional for backward compatibility)
|
{
|
||||||
nlohmann::json::number_unsigned_t version = 1;
|
auto version = getUnsigned(valueAt(json, "version"));
|
||||||
if (json.contains("version")) {
|
if (version != 2)
|
||||||
version = getUnsigned(valueAt(json, "version"));
|
throw Error("Unsupported path info JSON format version %d, only version 2 is currently supported", version);
|
||||||
if (version != 1 && version != 2) {
|
|
||||||
throw Error("Unsupported path info JSON format version %d, expected 1 through 2", version);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
res.narHash = Hash::parseAny(getString(valueAt(json, "narHash")), std::nullopt);
|
res.narHash = valueAt(json, "narHash");
|
||||||
res.narSize = getUnsigned(valueAt(json, "narSize"));
|
res.narSize = getUnsigned(valueAt(json, "narSize"));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -213,18 +209,11 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig & store
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// New format as this as nullable but mandatory field; handling
|
try {
|
||||||
// missing is for back-compat.
|
res.ca = ptrToOwned<ContentAddress>(getNullable(valueAt(json, "ca")));
|
||||||
if (auto * rawCa0 = optionalValueAt(json, "ca"))
|
} catch (Error & e) {
|
||||||
if (auto * rawCa = getNullable(*rawCa0))
|
e.addTrace({}, "while reading key 'ca'");
|
||||||
switch (version) {
|
throw;
|
||||||
case 1:
|
|
||||||
// old string format also used in SQLite DB and .narinfo
|
|
||||||
res.ca = ContentAddress::parse(getString(*rawCa));
|
|
||||||
break;
|
|
||||||
case 2 ... std::numeric_limits<decltype(version)>::max():
|
|
||||||
res.ca = *rawCa;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auto * rawDeriver0 = optionalValueAt(json, "deriver"))
|
if (auto * rawDeriver0 = optionalValueAt(json, "deriver"))
|
||||||
|
|
|
||||||
|
|
@ -114,4 +114,13 @@ struct adl_serializer<std::optional<T>>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static inline std::optional<T> ptrToOwned(const json * ptr)
|
||||||
|
{
|
||||||
|
if (ptr)
|
||||||
|
return std::optional{*ptr};
|
||||||
|
else
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace nlohmann
|
} // namespace nlohmann
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ static json pathInfoToJSON(Store & store, const StorePathSet & storePaths, bool
|
||||||
// know the name yet until we've read the NAR info.
|
// know the name yet until we've read the NAR info.
|
||||||
printedStorePath = store.printStorePath(info->path);
|
printedStorePath = store.printStorePath(info->path);
|
||||||
|
|
||||||
jsonObject = info->toJSON(store, true, HashFormat::SRI);
|
jsonObject = info->toJSON(store, true);
|
||||||
|
|
||||||
if (showClosureSize) {
|
if (showClosureSize) {
|
||||||
StorePathSet closure;
|
StorePathSet closure;
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,16 @@ diff --unified --color=always \
|
||||||
jq --sort-keys 'map_values(.narHash)') \
|
jq --sort-keys 'map_values(.narHash)') \
|
||||||
<(jq --sort-keys <<-EOF
|
<(jq --sort-keys <<-EOF
|
||||||
{
|
{
|
||||||
"$foo": "sha256-QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA=",
|
"$foo": {
|
||||||
"$bar": "sha256-9fhYGu9fqxcQC2Kc81qh2RMo1QcLBUBo8U+pPn+jthQ=",
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "QvtAMbUl/uvi+LCObmqOhvNOapHdA2raiI4xG5zI5pA="
|
||||||
|
},
|
||||||
|
"$bar": {
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"format": "base64",
|
||||||
|
"hash": "9fhYGu9fqxcQC2Kc81qh2RMo1QcLBUBo8U+pPn+jthQ="
|
||||||
|
},
|
||||||
"$baz": null
|
"$baz": null
|
||||||
}
|
}
|
||||||
EOF
|
EOF
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue