about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <edolstra@gmail.com>2017-08-29T13·00+0200
committerEelco Dolstra <edolstra@gmail.com>2017-08-29T13·00+0200
commit05d68a6e23127e490193599f75489006830b302c (patch)
tree213b0c677dec14868a0dadc40d0dadbf40562b7a
parent5cc8609e30ab4f76053f3159c51ea78d9215bc8c (diff)
nix run: Add some flags for clearing/keeping the environment
This is useful for testing commands in isolation.

For example,

  $ nix run nixpkgs.geeqie -i -k DISPLAY -k XAUTHORITY -c geeqie

runs geeqie in an empty environment, except for $DISPLAY and
$XAUTHORITY.
-rw-r--r--src/nix/run.cc49
1 files changed, 49 insertions, 0 deletions
diff --git a/src/nix/run.cc b/src/nix/run.cc
index 39fbcc8acf9f..8175d38e8ca6 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -18,6 +18,8 @@ std::string chrootHelperName = "__run_in_chroot";
 struct CmdRun : InstallablesCommand
 {
     Strings command = { "bash" };
+    StringSet keep, unset;
+    bool ignoreEnvironment = false;
 
     CmdRun()
     {
@@ -31,6 +33,28 @@ struct CmdRun : InstallablesCommand
                 if (ss.empty()) throw UsageError("--command requires at least one argument");
                 command = ss;
             });
+
+        mkFlag()
+            .longName("ignore-environment")
+            .shortName('i')
+            .description("clear the entire environment (except those specified with --keep)")
+            .handler([&](Strings ss) { ignoreEnvironment = true; });
+
+        mkFlag()
+            .longName("keep")
+            .shortName('k')
+            .description("keep specified environment variable")
+            .arity(1)
+            .labels({"name"})
+            .handler([&](Strings ss) { keep.insert(ss.front()); });
+
+        mkFlag()
+            .longName("unset")
+            .shortName('u')
+            .description("unset specified environment variable")
+            .arity(1)
+            .labels({"name"})
+            .handler([&](Strings ss) { unset.insert(ss.front()); });
     }
 
     std::string name() override
@@ -49,6 +73,31 @@ struct CmdRun : InstallablesCommand
 
         auto accessor = store->getFSAccessor();
 
+        if (ignoreEnvironment) {
+
+            if (!unset.empty())
+                throw UsageError("--unset does not make sense with --ignore-environment");
+
+            std::map<std::string, std::string> kept;
+            for (auto & var : keep) {
+                auto s = getenv(var.c_str());
+                if (s) kept[var] = s;
+            }
+
+            clearenv();
+
+            for (auto & var : kept)
+                setenv(var.first.c_str(), var.second.c_str(), 1);
+
+        } else {
+
+            if (!keep.empty())
+                throw UsageError("--keep does not make sense without --ignore-environment");
+
+            for (auto & var : unset)
+                unsetenv(var.c_str());
+        }
+
         auto unixPath = tokenizeString<Strings>(getEnv("PATH"), ":");
         for (auto & path : outPaths)
             if (accessor->stat(path + "/bin").type != FSAccessor::tMissing)