diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 9be93710ad3..6725ab22e4f 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -134,6 +134,20 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, if (evalSettings.pureEval && !expectedHash) throw Error("in pure evaluation mode, '%s' requires a 'sha256' argument", who); + // try to substitute if we can + if (settings.useSubstitutes && expectedHash) { + auto substitutableStorePath = fetchers::trySubstitute(state.store, + unpack ? FileIngestionMethod::Recursive : FileIngestionMethod::Flat, *expectedHash, name); + if (substitutableStorePath) { + auto substitutablePath = state.store->toRealPath(*substitutableStorePath); + if (state.allowedPaths) + state.allowedPaths->insert(substitutablePath); + + mkString(v, substitutablePath, PathSet({substitutablePath})); + return; + } + } + auto storePath = unpack ? fetchers::downloadTarball(state.store, *url, name, (bool) expectedHash).storePath diff --git a/src/libfetchers/fetchers.cc b/src/libfetchers/fetchers.cc index 9174c3de467..ec0510652f4 100644 --- a/src/libfetchers/fetchers.cc +++ b/src/libfetchers/fetchers.cc @@ -72,4 +72,22 @@ std::pair> Input::fetchTree(ref store) return {std::move(tree), input}; } +std::optional trySubstitute(ref store, FileIngestionMethod ingestionMethod, + Hash hash, std::string_view name) +{ + auto substitutablePath = store->makeFixedOutputPath(ingestionMethod, hash, name); + + try { + store->ensurePath(substitutablePath); + + debug("using substituted path '%s'", store->printStorePath(substitutablePath)); + + return substitutablePath; + } catch (Error & e) { + debug("substitution of path '%s' failed: %s", store->printStorePath(substitutablePath), e.what()); + } + + return std::nullopt; +} + } diff --git a/src/libfetchers/fetchers.hh b/src/libfetchers/fetchers.hh index 59a58ae6781..2eeaed2f287 100644 --- a/src/libfetchers/fetchers.hh +++ b/src/libfetchers/fetchers.hh @@ -100,4 +100,7 @@ Tree downloadTarball( const std::string & name, bool immutable); +std::optional trySubstitute(ref store, FileIngestionMethod ingestionMethod, + Hash hash, std::string_view name); + }