Skip to content

Commit 05d68a6

Browse files
committed
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.
1 parent 5cc8609 commit 05d68a6

File tree

1 file changed

+49
-0
lines changed

1 file changed

+49
-0
lines changed

src/nix/run.cc

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ std::string chrootHelperName = "__run_in_chroot";
1818
struct CmdRun : InstallablesCommand
1919
{
2020
Strings command = { "bash" };
21+
StringSet keep, unset;
22+
bool ignoreEnvironment = false;
2123

2224
CmdRun()
2325
{
@@ -31,6 +33,28 @@ struct CmdRun : InstallablesCommand
3133
if (ss.empty()) throw UsageError("--command requires at least one argument");
3234
command = ss;
3335
});
36+
37+
mkFlag()
38+
.longName("ignore-environment")
39+
.shortName('i')
40+
.description("clear the entire environment (except those specified with --keep)")
41+
.handler([&](Strings ss) { ignoreEnvironment = true; });
42+
43+
mkFlag()
44+
.longName("keep")
45+
.shortName('k')
46+
.description("keep specified environment variable")
47+
.arity(1)
48+
.labels({"name"})
49+
.handler([&](Strings ss) { keep.insert(ss.front()); });
50+
51+
mkFlag()
52+
.longName("unset")
53+
.shortName('u')
54+
.description("unset specified environment variable")
55+
.arity(1)
56+
.labels({"name"})
57+
.handler([&](Strings ss) { unset.insert(ss.front()); });
3458
}
3559

3660
std::string name() override
@@ -49,6 +73,31 @@ struct CmdRun : InstallablesCommand
4973

5074
auto accessor = store->getFSAccessor();
5175

76+
if (ignoreEnvironment) {
77+
78+
if (!unset.empty())
79+
throw UsageError("--unset does not make sense with --ignore-environment");
80+
81+
std::map<std::string, std::string> kept;
82+
for (auto & var : keep) {
83+
auto s = getenv(var.c_str());
84+
if (s) kept[var] = s;
85+
}
86+
87+
clearenv();
88+
89+
for (auto & var : kept)
90+
setenv(var.first.c_str(), var.second.c_str(), 1);
91+
92+
} else {
93+
94+
if (!keep.empty())
95+
throw UsageError("--keep does not make sense without --ignore-environment");
96+
97+
for (auto & var : unset)
98+
unsetenv(var.c_str());
99+
}
100+
52101
auto unixPath = tokenizeString<Strings>(getEnv("PATH"), ":");
53102
for (auto & path : outPaths)
54103
if (accessor->stat(path + "/bin").type != FSAccessor::tMissing)

0 commit comments

Comments
 (0)