diff --git i/lix/libexpr/primops/fetchTree.cc w/lix/libexpr/primops/fetchTree.cc index 93b08ecc9..6d04ce24b 100644 --- i/lix/libexpr/primops/fetchTree.cc +++ w/lix/libexpr/primops/fetchTree.cc @@ -168,6 +168,11 @@ static void fetchTree( "attribute 'name' isn’t supported in call to 'fetchTree'" ).atPos(pos).debugThrow(); + // HACK: When using `fetchGit`, locking with only the hash should happen + // as we don't care about flake hallucinations about `lastModified` + if (type == "git" && attrs.contains("narHash")) + attrs["type"] = "git-locked"; + input = fetchers::Input::fromAttrs(std::move(attrs)); } else { auto url = state.coerceToString(pos, *args[0], context, diff --git i/lix/libfetchers/builtin-fetchers.hh w/lix/libfetchers/builtin-fetchers.hh index d3be7f7f2..d1389b8ba 100644 --- i/lix/libfetchers/builtin-fetchers.hh +++ w/lix/libfetchers/builtin-fetchers.hh @@ -10,6 +10,7 @@ std::unique_ptr makePathInputScheme(); std::unique_ptr makeFileInputScheme(); std::unique_ptr makeTarballInputScheme(); std::unique_ptr makeGitInputScheme(); +std::unique_ptr makeGitLockedInputScheme(); std::unique_ptr makeMercurialInputScheme(); std::unique_ptr makeGitHubInputScheme(); std::unique_ptr makeGitLabInputScheme(); diff --git i/lix/libfetchers/fetchers.cc w/lix/libfetchers/fetchers.cc index 0dc9f5e0c..91cd9332d 100644 --- i/lix/libfetchers/fetchers.cc +++ w/lix/libfetchers/fetchers.cc @@ -22,6 +22,7 @@ void initLibFetchers() registerInputScheme(makeTarballInputScheme()); registerInputScheme(makeFileInputScheme()); registerInputScheme(makeGitInputScheme()); + registerInputScheme(makeGitLockedInputScheme()); registerInputScheme(makeMercurialInputScheme()); registerInputScheme(makeGitHubInputScheme()); registerInputScheme(makeGitLabInputScheme()); diff --git i/lix/libfetchers/git.cc w/lix/libfetchers/git.cc index 21fa1904d..f9573eacd 100644 --- i/lix/libfetchers/git.cc +++ w/lix/libfetchers/git.cc @@ -812,4 +812,40 @@ std::unique_ptr makeGitInputScheme() return std::make_unique(); } +struct GitLockedInputScheme : GitInputScheme { + + std::optional inputFromAttrs(const Attrs & attrs) const override + { + if (maybeGetStrAttr(attrs, "type") != "git-locked") return {}; + + for (auto & [name, value] : attrs) + if (name != "type" && name != "url" && name != "ref" && name != "rev" && name != "shallow" && name != "submodules" && name != "lastModified" && name != "revCount" && name != "narHash" && name != "allRefs" && name != "name" && name != "dirtyRev" && name != "dirtyShortRev") + throw Error("unsupported Git input attribute '%s'", name); + + parseURL(getStrAttr(attrs, "url")); + maybeGetBoolAttr(attrs, "shallow"); + maybeGetBoolAttr(attrs, "submodules"); + maybeGetBoolAttr(attrs, "allRefs"); + + if (auto ref = maybeGetStrAttr(attrs, "ref")) { + if (std::regex_search(*ref, badGitRefRegex)) + throw BadURL("invalid Git branch/tag name '%s'", *ref); + } + + Input input; + input.attrs = attrs; + return input; + } + + bool hasAllInfo(const Input & input) const override { + return true; + } + +}; + +std::unique_ptr makeGitLockedInputScheme() +{ + return std::make_unique(); +} + }