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.
This commit is contained in:
Eelco Dolstra 2017-08-29 15:00:08 +02:00
parent 5cc8609e30
commit 05d68a6e23
No known key found for this signature in database
GPG key ID: 8170B4726D7198DE

View file

@ -18,6 +18,8 @@ std::string chrootHelperName = "__run_in_chroot";
struct CmdRun : InstallablesCommand struct CmdRun : InstallablesCommand
{ {
Strings command = { "bash" }; Strings command = { "bash" };
StringSet keep, unset;
bool ignoreEnvironment = false;
CmdRun() CmdRun()
{ {
@ -31,6 +33,28 @@ struct CmdRun : InstallablesCommand
if (ss.empty()) throw UsageError("--command requires at least one argument"); if (ss.empty()) throw UsageError("--command requires at least one argument");
command = ss; 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 std::string name() override
@ -49,6 +73,31 @@ struct CmdRun : InstallablesCommand
auto accessor = store->getFSAccessor(); 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"), ":"); auto unixPath = tokenizeString<Strings>(getEnv("PATH"), ":");
for (auto & path : outPaths) for (auto & path : outPaths)
if (accessor->stat(path + "/bin").type != FSAccessor::tMissing) if (accessor->stat(path + "/bin").type != FSAccessor::tMissing)