mirror of
https://github.com/NixOS/nix
synced 2025-06-28 17:51:15 +02:00
* Sync with the trunk.
This commit is contained in:
commit
aa45027818
109 changed files with 3350 additions and 4010 deletions
|
@ -1,6 +1,7 @@
|
|||
bin_PROGRAMS = nix-env
|
||||
|
||||
nix_env_SOURCES = nix-env.cc profiles.cc profiles.hh help.txt
|
||||
nix_env_SOURCES = nix-env.cc profiles.cc profiles.hh user-env.cc user-env.hh help.txt
|
||||
|
||||
nix_env_LDADD = ../libmain/libmain.la ../libexpr/libexpr.la \
|
||||
../libstore/libstore.la ../libutil/libutil.la \
|
||||
../boost/format/libformat.la
|
||||
|
@ -11,7 +12,6 @@ nix-env.o: help.txt.hh
|
|||
../bin2c/bin2c helpText < $< > $@ || (rm $@ && exit 1)
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
${aterm_include} \
|
||||
-I$(srcdir)/.. \
|
||||
-I$(srcdir)/../libutil -I$(srcdir)/../libstore \
|
||||
-I$(srcdir)/../libexpr -I$(srcdir)/../libmain -I../libexpr
|
||||
|
|
|
@ -6,15 +6,13 @@
|
|||
#include "parser.hh"
|
||||
#include "eval.hh"
|
||||
#include "help.txt.hh"
|
||||
#include "nixexpr-ast.hh"
|
||||
#include "get-drvs.hh"
|
||||
#include "attr-path.hh"
|
||||
#include "pathlocks.hh"
|
||||
#include "common-opts.hh"
|
||||
#include "xml-writer.hh"
|
||||
#include "store-api.hh"
|
||||
#include "user-env.hh"
|
||||
#include "util.hh"
|
||||
#include "aterm.hh"
|
||||
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
|
@ -48,7 +46,7 @@ struct InstallSourceInfo
|
|||
Path profile; /* for srcProfile */
|
||||
string systemFilter; /* for srcNixExprDrvs */
|
||||
bool prebuiltOnly;
|
||||
ATermMap autoArgs;
|
||||
Bindings autoArgs;
|
||||
InstallSourceInfo() : prebuiltOnly(false) { };
|
||||
};
|
||||
|
||||
|
@ -113,7 +111,7 @@ static bool isNixExpr(const Path & path)
|
|||
|
||||
|
||||
static void getAllExprs(EvalState & state,
|
||||
const Path & path, ATermMap & attrs)
|
||||
const Path & path, ExprAttrs & attrs)
|
||||
{
|
||||
Strings names = readDirectory(path);
|
||||
StringSet namesSorted(names.begin(), names.end());
|
||||
|
@ -133,8 +131,8 @@ static void getAllExprs(EvalState & state,
|
|||
string attrName = *i;
|
||||
if (hasSuffix(attrName, ".nix"))
|
||||
attrName = string(attrName, 0, attrName.size() - 4);
|
||||
attrs.set(toATerm(attrName), makeAttrRHS(
|
||||
parseExprFromFile(state, absPath(path2)), makeNoPos()));
|
||||
attrs.attrs[state.symbols.create(attrName)] =
|
||||
ExprAttrs::Attr(parseExprFromFile(state, absPath(path2)), noPos);
|
||||
}
|
||||
else
|
||||
/* `path2' is a directory (with no default.nix in it);
|
||||
|
@ -144,7 +142,7 @@ static void getAllExprs(EvalState & state,
|
|||
}
|
||||
|
||||
|
||||
static Expr loadSourceExpr(EvalState & state, const Path & path)
|
||||
static Expr * loadSourceExpr(EvalState & state, const Path & path)
|
||||
{
|
||||
if (isNixExpr(path)) return parseExprFromFile(state, absPath(path));
|
||||
|
||||
|
@ -154,20 +152,22 @@ static Expr loadSourceExpr(EvalState & state, const Path & path)
|
|||
(but keep the attribute set flat, not nested, to make it easier
|
||||
for a user to have a ~/.nix-defexpr directory that includes
|
||||
some system-wide directory). */
|
||||
ATermMap attrs;
|
||||
attrs.set(toATerm("_combineChannels"), makeAttrRHS(makeList(ATempty), makeNoPos()));
|
||||
getAllExprs(state, path, attrs);
|
||||
return makeAttrs(attrs);
|
||||
ExprAttrs * attrs = new ExprAttrs;
|
||||
attrs->attrs[state.symbols.create("_combineChannels")] =
|
||||
ExprAttrs::Attr(new ExprList(), noPos);
|
||||
getAllExprs(state, path, *attrs);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
|
||||
static void loadDerivations(EvalState & state, Path nixExprPath,
|
||||
string systemFilter, const ATermMap & autoArgs,
|
||||
string systemFilter, const Bindings & autoArgs,
|
||||
const string & pathPrefix, DrvInfos & elems)
|
||||
{
|
||||
getDerivations(state,
|
||||
findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath)),
|
||||
pathPrefix, autoArgs, elems);
|
||||
Value v;
|
||||
findAlongAttrPath(state, pathPrefix, autoArgs, loadSourceExpr(state, nixExprPath), v);
|
||||
|
||||
getDerivations(state, v, pathPrefix, autoArgs, elems);
|
||||
|
||||
/* Filter out all derivations not applicable to the current
|
||||
system. */
|
||||
|
@ -193,172 +193,6 @@ static Path getDefNixExprPath()
|
|||
}
|
||||
|
||||
|
||||
struct AddPos : TermFun
|
||||
{
|
||||
ATerm operator () (ATerm e)
|
||||
{
|
||||
ATerm x, y;
|
||||
if (matchObsoleteBind(e, x, y))
|
||||
return makeBind(x, y, makeNoPos());
|
||||
if (matchObsoleteStr(e, x))
|
||||
return makeStr(x, ATempty);
|
||||
return e;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||
{
|
||||
Path path = userEnv + "/manifest";
|
||||
|
||||
if (!pathExists(path))
|
||||
return DrvInfos(); /* not an error, assume nothing installed */
|
||||
|
||||
Expr e = ATreadFromNamedFile(path.c_str());
|
||||
if (!e) throw Error(format("cannot read Nix expression from `%1%'") % path);
|
||||
|
||||
/* Compatibility: Bind(x, y) -> Bind(x, y, NoPos). */
|
||||
AddPos addPos;
|
||||
e = bottomupRewrite(addPos, e);
|
||||
|
||||
DrvInfos elems;
|
||||
getDerivations(state, e, "", ATermMap(1), elems);
|
||||
return elems;
|
||||
}
|
||||
|
||||
|
||||
/* 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)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
static int getPriority(EvalState & state, const DrvInfo & drv)
|
||||
{
|
||||
MetaValue value = drv.queryMetaInfo(state, "priority");
|
||||
|
@ -517,14 +351,13 @@ static void queryInstSources(EvalState & state,
|
|||
(import ./foo.nix)' = `(import ./foo.nix).bar'. */
|
||||
case srcNixExprs: {
|
||||
|
||||
Expr e1 = loadSourceExpr(state, instSource.nixExprPath);
|
||||
Expr * e1 = loadSourceExpr(state, instSource.nixExprPath);
|
||||
|
||||
for (Strings::const_iterator i = args.begin();
|
||||
i != args.end(); ++i)
|
||||
{
|
||||
Expr e2 = parseExprFromString(state, *i, absPath("."));
|
||||
Expr call = makeCall(e2, e1);
|
||||
getDerivations(state, call, "", instSource.autoArgs, elems);
|
||||
foreach (Strings::const_iterator, i, args) {
|
||||
Expr * e2 = parseExprFromString(state, *i, absPath("."));
|
||||
Expr * call = new ExprApp(e2, e1);
|
||||
Value v; state.eval(call, v);
|
||||
getDerivations(state, v, "", instSource.autoArgs, elems);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -541,7 +374,7 @@ static void queryInstSources(EvalState & state,
|
|||
Path path = followLinksToStorePath(*i);
|
||||
|
||||
DrvInfo elem;
|
||||
elem.attrs = boost::shared_ptr<ATermMap>(new ATermMap(0)); /* ugh... */
|
||||
elem.attrs = new Bindings;
|
||||
string name = baseNameOf(path);
|
||||
string::size_type dash = name.find('-');
|
||||
if (dash != string::npos)
|
||||
|
@ -575,12 +408,12 @@ static void queryInstSources(EvalState & state,
|
|||
}
|
||||
|
||||
case srcAttrPath: {
|
||||
for (Strings::const_iterator i = args.begin();
|
||||
i != args.end(); ++i)
|
||||
getDerivations(state,
|
||||
findAlongAttrPath(state, *i, instSource.autoArgs,
|
||||
loadSourceExpr(state, instSource.nixExprPath)),
|
||||
"", instSource.autoArgs, elems);
|
||||
foreach (Strings::const_iterator, i, args) {
|
||||
Value v;
|
||||
findAlongAttrPath(state, *i, instSource.autoArgs,
|
||||
loadSourceExpr(state, instSource.nixExprPath), v);
|
||||
getDerivations(state, v, "", instSource.autoArgs, elems);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -1103,6 +936,7 @@ static void opQuery(Globals & globals,
|
|||
|
||||
foreach (vector<DrvInfo>::iterator, i, elems2) {
|
||||
try {
|
||||
startNest(nest, lvlDebug, format("outputting query result `%1%'") % i->attrPath);
|
||||
|
||||
/* For table output. */
|
||||
Strings columns;
|
||||
|
@ -1473,7 +1307,7 @@ void run(Strings args)
|
|||
|
||||
op(globals, remaining, opFlags, opArgs);
|
||||
|
||||
printEvalStats(globals.state);
|
||||
globals.state.printStats();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -130,6 +130,20 @@ void switchLink(Path link, Path target)
|
|||
throw SysError(format("renaming `%1%' to `%2%'") % tmp % link);
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
#include "types.hh"
|
||||
#include "pathlocks.hh"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
@ -37,6 +38,20 @@ void deleteGeneration(const Path & profile, unsigned int gen);
|
|||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
257
src/nix-env/user-env.cc
Normal file
257
src/nix-env/user-env.cc
Normal file
|
@ -0,0 +1,257 @@
|
|||
#include "util.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 {
|
||||
|
||||
|
||||
static void readLegacyManifest(const Path & path, DrvInfos & elems);
|
||||
|
||||
|
||||
DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
|
||||
{
|
||||
DrvInfos elems;
|
||||
|
||||
Path manifestFile = userEnv + "/manifest.nix";
|
||||
Path oldManifestFile = userEnv + "/manifest";
|
||||
|
||||
if (pathExists(manifestFile)) {
|
||||
Value v;
|
||||
state.eval(parseExprFromFile(state, manifestFile), v);
|
||||
getDerivations(state, v, "", Bindings(), elems);
|
||||
} else if (pathExists(oldManifestFile))
|
||||
readLegacyManifest(oldManifestFile, 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].value, "derivation");
|
||||
mkString((*v.attrs)[state.sName].value, i->name);
|
||||
mkString((*v.attrs)[state.sSystem].value, i->system);
|
||||
mkString((*v.attrs)[state.sOutPath].value, i->queryOutPath(state));
|
||||
if (drvPath != "")
|
||||
mkString((*v.attrs)[state.sDrvPath].value, i->queryDrvPath(state));
|
||||
|
||||
state.mkAttrs((*v.attrs)[state.sMeta].value);
|
||||
|
||||
MetaInfo meta = i->queryMetaInfo(state);
|
||||
|
||||
foreach (MetaInfo::const_iterator, j, meta) {
|
||||
Value & v2((*(*v.attrs)[state.sMeta].value.attrs)[state.symbols.create(j->first)].value);
|
||||
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].value, thisSystem);
|
||||
mkString((*args.attrs)[state.symbols.create("manifest")].value,
|
||||
manifestFile, singleton<PathSet>(manifestFile));
|
||||
(*args.attrs)[state.symbols.create("derivations")].value = 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. */
|
||||
|
||||
static string parseStr(std::istream & str)
|
||||
{
|
||||
expect(str, "Str(");
|
||||
string s = parseString(str);
|
||||
expect(str, ",[])");
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
static string parseWord(std::istream & str)
|
||||
{
|
||||
string res;
|
||||
while (isalpha(str.peek()))
|
||||
res += str.get();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static MetaInfo parseMeta(std::istream & str)
|
||||
{
|
||||
MetaInfo meta;
|
||||
|
||||
expect(str, "Attrs([");
|
||||
while (!endOfList(str)) {
|
||||
expect(str, "Bind(");
|
||||
|
||||
MetaValue value;
|
||||
|
||||
string name = parseString(str);
|
||||
expect(str, ",");
|
||||
|
||||
string type = parseWord(str);
|
||||
|
||||
if (type == "Str") {
|
||||
expect(str, "(");
|
||||
value.type = MetaValue::tpString;
|
||||
value.stringValue = parseString(str);
|
||||
expect(str, ",[])");
|
||||
}
|
||||
|
||||
else if (type == "List") {
|
||||
expect(str, "([");
|
||||
value.type = MetaValue::tpStrings;
|
||||
while (!endOfList(str))
|
||||
value.stringValues.push_back(parseStr(str));
|
||||
expect(str, ")");
|
||||
}
|
||||
|
||||
else throw Error(format("unexpected token `%1%'") % type);
|
||||
|
||||
expect(str, ",NoPos)");
|
||||
meta[name] = value;
|
||||
}
|
||||
|
||||
expect(str, ")");
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
||||
|
||||
static void readLegacyManifest(const Path & path, DrvInfos & elems)
|
||||
{
|
||||
string manifest = readFile(path);
|
||||
std::istringstream str(manifest);
|
||||
expect(str, "List([");
|
||||
|
||||
unsigned int n = 0;
|
||||
|
||||
while (!endOfList(str)) {
|
||||
DrvInfo elem;
|
||||
expect(str, "Attrs([");
|
||||
|
||||
while (!endOfList(str)) {
|
||||
expect(str, "Bind(");
|
||||
string name = parseString(str);
|
||||
expect(str, ",");
|
||||
|
||||
if (name == "meta") elem.setMetaInfo(parseMeta(str));
|
||||
else {
|
||||
string value = parseStr(str);
|
||||
if (name == "name") elem.name = value;
|
||||
else if (name == "outPath") elem.setOutPath(value);
|
||||
else if (name == "drvPath") elem.setDrvPath(value);
|
||||
else if (name == "system") elem.system = value;
|
||||
}
|
||||
|
||||
expect(str, ",NoPos)");
|
||||
}
|
||||
|
||||
expect(str, ")");
|
||||
|
||||
if (elem.name != "") {
|
||||
elem.attrPath = int2String(n++);
|
||||
elems.push_back(elem);
|
||||
}
|
||||
}
|
||||
|
||||
expect(str, ")");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
20
src/nix-env/user-env.hh
Normal file
20
src/nix-env/user-env.hh
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef __USER_ENV_H
|
||||
#define __USER_ENV_H
|
||||
|
||||
#include "get-drvs.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue