* Store user environment manifests as a Nix expression in
$out/manifest.nix rather than as an ATerm. (Hm, I thought I committed this two days ago...)
This commit is contained in:
parent
f3b8833a48
commit
fe2d869e04
|
@ -160,4 +160,4 @@ while (scalar(keys %postponed) > 0) {
|
||||||
print STDERR "created $symlinks symlinks in user environment\n";
|
print STDERR "created $symlinks symlinks in user environment\n";
|
||||||
|
|
||||||
|
|
||||||
symlink($ENV{"manifest"}, "$out/manifest") or die "cannot create manifest";
|
symlink($ENV{"manifest"}, "$out/manifest.nix") or die "cannot create manifest";
|
||||||
|
|
|
@ -98,6 +98,7 @@ EvalState::EvalState()
|
||||||
, sType(symbols.create("type"))
|
, sType(symbols.create("type"))
|
||||||
, sMeta(symbols.create("meta"))
|
, sMeta(symbols.create("meta"))
|
||||||
, sName(symbols.create("name"))
|
, sName(symbols.create("name"))
|
||||||
|
, sSystem(symbols.create("system"))
|
||||||
, baseEnv(allocEnv(128))
|
, baseEnv(allocEnv(128))
|
||||||
, baseEnvDispl(0)
|
, baseEnvDispl(0)
|
||||||
, staticBaseEnv(false, 0)
|
, staticBaseEnv(false, 0)
|
||||||
|
@ -131,12 +132,13 @@ void EvalState::addPrimOp(const string & name,
|
||||||
unsigned int arity, PrimOp primOp)
|
unsigned int arity, PrimOp primOp)
|
||||||
{
|
{
|
||||||
Value v;
|
Value v;
|
||||||
|
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
||||||
v.type = tPrimOp;
|
v.type = tPrimOp;
|
||||||
v.primOp.arity = arity;
|
v.primOp.arity = arity;
|
||||||
v.primOp.fun = primOp;
|
v.primOp.fun = primOp;
|
||||||
|
v.primOp.name = strdup(name2.c_str());
|
||||||
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl;
|
||||||
baseEnv.values[baseEnvDispl++] = v;
|
baseEnv.values[baseEnvDispl++] = v;
|
||||||
string name2 = string(name, 0, 2) == "__" ? string(name, 2) : name;
|
|
||||||
(*baseEnv.values[0].attrs)[symbols.create(name2)] = v;
|
(*baseEnv.values[0].attrs)[symbols.create(name2)] = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +552,12 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v)
|
||||||
vArgs[n--] = arg->primOpApp.right;
|
vArgs[n--] = arg->primOpApp.right;
|
||||||
|
|
||||||
/* And call the primop. */
|
/* And call the primop. */
|
||||||
primOp->primOp.fun(*this, vArgs, v);
|
try {
|
||||||
|
primOp->primOp.fun(*this, vArgs, v);
|
||||||
|
} catch (Error & e) {
|
||||||
|
addErrorPrefix(e, "while evaluating the builtin function `%1%':\n", primOp->primOp.name);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
Value * v2 = allocValues(2);
|
Value * v2 = allocValues(2);
|
||||||
v2[0] = fun;
|
v2[0] = fun;
|
||||||
|
|
|
@ -92,6 +92,7 @@ struct Value
|
||||||
Value * val;
|
Value * val;
|
||||||
struct {
|
struct {
|
||||||
PrimOp fun;
|
PrimOp fun;
|
||||||
|
char * name;
|
||||||
unsigned int arity;
|
unsigned int arity;
|
||||||
} primOp;
|
} primOp;
|
||||||
struct {
|
struct {
|
||||||
|
@ -138,6 +139,14 @@ static inline void mkCopy(Value & v, Value & src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mkApp(Value & v, Value & left, Value & right)
|
||||||
|
{
|
||||||
|
v.type = tApp;
|
||||||
|
v.app.left = &left;
|
||||||
|
v.app.right = &right;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void mkString(Value & v, const char * s);
|
void mkString(Value & v, const char * s);
|
||||||
void mkString(Value & v, const string & s, const PathSet & context = PathSet());
|
void mkString(Value & v, const string & s, const PathSet & context = PathSet());
|
||||||
void mkPath(Value & v, const char * s);
|
void mkPath(Value & v, const char * s);
|
||||||
|
@ -162,7 +171,7 @@ public:
|
||||||
|
|
||||||
SymbolTable symbols;
|
SymbolTable symbols;
|
||||||
|
|
||||||
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName;
|
const Symbol sWith, sOutPath, sDrvPath, sType, sMeta, sName, sSystem;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SrcToStore srcToStore;
|
SrcToStore srcToStore;
|
||||||
|
|
|
@ -70,27 +70,6 @@ void DrvInfo::setMetaInfo(const MetaInfo & meta)
|
||||||
{
|
{
|
||||||
metaInfoRead = true;
|
metaInfoRead = true;
|
||||||
this->meta = meta;
|
this->meta = meta;
|
||||||
|
|
||||||
#if 0
|
|
||||||
Value * metaAttrs = state.allocValues(1);
|
|
||||||
foreach (MetaInfo::const_iterator, i, meta) {
|
|
||||||
Expr e;
|
|
||||||
switch (i->second.type) {
|
|
||||||
case MetaValue::tpInt: e = makeInt(i->second.intValue); break;
|
|
||||||
case MetaValue::tpString: e = makeStr(i->second.stringValue); break;
|
|
||||||
case MetaValue::tpStrings: {
|
|
||||||
ATermList es = ATempty;
|
|
||||||
foreach (Strings::const_iterator, j, i->second.stringValues)
|
|
||||||
es = ATinsert(es, makeStr(*j));
|
|
||||||
e = makeList(ATreverse(es));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: abort();
|
|
||||||
}
|
|
||||||
metaAttrs.set(toATerm(i->first), makeAttrRHS(e, makeNoPos()));
|
|
||||||
}
|
|
||||||
attrs->set(toATerm("meta"), makeAttrs(metaAttrs));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -122,7 +101,7 @@ static bool getDerivation(EvalState & state, Value & v,
|
||||||
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
if (i == v.attrs->end()) throw TypeError("derivation name missing");
|
||||||
drv.name = state.forceStringNoCtx(i->second);
|
drv.name = state.forceStringNoCtx(i->second);
|
||||||
|
|
||||||
i = v.attrs->find(state.symbols.create("system"));
|
i = v.attrs->find(state.sSystem);
|
||||||
if (i == v.attrs->end())
|
if (i == v.attrs->end())
|
||||||
drv.system = "unknown";
|
drv.system = "unknown";
|
||||||
else
|
else
|
||||||
|
|
|
@ -41,7 +41,7 @@ public:
|
||||||
/* !!! make this private */
|
/* !!! make this private */
|
||||||
Bindings * attrs;
|
Bindings * attrs;
|
||||||
|
|
||||||
DrvInfo() : metaInfoRead(false) { };
|
DrvInfo() : metaInfoRead(false), attrs(0) { };
|
||||||
|
|
||||||
string queryDrvPath(EvalState & state) const;
|
string queryDrvPath(EvalState & state) const;
|
||||||
string queryOutPath(EvalState & state) const;
|
string queryOutPath(EvalState & state) const;
|
||||||
|
|
|
@ -89,24 +89,29 @@ static void prim_genericClosure(EvalState & state, Value * * args, Value & v)
|
||||||
{
|
{
|
||||||
startNest(nest, lvlDebug, "finding dependencies");
|
startNest(nest, lvlDebug, "finding dependencies");
|
||||||
|
|
||||||
Expr attrs = evalExpr(state, args[0]);
|
state.forceAttrs(*args[0]);
|
||||||
|
|
||||||
/* Get the start set. */
|
/* Get the start set. */
|
||||||
Expr startSet = queryAttr(attrs, "startSet");
|
Bindings::iterator startSet =
|
||||||
if (!startSet) throw EvalError("attribute `startSet' required");
|
args[0]->attrs->find(state.symbols.create("startSet"));
|
||||||
ATermList startSet2 = evalList(state, startSet);
|
if (startSet == args[0]->attrs->end())
|
||||||
|
throw EvalError("attribute `startSet' required");
|
||||||
|
state.forceList(startSet->second);
|
||||||
|
|
||||||
set<Expr> workSet; // !!! gc roots
|
list<Value> workSet;
|
||||||
for (ATermIterator i(startSet2); i; ++i) workSet.insert(*i);
|
for (unsigned int n = 0; n < startSet->second.list.length; ++n)
|
||||||
|
workSet.push_back(*startSet->second.list.elems[n]);
|
||||||
|
|
||||||
/* Get the operator. */
|
/* Get the operator. */
|
||||||
Expr op = queryAttr(attrs, "operator");
|
Bindings::iterator op =
|
||||||
if (!op) throw EvalError("attribute `operator' required");
|
args[0]->attrs->find(state.symbols.create("operator"));
|
||||||
|
if (op == args[0]->attrs->end())
|
||||||
|
throw EvalError("attribute `operator' required");
|
||||||
|
|
||||||
/* Construct the closure by applying the operator to element of
|
/* Construct the closure by applying the operator to element of
|
||||||
`workSet', adding the result to `workSet', continuing until
|
`workSet', adding the result to `workSet', continuing until
|
||||||
no new elements are found. */
|
no new elements are found. */
|
||||||
ATermList res = ATempty;
|
list<Value> res;
|
||||||
set<Expr> doneKeys; // !!! gc roots
|
set<Expr> doneKeys; // !!! gc roots
|
||||||
while (!workSet.empty()) {
|
while (!workSet.empty()) {
|
||||||
Expr e = *(workSet.begin());
|
Expr e = *(workSet.begin());
|
||||||
|
@ -322,8 +327,8 @@ static void prim_derivationStrict(EvalState & state, Value * * args, Value & v)
|
||||||
string s = state.coerceToString(i->second, context, true);
|
string s = state.coerceToString(i->second, context, true);
|
||||||
drv.env[key] = s;
|
drv.env[key] = s;
|
||||||
if (key == "builder") drv.builder = s;
|
if (key == "builder") drv.builder = s;
|
||||||
else if (key == "system") drv.platform = s;
|
else if (i->first == state.sSystem) drv.platform = s;
|
||||||
else if (key == "name") drvName = s;
|
else if (i->first == state.sName) drvName = s;
|
||||||
else if (key == "outputHash") outputHash = s;
|
else if (key == "outputHash") outputHash = s;
|
||||||
else if (key == "outputHashAlgo") outputHashAlgo = s;
|
else if (key == "outputHashAlgo") outputHashAlgo = s;
|
||||||
else if (key == "outputHashMode") {
|
else if (key == "outputHashMode") {
|
||||||
|
@ -830,9 +835,7 @@ static void prim_map(EvalState & state, Value * * args, Value & v)
|
||||||
|
|
||||||
for (unsigned int n = 0; n < v.list.length; ++n) {
|
for (unsigned int n = 0; n < v.list.length; ++n) {
|
||||||
v.list.elems[n] = &vs[n];
|
v.list.elems[n] = &vs[n];
|
||||||
vs[n].type = tApp;
|
mkApp(vs[n], *args[0], *args[1]->list.elems[n]);
|
||||||
vs[n].app.left = args[0];
|
|
||||||
vs[n].app.right = args[1]->list.elems[n];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include "help.txt.hh"
|
#include "help.txt.hh"
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
#include "attr-path.hh"
|
#include "attr-path.hh"
|
||||||
#include "pathlocks.hh"
|
|
||||||
#include "common-opts.hh"
|
#include "common-opts.hh"
|
||||||
#include "xml-writer.hh"
|
#include "xml-writer.hh"
|
||||||
#include "store-api.hh"
|
#include "store-api.hh"
|
||||||
|
@ -193,141 +192,6 @@ static Path getDefNixExprPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Ensure exclusive access to a profile. Any command that modifies
|
|
||||||
the profile first acquires this lock. */
|
|
||||||
static void lockProfile(PathLocks & lock, const Path & profile)
|
|
||||||
{
|
|
||||||
lock.lockPaths(singleton<PathSet>(profile),
|
|
||||||
(format("waiting for lock on profile `%1%'") % profile).str());
|
|
||||||
lock.setDeletion(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Optimistic locking is used by long-running operations like `nix-env
|
|
||||||
-i'. Instead of acquiring the exclusive lock for the entire
|
|
||||||
duration of the operation, we just perform the operation
|
|
||||||
optimistically (without an exclusive lock), and check at the end
|
|
||||||
whether the profile changed while we were busy (i.e., the symlink
|
|
||||||
target changed). If so, the operation is restarted. Restarting is
|
|
||||||
generally cheap, since the build results are still in the Nix
|
|
||||||
store. Most of the time, only the user environment has to be
|
|
||||||
rebuilt. */
|
|
||||||
static string optimisticLockProfile(const Path & profile)
|
|
||||||
{
|
|
||||||
return pathExists(profile) ? readLink(profile) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static bool createUserEnv(EvalState & state, DrvInfos & elems,
|
|
||||||
const Path & profile, bool keepDerivations,
|
|
||||||
const string & lockToken)
|
|
||||||
{
|
|
||||||
throw Error("not implemented");
|
|
||||||
#if 0
|
|
||||||
/* Build the components in the user environment, if they don't
|
|
||||||
exist already. */
|
|
||||||
PathSet drvsToBuild;
|
|
||||||
foreach (DrvInfos::const_iterator, i, elems)
|
|
||||||
/* Call to `isDerivation' is for compatibility with Nix <= 0.7
|
|
||||||
user environments. */
|
|
||||||
if (i->queryDrvPath(state) != "" &&
|
|
||||||
isDerivation(i->queryDrvPath(state)))
|
|
||||||
drvsToBuild.insert(i->queryDrvPath(state));
|
|
||||||
|
|
||||||
debug(format("building user environment dependencies"));
|
|
||||||
store->buildDerivations(drvsToBuild);
|
|
||||||
|
|
||||||
/* Get the environment builder expression. */
|
|
||||||
Expr envBuilder = parseExprFromFile(state,
|
|
||||||
nixDataDir + "/nix/corepkgs/buildenv"); /* !!! */
|
|
||||||
|
|
||||||
/* Construct the whole top level derivation. */
|
|
||||||
PathSet references;
|
|
||||||
ATermList manifest = ATempty;
|
|
||||||
ATermList inputs = ATempty;
|
|
||||||
foreach (DrvInfos::iterator, i, elems) {
|
|
||||||
/* Create a pseudo-derivation containing the name, system,
|
|
||||||
output path, and optionally the derivation path, as well as
|
|
||||||
the meta attributes. */
|
|
||||||
Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
|
|
||||||
|
|
||||||
/* Round trip to get rid of "bad" meta values (like
|
|
||||||
functions). */
|
|
||||||
MetaInfo meta = i->queryMetaInfo(state);
|
|
||||||
i->setMetaInfo(meta);
|
|
||||||
|
|
||||||
ATermList as = ATmakeList5(
|
|
||||||
makeBind(toATerm("type"),
|
|
||||||
makeStr("derivation"), makeNoPos()),
|
|
||||||
makeBind(toATerm("name"),
|
|
||||||
makeStr(i->name), makeNoPos()),
|
|
||||||
makeBind(toATerm("system"),
|
|
||||||
makeStr(i->system), makeNoPos()),
|
|
||||||
makeBind(toATerm("outPath"),
|
|
||||||
makeStr(i->queryOutPath(state)), makeNoPos()),
|
|
||||||
makeBind(toATerm("meta"),
|
|
||||||
i->attrs->get(toATerm("meta")), makeNoPos()));
|
|
||||||
|
|
||||||
if (drvPath != "") as = ATinsert(as,
|
|
||||||
makeBind(toATerm("drvPath"),
|
|
||||||
makeStr(drvPath), makeNoPos()));
|
|
||||||
|
|
||||||
manifest = ATinsert(manifest, makeAttrs(as));
|
|
||||||
|
|
||||||
inputs = ATinsert(inputs, makeStr(i->queryOutPath(state)));
|
|
||||||
|
|
||||||
/* This is only necessary when installing store paths, e.g.,
|
|
||||||
`nix-env -i /nix/store/abcd...-foo'. */
|
|
||||||
store->addTempRoot(i->queryOutPath(state));
|
|
||||||
store->ensurePath(i->queryOutPath(state));
|
|
||||||
|
|
||||||
references.insert(i->queryOutPath(state));
|
|
||||||
if (drvPath != "") references.insert(drvPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Also write a copy of the list of inputs to the store; we need
|
|
||||||
it for future modifications of the environment. */
|
|
||||||
Path manifestFile = store->addTextToStore("env-manifest",
|
|
||||||
atPrint(canonicaliseExpr(makeList(ATreverse(manifest)))), references);
|
|
||||||
|
|
||||||
Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
|
|
||||||
makeBind(toATerm("system"),
|
|
||||||
makeStr(thisSystem), makeNoPos()),
|
|
||||||
makeBind(toATerm("derivations"),
|
|
||||||
makeList(ATreverse(manifest)), makeNoPos()),
|
|
||||||
makeBind(toATerm("manifest"),
|
|
||||||
makeStr(manifestFile, singleton<PathSet>(manifestFile)), makeNoPos())
|
|
||||||
)));
|
|
||||||
|
|
||||||
/* Instantiate it. */
|
|
||||||
debug(format("evaluating builder expression `%1%'") % topLevel);
|
|
||||||
DrvInfo topLevelDrv;
|
|
||||||
if (!getDerivation(state, topLevel, topLevelDrv))
|
|
||||||
abort();
|
|
||||||
|
|
||||||
/* Realise the resulting store expression. */
|
|
||||||
debug(format("building user environment"));
|
|
||||||
store->buildDerivations(singleton<PathSet>(topLevelDrv.queryDrvPath(state)));
|
|
||||||
|
|
||||||
/* Switch the current user environment to the output path. */
|
|
||||||
PathLocks lock;
|
|
||||||
lockProfile(lock, profile);
|
|
||||||
|
|
||||||
Path lockTokenCur = optimisticLockProfile(profile);
|
|
||||||
if (lockToken != lockTokenCur) {
|
|
||||||
printMsg(lvlError, format("profile `%1%' changed while we were busy; restarting") % profile);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(format("switching to new user environment"));
|
|
||||||
Path generation = createGeneration(profile, topLevelDrv.queryOutPath(state));
|
|
||||||
switchLink(profile, generation);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int getPriority(EvalState & state, const DrvInfo & drv)
|
static int getPriority(EvalState & state, const DrvInfo & drv)
|
||||||
{
|
{
|
||||||
MetaValue value = drv.queryMetaInfo(state, "priority");
|
MetaValue value = drv.queryMetaInfo(state, "priority");
|
||||||
|
|
|
@ -131,5 +131,19 @@ void switchLink(Path link, Path target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void lockProfile(PathLocks & lock, const Path & profile)
|
||||||
|
{
|
||||||
|
lock.lockPaths(singleton<PathSet>(profile),
|
||||||
|
(format("waiting for lock on profile `%1%'") % profile).str());
|
||||||
|
lock.setDeletion(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string optimisticLockProfile(const Path & profile)
|
||||||
|
{
|
||||||
|
return pathExists(profile) ? readLink(profile) : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define __PROFILES_H
|
#define __PROFILES_H
|
||||||
|
|
||||||
#include "types.hh"
|
#include "types.hh"
|
||||||
|
#include "pathlocks.hh"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
@ -37,6 +38,20 @@ void deleteGeneration(const Path & profile, unsigned int gen);
|
||||||
|
|
||||||
void switchLink(Path link, Path target);
|
void switchLink(Path link, Path target);
|
||||||
|
|
||||||
|
/* Ensure exclusive access to a profile. Any command that modifies
|
||||||
|
the profile first acquires this lock. */
|
||||||
|
void lockProfile(PathLocks & lock, const Path & profile);
|
||||||
|
|
||||||
|
/* Optimistic locking is used by long-running operations like `nix-env
|
||||||
|
-i'. Instead of acquiring the exclusive lock for the entire
|
||||||
|
duration of the operation, we just perform the operation
|
||||||
|
optimistically (without an exclusive lock), and check at the end
|
||||||
|
whether the profile changed while we were busy (i.e., the symlink
|
||||||
|
target changed). If so, the operation is restarted. Restarting is
|
||||||
|
generally cheap, since the build results are still in the Nix
|
||||||
|
store. Most of the time, only the user environment has to be
|
||||||
|
rebuilt. */
|
||||||
|
string optimisticLockProfile(const Path & profile);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
#include "util.hh"
|
#include "util.hh"
|
||||||
#include "get-drvs.hh"
|
#include "get-drvs.hh"
|
||||||
|
#include "derivations.hh"
|
||||||
|
#include "store-api.hh"
|
||||||
|
#include "globals.hh"
|
||||||
|
#include "shared.hh"
|
||||||
|
#include "eval.hh"
|
||||||
|
#include "parser.hh"
|
||||||
|
#include "profiles.hh"
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
@ -12,17 +19,137 @@ DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||||
{
|
{
|
||||||
DrvInfos elems;
|
DrvInfos elems;
|
||||||
|
|
||||||
Path path = userEnv + "/manifest";
|
Path manifestFile = userEnv + "/manifest.nix";
|
||||||
|
Path oldManifestFile = userEnv + "/manifest";
|
||||||
|
|
||||||
if (!pathExists(path))
|
if (pathExists(manifestFile)) {
|
||||||
return DrvInfos(); /* not an error, assume nothing installed */
|
Value v;
|
||||||
|
state.eval(parseExprFromFile(state, manifestFile), v);
|
||||||
readLegacyManifest(path, elems);
|
getDerivations(state, v, "", Bindings(), elems);
|
||||||
|
} else if (pathExists(oldManifestFile))
|
||||||
|
readLegacyManifest(oldManifestFile, elems);
|
||||||
|
|
||||||
return elems;
|
return elems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
|
const Path & profile, bool keepDerivations,
|
||||||
|
const string & lockToken)
|
||||||
|
{
|
||||||
|
/* Build the components in the user environment, if they don't
|
||||||
|
exist already. */
|
||||||
|
PathSet drvsToBuild;
|
||||||
|
foreach (DrvInfos::const_iterator, i, elems)
|
||||||
|
if (i->queryDrvPath(state) != "")
|
||||||
|
drvsToBuild.insert(i->queryDrvPath(state));
|
||||||
|
|
||||||
|
debug(format("building user environment dependencies"));
|
||||||
|
store->buildDerivations(drvsToBuild);
|
||||||
|
|
||||||
|
/* Construct the whole top level derivation. */
|
||||||
|
PathSet references;
|
||||||
|
Value manifest;
|
||||||
|
state.mkList(manifest, elems.size());
|
||||||
|
unsigned int n = 0;
|
||||||
|
foreach (DrvInfos::iterator, i, elems) {
|
||||||
|
/* Create a pseudo-derivation containing the name, system,
|
||||||
|
output path, and optionally the derivation path, as well as
|
||||||
|
the meta attributes. */
|
||||||
|
Path drvPath = keepDerivations ? i->queryDrvPath(state) : "";
|
||||||
|
|
||||||
|
Value & v(*state.allocValues(1));
|
||||||
|
manifest.list.elems[n++] = &v;
|
||||||
|
state.mkAttrs(v);
|
||||||
|
|
||||||
|
mkString((*v.attrs)[state.sType], "derivation");
|
||||||
|
mkString((*v.attrs)[state.sName], i->name);
|
||||||
|
mkString((*v.attrs)[state.sSystem], i->system);
|
||||||
|
mkString((*v.attrs)[state.sOutPath], i->queryOutPath(state));
|
||||||
|
if (drvPath != "")
|
||||||
|
mkString((*v.attrs)[state.sDrvPath], i->queryDrvPath(state));
|
||||||
|
|
||||||
|
state.mkAttrs((*v.attrs)[state.sMeta]);
|
||||||
|
|
||||||
|
MetaInfo meta = i->queryMetaInfo(state);
|
||||||
|
|
||||||
|
foreach (MetaInfo::const_iterator, j, meta) {
|
||||||
|
Value & v2((*(*v.attrs)[state.sMeta].attrs)[state.symbols.create(j->first)]);
|
||||||
|
switch (j->second.type) {
|
||||||
|
case MetaValue::tpInt: mkInt(v2, j->second.intValue); break;
|
||||||
|
case MetaValue::tpString: mkString(v2, j->second.stringValue); break;
|
||||||
|
case MetaValue::tpStrings: {
|
||||||
|
state.mkList(v2, j->second.stringValues.size());
|
||||||
|
unsigned int m = 0;
|
||||||
|
foreach (Strings::const_iterator, k, j->second.stringValues) {
|
||||||
|
v2.list.elems[m] = state.allocValues(1);
|
||||||
|
mkString(*v2.list.elems[m++], *k);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is only necessary when installing store paths, e.g.,
|
||||||
|
`nix-env -i /nix/store/abcd...-foo'. */
|
||||||
|
store->addTempRoot(i->queryOutPath(state));
|
||||||
|
store->ensurePath(i->queryOutPath(state));
|
||||||
|
|
||||||
|
references.insert(i->queryOutPath(state));
|
||||||
|
if (drvPath != "") references.insert(drvPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Also write a copy of the list of user environment elements to
|
||||||
|
the store; we need it for future modifications of the
|
||||||
|
environment. */
|
||||||
|
Path manifestFile = store->addTextToStore("env-manifest.nix",
|
||||||
|
(format("%1%") % manifest).str(), references);
|
||||||
|
|
||||||
|
printMsg(lvlError, manifestFile);
|
||||||
|
|
||||||
|
/* Get the environment builder expression. */
|
||||||
|
Value envBuilder;
|
||||||
|
state.eval(parseExprFromFile(state, nixDataDir + "/nix/corepkgs/buildenv"), envBuilder);
|
||||||
|
|
||||||
|
/* Construct a Nix expression that calls the user environment
|
||||||
|
builder with the manifest as argument. */
|
||||||
|
Value args, topLevel;
|
||||||
|
state.mkAttrs(args);
|
||||||
|
mkString((*args.attrs)[state.sSystem], thisSystem);
|
||||||
|
mkString((*args.attrs)[state.symbols.create("manifest")],
|
||||||
|
manifestFile, singleton<PathSet>(manifestFile));
|
||||||
|
(*args.attrs)[state.symbols.create("derivations")] = manifest;
|
||||||
|
mkApp(topLevel, envBuilder, args);
|
||||||
|
|
||||||
|
/* Evaluate it. */
|
||||||
|
debug("evaluating user environment builder");
|
||||||
|
DrvInfo topLevelDrv;
|
||||||
|
if (!getDerivation(state, topLevel, topLevelDrv))
|
||||||
|
abort();
|
||||||
|
|
||||||
|
/* Realise the resulting store expression. */
|
||||||
|
debug("building user environment");
|
||||||
|
store->buildDerivations(singleton<PathSet>(topLevelDrv.queryDrvPath(state)));
|
||||||
|
|
||||||
|
/* Switch the current user environment to the output path. */
|
||||||
|
PathLocks lock;
|
||||||
|
lockProfile(lock, profile);
|
||||||
|
|
||||||
|
Path lockTokenCur = optimisticLockProfile(profile);
|
||||||
|
if (lockToken != lockTokenCur) {
|
||||||
|
printMsg(lvlError, format("profile `%1%' changed while we were busy; restarting") % profile);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(format("switching to new user environment"));
|
||||||
|
Path generation = createGeneration(profile, topLevelDrv.queryOutPath(state));
|
||||||
|
switchLink(profile, generation);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Code for parsing manifests in the old textual ATerm format. */
|
/* Code for parsing manifests in the old textual ATerm format. */
|
||||||
|
|
||||||
static string parseStr(std::istream & str)
|
static string parseStr(std::istream & str)
|
||||||
|
|
|
@ -7,6 +7,10 @@ namespace nix {
|
||||||
|
|
||||||
DrvInfos queryInstalled(EvalState & state, const Path & userEnv);
|
DrvInfos queryInstalled(EvalState & state, const Path & userEnv);
|
||||||
|
|
||||||
|
bool createUserEnv(EvalState & state, DrvInfos & elems,
|
||||||
|
const Path & profile, bool keepDerivations,
|
||||||
|
const string & lockToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* !__USER_ENV_H */
|
#endif /* !__USER_ENV_H */
|
||||||
|
|
Loading…
Reference in a new issue