about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--nix.conf.example21
-rw-r--r--src/libstore/gc.cc4
-rw-r--r--src/libstore/globals.cc12
-rw-r--r--src/libstore/globals.hh2
-rw-r--r--src/nix-env/main.cc68
5 files changed, 72 insertions, 35 deletions
diff --git a/nix.conf.example b/nix.conf.example
index 1af5df952b37..fcdf6fccd94d 100644
--- a/nix.conf.example
+++ b/nix.conf.example
@@ -7,7 +7,7 @@
 # 
 # In general, outputs must be registered as roots separately.
 # However, even if the output of a derivation is registered as a root,
-# the collector will still delete store paths that are used only a
+# the collector will still delete store paths that are used only at
 # build time (e.g., the C compiler, or source tarballs downloaded from
 # the network).  To prevent it from doing so, set this option to
 # `true'.
@@ -28,3 +28,22 @@ gc-keep-outputs = false
 # turned on).
 gc-keep-derivations = true
 
+
+### Option `env-keep-derivations'
+#
+# If `false' (default), derivations are not stored in Nix user
+# environments.  That is, the derivation any build-time-only
+# dependencies may be garbage-collected.
+#
+# If `true', when you add a Nix derivation to a user environment, the
+# path of the derivation is stored in the user environment.  Thus, the
+# derivation will not be garbage-collected until the user environment
+# generation is deleted (`nix-env --delete-generations').  To prevent
+# build-time-only dependencies from being collected, you should also
+# turn on `gc-keep-outputs'.
+#
+# The difference between this option and `gc-keep-derivations' is that
+# this one is `sticky': it applies to any user environment created
+# while this option was enabled, while `gc-keep-derivations' only
+# applies at the moment the garbage collector is run.
+env-keep-derivations = false
diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc
index 4d63d46ea1f5..98b863314ac9 100644
--- a/src/libstore/gc.cc
+++ b/src/libstore/gc.cc
@@ -306,7 +306,7 @@ void collectGarbage(GCAction action, PathSet & result)
 {
     result.clear();
 
-    string gcKeepOutputs = querySetting("gc-keep-outputs", "false");
+    bool gcKeepOutputs = queryBoolSetting("gc-keep-outputs", false);
 
     /* Acquire the global GC root.  This prevents
        a) New roots from being added.
@@ -330,7 +330,7 @@ void collectGarbage(GCAction action, PathSet & result)
     for (PathSet::const_iterator i = roots.begin(); i != roots.end(); ++i)
         computeFSClosure(canonPath(*i), livePaths);
 
-    if (gcKeepOutputs == "true") {
+    if (gcKeepOutputs) {
         /* Hmz, identical to storePathRequisites in nix-store. */
         for (PathSet::iterator i = livePaths.begin();
              i != livePaths.end(); ++i)
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 22820f2fe8ac..4387c8acc2aa 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -52,7 +52,7 @@ static void readSettings()
         string name, sep, value;
         is >> name >> sep >> value;
         if (sep != "=" || !is)
-            throw Error(format("illegal configuration line `%1%'") % line);
+            throw Error(format("illegal configuration line `%1%' in `%2%'") % line % settingsFile);
         
         settings[name] = value;
     };
@@ -67,3 +67,13 @@ string querySetting(const string & name, const string & def)
     map<string, string>::iterator i = settings.find(name);
     return i == settings.end() ? def : i->second;
 }
+
+
+bool queryBoolSetting(const string & name, bool def)
+{
+    string value = querySetting(name, def ? "true" : "false");
+    if (value == "true") return true;
+    else if (value == "false") return false;
+    else throw Error(format("configuration option `%1%' should be either `true' or `false', not `%2%'")
+        % name % value);
+}
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 0e851fd748c6..e2ae2ed655b3 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -55,5 +55,7 @@ extern bool readOnlyMode;
 
 string querySetting(const string & name, const string & def);
 
+bool queryBoolSetting(const string & name, bool def);
+
 
 #endif /* !__GLOBALS_H */
