mirror of
https://github.com/NixOS/nix.git
synced 2025-12-11 11:31:03 +01:00
Merge pull request #14704 from NixOS/version-output
Introduce `--json-format` for `nix path-info`
This commit is contained in:
commit
9246dca541
36 changed files with 464 additions and 132 deletions
|
|
@ -25,7 +25,8 @@ struct UnkeyedNarInfo : virtual UnkeyedValidPathInfo
|
|||
// 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;
|
||||
nlohmann::json
|
||||
toJSON(const StoreDirConfig * store, bool includeImpureInfo, PathInfoJsonFormat format) const override;
|
||||
static UnkeyedNarInfo fromJSON(const StoreDirConfig * store, const nlohmann::json & json);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ namespace nix {
|
|||
class Store;
|
||||
struct StoreDirConfig;
|
||||
|
||||
/**
|
||||
* JSON format version for path info output.
|
||||
*/
|
||||
enum class PathInfoJsonFormat {
|
||||
/// Legacy format with string hashes and full store paths
|
||||
V1 = 1,
|
||||
/// New format with structured hashes and store path base names
|
||||
V2 = 2,
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an integer version number to PathInfoJsonFormat.
|
||||
* Throws Error if the version is not supported.
|
||||
*/
|
||||
PathInfoJsonFormat parsePathInfoJsonFormat(uint64_t version);
|
||||
|
||||
struct SubstitutablePathInfo
|
||||
{
|
||||
std::optional<StorePath> deriver;
|
||||
|
|
@ -114,10 +130,16 @@ struct UnkeyedValidPathInfo
|
|||
virtual ~UnkeyedValidPathInfo() {}
|
||||
|
||||
/**
|
||||
* @param store If non-null, store paths are rendered as full paths.
|
||||
* If null, store paths are rendered as base names.
|
||||
* @param includeImpureInfo If true, variable elements such as the
|
||||
* registration time are included.
|
||||
* registration time are included.
|
||||
* @param format JSON format version. Version 1 uses string hashes and
|
||||
* string content addresses. Version 2 uses structured
|
||||
* hashes and structured content addresses.
|
||||
*/
|
||||
virtual nlohmann::json toJSON(const StoreDirConfig * store, bool includeImpureInfo) const;
|
||||
virtual nlohmann::json
|
||||
toJSON(const StoreDirConfig * store, bool includeImpureInfo, PathInfoJsonFormat format) const;
|
||||
static UnkeyedValidPathInfo fromJSON(const StoreDirConfig * store, const nlohmann::json & json);
|
||||
};
|
||||
|
||||
|
|
@ -196,5 +218,6 @@ using ValidPathInfos = std::map<StorePath, ValidPathInfo>;
|
|||
|
||||
} // namespace nix
|
||||
|
||||
JSON_IMPL(nix::PathInfoJsonFormat)
|
||||
JSON_IMPL(nix::UnkeyedValidPathInfo)
|
||||
JSON_IMPL(nix::ValidPathInfo)
|
||||
|
|
|
|||
|
|
@ -132,19 +132,24 @@ std::string NarInfo::to_string(const StoreDirConfig & store) const
|
|||
return res;
|
||||
}
|
||||
|
||||
nlohmann::json UnkeyedNarInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const
|
||||
nlohmann::json
|
||||
UnkeyedNarInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo, PathInfoJsonFormat format) const
|
||||
{
|
||||
using nlohmann::json;
|
||||
|
||||
auto jsonObject = UnkeyedValidPathInfo::toJSON(store, includeImpureInfo);
|
||||
auto jsonObject = UnkeyedValidPathInfo::toJSON(store, includeImpureInfo, format);
|
||||
|
||||
if (includeImpureInfo) {
|
||||
if (!url.empty())
|
||||
jsonObject["url"] = url;
|
||||
if (!compression.empty())
|
||||
jsonObject["compression"] = compression;
|
||||
if (fileHash)
|
||||
jsonObject["downloadHash"] = *fileHash;
|
||||
if (fileHash) {
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
jsonObject["downloadHash"] = fileHash->to_string(HashFormat::SRI, true);
|
||||
else
|
||||
jsonObject["downloadHash"] = *fileHash;
|
||||
}
|
||||
if (fileSize)
|
||||
jsonObject["downloadSize"] = fileSize;
|
||||
}
|
||||
|
|
@ -154,20 +159,26 @@ nlohmann::json UnkeyedNarInfo::toJSON(const StoreDirConfig * store, bool include
|
|||
|
||||
UnkeyedNarInfo UnkeyedNarInfo::fromJSON(const StoreDirConfig * store, const nlohmann::json & json)
|
||||
{
|
||||
using nlohmann::detail::value_t;
|
||||
|
||||
UnkeyedNarInfo res{UnkeyedValidPathInfo::fromJSON(store, json)};
|
||||
|
||||
auto & obj = getObject(json);
|
||||
|
||||
PathInfoJsonFormat format = PathInfoJsonFormat::V1;
|
||||
if (auto * version = optionalValueAt(obj, "version"))
|
||||
format = *version;
|
||||
|
||||
if (auto * url = get(obj, "url"))
|
||||
res.url = getString(*url);
|
||||
|
||||
if (auto * compression = get(obj, "compression"))
|
||||
res.compression = getString(*compression);
|
||||
|
||||
if (auto * downloadHash = get(obj, "downloadHash"))
|
||||
res.fileHash = *downloadHash;
|
||||
if (auto * downloadHash = get(obj, "downloadHash")) {
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
res.fileHash = Hash::parseSRI(getString(*downloadHash));
|
||||
else
|
||||
res.fileHash = *downloadHash;
|
||||
}
|
||||
|
||||
if (auto * downloadSize = get(obj, "downloadSize"))
|
||||
res.fileSize = getUnsigned(*downloadSize);
|
||||
|
|
@ -188,7 +199,7 @@ UnkeyedNarInfo adl_serializer<UnkeyedNarInfo>::from_json(const json & json)
|
|||
|
||||
void adl_serializer<UnkeyedNarInfo>::to_json(json & json, const UnkeyedNarInfo & c)
|
||||
{
|
||||
json = c.toJSON(nullptr, true);
|
||||
json = c.toJSON(nullptr, true, PathInfoJsonFormat::V2);
|
||||
}
|
||||
|
||||
} // namespace nlohmann
|
||||
|
|
|
|||
|
|
@ -8,6 +8,18 @@
|
|||
|
||||
namespace nix {
|
||||
|
||||
PathInfoJsonFormat parsePathInfoJsonFormat(uint64_t version)
|
||||
{
|
||||
switch (version) {
|
||||
case 1:
|
||||
return PathInfoJsonFormat::V1;
|
||||
case 2:
|
||||
return PathInfoJsonFormat::V2;
|
||||
default:
|
||||
throw Error("unsupported path info JSON format version %d; supported versions are 1 and 2", version);
|
||||
}
|
||||
}
|
||||
|
||||
GENERATE_CMP_EXT(
|
||||
,
|
||||
std::weak_ordering,
|
||||
|
|
@ -149,31 +161,45 @@ ValidPathInfo ValidPathInfo::makeFromCA(
|
|||
return res;
|
||||
}
|
||||
|
||||
nlohmann::json UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo) const
|
||||
nlohmann::json
|
||||
UnkeyedValidPathInfo::toJSON(const StoreDirConfig * store, bool includeImpureInfo, PathInfoJsonFormat format) const
|
||||
{
|
||||
using nlohmann::json;
|
||||
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
assert(store);
|
||||
|
||||
auto jsonObject = json::object();
|
||||
|
||||
jsonObject["version"] = 2;
|
||||
jsonObject["version"] = format;
|
||||
|
||||
jsonObject["narHash"] = format == PathInfoJsonFormat::V1
|
||||
? static_cast<json>(narHash.to_string(HashFormat::SRI, true))
|
||||
: static_cast<json>(narHash);
|
||||
|
||||
jsonObject["narHash"] = narHash;
|
||||
jsonObject["narSize"] = narSize;
|
||||
|
||||
{
|
||||
auto & jsonRefs = jsonObject["references"] = json::array();
|
||||
for (auto & ref : references)
|
||||
jsonRefs.emplace_back(store ? static_cast<json>(store->printStorePath(ref)) : static_cast<json>(ref));
|
||||
jsonRefs.emplace_back(
|
||||
format == PathInfoJsonFormat::V1 ? static_cast<json>(store->printStorePath(ref))
|
||||
: static_cast<json>(ref));
|
||||
}
|
||||
|
||||
jsonObject["ca"] = ca;
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
jsonObject["ca"] = ca ? static_cast<json>(renderContentAddress(*ca)) : static_cast<json>(nullptr);
|
||||
else
|
||||
jsonObject["ca"] = ca;
|
||||
|
||||
if (includeImpureInfo) {
|
||||
jsonObject["deriver"] = deriver ? (store ? static_cast<json>(std::optional{store->printStorePath(*deriver)})
|
||||
: static_cast<json>(std::optional{*deriver}))
|
||||
: static_cast<json>(std::optional<StorePath>{});
|
||||
|
||||
jsonObject["registrationTime"] = registrationTime ? (std::optional{registrationTime}) : std::nullopt;
|
||||
if (format == PathInfoJsonFormat::V1) {
|
||||
jsonObject["deriver"] =
|
||||
deriver ? static_cast<json>(store->printStorePath(*deriver)) : static_cast<json>(nullptr);
|
||||
} else {
|
||||
jsonObject["deriver"] = deriver;
|
||||
}
|
||||
jsonObject["registrationTime"] = registrationTime ? std::optional{registrationTime} : std::nullopt;
|
||||
|
||||
jsonObject["ultimate"] = ultimate;
|
||||
|
||||
|
|
@ -193,34 +219,51 @@ UnkeyedValidPathInfo UnkeyedValidPathInfo::fromJSON(const StoreDirConfig * store
|
|||
|
||||
auto & json = getObject(_json);
|
||||
|
||||
{
|
||||
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);
|
||||
}
|
||||
PathInfoJsonFormat format = PathInfoJsonFormat::V1;
|
||||
if (auto * version = optionalValueAt(json, "version"))
|
||||
format = *version;
|
||||
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
assert(store);
|
||||
|
||||
if (format == PathInfoJsonFormat::V1)
|
||||
res.narHash = Hash::parseSRI(getString(valueAt(json, "narHash")));
|
||||
else
|
||||
res.narHash = valueAt(json, "narHash");
|
||||
|
||||
res.narHash = valueAt(json, "narHash");
|
||||
res.narSize = getUnsigned(valueAt(json, "narSize"));
|
||||
|
||||
try {
|
||||
auto references = getStringList(valueAt(json, "references"));
|
||||
auto & references = getArray(valueAt(json, "references"));
|
||||
for (auto & input : references)
|
||||
res.references.insert(store ? store->parseStorePath(getString(input)) : static_cast<StorePath>(input));
|
||||
res.references.insert(
|
||||
format == PathInfoJsonFormat::V1 ? store->parseStorePath(getString(input))
|
||||
: static_cast<StorePath>(input));
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "while reading key 'references'");
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
res.ca = ptrToOwned<ContentAddress>(getNullable(valueAt(json, "ca")));
|
||||
if (format == PathInfoJsonFormat::V1) {
|
||||
if (auto * rawCa = getNullable(valueAt(json, "ca")))
|
||||
res.ca = ContentAddress::parse(getString(*rawCa));
|
||||
} else {
|
||||
res.ca = ptrToOwned<ContentAddress>(getNullable(valueAt(json, "ca")));
|
||||
}
|
||||
} catch (Error & e) {
|
||||
e.addTrace({}, "while reading key 'ca'");
|
||||
throw;
|
||||
}
|
||||
|
||||
if (auto * rawDeriver0 = optionalValueAt(json, "deriver"))
|
||||
if (auto * rawDeriver = getNullable(*rawDeriver0))
|
||||
res.deriver = store ? store->parseStorePath(getString(*rawDeriver)) : static_cast<StorePath>(*rawDeriver);
|
||||
if (auto * rawDeriver0 = optionalValueAt(json, "deriver")) {
|
||||
if (format == PathInfoJsonFormat::V1) {
|
||||
if (auto * rawDeriver = getNullable(*rawDeriver0))
|
||||
res.deriver = store->parseStorePath(getString(*rawDeriver));
|
||||
} else {
|
||||
res.deriver = ptrToOwned<StorePath>(getNullable(*rawDeriver0));
|
||||
}
|
||||
}
|
||||
|
||||
if (auto * rawRegistrationTime0 = optionalValueAt(json, "registrationTime"))
|
||||
if (auto * rawRegistrationTime = getNullable(*rawRegistrationTime0))
|
||||
|
|
@ -241,6 +284,16 @@ namespace nlohmann {
|
|||
|
||||
using namespace nix;
|
||||
|
||||
PathInfoJsonFormat adl_serializer<PathInfoJsonFormat>::from_json(const json & json)
|
||||
{
|
||||
return parsePathInfoJsonFormat(getUnsigned(json));
|
||||
}
|
||||
|
||||
void adl_serializer<PathInfoJsonFormat>::to_json(json & json, const PathInfoJsonFormat & format)
|
||||
{
|
||||
json = static_cast<int>(format);
|
||||
}
|
||||
|
||||
UnkeyedValidPathInfo adl_serializer<UnkeyedValidPathInfo>::from_json(const json & json)
|
||||
{
|
||||
return UnkeyedValidPathInfo::fromJSON(nullptr, json);
|
||||
|
|
@ -248,7 +301,7 @@ UnkeyedValidPathInfo adl_serializer<UnkeyedValidPathInfo>::from_json(const json
|
|||
|
||||
void adl_serializer<UnkeyedValidPathInfo>::to_json(json & json, const UnkeyedValidPathInfo & c)
|
||||
{
|
||||
json = c.toJSON(nullptr, true);
|
||||
json = c.toJSON(nullptr, true, PathInfoJsonFormat::V2);
|
||||
}
|
||||
|
||||
ValidPathInfo adl_serializer<ValidPathInfo>::from_json(const json & json0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue