nix3-develop: correctly escape ASCII control characters for JSON
Fixes #991.
(cherry picked from commit 138c7161be)
Change-Id: Iafc7d9603fbc3615393d32d9630f0e8fe548950b
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
synopsis: Fix develop shells for derivations with escape codes
|
||||
issues: [fj#991]
|
||||
cls: [4154, 4155]
|
||||
category: Fixes
|
||||
credits: [Qyriad]
|
||||
---
|
||||
|
||||
ASCII control characters (including `\e`, used for ANSI escape codes) in derivation variables are now correctly escaped for `nix develop` and `nix print-dev-env`, instead of erroring.
|
||||
+13
-10
@@ -142,20 +142,20 @@ struct BuildEnvironment
|
||||
for (auto & [name, value] : vars) {
|
||||
if (!ignoreVars.count(name)) {
|
||||
if (auto str = std::get_if<String>(&value)) {
|
||||
out << fmt("%s=%s\n", name, shellEscape(str->value));
|
||||
out << fmt("%s=%s\n", name, bashEscape(str->value));
|
||||
if (str->exported)
|
||||
out << fmt("export %s\n", name);
|
||||
}
|
||||
else if (auto arr = std::get_if<Array>(&value)) {
|
||||
out << "declare -a " << name << "=(";
|
||||
for (auto & s : *arr)
|
||||
out << shellEscape(s) << " ";
|
||||
out << bashEscape(s) << " ";
|
||||
out << ")\n";
|
||||
}
|
||||
else if (auto arr = std::get_if<Associative>(&value)) {
|
||||
out << "declare -A " << name << "=(";
|
||||
for (auto & [n, v] : *arr)
|
||||
out << "[" << shellEscape(n) << "]=" << shellEscape(v) << " ";
|
||||
out << "[" << bashEscape(n) << "]=" << bashEscape(v) << " ";
|
||||
out << ")\n";
|
||||
}
|
||||
}
|
||||
@@ -599,21 +599,24 @@ struct CmdDevelop : Common, MixEnvironment
|
||||
else if (!command.empty()) {
|
||||
std::vector<std::string> args;
|
||||
for (auto s : command)
|
||||
args.push_back(shellEscape(s));
|
||||
args.push_back(bashEscape(s));
|
||||
script += fmt("exec %s\n", concatStringsSep(" ", args));
|
||||
}
|
||||
|
||||
else {
|
||||
script = "[ -n \"$PS1\" ] && [ -e ~/.bashrc ] && source ~/.bashrc;\n" + script;
|
||||
if (developSettings.bashPrompt != "")
|
||||
script += fmt("[ -n \"$PS1\" ] && PS1=%s;\n",
|
||||
shellEscape(developSettings.bashPrompt.get()));
|
||||
script +=
|
||||
fmt("[ -n \"$PS1\" ] && PS1=%s;\n",
|
||||
bashEscape(developSettings.bashPrompt.get()));
|
||||
if (developSettings.bashPromptPrefix != "")
|
||||
script += fmt("[ -n \"$PS1\" ] && PS1=%s\"$PS1\";\n",
|
||||
shellEscape(developSettings.bashPromptPrefix.get()));
|
||||
script +=
|
||||
fmt("[ -n \"$PS1\" ] && PS1=%s\"$PS1\";\n",
|
||||
bashEscape(developSettings.bashPromptPrefix.get()));
|
||||
if (developSettings.bashPromptSuffix != "")
|
||||
script += fmt("[ -n \"$PS1\" ] && PS1+=%s;\n",
|
||||
shellEscape(developSettings.bashPromptSuffix.get()));
|
||||
script +=
|
||||
fmt("[ -n \"$PS1\" ] && PS1+=%s;\n",
|
||||
bashEscape(developSettings.bashPromptSuffix.get()));
|
||||
}
|
||||
|
||||
writeFull(rcFileFd.get(), script);
|
||||
|
||||
@@ -12,6 +12,31 @@ fi
|
||||
__vars="$(declare -p)"
|
||||
__functions="$(declare -F)"
|
||||
|
||||
# Literal control characters (ASCII 0-31) aren't valid JSON.
|
||||
__escapeCtrl() {
|
||||
local escaped="$1"
|
||||
|
||||
# I don't know if NUL bytes are at ALL possible in here,
|
||||
# but covering them is free.
|
||||
local i=0
|
||||
# NOTE: safe input `i` to arithmetic expansion.
|
||||
while [[ "$i" -le 32 ]]; do
|
||||
# Convert the decimal ASCII value to its actual string.
|
||||
local asHex; printf -v asHex "%02x" "$i"
|
||||
local asStr; printf -v asStr "%b" "\x$asHex"
|
||||
|
||||
# Format it to \uXXXX.
|
||||
# All control characters fit within four hex digits.
|
||||
local asUni; printf -v asUni '\\u%04x' "$i"
|
||||
|
||||
escaped="${escaped//"$asStr"/"$asUni"}"
|
||||
|
||||
i="$((i + 1))"
|
||||
done
|
||||
|
||||
printf "%s" "$escaped"
|
||||
}
|
||||
|
||||
__dumpEnv() {
|
||||
printf '{\n'
|
||||
|
||||
@@ -125,6 +150,7 @@ __escapeString() {
|
||||
__s="${__s//$'\n'/\\n}"
|
||||
__s="${__s//$'\r'/\\r}"
|
||||
__s="${__s//$'\t'/\\t}"
|
||||
__s="$(__escapeCtrl "$__s")"
|
||||
printf '"%s"' "$__s"
|
||||
}
|
||||
|
||||
|
||||
@@ -132,6 +132,7 @@ set -u
|
||||
[[ ${arr2[1]} = $'\n' ]]
|
||||
[[ ${arr2[2]} = $'x\ny' ]]
|
||||
[[ $(fun) = blabla ]]
|
||||
[[ "$ASCII_ESC" = "$(printf "\e")" ]]
|
||||
[[ $PATH = $(jq -r .variables.PATH.value $TEST_ROOT/dev-env.json):$path ]]
|
||||
)
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ let pkgs = rec {
|
||||
VAR_FROM_NIX = "bar";
|
||||
ASCII_PERCENT = "%";
|
||||
ASCII_AT = "@";
|
||||
ASCII_ESC = "";
|
||||
TEST_inNixShell = if inNixShell then "true" else "false";
|
||||
inherit stdenv;
|
||||
outputs = ["dev" "out"];
|
||||
|
||||
Reference in New Issue
Block a user