aboutsummaryrefslogtreecommitdiff
path: root/src/nix-env
diff options
context:
space:
mode:
Diffstat (limited to 'src/nix-env')
-rw-r--r--src/nix-env/nix-env.cc136
-rw-r--r--src/nix-env/profiles.cc16
-rw-r--r--src/nix-env/profiles.hh15
-rw-r--r--src/nix-env/user-env.cc137
-rw-r--r--src/nix-env/user-env.hh4
5 files changed, 166 insertions, 142 deletions
diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc
index e298c4003..4a9df454d 100644
--- a/src/nix-env/nix-env.cc
+++ b/src/nix-env/nix-env.cc
@@ -8,7 +8,6 @@
#include "help.txt.hh"
#include "get-drvs.hh"
#include "attr-path.hh"
-#include "pathlocks.hh"
#include "common-opts.hh"
#include "xml-writer.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)
{
MetaValue value = drv.queryMetaInfo(state, "priority");
diff --git a/src/nix-env/profiles.cc b/src/nix-env/profiles.cc
index 75585b1b2..60576f1ae 100644
--- a/src/nix-env/profiles.cc
+++ b/src/nix-env/profiles.cc
@@ -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) : "";
+}
+
+
}
diff --git a/src/nix-env/profiles.hh b/src/nix-env/profiles.hh
index 99c20f42d..a64258dae 100644
--- a/src/nix-env/profiles.hh
+++ b/src/nix-env/profiles.hh
@@ -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);
}
diff --git a/src/nix-env/user-env.cc b/src/nix-env/user-env.cc
index f040f8c11..a0e51cae1 100644
--- a/src/nix-env/user-env.cc
+++ b/src/nix-env/user-env.cc
@@ -1,5 +1,12 @@
#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 {
@@ -11,18 +18,138 @@ static void readLegacyManifest(const Path & path, DrvInfos & elems);
DrvInfos queryInstalled(EvalState & state, const Path & userEnv)
{
DrvInfos elems;
-
- Path path = userEnv + "/manifest";
- if (!pathExists(path))
- return DrvInfos(); /* not an error, assume nothing installed */
+ Path manifestFile = userEnv + "/manifest.nix";
+ Path oldManifestFile = userEnv + "/manifest";
- readLegacyManifest(path, elems);
+ 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], "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. */
static string parseStr(std::istream & str)
diff --git a/src/nix-env/user-env.hh b/src/nix-env/user-env.hh
index 6675014f1..4125d8217 100644
--- a/src/nix-env/user-env.hh
+++ b/src/nix-env/user-env.hh
@@ -7,6 +7,10 @@ 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 */