diff --git a/src/libcmd/installables.cc b/src/libcmd/installables.cc index 4c7d134ec91e..398aca5dcba2 100644 --- a/src/libcmd/installables.cc +++ b/src/libcmd/installables.cc @@ -721,7 +721,14 @@ StorePathSet Installable::toDerivations( : throw Error("argument '%s' did not evaluate to a derivation", i->what())); }, [&](const DerivedPath::Built & bfd) { - drvPaths.insert(resolveDerivedPath(*store, *bfd.drvPath)); + drvPaths.insert(std::visit(overloaded { + [&](const SingleDerivedPath::Opaque o) -> StorePath { + return o.path; + }, + [&](const SingleDerivedPath::Built b) -> StorePath { + throw Error("argument '%s' did not evaluate to output of dynamic derivation '%s' which is not yet built.", i->what(), b.to_string(*store)); + }, + }, tryResolveDerivedPath(*store, *bfd.drvPath).raw())); }, }, b.path.raw()); diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 9c09b490ff66..64e8375f705c 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -384,6 +384,44 @@ OutputPathMap resolveDerivedPath(Store & store, const DerivedPath::Built & bfd, } +SingleDerivedPath tryResolveDerivedPath(Store & store, const SingleDerivedPath & req, Store * evalStore_) +{ + auto & evalStore = evalStore_ ? *evalStore_ : store; + + return std::visit(overloaded { + [&](const SingleDerivedPath::Opaque &) -> SingleDerivedPath { + return req; + }, + [&](const SingleDerivedPath::Built & bfd0) -> SingleDerivedPath { + SingleDerivedPath::Built bfd { + make_ref(tryResolveDerivedPath(store, *bfd0.drvPath, evalStore_)), + bfd0.output, + }; + return std::visit(overloaded { + [&](const SingleDerivedPath::Opaque & bo) -> SingleDerivedPath { + auto & drvPath = bo.path; + auto outputPaths = evalStore.queryPartialDerivationOutputMap(drvPath, evalStore_); + if (outputPaths.count(bfd.output) == 0) + throw Error("derivation '%s' does not have an output named '%s'", + bfd0.drvPath->to_string(store), bfd.output); + auto & optPath = outputPaths.at(bfd.output); + if (optPath) + // Can resolve this step + return DerivedPath::Opaque { *optPath }; + else + // Can't resolve this step + return bfd; + }, + [&](const SingleDerivedPath::Built & _) -> SingleDerivedPath { + // Can't resolve previous step, and thus all future steps. + return bfd; + }, + }, bfd.drvPath->raw()); + }, + }, req.raw()); +} + + StorePath resolveDerivedPath(Store & store, const SingleDerivedPath & req, Store * evalStore_) { auto & evalStore = evalStore_ ? *evalStore_ : store; diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index da1a3eefbbc4..ed65b052919d 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -941,6 +941,13 @@ void copyClosure( void removeTempRoots(); +/** + * Attempt to recursively replace derivation outputs with produced paths as + * much as possible, but where the derivation resolution doesn't exists, leave + * as-is. + */ +SingleDerivedPath tryResolveDerivedPath(Store &, const SingleDerivedPath &, Store * evalStore = nullptr); + /** * Resolve the derived path completely, failing if any derivation output * is unknown.