From c10c61449f954702ae6d8092120321744acd82ff Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Thu, 4 Feb 2016 14:28:26 +0100 Subject: [PATCH] Eliminate the "store" global variable Also, move a few free-standing functions into StoreAPI and Derivation. Also, introduce a non-nullable smart pointer, ref, which is just a wrapper around std::shared_ptr ensuring that the pointer is never null. (For reference-counted values, this is better than passing a "T&", because the latter doesn't maintain the refcount. Usually, the caller will have a shared_ptr keeping the value alive, but that's not always the case, e.g., when passing a reference to a std::thread via std::bind.) --- perl/lib/Nix/Store.xs | 59 ++++----- src/libexpr/common-opts.cc | 2 +- src/libexpr/common-opts.hh | 2 + src/libexpr/eval.cc | 3 +- src/libexpr/eval.hh | 10 +- src/libexpr/parser.y | 2 +- src/libexpr/primops.cc | 61 +++++---- src/libmain/shared.cc | 9 +- src/libmain/shared.hh | 8 +- src/libstore/build.cc | 85 ++++--------- src/libstore/derivations.cc | 81 +++++++++--- src/libstore/derivations.hh | 36 ++++-- src/libstore/download.cc | 2 +- src/libstore/download.hh | 5 +- src/libstore/gc.cc | 49 ++++---- src/libstore/local-store.cc | 4 +- src/libstore/local-store.hh | 4 + src/libstore/misc.cc | 116 ++++++++---------- src/libstore/misc.hh | 40 ------ src/libstore/profiles.cc | 4 +- src/libstore/profiles.hh | 4 +- src/libstore/store-api.cc | 13 +- src/libstore/store-api.hh | 54 +++++--- src/libutil/types.hh | 67 ++++++++++ src/libutil/util.hh | 10 ++ .../nix-collect-garbage.cc | 2 +- src/nix-daemon/nix-daemon.cc | 91 +++++++------- src/nix-env/nix-env.cc | 42 +++---- src/nix-env/user-env.cc | 12 +- src/nix-instantiate/nix-instantiate.cc | 13 +- src/nix-prefetch-url/nix-prefetch-url.cc | 4 +- src/nix-store/dotgraph.cc | 4 +- src/nix-store/dotgraph.hh | 4 +- src/nix-store/nix-store.cc | 59 ++++----- src/nix-store/xmlgraph.cc | 4 +- src/nix-store/xmlgraph.hh | 4 +- 36 files changed, 511 insertions(+), 458 deletions(-) delete mode 100644 src/libstore/misc.hh diff --git a/perl/lib/Nix/Store.xs b/perl/lib/Nix/Store.xs index 8d79399d4..76d3cc36a 100644 --- a/perl/lib/Nix/Store.xs +++ b/perl/lib/Nix/Store.xs @@ -6,10 +6,10 @@ #undef do_open #undef do_close -#include -#include -#include -#include +#include "derivations.hh" +#include "globals.hh" +#include "store-api.hh" +#include "util.hh" #if HAVE_SODIUM #include @@ -19,19 +19,21 @@ using namespace nix; -void doInit() +static ref store() { - if (!store) { + static std::shared_ptr _store; + if (!_store) { try { settings.processEnvironment(); settings.loadConfFile(); settings.update(); settings.lockCPU = false; - store = openStore(); + _store = openStore(); } catch (Error & e) { croak("%s", e.what()); } } + return ref(_store); } @@ -45,7 +47,7 @@ PROTOTYPES: ENABLE void init() CODE: - doInit(); + store(); void setVerbosity(int level) @@ -56,8 +58,7 @@ void setVerbosity(int level) int isValidPath(char * path) CODE: try { - doInit(); - RETVAL = store->isValidPath(path); + RETVAL = store()->isValidPath(path); } catch (Error & e) { croak("%s", e.what()); } @@ -68,9 +69,8 @@ int isValidPath(char * path) SV * queryReferences(char * path) PPCODE: try { - doInit(); PathSet paths; - store->queryReferences(path, paths); + store()->queryReferences(path, paths); for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); } catch (Error & e) { @@ -81,8 +81,7 @@ SV * queryReferences(char * path) SV * queryPathHash(char * path) PPCODE: try { - doInit(); - Hash hash = store->queryPathHash(path); + Hash hash = store()->queryPathHash(path); string s = "sha256:" + printHash32(hash); XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0))); } catch (Error & e) { @@ -93,8 +92,7 @@ SV * queryPathHash(char * path) SV * queryDeriver(char * path) PPCODE: try { - doInit(); - Path deriver = store->queryDeriver(path); + Path deriver = store()->queryDeriver(path); if (deriver == "") XSRETURN_UNDEF; XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0))); } catch (Error & e) { @@ -105,8 +103,7 @@ SV * queryDeriver(char * path) SV * queryPathInfo(char * path, int base32) PPCODE: try { - doInit(); - ValidPathInfo info = store->queryPathInfo(path); + ValidPathInfo info = store()->queryPathInfo(path); if (info.deriver == "") XPUSHs(&PL_sv_undef); else @@ -127,8 +124,7 @@ SV * queryPathInfo(char * path, int base32) SV * queryPathFromHashPart(char * hashPart) PPCODE: try { - doInit(); - Path path = store->queryPathFromHashPart(hashPart); + Path path = store()->queryPathFromHashPart(hashPart); XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); } catch (Error & e) { croak("%s", e.what()); @@ -138,10 +134,9 @@ SV * queryPathFromHashPart(char * hashPart) SV * computeFSClosure(int flipDirection, int includeOutputs, ...) PPCODE: try { - doInit(); PathSet paths; for (int n = 2; n < items; ++n) - computeFSClosure(*store, SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs); + store()->computeFSClosure(SvPV_nolen(ST(n)), paths, flipDirection, includeOutputs); for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i) XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); } catch (Error & e) { @@ -152,10 +147,9 @@ SV * computeFSClosure(int flipDirection, int includeOutputs, ...) SV * topoSortPaths(...) PPCODE: try { - doInit(); PathSet paths; for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n))); - Paths sorted = topoSortPaths(*store, paths); + Paths sorted = store()->topoSortPaths(paths); for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i) XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0))); } catch (Error & e) { @@ -166,7 +160,6 @@ SV * topoSortPaths(...) SV * followLinksToStorePath(char * path) CODE: try { - doInit(); RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0); } catch (Error & e) { croak("%s", e.what()); @@ -178,11 +171,10 @@ SV * followLinksToStorePath(char * path) void exportPaths(int fd, int sign, ...) PPCODE: try { - doInit(); Paths paths; for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n))); FdSink sink(fd); - exportPaths(*store, paths, sign, sink); + store()->exportPaths(paths, sign, sink); } catch (Error & e) { croak("%s", e.what()); } @@ -191,9 +183,8 @@ void exportPaths(int fd, int sign, ...) void importPaths(int fd) PPCODE: try { - doInit(); FdSource source(fd); - store->importPaths(false, source); + store()->importPaths(false, source); } catch (Error & e) { croak("%s", e.what()); } @@ -292,8 +283,7 @@ int checkSignature(SV * publicKey_, SV * sig_, char * msg) SV * addToStore(char * srcPath, int recursive, char * algo) PPCODE: try { - doInit(); - Path path = store->addToStore(baseNameOf(srcPath), srcPath, recursive, parseHashType(algo)); + Path path = store()->addToStore(baseNameOf(srcPath), srcPath, recursive, parseHashType(algo)); XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0))); } catch (Error & e) { croak("%s", e.what()); @@ -303,7 +293,6 @@ SV * addToStore(char * srcPath, int recursive, char * algo) SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name) PPCODE: try { - doInit(); HashType ht = parseHashType(algo); Path path = makeFixedOutputPath(recursive, ht, parseHash16or32(ht, hash), name); @@ -318,8 +307,7 @@ SV * derivationFromPath(char * drvPath) HV *hash; CODE: try { - doInit(); - Derivation drv = derivationFromPath(*store, drvPath); + Derivation drv = store()->derivationFromPath(drvPath); hash = newHV(); HV * outputs = newHV(); @@ -361,8 +349,7 @@ SV * derivationFromPath(char * drvPath) void addTempRoot(char * storePath) PPCODE: try { - doInit(); - store->addTempRoot(storePath); + store()->addTempRoot(storePath); } catch (Error & e) { croak("%s", e.what()); } diff --git a/src/libexpr/common-opts.cc b/src/libexpr/common-opts.cc index 13760490d..68ab4b5cd 100644 --- a/src/libexpr/common-opts.cc +++ b/src/libexpr/common-opts.cc @@ -55,7 +55,7 @@ bool parseSearchPathArg(Strings::iterator & i, Path lookupFileArg(EvalState & state, string s) { if (isUri(s)) - return downloadFileCached(s, true); + return downloadFileCached(state.store, s, true); else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') { Path p = s.substr(1, s.size() - 2); return state.findFile(p); diff --git a/src/libexpr/common-opts.hh b/src/libexpr/common-opts.hh index be0f40202..0500b0a83 100644 --- a/src/libexpr/common-opts.hh +++ b/src/libexpr/common-opts.hh @@ -4,6 +4,8 @@ namespace nix { +class StoreAPI; + /* Some common option parsing between nix-env and nix-instantiate. */ bool parseAutoArgs(Strings::iterator & i, const Strings::iterator & argsEnd, std::map & res); diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 3b21c078f..702b12ee4 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -244,7 +244,7 @@ static Strings parseNixPath(const string & in) } -EvalState::EvalState(const Strings & _searchPath) +EvalState::EvalState(const Strings & _searchPath, ref store) : sWith(symbols.create("")) , sOutPath(symbols.create("outPath")) , sDrvPath(symbols.create("drvPath")) @@ -262,6 +262,7 @@ EvalState::EvalState(const Strings & _searchPath) , sColumn(symbols.create("column")) , sFunctor(symbols.create("__functor")) , sToString(symbols.create("__toString")) + , store(store) , baseEnv(allocEnv(128)) , staticBaseEnv(false, 0) { diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 2d7b7bcdc..a4286ce1f 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -16,6 +16,7 @@ namespace nix { +class StoreAPI; class EvalState; @@ -82,6 +83,8 @@ public: Value vEmptySet; + const ref store; + private: SrcToStore srcToStore; @@ -97,7 +100,7 @@ private: public: - EvalState(const Strings & _searchPath); + EvalState(const Strings & _searchPath, ref store); ~EvalState(); void addToSearchPath(const string & s, bool warn = false); @@ -240,6 +243,8 @@ public: /* Print statistics. */ void printStats(); + void realiseContext(const PathSet & context); + private: unsigned long nrEnvs = 0; @@ -290,7 +295,4 @@ struct InvalidPathError : EvalError #endif }; -/* Realise all paths in `context' */ -void realiseContext(const PathSet & context); - } diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y index d34882f36..3e6c6d917 100644 --- a/src/libexpr/parser.y +++ b/src/libexpr/parser.y @@ -603,7 +603,7 @@ void EvalState::addToSearchPath(const string & s, bool warn) } if (isUri(path)) - path = downloadFileCached(path, true); + path = downloadFileCached(store, path, true); path = absPath(path); if (pathExists(path)) { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 87ee4f68a..2371ae174 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1,15 +1,15 @@ -#include "eval.hh" -#include "misc.hh" -#include "globals.hh" -#include "store-api.hh" -#include "util.hh" #include "archive.hh" -#include "value-to-xml.hh" -#include "value-to-json.hh" +#include "derivations.hh" +#include "download.hh" +#include "eval-inline.hh" +#include "eval.hh" +#include "globals.hh" #include "json-to-value.hh" #include "names.hh" -#include "eval-inline.hh" -#include "download.hh" +#include "store-api.hh" +#include "util.hh" +#include "value-to-json.hh" +#include "value-to-xml.hh" #include #include @@ -43,7 +43,7 @@ std::pair decodeContext(const string & s) InvalidPathError::InvalidPathError(const Path & path) : EvalError(format("path ‘%1%’ is not valid") % path), path(path) {} -void realiseContext(const PathSet & context) +void EvalState::realiseContext(const PathSet & context) { PathSet drvs; for (auto & i : context) { @@ -52,16 +52,14 @@ void realiseContext(const PathSet & context) assert(isStorePath(ctx)); if (!store->isValidPath(ctx)) throw InvalidPathError(ctx); - if (!decoded.second.empty() && isDerivation(ctx)) + if (!decoded.second.empty() && nix::isDerivation(ctx)) drvs.insert(decoded.first + "!" + decoded.second); } if (!drvs.empty()) { /* For performance, prefetch all substitute info. */ PathSet willBuild, willSubstitute, unknown; unsigned long long downloadSize, narSize; - queryMissing(*store, drvs, - willBuild, willSubstitute, unknown, downloadSize, narSize); - + store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize); store->buildPaths(drvs); } } @@ -75,7 +73,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[1], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -83,7 +81,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args path = state.checkSourcePath(path); - if (isStorePath(path) && store->isValidPath(path) && isDerivation(path)) { + if (isStorePath(path) && state.store->isValidPath(path) && isDerivation(path)) { Derivation drv = readDerivation(path); Value & w = *state.allocValue(); state.mkAttrs(w, 3 + drv.outputs.size()); @@ -145,7 +143,7 @@ static void prim_importNative(EvalState & state, const Pos & pos, Value * * args Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -560,11 +558,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * runs. */ if (path.at(0) == '=') { /* !!! This doesn't work if readOnlyMode is set. */ - PathSet refs; computeFSClosure(*store, string(path, 1), refs); + PathSet refs; + state.store->computeFSClosure(string(path, 1), refs); for (auto & j : refs) { drv.inputSrcs.insert(j); if (isDerivation(j)) - drv.inputDrvs[j] = store->queryDerivationOutputNames(j); + drv.inputDrvs[j] = state.store->queryDerivationOutputNames(j); } } @@ -581,7 +580,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Handle derivation contexts returned by ‘builtins.storePath’. */ else if (isDerivation(path)) - drv.inputDrvs[path] = store->queryDerivationOutputNames(path); + drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path); /* Otherwise it's a source file. */ else @@ -630,7 +629,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Use the masked derivation expression to compute the output path. */ - Hash h = hashDerivationModulo(*store, drv); + Hash h = hashDerivationModulo(*state.store, drv); for (auto & i : drv.outputs) if (i.second.path == "") { @@ -641,7 +640,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * } /* Write the resulting term into the Nix store directory. */ - Path drvPath = writeDerivation(*store, drv, drvName, state.repair); + Path drvPath = writeDerivation(state.store, drv, drvName, state.repair); printMsg(lvlChatty, format("instantiated ‘%1%’ -> ‘%2%’") % drvName % drvPath); @@ -649,7 +648,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * /* Optimisation, but required in read-only mode! because in that case we don't actually write store derivations, so we can't read them later. */ - drvHashes[drvPath] = hashDerivationModulo(*store, drv); + drvHashes[drvPath] = hashDerivationModulo(*state.store, drv); state.mkAttrs(v, 1 + drv.outputs.size()); mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton("=" + drvPath)); @@ -695,7 +694,7 @@ static void prim_storePath(EvalState & state, const Pos & pos, Value * * args, V throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos); Path path2 = toStorePath(path); if (!settings.readOnlyMode) - store->ensurePath(path2); + state.store->ensurePath(path2); context.insert(path2); mkString(v, path, context); } @@ -745,7 +744,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va PathSet context; Path path = state.coerceToPath(pos, *args[0], context); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -786,7 +785,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va string path = state.forceStringNoCtx(*args[1], pos); try { - realiseContext(context); + state.realiseContext(context); } catch (InvalidPathError & e) { throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -801,7 +800,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val PathSet ctx; Path path = state.coerceToPath(pos, *args[0], ctx); try { - realiseContext(ctx); + state.realiseContext(ctx); } catch (InvalidPathError & e) { throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%") % path % e.path % pos); @@ -879,13 +878,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu if (path.at(0) != '~') throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos); path = string(path, 1); - } + } refs.insert(path); } Path storePath = settings.readOnlyMode ? computeStorePathForText(name, contents, refs) - : store->addTextToStore(name, contents, refs, state.repair); + : state.store->addTextToStore(name, contents, refs, state.repair); /* Note: we don't need to add `context' to the context of the result, since `storePath' itself has references to the paths @@ -951,7 +950,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args Path dstPath = settings.readOnlyMode ? computeStorePathForPath(path, true, htSHA256, filter).first - : store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); + : state.store->addToStore(baseNameOf(path), path, true, htSHA256, filter, state.repair); mkString(v, dstPath, singleton(dstPath)); } @@ -1678,7 +1677,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, } else url = state.forceStringNoCtx(*args[0], pos); - Path res = downloadFileCached(url, unpack); + Path res = downloadFileCached(state.store, url, unpack); mkString(v, res, PathSet({res})); } diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index 5106739c8..656d04cab 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -4,7 +4,6 @@ #include "globals.hh" #include "store-api.hh" #include "util.hh" -#include "misc.hh" #include #include @@ -47,22 +46,22 @@ void printGCWarning() } -void printMissing(StoreAPI & store, const PathSet & paths) +void printMissing(ref store, const PathSet & paths) { unsigned long long downloadSize, narSize; PathSet willBuild, willSubstitute, unknown; - queryMissing(store, paths, willBuild, willSubstitute, unknown, downloadSize, narSize); + store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize); printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize); } -void printMissing(StoreAPI & store, const PathSet & willBuild, +void printMissing(ref store, const PathSet & willBuild, const PathSet & willSubstitute, const PathSet & unknown, unsigned long long downloadSize, unsigned long long narSize) { if (!willBuild.empty()) { printMsg(lvlInfo, format("these derivations will be built:")); - Paths sorted = topoSortPaths(store, willBuild); + Paths sorted = store->topoSortPaths(willBuild); reverse(sorted.begin(), sorted.end()); for (auto & i : sorted) printMsg(lvlInfo, format(" %1%") % i); diff --git a/src/libmain/shared.hh b/src/libmain/shared.hh index 8e756bd5e..6f826d8f6 100644 --- a/src/libmain/shared.hh +++ b/src/libmain/shared.hh @@ -19,8 +19,6 @@ public: Exit(int status) : status(status) { } }; -class StoreAPI; - int handleExceptions(const string & programName, std::function fun); void initNix(); @@ -33,9 +31,11 @@ void printVersion(const string & programName); /* Ugh. No better place to put this. */ void printGCWarning(); -void printMissing(StoreAPI & store, const PathSet & paths); +class StoreAPI; -void printMissing(StoreAPI & store, const PathSet & willBuild, +void printMissing(ref store, const PathSet & paths); + +void printMissing(ref store, const PathSet & willBuild, const PathSet & willSubstitute, const PathSet & unknown, unsigned long long downloadSize, unsigned long long narSize); diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 9b9621dc1..180a558dc 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -2,7 +2,6 @@ #include "references.hh" #include "pathlocks.hh" -#include "misc.hh" #include "globals.hh" #include "local-store.hh" #include "util.hh" @@ -906,7 +905,7 @@ DerivationGoal::DerivationGoal(const Path & drvPath, const BasicDerivation & drv { this->drv = std::unique_ptr(new BasicDerivation(drv)); state = &DerivationGoal::haveDerivation; - name = (format("building of %1%") % showPaths(outputPaths(drv))).str(); + name = (format("building of %1%") % showPaths(drv.outputPaths())).str(); trace("created"); /* Prevent the .chroot directory from being @@ -1018,7 +1017,7 @@ void DerivationGoal::loadDerivation() assert(worker.store.isValidPath(drvPath)); /* Get the derivation. */ - drv = std::unique_ptr(new Derivation(derivationFromPath(worker.store, drvPath))); + drv = std::unique_ptr(new Derivation(worker.store.derivationFromPath(drvPath))); haveDerivation(); } @@ -1057,7 +1056,7 @@ void DerivationGoal::haveDerivation() /* We are first going to try to create the invalid output paths through substitutes. If that doesn't work, we'll build them. */ - if (settings.useSubstitutes && substitutesAllowed(*drv)) + if (settings.useSubstitutes && drv->substitutesAllowed()) for (auto & i : invalidOutputs) addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair)); @@ -1138,7 +1137,7 @@ void DerivationGoal::repairClosure() PathSet outputClosure; for (auto & i : drv->outputs) { if (!wantOutput(i.first, wantedOutputs)) continue; - computeFSClosure(worker.store, i.second.path, outputClosure); + worker.store.computeFSClosure(i.second.path, outputClosure); } /* Filter out our own outputs (which we have already checked). */ @@ -1149,11 +1148,11 @@ void DerivationGoal::repairClosure() derivation is responsible for which path in the output closure. */ PathSet inputClosure; - if (useDerivation) computeFSClosure(worker.store, drvPath, inputClosure); + if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure); std::map outputsToDrv; for (auto & i : inputClosure) if (isDerivation(i)) { - Derivation drv = derivationFromPath(worker.store, i); + Derivation drv = worker.store.derivationFromPath(i); for (auto & j : drv.outputs) outputsToDrv[j.second.path] = i; } @@ -1225,10 +1224,10 @@ void DerivationGoal::inputsRealised() `i' as input paths. Only add the closures of output paths that are specified as inputs. */ assert(worker.store.isValidPath(i.first)); - Derivation inDrv = derivationFromPath(worker.store, i.first); + Derivation inDrv = worker.store.derivationFromPath(i.first); for (auto & j : i.second) if (inDrv.outputs.find(j) != inDrv.outputs.end()) - computeFSClosure(worker.store, inDrv.outputs[j].path, inputPaths); + worker.store.computeFSClosure(inDrv.outputs[j].path, inputPaths); else throw Error( format("derivation ‘%1%’ requires non-existent output ‘%2%’ from input derivation ‘%3%’") @@ -1237,7 +1236,7 @@ void DerivationGoal::inputsRealised() /* Second, the input sources. */ for (auto & i : drv->inputSrcs) - computeFSClosure(worker.store, i, inputPaths); + worker.store.computeFSClosure(i, inputPaths); debug(format("added input paths %1%") % showPaths(inputPaths)); @@ -1260,46 +1259,6 @@ void DerivationGoal::inputsRealised() } -static bool isBuiltin(const BasicDerivation & drv) -{ - return string(drv.builder, 0, 8) == "builtin:"; -} - - -static bool canBuildLocally(const BasicDerivation & drv) -{ - return drv.platform == settings.thisSystem - || isBuiltin(drv) -#if __linux__ - || (drv.platform == "i686-linux" && settings.thisSystem == "x86_64-linux") - || (drv.platform == "armv6l-linux" && settings.thisSystem == "armv7l-linux") -#elif __FreeBSD__ - || (drv.platform == "i686-linux" && settings.thisSystem == "x86_64-freebsd") - || (drv.platform == "i686-linux" && settings.thisSystem == "i686-freebsd") -#endif - ; -} - - -static string get(const StringPairs & map, const string & key, const string & def = "") -{ - StringPairs::const_iterator i = map.find(key); - return i == map.end() ? def : i->second; -} - - -bool willBuildLocally(const BasicDerivation & drv) -{ - return get(drv.env, "preferLocalBuild") == "1" && canBuildLocally(drv); -} - - -bool substitutesAllowed(const BasicDerivation & drv) -{ - return get(drv.env, "allowSubstitutes", "1") == "1"; -} - - void DerivationGoal::tryToBuild() { trace("trying to build"); @@ -1322,7 +1281,7 @@ void DerivationGoal::tryToBuild() can't acquire the lock, then continue; hopefully some other goal can start a build, and if not, the main loop will sleep a few seconds and then retry this goal. */ - if (!outputLocks.lockPaths(outputPaths(*drv), "", false)) { + if (!outputLocks.lockPaths(drv->outputPaths(), "", false)) { worker.waitForAWhile(shared_from_this()); return; } @@ -1342,7 +1301,7 @@ void DerivationGoal::tryToBuild() return; } - missingPaths = outputPaths(*drv); + missingPaths = drv->outputPaths(); if (buildMode != bmCheck) for (auto & i : validPaths) missingPaths.erase(i); @@ -1365,7 +1324,7 @@ void DerivationGoal::tryToBuild() /* Don't do a remote build if the derivation has the attribute `preferLocalBuild' set. Also, check and repair modes are only supported for local builds. */ - bool buildLocally = buildMode != bmNormal || willBuildLocally(*drv); + bool buildLocally = buildMode != bmNormal || drv->willBuildLocally(); /* Is the build hook willing to accept this job? */ if (!buildLocally) { @@ -1661,7 +1620,7 @@ HookReply DerivationGoal::tryBuildHook() list it since the remote system *probably* already has it.) */ PathSet allInputs; allInputs.insert(inputPaths.begin(), inputPaths.end()); - computeFSClosure(worker.store, drvPath, allInputs); + worker.store.computeFSClosure(drvPath, allInputs); string s; for (auto & i : allInputs) { s += i; s += ' '; } @@ -1716,7 +1675,7 @@ void DerivationGoal::startBuilder() startNest(nest, lvlInfo, f % showPaths(missingPaths) % curRound % nrRounds); /* Right platform? */ - if (!canBuildLocally(*drv)) { + if (!drv->canBuildLocally()) { if (settings.printBuildTrace) printMsg(lvlError, format("@ unsupported-platform %1% %2%") % drvPath % drv->platform); throw Error( @@ -1873,14 +1832,14 @@ void DerivationGoal::startBuilder() like passing all build-time dependencies of some path to a derivation that builds a NixOS DVD image. */ PathSet paths, paths2; - computeFSClosure(worker.store, storePath, paths); + worker.store.computeFSClosure(storePath, paths); paths2 = paths; for (auto & j : paths2) { if (isDerivation(j)) { - Derivation drv = derivationFromPath(worker.store, j); + Derivation drv = worker.store.derivationFromPath(j); for (auto & k : drv.outputs) - computeFSClosure(worker.store, k.second.path, paths); + worker.store.computeFSClosure(k.second.path, paths); } } @@ -1944,7 +1903,7 @@ void DerivationGoal::startBuilder() PathSet closure; for (auto & i : dirsInChroot) if (isInStore(i.second)) - computeFSClosure(worker.store, toStorePath(i.second), closure); + worker.store.computeFSClosure(toStorePath(i.second), closure); for (auto & i : closure) dirsInChroot[i] = i; @@ -2212,7 +2171,7 @@ void DerivationGoal::startBuilder() #endif { ProcessOptions options; - options.allowVfork = !buildUser.enabled() && !isBuiltin(*drv); + options.allowVfork = !buildUser.enabled() && !drv->isBuiltin(); pid = startProcess([&]() { runChild(); }, options); @@ -2466,7 +2425,7 @@ void DerivationGoal::runChild() const char *builder = "invalid"; string sandboxProfile; - if (isBuiltin(*drv)) { + if (drv->isBuiltin()) { ; #if __APPLE__ } else if (useChroot) { @@ -2583,7 +2542,7 @@ void DerivationGoal::runChild() writeFull(STDERR_FILENO, string("\1\n")); /* Execute the program. This should not return. */ - if (isBuiltin(*drv)) { + if (drv->isBuiltin()) { try { logType = ltFlat; if (drv->builder == "builtin:fetchurl") @@ -2813,7 +2772,7 @@ void DerivationGoal::registerOutputs() for (auto & i : references) /* Don't call computeFSClosure on ourselves. */ if (actualPath != i) - computeFSClosure(worker.store, i, used); + worker.store.computeFSClosure(i, used); } else used = references; diff --git a/src/libstore/derivations.cc b/src/libstore/derivations.cc index 7959d5bfc..da1747da0 100644 --- a/src/libstore/derivations.cc +++ b/src/libstore/derivations.cc @@ -2,7 +2,6 @@ #include "store-api.hh" #include "globals.hh" #include "util.hh" -#include "misc.hh" #include "worker-protocol.hh" @@ -27,7 +26,49 @@ void DerivationOutput::parseHashInfo(bool & recursive, HashType & hashType, Hash } -Path writeDerivation(StoreAPI & store, +Path BasicDerivation::findOutput(const string & id) const +{ + auto i = outputs.find(id); + if (i == outputs.end()) + throw Error(format("derivation has no output ‘%1%’") % id); + return i->second.path; +} + + +bool BasicDerivation::willBuildLocally() const +{ + return get(env, "preferLocalBuild") == "1" && canBuildLocally(); +} + + +bool BasicDerivation::substitutesAllowed() const +{ + return get(env, "allowSubstitutes", "1") == "1"; +} + + +bool BasicDerivation::isBuiltin() const +{ + return string(builder, 0, 8) == "builtin:"; +} + + +bool BasicDerivation::canBuildLocally() const +{ + return platform == settings.thisSystem + || isBuiltin() +#if __linux__ + || (platform == "i686-linux" && settings.thisSystem == "x86_64-linux") + || (platform == "armv6l-linux" && settings.thisSystem == "armv7l-linux") +#elif __FreeBSD__ + || (platform == "i686-linux" && settings.thisSystem == "x86_64-freebsd") + || (platform == "i686-linux" && settings.thisSystem == "i686-freebsd") +#endif + ; +} + + +Path writeDerivation(ref store, const Derivation & drv, const string & name, bool repair) { PathSet references; @@ -38,10 +79,10 @@ Path writeDerivation(StoreAPI & store, (that can be missing (of course) and should not necessarily be held during a garbage collection). */ string suffix = name + drvExtension; - string contents = unparseDerivation(drv); + string contents = drv.unparse(); return settings.readOnlyMode ? computeStorePathForText(suffix, contents, references) - : store.addTextToStore(suffix, contents, references, repair); + : store->addTextToStore(suffix, contents, references, repair); } @@ -149,14 +190,14 @@ static void printStrings(string & res, ForwardIterator i, ForwardIterator j) } -string unparseDerivation(const Derivation & drv) +string Derivation::unparse() const { string s; s.reserve(65536); s += "Derive(["; bool first = true; - for (auto & i : drv.outputs) { + for (auto & i : outputs) { if (first) first = false; else s += ','; s += '('; printString(s, i.first); s += ','; printString(s, i.second.path); @@ -167,7 +208,7 @@ string unparseDerivation(const Derivation & drv) s += "],["; first = true; - for (auto & i : drv.inputDrvs) { + for (auto & i : inputDrvs) { if (first) first = false; else s += ','; s += '('; printString(s, i.first); s += ','; printStrings(s, i.second.begin(), i.second.end()); @@ -175,15 +216,15 @@ string unparseDerivation(const Derivation & drv) } s += "],"; - printStrings(s, drv.inputSrcs.begin(), drv.inputSrcs.end()); + printStrings(s, inputSrcs.begin(), inputSrcs.end()); - s += ','; printString(s, drv.platform); - s += ','; printString(s, drv.builder); - s += ','; printStrings(s, drv.args.begin(), drv.args.end()); + s += ','; printString(s, platform); + s += ','; printString(s, builder); + s += ','; printStrings(s, args.begin(), args.end()); s += ",["; first = true; - for (auto & i : drv.env) { + for (auto & i : env) { if (first) first = false; else s += ','; s += '('; printString(s, i.first); s += ','; printString(s, i.second); @@ -202,11 +243,11 @@ bool isDerivation(const string & fileName) } -bool isFixedOutputDrv(const Derivation & drv) +bool BasicDerivation::isFixedOutput() const { - return drv.outputs.size() == 1 && - drv.outputs.begin()->first == "out" && - drv.outputs.begin()->second.hash != ""; + return outputs.size() == 1 && + outputs.begin()->first == "out" && + outputs.begin()->second.hash != ""; } @@ -236,7 +277,7 @@ DrvHashes drvHashes; Hash hashDerivationModulo(StoreAPI & store, Derivation drv) { /* Return a fixed hash for fixed-output derivations. */ - if (isFixedOutputDrv(drv)) { + if (drv.isFixedOutput()) { DerivationOutputs::const_iterator i = drv.outputs.begin(); return hashString(htSHA256, "fixed:out:" + i->second.hashAlgo + ":" @@ -259,7 +300,7 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv) } drv.inputDrvs = inputs2; - return hashString(htSHA256, unparseDerivation(drv)); + return hashString(htSHA256, drv.unparse()); } @@ -286,10 +327,10 @@ bool wantOutput(const string & output, const std::set & wanted) } -PathSet outputPaths(const BasicDerivation & drv) +PathSet BasicDerivation::outputPaths() const { PathSet paths; - for (auto & i : drv.outputs) + for (auto & i : outputs) paths.insert(i.second.path); return paths; } diff --git a/src/libstore/derivations.hh b/src/libstore/derivations.hh index f0842045f..4dda10b45 100644 --- a/src/libstore/derivations.hh +++ b/src/libstore/derivations.hh @@ -50,11 +50,33 @@ struct BasicDerivation StringPairs env; virtual ~BasicDerivation() { }; + + /* Return the path corresponding to the output identifier `id' in + the given derivation. */ + Path findOutput(const string & id) const; + + bool willBuildLocally() const; + + bool substitutesAllowed() const; + + bool isBuiltin() const; + + bool canBuildLocally() const; + + /* Return true iff this is a fixed-output derivation. */ + bool isFixedOutput() const; + + /* Return the output paths of a derivation. */ + PathSet outputPaths() const; + }; struct Derivation : BasicDerivation { DerivationInputs inputDrvs; /* inputs that are sub-derivations */ + + /* Print a derivation. */ + std::string unparse() const; }; @@ -62,28 +84,22 @@ class StoreAPI; /* Write a derivation to the Nix store, and return its path. */ -Path writeDerivation(StoreAPI & store, +Path writeDerivation(ref store, const Derivation & drv, const string & name, bool repair = false); /* Read a derivation from a file. */ Derivation readDerivation(const Path & drvPath); -/* Print a derivation. */ -string unparseDerivation(const Derivation & drv); - -/* Check whether a file name ends with the extensions for +/* Check whether a file name ends with the extension for derivations. */ bool isDerivation(const string & fileName); -/* Return true iff this is a fixed-output derivation. */ -bool isFixedOutputDrv(const Derivation & drv); - Hash hashDerivationModulo(StoreAPI & store, Derivation drv); /* Memoisation of hashDerivationModulo(). */ typedef std::map DrvHashes; -extern DrvHashes drvHashes; +extern DrvHashes drvHashes; // FIXME: global, not thread-safe /* Split a string specifying a derivation and a set of outputs (/nix/store/hash-foo!out1,out2,...) into the derivation path and @@ -95,8 +111,6 @@ Path makeDrvPathWithOutputs(const Path & drvPath, const std::set & outpu bool wantOutput(const string & output, const std::set & wanted); -PathSet outputPaths(const BasicDerivation & drv); - struct Source; struct Sink; diff --git a/src/libstore/download.cc b/src/libstore/download.cc index 822e9a8db..5e50c1480 100644 --- a/src/libstore/download.cc +++ b/src/libstore/download.cc @@ -188,7 +188,7 @@ DownloadResult downloadFile(string url, const DownloadOptions & options) } -Path downloadFileCached(const string & url, bool unpack) +Path downloadFileCached(ref store, const string & url, bool unpack) { Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs"; createDirs(cacheDir); diff --git a/src/libstore/download.hh b/src/libstore/download.hh index c1cb25b90..a727936d1 100644 --- a/src/libstore/download.hh +++ b/src/libstore/download.hh @@ -1,6 +1,7 @@ #pragma once #include "types.hh" + #include namespace nix { @@ -18,9 +19,11 @@ struct DownloadResult string data, etag; }; +class StoreAPI; + DownloadResult downloadFile(string url, const DownloadOptions & options); -Path downloadFileCached(const string & url, bool unpack); +Path downloadFileCached(ref store, const string & url, bool unpack); MakeError(DownloadError, Error) diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 998a7516a..9c158c3ee 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -1,5 +1,5 @@ +#include "derivations.hh" #include "globals.hh" -#include "misc.hh" #include "local-store.hh" #include @@ -83,7 +83,7 @@ void LocalStore::addIndirectRoot(const Path & path) } -Path addPermRoot(StoreAPI & store, const Path & _storePath, +Path addPermRoot(ref store, const Path & _storePath, const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir) { Path storePath(canonPath(_storePath)); @@ -101,7 +101,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot)))) throw Error(format("cannot create symlink ‘%1%’; already exists") % gcRoot); makeSymlink(gcRoot, storePath); - store.addIndirectRoot(gcRoot); + store->addIndirectRoot(gcRoot); } else { @@ -127,7 +127,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, check if the root is in a directory in or linked from the gcroots directory. */ if (settings.checkRootReachability) { - Roots roots = store.findRoots(); + Roots roots = store->findRoots(); if (roots.find(gcRoot) == roots.end()) printMsg(lvlError, format( @@ -139,7 +139,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath, /* Grab the global GC root, causing us to block while a GC is in progress. This prevents the set of permanent roots from increasing while a GC is in progress. */ - store.syncWithGC(); + store->syncWithGC(); return gcRoot; } @@ -260,19 +260,16 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds) } -static void foundRoot(StoreAPI & store, - const Path & path, const Path & target, Roots & roots) +void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots) { - Path storePath = toStorePath(target); - if (store.isValidPath(storePath)) - roots[path] = storePath; - else - printMsg(lvlInfo, format("skipping invalid root from ‘%1%’ to ‘%2%’") % path % storePath); -} + auto foundRoot = [&](const Path & path, const Path & target) { + Path storePath = toStorePath(target); + if (isValidPath(storePath)) + roots[path] = storePath; + else + printMsg(lvlInfo, format("skipping invalid root from ‘%1%’ to ‘%2%’") % path % storePath); + }; - -static void findRoots(StoreAPI & store, const Path & path, unsigned char type, Roots & roots) -{ try { if (type == DT_UNKNOWN) @@ -280,13 +277,13 @@ static void findRoots(StoreAPI & store, const Path & path, unsigned char type, R if (type == DT_DIR) { for (auto & i : readDirectory(path)) - findRoots(store, path + "/" + i.name, i.type, roots); + findRoots(path + "/" + i.name, i.type, roots); } else if (type == DT_LNK) { Path target = readLink(path); if (isInStore(target)) - foundRoot(store, path, target, roots); + foundRoot(path, target); /* Handle indirect roots. */ else { @@ -300,14 +297,14 @@ static void findRoots(StoreAPI & store, const Path & path, unsigned char type, R struct stat st2 = lstat(target); if (!S_ISLNK(st2.st_mode)) return; Path target2 = readLink(target); - if (isInStore(target2)) foundRoot(store, target, target2, roots); + if (isInStore(target2)) foundRoot(target, target2); } } } else if (type == DT_REG) { Path storePath = settings.nixStore + "/" + baseNameOf(path); - if (store.isValidPath(storePath)) + if (isValidPath(storePath)) roots[path] = storePath; } @@ -328,16 +325,16 @@ Roots LocalStore::findRoots() Roots roots; /* Process direct roots in {gcroots,manifests,profiles}. */ - nix::findRoots(*this, settings.nixStateDir + "/" + gcRootsDir, DT_UNKNOWN, roots); + findRoots(settings.nixStateDir + "/" + gcRootsDir, DT_UNKNOWN, roots); if (pathExists(settings.nixStateDir + "/manifests")) - nix::findRoots(*this, settings.nixStateDir + "/manifests", DT_UNKNOWN, roots); - nix::findRoots(*this, settings.nixStateDir + "/profiles", DT_UNKNOWN, roots); + findRoots(settings.nixStateDir + "/manifests", DT_UNKNOWN, roots); + findRoots(settings.nixStateDir + "/profiles", DT_UNKNOWN, roots); return roots; } -static void addAdditionalRoots(StoreAPI & store, PathSet & roots) +void LocalStore::findRuntimeRoots(PathSet & roots) { Path rootFinder = getEnv("NIX_ROOT_FINDER", settings.nixLibexecDir + "/nix/find-runtime-roots.pl"); @@ -353,7 +350,7 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots) for (auto & i : paths) if (isInStore(i)) { Path path = toStorePath(i); - if (roots.find(path) == roots.end() && store.isValidPath(path)) { + if (roots.find(path) == roots.end() && isValidPath(path)) { debug(format("got additional root ‘%1%’") % path); roots.insert(path); } @@ -628,7 +625,7 @@ void LocalStore::collectGarbage(const GCOptions & options, GCResults & results) to add running programs to the set of roots (to prevent them from being garbage collected). */ if (!options.ignoreLiveness) - addAdditionalRoots(*this, state.roots); + findRuntimeRoots(state.roots); /* Read the temporary roots. This acquires read locks on all per-process temporary root files. So after this point no paths diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 55bd3e70e..13179459f 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -655,7 +655,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation & assert(isDerivation(drvName)); drvName = string(drvName, 0, drvName.size() - drvExtension.size()); - if (isFixedOutputDrv(drv)) { + if (drv.isFixedOutput()) { DerivationOutputs::const_iterator out = drv.outputs.find("out"); if (out == drv.outputs.end()) throw Error(format("derivation ‘%1%’ does not have an output named ‘out’") % drvPath); @@ -1335,7 +1335,7 @@ void LocalStore::registerValidPaths(const ValidPathInfos & infos) error if a cycle is detected and roll back the transaction. Cycles can only occur when a derivation has multiple outputs. */ - topoSortPaths(*this, paths); + topoSortPaths(paths); txn.commit(); } end_retry_sqlite; diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index 5b27f9072..3ef042b61 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -303,6 +303,10 @@ private: int openGCLock(LockType lockType); + void findRoots(const Path & path, unsigned char type, Roots & roots); + + void findRuntimeRoots(PathSet & roots); + void removeUnusedLinks(const GCState & state); void startSubstituter(const Path & substituter, diff --git a/src/libstore/misc.cc b/src/libstore/misc.cc index 61a976c02..032dfe658 100644 --- a/src/libstore/misc.cc +++ b/src/libstore/misc.cc @@ -1,21 +1,21 @@ -#include "misc.hh" -#include "store-api.hh" -#include "local-store.hh" +#include "derivations.hh" #include "globals.hh" +#include "local-store.hh" +#include "store-api.hh" namespace nix { -Derivation derivationFromPath(StoreAPI & store, const Path & drvPath) +Derivation StoreAPI::derivationFromPath(const Path & drvPath) { assertStorePath(drvPath); - store.ensurePath(drvPath); + ensurePath(drvPath); return readDerivation(drvPath); } -void computeFSClosure(StoreAPI & store, const Path & path, +void StoreAPI::computeFSClosure(const Path & path, PathSet & paths, bool flipDirection, bool includeOutputs, bool includeDerivers) { if (paths.find(path) != paths.end()) return; @@ -24,50 +24,42 @@ void computeFSClosure(StoreAPI & store, const Path & path, PathSet edges; if (flipDirection) { - store.queryReferrers(path, edges); + queryReferrers(path, edges); if (includeOutputs) { - PathSet derivers = store.queryValidDerivers(path); + PathSet derivers = queryValidDerivers(path); for (auto & i : derivers) edges.insert(i); } if (includeDerivers && isDerivation(path)) { - PathSet outputs = store.queryDerivationOutputs(path); + PathSet outputs = queryDerivationOutputs(path); for (auto & i : outputs) - if (store.isValidPath(i) && store.queryDeriver(i) == path) + if (isValidPath(i) && queryDeriver(i) == path) edges.insert(i); } } else { - store.queryReferences(path, edges); + queryReferences(path, edges); if (includeOutputs && isDerivation(path)) { - PathSet outputs = store.queryDerivationOutputs(path); + PathSet outputs = queryDerivationOutputs(path); for (auto & i : outputs) - if (store.isValidPath(i)) edges.insert(i); + if (isValidPath(i)) edges.insert(i); } if (includeDerivers) { - Path deriver = store.queryDeriver(path); - if (store.isValidPath(deriver)) edges.insert(deriver); + Path deriver = queryDeriver(path); + if (isValidPath(deriver)) edges.insert(deriver); } } for (auto & i : edges) - computeFSClosure(store, i, paths, flipDirection, includeOutputs, includeDerivers); + computeFSClosure(i, paths, flipDirection, includeOutputs, includeDerivers); } -Path findOutput(const Derivation & drv, string id) -{ - for (auto & i : drv.outputs) - if (i.first == id) return i.second.path; - throw Error(format("derivation has no output ‘%1%’") % id); -} - - -void queryMissing(StoreAPI & store, const PathSet & targets, +void StoreAPI::queryMissing(const PathSet & targets, PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, unsigned long long & downloadSize, unsigned long long & narSize) { @@ -105,27 +97,27 @@ void queryMissing(StoreAPI & store, const PathSet & targets, DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i); if (isDerivation(i2.first)) { - if (!store.isValidPath(i2.first)) { + if (!isValidPath(i2.first)) { // FIXME: we could try to substitute p. unknown.insert(i); continue; } - Derivation drv = derivationFromPath(store, i2.first); + Derivation drv = derivationFromPath(i2.first); PathSet invalid; for (auto & j : drv.outputs) if (wantOutput(j.first, i2.second) - && !store.isValidPath(j.second.path)) + && !isValidPath(j.second.path)) invalid.insert(j.second.path); if (invalid.empty()) continue; todoDrv.insert(i); - if (settings.useSubstitutes && substitutesAllowed(drv)) + if (settings.useSubstitutes && drv.substitutesAllowed()) query.insert(invalid.begin(), invalid.end()); } else { - if (store.isValidPath(i)) continue; + if (isValidPath(i)) continue; query.insert(i); todoNonDrv.insert(i); } @@ -134,20 +126,20 @@ void queryMissing(StoreAPI & store, const PathSet & targets, todo.clear(); SubstitutablePathInfos infos; - store.querySubstitutablePathInfos(query, infos); + querySubstitutablePathInfos(query, infos); for (auto & i : todoDrv) { DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i); // FIXME: cache this - Derivation drv = derivationFromPath(store, i2.first); + Derivation drv = derivationFromPath(i2.first); PathSet outputs; bool mustBuild = false; - if (settings.useSubstitutes && substitutesAllowed(drv)) { + if (settings.useSubstitutes && drv.substitutesAllowed()) { for (auto & j : drv.outputs) { if (!wantOutput(j.first, i2.second)) continue; - if (!store.isValidPath(j.second.path)) { + if (!isValidPath(j.second.path)) { if (infos.find(j.second.path) == infos.end()) mustBuild = true; else @@ -181,38 +173,38 @@ void queryMissing(StoreAPI & store, const PathSet & targets, } -static void dfsVisit(StoreAPI & store, const PathSet & paths, - const Path & path, PathSet & visited, Paths & sorted, - PathSet & parents) -{ - if (parents.find(path) != parents.end()) - throw BuildError(format("cycle detected in the references of ‘%1%’") % path); - - if (visited.find(path) != visited.end()) return; - visited.insert(path); - parents.insert(path); - - PathSet references; - if (store.isValidPath(path)) - store.queryReferences(path, references); - - for (auto & i : references) - /* Don't traverse into paths that don't exist. That can - happen due to substitutes for non-existent paths. */ - if (i != path && paths.find(i) != paths.end()) - dfsVisit(store, paths, i, visited, sorted, parents); - - sorted.push_front(path); - parents.erase(path); -} - - -Paths topoSortPaths(StoreAPI & store, const PathSet & paths) +Paths StoreAPI::topoSortPaths(const PathSet & paths) { Paths sorted; PathSet visited, parents; + + std::function dfsVisit; + + dfsVisit = [&](const Path & path) { + if (parents.find(path) != parents.end()) + throw BuildError(format("cycle detected in the references of ‘%1%’") % path); + + if (visited.find(path) != visited.end()) return; + visited.insert(path); + parents.insert(path); + + PathSet references; + if (isValidPath(path)) + queryReferences(path, references); + + for (auto & i : references) + /* Don't traverse into paths that don't exist. That can + happen due to substitutes for non-existent paths. */ + if (i != path && paths.find(i) != paths.end()) + dfsVisit(i); + + sorted.push_front(path); + parents.erase(path); + }; + for (auto & i : paths) - dfsVisit(store, paths, i, visited, sorted, parents); + dfsVisit(i); + return sorted; } diff --git a/src/libstore/misc.hh b/src/libstore/misc.hh deleted file mode 100644 index 495c52875..000000000 --- a/src/libstore/misc.hh +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include "derivations.hh" - - -namespace nix { - - -/* Read a derivation, after ensuring its existence through - ensurePath(). */ -Derivation derivationFromPath(StoreAPI & store, const Path & drvPath); - -/* Place in `paths' the set of all store paths in the file system - closure of `storePath'; that is, all paths than can be directly or - indirectly reached from it. `paths' is not cleared. If - `flipDirection' is true, the set of paths that can reach - `storePath' is returned; that is, the closures under the - `referrers' relation instead of the `references' relation is - returned. */ -void computeFSClosure(StoreAPI & store, const Path & path, - PathSet & paths, bool flipDirection = false, - bool includeOutputs = false, bool includeDerivers = false); - -/* Return the path corresponding to the output identifier `id' in the - given derivation. */ -Path findOutput(const Derivation & drv, string id); - -/* Given a set of paths that are to be built, return the set of - derivations that will be built, and the set of output paths that - will be substituted. */ -void queryMissing(StoreAPI & store, const PathSet & targets, - PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, - unsigned long long & downloadSize, unsigned long long & narSize); - -bool willBuildLocally(const BasicDerivation & drv); - -bool substitutesAllowed(const BasicDerivation & drv); - - -} diff --git a/src/libstore/profiles.cc b/src/libstore/profiles.cc index da3f7da9d..4903b12f6 100644 --- a/src/libstore/profiles.cc +++ b/src/libstore/profiles.cc @@ -74,7 +74,7 @@ static void makeName(const Path & profile, unsigned int num, } -Path createGeneration(Path profile, Path outPath) +Path createGeneration(ref store, Path profile, Path outPath) { /* The new generation number should be higher than old the previous ones. */ @@ -108,7 +108,7 @@ Path createGeneration(Path profile, Path outPath) user environment etc. we've just built. */ Path generation; makeName(profile, num + 1, generation); - addPermRoot(*store, outPath, generation, false, true); + addPermRoot(store, outPath, generation, false, true); return generation; } diff --git a/src/libstore/profiles.hh b/src/libstore/profiles.hh index e99bbf398..37d8ec999 100644 --- a/src/libstore/profiles.hh +++ b/src/libstore/profiles.hh @@ -31,7 +31,9 @@ typedef list Generations; profile, sorted by generation number. */ Generations findGenerations(Path profile, int & curGen); -Path createGeneration(Path profile, Path outPath); +class StoreAPI; + +Path createGeneration(ref store, Path profile, Path outPath); void deleteGeneration(const Path & profile, unsigned int gen); diff --git a/src/libstore/store-api.cc b/src/libstore/store-api.cc index f5035d323..98399cc48 100644 --- a/src/libstore/store-api.cc +++ b/src/libstore/store-api.cc @@ -284,12 +284,12 @@ string showPaths(const PathSet & paths) } -void exportPaths(StoreAPI & store, const Paths & paths, +void StoreAPI::exportPaths(const Paths & paths, bool sign, Sink & sink) { for (auto & i : paths) { sink << 1; - store.exportPath(i, sign, sink); + exportPath(i, sign, sink); } sink << 0; } @@ -306,10 +306,7 @@ void exportPaths(StoreAPI & store, const Paths & paths, namespace nix { -std::shared_ptr store; - - -std::shared_ptr openStore(bool reserveSpace) +ref openStore(bool reserveSpace) { enum { mDaemon, mLocal, mAuto } mode; @@ -325,8 +322,8 @@ std::shared_ptr openStore(bool reserveSpace) } return mode == mDaemon - ? (std::shared_ptr) std::make_shared() - : std::make_shared(reserveSpace); + ? make_ref() + : make_ref(reserveSpace); } diff --git a/src/libstore/store-api.hh b/src/libstore/store-api.hh index 9fa137030..ce085ff55 100644 --- a/src/libstore/store-api.hh +++ b/src/libstore/store-api.hh @@ -132,6 +132,7 @@ struct BuildResult struct BasicDerivation; +struct Derivation; class StoreAPI @@ -214,6 +215,10 @@ public: virtual void exportPath(const Path & path, bool sign, Sink & sink) = 0; + /* Export multiple paths in the format expected by ‘nix-store + --import’. */ + void exportPaths(const Paths & paths, bool sign, Sink & sink); + /* Import a sequence of NAR dumps created by exportPaths() into the Nix store. */ virtual Paths importPaths(bool requireSignature, Source & source) = 0; @@ -298,6 +303,35 @@ public: /* Check the integrity of the Nix store. Returns true if errors remain. */ virtual bool verifyStore(bool checkContents, bool repair) = 0; + + /* Utility functions. */ + + /* Read a derivation, after ensuring its existence through + ensurePath(). */ + Derivation derivationFromPath(const Path & drvPath); + + /* Place in `paths' the set of all store paths in the file system + closure of `storePath'; that is, all paths than can be directly + or indirectly reached from it. `paths' is not cleared. If + `flipDirection' is true, the set of paths that can reach + `storePath' is returned; that is, the closures under the + `referrers' relation instead of the `references' relation is + returned. */ + void computeFSClosure(const Path & path, + PathSet & paths, bool flipDirection = false, + bool includeOutputs = false, bool includeDerivers = false); + + /* Given a set of paths that are to be built, return the set of + derivations that will be built, and the set of output paths + that will be substituted. */ + void queryMissing(const PathSet & targets, + PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown, + unsigned long long & downloadSize, unsigned long long & narSize); + + /* Sort a set of paths topologically under the references + relation. If p refers to q, then p preceeds q in this list. */ + Paths topoSortPaths(const PathSet & paths); + }; @@ -373,23 +407,13 @@ void removeTempRoots(); /* Register a permanent GC root. */ -Path addPermRoot(StoreAPI & store, const Path & storePath, +Path addPermRoot(ref store, const Path & storePath, const Path & gcRoot, bool indirect, bool allowOutsideRootsDir = false); -/* Sort a set of paths topologically under the references relation. - If p refers to q, then p preceeds q in this list. */ -Paths topoSortPaths(StoreAPI & store, const PathSet & paths); - - -/* For now, there is a single global store API object, but we'll - purify that in the future. */ -extern std::shared_ptr store; - - /* Factory method: open the Nix database, either through the local or remote implementation. */ -std::shared_ptr openStore(bool reserveSpace = true); +ref openStore(bool reserveSpace = true); /* Display a set of paths in human-readable form (i.e., between quotes @@ -401,12 +425,6 @@ ValidPathInfo decodeValidPathInfo(std::istream & str, bool hashGiven = false); -/* Export multiple paths in the format expected by ‘nix-store - --import’. */ -void exportPaths(StoreAPI & store, const Paths & paths, - bool sign, Sink & sink); - - MakeError(SubstError, Error) MakeError(BuildError, Error) /* denotes a permanent build failure */ diff --git a/src/libutil/types.hh b/src/libutil/types.hh index 160884ee1..23eb52512 100644 --- a/src/libutil/types.hh +++ b/src/libutil/types.hh @@ -5,6 +5,7 @@ #include #include #include +#include #include @@ -96,4 +97,70 @@ typedef enum { } Verbosity; +/* A simple non-nullable reference-counted pointer. Actually a wrapper + around std::shared_ptr that prevents non-null constructions. */ +template +class ref +{ +private: + + std::shared_ptr p; + +public: + + ref(const ref & r) + : p(r.p) + { } + + explicit ref(const std::shared_ptr & p) + : p(p) + { + if (!p) + throw std::invalid_argument("null pointer cast to ref"); + } + + T* operator ->() const + { + return &*p; + } + + T& operator *() const + { + return *p; + } + + operator std::shared_ptr () + { + return p; + } + +private: + + template + friend ref + make_ref(Args&&... args); + + template + friend ref + make_ref(Args&&... args); + +}; + +template +inline ref +make_ref(Args&&... args) +{ + auto p = std::make_shared(std::forward(args)...); + return ref(p); +} + +template +inline ref +make_ref(Args&&... args) +{ + auto p = std::make_shared(std::forward(args)...); + return ref(p); +} + + } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index a889ef2f1..b714cdc64 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -413,4 +413,14 @@ string base64Encode(const string & s); string base64Decode(const string & s); +/* Get a value for the specified key from an associate container, or a + default value if the key doesn't exist. */ +template +string get(const T & map, const string & key, const string & def = "") +{ + auto i = map.find(key); + return i == map.end() ? def : i->second; +} + + } diff --git a/src/nix-collect-garbage/nix-collect-garbage.cc b/src/nix-collect-garbage/nix-collect-garbage.cc index 5a72cb712..b9ccafb75 100644 --- a/src/nix-collect-garbage/nix-collect-garbage.cc +++ b/src/nix-collect-garbage/nix-collect-garbage.cc @@ -82,7 +82,7 @@ int main(int argc, char * * argv) // Run the actual garbage collector. if (!dryRun) { - store = openStore(false); + auto store = openStore(false); options.action = GCOptions::gcDeleteDead; GCResults results; PrintFreed freed(true, results); diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc index c5e11afa1..aa20aa67d 100644 --- a/src/nix-daemon/nix-daemon.cc +++ b/src/nix-daemon/nix-daemon.cc @@ -149,7 +149,7 @@ struct SavingSourceAdapter : Source }; -static void performOp(bool trusted, unsigned int clientVersion, +static void performOp(ref store, bool trusted, unsigned int clientVersion, Source & from, Sink & to, unsigned int op) { switch (op) { @@ -278,8 +278,7 @@ static void performOp(bool trusted, unsigned int clientVersion, startWork(); if (!savedRegular.regular) throw Error("regular file expected"); - Path path = dynamic_cast(store.get()) - ->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo); + Path path = store->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo); stopWork(); to << path; @@ -583,56 +582,56 @@ static void processConnection(bool trusted) #endif /* Open the store. */ - store = std::shared_ptr(new LocalStore(reserveSpace)); + auto store = make_ref(reserveSpace); stopWork(); to.flush(); + /* Process client requests. */ + unsigned int opCount = 0; + + while (true) { + WorkerOp op; + try { + op = (WorkerOp) readInt(from); + } catch (Interrupted & e) { + break; + } catch (EndOfFile & e) { + break; + } + + opCount++; + + try { + performOp(store, trusted, clientVersion, from, to, op); + } catch (Error & e) { + /* If we're not in a state where we can send replies, then + something went wrong processing the input of the + client. This can happen especially if I/O errors occur + during addTextToStore() / importPath(). If that + happens, just send the error message and exit. */ + bool errorAllowed = canSendStderr; + stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? e.status : 0); + if (!errorAllowed) throw; + } catch (std::bad_alloc & e) { + stopWork(false, "Nix daemon out of memory", GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0); + throw; + } + + to.flush(); + + assert(!canSendStderr); + }; + + canSendStderr = false; + _isInterrupted = false; + printMsg(lvlDebug, format("%1% operations") % opCount); + } catch (Error & e) { stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0); to.flush(); return; } - - /* Process client requests. */ - unsigned int opCount = 0; - - while (true) { - WorkerOp op; - try { - op = (WorkerOp) readInt(from); - } catch (Interrupted & e) { - break; - } catch (EndOfFile & e) { - break; - } - - opCount++; - - try { - performOp(trusted, clientVersion, from, to, op); - } catch (Error & e) { - /* If we're not in a state where we can send replies, then - something went wrong processing the input of the - client. This can happen especially if I/O errors occur - during addTextToStore() / importPath(). If that - happens, just send the error message and exit. */ - bool errorAllowed = canSendStderr; - stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? e.status : 0); - if (!errorAllowed) throw; - } catch (std::bad_alloc & e) { - stopWork(false, "Nix daemon out of memory", GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0); - throw; - } - - to.flush(); - - assert(!canSendStderr); - }; - - canSendStderr = false; - _isInterrupted = false; - printMsg(lvlDebug, format("%1% operations") % opCount); } @@ -787,10 +786,6 @@ static void daemonLoop(char * * argv) while (1) { try { - /* Important: the server process *cannot* open the SQLite - database, because it doesn't like forks very much. */ - assert(!store); - /* Accept a connection. */ struct sockaddr_un remoteAddr; socklen_t remoteAddrLen = sizeof(remoteAddr); diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 02a9f25a7..12e19d4af 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1,17 +1,17 @@ -#include "profiles.hh" -#include "names.hh" -#include "globals.hh" -#include "misc.hh" -#include "shared.hh" -#include "eval.hh" -#include "get-drvs.hh" #include "attr-path.hh" #include "common-opts.hh" -#include "xml-writer.hh" +#include "derivations.hh" +#include "eval.hh" +#include "get-drvs.hh" +#include "globals.hh" +#include "names.hh" +#include "profiles.hh" +#include "shared.hh" #include "store-api.hh" #include "user-env.hh" #include "util.hh" #include "value-to-json.hh" +#include "xml-writer.hh" #include #include @@ -223,8 +223,8 @@ static int comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2) static bool isPrebuilt(EvalState & state, DrvInfo & elem) { Path path = elem.queryOutPath(); - if (store->isValidPath(path)) return true; - PathSet ps = store->querySubstitutablePaths(singleton(path)); + if (state.store->isValidPath(path)) return true; + PathSet ps = state.store->querySubstitutablePaths(singleton(path)); return ps.find(path) != ps.end(); } @@ -398,7 +398,7 @@ static void queryInstSources(EvalState & state, if (isDerivation(path)) { elem.setDrvPath(path); - elem.setOutPath(findOutput(derivationFromPath(*store, path), "out")); + elem.setOutPath(state.store->derivationFromPath(path).findOutput("out")); if (name.size() >= drvExtension.size() && string(name, name.size() - drvExtension.size()) == drvExtension) name = string(name, 0, name.size() - drvExtension.size()); @@ -445,7 +445,7 @@ static void printMissing(EvalState & state, DrvInfos & elems) targets.insert(i.queryOutPath()); } - printMissing(*store, targets); + printMissing(state.store, targets); } @@ -711,18 +711,18 @@ static void opSet(Globals & globals, Strings opFlags, Strings opArgs) if (drv.queryDrvPath() != "") { PathSet paths = singleton(drv.queryDrvPath()); - printMissing(*store, paths); + printMissing(globals.state->store, paths); if (globals.dryRun) return; - store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal); + globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal); } else { - printMissing(*store, singleton(drv.queryOutPath())); + printMissing(globals.state->store, singleton(drv.queryOutPath())); if (globals.dryRun) return; - store->ensurePath(drv.queryOutPath()); + globals.state->store->ensurePath(drv.queryOutPath()); } debug(format("switching to new user environment")); - Path generation = createGeneration(globals.profile, drv.queryOutPath()); + Path generation = createGeneration(globals.state->store, globals.profile, drv.queryOutPath()); switchLink(globals.profile, generation); } @@ -973,8 +973,8 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name); i.setFailed(); } - validPaths = store->queryValidPaths(paths); - substitutablePaths = store->querySubstitutablePaths(paths); + validPaths = globals.state->store->queryValidPaths(paths); + substitutablePaths = globals.state->store->querySubstitutablePaths(paths); } @@ -1394,9 +1394,9 @@ int main(int argc, char * * argv) if (!op) throw UsageError("no operation specified"); - store = openStore(); + auto store = openStore(); - globals.state = std::shared_ptr(new EvalState(searchPath)); + globals.state = std::shared_ptr(new EvalState(searchPath, store)); globals.state->repair = repair; if (file != "") diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc index 9a20b9433..4e0e28c11 100644 --- a/src/nix-env/user-env.cc +++ b/src/nix-env/user-env.cc @@ -38,7 +38,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, drvsToBuild.insert(i.queryDrvPath()); debug(format("building user environment dependencies")); - store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal); + state.store->buildPaths(drvsToBuild, state.repair ? bmRepair : bmNormal); /* Construct the whole top level derivation. */ PathSet references; @@ -76,8 +76,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, /* This is only necessary when installing store paths, e.g., `nix-env -i /nix/store/abcd...-foo'. */ - store->addTempRoot(j.second); - store->ensurePath(j.second); + state.store->addTempRoot(j.second); + state.store->ensurePath(j.second); references.insert(j.second); } @@ -100,7 +100,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, /* Also write a copy of the list of user environment elements to the store; we need it for future modifications of the environment. */ - Path manifestFile = store->addTextToStore("env-manifest.nix", + Path manifestFile = state.store->addTextToStore("env-manifest.nix", (format("%1%") % manifest).str(), references); /* Get the environment builder expression. */ @@ -128,7 +128,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, /* Realise the resulting store expression. */ debug("building user environment"); - store->buildPaths(singleton(topLevelDrv), state.repair ? bmRepair : bmNormal); + state.store->buildPaths(singleton(topLevelDrv), state.repair ? bmRepair : bmNormal); /* Switch the current user environment to the output path. */ PathLocks lock; @@ -141,7 +141,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems, } debug(format("switching to new user environment")); - Path generation = createGeneration(profile, topLevelOut); + Path generation = createGeneration(state.store, profile, topLevelOut); switchLink(profile, generation); return true; diff --git a/src/nix-instantiate/nix-instantiate.cc b/src/nix-instantiate/nix-instantiate.cc index 13a145a3b..a20c5ce63 100644 --- a/src/nix-instantiate/nix-instantiate.cc +++ b/src/nix-instantiate/nix-instantiate.cc @@ -9,7 +9,6 @@ #include "util.hh" #include "store-api.hh" #include "common-opts.hh" -#include "misc.hh" #include #include @@ -33,7 +32,7 @@ static bool indirectRoot = false; enum OutputKind { okPlain, okXML, okJSON }; -void processExpr(EvalState & state, const Strings & attrPaths, +void processExpr(ref store, EvalState & state, const Strings & attrPaths, bool parseOnly, bool strict, Bindings & autoArgs, bool evalOnly, OutputKind output, bool location, Expr * e) { @@ -80,7 +79,7 @@ void processExpr(EvalState & state, const Strings & attrPaths, else { Path rootName = gcRoot; if (++rootNr > 1) rootName += "-" + std::to_string(rootNr); - drvPath = addPermRoot(*store, drvPath, rootName, indirectRoot); + drvPath = addPermRoot(store, drvPath, rootName, indirectRoot); } std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : ""); } @@ -158,9 +157,9 @@ int main(int argc, char * * argv) if (evalOnly && !wantsReadWrite) settings.readOnlyMode = true; - store = openStore(); + auto store = openStore(); - EvalState state(searchPath); + EvalState state(searchPath, store); state.repair = repair; Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); @@ -178,7 +177,7 @@ int main(int argc, char * * argv) if (readStdin) { Expr * e = parseStdin(state); - processExpr(state, attrPaths, parseOnly, strict, autoArgs, + processExpr(store, state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); } else if (files.empty() && !fromArgs) files.push_back("./default.nix"); @@ -187,7 +186,7 @@ int main(int argc, char * * argv) Expr * e = fromArgs ? state.parseExprFromString(i, absPath(".")) : state.parseExprFromFile(resolveExprPath(lookupFileArg(state, i))); - processExpr(state, attrPaths, parseOnly, strict, autoArgs, + processExpr(store, state, attrPaths, parseOnly, strict, autoArgs, evalOnly, outputKind, xmlOutputSourceLocation, e); } diff --git a/src/nix-prefetch-url/nix-prefetch-url.cc b/src/nix-prefetch-url/nix-prefetch-url.cc index 73a2845e0..c0c05a60b 100644 --- a/src/nix-prefetch-url/nix-prefetch-url.cc +++ b/src/nix-prefetch-url/nix-prefetch-url.cc @@ -91,8 +91,8 @@ int main(int argc, char * * argv) if (args.size() > 2) throw UsageError("too many arguments"); - store = openStore(); - EvalState state(searchPath); + auto store = openStore(); + EvalState state(searchPath, store); Bindings & autoArgs(*evalAutoArgs(state, autoArgs_)); diff --git a/src/nix-store/dotgraph.cc b/src/nix-store/dotgraph.cc index af4cd48e7..326c668e0 100644 --- a/src/nix-store/dotgraph.cc +++ b/src/nix-store/dotgraph.cc @@ -94,7 +94,7 @@ void printClosure(const Path & nePath, const StoreExpr & fs) #endif -void printDotGraph(const PathSet & roots) +void printDotGraph(StoreAPI & store, const PathSet & roots) { PathSet workList(roots); PathSet doneSet; @@ -111,7 +111,7 @@ void printDotGraph(const PathSet & roots) cout << makeNode(path, symbolicName(path), "#ff0000"); PathSet references; - store->queryReferences(path, references); + store.queryReferences(path, references); for (PathSet::iterator i = references.begin(); i != references.end(); ++i) diff --git a/src/nix-store/dotgraph.hh b/src/nix-store/dotgraph.hh index 68410d841..d3b37642c 100644 --- a/src/nix-store/dotgraph.hh +++ b/src/nix-store/dotgraph.hh @@ -4,6 +4,8 @@ namespace nix { -void printDotGraph(const PathSet & roots); +class StoreAPI; + +void printDotGraph(StoreAPI & store, const PathSet & roots); } diff --git a/src/nix-store/nix-store.cc b/src/nix-store/nix-store.cc index df6afd979..d5242492e 100644 --- a/src/nix-store/nix-store.cc +++ b/src/nix-store/nix-store.cc @@ -1,14 +1,14 @@ -#include "globals.hh" -#include "misc.hh" #include "archive.hh" -#include "shared.hh" +#include "derivations.hh" #include "dotgraph.hh" -#include "xmlgraph.hh" +#include "globals.hh" #include "local-store.hh" -#include "util.hh" -#include "serve-protocol.hh" -#include "worker-protocol.hh" #include "monitor-fd.hh" +#include "serve-protocol.hh" +#include "shared.hh" +#include "util.hh" +#include "worker-protocol.hh" +#include "xmlgraph.hh" #include #include @@ -37,6 +37,7 @@ static Path gcRoot; static int rootNr = 0; static bool indirectRoot = false; static bool noOutput = false; +static std::shared_ptr store; LocalStore & ensureLocalStore() @@ -65,7 +66,7 @@ static PathSet realisePath(Path path, bool build = true) if (isDerivation(p.first)) { if (build) store->buildPaths(singleton(path)); - Derivation drv = derivationFromPath(*store, p.first); + Derivation drv = store->derivationFromPath(p.first); rootNr++; if (p.second.empty()) @@ -83,7 +84,7 @@ static PathSet realisePath(Path path, bool build = true) Path rootName = gcRoot; if (rootNr > 1) rootName += "-" + std::to_string(rootNr); if (i->first != "out") rootName += "-" + i->first; - outPath = addPermRoot(*store, outPath, rootName, indirectRoot); + outPath = addPermRoot(ref(store), outPath, rootName, indirectRoot); } outputs.insert(outPath); } @@ -99,7 +100,7 @@ static PathSet realisePath(Path path, bool build = true) Path rootName = gcRoot; rootNr++; if (rootNr > 1) rootName += "-" + std::to_string(rootNr); - path = addPermRoot(*store, path, rootName, indirectRoot); + path = addPermRoot(ref(store), path, rootName, indirectRoot); } return singleton(path); } @@ -129,7 +130,7 @@ static void opRealise(Strings opFlags, Strings opArgs) unsigned long long downloadSize, narSize; PathSet willBuild, willSubstitute, unknown; - queryMissing(*store, PathSet(paths.begin(), paths.end()), + store->queryMissing(PathSet(paths.begin(), paths.end()), willBuild, willSubstitute, unknown, downloadSize, narSize); if (ignoreUnknown) { @@ -141,7 +142,7 @@ static void opRealise(Strings opFlags, Strings opArgs) } if (settings.get("print-missing", true)) - printMissing(*store, willBuild, willSubstitute, unknown, downloadSize, narSize); + printMissing(ref(store), willBuild, willSubstitute, unknown, downloadSize, narSize); if (dryRun) return; @@ -216,7 +217,7 @@ static PathSet maybeUseOutputs(const Path & storePath, bool useOutput, bool forc { if (forceRealise) realisePath(storePath); if (useOutput && isDerivation(storePath)) { - Derivation drv = derivationFromPath(*store, storePath); + Derivation drv = store->derivationFromPath(storePath); PathSet outputs; for (auto & i : drv.outputs) outputs.insert(i.second.path); @@ -253,7 +254,7 @@ static void printTree(const Path & path, closure(B). That is, if derivation A is an (possibly indirect) input of B, then A is printed first. This has the effect of flattening the tree, preventing deeply nested structures. */ - Paths sorted = topoSortPaths(*store, references); + Paths sorted = store->topoSortPaths(references); reverse(sorted.begin(), sorted.end()); for (auto i = sorted.begin(); i != sorted.end(); ++i) { @@ -318,7 +319,7 @@ static void opQuery(Strings opFlags, Strings opArgs) for (auto & i : opArgs) { i = followLinksToStorePath(i); if (forceRealise) realisePath(i); - Derivation drv = derivationFromPath(*store, i); + Derivation drv = store->derivationFromPath(i); for (auto & j : drv.outputs) cout << format("%1%\n") % j.second.path; } @@ -333,13 +334,13 @@ static void opQuery(Strings opFlags, Strings opArgs) for (auto & i : opArgs) { PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); for (auto & j : ps) { - if (query == qRequisites) computeFSClosure(*store, j, paths, false, includeOutputs); + if (query == qRequisites) store->computeFSClosure(j, paths, false, includeOutputs); else if (query == qReferences) store->queryReferences(j, paths); else if (query == qReferrers) store->queryReferrers(j, paths); - else if (query == qReferrersClosure) computeFSClosure(*store, j, paths, true); + else if (query == qReferrersClosure) store->computeFSClosure(j, paths, true); } } - Paths sorted = topoSortPaths(*store, paths); + Paths sorted = store->topoSortPaths(paths); for (Paths::reverse_iterator i = sorted.rbegin(); i != sorted.rend(); ++i) cout << format("%s\n") % *i; @@ -357,7 +358,7 @@ static void opQuery(Strings opFlags, Strings opArgs) case qBinding: for (auto & i : opArgs) { Path path = useDeriver(followLinksToStorePath(i)); - Derivation drv = derivationFromPath(*store, path); + Derivation drv = store->derivationFromPath(path); StringPairs::iterator j = drv.env.find(bindingName); if (j == drv.env.end()) throw Error(format("derivation ‘%1%’ has no environment binding named ‘%2%’") @@ -394,7 +395,7 @@ static void opQuery(Strings opFlags, Strings opArgs) PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); roots.insert(paths.begin(), paths.end()); } - printDotGraph(roots); + printDotGraph(*store, roots); break; } @@ -404,7 +405,7 @@ static void opQuery(Strings opFlags, Strings opArgs) PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); roots.insert(paths.begin(), paths.end()); } - printXmlGraph(roots); + printXmlGraph(*store, roots); break; } @@ -419,7 +420,7 @@ static void opQuery(Strings opFlags, Strings opArgs) for (auto & i : opArgs) { PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise); for (auto & j : paths) - computeFSClosure(*store, j, referrers, true, + store->computeFSClosure(j, referrers, true, settings.gcKeepOutputs, settings.gcKeepDerivations); } Roots roots = store->findRoots(); @@ -450,7 +451,7 @@ static void opPrintEnv(Strings opFlags, Strings opArgs) if (opArgs.size() != 1) throw UsageError("‘--print-env’ requires one derivation store path"); Path drvPath = opArgs.front(); - Derivation drv = derivationFromPath(*store, drvPath); + Derivation drv = store->derivationFromPath(drvPath); /* Print each environment variable in the derivation in a format that can be sourced by the shell. */ @@ -715,9 +716,9 @@ static void opExport(Strings opFlags, Strings opArgs) else throw UsageError(format("unknown flag ‘%1%’") % i); FdSink sink(STDOUT_FILENO); - Paths sorted = topoSortPaths(*store, PathSet(opArgs.begin(), opArgs.end())); + Paths sorted = store->topoSortPaths(PathSet(opArgs.begin(), opArgs.end())); reverse(sorted.begin(), sorted.end()); - exportPaths(*store, sorted, sign, sink); + store->exportPaths(sorted, sign, sink); } @@ -896,7 +897,7 @@ static void opServe(Strings opFlags, Strings opArgs) if (!isDerivation(path)) paths2.insert(path); unsigned long long downloadSize, narSize; PathSet willBuild, willSubstitute, unknown; - queryMissing(*store, PathSet(paths2.begin(), paths2.end()), + store->queryMissing(PathSet(paths2.begin(), paths2.end()), willBuild, willSubstitute, unknown, downloadSize, narSize); /* FIXME: should use ensurePath(), but it only does one path at a time. */ @@ -941,9 +942,9 @@ static void opServe(Strings opFlags, Strings opArgs) case cmdExportPaths: { bool sign = readInt(in); - Paths sorted = topoSortPaths(*store, readStorePaths(in)); + Paths sorted = store->topoSortPaths(readStorePaths(in)); reverse(sorted.begin(), sorted.end()); - exportPaths(*store, sorted, sign, out); + store->exportPaths(sorted, sign, out); break; } @@ -988,7 +989,7 @@ static void opServe(Strings opFlags, Strings opArgs) PathSet paths = readStorePaths(in); PathSet closure; for (auto & i : paths) - computeFSClosure(*store, i, closure, false, includeOutputs); + store->computeFSClosure(i, closure, false, includeOutputs); out << closure; break; } diff --git a/src/nix-store/xmlgraph.cc b/src/nix-store/xmlgraph.cc index 98ab9e626..f88266bbb 100644 --- a/src/nix-store/xmlgraph.cc +++ b/src/nix-store/xmlgraph.cc @@ -33,7 +33,7 @@ static string makeNode(const string & id) } -void printXmlGraph(const PathSet & roots) +void printXmlGraph(StoreAPI & store, const PathSet & roots) { PathSet workList(roots); PathSet doneSet; @@ -51,7 +51,7 @@ void printXmlGraph(const PathSet & roots) cout << makeNode(path); PathSet references; - store->queryReferences(path, references); + store.queryReferences(path, references); for (PathSet::iterator i = references.begin(); i != references.end(); ++i) diff --git a/src/nix-store/xmlgraph.hh b/src/nix-store/xmlgraph.hh index c2216c5a4..6d6d12a06 100644 --- a/src/nix-store/xmlgraph.hh +++ b/src/nix-store/xmlgraph.hh @@ -4,6 +4,8 @@ namespace nix { -void printXmlGraph(const PathSet & roots); +class StoreAPI; + +void printXmlGraph(StoreAPI & store, const PathSet & roots); }