Skip to content

Commit

Permalink
feat: add flag add to MixEnvironment
Browse files Browse the repository at this point in the history
  • Loading branch information
bryanhonof committed Sep 12, 2024
1 parent 48477d4 commit a09ae84
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 26 deletions.
55 changes: 35 additions & 20 deletions src/libcmd/command.cc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include <algorithm>
#include <nlohmann/json.hpp>

#include "command.hh"
Expand All @@ -9,8 +10,7 @@
#include "profiles.hh"
#include "repl.hh"
#include "strings.hh"

extern char * * environ __attribute__((weak));
#include "environment-variables.hh"

namespace nix {

Expand Down Expand Up @@ -301,37 +301,52 @@ MixEnvironment::MixEnvironment() : ignoreEnvironment(false)
.shortName = 'k',
.description = "Keep the environment variable *name*.",
.labels = {"name"},
.handler = {[&](std::string s) { keep.insert(s); }},
.handler = {[&](std::string s) { keepVars.insert(s); }},
});

addFlag({
.longName = "unset",
.longName = "unset-var",
.shortName = 'u',
.description = "Unset the environment variable *name*.",
.labels = {"name"},
.handler = {[&](std::string s) { unset.insert(s); }},
.handler = {[&](std::string s) { unsetVars.insert(s); }},
});

addFlag({
.longName = "set-var",
.shortName = 's',
.description = "Add/override an environment variable *name* with *value*.",
.labels = {"name", "value"},
.handler = {[&](std::string name, std::string value) { setVars.insert_or_assign(name, value); }},
});
}

void MixEnvironment::setEnviron() {
if (ignoreEnvironment) {
if (!unset.empty())
throw UsageError("--unset does not make sense with --ignore-environment");
if (ignoreEnvironment && !unsetVars.empty())
throw UsageError("--unset-var 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));
}
if (!ignoreEnvironment && !keepVars.empty())
throw UsageError("--keep does not make sense without --ignore-environment");

vectorEnv = stringsToCharPtrs(stringsEnv);
environ = vectorEnv.data();
} else {
if (!keep.empty())
throw UsageError("--keep does not make sense without --ignore-environment");
auto env = getEnv();

for (const auto & var : unset)
unsetenv(var.c_str());
}
if (ignoreEnvironment)
std::erase_if(env, [&](const auto & var) {
return !keepVars.contains(var.first);
});

if (!unsetVars.empty())
std::erase_if(env, [&](const auto & var) {
return unsetVars.contains(var.first);
});

if (!setVars.empty())
for (const auto & [name, value] : setVars)
env[name] = value;

replaceEnv(std::move(env));

return;
}

}
13 changes: 7 additions & 6 deletions src/libcmd/command.hh
Original file line number Diff line number Diff line change
Expand Up @@ -315,17 +315,18 @@ struct MixDefaultProfile : MixProfile

struct MixEnvironment : virtual Args {

StringSet keep, unset;
Strings stringsEnv;
std::vector<char*> vectorEnv;
StringSet keepVars;
StringSet unsetVars;
std::map<std::string, std::string> setVars;
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.
* Modify global environ based on `ignoreEnvironment`, `keep`,
* `unset`, and `added`. It's expected that exec will be called
* before this class goes out of scope, otherwise `environ` will
* become invalid.
*/
void setEnviron();
};
Expand Down

0 comments on commit a09ae84

Please sign in to comment.