diff --git a/src/nix-env/main.cc b/src/nix-env/main.cc
index d45dd2bd8c06..fa07135fc09e 100644
--- a/src/nix-env/main.cc
+++ b/src/nix-env/main.cc
@@ -37,6 +37,7 @@ struct Globals
     EvalState state;
     bool dryRun;
     bool preserveInstalled;
+    bool keepDerivations;
 };
 
 
@@ -203,7 +204,7 @@ void queryInstalled(EvalState & state, DrvInfos & drvs,
 
 
 void createUserEnv(EvalState & state, const DrvInfos & drvs,
-    const Path & profile)
+    const Path & profile, bool keepDerivations)
 {
     /* Build the components in the user environment, if they don't
        exist already. */
@@ -227,19 +228,23 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
     for (DrvInfos::const_iterator i = drvs.begin(); 
          i != drvs.end(); ++i)
     {
-        ATerm t = makeAttrs(ATmakeList4(
+        Path drvPath = keepDerivations ? i->second.drvPath : "";
+        ATerm t = makeAttrs(ATmakeList5(
             makeBind(toATerm("type"),
                 makeStr(toATerm("derivation")), makeNoPos()),
             makeBind(toATerm("name"),
                 makeStr(toATerm(i->second.name)), makeNoPos()),
             makeBind(toATerm("system"),
                 makeStr(toATerm(i->second.system)), makeNoPos()),
+            makeBind(toATerm("drvPath"),
+                makePath(toATerm(drvPath)), makeNoPos()),
             makeBind(toATerm("outPath"),
                 makePath(toATerm(i->second.outPath)), makeNoPos())
             ));
         manifest = ATinsert(manifest, t);
         inputs = ATinsert(inputs, makeStr(toATerm(i->second.outPath)));
         references.insert(i->second.outPath);
+        if (drvPath != "") references.insert(drvPath);
     }
 
     /* Also write a copy of the list of inputs to the store; we need
@@ -247,8 +252,6 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
     Path manifestFile = addTextToStore("env-manifest",
         atPrint(makeList(ATreverse(manifest))), references);
 
-    printMsg(lvlError, format("manifest is %1%") % manifestFile);
-
     Expr topLevel = makeCall(envBuilder, makeAttrs(ATmakeList3(
         makeBind(toATerm("system"),
             makeStr(toATerm(thisSystem)), makeNoPos()),
@@ -281,15 +284,14 @@ void createUserEnv(EvalState & state, const DrvInfos & drvs,
 }
 
 
-static void installDerivations(EvalState & state,
-    const InstallSourceInfo & instSource, DrvNames & selectors,
-    const Path & profile, bool dryRun, bool preserveInstalled)
+static void installDerivations(Globals & globals,
+    DrvNames & selectors, const Path & profile)
 {
     debug(format("installing derivations"));
 
     /* Fetch all derivations from the input file. */
     DrvInfos availDrvs;
-    queryInstSources(state, instSource, availDrvs);
+    queryInstSources(globals.state, globals.instSource, availDrvs);
 
     /* Filter out the ones we're not interested in. */
     DrvInfos selectedDrvs;
@@ -320,13 +322,13 @@ static void installDerivations(EvalState & state,
     
     /* Add in the already installed derivations. */
     DrvInfos installedDrvs;
-    queryInstalled(state, installedDrvs, profile);
+    queryInstalled(globals.state, installedDrvs, profile);
 
     for (DrvInfos::iterator i = installedDrvs.begin();
          i != installedDrvs.end(); ++i)
     {
         DrvName drvName(i->second.name);
-        if (!preserveInstalled &&
+        if (!globals.preserveInstalled &&
             selectedNames.find(drvName.name) != selectedNames.end())
             printMsg(lvlInfo,
                 format("uninstalling `%1%'") % i->second.name);
@@ -334,9 +336,10 @@ static void installDerivations(EvalState & state,
             selectedDrvs.insert(*i);
     }
 
-    if (dryRun) return;
+    if (globals.dryRun) return;
 
-    createUserEnv(state, selectedDrvs, profile);
+    createUserEnv(globals.state, selectedDrvs,
+        profile, globals.keepDerivations);
 }
 
 
@@ -348,18 +351,16 @@ static void opInstall(Globals & globals,
 
     DrvNames drvNames = drvNamesFromArgs(opArgs);
     
-    installDerivations(globals.state, globals.instSource,
-        drvNames, globals.profile, globals.dryRun,
-        globals.preserveInstalled);
+    installDerivations(globals, drvNames, globals.profile);
 }
 
 
 typedef enum { utLt, utLeq, utAlways } UpgradeType;
 
 
-static void upgradeDerivations(EvalState & state,
-    const InstallSourceInfo & instSource, DrvNames & selectors, const Path & profile,
-    UpgradeType upgradeType, bool dryRun)
+static void upgradeDerivations(Globals & globals,
+    DrvNames & selectors, const Path & profile,
+    UpgradeType upgradeType)
 {
     debug(format("upgrading derivations"));
 
@@ -370,11 +371,11 @@ static void upgradeDerivations(EvalState & state,
 
     /* Load the currently installed derivations. */
     DrvInfos installedDrvs;
-    queryInstalled(state, installedDrvs, profile);
+    queryInstalled(globals.state, installedDrvs, profile);
 
     /* Fetch all derivations from the input file. */
     DrvInfos availDrvs;
-    // xxx    loadDerivations(state, nePath, availDrvs, systemFilter);
+    queryInstSources(globals.state, globals.instSource, availDrvs);
 
     /* Go through all installed derivations. */
     DrvInfos newDrvs;
@@ -440,9 +441,10 @@ static void upgradeDerivations(EvalState & state,
         } else newDrvs.insert(*i);
     }
     
-    if (dryRun) return;
+    if (globals.dryRun) return;
 
-    createUserEnv(state, newDrvs, profile);
+    createUserEnv(globals.state, newDrvs,
+        profile, globals.keepDerivations);
 }
 
 
@@ -459,16 +461,15 @@ static void opUpgrade(Globals & globals,
 
     DrvNames drvNames = drvNamesFromArgs(opArgs);
     
-    upgradeDerivations(globals.state, globals.instSource,
-        drvNames, globals.profile, upgradeType, globals.dryRun);
+    upgradeDerivations(globals, drvNames, globals.profile, upgradeType);
 }
 
 
-static void uninstallDerivations(EvalState & state, DrvNames & selectors,
-    Path & profile, bool dryRun)
+static void uninstallDerivations(Globals & globals, DrvNames & selectors,
+    Path & profile)
 {
     DrvInfos installedDrvs;
-    queryInstalled(state, installedDrvs, profile);
+    queryInstalled(globals.state, installedDrvs, profile);
 
     for (DrvInfos::iterator i = installedDrvs.begin();
          i != installedDrvs.end(); ++i)
@@ -483,9 +484,10 @@ static void uninstallDerivations(EvalState & state, DrvNames & selectors,
             }
     }
 
-    if (dryRun) return;
+    if (globals.dryRun) return;
 
-    createUserEnv(state, installedDrvs, profile);
+    createUserEnv(globals.state, installedDrvs,
+        profile, globals.keepDerivations);
 }
 
 
@@ -497,8 +499,8 @@ static void opUninstall(Globals & globals,
 
     DrvNames drvNames = drvNamesFromArgs(opArgs);
 
-    uninstallDerivations(globals.state, drvNames,
-        globals.profile, globals.dryRun);
+    uninstallDerivations(globals, drvNames,
+        globals.profile);
 }
 
 
@@ -798,6 +800,7 @@ void run(Strings args)
     Operation op = 0;
     
     Globals globals;
+    
     globals.instSource.type = srcUnknown;
     globals.instSource.nixExprPath = getDefNixExprPath();
     globals.instSource.systemFilter = thisSystem;
@@ -805,6 +808,9 @@ void run(Strings args)
     globals.dryRun = false;
     globals.preserveInstalled = false;
 
+    globals.keepDerivations =
+        queryBoolSetting("env-keep-derivations", false);
+    
     for (Strings::iterator i = args.begin(); i != args.end(); ++i) {
         string arg = *i;