From c67407172d8383394f4962ad177c84bf04529e5e Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Wed, 18 Sep 2019 21:17:27 +0200 Subject: [PATCH] Record original flakerefs in the lock file again If 'input..uri' changes, then the entry in the lockfile for input should be considered stale. Also print some messages when lock file entries are added/updated. --- flake.lock | 7 +++--- src/libexpr/flake/flake.cc | 43 ++++++++++++++++++++++++----------- src/libexpr/flake/flake.hh | 2 +- src/libexpr/flake/lockfile.cc | 6 +++-- src/libexpr/flake/lockfile.hh | 6 ++--- src/nix/flake.cc | 7 +++--- 6 files changed, 45 insertions(+), 26 deletions(-) diff --git a/flake.lock b/flake.lock index fa5649c03..70a433b26 100644 --- a/flake.lock +++ b/flake.lock @@ -2,9 +2,10 @@ "inputs": { "nixpkgs": { "inputs": {}, - "narHash": "sha256-TrLhI3xPkTTznE9gcMHhkHirGNN7N02zM4DxJ/U3WRs=", - "uri": "github:edolstra/nixpkgs/24bf27fc215e8300877dfa1c426b9966bbfbd150" + "narHash": "sha256-HGlE2VNbdEjCP76hWAS72kHBlMWhpvqWo58Obg1Vy6s=", + "originalUri": "nixpkgs", + "uri": "github:edolstra/nixpkgs/13e1bce51f4aebdf3db58ce8c4a93e904a272bff" } }, - "version": 2 + "version": 3 } diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 050e65259..accdb4194 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -205,8 +205,10 @@ static void expectType(EvalState & state, ValueType type, showType(type), showType(value.type), pos); } -Flake getFlake(EvalState & state, const FlakeRef & flakeRef) +Flake getFlake(EvalState & state, const FlakeRef & originalRef, bool allowLookup) { + auto flakeRef = maybeLookupFlake(state, originalRef, allowLookup); + SourceInfo sourceInfo = fetchFlake(state, flakeRef); debug("got flake source '%s' with flakeref %s", sourceInfo.storePath, sourceInfo.resolvedRef.to_string()); @@ -223,7 +225,7 @@ Flake getFlake(EvalState & state, const FlakeRef & flakeRef) if (!isInDir(realFlakeFile, state.store->toRealPath(sourceInfo.storePath))) throw Error("'flake.nix' file of flake '%s' escapes from '%s'", resolvedRef, sourceInfo.storePath); - Flake flake(flakeRef, sourceInfo); + Flake flake(originalRef, sourceInfo); if (!pathExists(realFlakeFile)) throw Error("source tree referenced by '%s' does not contain a '%s/flake.nix' file", resolvedRef, resolvedRef.subdir); @@ -358,6 +360,7 @@ bool allowedToUseRegistries(HandleLockFile handle, bool isTopRef) Note that this is lazy: we only recursively fetch inputs that are not in the lockfile yet. */ static std::pair updateLocks( + const std::string & inputPath, EvalState & state, const Flake & flake, HandleLockFile handleLockFile, @@ -366,23 +369,36 @@ static std::pair updateLocks( { LockedInput newEntry( flake.sourceInfo.resolvedRef, + flake.originalRef, flake.sourceInfo.narHash); for (auto & [id, input] : flake.inputs) { + auto inputPath2 = (inputPath.empty() ? "" : inputPath + "/") + id; auto i = oldEntry.inputs.find(id); - if (i != oldEntry.inputs.end()) { + if (i != oldEntry.inputs.end() && i->second.originalRef == input.ref) { newEntry.inputs.insert_or_assign(id, i->second); } else { if (handleLockFile == AllPure || handleLockFile == TopRefUsesRegistries) throw Error("cannot update flake input '%s' in pure mode", id); - if (input.isFlake) + if (input.isFlake) { + auto actualInput = getFlake(state, input.ref, + allowedToUseRegistries(handleLockFile, false)); + if (i == oldEntry.inputs.end()) + printMsg(lvlWarn, "mapped flake input '%s' to '%s'", + inputPath2, actualInput.sourceInfo.resolvedRef); + else + printMsg(lvlWarn, "updated flake input '%s' from '%s' to '%s'", + inputPath2, i->second.originalRef, actualInput.sourceInfo.resolvedRef); newEntry.inputs.insert_or_assign(id, - updateLocks(state, - getFlake(state, maybeLookupFlake(state, input.ref, allowedToUseRegistries(handleLockFile, false))), - handleLockFile, {}, false).second); - else { - auto sourceInfo = getNonFlake(state, maybeLookupFlake(state, input.ref, allowedToUseRegistries(handleLockFile, false))); - newEntry.inputs.insert_or_assign(id, LockedInput(sourceInfo.resolvedRef, sourceInfo.narHash)); + updateLocks(inputPath2, state, actualInput, handleLockFile, {}, false).second); + } else { + auto sourceInfo = getNonFlake(state, + maybeLookupFlake(state, input.ref, + allowedToUseRegistries(handleLockFile, false))); + printMsg(lvlWarn, "mapped flake input '%s' to '%s'", + inputPath2, sourceInfo.resolvedRef); + newEntry.inputs.insert_or_assign(id, + LockedInput(sourceInfo.resolvedRef, input.ref, sourceInfo.narHash)); } } } @@ -394,7 +410,8 @@ static std::pair updateLocks( and optionally write it to file, it the flake is writable. */ ResolvedFlake resolveFlake(EvalState & state, const FlakeRef & topRef, HandleLockFile handleLockFile) { - auto flake = getFlake(state, maybeLookupFlake(state, topRef, allowedToUseRegistries(handleLockFile, true))); + auto flake = getFlake(state, topRef, + allowedToUseRegistries(handleLockFile, true)); LockFile oldLockFile; @@ -407,7 +424,7 @@ ResolvedFlake resolveFlake(EvalState & state, const FlakeRef & topRef, HandleLoc } LockFile lockFile(updateLocks( - state, flake, handleLockFile, oldLockFile, true).second); + "", state, flake, handleLockFile, oldLockFile, true).second); if (!(lockFile == oldLockFile)) { if (allowedToWrite(handleLockFile)) { @@ -476,7 +493,7 @@ static void prim_callFlake(EvalState & state, const Pos & pos, Value * * args, V assert(lazyInput->lockedInput.ref.isImmutable()); if (lazyInput->isFlake) { - auto flake = getFlake(state, lazyInput->lockedInput.ref); + auto flake = getFlake(state, lazyInput->lockedInput.ref, false); if (flake.sourceInfo.narHash != lazyInput->lockedInput.narHash) throw Error("the content hash of flake '%s' doesn't match the hash recorded in the referring lockfile", flake.sourceInfo.resolvedRef); diff --git a/src/libexpr/flake/flake.hh b/src/libexpr/flake/flake.hh index 8f05e9799..b366e650b 100644 --- a/src/libexpr/flake/flake.hh +++ b/src/libexpr/flake/flake.hh @@ -78,7 +78,7 @@ struct Flake : originalRef(origRef), sourceInfo(sourceInfo) {}; }; -Flake getFlake(EvalState &, const FlakeRef &); +Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool allowLookup); /* If 'allowLookup' is true, then resolve 'flakeRef' using the registries. */ diff --git a/src/libexpr/flake/lockfile.cc b/src/libexpr/flake/lockfile.cc index f32d752f9..039b7a7c1 100644 --- a/src/libexpr/flake/lockfile.cc +++ b/src/libexpr/flake/lockfile.cc @@ -6,6 +6,7 @@ namespace nix::flake { LockedInput::LockedInput(const nlohmann::json & json) : LockedInputs(json) , ref(json["uri"]) + , originalRef(json["originalUri"]) , narHash(Hash((std::string) json["narHash"])) { if (!ref.isImmutable()) @@ -16,6 +17,7 @@ nlohmann::json LockedInput::toJson() const { auto json = LockedInputs::toJson(); json["uri"] = ref.to_string(); + json["originalUri"] = originalRef.to_string(); json["narHash"] = narHash.to_string(SRI); return json; } @@ -54,7 +56,7 @@ bool LockedInputs::isDirty() const nlohmann::json LockFile::toJson() const { auto json = LockedInputs::toJson(); - json["version"] = 2; + json["version"] = 3; return json; } @@ -64,7 +66,7 @@ LockFile LockFile::read(const Path & path) auto json = nlohmann::json::parse(readFile(path)); auto version = json.value("version", 0); - if (version != 2) + if (version != 3) throw Error("lock file '%s' has unsupported version %d", path, version); return LockFile(json); diff --git a/src/libexpr/flake/lockfile.hh b/src/libexpr/flake/lockfile.hh index 084eabc1a..ab81eac8b 100644 --- a/src/libexpr/flake/lockfile.hh +++ b/src/libexpr/flake/lockfile.hh @@ -30,11 +30,11 @@ struct LockedInputs /* Lock file information about a flake input. */ struct LockedInput : LockedInputs { - FlakeRef ref; + FlakeRef ref, originalRef; Hash narHash; - LockedInput(const FlakeRef & ref, const Hash & narHash) - : ref(ref), narHash(narHash) + LockedInput(const FlakeRef & ref, const FlakeRef & originalRef, const Hash & narHash) + : ref(ref), originalRef(originalRef), narHash(narHash) { assert(ref.isImmutable()); }; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 5fd3f5508..599bf12eb 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -38,8 +38,7 @@ public: Flake getFlake() { auto evalState = getEvalState(); - return flake::getFlake(*evalState, - maybeLookupFlake(*evalState, getFlakeRef(), useRegistries)); + return flake::getFlake(*evalState, getFlakeRef(), useRegistries); } ResolvedFlake resolveFlake() @@ -500,13 +499,13 @@ struct CmdFlakePin : virtual Args, EvalCommand FlakeRegistry userRegistry = *readRegistry(userRegistryPath); auto it = userRegistry.entries.find(FlakeRef(alias)); if (it != userRegistry.entries.end()) { - it->second = getFlake(*evalState, maybeLookupFlake(*evalState, it->second, true)).sourceInfo.resolvedRef; + it->second = getFlake(*evalState, it->second, true).sourceInfo.resolvedRef; writeRegistry(userRegistry, userRegistryPath); } else { std::shared_ptr globalReg = evalState->getGlobalFlakeRegistry(); it = globalReg->entries.find(FlakeRef(alias)); if (it != globalReg->entries.end()) { - auto newRef = getFlake(*evalState, maybeLookupFlake(*evalState, it->second, true)).sourceInfo.resolvedRef; + auto newRef = getFlake(*evalState, it->second, true).sourceInfo.resolvedRef; userRegistry.entries.insert_or_assign(alias, newRef); writeRegistry(userRegistry, userRegistryPath); } else