Skip to content

Commit

Permalink
develop: Allow shells to declare the minimal bash version they require
Browse files Browse the repository at this point in the history
Allow derivations to export a `NIX_ENV_MIN_BASH_VERSION` that sets the
minimal (major) bash version that is required to parse their setup
script, and use that to gracefully fail if the current bash is too old.

Fix #10263 (from the Nix side at least, needs NixOS/nixpkgs#299490 from the Nixpkgs side to be useful in practice)
  • Loading branch information
Théophane Hufschmitt committed Mar 29, 2024
1 parent b72e1c7 commit 16175e0
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 0 deletions.
17 changes: 17 additions & 0 deletions src/nix/develop.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ struct BuildEnvironment
std::map<std::string, Value> vars;
std::map<std::string, std::string> bashFunctions;
std::optional<std::pair<std::string, std::string>> structuredAttrs;
std::optional<int> minimalBashVersion;

static BuildEnvironment fromJSON(std::string_view in)
{
Expand Down Expand Up @@ -81,6 +82,10 @@ struct BuildEnvironment
res.structuredAttrs = {json["structuredAttrs"][".attrs.json"], json["structuredAttrs"][".attrs.sh"]};
}

if (json.contains("meta") && json["meta"].contains("min-bash-version")) {
res.minimalBashVersion = std::optional<int>{ json["meta"]["min-bash-version"] };
}

return res;
}

Expand Down Expand Up @@ -142,6 +147,18 @@ struct BuildEnvironment

void toBash(std::ostream & out, const std::set<std::string> & ignoreVars) const
{
if (minimalBashVersion.has_value()) {
out << stripIndentation(fmt(R"__NIX_STR(
if [[ -n "${BASH_VERSINFO-}" && "${BASH_VERSINFO-}" -lt %d ]]; then
echo "Detected Bash version that isn't supported by this derivation (${BASH_VERSION})"
echo "Please install Bash %d or greater to continue."
exit 1
fi
)__NIX_STR",
minimalBashVersion.value(),
minimalBashVersion.value()));
}

for (auto & [name, value] : vars) {
if (!ignoreVars.count(name)) {
if (auto str = std::get_if<String>(&value)) {
Expand Down
10 changes: 10 additions & 0 deletions src/nix/get-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,16 @@ __dumpEnv() {
printf '\n }'
fi

printf ',\n "meta": {\n '
# min-bash-version is supposed to be an integer.
# If not, just ignore it.
if [[ -n "${NIX_ENV_MIN_BASH_VERSION-}" && "$NIX_ENV_MIN_BASH_VERSION" -eq "$NIX_ENV_MIN_BASH_VERSION" ]]; then
__escapeString "min-bash-version"
printf ': '
printf '%d' "${NIX_ENV_MIN_BASH_VERSION}"
fi
printf '\n }'

printf '\n}'
}

Expand Down
17 changes: 17 additions & 0 deletions tests/functional/flakes/develop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,20 @@ EOF
)" -ef "$BASH_INTERACTIVE_EXECUTABLE" ]]

clearStore

# Use a newer bash version than the current one
cat <<EOF >$TEST_HOME/flake.nix
{
inputs.nixpkgs.url = "$TEST_HOME/nixpkgs";
outputs = {self, nixpkgs}: {
packages.$system.hello = (import ./config.nix).mkDerivation {
name = "hello";
outputs = [ "out" "dev" ];
meta.outputsToInstall = [ "out" ];
buildCommand = "";
NIX_ENV_MIN_BASH_VERSION=99;
};
};
}
EOF
expect 1 nix develop .#hello --command true

0 comments on commit 16175e0

Please sign in to comment.