Merge pull request #513 from K900/ambient-nix-with-fallback

Use ambient Nix when available, with a two stage fallback
This commit is contained in:
Jörg Thalheim 2024-08-22 12:43:03 +02:00 committed by GitHub
commit a3139c8f49
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 62 additions and 17 deletions

View file

@ -311,6 +311,14 @@ invocation or are purely incidental and should not be relied upon.
flake's devShell are invalid and nix-direnv has loaded the last known working flake's devShell are invalid and nix-direnv has loaded the last known working
shell. shell.
nix-direnv also respects the following environment variables for configuration.
- `NIX_DIRENV_FALLBACK_NIX`: Can be set to a fallback Nix binary location, to be
used when a compatible one isn't available in `PATH`. Defaults to
`config.nix.package` if installed via the NixOS module, otherwise needs to be
set manually. Leave unset or empty to fail immediately when a Nix
implementation can't be found on `PATH`.
## General direnv tips ## General direnv tips
- [Changing where direnv stores its cache][cache_location] - [Changing where direnv stores its cache][cache_location]

View file

@ -2,8 +2,8 @@
resholve, resholve,
lib, lib,
coreutils, coreutils,
direnv,
nix, nix,
writeText,
}: }:
# resholve does not yet support `finalAttrs` call pattern hence `rec` # resholve does not yet support `finalAttrs` call pattern hence `rec`
@ -17,11 +17,6 @@ resholve.mkDerivation rec {
name = pname; name = pname;
}; };
# skip min version checks which are redundant when built with nix
postPatch = ''
sed -i 1iNIX_DIRENV_SKIP_VERSION_CHECK=1 direnvrc
'';
installPhase = '' installPhase = ''
install -m400 -D direnvrc $out/share/${pname}/direnvrc install -m400 -D direnvrc $out/share/${pname}/direnvrc
''; '';
@ -30,10 +25,7 @@ resholve.mkDerivation rec {
default = { default = {
scripts = [ "share/${pname}/direnvrc" ]; scripts = [ "share/${pname}/direnvrc" ];
interpreter = "none"; interpreter = "none";
inputs = [ inputs = [ coreutils ];
coreutils
nix
];
fake = { fake = {
builtin = [ builtin = [
"PATH_add" "PATH_add"
@ -48,15 +40,26 @@ resholve.mkDerivation rec {
# cannot be reached when built with nix # cannot be reached when built with nix
"shasum" "shasum"
]; ];
external = [
# We want to reference the ambient Nix when possible, and have custom logic
# for the fallback
"nix"
];
}; };
keep = { keep = {
"$cmd" = true; "$cmd" = true;
"$direnv" = true; "$direnv" = true;
# Nix fallback implementation
"$_nix_direnv_nix" = true;
"$ambient_nix" = true;
"$NIX_DIRENV_FALLBACK_NIX" = true;
}; };
execer = [ prologue =
"cannot:${direnv}/bin/direnv" (writeText "prologue.sh" ''
"cannot:${nix}/bin/nix" NIX_DIRENV_SKIP_VERSION_CHECK=1
]; NIX_DIRENV_FALLBACK_NIX=''${NIX_DIRENV_FALLBACK_NIX:-${lib.getExe nix}}
'').outPath;
}; };
}; };

View file

@ -29,8 +29,10 @@ _nix_direnv_warning() {
_nix_direnv_error() { log_error "${_NIX_DIRENV_LOG_PREFIX}$*"; } _nix_direnv_error() { log_error "${_NIX_DIRENV_LOG_PREFIX}$*"; }
_nix_direnv_nix=""
_nix() { _nix() {
nix --extra-experimental-features "nix-command flakes" "$@" ${_nix_direnv_nix} --extra-experimental-features "nix-command flakes" "$@"
} }
_require_version() { _require_version() {
@ -53,6 +55,34 @@ _require_cmd_version() {
_require_version "$cmd" "${BASH_REMATCH[1]}" "$required" _require_version "$cmd" "${BASH_REMATCH[1]}" "$required"
} }
_nix_direnv_resolve_nix() {
local ambient_nix
if ambient_nix=$(command -v nix); then
if _require_cmd_version "${ambient_nix}" "${NIX_MIN_VERSION}"; then
echo "${ambient_nix}"
return 0
else
_nix_direnv_warning "Nix version in PATH is too old, wanted ${NIX_MIN_VERSION}+, got $(${ambient_nix} --version), will attempt fallback"
fi
else
_nix_direnv_warning "Could not find Nix in PATH, will attempt fallback"
fi
if [ -n "${NIX_DIRENV_FALLBACK_NIX}" ]; then
if _require_cmd_version "${NIX_DIRENV_FALLBACK_NIX}" "${NIX_MIN_VERSION}"; then
echo "${NIX_DIRENV_FALLBACK_NIX}"
return 0
else
_nix_direnv_error "Fallback Nix version is too old, wanted ${NIX_MIN_VERSION}+, got $(${NIX_DIRENV_FALLBACK_NIX} --version)"
return 1
fi
else
_nix_direnv_error "Could not find fallback Nix binary, please add Nix to PATH or set NIX_DIRENV_FALLBACK_NIX"
return 1
fi
}
_nix_direnv_preflight() { _nix_direnv_preflight() {
if [[ -z $direnv ]]; then if [[ -z $direnv ]]; then
# shellcheck disable=2016 # shellcheck disable=2016
@ -66,12 +96,16 @@ _nix_direnv_preflight() {
# _require_cmd_version because _require_cmd_version uses =~ operator which would be # _require_cmd_version because _require_cmd_version uses =~ operator which would be
# a syntax error on bash < 3 # a syntax error on bash < 3
if ! _require_version bash "$BASH_VERSION" "$BASH_MIN_VERSION" || if ! _require_version bash "$BASH_VERSION" "$BASH_MIN_VERSION" ||
! _require_cmd_version "$direnv" "$DIRENV_MIN_VERSION" || # direnv stdlib defines $direnv # direnv stdlib defines $direnv
! _require_cmd_version nix "$NIX_MIN_VERSION"; then ! _require_cmd_version "$direnv" "$DIRENV_MIN_VERSION"; then
return 1 return 1
fi fi
fi fi
if ! _nix_direnv_nix=$(_nix_direnv_resolve_nix); then
return 1
fi
local layout_dir local layout_dir
layout_dir=$(direnv_layout_dir) layout_dir=$(direnv_layout_dir)