aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nix/command.cc44
-rw-r--r--src/nix/command.hh15
-rw-r--r--src/nix/run.cc52
-rw-r--r--src/nix/shell.cc4
4 files changed, 64 insertions, 51 deletions
diff --git a/src/nix/command.cc b/src/nix/command.cc
index 111b5a10f..4520309cd 100644
--- a/src/nix/command.cc
+++ b/src/nix/command.cc
@@ -142,4 +142,48 @@ MixDefaultProfile::MixDefaultProfile()
profile = getDefaultProfile();
}
+MixEnvironment::MixEnvironment() : ignoreEnvironment(false) {
+ mkFlag()
+ .longName("ignore-environment")
+ .shortName('i')
+ .description("clear the entire environment (except those specified with --keep)")
+ .set(&ignoreEnvironment, true);
+
+ mkFlag()
+ .longName("keep")
+ .shortName('k')
+ .description("keep specified environment variable")
+ .arity(1)
+ .labels({"name"})
+ .handler([&](std::vector<std::string> ss) { keep.insert(ss.front()); });
+
+ mkFlag()
+ .longName("unset")
+ .shortName('u')
+ .description("unset specified environment variable")
+ .arity(1)
+ .labels({"name"})
+ .handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); });
+}
+
+void MixEnvironment::setEnviron() {
+ if (ignoreEnvironment) {
+ if (!unset.empty())
+ throw UsageError("--unset does not make sense with --ignore-environment");
+
+ for (const auto & var : keep) {
+ auto val = getenv(var.c_str());
+ if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
+ }
+ vectorEnv = stringsToCharPtrs(stringsEnv);
+ environ = vectorEnv.data();
+ } else {
+ if (!keep.empty())
+ throw UsageError("--keep does not make sense without --ignore-environment");
+
+ for (const auto & var : unset)
+ unsetenv(var.c_str());
+ }
+}
+
}
diff --git a/src/nix/command.hh b/src/nix/command.hh
index 42c14927f..16f8997dd 100644
--- a/src/nix/command.hh
+++ b/src/nix/command.hh
@@ -200,4 +200,17 @@ struct MixDefaultProfile : MixProfile
MixDefaultProfile();
};
-}
+struct MixEnvironment : virtual Args {
+
+ StringSet keep, unset;
+ Strings stringsEnv;
+ std::vector<char*> vectorEnv;
+ bool ignoreEnvironment;
+
+ MixEnvironment();
+
+ /* Modify global environ based on ignoreEnvironment, keep, and unset. It's expected that exec will be called before this class goes out of scope, otherwise environ will become invalid. */
+ void setEnviron();
+};
+
+} \ No newline at end of file
diff --git a/src/nix/run.cc b/src/nix/run.cc
index ed15527b8..0fbd0b8a8 100644
--- a/src/nix/run.cc
+++ b/src/nix/run.cc
@@ -57,11 +57,9 @@ struct RunCommon : virtual Command
}
};
-struct CmdRun : InstallablesCommand, RunCommon
+struct CmdRun : InstallablesCommand, RunCommon, MixEnvironment
{
std::vector<std::string> command = { "bash" };
- StringSet keep, unset;
- bool ignoreEnvironment = false;
CmdRun()
{
@@ -75,28 +73,6 @@ struct CmdRun : InstallablesCommand, RunCommon
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)")
- .set(&ignoreEnvironment, true);
-
- mkFlag()
- .longName("keep")
- .shortName('k')
- .description("keep specified environment variable")
- .arity(1)
- .labels({"name"})
- .handler([&](std::vector<std::string> ss) { keep.insert(ss.front()); });
-
- mkFlag()
- .longName("unset")
- .shortName('u')
- .description("unset specified environment variable")
- .arity(1)
- .labels({"name"})
- .handler([&](std::vector<std::string> ss) { unset.insert(ss.front()); });
}
std::string description() override
@@ -132,35 +108,13 @@ struct CmdRun : InstallablesCommand, RunCommon
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());
- }
std::unordered_set<Path> done;
std::queue<Path> todo;
for (auto & path : outPaths) todo.push(path);
+ setEnviron();
+
auto unixPath = tokenizeString<Strings>(getEnv("PATH"), ":");
while (!todo.empty()) {
diff --git a/src/nix/shell.cc b/src/nix/shell.cc
index 6fa471dfc..2c5142518 100644
--- a/src/nix/shell.cc
+++ b/src/nix/shell.cc
@@ -231,7 +231,7 @@ struct Common : InstallableCommand, MixProfile
}
};
-struct CmdDevShell : Common
+struct CmdDevShell : Common, MixEnvironment
{
std::string description() override
{
@@ -277,6 +277,8 @@ struct CmdDevShell : Common
auto shell = getEnv("SHELL", "bash");
+ setEnviron();
+
auto args = Strings{baseNameOf(shell), "--rcfile", rcFilePath};
restoreAffinity();