From 05d68a6e23127e490193599f75489006830b302c Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Tue, 29 Aug 2017 15:00:08 +0200 Subject: [PATCH] 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. --- src/nix/run.cc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/nix/run.cc b/src/nix/run.cc index 39fbcc8ac..8175d38e8 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 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(getEnv("PATH"), ":"); for (auto & path : outPaths) if (accessor->stat(path + "/bin").type != FSAccessor::tMissing)