1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-21 09:49:36 +01:00

Eliminate the "store" global variable

Also, move a few free-standing functions into StoreAPI and Derivation.

Also, introduce a non-nullable smart pointer, ref<T>, 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.)
This commit is contained in:
Eelco Dolstra 2016-02-04 14:28:26 +01:00
parent 4f7824c58e
commit c10c61449f
36 changed files with 511 additions and 458 deletions

View file

@ -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<BasicDerivation>(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<BasicDerivation>(new Derivation(derivationFromPath(worker.store, drvPath)));
drv = std::unique_ptr<BasicDerivation>(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<Path, Path> 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;

View file

@ -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<StoreAPI> 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<string> & 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;
}

View file

@ -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<StoreAPI> 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<Path, Hash> 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<string> & outpu
bool wantOutput(const string & output, const std::set<string> & wanted);
PathSet outputPaths(const BasicDerivation & drv);
struct Source;
struct Sink;

View file

@ -188,7 +188,7 @@ DownloadResult downloadFile(string url, const DownloadOptions & options)
}
Path downloadFileCached(const string & url, bool unpack)
Path downloadFileCached(ref<StoreAPI> store, const string & url, bool unpack)
{
Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
createDirs(cacheDir);

View file

@ -1,6 +1,7 @@
#pragma once
#include "types.hh"
#include <string>
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<StoreAPI> store, const string & url, bool unpack);
MakeError(DownloadError, Error)

View file

@ -1,5 +1,5 @@
#include "derivations.hh"
#include "globals.hh"
#include "misc.hh"
#include "local-store.hh"
#include <functional>
@ -83,7 +83,7 @@ void LocalStore::addIndirectRoot(const Path & path)
}
Path addPermRoot(StoreAPI & store, const Path & _storePath,
Path addPermRoot(ref<StoreAPI> 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

View file

@ -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;

View file

@ -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,

View file

@ -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<void(const Path & path)> 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;
}

View file

@ -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);
}

View file

@ -74,7 +74,7 @@ static void makeName(const Path & profile, unsigned int num,
}
Path createGeneration(Path profile, Path outPath)
Path createGeneration(ref<StoreAPI> 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;
}

View file

@ -31,7 +31,9 @@ typedef list<Generation> Generations;
profile, sorted by generation number. */
Generations findGenerations(Path profile, int & curGen);
Path createGeneration(Path profile, Path outPath);
class StoreAPI;
Path createGeneration(ref<StoreAPI> store, Path profile, Path outPath);
void deleteGeneration(const Path & profile, unsigned int gen);

View file

@ -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<StoreAPI> store;
std::shared_ptr<StoreAPI> openStore(bool reserveSpace)
ref<StoreAPI> openStore(bool reserveSpace)
{
enum { mDaemon, mLocal, mAuto } mode;
@ -325,8 +322,8 @@ std::shared_ptr<StoreAPI> openStore(bool reserveSpace)
}
return mode == mDaemon
? (std::shared_ptr<StoreAPI>) std::make_shared<RemoteStore>()
: std::make_shared<LocalStore>(reserveSpace);
? make_ref<StoreAPI, RemoteStore>()
: make_ref<StoreAPI, LocalStore>(reserveSpace);
}

View file

@ -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<StoreAPI> 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<StoreAPI> store;
/* Factory method: open the Nix database, either through the local or
remote implementation. */
std::shared_ptr<StoreAPI> openStore(bool reserveSpace = true);
ref<StoreAPI> 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 */