Record TreeInfo in the lock file

Necessary for #3253.
This commit is contained in:
Eelco Dolstra 2020-02-01 23:33:44 +01:00
parent 8451298b35
commit b9d64f9318
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE
4 changed files with 89 additions and 16 deletions

View file

@ -478,7 +478,7 @@ LockedFlake lockFlake(
lockFlags.useRegistries, flakeCache); lockFlags.useRegistries, flakeCache);
newLocks.inputs.insert_or_assign(id, newLocks.inputs.insert_or_assign(id,
LockedInput(inputFlake.resolvedRef, inputFlake.originalRef, inputFlake.sourceInfo->info.narHash)); LockedInput(inputFlake.resolvedRef, inputFlake.originalRef, inputFlake.sourceInfo->info));
/* Recursively process the inputs of this /* Recursively process the inputs of this
flake. Also, unless we already have this flake. Also, unless we already have this
@ -497,7 +497,7 @@ LockedFlake lockFlake(
auto [sourceInfo, resolvedRef] = getNonFlake(state, input.ref, auto [sourceInfo, resolvedRef] = getNonFlake(state, input.ref,
lockFlags.useRegistries, flakeCache); lockFlags.useRegistries, flakeCache);
newLocks.inputs.insert_or_assign(id, newLocks.inputs.insert_or_assign(id,
LockedInput(resolvedRef, input.ref, sourceInfo.info.narHash)); LockedInput(resolvedRef, input.ref, sourceInfo.info));
} }
} }
} }
@ -604,9 +604,14 @@ static void prim_callFlake(EvalState & state, const Pos & pos, Value * * args, V
if (lazyInput->isFlake) { if (lazyInput->isFlake) {
auto flake = getFlake(state, lazyInput->lockedInput.ref, false); auto flake = getFlake(state, lazyInput->lockedInput.ref, false);
if (flake.sourceInfo->info.narHash != lazyInput->lockedInput.narHash) if (flake.sourceInfo->info.narHash != lazyInput->lockedInput.info.narHash)
throw Error("the content hash of flake '%s' doesn't match the hash recorded in the referring lockfile", throw Error("the content hash of flake '%s' (%s) doesn't match the hash recorded in the referring lock file (%s)",
lazyInput->lockedInput.ref); lazyInput->lockedInput.ref,
flake.sourceInfo->info.narHash.to_string(SRI),
lazyInput->lockedInput.info.narHash.to_string(SRI));
// FIXME: check all the other attributes in lockedInput.info
// once we've dropped support for lock file version 4.
assert(flake.sourceInfo->storePath == lazyInput->lockedInput.computeStorePath(*state.store)); assert(flake.sourceInfo->storePath == lazyInput->lockedInput.computeStorePath(*state.store));
@ -615,9 +620,14 @@ static void prim_callFlake(EvalState & state, const Pos & pos, Value * * args, V
FlakeCache flakeCache; FlakeCache flakeCache;
auto [sourceInfo, resolvedRef] = getNonFlake(state, lazyInput->lockedInput.ref, false, flakeCache); auto [sourceInfo, resolvedRef] = getNonFlake(state, lazyInput->lockedInput.ref, false, flakeCache);
if (sourceInfo.info.narHash != lazyInput->lockedInput.narHash) if (sourceInfo.info.narHash != lazyInput->lockedInput.info.narHash)
throw Error("the content hash of repository '%s' doesn't match the hash recorded in the referring lockfile", throw Error("the content hash of repository '%s' (%s) doesn't match the hash recorded in the referring lock file (%s)",
lazyInput->lockedInput.ref); lazyInput->lockedInput.ref,
sourceInfo.info.narHash.to_string(SRI),
lazyInput->lockedInput.info.narHash.to_string(SRI));
// FIXME: check all the other attributes in lockedInput.info
// once we've dropped support for lock file version 4.
assert(sourceInfo.storePath == lazyInput->lockedInput.computeStorePath(*state.store)); assert(sourceInfo.storePath == lazyInput->lockedInput.computeStorePath(*state.store));

View file

@ -44,28 +44,81 @@ FlakeRef getFlakeRef(
throw Error("attribute '%s' missing in lock file", version4Attr); throw Error("attribute '%s' missing in lock file", version4Attr);
} }
static TreeInfo parseTreeInfo(const nlohmann::json & json)
{
TreeInfo info;
auto i = json.find("info");
if (i != json.end()) {
const nlohmann::json & i2(*i);
auto j = i2.find("narHash");
if (j != i2.end())
info.narHash = Hash((std::string) *j);
else
throw Error("attribute 'narHash' missing in lock file");
j = i2.find("rev");
if (j != i2.end())
info.rev = Hash((std::string) *j, htSHA1);
j = i2.find("revCount");
if (j != i2.end())
info.revCount = *j;
j = i2.find("lastModified");
if (j != i2.end())
info.lastModified = *j;
return info;
}
i = json.find("narHash");
if (i != json.end()) {
info.narHash = Hash((std::string) *i);
return info;
}
throw Error("attribute 'info' missing in lock file");
}
LockedInput::LockedInput(const nlohmann::json & json) LockedInput::LockedInput(const nlohmann::json & json)
: LockedInputs(json) : LockedInputs(json)
, ref(getFlakeRef(json, "url", "uri", "resolvedRef")) , ref(getFlakeRef(json, "url", "uri", "resolvedRef"))
, originalRef(getFlakeRef(json, "originalUrl", "originalUri", "originalRef")) , originalRef(getFlakeRef(json, "originalUrl", "originalUri", "originalRef"))
, narHash(Hash((std::string) json["narHash"])) , info(parseTreeInfo(json))
{ {
if (!ref.isImmutable()) if (!ref.isImmutable())
throw Error("lockfile contains mutable flakeref '%s'", ref); throw Error("lockfile contains mutable flakeref '%s'", ref);
} }
static nlohmann::json treeInfoToJson(const TreeInfo & info)
{
nlohmann::json json;
assert(info.narHash);
json["narHash"] = info.narHash.to_string(SRI);
if (info.rev)
json["rev"] = info.rev->gitRev();
if (info.revCount)
json["revCount"] = *info.revCount;
if (info.lastModified)
json["lastModified"] = *info.lastModified;
return json;
}
nlohmann::json LockedInput::toJson() const nlohmann::json LockedInput::toJson() const
{ {
auto json = LockedInputs::toJson(); auto json = LockedInputs::toJson();
json["originalRef"] = fetchers::attrsToJson(originalRef.toAttrs()); json["originalRef"] = fetchers::attrsToJson(originalRef.toAttrs());
json["resolvedRef"] = fetchers::attrsToJson(ref.toAttrs()); json["resolvedRef"] = fetchers::attrsToJson(ref.toAttrs());
json["narHash"] = narHash.to_string(SRI); // FIXME json["info"] = treeInfoToJson(info);
return json; return json;
} }
StorePath LockedInput::computeStorePath(Store & store) const StorePath LockedInput::computeStorePath(Store & store) const
{ {
return store.makeFixedOutputPath(true, narHash, "source"); assert(info.narHash);
return store.makeFixedOutputPath(true, info.narHash, "source");
} }
LockedInputs::LockedInputs(const nlohmann::json & json) LockedInputs::LockedInputs(const nlohmann::json & json)

View file

@ -36,10 +36,10 @@ struct LockedInputs
struct LockedInput : LockedInputs struct LockedInput : LockedInputs
{ {
FlakeRef ref, originalRef; FlakeRef ref, originalRef;
Hash narHash; TreeInfo info;
LockedInput(const FlakeRef & ref, const FlakeRef & originalRef, const Hash & narHash) LockedInput(const FlakeRef & ref, const FlakeRef & originalRef, const TreeInfo & info)
: ref(ref), originalRef(originalRef), narHash(narHash) : ref(ref), originalRef(originalRef), info(info)
{ } { }
LockedInput(const nlohmann::json & json); LockedInput(const nlohmann::json & json);
@ -48,7 +48,8 @@ struct LockedInput : LockedInputs
{ {
return return
ref == other.ref ref == other.ref
&& narHash == other.narHash && originalRef == other.originalRef
&& info == other.info
&& inputs == other.inputs; && inputs == other.inputs;
} }

View file

@ -5,9 +5,18 @@ namespace nix {
struct TreeInfo struct TreeInfo
{ {
Hash narHash; Hash narHash;
std::optional<Hash> rev; std::optional<Hash> rev; // FIXME: remove
std::optional<uint64_t> revCount; std::optional<uint64_t> revCount;
std::optional<time_t> lastModified; std::optional<time_t> lastModified;
bool operator ==(const TreeInfo & other) const
{
return
narHash == other.narHash
&& rev == other.rev
&& revCount == other.revCount
&& lastModified == other.lastModified;
}
}; };
} }