diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index bc6c3287c79..0eac3d69d88 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -16,6 +16,7 @@ MakeError(ThrownError, AssertionError) MakeError(Abort, EvalError) MakeError(TypeError, EvalError) MakeError(ImportError, EvalError) // error building an imported derivation +MakeError(ImportReadOnlyError, EvalError) // error when trying to import a derivation in read-only mode /* Position objects. */ diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index d3809e6984a..7189465af93 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -45,24 +45,41 @@ static void prim_import(EvalState & state, Value * * args, Value & v) foreach (PathSet::iterator, i, context) { Path ctx = decodeContext(*i).first; + string outputName = decodeContext(*i).second; assert(isStorePath(ctx)); - if (!store->isValidPath(ctx)) - throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") - % path % ctx); - if (isDerivation(ctx)) - try { - /* For performance, prefetch all substitute info. */ - PathSet willBuild, willSubstitute, unknown; - unsigned long long downloadSize, narSize; - queryMissing(*store, singleton(ctx), - willBuild, willSubstitute, unknown, downloadSize, narSize); + if (!store->isValidPath(ctx)) { + if (outputName.empty()) + throw EvalError(format("cannot import `%1%', since path `%2%' is not valid") + % path % ctx); + else + throw ImportReadOnlyError(format("cannot import `%1%', since path `%2%' cannot be written to the store in read-only mode") + % path % ctx); + } + if (isDerivation(ctx)) { + Derivation drv = derivationFromPath(*store, ctx); + + if (outputName.empty() || + !store->isValidPath(drv.outputs[outputName].path)) { + if (settings.readOnlyMode) + foreach (DerivationOutputs::iterator, j, drv.outputs) + if (!store->isValidPath(j->second.path)) + throw ImportReadOnlyError(format("cannot import `%1%', since derivation `%2%' cannot be realised in read-only mode") + % path % ctx); + try { + /* For performance, prefetch all substitute info. */ + PathSet willBuild, willSubstitute, unknown; + unsigned long long downloadSize, narSize; + queryMissing(*store, singleton(ctx), + willBuild, willSubstitute, unknown, downloadSize, narSize); - /* !!! If using a substitute, we only need to fetch - the selected output of this derivation. */ - store->buildPaths(singleton(ctx)); - } catch (Error & e) { - throw ImportError(e.msg()); + /* !!! If using a substitute, we only need to fetch + the selected output of this derivation. */ + store->buildPaths(singleton(ctx)); + } catch (Error & e) { + throw ImportError(e.msg()); + } } + } } if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) {