From 16175e07a91bede0bf06e2278adef6309bd7ffa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9ophane=20Hufschmitt?= Date: Fri, 29 Mar 2024 15:43:19 +0100 Subject: [PATCH] develop: Allow shells to declare the minimal bash version they require 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 https://github.com/NixOS/nixpkgs/pull/299490 from the Nixpkgs side to be useful in practice) --- src/nix/develop.cc | 17 +++++++++++++++++ src/nix/get-env.sh | 10 ++++++++++ tests/functional/flakes/develop.sh | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/src/nix/develop.cc b/src/nix/develop.cc index c1842f2d5..8185d5223 100644 --- a/src/nix/develop.cc +++ b/src/nix/develop.cc @@ -54,6 +54,7 @@ struct BuildEnvironment std::map vars; std::map bashFunctions; std::optional> structuredAttrs; + std::optional minimalBashVersion; static BuildEnvironment fromJSON(std::string_view in) { @@ -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{ json["meta"]["min-bash-version"] }; + } + return res; } @@ -142,6 +147,18 @@ struct BuildEnvironment void toBash(std::ostream & out, const std::set & 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(&value)) { diff --git a/src/nix/get-env.sh b/src/nix/get-env.sh index 832cc2f11..248947d27 100644 --- a/src/nix/get-env.sh +++ b/src/nix/get-env.sh @@ -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}' } diff --git a/tests/functional/flakes/develop.sh b/tests/functional/flakes/develop.sh index e1e53d364..6422cf9ed 100644 --- a/tests/functional/flakes/develop.sh +++ b/tests/functional/flakes/develop.sh @@ -65,3 +65,20 @@ EOF )" -ef "$BASH_INTERACTIVE_EXECUTABLE" ]] clearStore + +# Use a newer bash version than the current one +cat <$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