nix dev-shell: Improve environment handling
Only variables that were marked as exported are exported in the dev shell. Also, we no longer try to parse the function section of the env file, fixing $ nix dev-shell error: shell environment '/nix/store/h7ama3kahb8lypf4nvjx34z06g9ncw4h-nixops-1.7pre20190926.4c7acbb-env' has unexpected line '/^[a-z]?"""/ {'
This commit is contained in:
parent
15b888c9a5
commit
9b9de3a5e3
110
src/nix/shell.cc
110
src/nix/shell.cc
|
@ -7,55 +7,76 @@
|
||||||
#include "affinity.hh"
|
#include "affinity.hh"
|
||||||
#include "progress-bar.hh"
|
#include "progress-bar.hh"
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
|
struct Var
|
||||||
|
{
|
||||||
|
bool exported;
|
||||||
|
std::string value; // quoted string or array
|
||||||
|
};
|
||||||
|
|
||||||
struct BuildEnvironment
|
struct BuildEnvironment
|
||||||
{
|
{
|
||||||
// FIXME: figure out which vars should be exported.
|
std::map<std::string, Var> env;
|
||||||
std::map<std::string, std::string> env;
|
std::string bashFunctions;
|
||||||
std::map<std::string, std::string> functions;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
BuildEnvironment readEnvironment(const Path & path)
|
BuildEnvironment readEnvironment(const Path & path)
|
||||||
{
|
{
|
||||||
BuildEnvironment res;
|
BuildEnvironment res;
|
||||||
|
|
||||||
auto lines = tokenizeString<Strings>(readFile(path), "\n");
|
std::set<std::string> exported;
|
||||||
|
|
||||||
auto getLine =
|
auto file = readFile(path);
|
||||||
[&]() {
|
//auto file = readFile("/tmp/x");
|
||||||
if (lines.empty())
|
|
||||||
throw Error("shell environment '%s' ends unexpectedly", path);
|
|
||||||
auto line = lines.front();
|
|
||||||
lines.pop_front();
|
|
||||||
return line;
|
|
||||||
};
|
|
||||||
|
|
||||||
while (!lines.empty()) {
|
auto pos = file.cbegin();
|
||||||
auto line = getLine();
|
|
||||||
|
|
||||||
auto eq = line.find('=');
|
static std::string varNameRegex =
|
||||||
if (eq != std::string::npos) {
|
R"re((?:[a-zA-Z_][a-zA-Z0-9_]*))re";
|
||||||
std::string name(line, 0, eq);
|
|
||||||
std::string value(line, eq + 1);
|
static std::regex declareRegex(
|
||||||
// FIXME: parse arrays
|
"^declare -x (" + varNameRegex + ")" +
|
||||||
res.env.insert({name, value});
|
R"re((?:="((?:[^"\\]|\\.)*)")?\n)re");
|
||||||
|
|
||||||
|
static std::string simpleStringRegex =
|
||||||
|
R"re((?:[a-zA-Z0-9_/:\.\-1\+]*))re";
|
||||||
|
|
||||||
|
static std::string quotedStringRegex =
|
||||||
|
R"re((?:\$?'[^']*'))re";
|
||||||
|
|
||||||
|
static std::string arrayRegex =
|
||||||
|
R"re((?:\(( *\[[^\]]+\]="(?:[^"\\]|\\.)*")*\)))re";
|
||||||
|
|
||||||
|
static std::regex varRegex(
|
||||||
|
"^(" + varNameRegex + ")=(" + simpleStringRegex + "|" + quotedStringRegex + "|" + arrayRegex + ")\n");
|
||||||
|
|
||||||
|
static std::regex functionRegex(
|
||||||
|
"^" + varNameRegex + " \\(\\) *\n");
|
||||||
|
|
||||||
|
while (pos != file.end()) {
|
||||||
|
|
||||||
|
std::smatch match;
|
||||||
|
|
||||||
|
if (std::regex_search(pos, file.cend(), match, declareRegex)) {
|
||||||
|
pos = match[0].second;
|
||||||
|
exported.insert(match[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (hasSuffix(line, " () ")) {
|
else if (std::regex_search(pos, file.cend(), match, varRegex)) {
|
||||||
std::string name(line, 0, line.size() - 4);
|
pos = match[0].second;
|
||||||
// FIXME: validate name
|
res.env.insert({match[1], Var { (bool) exported.count(match[1]), match[2] }});
|
||||||
auto l = getLine();
|
|
||||||
if (l != "{ ") throw Error("shell environment '%s' has unexpected line '%s'", path, l);
|
|
||||||
std::string body;
|
|
||||||
while ((l = getLine()) != "}") {
|
|
||||||
body += l;
|
|
||||||
body += '\n';
|
|
||||||
}
|
|
||||||
res.functions.insert({name, body});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else throw Error("shell environment '%s' has unexpected line '%s'", path, line);
|
else if (std::regex_search(pos, file.cend(), match, functionRegex)) {
|
||||||
|
res.bashFunctions = std::string(pos, file.cend());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
else throw Error("shell environment '%s' has unexpected line '%s'",
|
||||||
|
path, file.substr(pos - file.cbegin(), 60));
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -72,7 +93,16 @@ Path getDerivationEnvironment(ref<Store> store, Derivation drv)
|
||||||
if (builder != "bash")
|
if (builder != "bash")
|
||||||
throw Error("'nix shell' only works on derivations that use 'bash' as their builder");
|
throw Error("'nix shell' only works on derivations that use 'bash' as their builder");
|
||||||
|
|
||||||
drv.args = {"-c", "set -e; export IN_NIX_SHELL=impure; export dontAddDisableDepTrack=1; if [[ -n $stdenv ]]; then source $stdenv/setup; fi; set > $out"};
|
drv.args = {
|
||||||
|
"-c",
|
||||||
|
"set -e; "
|
||||||
|
"export IN_NIX_SHELL=impure; "
|
||||||
|
"export dontAddDisableDepTrack=1; "
|
||||||
|
"if [[ -n $stdenv ]]; then "
|
||||||
|
" source $stdenv/setup; "
|
||||||
|
"fi; "
|
||||||
|
"export > $out; "
|
||||||
|
"set >> $out "};
|
||||||
|
|
||||||
/* Remove derivation checks. */
|
/* Remove derivation checks. */
|
||||||
drv.env.erase("allowedReferences");
|
drv.env.erase("allowedReferences");
|
||||||
|
@ -146,18 +176,16 @@ struct Common : InstallableCommand, MixProfile
|
||||||
out << "nix_saved_PATH=\"$PATH\"\n";
|
out << "nix_saved_PATH=\"$PATH\"\n";
|
||||||
|
|
||||||
for (auto & i : buildEnvironment.env) {
|
for (auto & i : buildEnvironment.env) {
|
||||||
// FIXME: shellEscape
|
if (!ignoreVars.count(i.first) && !hasPrefix(i.first, "BASH_")) {
|
||||||
// FIXME: figure out what to export
|
out << fmt("%s=%s\n", i.first, i.second.value);
|
||||||
// FIXME: handle arrays
|
if (i.second.exported)
|
||||||
if (!ignoreVars.count(i.first) && !hasPrefix(i.first, "BASH_"))
|
out << fmt("export %s\n", i.first);
|
||||||
out << fmt("export %s=%s\n", i.first, i.second);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "PATH=\"$PATH:$nix_saved_PATH\"\n";
|
out << "PATH=\"$PATH:$nix_saved_PATH\"\n";
|
||||||
|
|
||||||
for (auto & i : buildEnvironment.functions) {
|
out << buildEnvironment.bashFunctions << "\n";
|
||||||
out << fmt("%s () {\n%s\n}\n", i.first, i.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: set outputs
|
// FIXME: set outputs
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue