Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/nix/command.cc
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,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());
}
}

}
15 changes: 14 additions & 1 deletion src/nix/command.hh
Original file line number Diff line number Diff line change
Expand Up @@ -194,4 +194,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();
};

}
52 changes: 3 additions & 49 deletions src/nix/run.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand All @@ -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
Expand Down Expand Up @@ -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()) {
Expand Down
4 changes: 3 additions & 1 deletion src/nix/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ struct Common : InstallableCommand, MixProfile
}
};

struct CmdDevShell : Common
struct CmdDevShell : Common, MixEnvironment
{
std::string description() override
{
Expand Down Expand Up @@ -275,6 +275,8 @@ struct CmdDevShell : Common

auto shell = getEnv("SHELL", "bash");

setEnviron();

auto args = Strings{baseNameOf(shell), "--rcfile", rcFilePath};

restoreAffinity();
Expand Down