diff --git a/src/libexpr/primops/flake.cc b/src/libexpr/primops/flake.cc index 88a0293e3..e806ef6c7 100644 --- a/src/libexpr/primops/flake.cc +++ b/src/libexpr/primops/flake.cc @@ -194,11 +194,8 @@ static FlakeRef lookupFlake(EvalState & state, const FlakeRef & flakeRef, const return flakeRef; } -static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef flakeRef, bool impureIsAllowed = false) +static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef fRef, bool impureIsAllowed = false) { - FlakeRef fRef = lookupFlake(state, flakeRef, - impureIsAllowed ? state.getFlakeRegistries() : std::vector>()); - if (evalSettings.pureEval && !impureIsAllowed && !fRef.isImmutable()) throw Error("requested to fetch mutable flake '%s' in pure mode", fRef); @@ -266,26 +263,31 @@ static FlakeSourceInfo fetchFlake(EvalState & state, const FlakeRef flakeRef, bo // This will return the flake which corresponds to a given FlakeRef. The lookupFlake is done within this function. Flake getFlake(EvalState & state, const FlakeRef & flakeRef, bool impureIsAllowed = false) { - FlakeSourceInfo sourceInfo = fetchFlake(state, flakeRef, impureIsAllowed); + FlakeRef resolvedRef = lookupFlake(state, flakeRef, + impureIsAllowed ? state.getFlakeRegistries() : std::vector>()); + + FlakeSourceInfo sourceInfo = fetchFlake(state, resolvedRef, impureIsAllowed); debug("got flake source '%s' with revision %s", sourceInfo.storePath, sourceInfo.rev.value_or(Hash(htSHA1)).to_string(Base16, false)); + resolvedRef = sourceInfo.flakeRef; // `resolvedRef` is now immutable + state.store->assertStorePath(sourceInfo.storePath); if (state.allowedPaths) state.allowedPaths->insert(sourceInfo.storePath); - Flake flake(flakeRef, std::move(sourceInfo)); - if (std::get_if(&flakeRef.data)) { + Flake flake(resolvedRef, std::move(sourceInfo)); + if (std::get_if(&resolvedRef.data)) { // FIXME: ehm? if (flake.sourceInfo.rev) - flake.ref = FlakeRef(flakeRef.baseRef().to_string() + flake.ref = FlakeRef(resolvedRef.baseRef().to_string() + "/" + flake.sourceInfo.rev->to_string(Base16, false)); } - Path flakeFile = sourceInfo.storePath + "/flake.nix"; + Path flakeFile = sourceInfo.storePath + resolvedRef.subdir + "/flake.nix"; if (!pathExists(flakeFile)) - throw Error("source tree referenced by '%s' does not contain a 'flake.nix' file", flakeRef); + throw Error("source tree referenced by '%s' does not contain a 'flake.nix' file", resolvedRef); Value vInfo; state.evalFile(flakeFile, vInfo); // FIXME: symlink attack diff --git a/src/libexpr/primops/flakeref.cc b/src/libexpr/primops/flakeref.cc index b91bbee2a..022535515 100644 --- a/src/libexpr/primops/flakeref.cc +++ b/src/libexpr/primops/flakeref.cc @@ -139,6 +139,7 @@ std::string FlakeRef::to_string() const string += (ref ? "/" + *ref : "") + (rev ? "/" + rev->to_string(Base16, false) : ""); + if (subdir != "") string += "?dir=" + subdir; return string; } diff --git a/src/libexpr/primops/flakeref.hh b/src/libexpr/primops/flakeref.hh index 51fdc3b70..299094634 100644 --- a/src/libexpr/primops/flakeref.hh +++ b/src/libexpr/primops/flakeref.hh @@ -69,7 +69,7 @@ namespace nix { https://example.org/my/repo.git https://example.org/my/repo.git?ref=release-1.2.3 https://example.org/my/repo.git?rev=e72daba8250068216d79d2aeef40d4d95aff6666 - git://github.com/edolstra/dwarffs.git\?ref=flake\&rev=2efca4bc9da70fb001b26c3dc858c6397d3c4817 + git://github.com/edolstra/dwarffs.git?ref=flake&rev=2efca4bc9da70fb001b26c3dc858c6397d3c4817 * /path.git(\?attr(&attr)*)? @@ -144,17 +144,18 @@ struct FlakeRef std::optional ref; std::optional rev; + Path subdir = ""; // This is a relative path pointing at the flake.nix file's directory, relative to the git root. bool operator<(const FlakeRef & flakeRef) const { - return std::make_tuple(this->data, ref, rev) < - std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev); + return std::make_tuple(data, ref, rev, subdir) < + std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev, subdir); } bool operator==(const FlakeRef & flakeRef) const { - return std::make_tuple(this->data, ref, rev) == - std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev); + return std::make_tuple(data, ref, rev, subdir) == + std::make_tuple(flakeRef.data, flakeRef.ref, flakeRef.rev, flakeRef.subdir); } // Parse a flake URI.