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:
parent
4f7824c58e
commit
c10c61449f
36 changed files with 511 additions and 458 deletions
|
@ -6,10 +6,10 @@
|
||||||
#undef do_open
|
#undef do_open
|
||||||
#undef do_close
|
#undef do_close
|
||||||
|
|
||||||
#include <store-api.hh>
|
#include "derivations.hh"
|
||||||
#include <globals.hh>
|
#include "globals.hh"
|
||||||
#include <misc.hh>
|
#include "store-api.hh"
|
||||||
#include <util.hh>
|
#include "util.hh"
|
||||||
|
|
||||||
#if HAVE_SODIUM
|
#if HAVE_SODIUM
|
||||||
#include <sodium.h>
|
#include <sodium.h>
|
||||||
|
@ -19,19 +19,21 @@
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
|
|
||||||
void doInit()
|
static ref<StoreAPI> store()
|
||||||
{
|
{
|
||||||
if (!store) {
|
static std::shared_ptr<StoreAPI> _store;
|
||||||
|
if (!_store) {
|
||||||
try {
|
try {
|
||||||
settings.processEnvironment();
|
settings.processEnvironment();
|
||||||
settings.loadConfFile();
|
settings.loadConfFile();
|
||||||
settings.update();
|
settings.update();
|
||||||
settings.lockCPU = false;
|
settings.lockCPU = false;
|
||||||
store = openStore();
|
_store = openStore();
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ref<StoreAPI>(_store);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,7 +47,7 @@ PROTOTYPES: ENABLE
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
CODE:
|
CODE:
|
||||||
doInit();
|
store();
|
||||||
|
|
||||||
|
|
||||||
void setVerbosity(int level)
|
void setVerbosity(int level)
|
||||||
|
@ -56,8 +58,7 @@ void setVerbosity(int level)
|
||||||
int isValidPath(char * path)
|
int isValidPath(char * path)
|
||||||
CODE:
|
CODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
RETVAL = store()->isValidPath(path);
|
||||||
RETVAL = store->isValidPath(path);
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
}
|
}
|
||||||
|
@ -68,9 +69,8 @@ int isValidPath(char * path)
|
||||||
SV * queryReferences(char * path)
|
SV * queryReferences(char * path)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
store->queryReferences(path, paths);
|
store()->queryReferences(path, paths);
|
||||||
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
|
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
|
||||||
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -81,8 +81,7 @@ SV * queryReferences(char * path)
|
||||||
SV * queryPathHash(char * path)
|
SV * queryPathHash(char * path)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
Hash hash = store()->queryPathHash(path);
|
||||||
Hash hash = store->queryPathHash(path);
|
|
||||||
string s = "sha256:" + printHash32(hash);
|
string s = "sha256:" + printHash32(hash);
|
||||||
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(s.c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -93,8 +92,7 @@ SV * queryPathHash(char * path)
|
||||||
SV * queryDeriver(char * path)
|
SV * queryDeriver(char * path)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
Path deriver = store()->queryDeriver(path);
|
||||||
Path deriver = store->queryDeriver(path);
|
|
||||||
if (deriver == "") XSRETURN_UNDEF;
|
if (deriver == "") XSRETURN_UNDEF;
|
||||||
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(deriver.c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -105,8 +103,7 @@ SV * queryDeriver(char * path)
|
||||||
SV * queryPathInfo(char * path, int base32)
|
SV * queryPathInfo(char * path, int base32)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
ValidPathInfo info = store()->queryPathInfo(path);
|
||||||
ValidPathInfo info = store->queryPathInfo(path);
|
|
||||||
if (info.deriver == "")
|
if (info.deriver == "")
|
||||||
XPUSHs(&PL_sv_undef);
|
XPUSHs(&PL_sv_undef);
|
||||||
else
|
else
|
||||||
|
@ -127,8 +124,7 @@ SV * queryPathInfo(char * path, int base32)
|
||||||
SV * queryPathFromHashPart(char * hashPart)
|
SV * queryPathFromHashPart(char * hashPart)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
Path path = store()->queryPathFromHashPart(hashPart);
|
||||||
Path path = store->queryPathFromHashPart(hashPart);
|
|
||||||
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
|
@ -138,10 +134,9 @@ SV * queryPathFromHashPart(char * hashPart)
|
||||||
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
|
SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
for (int n = 2; n < items; ++n)
|
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)
|
for (PathSet::iterator i = paths.begin(); i != paths.end(); ++i)
|
||||||
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -152,10 +147,9 @@ SV * computeFSClosure(int flipDirection, int includeOutputs, ...)
|
||||||
SV * topoSortPaths(...)
|
SV * topoSortPaths(...)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
PathSet paths;
|
PathSet paths;
|
||||||
for (int n = 0; n < items; ++n) paths.insert(SvPV_nolen(ST(n)));
|
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)
|
for (Paths::iterator i = sorted.begin(); i != sorted.end(); ++i)
|
||||||
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
XPUSHs(sv_2mortal(newSVpv(i->c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
|
@ -166,7 +160,6 @@ SV * topoSortPaths(...)
|
||||||
SV * followLinksToStorePath(char * path)
|
SV * followLinksToStorePath(char * path)
|
||||||
CODE:
|
CODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0);
|
RETVAL = newSVpv(followLinksToStorePath(path).c_str(), 0);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
|
@ -178,11 +171,10 @@ SV * followLinksToStorePath(char * path)
|
||||||
void exportPaths(int fd, int sign, ...)
|
void exportPaths(int fd, int sign, ...)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
Paths paths;
|
Paths paths;
|
||||||
for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n)));
|
for (int n = 2; n < items; ++n) paths.push_back(SvPV_nolen(ST(n)));
|
||||||
FdSink sink(fd);
|
FdSink sink(fd);
|
||||||
exportPaths(*store, paths, sign, sink);
|
store()->exportPaths(paths, sign, sink);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
}
|
}
|
||||||
|
@ -191,9 +183,8 @@ void exportPaths(int fd, int sign, ...)
|
||||||
void importPaths(int fd)
|
void importPaths(int fd)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
FdSource source(fd);
|
FdSource source(fd);
|
||||||
store->importPaths(false, source);
|
store()->importPaths(false, source);
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
}
|
}
|
||||||
|
@ -292,8 +283,7 @@ int checkSignature(SV * publicKey_, SV * sig_, char * msg)
|
||||||
SV * addToStore(char * srcPath, int recursive, char * algo)
|
SV * addToStore(char * srcPath, int recursive, char * algo)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
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)));
|
XPUSHs(sv_2mortal(newSVpv(path.c_str(), 0)));
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
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)
|
SV * makeFixedOutputPath(int recursive, char * algo, char * hash, char * name)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
|
||||||
HashType ht = parseHashType(algo);
|
HashType ht = parseHashType(algo);
|
||||||
Path path = makeFixedOutputPath(recursive, ht,
|
Path path = makeFixedOutputPath(recursive, ht,
|
||||||
parseHash16or32(ht, hash), name);
|
parseHash16or32(ht, hash), name);
|
||||||
|
@ -318,8 +307,7 @@ SV * derivationFromPath(char * drvPath)
|
||||||
HV *hash;
|
HV *hash;
|
||||||
CODE:
|
CODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
Derivation drv = store()->derivationFromPath(drvPath);
|
||||||
Derivation drv = derivationFromPath(*store, drvPath);
|
|
||||||
hash = newHV();
|
hash = newHV();
|
||||||
|
|
||||||
HV * outputs = newHV();
|
HV * outputs = newHV();
|
||||||
|
@ -361,8 +349,7 @@ SV * derivationFromPath(char * drvPath)
|
||||||
void addTempRoot(char * storePath)
|
void addTempRoot(char * storePath)
|
||||||
PPCODE:
|
PPCODE:
|
||||||
try {
|
try {
|
||||||
doInit();
|
store()->addTempRoot(storePath);
|
||||||
store->addTempRoot(storePath);
|
|
||||||
} catch (Error & e) {
|
} catch (Error & e) {
|
||||||
croak("%s", e.what());
|
croak("%s", e.what());
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,7 +55,7 @@ bool parseSearchPathArg(Strings::iterator & i,
|
||||||
Path lookupFileArg(EvalState & state, string s)
|
Path lookupFileArg(EvalState & state, string s)
|
||||||
{
|
{
|
||||||
if (isUri(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) == '>') {
|
else if (s.size() > 2 && s.at(0) == '<' && s.at(s.size() - 1) == '>') {
|
||||||
Path p = s.substr(1, s.size() - 2);
|
Path p = s.substr(1, s.size() - 2);
|
||||||
return state.findFile(p);
|
return state.findFile(p);
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
class StoreAPI;
|
||||||
|
|
||||||
/* Some common option parsing between nix-env and nix-instantiate. */
|
/* Some common option parsing between nix-env and nix-instantiate. */
|
||||||
bool parseAutoArgs(Strings::iterator & i,
|
bool parseAutoArgs(Strings::iterator & i,
|
||||||
const Strings::iterator & argsEnd, std::map<string, string> & res);
|
const Strings::iterator & argsEnd, std::map<string, string> & res);
|
||||||
|
|
|
@ -244,7 +244,7 @@ static Strings parseNixPath(const string & in)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
EvalState::EvalState(const Strings & _searchPath)
|
EvalState::EvalState(const Strings & _searchPath, ref<StoreAPI> store)
|
||||||
: sWith(symbols.create("<with>"))
|
: sWith(symbols.create("<with>"))
|
||||||
, sOutPath(symbols.create("outPath"))
|
, sOutPath(symbols.create("outPath"))
|
||||||
, sDrvPath(symbols.create("drvPath"))
|
, sDrvPath(symbols.create("drvPath"))
|
||||||
|
@ -262,6 +262,7 @@ EvalState::EvalState(const Strings & _searchPath)
|
||||||
, sColumn(symbols.create("column"))
|
, sColumn(symbols.create("column"))
|
||||||
, sFunctor(symbols.create("__functor"))
|
, sFunctor(symbols.create("__functor"))
|
||||||
, sToString(symbols.create("__toString"))
|
, sToString(symbols.create("__toString"))
|
||||||
|
, store(store)
|
||||||
, baseEnv(allocEnv(128))
|
, baseEnv(allocEnv(128))
|
||||||
, staticBaseEnv(false, 0)
|
, staticBaseEnv(false, 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
|
class StoreAPI;
|
||||||
class EvalState;
|
class EvalState;
|
||||||
|
|
||||||
|
|
||||||
|
@ -82,6 +83,8 @@ public:
|
||||||
|
|
||||||
Value vEmptySet;
|
Value vEmptySet;
|
||||||
|
|
||||||
|
const ref<StoreAPI> store;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrcToStore srcToStore;
|
SrcToStore srcToStore;
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
EvalState(const Strings & _searchPath);
|
EvalState(const Strings & _searchPath, ref<StoreAPI> store);
|
||||||
~EvalState();
|
~EvalState();
|
||||||
|
|
||||||
void addToSearchPath(const string & s, bool warn = false);
|
void addToSearchPath(const string & s, bool warn = false);
|
||||||
|
@ -240,6 +243,8 @@ public:
|
||||||
/* Print statistics. */
|
/* Print statistics. */
|
||||||
void printStats();
|
void printStats();
|
||||||
|
|
||||||
|
void realiseContext(const PathSet & context);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned long nrEnvs = 0;
|
unsigned long nrEnvs = 0;
|
||||||
|
@ -290,7 +295,4 @@ struct InvalidPathError : EvalError
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Realise all paths in `context' */
|
|
||||||
void realiseContext(const PathSet & context);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -603,7 +603,7 @@ void EvalState::addToSearchPath(const string & s, bool warn)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isUri(path))
|
if (isUri(path))
|
||||||
path = downloadFileCached(path, true);
|
path = downloadFileCached(store, path, true);
|
||||||
|
|
||||||
path = absPath(path);
|
path = absPath(path);
|
||||||
if (pathExists(path)) {
|
if (pathExists(path)) {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
#include "eval.hh"
|
|
||||||
#include "misc.hh"
|
|
||||||
#include "globals.hh"
|
|
||||||
#include "store-api.hh"
|
|
||||||
#include "util.hh"
|
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "value-to-xml.hh"
|
#include "derivations.hh"
|
||||||
#include "value-to-json.hh"
|
#include "download.hh"
|
||||||
|
#include "eval-inline.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "globals.hh"
|
||||||
#include "json-to-value.hh"
|
#include "json-to-value.hh"
|
||||||
#include "names.hh"
|
#include "names.hh"
|
||||||
#include "eval-inline.hh"
|
#include "store-api.hh"
|
||||||
#include "download.hh"
|
#include "util.hh"
|
||||||
|
#include "value-to-json.hh"
|
||||||
|
#include "value-to-xml.hh"
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -43,7 +43,7 @@ std::pair<string, string> decodeContext(const string & s)
|
||||||
InvalidPathError::InvalidPathError(const Path & path) :
|
InvalidPathError::InvalidPathError(const Path & path) :
|
||||||
EvalError(format("path ‘%1%’ is not valid") % path), 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;
|
PathSet drvs;
|
||||||
for (auto & i : context) {
|
for (auto & i : context) {
|
||||||
|
@ -52,16 +52,14 @@ void realiseContext(const PathSet & context)
|
||||||
assert(isStorePath(ctx));
|
assert(isStorePath(ctx));
|
||||||
if (!store->isValidPath(ctx))
|
if (!store->isValidPath(ctx))
|
||||||
throw InvalidPathError(ctx);
|
throw InvalidPathError(ctx);
|
||||||
if (!decoded.second.empty() && isDerivation(ctx))
|
if (!decoded.second.empty() && nix::isDerivation(ctx))
|
||||||
drvs.insert(decoded.first + "!" + decoded.second);
|
drvs.insert(decoded.first + "!" + decoded.second);
|
||||||
}
|
}
|
||||||
if (!drvs.empty()) {
|
if (!drvs.empty()) {
|
||||||
/* For performance, prefetch all substitute info. */
|
/* For performance, prefetch all substitute info. */
|
||||||
PathSet willBuild, willSubstitute, unknown;
|
PathSet willBuild, willSubstitute, unknown;
|
||||||
unsigned long long downloadSize, narSize;
|
unsigned long long downloadSize, narSize;
|
||||||
queryMissing(*store, drvs,
|
store->queryMissing(drvs, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
|
||||||
|
|
||||||
store->buildPaths(drvs);
|
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);
|
Path path = state.coerceToPath(pos, *args[1], context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
realiseContext(context);
|
state.realiseContext(context);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||||
% path % e.path % pos);
|
% path % e.path % pos);
|
||||||
|
@ -83,7 +81,7 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
|
||||||
|
|
||||||
path = state.checkSourcePath(path);
|
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);
|
Derivation drv = readDerivation(path);
|
||||||
Value & w = *state.allocValue();
|
Value & w = *state.allocValue();
|
||||||
state.mkAttrs(w, 3 + drv.outputs.size());
|
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);
|
Path path = state.coerceToPath(pos, *args[0], context);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
realiseContext(context);
|
state.realiseContext(context);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
throw EvalError(format("cannot import ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||||
% path % e.path % pos);
|
% path % e.path % pos);
|
||||||
|
@ -560,11 +558,12 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
runs. */
|
runs. */
|
||||||
if (path.at(0) == '=') {
|
if (path.at(0) == '=') {
|
||||||
/* !!! This doesn't work if readOnlyMode is set. */
|
/* !!! 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) {
|
for (auto & j : refs) {
|
||||||
drv.inputSrcs.insert(j);
|
drv.inputSrcs.insert(j);
|
||||||
if (isDerivation(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
|
/* Handle derivation contexts returned by
|
||||||
‘builtins.storePath’. */
|
‘builtins.storePath’. */
|
||||||
else if (isDerivation(path))
|
else if (isDerivation(path))
|
||||||
drv.inputDrvs[path] = store->queryDerivationOutputNames(path);
|
drv.inputDrvs[path] = state.store->queryDerivationOutputNames(path);
|
||||||
|
|
||||||
/* Otherwise it's a source file. */
|
/* Otherwise it's a source file. */
|
||||||
else
|
else
|
||||||
|
@ -630,7 +629,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * *
|
||||||
|
|
||||||
/* Use the masked derivation expression to compute the output
|
/* Use the masked derivation expression to compute the output
|
||||||
path. */
|
path. */
|
||||||
Hash h = hashDerivationModulo(*store, drv);
|
Hash h = hashDerivationModulo(*state.store, drv);
|
||||||
|
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
if (i.second.path == "") {
|
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. */
|
/* 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%’")
|
printMsg(lvlChatty, format("instantiated ‘%1%’ -> ‘%2%’")
|
||||||
% drvName % drvPath);
|
% 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
|
/* Optimisation, but required in read-only mode! because in that
|
||||||
case we don't actually write store derivations, so we can't
|
case we don't actually write store derivations, so we can't
|
||||||
read them later. */
|
read them later. */
|
||||||
drvHashes[drvPath] = hashDerivationModulo(*store, drv);
|
drvHashes[drvPath] = hashDerivationModulo(*state.store, drv);
|
||||||
|
|
||||||
state.mkAttrs(v, 1 + drv.outputs.size());
|
state.mkAttrs(v, 1 + drv.outputs.size());
|
||||||
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + drvPath));
|
mkString(*state.allocAttr(v, state.sDrvPath), drvPath, singleton<PathSet>("=" + 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);
|
throw EvalError(format("path ‘%1%’ is not in the Nix store, at %2%") % path % pos);
|
||||||
Path path2 = toStorePath(path);
|
Path path2 = toStorePath(path);
|
||||||
if (!settings.readOnlyMode)
|
if (!settings.readOnlyMode)
|
||||||
store->ensurePath(path2);
|
state.store->ensurePath(path2);
|
||||||
context.insert(path2);
|
context.insert(path2);
|
||||||
mkString(v, path, context);
|
mkString(v, path, context);
|
||||||
}
|
}
|
||||||
|
@ -745,7 +744,7 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
|
||||||
PathSet context;
|
PathSet context;
|
||||||
Path path = state.coerceToPath(pos, *args[0], context);
|
Path path = state.coerceToPath(pos, *args[0], context);
|
||||||
try {
|
try {
|
||||||
realiseContext(context);
|
state.realiseContext(context);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||||
% path % e.path % pos);
|
% 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);
|
string path = state.forceStringNoCtx(*args[1], pos);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
realiseContext(context);
|
state.realiseContext(context);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
throw EvalError(format("cannot find ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||||
% path % e.path % pos);
|
% path % e.path % pos);
|
||||||
|
@ -801,7 +800,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
|
||||||
PathSet ctx;
|
PathSet ctx;
|
||||||
Path path = state.coerceToPath(pos, *args[0], ctx);
|
Path path = state.coerceToPath(pos, *args[0], ctx);
|
||||||
try {
|
try {
|
||||||
realiseContext(ctx);
|
state.realiseContext(ctx);
|
||||||
} catch (InvalidPathError & e) {
|
} catch (InvalidPathError & e) {
|
||||||
throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
|
||||||
% path % e.path % pos);
|
% path % e.path % pos);
|
||||||
|
@ -879,13 +878,13 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
if (path.at(0) != '~')
|
if (path.at(0) != '~')
|
||||||
throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos);
|
throw EvalError(format("in ‘toFile’: the file ‘%1%’ cannot refer to derivation outputs, at %2%") % name % pos);
|
||||||
path = string(path, 1);
|
path = string(path, 1);
|
||||||
}
|
}
|
||||||
refs.insert(path);
|
refs.insert(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path storePath = settings.readOnlyMode
|
Path storePath = settings.readOnlyMode
|
||||||
? computeStorePathForText(name, contents, refs)
|
? 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
|
/* Note: we don't need to add `context' to the context of the
|
||||||
result, since `storePath' itself has references to the paths
|
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
|
Path dstPath = settings.readOnlyMode
|
||||||
? computeStorePathForPath(path, true, htSHA256, filter).first
|
? 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<PathSet>(dstPath));
|
mkString(v, dstPath, singleton<PathSet>(dstPath));
|
||||||
}
|
}
|
||||||
|
@ -1678,7 +1677,7 @@ void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v,
|
||||||
} else
|
} else
|
||||||
url = state.forceStringNoCtx(*args[0], pos);
|
url = state.forceStringNoCtx(*args[0], pos);
|
||||||
|
|
||||||
Path res = downloadFileCached(url, unpack);
|
Path res = downloadFileCached(state.store, url, unpack);
|
||||||
mkString(v, res, PathSet({res}));
|
mkString(v, res, PathSet({res}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "misc.hh"
|
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
|
@ -47,22 +46,22 @@ void printGCWarning()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void printMissing(StoreAPI & store, const PathSet & paths)
|
void printMissing(ref<StoreAPI> store, const PathSet & paths)
|
||||||
{
|
{
|
||||||
unsigned long long downloadSize, narSize;
|
unsigned long long downloadSize, narSize;
|
||||||
PathSet willBuild, willSubstitute, unknown;
|
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);
|
printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void printMissing(StoreAPI & store, const PathSet & willBuild,
|
void printMissing(ref<StoreAPI> store, const PathSet & willBuild,
|
||||||
const PathSet & willSubstitute, const PathSet & unknown,
|
const PathSet & willSubstitute, const PathSet & unknown,
|
||||||
unsigned long long downloadSize, unsigned long long narSize)
|
unsigned long long downloadSize, unsigned long long narSize)
|
||||||
{
|
{
|
||||||
if (!willBuild.empty()) {
|
if (!willBuild.empty()) {
|
||||||
printMsg(lvlInfo, format("these derivations will be built:"));
|
printMsg(lvlInfo, format("these derivations will be built:"));
|
||||||
Paths sorted = topoSortPaths(store, willBuild);
|
Paths sorted = store->topoSortPaths(willBuild);
|
||||||
reverse(sorted.begin(), sorted.end());
|
reverse(sorted.begin(), sorted.end());
|
||||||
for (auto & i : sorted)
|
for (auto & i : sorted)
|
||||||
printMsg(lvlInfo, format(" %1%") % i);
|
printMsg(lvlInfo, format(" %1%") % i);
|
||||||
|
|
|
@ -19,8 +19,6 @@ public:
|
||||||
Exit(int status) : status(status) { }
|
Exit(int status) : status(status) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class StoreAPI;
|
|
||||||
|
|
||||||
int handleExceptions(const string & programName, std::function<void()> fun);
|
int handleExceptions(const string & programName, std::function<void()> fun);
|
||||||
|
|
||||||
void initNix();
|
void initNix();
|
||||||
|
@ -33,9 +31,11 @@ void printVersion(const string & programName);
|
||||||
/* Ugh. No better place to put this. */
|
/* Ugh. No better place to put this. */
|
||||||
void printGCWarning();
|
void printGCWarning();
|
||||||
|
|
||||||
void printMissing(StoreAPI & store, const PathSet & paths);
|
class StoreAPI;
|
||||||
|
|
||||||
void printMissing(StoreAPI & store, const PathSet & willBuild,
|
void printMissing(ref<StoreAPI> store, const PathSet & paths);
|
||||||
|
|
||||||
|
void printMissing(ref<StoreAPI> store, const PathSet & willBuild,
|
||||||
const PathSet & willSubstitute, const PathSet & unknown,
|
const PathSet & willSubstitute, const PathSet & unknown,
|
||||||
unsigned long long downloadSize, unsigned long long narSize);
|
unsigned long long downloadSize, unsigned long long narSize);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
#include "references.hh"
|
#include "references.hh"
|
||||||
#include "pathlocks.hh"
|
#include "pathlocks.hh"
|
||||||
#include "misc.hh"
|
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "local-store.hh"
|
#include "local-store.hh"
|
||||||
#include "util.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));
|
this->drv = std::unique_ptr<BasicDerivation>(new BasicDerivation(drv));
|
||||||
state = &DerivationGoal::haveDerivation;
|
state = &DerivationGoal::haveDerivation;
|
||||||
name = (format("building of %1%") % showPaths(outputPaths(drv))).str();
|
name = (format("building of %1%") % showPaths(drv.outputPaths())).str();
|
||||||
trace("created");
|
trace("created");
|
||||||
|
|
||||||
/* Prevent the .chroot directory from being
|
/* Prevent the .chroot directory from being
|
||||||
|
@ -1018,7 +1017,7 @@ void DerivationGoal::loadDerivation()
|
||||||
assert(worker.store.isValidPath(drvPath));
|
assert(worker.store.isValidPath(drvPath));
|
||||||
|
|
||||||
/* Get the derivation. */
|
/* 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();
|
haveDerivation();
|
||||||
}
|
}
|
||||||
|
@ -1057,7 +1056,7 @@ void DerivationGoal::haveDerivation()
|
||||||
/* We are first going to try to create the invalid output paths
|
/* We are first going to try to create the invalid output paths
|
||||||
through substitutes. If that doesn't work, we'll build
|
through substitutes. If that doesn't work, we'll build
|
||||||
them. */
|
them. */
|
||||||
if (settings.useSubstitutes && substitutesAllowed(*drv))
|
if (settings.useSubstitutes && drv->substitutesAllowed())
|
||||||
for (auto & i : invalidOutputs)
|
for (auto & i : invalidOutputs)
|
||||||
addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair));
|
addWaitee(worker.makeSubstitutionGoal(i, buildMode == bmRepair));
|
||||||
|
|
||||||
|
@ -1138,7 +1137,7 @@ void DerivationGoal::repairClosure()
|
||||||
PathSet outputClosure;
|
PathSet outputClosure;
|
||||||
for (auto & i : drv->outputs) {
|
for (auto & i : drv->outputs) {
|
||||||
if (!wantOutput(i.first, wantedOutputs)) continue;
|
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). */
|
/* 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
|
derivation is responsible for which path in the output
|
||||||
closure. */
|
closure. */
|
||||||
PathSet inputClosure;
|
PathSet inputClosure;
|
||||||
if (useDerivation) computeFSClosure(worker.store, drvPath, inputClosure);
|
if (useDerivation) worker.store.computeFSClosure(drvPath, inputClosure);
|
||||||
std::map<Path, Path> outputsToDrv;
|
std::map<Path, Path> outputsToDrv;
|
||||||
for (auto & i : inputClosure)
|
for (auto & i : inputClosure)
|
||||||
if (isDerivation(i)) {
|
if (isDerivation(i)) {
|
||||||
Derivation drv = derivationFromPath(worker.store, i);
|
Derivation drv = worker.store.derivationFromPath(i);
|
||||||
for (auto & j : drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
outputsToDrv[j.second.path] = i;
|
outputsToDrv[j.second.path] = i;
|
||||||
}
|
}
|
||||||
|
@ -1225,10 +1224,10 @@ void DerivationGoal::inputsRealised()
|
||||||
`i' as input paths. Only add the closures of output paths
|
`i' as input paths. Only add the closures of output paths
|
||||||
that are specified as inputs. */
|
that are specified as inputs. */
|
||||||
assert(worker.store.isValidPath(i.first));
|
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)
|
for (auto & j : i.second)
|
||||||
if (inDrv.outputs.find(j) != inDrv.outputs.end())
|
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
|
else
|
||||||
throw Error(
|
throw Error(
|
||||||
format("derivation ‘%1%’ requires non-existent output ‘%2%’ from input derivation ‘%3%’")
|
format("derivation ‘%1%’ requires non-existent output ‘%2%’ from input derivation ‘%3%’")
|
||||||
|
@ -1237,7 +1236,7 @@ void DerivationGoal::inputsRealised()
|
||||||
|
|
||||||
/* Second, the input sources. */
|
/* Second, the input sources. */
|
||||||
for (auto & i : drv->inputSrcs)
|
for (auto & i : drv->inputSrcs)
|
||||||
computeFSClosure(worker.store, i, inputPaths);
|
worker.store.computeFSClosure(i, inputPaths);
|
||||||
|
|
||||||
debug(format("added input paths %1%") % showPaths(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()
|
void DerivationGoal::tryToBuild()
|
||||||
{
|
{
|
||||||
trace("trying to build");
|
trace("trying to build");
|
||||||
|
@ -1322,7 +1281,7 @@ void DerivationGoal::tryToBuild()
|
||||||
can't acquire the lock, then continue; hopefully some other
|
can't acquire the lock, then continue; hopefully some other
|
||||||
goal can start a build, and if not, the main loop will sleep a
|
goal can start a build, and if not, the main loop will sleep a
|
||||||
few seconds and then retry this goal. */
|
few seconds and then retry this goal. */
|
||||||
if (!outputLocks.lockPaths(outputPaths(*drv), "", false)) {
|
if (!outputLocks.lockPaths(drv->outputPaths(), "", false)) {
|
||||||
worker.waitForAWhile(shared_from_this());
|
worker.waitForAWhile(shared_from_this());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1301,7 @@ void DerivationGoal::tryToBuild()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
missingPaths = outputPaths(*drv);
|
missingPaths = drv->outputPaths();
|
||||||
if (buildMode != bmCheck)
|
if (buildMode != bmCheck)
|
||||||
for (auto & i : validPaths) missingPaths.erase(i);
|
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
|
/* Don't do a remote build if the derivation has the attribute
|
||||||
`preferLocalBuild' set. Also, check and repair modes are only
|
`preferLocalBuild' set. Also, check and repair modes are only
|
||||||
supported for local builds. */
|
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? */
|
/* Is the build hook willing to accept this job? */
|
||||||
if (!buildLocally) {
|
if (!buildLocally) {
|
||||||
|
@ -1661,7 +1620,7 @@ HookReply DerivationGoal::tryBuildHook()
|
||||||
list it since the remote system *probably* already has it.) */
|
list it since the remote system *probably* already has it.) */
|
||||||
PathSet allInputs;
|
PathSet allInputs;
|
||||||
allInputs.insert(inputPaths.begin(), inputPaths.end());
|
allInputs.insert(inputPaths.begin(), inputPaths.end());
|
||||||
computeFSClosure(worker.store, drvPath, allInputs);
|
worker.store.computeFSClosure(drvPath, allInputs);
|
||||||
|
|
||||||
string s;
|
string s;
|
||||||
for (auto & i : allInputs) { s += i; s += ' '; }
|
for (auto & i : allInputs) { s += i; s += ' '; }
|
||||||
|
@ -1716,7 +1675,7 @@ void DerivationGoal::startBuilder()
|
||||||
startNest(nest, lvlInfo, f % showPaths(missingPaths) % curRound % nrRounds);
|
startNest(nest, lvlInfo, f % showPaths(missingPaths) % curRound % nrRounds);
|
||||||
|
|
||||||
/* Right platform? */
|
/* Right platform? */
|
||||||
if (!canBuildLocally(*drv)) {
|
if (!drv->canBuildLocally()) {
|
||||||
if (settings.printBuildTrace)
|
if (settings.printBuildTrace)
|
||||||
printMsg(lvlError, format("@ unsupported-platform %1% %2%") % drvPath % drv->platform);
|
printMsg(lvlError, format("@ unsupported-platform %1% %2%") % drvPath % drv->platform);
|
||||||
throw Error(
|
throw Error(
|
||||||
|
@ -1873,14 +1832,14 @@ void DerivationGoal::startBuilder()
|
||||||
like passing all build-time dependencies of some path to a
|
like passing all build-time dependencies of some path to a
|
||||||
derivation that builds a NixOS DVD image. */
|
derivation that builds a NixOS DVD image. */
|
||||||
PathSet paths, paths2;
|
PathSet paths, paths2;
|
||||||
computeFSClosure(worker.store, storePath, paths);
|
worker.store.computeFSClosure(storePath, paths);
|
||||||
paths2 = paths;
|
paths2 = paths;
|
||||||
|
|
||||||
for (auto & j : paths2) {
|
for (auto & j : paths2) {
|
||||||
if (isDerivation(j)) {
|
if (isDerivation(j)) {
|
||||||
Derivation drv = derivationFromPath(worker.store, j);
|
Derivation drv = worker.store.derivationFromPath(j);
|
||||||
for (auto & k : drv.outputs)
|
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;
|
PathSet closure;
|
||||||
for (auto & i : dirsInChroot)
|
for (auto & i : dirsInChroot)
|
||||||
if (isInStore(i.second))
|
if (isInStore(i.second))
|
||||||
computeFSClosure(worker.store, toStorePath(i.second), closure);
|
worker.store.computeFSClosure(toStorePath(i.second), closure);
|
||||||
for (auto & i : closure)
|
for (auto & i : closure)
|
||||||
dirsInChroot[i] = i;
|
dirsInChroot[i] = i;
|
||||||
|
|
||||||
|
@ -2212,7 +2171,7 @@ void DerivationGoal::startBuilder()
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
ProcessOptions options;
|
ProcessOptions options;
|
||||||
options.allowVfork = !buildUser.enabled() && !isBuiltin(*drv);
|
options.allowVfork = !buildUser.enabled() && !drv->isBuiltin();
|
||||||
pid = startProcess([&]() {
|
pid = startProcess([&]() {
|
||||||
runChild();
|
runChild();
|
||||||
}, options);
|
}, options);
|
||||||
|
@ -2466,7 +2425,7 @@ void DerivationGoal::runChild()
|
||||||
const char *builder = "invalid";
|
const char *builder = "invalid";
|
||||||
|
|
||||||
string sandboxProfile;
|
string sandboxProfile;
|
||||||
if (isBuiltin(*drv)) {
|
if (drv->isBuiltin()) {
|
||||||
;
|
;
|
||||||
#if __APPLE__
|
#if __APPLE__
|
||||||
} else if (useChroot) {
|
} else if (useChroot) {
|
||||||
|
@ -2583,7 +2542,7 @@ void DerivationGoal::runChild()
|
||||||
writeFull(STDERR_FILENO, string("\1\n"));
|
writeFull(STDERR_FILENO, string("\1\n"));
|
||||||
|
|
||||||
/* Execute the program. This should not return. */
|
/* Execute the program. This should not return. */
|
||||||
if (isBuiltin(*drv)) {
|
if (drv->isBuiltin()) {
|
||||||
try {
|
try {
|
||||||
logType = ltFlat;
|
logType = ltFlat;
|
||||||
if (drv->builder == "builtin:fetchurl")
|
if (drv->builder == "builtin:fetchurl")
|
||||||
|
@ -2813,7 +2772,7 @@ void DerivationGoal::registerOutputs()
|
||||||
for (auto & i : references)
|
for (auto & i : references)
|
||||||
/* Don't call computeFSClosure on ourselves. */
|
/* Don't call computeFSClosure on ourselves. */
|
||||||
if (actualPath != i)
|
if (actualPath != i)
|
||||||
computeFSClosure(worker.store, i, used);
|
worker.store.computeFSClosure(i, used);
|
||||||
} else
|
} else
|
||||||
used = references;
|
used = references;
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "misc.hh"
|
|
||||||
#include "worker-protocol.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)
|
const Derivation & drv, const string & name, bool repair)
|
||||||
{
|
{
|
||||||
PathSet references;
|
PathSet references;
|
||||||
|
@ -38,10 +79,10 @@ Path writeDerivation(StoreAPI & store,
|
||||||
(that can be missing (of course) and should not necessarily be
|
(that can be missing (of course) and should not necessarily be
|
||||||
held during a garbage collection). */
|
held during a garbage collection). */
|
||||||
string suffix = name + drvExtension;
|
string suffix = name + drvExtension;
|
||||||
string contents = unparseDerivation(drv);
|
string contents = drv.unparse();
|
||||||
return settings.readOnlyMode
|
return settings.readOnlyMode
|
||||||
? computeStorePathForText(suffix, contents, references)
|
? 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;
|
string s;
|
||||||
s.reserve(65536);
|
s.reserve(65536);
|
||||||
s += "Derive([";
|
s += "Derive([";
|
||||||
|
|
||||||
bool first = true;
|
bool first = true;
|
||||||
for (auto & i : drv.outputs) {
|
for (auto & i : outputs) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i.first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printString(s, i.second.path);
|
s += ','; printString(s, i.second.path);
|
||||||
|
@ -167,7 +208,7 @@ string unparseDerivation(const Derivation & drv)
|
||||||
|
|
||||||
s += "],[";
|
s += "],[";
|
||||||
first = true;
|
first = true;
|
||||||
for (auto & i : drv.inputDrvs) {
|
for (auto & i : inputDrvs) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i.first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printStrings(s, i.second.begin(), i.second.end());
|
s += ','; printStrings(s, i.second.begin(), i.second.end());
|
||||||
|
@ -175,15 +216,15 @@ string unparseDerivation(const Derivation & drv)
|
||||||
}
|
}
|
||||||
|
|
||||||
s += "],";
|
s += "],";
|
||||||
printStrings(s, drv.inputSrcs.begin(), drv.inputSrcs.end());
|
printStrings(s, inputSrcs.begin(), inputSrcs.end());
|
||||||
|
|
||||||
s += ','; printString(s, drv.platform);
|
s += ','; printString(s, platform);
|
||||||
s += ','; printString(s, drv.builder);
|
s += ','; printString(s, builder);
|
||||||
s += ','; printStrings(s, drv.args.begin(), drv.args.end());
|
s += ','; printStrings(s, args.begin(), args.end());
|
||||||
|
|
||||||
s += ",[";
|
s += ",[";
|
||||||
first = true;
|
first = true;
|
||||||
for (auto & i : drv.env) {
|
for (auto & i : env) {
|
||||||
if (first) first = false; else s += ',';
|
if (first) first = false; else s += ',';
|
||||||
s += '('; printString(s, i.first);
|
s += '('; printString(s, i.first);
|
||||||
s += ','; printString(s, i.second);
|
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 &&
|
return outputs.size() == 1 &&
|
||||||
drv.outputs.begin()->first == "out" &&
|
outputs.begin()->first == "out" &&
|
||||||
drv.outputs.begin()->second.hash != "";
|
outputs.begin()->second.hash != "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -236,7 +277,7 @@ DrvHashes drvHashes;
|
||||||
Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
|
Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
|
||||||
{
|
{
|
||||||
/* Return a fixed hash for fixed-output derivations. */
|
/* Return a fixed hash for fixed-output derivations. */
|
||||||
if (isFixedOutputDrv(drv)) {
|
if (drv.isFixedOutput()) {
|
||||||
DerivationOutputs::const_iterator i = drv.outputs.begin();
|
DerivationOutputs::const_iterator i = drv.outputs.begin();
|
||||||
return hashString(htSHA256, "fixed:out:"
|
return hashString(htSHA256, "fixed:out:"
|
||||||
+ i->second.hashAlgo + ":"
|
+ i->second.hashAlgo + ":"
|
||||||
|
@ -259,7 +300,7 @@ Hash hashDerivationModulo(StoreAPI & store, Derivation drv)
|
||||||
}
|
}
|
||||||
drv.inputDrvs = inputs2;
|
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;
|
PathSet paths;
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : outputs)
|
||||||
paths.insert(i.second.path);
|
paths.insert(i.second.path);
|
||||||
return paths;
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,11 +50,33 @@ struct BasicDerivation
|
||||||
StringPairs env;
|
StringPairs env;
|
||||||
|
|
||||||
virtual ~BasicDerivation() { };
|
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
|
struct Derivation : BasicDerivation
|
||||||
{
|
{
|
||||||
DerivationInputs inputDrvs; /* inputs that are sub-derivations */
|
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. */
|
/* 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);
|
const Derivation & drv, const string & name, bool repair = false);
|
||||||
|
|
||||||
/* Read a derivation from a file. */
|
/* Read a derivation from a file. */
|
||||||
Derivation readDerivation(const Path & drvPath);
|
Derivation readDerivation(const Path & drvPath);
|
||||||
|
|
||||||
/* Print a derivation. */
|
/* Check whether a file name ends with the extension for
|
||||||
string unparseDerivation(const Derivation & drv);
|
|
||||||
|
|
||||||
/* Check whether a file name ends with the extensions for
|
|
||||||
derivations. */
|
derivations. */
|
||||||
bool isDerivation(const string & fileName);
|
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);
|
Hash hashDerivationModulo(StoreAPI & store, Derivation drv);
|
||||||
|
|
||||||
/* Memoisation of hashDerivationModulo(). */
|
/* Memoisation of hashDerivationModulo(). */
|
||||||
typedef std::map<Path, Hash> DrvHashes;
|
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
|
/* Split a string specifying a derivation and a set of outputs
|
||||||
(/nix/store/hash-foo!out1,out2,...) into the derivation path and
|
(/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);
|
bool wantOutput(const string & output, const std::set<string> & wanted);
|
||||||
|
|
||||||
PathSet outputPaths(const BasicDerivation & drv);
|
|
||||||
|
|
||||||
struct Source;
|
struct Source;
|
||||||
struct Sink;
|
struct Sink;
|
||||||
|
|
||||||
|
|
|
@ -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";
|
Path cacheDir = getEnv("XDG_CACHE_HOME", getEnv("HOME", "") + "/.cache") + "/nix/tarballs";
|
||||||
createDirs(cacheDir);
|
createDirs(cacheDir);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -18,9 +19,11 @@ struct DownloadResult
|
||||||
string data, etag;
|
string data, etag;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class StoreAPI;
|
||||||
|
|
||||||
DownloadResult downloadFile(string url, const DownloadOptions & options);
|
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)
|
MakeError(DownloadError, Error)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
#include "derivations.hh"
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
#include "misc.hh"
|
|
||||||
#include "local-store.hh"
|
#include "local-store.hh"
|
||||||
|
|
||||||
#include <functional>
|
#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)
|
const Path & _gcRoot, bool indirect, bool allowOutsideRootsDir)
|
||||||
{
|
{
|
||||||
Path storePath(canonPath(_storePath));
|
Path storePath(canonPath(_storePath));
|
||||||
|
@ -101,7 +101,7 @@ Path addPermRoot(StoreAPI & store, const Path & _storePath,
|
||||||
if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
|
if (pathExists(gcRoot) && (!isLink(gcRoot) || !isInStore(readLink(gcRoot))))
|
||||||
throw Error(format("cannot create symlink ‘%1%’; already exists") % gcRoot);
|
throw Error(format("cannot create symlink ‘%1%’; already exists") % gcRoot);
|
||||||
makeSymlink(gcRoot, storePath);
|
makeSymlink(gcRoot, storePath);
|
||||||
store.addIndirectRoot(gcRoot);
|
store->addIndirectRoot(gcRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
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
|
check if the root is in a directory in or linked from the
|
||||||
gcroots directory. */
|
gcroots directory. */
|
||||||
if (settings.checkRootReachability) {
|
if (settings.checkRootReachability) {
|
||||||
Roots roots = store.findRoots();
|
Roots roots = store->findRoots();
|
||||||
if (roots.find(gcRoot) == roots.end())
|
if (roots.find(gcRoot) == roots.end())
|
||||||
printMsg(lvlError,
|
printMsg(lvlError,
|
||||||
format(
|
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
|
/* Grab the global GC root, causing us to block while a GC is in
|
||||||
progress. This prevents the set of permanent roots from
|
progress. This prevents the set of permanent roots from
|
||||||
increasing while a GC is in progress. */
|
increasing while a GC is in progress. */
|
||||||
store.syncWithGC();
|
store->syncWithGC();
|
||||||
|
|
||||||
return gcRoot;
|
return gcRoot;
|
||||||
}
|
}
|
||||||
|
@ -260,19 +260,16 @@ static void readTempRoots(PathSet & tempRoots, FDs & fds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void foundRoot(StoreAPI & store,
|
void LocalStore::findRoots(const Path & path, unsigned char type, Roots & roots)
|
||||||
const Path & path, const Path & target, Roots & roots)
|
|
||||||
{
|
{
|
||||||
Path storePath = toStorePath(target);
|
auto foundRoot = [&](const Path & path, const Path & target) {
|
||||||
if (store.isValidPath(storePath))
|
Path storePath = toStorePath(target);
|
||||||
roots[path] = storePath;
|
if (isValidPath(storePath))
|
||||||
else
|
roots[path] = storePath;
|
||||||
printMsg(lvlInfo, format("skipping invalid root from ‘%1%’ to ‘%2%’") % 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 {
|
try {
|
||||||
|
|
||||||
if (type == DT_UNKNOWN)
|
if (type == DT_UNKNOWN)
|
||||||
|
@ -280,13 +277,13 @@ static void findRoots(StoreAPI & store, const Path & path, unsigned char type, R
|
||||||
|
|
||||||
if (type == DT_DIR) {
|
if (type == DT_DIR) {
|
||||||
for (auto & i : readDirectory(path))
|
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) {
|
else if (type == DT_LNK) {
|
||||||
Path target = readLink(path);
|
Path target = readLink(path);
|
||||||
if (isInStore(target))
|
if (isInStore(target))
|
||||||
foundRoot(store, path, target, roots);
|
foundRoot(path, target);
|
||||||
|
|
||||||
/* Handle indirect roots. */
|
/* Handle indirect roots. */
|
||||||
else {
|
else {
|
||||||
|
@ -300,14 +297,14 @@ static void findRoots(StoreAPI & store, const Path & path, unsigned char type, R
|
||||||
struct stat st2 = lstat(target);
|
struct stat st2 = lstat(target);
|
||||||
if (!S_ISLNK(st2.st_mode)) return;
|
if (!S_ISLNK(st2.st_mode)) return;
|
||||||
Path target2 = readLink(target);
|
Path target2 = readLink(target);
|
||||||
if (isInStore(target2)) foundRoot(store, target, target2, roots);
|
if (isInStore(target2)) foundRoot(target, target2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (type == DT_REG) {
|
else if (type == DT_REG) {
|
||||||
Path storePath = settings.nixStore + "/" + baseNameOf(path);
|
Path storePath = settings.nixStore + "/" + baseNameOf(path);
|
||||||
if (store.isValidPath(storePath))
|
if (isValidPath(storePath))
|
||||||
roots[path] = storePath;
|
roots[path] = storePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,16 +325,16 @@ Roots LocalStore::findRoots()
|
||||||
Roots roots;
|
Roots roots;
|
||||||
|
|
||||||
/* Process direct roots in {gcroots,manifests,profiles}. */
|
/* 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"))
|
if (pathExists(settings.nixStateDir + "/manifests"))
|
||||||
nix::findRoots(*this, settings.nixStateDir + "/manifests", DT_UNKNOWN, roots);
|
findRoots(settings.nixStateDir + "/manifests", DT_UNKNOWN, roots);
|
||||||
nix::findRoots(*this, settings.nixStateDir + "/profiles", DT_UNKNOWN, roots);
|
findRoots(settings.nixStateDir + "/profiles", DT_UNKNOWN, roots);
|
||||||
|
|
||||||
return roots;
|
return roots;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
|
void LocalStore::findRuntimeRoots(PathSet & roots)
|
||||||
{
|
{
|
||||||
Path rootFinder = getEnv("NIX_ROOT_FINDER",
|
Path rootFinder = getEnv("NIX_ROOT_FINDER",
|
||||||
settings.nixLibexecDir + "/nix/find-runtime-roots.pl");
|
settings.nixLibexecDir + "/nix/find-runtime-roots.pl");
|
||||||
|
@ -353,7 +350,7 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots)
|
||||||
for (auto & i : paths)
|
for (auto & i : paths)
|
||||||
if (isInStore(i)) {
|
if (isInStore(i)) {
|
||||||
Path path = toStorePath(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);
|
debug(format("got additional root ‘%1%’") % path);
|
||||||
roots.insert(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
|
to add running programs to the set of roots (to prevent them
|
||||||
from being garbage collected). */
|
from being garbage collected). */
|
||||||
if (!options.ignoreLiveness)
|
if (!options.ignoreLiveness)
|
||||||
addAdditionalRoots(*this, state.roots);
|
findRuntimeRoots(state.roots);
|
||||||
|
|
||||||
/* Read the temporary roots. This acquires read locks on all
|
/* Read the temporary roots. This acquires read locks on all
|
||||||
per-process temporary root files. So after this point no paths
|
per-process temporary root files. So after this point no paths
|
||||||
|
|
|
@ -655,7 +655,7 @@ void LocalStore::checkDerivationOutputs(const Path & drvPath, const Derivation &
|
||||||
assert(isDerivation(drvName));
|
assert(isDerivation(drvName));
|
||||||
drvName = string(drvName, 0, drvName.size() - drvExtension.size());
|
drvName = string(drvName, 0, drvName.size() - drvExtension.size());
|
||||||
|
|
||||||
if (isFixedOutputDrv(drv)) {
|
if (drv.isFixedOutput()) {
|
||||||
DerivationOutputs::const_iterator out = drv.outputs.find("out");
|
DerivationOutputs::const_iterator out = drv.outputs.find("out");
|
||||||
if (out == drv.outputs.end())
|
if (out == drv.outputs.end())
|
||||||
throw Error(format("derivation ‘%1%’ does not have an output named ‘out’") % drvPath);
|
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
|
error if a cycle is detected and roll back the
|
||||||
transaction. Cycles can only occur when a derivation
|
transaction. Cycles can only occur when a derivation
|
||||||
has multiple outputs. */
|
has multiple outputs. */
|
||||||
topoSortPaths(*this, paths);
|
topoSortPaths(paths);
|
||||||
|
|
||||||
txn.commit();
|
txn.commit();
|
||||||
} end_retry_sqlite;
|
} end_retry_sqlite;
|
||||||
|
|
|
@ -303,6 +303,10 @@ private:
|
||||||
|
|
||||||
int openGCLock(LockType lockType);
|
int openGCLock(LockType lockType);
|
||||||
|
|
||||||
|
void findRoots(const Path & path, unsigned char type, Roots & roots);
|
||||||
|
|
||||||
|
void findRuntimeRoots(PathSet & roots);
|
||||||
|
|
||||||
void removeUnusedLinks(const GCState & state);
|
void removeUnusedLinks(const GCState & state);
|
||||||
|
|
||||||
void startSubstituter(const Path & substituter,
|
void startSubstituter(const Path & substituter,
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
#include "misc.hh"
|
#include "derivations.hh"
|
||||||
#include "store-api.hh"
|
|
||||||
#include "local-store.hh"
|
|
||||||
#include "globals.hh"
|
#include "globals.hh"
|
||||||
|
#include "local-store.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
Derivation derivationFromPath(StoreAPI & store, const Path & drvPath)
|
Derivation StoreAPI::derivationFromPath(const Path & drvPath)
|
||||||
{
|
{
|
||||||
assertStorePath(drvPath);
|
assertStorePath(drvPath);
|
||||||
store.ensurePath(drvPath);
|
ensurePath(drvPath);
|
||||||
return readDerivation(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)
|
PathSet & paths, bool flipDirection, bool includeOutputs, bool includeDerivers)
|
||||||
{
|
{
|
||||||
if (paths.find(path) != paths.end()) return;
|
if (paths.find(path) != paths.end()) return;
|
||||||
|
@ -24,50 +24,42 @@ void computeFSClosure(StoreAPI & store, const Path & path,
|
||||||
PathSet edges;
|
PathSet edges;
|
||||||
|
|
||||||
if (flipDirection) {
|
if (flipDirection) {
|
||||||
store.queryReferrers(path, edges);
|
queryReferrers(path, edges);
|
||||||
|
|
||||||
if (includeOutputs) {
|
if (includeOutputs) {
|
||||||
PathSet derivers = store.queryValidDerivers(path);
|
PathSet derivers = queryValidDerivers(path);
|
||||||
for (auto & i : derivers)
|
for (auto & i : derivers)
|
||||||
edges.insert(i);
|
edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDerivers && isDerivation(path)) {
|
if (includeDerivers && isDerivation(path)) {
|
||||||
PathSet outputs = store.queryDerivationOutputs(path);
|
PathSet outputs = queryDerivationOutputs(path);
|
||||||
for (auto & i : outputs)
|
for (auto & i : outputs)
|
||||||
if (store.isValidPath(i) && store.queryDeriver(i) == path)
|
if (isValidPath(i) && queryDeriver(i) == path)
|
||||||
edges.insert(i);
|
edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
store.queryReferences(path, edges);
|
queryReferences(path, edges);
|
||||||
|
|
||||||
if (includeOutputs && isDerivation(path)) {
|
if (includeOutputs && isDerivation(path)) {
|
||||||
PathSet outputs = store.queryDerivationOutputs(path);
|
PathSet outputs = queryDerivationOutputs(path);
|
||||||
for (auto & i : outputs)
|
for (auto & i : outputs)
|
||||||
if (store.isValidPath(i)) edges.insert(i);
|
if (isValidPath(i)) edges.insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeDerivers) {
|
if (includeDerivers) {
|
||||||
Path deriver = store.queryDeriver(path);
|
Path deriver = queryDeriver(path);
|
||||||
if (store.isValidPath(deriver)) edges.insert(deriver);
|
if (isValidPath(deriver)) edges.insert(deriver);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto & i : edges)
|
for (auto & i : edges)
|
||||||
computeFSClosure(store, i, paths, flipDirection, includeOutputs, includeDerivers);
|
computeFSClosure(i, paths, flipDirection, includeOutputs, includeDerivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Path findOutput(const Derivation & drv, string id)
|
void StoreAPI::queryMissing(const PathSet & targets,
|
||||||
{
|
|
||||||
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,
|
|
||||||
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
|
PathSet & willBuild, PathSet & willSubstitute, PathSet & unknown,
|
||||||
unsigned long long & downloadSize, unsigned long long & narSize)
|
unsigned long long & downloadSize, unsigned long long & narSize)
|
||||||
{
|
{
|
||||||
|
@ -105,27 +97,27 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
||||||
|
|
||||||
if (isDerivation(i2.first)) {
|
if (isDerivation(i2.first)) {
|
||||||
if (!store.isValidPath(i2.first)) {
|
if (!isValidPath(i2.first)) {
|
||||||
// FIXME: we could try to substitute p.
|
// FIXME: we could try to substitute p.
|
||||||
unknown.insert(i);
|
unknown.insert(i);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Derivation drv = derivationFromPath(store, i2.first);
|
Derivation drv = derivationFromPath(i2.first);
|
||||||
|
|
||||||
PathSet invalid;
|
PathSet invalid;
|
||||||
for (auto & j : drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
if (wantOutput(j.first, i2.second)
|
if (wantOutput(j.first, i2.second)
|
||||||
&& !store.isValidPath(j.second.path))
|
&& !isValidPath(j.second.path))
|
||||||
invalid.insert(j.second.path);
|
invalid.insert(j.second.path);
|
||||||
if (invalid.empty()) continue;
|
if (invalid.empty()) continue;
|
||||||
|
|
||||||
todoDrv.insert(i);
|
todoDrv.insert(i);
|
||||||
if (settings.useSubstitutes && substitutesAllowed(drv))
|
if (settings.useSubstitutes && drv.substitutesAllowed())
|
||||||
query.insert(invalid.begin(), invalid.end());
|
query.insert(invalid.begin(), invalid.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else {
|
||||||
if (store.isValidPath(i)) continue;
|
if (isValidPath(i)) continue;
|
||||||
query.insert(i);
|
query.insert(i);
|
||||||
todoNonDrv.insert(i);
|
todoNonDrv.insert(i);
|
||||||
}
|
}
|
||||||
|
@ -134,20 +126,20 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
todo.clear();
|
todo.clear();
|
||||||
|
|
||||||
SubstitutablePathInfos infos;
|
SubstitutablePathInfos infos;
|
||||||
store.querySubstitutablePathInfos(query, infos);
|
querySubstitutablePathInfos(query, infos);
|
||||||
|
|
||||||
for (auto & i : todoDrv) {
|
for (auto & i : todoDrv) {
|
||||||
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
DrvPathWithOutputs i2 = parseDrvPathWithOutputs(i);
|
||||||
|
|
||||||
// FIXME: cache this
|
// FIXME: cache this
|
||||||
Derivation drv = derivationFromPath(store, i2.first);
|
Derivation drv = derivationFromPath(i2.first);
|
||||||
|
|
||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
bool mustBuild = false;
|
bool mustBuild = false;
|
||||||
if (settings.useSubstitutes && substitutesAllowed(drv)) {
|
if (settings.useSubstitutes && drv.substitutesAllowed()) {
|
||||||
for (auto & j : drv.outputs) {
|
for (auto & j : drv.outputs) {
|
||||||
if (!wantOutput(j.first, i2.second)) continue;
|
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())
|
if (infos.find(j.second.path) == infos.end())
|
||||||
mustBuild = true;
|
mustBuild = true;
|
||||||
else
|
else
|
||||||
|
@ -181,38 +173,38 @@ void queryMissing(StoreAPI & store, const PathSet & targets,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void dfsVisit(StoreAPI & store, const PathSet & paths,
|
Paths StoreAPI::topoSortPaths(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 sorted;
|
Paths sorted;
|
||||||
PathSet visited, parents;
|
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)
|
for (auto & i : paths)
|
||||||
dfsVisit(store, paths, i, visited, sorted, parents);
|
dfsVisit(i);
|
||||||
|
|
||||||
return sorted;
|
return sorted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
/* The new generation number should be higher than old the
|
||||||
previous ones. */
|
previous ones. */
|
||||||
|
@ -108,7 +108,7 @@ Path createGeneration(Path profile, Path outPath)
|
||||||
user environment etc. we've just built. */
|
user environment etc. we've just built. */
|
||||||
Path generation;
|
Path generation;
|
||||||
makeName(profile, num + 1, generation);
|
makeName(profile, num + 1, generation);
|
||||||
addPermRoot(*store, outPath, generation, false, true);
|
addPermRoot(store, outPath, generation, false, true);
|
||||||
|
|
||||||
return generation;
|
return generation;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,9 @@ typedef list<Generation> Generations;
|
||||||
profile, sorted by generation number. */
|
profile, sorted by generation number. */
|
||||||
Generations findGenerations(Path profile, int & curGen);
|
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);
|
void deleteGeneration(const Path & profile, unsigned int gen);
|
||||||
|
|
||||||
|
|
|
@ -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)
|
bool sign, Sink & sink)
|
||||||
{
|
{
|
||||||
for (auto & i : paths) {
|
for (auto & i : paths) {
|
||||||
sink << 1;
|
sink << 1;
|
||||||
store.exportPath(i, sign, sink);
|
exportPath(i, sign, sink);
|
||||||
}
|
}
|
||||||
sink << 0;
|
sink << 0;
|
||||||
}
|
}
|
||||||
|
@ -306,10 +306,7 @@ void exportPaths(StoreAPI & store, const Paths & paths,
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<StoreAPI> store;
|
ref<StoreAPI> openStore(bool reserveSpace)
|
||||||
|
|
||||||
|
|
||||||
std::shared_ptr<StoreAPI> openStore(bool reserveSpace)
|
|
||||||
{
|
{
|
||||||
enum { mDaemon, mLocal, mAuto } mode;
|
enum { mDaemon, mLocal, mAuto } mode;
|
||||||
|
|
||||||
|
@ -325,8 +322,8 @@ std::shared_ptr<StoreAPI> openStore(bool reserveSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mode == mDaemon
|
return mode == mDaemon
|
||||||
? (std::shared_ptr<StoreAPI>) std::make_shared<RemoteStore>()
|
? make_ref<StoreAPI, RemoteStore>()
|
||||||
: std::make_shared<LocalStore>(reserveSpace);
|
: make_ref<StoreAPI, LocalStore>(reserveSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -132,6 +132,7 @@ struct BuildResult
|
||||||
|
|
||||||
|
|
||||||
struct BasicDerivation;
|
struct BasicDerivation;
|
||||||
|
struct Derivation;
|
||||||
|
|
||||||
|
|
||||||
class StoreAPI
|
class StoreAPI
|
||||||
|
@ -214,6 +215,10 @@ public:
|
||||||
virtual void exportPath(const Path & path, bool sign,
|
virtual void exportPath(const Path & path, bool sign,
|
||||||
Sink & sink) = 0;
|
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
|
/* Import a sequence of NAR dumps created by exportPaths() into
|
||||||
the Nix store. */
|
the Nix store. */
|
||||||
virtual Paths importPaths(bool requireSignature, Source & source) = 0;
|
virtual Paths importPaths(bool requireSignature, Source & source) = 0;
|
||||||
|
@ -298,6 +303,35 @@ public:
|
||||||
/* Check the integrity of the Nix store. Returns true if errors
|
/* Check the integrity of the Nix store. Returns true if errors
|
||||||
remain. */
|
remain. */
|
||||||
virtual bool verifyStore(bool checkContents, bool repair) = 0;
|
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. */
|
/* 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);
|
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
|
/* Factory method: open the Nix database, either through the local or
|
||||||
remote implementation. */
|
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
|
/* 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);
|
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(SubstError, Error)
|
||||||
MakeError(BuildError, Error) /* denotes a permanent build failure */
|
MakeError(BuildError, Error) /* denotes a permanent build failure */
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <boost/format.hpp>
|
#include <boost/format.hpp>
|
||||||
|
|
||||||
|
@ -96,4 +97,70 @@ typedef enum {
|
||||||
} Verbosity;
|
} Verbosity;
|
||||||
|
|
||||||
|
|
||||||
|
/* A simple non-nullable reference-counted pointer. Actually a wrapper
|
||||||
|
around std::shared_ptr that prevents non-null constructions. */
|
||||||
|
template<typename T>
|
||||||
|
class ref
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
|
||||||
|
std::shared_ptr<T> p;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
ref<T>(const ref<T> & r)
|
||||||
|
: p(r.p)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
explicit ref<T>(const std::shared_ptr<T> & 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<T> ()
|
||||||
|
{
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
template<typename T2, typename... Args>
|
||||||
|
friend ref<T2>
|
||||||
|
make_ref(Args&&... args);
|
||||||
|
|
||||||
|
template<typename T2, typename T3, typename... Args>
|
||||||
|
friend ref<T2>
|
||||||
|
make_ref(Args&&... args);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
inline ref<T>
|
||||||
|
make_ref(Args&&... args)
|
||||||
|
{
|
||||||
|
auto p = std::make_shared<T>(std::forward<Args>(args)...);
|
||||||
|
return ref<T>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T, typename T2, typename... Args>
|
||||||
|
inline ref<T>
|
||||||
|
make_ref(Args&&... args)
|
||||||
|
{
|
||||||
|
auto p = std::make_shared<T2>(std::forward<Args>(args)...);
|
||||||
|
return ref<T>(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -413,4 +413,14 @@ string base64Encode(const string & s);
|
||||||
string base64Decode(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 <class T>
|
||||||
|
string get(const T & map, const string & key, const string & def = "")
|
||||||
|
{
|
||||||
|
auto i = map.find(key);
|
||||||
|
return i == map.end() ? def : i->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
// Run the actual garbage collector.
|
// Run the actual garbage collector.
|
||||||
if (!dryRun) {
|
if (!dryRun) {
|
||||||
store = openStore(false);
|
auto store = openStore(false);
|
||||||
options.action = GCOptions::gcDeleteDead;
|
options.action = GCOptions::gcDeleteDead;
|
||||||
GCResults results;
|
GCResults results;
|
||||||
PrintFreed freed(true, results);
|
PrintFreed freed(true, results);
|
||||||
|
|
|
@ -149,7 +149,7 @@ struct SavingSourceAdapter : Source
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void performOp(bool trusted, unsigned int clientVersion,
|
static void performOp(ref<LocalStore> store, bool trusted, unsigned int clientVersion,
|
||||||
Source & from, Sink & to, unsigned int op)
|
Source & from, Sink & to, unsigned int op)
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
@ -278,8 +278,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
||||||
|
|
||||||
startWork();
|
startWork();
|
||||||
if (!savedRegular.regular) throw Error("regular file expected");
|
if (!savedRegular.regular) throw Error("regular file expected");
|
||||||
Path path = dynamic_cast<LocalStore *>(store.get())
|
Path path = store->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
|
||||||
->addToStoreFromDump(recursive ? savedNAR.s : savedRegular.s, baseName, recursive, hashAlgo);
|
|
||||||
stopWork();
|
stopWork();
|
||||||
|
|
||||||
to << path;
|
to << path;
|
||||||
|
@ -583,56 +582,56 @@ static void processConnection(bool trusted)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Open the store. */
|
/* Open the store. */
|
||||||
store = std::shared_ptr<StoreAPI>(new LocalStore(reserveSpace));
|
auto store = make_ref<LocalStore>(reserveSpace);
|
||||||
|
|
||||||
stopWork();
|
stopWork();
|
||||||
to.flush();
|
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) {
|
} catch (Error & e) {
|
||||||
stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
|
stopWork(false, e.msg(), GET_PROTOCOL_MINOR(clientVersion) >= 8 ? 1 : 0);
|
||||||
to.flush();
|
to.flush();
|
||||||
return;
|
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) {
|
while (1) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
/* Important: the server process *cannot* open the SQLite
|
|
||||||
database, because it doesn't like forks very much. */
|
|
||||||
assert(!store);
|
|
||||||
|
|
||||||
/* Accept a connection. */
|
/* Accept a connection. */
|
||||||
struct sockaddr_un remoteAddr;
|
struct sockaddr_un remoteAddr;
|
||||||
socklen_t remoteAddrLen = sizeof(remoteAddr);
|
socklen_t remoteAddrLen = sizeof(remoteAddr);
|
||||||
|
|
|
@ -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 "attr-path.hh"
|
||||||
#include "common-opts.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 "store-api.hh"
|
||||||
#include "user-env.hh"
|
#include "user-env.hh"
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "value-to-json.hh"
|
#include "value-to-json.hh"
|
||||||
|
#include "xml-writer.hh"
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
@ -223,8 +223,8 @@ static int comparePriorities(EvalState & state, DrvInfo & drv1, DrvInfo & drv2)
|
||||||
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
static bool isPrebuilt(EvalState & state, DrvInfo & elem)
|
||||||
{
|
{
|
||||||
Path path = elem.queryOutPath();
|
Path path = elem.queryOutPath();
|
||||||
if (store->isValidPath(path)) return true;
|
if (state.store->isValidPath(path)) return true;
|
||||||
PathSet ps = store->querySubstitutablePaths(singleton<PathSet>(path));
|
PathSet ps = state.store->querySubstitutablePaths(singleton<PathSet>(path));
|
||||||
return ps.find(path) != ps.end();
|
return ps.find(path) != ps.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,7 +398,7 @@ static void queryInstSources(EvalState & state,
|
||||||
|
|
||||||
if (isDerivation(path)) {
|
if (isDerivation(path)) {
|
||||||
elem.setDrvPath(path);
|
elem.setDrvPath(path);
|
||||||
elem.setOutPath(findOutput(derivationFromPath(*store, path), "out"));
|
elem.setOutPath(state.store->derivationFromPath(path).findOutput("out"));
|
||||||
if (name.size() >= drvExtension.size() &&
|
if (name.size() >= drvExtension.size() &&
|
||||||
string(name, name.size() - drvExtension.size()) == drvExtension)
|
string(name, name.size() - drvExtension.size()) == drvExtension)
|
||||||
name = string(name, 0, name.size() - drvExtension.size());
|
name = string(name, 0, name.size() - drvExtension.size());
|
||||||
|
@ -445,7 +445,7 @@ static void printMissing(EvalState & state, DrvInfos & elems)
|
||||||
targets.insert(i.queryOutPath());
|
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() != "") {
|
if (drv.queryDrvPath() != "") {
|
||||||
PathSet paths = singleton<PathSet>(drv.queryDrvPath());
|
PathSet paths = singleton<PathSet>(drv.queryDrvPath());
|
||||||
printMissing(*store, paths);
|
printMissing(globals.state->store, paths);
|
||||||
if (globals.dryRun) return;
|
if (globals.dryRun) return;
|
||||||
store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal);
|
globals.state->store->buildPaths(paths, globals.state->repair ? bmRepair : bmNormal);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printMissing(*store, singleton<PathSet>(drv.queryOutPath()));
|
printMissing(globals.state->store, singleton<PathSet>(drv.queryOutPath()));
|
||||||
if (globals.dryRun) return;
|
if (globals.dryRun) return;
|
||||||
store->ensurePath(drv.queryOutPath());
|
globals.state->store->ensurePath(drv.queryOutPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(format("switching to new user environment"));
|
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);
|
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);
|
printMsg(lvlTalkative, format("skipping derivation named ‘%1%’ which gives an assertion failure") % i.name);
|
||||||
i.setFailed();
|
i.setFailed();
|
||||||
}
|
}
|
||||||
validPaths = store->queryValidPaths(paths);
|
validPaths = globals.state->store->queryValidPaths(paths);
|
||||||
substitutablePaths = store->querySubstitutablePaths(paths);
|
substitutablePaths = globals.state->store->querySubstitutablePaths(paths);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1394,9 +1394,9 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
if (!op) throw UsageError("no operation specified");
|
if (!op) throw UsageError("no operation specified");
|
||||||
|
|
||||||
store = openStore();
|
auto store = openStore();
|
||||||
|
|
||||||
globals.state = std::shared_ptr<EvalState>(new EvalState(searchPath));
|
globals.state = std::shared_ptr<EvalState>(new EvalState(searchPath, store));
|
||||||
globals.state->repair = repair;
|
globals.state->repair = repair;
|
||||||
|
|
||||||
if (file != "")
|
if (file != "")
|
||||||
|
|
|
@ -38,7 +38,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
drvsToBuild.insert(i.queryDrvPath());
|
drvsToBuild.insert(i.queryDrvPath());
|
||||||
|
|
||||||
debug(format("building user environment dependencies"));
|
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. */
|
/* Construct the whole top level derivation. */
|
||||||
PathSet references;
|
PathSet references;
|
||||||
|
@ -76,8 +76,8 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
store->addTempRoot(j.second);
|
state.store->addTempRoot(j.second);
|
||||||
store->ensurePath(j.second);
|
state.store->ensurePath(j.second);
|
||||||
|
|
||||||
references.insert(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
|
/* Also write a copy of the list of user environment elements to
|
||||||
the store; we need it for future modifications of the
|
the store; we need it for future modifications of the
|
||||||
environment. */
|
environment. */
|
||||||
Path manifestFile = store->addTextToStore("env-manifest.nix",
|
Path manifestFile = state.store->addTextToStore("env-manifest.nix",
|
||||||
(format("%1%") % manifest).str(), references);
|
(format("%1%") % manifest).str(), references);
|
||||||
|
|
||||||
/* Get the environment builder expression. */
|
/* Get the environment builder expression. */
|
||||||
|
@ -128,7 +128,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
|
|
||||||
/* Realise the resulting store expression. */
|
/* Realise the resulting store expression. */
|
||||||
debug("building user environment");
|
debug("building user environment");
|
||||||
store->buildPaths(singleton<PathSet>(topLevelDrv), state.repair ? bmRepair : bmNormal);
|
state.store->buildPaths(singleton<PathSet>(topLevelDrv), state.repair ? bmRepair : bmNormal);
|
||||||
|
|
||||||
/* Switch the current user environment to the output path. */
|
/* Switch the current user environment to the output path. */
|
||||||
PathLocks lock;
|
PathLocks lock;
|
||||||
|
@ -141,7 +141,7 @@ bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(format("switching to new user environment"));
|
debug(format("switching to new user environment"));
|
||||||
Path generation = createGeneration(profile, topLevelOut);
|
Path generation = createGeneration(state.store, profile, topLevelOut);
|
||||||
switchLink(profile, generation);
|
switchLink(profile, generation);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
#include "common-opts.hh"
|
#include "common-opts.hh"
|
||||||
#include "misc.hh"
|
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -33,7 +32,7 @@ static bool indirectRoot = false;
|
||||||
enum OutputKind { okPlain, okXML, okJSON };
|
enum OutputKind { okPlain, okXML, okJSON };
|
||||||
|
|
||||||
|
|
||||||
void processExpr(EvalState & state, const Strings & attrPaths,
|
void processExpr(ref<StoreAPI> store, EvalState & state, const Strings & attrPaths,
|
||||||
bool parseOnly, bool strict, Bindings & autoArgs,
|
bool parseOnly, bool strict, Bindings & autoArgs,
|
||||||
bool evalOnly, OutputKind output, bool location, Expr * e)
|
bool evalOnly, OutputKind output, bool location, Expr * e)
|
||||||
{
|
{
|
||||||
|
@ -80,7 +79,7 @@ void processExpr(EvalState & state, const Strings & attrPaths,
|
||||||
else {
|
else {
|
||||||
Path rootName = gcRoot;
|
Path rootName = gcRoot;
|
||||||
if (++rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
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 : "");
|
std::cout << format("%1%%2%\n") % drvPath % (outputName != "out" ? "!" + outputName : "");
|
||||||
}
|
}
|
||||||
|
@ -158,9 +157,9 @@ int main(int argc, char * * argv)
|
||||||
if (evalOnly && !wantsReadWrite)
|
if (evalOnly && !wantsReadWrite)
|
||||||
settings.readOnlyMode = true;
|
settings.readOnlyMode = true;
|
||||||
|
|
||||||
store = openStore();
|
auto store = openStore();
|
||||||
|
|
||||||
EvalState state(searchPath);
|
EvalState state(searchPath, store);
|
||||||
state.repair = repair;
|
state.repair = repair;
|
||||||
|
|
||||||
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
|
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
|
||||||
|
@ -178,7 +177,7 @@ int main(int argc, char * * argv)
|
||||||
|
|
||||||
if (readStdin) {
|
if (readStdin) {
|
||||||
Expr * e = parseStdin(state);
|
Expr * e = parseStdin(state);
|
||||||
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(store, state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
} else if (files.empty() && !fromArgs)
|
} else if (files.empty() && !fromArgs)
|
||||||
files.push_back("./default.nix");
|
files.push_back("./default.nix");
|
||||||
|
@ -187,7 +186,7 @@ int main(int argc, char * * argv)
|
||||||
Expr * e = fromArgs
|
Expr * e = fromArgs
|
||||||
? state.parseExprFromString(i, absPath("."))
|
? state.parseExprFromString(i, absPath("."))
|
||||||
: state.parseExprFromFile(resolveExprPath(lookupFileArg(state, i)));
|
: state.parseExprFromFile(resolveExprPath(lookupFileArg(state, i)));
|
||||||
processExpr(state, attrPaths, parseOnly, strict, autoArgs,
|
processExpr(store, state, attrPaths, parseOnly, strict, autoArgs,
|
||||||
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
evalOnly, outputKind, xmlOutputSourceLocation, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,8 +91,8 @@ int main(int argc, char * * argv)
|
||||||
if (args.size() > 2)
|
if (args.size() > 2)
|
||||||
throw UsageError("too many arguments");
|
throw UsageError("too many arguments");
|
||||||
|
|
||||||
store = openStore();
|
auto store = openStore();
|
||||||
EvalState state(searchPath);
|
EvalState state(searchPath, store);
|
||||||
|
|
||||||
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
|
Bindings & autoArgs(*evalAutoArgs(state, autoArgs_));
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ void printClosure(const Path & nePath, const StoreExpr & fs)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void printDotGraph(const PathSet & roots)
|
void printDotGraph(StoreAPI & store, const PathSet & roots)
|
||||||
{
|
{
|
||||||
PathSet workList(roots);
|
PathSet workList(roots);
|
||||||
PathSet doneSet;
|
PathSet doneSet;
|
||||||
|
@ -111,7 +111,7 @@ void printDotGraph(const PathSet & roots)
|
||||||
cout << makeNode(path, symbolicName(path), "#ff0000");
|
cout << makeNode(path, symbolicName(path), "#ff0000");
|
||||||
|
|
||||||
PathSet references;
|
PathSet references;
|
||||||
store->queryReferences(path, references);
|
store.queryReferences(path, references);
|
||||||
|
|
||||||
for (PathSet::iterator i = references.begin();
|
for (PathSet::iterator i = references.begin();
|
||||||
i != references.end(); ++i)
|
i != references.end(); ++i)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void printDotGraph(const PathSet & roots);
|
class StoreAPI;
|
||||||
|
|
||||||
|
void printDotGraph(StoreAPI & store, const PathSet & roots);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
#include "globals.hh"
|
|
||||||
#include "misc.hh"
|
|
||||||
#include "archive.hh"
|
#include "archive.hh"
|
||||||
#include "shared.hh"
|
#include "derivations.hh"
|
||||||
#include "dotgraph.hh"
|
#include "dotgraph.hh"
|
||||||
#include "xmlgraph.hh"
|
#include "globals.hh"
|
||||||
#include "local-store.hh"
|
#include "local-store.hh"
|
||||||
#include "util.hh"
|
|
||||||
#include "serve-protocol.hh"
|
|
||||||
#include "worker-protocol.hh"
|
|
||||||
#include "monitor-fd.hh"
|
#include "monitor-fd.hh"
|
||||||
|
#include "serve-protocol.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "util.hh"
|
||||||
|
#include "worker-protocol.hh"
|
||||||
|
#include "xmlgraph.hh"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
@ -37,6 +37,7 @@ static Path gcRoot;
|
||||||
static int rootNr = 0;
|
static int rootNr = 0;
|
||||||
static bool indirectRoot = false;
|
static bool indirectRoot = false;
|
||||||
static bool noOutput = false;
|
static bool noOutput = false;
|
||||||
|
static std::shared_ptr<StoreAPI> store;
|
||||||
|
|
||||||
|
|
||||||
LocalStore & ensureLocalStore()
|
LocalStore & ensureLocalStore()
|
||||||
|
@ -65,7 +66,7 @@ static PathSet realisePath(Path path, bool build = true)
|
||||||
|
|
||||||
if (isDerivation(p.first)) {
|
if (isDerivation(p.first)) {
|
||||||
if (build) store->buildPaths(singleton<PathSet>(path));
|
if (build) store->buildPaths(singleton<PathSet>(path));
|
||||||
Derivation drv = derivationFromPath(*store, p.first);
|
Derivation drv = store->derivationFromPath(p.first);
|
||||||
rootNr++;
|
rootNr++;
|
||||||
|
|
||||||
if (p.second.empty())
|
if (p.second.empty())
|
||||||
|
@ -83,7 +84,7 @@ static PathSet realisePath(Path path, bool build = true)
|
||||||
Path rootName = gcRoot;
|
Path rootName = gcRoot;
|
||||||
if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
||||||
if (i->first != "out") rootName += "-" + i->first;
|
if (i->first != "out") rootName += "-" + i->first;
|
||||||
outPath = addPermRoot(*store, outPath, rootName, indirectRoot);
|
outPath = addPermRoot(ref<StoreAPI>(store), outPath, rootName, indirectRoot);
|
||||||
}
|
}
|
||||||
outputs.insert(outPath);
|
outputs.insert(outPath);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ static PathSet realisePath(Path path, bool build = true)
|
||||||
Path rootName = gcRoot;
|
Path rootName = gcRoot;
|
||||||
rootNr++;
|
rootNr++;
|
||||||
if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
if (rootNr > 1) rootName += "-" + std::to_string(rootNr);
|
||||||
path = addPermRoot(*store, path, rootName, indirectRoot);
|
path = addPermRoot(ref<StoreAPI>(store), path, rootName, indirectRoot);
|
||||||
}
|
}
|
||||||
return singleton<PathSet>(path);
|
return singleton<PathSet>(path);
|
||||||
}
|
}
|
||||||
|
@ -129,7 +130,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
|
||||||
|
|
||||||
unsigned long long downloadSize, narSize;
|
unsigned long long downloadSize, narSize;
|
||||||
PathSet willBuild, willSubstitute, unknown;
|
PathSet willBuild, willSubstitute, unknown;
|
||||||
queryMissing(*store, PathSet(paths.begin(), paths.end()),
|
store->queryMissing(PathSet(paths.begin(), paths.end()),
|
||||||
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
|
||||||
if (ignoreUnknown) {
|
if (ignoreUnknown) {
|
||||||
|
@ -141,7 +142,7 @@ static void opRealise(Strings opFlags, Strings opArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settings.get("print-missing", true))
|
if (settings.get("print-missing", true))
|
||||||
printMissing(*store, willBuild, willSubstitute, unknown, downloadSize, narSize);
|
printMissing(ref<StoreAPI>(store), willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
|
|
||||||
if (dryRun) return;
|
if (dryRun) return;
|
||||||
|
|
||||||
|
@ -216,7 +217,7 @@ static PathSet maybeUseOutputs(const Path & storePath, bool useOutput, bool forc
|
||||||
{
|
{
|
||||||
if (forceRealise) realisePath(storePath);
|
if (forceRealise) realisePath(storePath);
|
||||||
if (useOutput && isDerivation(storePath)) {
|
if (useOutput && isDerivation(storePath)) {
|
||||||
Derivation drv = derivationFromPath(*store, storePath);
|
Derivation drv = store->derivationFromPath(storePath);
|
||||||
PathSet outputs;
|
PathSet outputs;
|
||||||
for (auto & i : drv.outputs)
|
for (auto & i : drv.outputs)
|
||||||
outputs.insert(i.second.path);
|
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)
|
closure(B). That is, if derivation A is an (possibly indirect)
|
||||||
input of B, then A is printed first. This has the effect of
|
input of B, then A is printed first. This has the effect of
|
||||||
flattening the tree, preventing deeply nested structures. */
|
flattening the tree, preventing deeply nested structures. */
|
||||||
Paths sorted = topoSortPaths(*store, references);
|
Paths sorted = store->topoSortPaths(references);
|
||||||
reverse(sorted.begin(), sorted.end());
|
reverse(sorted.begin(), sorted.end());
|
||||||
|
|
||||||
for (auto i = sorted.begin(); i != sorted.end(); ++i) {
|
for (auto i = sorted.begin(); i != sorted.end(); ++i) {
|
||||||
|
@ -318,7 +319,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
i = followLinksToStorePath(i);
|
i = followLinksToStorePath(i);
|
||||||
if (forceRealise) realisePath(i);
|
if (forceRealise) realisePath(i);
|
||||||
Derivation drv = derivationFromPath(*store, i);
|
Derivation drv = store->derivationFromPath(i);
|
||||||
for (auto & j : drv.outputs)
|
for (auto & j : drv.outputs)
|
||||||
cout << format("%1%\n") % j.second.path;
|
cout << format("%1%\n") % j.second.path;
|
||||||
}
|
}
|
||||||
|
@ -333,13 +334,13 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
PathSet ps = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
for (auto & j : ps) {
|
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 == qReferences) store->queryReferences(j, paths);
|
||||||
else if (query == qReferrers) store->queryReferrers(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();
|
for (Paths::reverse_iterator i = sorted.rbegin();
|
||||||
i != sorted.rend(); ++i)
|
i != sorted.rend(); ++i)
|
||||||
cout << format("%s\n") % *i;
|
cout << format("%s\n") % *i;
|
||||||
|
@ -357,7 +358,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
case qBinding:
|
case qBinding:
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
Path path = useDeriver(followLinksToStorePath(i));
|
Path path = useDeriver(followLinksToStorePath(i));
|
||||||
Derivation drv = derivationFromPath(*store, path);
|
Derivation drv = store->derivationFromPath(path);
|
||||||
StringPairs::iterator j = drv.env.find(bindingName);
|
StringPairs::iterator j = drv.env.find(bindingName);
|
||||||
if (j == drv.env.end())
|
if (j == drv.env.end())
|
||||||
throw Error(format("derivation ‘%1%’ has no environment binding named ‘%2%’")
|
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);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
roots.insert(paths.begin(), paths.end());
|
roots.insert(paths.begin(), paths.end());
|
||||||
}
|
}
|
||||||
printDotGraph(roots);
|
printDotGraph(*store, roots);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +405,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
roots.insert(paths.begin(), paths.end());
|
roots.insert(paths.begin(), paths.end());
|
||||||
}
|
}
|
||||||
printXmlGraph(roots);
|
printXmlGraph(*store, roots);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +420,7 @@ static void opQuery(Strings opFlags, Strings opArgs)
|
||||||
for (auto & i : opArgs) {
|
for (auto & i : opArgs) {
|
||||||
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
PathSet paths = maybeUseOutputs(followLinksToStorePath(i), useOutput, forceRealise);
|
||||||
for (auto & j : paths)
|
for (auto & j : paths)
|
||||||
computeFSClosure(*store, j, referrers, true,
|
store->computeFSClosure(j, referrers, true,
|
||||||
settings.gcKeepOutputs, settings.gcKeepDerivations);
|
settings.gcKeepOutputs, settings.gcKeepDerivations);
|
||||||
}
|
}
|
||||||
Roots roots = store->findRoots();
|
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");
|
if (opArgs.size() != 1) throw UsageError("‘--print-env’ requires one derivation store path");
|
||||||
|
|
||||||
Path drvPath = opArgs.front();
|
Path drvPath = opArgs.front();
|
||||||
Derivation drv = derivationFromPath(*store, drvPath);
|
Derivation drv = store->derivationFromPath(drvPath);
|
||||||
|
|
||||||
/* Print each environment variable in the derivation in a format
|
/* Print each environment variable in the derivation in a format
|
||||||
that can be sourced by the shell. */
|
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);
|
else throw UsageError(format("unknown flag ‘%1%’") % i);
|
||||||
|
|
||||||
FdSink sink(STDOUT_FILENO);
|
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());
|
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);
|
if (!isDerivation(path)) paths2.insert(path);
|
||||||
unsigned long long downloadSize, narSize;
|
unsigned long long downloadSize, narSize;
|
||||||
PathSet willBuild, willSubstitute, unknown;
|
PathSet willBuild, willSubstitute, unknown;
|
||||||
queryMissing(*store, PathSet(paths2.begin(), paths2.end()),
|
store->queryMissing(PathSet(paths2.begin(), paths2.end()),
|
||||||
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
willBuild, willSubstitute, unknown, downloadSize, narSize);
|
||||||
/* FIXME: should use ensurePath(), but it only
|
/* FIXME: should use ensurePath(), but it only
|
||||||
does one path at a time. */
|
does one path at a time. */
|
||||||
|
@ -941,9 +942,9 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
|
|
||||||
case cmdExportPaths: {
|
case cmdExportPaths: {
|
||||||
bool sign = readInt(in);
|
bool sign = readInt(in);
|
||||||
Paths sorted = topoSortPaths(*store, readStorePaths<PathSet>(in));
|
Paths sorted = store->topoSortPaths(readStorePaths<PathSet>(in));
|
||||||
reverse(sorted.begin(), sorted.end());
|
reverse(sorted.begin(), sorted.end());
|
||||||
exportPaths(*store, sorted, sign, out);
|
store->exportPaths(sorted, sign, out);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -988,7 +989,7 @@ static void opServe(Strings opFlags, Strings opArgs)
|
||||||
PathSet paths = readStorePaths<PathSet>(in);
|
PathSet paths = readStorePaths<PathSet>(in);
|
||||||
PathSet closure;
|
PathSet closure;
|
||||||
for (auto & i : paths)
|
for (auto & i : paths)
|
||||||
computeFSClosure(*store, i, closure, false, includeOutputs);
|
store->computeFSClosure(i, closure, false, includeOutputs);
|
||||||
out << closure;
|
out << closure;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 workList(roots);
|
||||||
PathSet doneSet;
|
PathSet doneSet;
|
||||||
|
@ -51,7 +51,7 @@ void printXmlGraph(const PathSet & roots)
|
||||||
cout << makeNode(path);
|
cout << makeNode(path);
|
||||||
|
|
||||||
PathSet references;
|
PathSet references;
|
||||||
store->queryReferences(path, references);
|
store.queryReferences(path, references);
|
||||||
|
|
||||||
for (PathSet::iterator i = references.begin();
|
for (PathSet::iterator i = references.begin();
|
||||||
i != references.end(); ++i)
|
i != references.end(); ++i)
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
void printXmlGraph(const PathSet & roots);
|
class StoreAPI;
|
||||||
|
|
||||||
|
void printXmlGraph(StoreAPI & store, const PathSet & roots);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue