From 06398c87345d74f1c70443a6d545af01c5b4fd8b Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Tue, 24 Mar 2026 19:13:58 +0100 Subject: [PATCH 01/34] feat(wrapperModules.direnv): init --- wrapperModules/d/direnv/module.nix | 92 ++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 wrapperModules/d/direnv/module.nix diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix new file mode 100644 index 00000000..64a39bf2 --- /dev/null +++ b/wrapperModules/d/direnv/module.nix @@ -0,0 +1,92 @@ +{ config, lib, wlib, pkgs, ... }: +let + cfg = config; + + tomlFmt = pkgs.formats.toml { }; + direnvToml = tomlFmt.generate "direnv.toml" config.extraConfig; +in +{ + imports = [ wlib.modules.default ]; + options = { + configDirname = lib.mkOption { + type = lib.types.str; + default = "${config.binName}-dot-dir"; + description = "Name of the directory which is created as the dotdir in the wrapper output"; + }; + silent = lib.mkEnableOption "silent mode, that is, disabling direnv logging"; + direnvrc = lib.mkOption { + type = lib.types.lines; + description = '' + Content of $DIRENV_CONFIG/direnv.toml + ''; + default = ""; + }; + nix-direnv = { + enable = lib.mkEnableOption "nix-direnv integration"; + package = lib.mkPackageOption pkgs "nix-direnv" { }; + }; + lib = lib.mkOption { + type = with lib.types; attrsOf lines; + default = {}; + }; + extraConfig = lib.mkOption { + inherit (tomlFmt) type; + default = { }; + description = '' + Configuration of direnv.toml. + See + ''; + }; + }; + config = { + package = lib.mkDefault pkgs.direnv; + env = { + # **IMPORTANT** DIRENV_CONFIG needs to be explicitly set in your shells environment + # because right now, direnv will use the `direnv` binary directly in its shell + # hook and not the wrapper (in which $DIRENV_CONFIG got injected). + # Hence the wrapped config will not be picked up unless you explicitly reference + # this variable and set it. + # + # If the PR below will ever be merged, this issue can be fixed by setting: + # + # env.DIRENV_EXE_PATH = "${placeholder "out"}/bin/direnv"; + # + # This would make the direnv hook use the wrapper instead of the original binary. + # + # https://github.com/direnv/direnv/pull/1564 + + # **IMPORTANT** Using `placeholder "out"` here seems to cause issues if this wrapper issue + # built inside a subWrapperModule (for example within the zshWrapper) as it refers + # to the build zsh output in that context. The passthru variants seems to solve this issue. + # DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; + }; + passthru.DIRENV_CONFIG = "${config.wrapper.${config.outputName}}/${config.configDirname}"; + lib."nix-direnv.sh" = lib.mkIf + (config.nix-direnv.enable) + "source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc"; + extraConfig = { + global = lib.mkIf (config.silent) { + log_format = "-"; + log_filter = "^$"; + }; + }; + constructFiles = { + direnvToml = { + content = builtins.readFile direnvToml; + relPath = "${config.configDirname}/direnv.toml"; + }; + direnvRc = { + content = config.direnvrc; + relPath = "${config.configDirname}/direnvrc"; + }; + } // + # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. + # This hack somehow avoids the issue. Find out if this needs to be fixed in + # `constructFiles`. + lib.mapAttrs' (name: value: lib.nameValuePair (builtins.replaceStrings ["." "-"] ["" ""] name) { + content = value; + relPath = "${config.configDirname}/lib/${name}"; + }) config.lib; + }; +} + From 172bb6be58989613136a538a3993c47d6f4b4f21 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Tue, 24 Mar 2026 22:31:03 +0100 Subject: [PATCH 02/34] style(wrapperModues.direnv): apply nix fmt --- wrapperModules/d/direnv/module.nix | 50 +++++++++++++++++------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index 64a39bf2..b8ee0e8d 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -1,4 +1,10 @@ -{ config, lib, wlib, pkgs, ... }: +{ + config, + lib, + wlib, + pkgs, + ... +}: let cfg = config; @@ -27,7 +33,7 @@ in }; lib = lib.mkOption { type = with lib.types; attrsOf lines; - default = {}; + default = { }; }; extraConfig = lib.mkOption { inherit (tomlFmt) type; @@ -40,19 +46,19 @@ in }; config = { package = lib.mkDefault pkgs.direnv; - env = { + env = { # **IMPORTANT** DIRENV_CONFIG needs to be explicitly set in your shells environment - # because right now, direnv will use the `direnv` binary directly in its shell - # hook and not the wrapper (in which $DIRENV_CONFIG got injected). - # Hence the wrapped config will not be picked up unless you explicitly reference - # this variable and set it. - # + # because right now, direnv will use the `direnv` binary directly in its shell + # hook and not the wrapper (in which $DIRENV_CONFIG got injected). + # Hence the wrapped config will not be picked up unless you explicitly reference + # this variable and set it. + # # If the PR below will ever be merged, this issue can be fixed by setting: # # env.DIRENV_EXE_PATH = "${placeholder "out"}/bin/direnv"; # # This would make the direnv hook use the wrapper instead of the original binary. - # + # # https://github.com/direnv/direnv/pull/1564 # **IMPORTANT** Using `placeholder "out"` here seems to cause issues if this wrapper issue @@ -61,9 +67,8 @@ in # DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; }; passthru.DIRENV_CONFIG = "${config.wrapper.${config.outputName}}/${config.configDirname}"; - lib."nix-direnv.sh" = lib.mkIf - (config.nix-direnv.enable) - "source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc"; + lib."nix-direnv.sh" = + lib.mkIf (config.nix-direnv.enable) "source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc"; extraConfig = { global = lib.mkIf (config.silent) { log_format = "-"; @@ -79,14 +84,17 @@ in content = config.direnvrc; relPath = "${config.configDirname}/direnvrc"; }; - } // - # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. - # This hack somehow avoids the issue. Find out if this needs to be fixed in - # `constructFiles`. - lib.mapAttrs' (name: value: lib.nameValuePair (builtins.replaceStrings ["." "-"] ["" ""] name) { - content = value; - relPath = "${config.configDirname}/lib/${name}"; - }) config.lib; + } + // + # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. + # This hack somehow avoids the issue. Find out if this needs to be fixed in + # `constructFiles`. + lib.mapAttrs' ( + name: value: + lib.nameValuePair (builtins.replaceStrings [ "." "-" ] [ "" "" ] name) { + content = value; + relPath = "${config.configDirname}/lib/${name}"; + } + ) config.lib; }; } - From c5aa14483abbf6a5737db041d19173fd82f12e9c Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 20:16:50 +0200 Subject: [PATCH 03/34] fix(wrapperModules.direnv): add maintainers --- maintainers/default.nix | 4 ++++ wrapperModules/d/direnv/module.nix | 1 + 2 files changed, 5 insertions(+) diff --git a/maintainers/default.nix b/maintainers/default.nix index 71c8b112..4ae93165 100644 --- a/maintainers/default.nix +++ b/maintainers/default.nix @@ -60,6 +60,10 @@ github = "nikitawootten"; githubId = 8916363; name = "Nikita Wootten"; + zenoli = { + name = "Zenoli"; + github = "zenoli"; + githubId = 8073528; }; pengolord = { name = "pengo"; diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index b8ee0e8d..0cf50fec 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -96,5 +96,6 @@ in relPath = "${config.configDirname}/lib/${name}"; } ) config.lib; + meta.maintainers = [ wlib.maintainers.zenoli ]; }; } From be3766d95de4094e7095ebd695646e305018e709 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 27 Mar 2026 18:49:05 +0100 Subject: [PATCH 04/34] feat: use key --- wrapperModules/d/direnv/module.nix | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index 0cf50fec..83aeefb2 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -89,13 +89,11 @@ in # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. # This hack somehow avoids the issue. Find out if this needs to be fixed in # `constructFiles`. - lib.mapAttrs' ( - name: value: - lib.nameValuePair (builtins.replaceStrings [ "." "-" ] [ "" "" ] name) { - content = value; - relPath = "${config.configDirname}/lib/${name}"; - } - ) config.lib; + lib.mapAttrs (name: value: { + key = builtins.replaceStrings [ "." "-" ] [ "" "" ] name; + content = value; + relPath = "${config.configDirname}/lib/${name}"; + }) config.lib; meta.maintainers = [ wlib.maintainers.zenoli ]; }; } From 37ddd8cc915954b03aff987fda3d26512604fa6c Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 27 Mar 2026 19:37:26 +0100 Subject: [PATCH 05/34] direnv: add checks --- wrapperModules/d/direnv/check.nix | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 wrapperModules/d/direnv/check.nix diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix new file mode 100644 index 00000000..bd5a65a1 --- /dev/null +++ b/wrapperModules/d/direnv/check.nix @@ -0,0 +1,19 @@ +{ + pkgs, + self, +}: + +let + direnvWrapped = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + + zshWithArgs = zshWrapped.wrap { flags."-ic" = "echo \"$TESTVAR\""; }; + +in +pkgs.runCommand "direnv-test" { } '' + "${zshWrapped}/bin/direnv" --version | grep -q "${direnv.version}" + + touch $out +'' From 9cb8dd9f2505f320fe35ca014e4ad337420481b0 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 28 Mar 2026 00:28:05 +0100 Subject: [PATCH 06/34] refactor tests --- wrapperModules/d/direnv/check.nix | 63 ++++++++++++++++--- wrapperModules/d/direnv/checks/nix-direnv.nix | 22 +++++++ wrapperModules/d/direnv/module.nix | 1 + 3 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 wrapperModules/d/direnv/checks/nix-direnv.nix diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index bd5a65a1..ae31943b 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -4,16 +4,61 @@ }: let - direnvWrapped = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = true; - }; + lib = pkgs.lib; + # wrapperWithoutNixDirenv = self.wrappers.direnv.wrap { + # inherit pkgs; + # nix-direnv.enable = true; + # }; + # wrapperWithNixDirenv = self.wrappers.direnv.wrap { + # inherit pkgs; + # nix-direnv.enable = true; + # }; + # TODO: This seems dumb. Is there no better way to do this? + # cfg = (wrapperWithNixDirenv.eval { }).config; + # dotdir = "${wrapperWithNixDirenv}/${cfg.configDirname}"; - zshWithArgs = zshWrapped.wrap { flags."-ic" = "echo \"$TESTVAR\""; }; + testUtils = '' + is_directory() { + local path="$1" + if [ -d "$path" ]; then + return 0 + else + echo "No directory $path" >&2 + return 1 + fi + } -in -pkgs.runCommand "direnv-test" { } '' - "${zshWrapped}/bin/direnv" --version | grep -q "${direnv.version}" + is_file() { + local path="$1" + if [ -f "$path" ]; then + return 0 + else + echo "No such file $path" >&2 + return 1 + fi + } + ''; + + runTest = + name: attrs: script: + pkgs.runCommand name attrs '' + ${testUtils} + + ${script} - touch $out + touch $out + ''; + + runCheck = name: (import ./checks/${name}) { inherit pkgs self runTest; }; + checks = lib.pipe ./checks [ + builtins.readDir + (lib.filterAttrs (name: type: type == "regular")) + (lib.mapAttrsToList (name: _: (runCheck name))) + ]; +in +# TODO: We need to return a derivation. +# Create a dummie derivation that references `checks` to +# ensure they are evaluated. +runTest "all-tests" { } '' + # "${lib.concatStringsSep " " checks}" '' diff --git a/wrapperModules/d/direnv/checks/nix-direnv.nix b/wrapperModules/d/direnv/checks/nix-direnv.nix new file mode 100644 index 00000000..2e461522 --- /dev/null +++ b/wrapperModules/d/direnv/checks/nix-direnv.nix @@ -0,0 +1,22 @@ +{ + pkgs, + self, + runTest, +}: + +let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + # TODO: This seems dumb. Is there no better way to do this? + cfg = (wrapper.eval { }).config; + dotdir = "${wrapper}/${cfg.configDirname}"; + + test = runTest "direnv-test" { } '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + is_directory "${dotdir}" + is_file "${dotdir}/lib/nix-direnv.sh" + ''; +in +test diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index 83aeefb2..c18fe3a6 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -33,6 +33,7 @@ in }; lib = lib.mkOption { type = with lib.types; attrsOf lines; + description = "TODO"; default = { }; }; extraConfig = lib.mkOption { From 4cf2c0298a030077031aa75c6ab7191b05996d35 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 28 Mar 2026 09:40:49 +0100 Subject: [PATCH 07/34] rework tests --- wrapperModules/d/direnv/check.nix | 40 +++++++-------- wrapperModules/d/direnv/checks/nix-direnv.nix | 50 +++++++++++++------ 2 files changed, 55 insertions(+), 35 deletions(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index ae31943b..35db8f1f 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -5,18 +5,6 @@ let lib = pkgs.lib; - # wrapperWithoutNixDirenv = self.wrappers.direnv.wrap { - # inherit pkgs; - # nix-direnv.enable = true; - # }; - # wrapperWithNixDirenv = self.wrappers.direnv.wrap { - # inherit pkgs; - # nix-direnv.enable = true; - # }; - # TODO: This seems dumb. Is there no better way to do this? - # cfg = (wrapperWithNixDirenv.eval { }).config; - # dotdir = "${wrapperWithNixDirenv}/${cfg.configDirname}"; - testUtils = '' is_directory() { local path="$1" @@ -40,8 +28,8 @@ let ''; runTest = - name: attrs: script: - pkgs.runCommand name attrs '' + name: script: + pkgs.runCommand name { } '' ${testUtils} ${script} @@ -49,16 +37,26 @@ let touch $out ''; - runCheck = name: (import ./checks/${name}) { inherit pkgs self runTest; }; + runTests = + name: tests: + runTest "test-group-${name}" '' + # "${lib.concatStringsSep " " tests}" + ''; + + runCheck = + name: + (import ./checks/${name}) { + inherit + pkgs + self + runTest + runTests + ; + }; checks = lib.pipe ./checks [ builtins.readDir (lib.filterAttrs (name: type: type == "regular")) (lib.mapAttrsToList (name: _: (runCheck name))) ]; in -# TODO: We need to return a derivation. -# Create a dummie derivation that references `checks` to -# ensure they are evaluated. -runTest "all-tests" { } '' - # "${lib.concatStringsSep " " checks}" -'' +runTests "direnv-all" checks diff --git a/wrapperModules/d/direnv/checks/nix-direnv.nix b/wrapperModules/d/direnv/checks/nix-direnv.nix index 2e461522..736a3eed 100644 --- a/wrapperModules/d/direnv/checks/nix-direnv.nix +++ b/wrapperModules/d/direnv/checks/nix-direnv.nix @@ -2,21 +2,43 @@ pkgs, self, runTest, + runTests, }: let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = true; - }; - # TODO: This seems dumb. Is there no better way to do this? - cfg = (wrapper.eval { }).config; - dotdir = "${wrapper}/${cfg.configDirname}"; - - test = runTest "direnv-test" { } '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - is_directory "${dotdir}" - is_file "${dotdir}/lib/nix-direnv.sh" - ''; + getDotdir = + wrapper: + let + cfg = (wrapper.eval { }).config; + dotdir = "${wrapper}/${cfg.configDirname}"; + in + dotdir; in -test +runTests "nix-direnv" [ + (runTest "if nix-direnv is enabled then lib/nix-direnv.sh exists" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + in + '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + is_directory "${getDotdir wrapper}" + is_file "${getDotdir wrapper}/lib/nix-direnv.sh" + '' + )) + (runTest "if nix-direnv is diabled then lib/nix-direnv.sh does not exist" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = false; + }; + in + '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + is_directory "${getDotdir wrapper}" + ! is_file "${getDotdir wrapper}/lib/nix-direnv.sh" + '' + )) +] From 0d709d0044f35bc46a2ff481d59f662762e4f295 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 12:58:04 +0200 Subject: [PATCH 08/34] use a single drv for tests --- wrapperModules/d/direnv/check.nix | 155 +++++++++++++++--- wrapperModules/d/direnv/checks/nix-direnv.nix | 44 ----- 2 files changed, 129 insertions(+), 70 deletions(-) delete mode 100644 wrapperModules/d/direnv/checks/nix-direnv.nix diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 35db8f1f..0cf0cba9 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -25,38 +25,141 @@ let return 1 fi } + + file_contains() { + local file="$1" + local pattern="$2" + if grep -q "$pattern" "$file"; then + return 0 + else + echo "Pattern '$pattern' not found in $file" >&2 + return 1 + fi + } ''; - runTest = - name: script: + runTests = + name: scripts: pkgs.runCommand name { } '' ${testUtils} - - ${script} - + ${lib.concatStringsSep "\n\n" scripts} touch $out ''; - runTests = - name: tests: - runTest "test-group-${name}" '' - # "${lib.concatStringsSep " " tests}" - ''; + runTest = name: script: '' + run() { + ${script} + } + + run || (echo 'test "${name}" failed' >&2 && exit 1) + ''; - runCheck = - name: - (import ./checks/${name}) { - inherit - pkgs - self - runTest - runTests - ; - }; - checks = lib.pipe ./checks [ - builtins.readDir - (lib.filterAttrs (name: type: type == "regular")) - (lib.mapAttrsToList (name: _: (runCheck name))) - ]; + getDotdir = + wrapper: + let + cfg = (wrapper.eval { }).config; + dotdir = "${wrapper}/${cfg.configDirname}"; + in + dotdir; in -runTests "direnv-all" checks +# runTests "direnv-all" checks +runTests "direnv-test" [ + (runTest "wrapper should output correct version" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + in + '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + '' + )) + (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + in + '' + is_directory "${getDotdir wrapper}" + is_file "${getDotdir wrapper}/lib/nix-direnv.sh" + '' + )) + (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = false; + }; + in + '' + is_directory "${getDotdir wrapper}" + ! is_file "${getDotdir wrapper}/lib/nix-direnv.sh" + '' + )) + (runTest "if a lib-script is set then it should be generated" ( + let + libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + libScriptContent = "echo foo"; + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + lib."foo.sh" = libScriptContent; + }; + in + '' + is_directory "${getDotdir wrapper}" + is_file "${libScriptFile}" + file_contains ${libScriptFile} ${libScriptContent} + '' + )) + (runTest "if silent mode is enabled then log settings should be set" ( + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + silent = true; + }; + in + '' + is_directory "${getDotdir wrapper}" + is_file "${direnvTomlFile}" + file_contains ${direnvTomlFile} 'log_format' + file_contains ${direnvTomlFile} 'log_filter' + '' + )) + (runTest "if extraConfig is working" ( + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + extraConfig = { + fooSection.fooKey = "fooValue"; + }; + }; + in + '' + is_directory "${getDotdir wrapper}" + is_file "${direnvTomlFile}" + file_contains ${direnvTomlFile} '[fooSection]' + file_contains ${direnvTomlFile} 'fooKey.*fooValue' + '' + )) + (runTest "if direnvrc is working" ( + let + direnvrcFile = "${getDotdir wrapper}/direnvrc"; + direnvrcContent = "echo foo"; + + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + direnvrc = direnvrcContent; + }; + in + '' + is_directory "${getDotdir wrapper}" + is_file "${direnvrcFile}" + file_contains ${direnvrcFile} '${direnvrcContent}' + '' + )) +] diff --git a/wrapperModules/d/direnv/checks/nix-direnv.nix b/wrapperModules/d/direnv/checks/nix-direnv.nix deleted file mode 100644 index 736a3eed..00000000 --- a/wrapperModules/d/direnv/checks/nix-direnv.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ - pkgs, - self, - runTest, - runTests, -}: - -let - getDotdir = - wrapper: - let - cfg = (wrapper.eval { }).config; - dotdir = "${wrapper}/${cfg.configDirname}"; - in - dotdir; -in -runTests "nix-direnv" [ - (runTest "if nix-direnv is enabled then lib/nix-direnv.sh exists" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = true; - }; - in - '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - is_directory "${getDotdir wrapper}" - is_file "${getDotdir wrapper}/lib/nix-direnv.sh" - '' - )) - (runTest "if nix-direnv is diabled then lib/nix-direnv.sh does not exist" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = false; - }; - in - '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - is_directory "${getDotdir wrapper}" - ! is_file "${getDotdir wrapper}/lib/nix-direnv.sh" - '' - )) -] From a8378879883f9335715cecd94d08664ac887518a Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 15:49:35 +0200 Subject: [PATCH 09/34] rework: use nix functions as assertions This way we have a way to join assertions using '&&' and can group assertions. If any assertion fails it will print the error message of the given assertin as well as the name of the test --- wrapperModules/d/direnv/check.nix | 38 ++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 0cf0cba9..5f9db2f1 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -5,6 +5,20 @@ let lib = pkgs.lib; + is_directory = path: '' + [ -d "${path}" ] || (echo "No such directory ${path}" >&2; return 1) + ''; + is_file = path: '' + [ -f "${path}" ] || (echo "No such file ${path}" >&2; return 1) + ''; + file_contains = file: pattern: '' + if grep -q '${pattern}' "${file}"; then + return 0 + else + echo "Pattern '${pattern}' not found in ${file}" >&2 + return 1 + fi + ''; testUtils = '' is_directory() { local path="$1" @@ -46,6 +60,13 @@ let touch $out ''; + runTest2 = name: assertions: '' + run() { + ${lib.concatMapStringsSep " && " (a: "(${a})") assertions} + } + + run || (echo 'test "${name}" failed' >&2 && exit 1) + ''; runTest = name: script: '' run() { ${script} @@ -129,6 +150,21 @@ runTests "direnv-test" [ file_contains ${direnvTomlFile} 'log_filter' '' )) + (runTest2 "if silent mode is enabled then log settings should be set" ( + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + silent = true; + }; + in + [ + (is_directory (getDotdir wrapper)) + (is_file (direnvTomlFile)) + (file_contains direnvTomlFile "log_format") + (file_contains direnvTomlFile "log_filter") + ] + )) (runTest "if extraConfig is working" ( let direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; @@ -142,7 +178,7 @@ runTests "direnv-test" [ '' is_directory "${getDotdir wrapper}" is_file "${direnvTomlFile}" - file_contains ${direnvTomlFile} '[fooSection]' + file_contains ${direnvTomlFile} '\[fooSection\]' file_contains ${direnvTomlFile} 'fooKey.*fooValue' '' )) From e8879cc15b7d4602b37652bb296960cf91f84967 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 16:15:55 +0200 Subject: [PATCH 10/34] make all tests assertion-based --- wrapperModules/d/direnv/check.nix | 87 ++++++++++++++----------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 5f9db2f1..feea0689 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -11,6 +11,9 @@ let is_file = path: '' [ -f "${path}" ] || (echo "No such file ${path}" >&2; return 1) ''; + not_is_file = path: '' + [ ! -f "${path}" ] || (echo "File ${path} should not exist" >&2; return 1) + ''; file_contains = file: pattern: '' if grep -q '${pattern}' "${file}"; then return 0 @@ -62,7 +65,7 @@ let runTest2 = name: assertions: '' run() { - ${lib.concatMapStringsSep " && " (a: "(${a})") assertions} + ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} } run || (echo 'test "${name}" failed' >&2 && exit 1) @@ -83,9 +86,8 @@ let in dotdir; in -# runTests "direnv-all" checks runTests "direnv-test" [ - (runTest "wrapper should output correct version" ( + (runTest2 "wrapper should output correct version" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; @@ -96,31 +98,31 @@ runTests "direnv-test" [ "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '' )) - (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( + (runTest2 "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; nix-direnv.enable = true; }; in - '' - is_directory "${getDotdir wrapper}" - is_file "${getDotdir wrapper}/lib/nix-direnv.sh" - '' + [ + (is_directory (getDotdir wrapper)) + (is_file "${getDotdir wrapper}/lib/nix-direnv.sh") + ] )) - (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( + (runTest2 "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; nix-direnv.enable = false; }; in - '' - is_directory "${getDotdir wrapper}" - ! is_file "${getDotdir wrapper}/lib/nix-direnv.sh" - '' + [ + (is_directory (getDotdir wrapper)) + (not_is_file "${getDotdir wrapper}/lib/nix-direnv.sh") + ] )) - (runTest "if a lib-script is set then it should be generated" ( + (runTest2 "if a lib-script is set then it should be generated" ( let libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; libScriptContent = "echo foo"; @@ -129,26 +131,12 @@ runTests "direnv-test" [ lib."foo.sh" = libScriptContent; }; in - '' - is_directory "${getDotdir wrapper}" - is_file "${libScriptFile}" - file_contains ${libScriptFile} ${libScriptContent} - '' - )) - (runTest "if silent mode is enabled then log settings should be set" ( - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - silent = true; - }; - in - '' - is_directory "${getDotdir wrapper}" - is_file "${direnvTomlFile}" - file_contains ${direnvTomlFile} 'log_format' - file_contains ${direnvTomlFile} 'log_filter' - '' + [ + (is_directory (getDotdir wrapper)) + (is_file libScriptFile) + (file_contains libScriptFile libScriptContent) + + ] )) (runTest2 "if silent mode is enabled then log settings should be set" ( let @@ -160,12 +148,13 @@ runTests "direnv-test" [ in [ (is_directory (getDotdir wrapper)) - (is_file (direnvTomlFile)) + (is_file direnvTomlFile) (file_contains direnvTomlFile "log_format") (file_contains direnvTomlFile "log_filter") + ] )) - (runTest "if extraConfig is working" ( + (runTest2 "if extraConfig is working" ( let direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; wrapper = self.wrappers.direnv.wrap { @@ -175,14 +164,15 @@ runTests "direnv-test" [ }; }; in - '' - is_directory "${getDotdir wrapper}" - is_file "${direnvTomlFile}" - file_contains ${direnvTomlFile} '\[fooSection\]' - file_contains ${direnvTomlFile} 'fooKey.*fooValue' - '' + [ + (is_directory (getDotdir wrapper)) + (is_file direnvTomlFile) + (file_contains direnvTomlFile "\\[fooSection\\]") + (file_contains direnvTomlFile "fooKey.*fooValue") + + ] )) - (runTest "if direnvrc is working" ( + (runTest2 "if direnvrc is working" ( let direnvrcFile = "${getDotdir wrapper}/direnvrc"; direnvrcContent = "echo foo"; @@ -192,10 +182,11 @@ runTests "direnv-test" [ direnvrc = direnvrcContent; }; in - '' - is_directory "${getDotdir wrapper}" - is_file "${direnvrcFile}" - file_contains ${direnvrcFile} '${direnvrcContent}' - '' + [ + (is_directory (getDotdir wrapper)) + (is_file direnvrcFile) + (file_contains direnvrcFile direnvrcContent) + + ] )) ] From 8eba70b3a14a21323a4d0b62dd3a9eeaaea64dd6 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 16:17:52 +0200 Subject: [PATCH 11/34] rename functions --- wrapperModules/d/direnv/check.nix | 136 ++++++++++++------------------ 1 file changed, 55 insertions(+), 81 deletions(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index feea0689..144be999 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -5,78 +5,52 @@ let lib = pkgs.lib; - is_directory = path: '' - [ -d "${path}" ] || (echo "No such directory ${path}" >&2; return 1) - ''; - is_file = path: '' - [ -f "${path}" ] || (echo "No such file ${path}" >&2; return 1) - ''; - not_is_file = path: '' - [ ! -f "${path}" ] || (echo "File ${path} should not exist" >&2; return 1) - ''; - file_contains = file: pattern: '' - if grep -q '${pattern}' "${file}"; then - return 0 - else - echo "Pattern '${pattern}' not found in ${file}" >&2 - return 1 - fi - ''; - testUtils = '' - is_directory() { - local path="$1" - if [ -d "$path" ]; then - return 0 - else - echo "No directory $path" >&2 - return 1 - fi - } + createAssertion = + { cond, message }: + '' + (${cond}) || (echo "${message}" >&2; return 1) + ''; - is_file() { - local path="$1" - if [ -f "$path" ]; then - return 0 - else - echo "No such file $path" >&2 - return 1 - fi - } + isDirectory = + path: + createAssertion { + cond = ''[ -d "${path}" ]''; + message = "No such directory ${path}"; + }; + isFile = + path: + createAssertion { + cond = ''[ -f "${path}" ]''; + message = "No such file ${path}"; + }; + notIsFile = + path: + createAssertion { + cond = ''[ ! -f "${path}" ]''; + message = "File ${path} should not exist"; + }; - file_contains() { - local file="$1" - local pattern="$2" - if grep -q "$pattern" "$file"; then - return 0 - else - echo "Pattern '$pattern' not found in $file" >&2 - return 1 - fi - } - ''; + fileContains = + file: pattern: + createAssertion { + cond = ''grep -q '${pattern}' "${file}"''; + message = "Pattern '${pattern}' not found in ${file}"; + }; runTests = name: scripts: pkgs.runCommand name { } '' - ${testUtils} ${lib.concatStringsSep "\n\n" scripts} touch $out ''; - runTest2 = name: assertions: '' + runTest = name: assertions: '' run() { ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} } run || (echo 'test "${name}" failed' >&2 && exit 1) ''; - runTest = name: script: '' - run() { - ${script} - } - - run || (echo 'test "${name}" failed' >&2 && exit 1) - ''; getDotdir = wrapper: @@ -87,7 +61,7 @@ let dotdir; in runTests "direnv-test" [ - (runTest2 "wrapper should output correct version" ( + (runTest "wrapper should output correct version" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; @@ -98,7 +72,7 @@ runTests "direnv-test" [ "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '' )) - (runTest2 "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( + (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; @@ -106,11 +80,11 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (is_file "${getDotdir wrapper}/lib/nix-direnv.sh") + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ] )) - (runTest2 "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( + (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( let wrapper = self.wrappers.direnv.wrap { inherit pkgs; @@ -118,11 +92,11 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (not_is_file "${getDotdir wrapper}/lib/nix-direnv.sh") + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") ] )) - (runTest2 "if a lib-script is set then it should be generated" ( + (runTest "if a lib-script is set then it should be generated" ( let libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; libScriptContent = "echo foo"; @@ -132,13 +106,13 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (is_file libScriptFile) - (file_contains libScriptFile libScriptContent) + (isDirectory (getDotdir wrapper)) + (isFile libScriptFile) + (fileContains libScriptFile libScriptContent) ] )) - (runTest2 "if silent mode is enabled then log settings should be set" ( + (runTest "if silent mode is enabled then log settings should be set" ( let direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; wrapper = self.wrappers.direnv.wrap { @@ -147,14 +121,14 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (is_file direnvTomlFile) - (file_contains direnvTomlFile "log_format") - (file_contains direnvTomlFile "log_filter") + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "log_format") + (fileContains direnvTomlFile "log_filter") ] )) - (runTest2 "if extraConfig is working" ( + (runTest "if extraConfig is working" ( let direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; wrapper = self.wrappers.direnv.wrap { @@ -165,14 +139,14 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (is_file direnvTomlFile) - (file_contains direnvTomlFile "\\[fooSection\\]") - (file_contains direnvTomlFile "fooKey.*fooValue") + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "\\[fooSection\\]") + (fileContains direnvTomlFile "fooKey.*fooValue") ] )) - (runTest2 "if direnvrc is working" ( + (runTest "if direnvrc is working" ( let direnvrcFile = "${getDotdir wrapper}/direnvrc"; direnvrcContent = "echo foo"; @@ -183,9 +157,9 @@ runTests "direnv-test" [ }; in [ - (is_directory (getDotdir wrapper)) - (is_file direnvrcFile) - (file_contains direnvrcFile direnvrcContent) + (isDirectory (getDotdir wrapper)) + (isFile direnvrcFile) + (fileContains direnvrcFile direnvrcContent) ] )) From 0972997796807574249de3099f0e1a4615efd4a2 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 20:03:56 +0200 Subject: [PATCH 12/34] add documentation --- wrapperModules/d/direnv/module.nix | 69 ++++++++++++++++++------------ 1 file changed, 41 insertions(+), 28 deletions(-) diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index c18fe3a6..80456307 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -10,6 +10,7 @@ let tomlFmt = pkgs.formats.toml { }; direnvToml = tomlFmt.generate "direnv.toml" config.extraConfig; + direnvDotdir = "${config.wrapper.${config.outputName}}/${config.configDirname}"; in { imports = [ wlib.modules.default ]; @@ -22,9 +23,7 @@ in silent = lib.mkEnableOption "silent mode, that is, disabling direnv logging"; direnvrc = lib.mkOption { type = lib.types.lines; - description = '' - Content of $DIRENV_CONFIG/direnv.toml - ''; + description = "Content of `$DIRENV_CONFIG/direnv`"; default = ""; }; nix-direnv = { @@ -33,7 +32,13 @@ in }; lib = lib.mkOption { type = with lib.types; attrsOf lines; - description = "TODO"; + description = '' + Configuration of [extension files](https://direnv.net/#the-stdlib) + that will be created at `$DIRENV_CONFIG/lib/*.sh` + ''; + example = { + "my-lib-script.sh" = "echo 'content of my-lib-script.sh'"; + }; default = { }; }; extraConfig = lib.mkOption { @@ -48,26 +53,15 @@ in config = { package = lib.mkDefault pkgs.direnv; env = { - # **IMPORTANT** DIRENV_CONFIG needs to be explicitly set in your shells environment - # because right now, direnv will use the `direnv` binary directly in its shell - # hook and not the wrapper (in which $DIRENV_CONFIG got injected). - # Hence the wrapped config will not be picked up unless you explicitly reference - # this variable and set it. - # - # If the PR below will ever be merged, this issue can be fixed by setting: - # - # env.DIRENV_EXE_PATH = "${placeholder "out"}/bin/direnv"; - # - # This would make the direnv hook use the wrapper instead of the original binary. - # - # https://github.com/direnv/direnv/pull/1564 + # We currently do not inject `DIRENV_CONFIG` for the reasons outlined in + # meta.description.pre. - # **IMPORTANT** Using `placeholder "out"` here seems to cause issues if this wrapper issue + # **IMPORTANT** Using `placeholder "out"` here seems to cause issues if this wrapper is # built inside a subWrapperModule (for example within the zshWrapper) as it refers # to the build zsh output in that context. The passthru variants seems to solve this issue. # DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; }; - passthru.DIRENV_CONFIG = "${config.wrapper.${config.outputName}}/${config.configDirname}"; + passthru.DIRENV_CONFIG = direnvDotdir; lib."nix-direnv.sh" = lib.mkIf (config.nix-direnv.enable) "source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc"; extraConfig = { @@ -86,15 +80,34 @@ in relPath = "${config.configDirname}/direnvrc"; }; } - // - # TODO: As of now, construcFiles does not accept keys like 'nix-direnv.sh'. - # This hack somehow avoids the issue. Find out if this needs to be fixed in - # `constructFiles`. - lib.mapAttrs (name: value: { - key = builtins.replaceStrings [ "." "-" ] [ "" "" ] name; - content = value; - relPath = "${config.configDirname}/lib/${name}"; - }) config.lib; + // lib.mapAttrs (name: value: { + # key must be a valid shell variable name + key = builtins.replaceStrings [ "." "-" ] [ "" "" ] name; + content = value; + relPath = "${config.configDirname}/lib/${name}"; + }) config.lib; meta.maintainers = [ wlib.maintainers.zenoli ]; + meta.description.pre = '' + **IMPORTANT** In order to use this wrapper, `DIRENV_CONFIG` needs to be explicitly + set in your shells environment: + + ```shell + DIRENV_CONFIG="''${direnvWrapper.passthru.DIRENV_CONFIG}" + ``` + + This is because right now, direnv will use the original `direnv` binary in its shell hook + and not the wrapper script. So injecting `DIRENV_CONFIG` currently has no effect. + + If the PR below will ever be merged, this issue can be fixed by setting: + + ```nix + env.DIRENV_EXE_PATH = "''${placeholder "out"}/bin/direnv"; + ``` + + This would make the direnv hook use the wrapper instead of the original binary and + injecting `DIRENV_CONFIG` into the wrapper would start to take effect. + + https://github.com/direnv/direnv/pull/1564 + ''; }; } From 3d61d9a806112448987961cd9c56353700366ba7 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 20:13:29 +0200 Subject: [PATCH 13/34] add mise integration --- wrapperModules/d/direnv/check.nix | 24 ++++++++++++++++++++++++ wrapperModules/d/direnv/module.nix | 16 ++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 144be999..9c59a9d3 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -96,6 +96,30 @@ runTests "direnv-test" [ (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") ] )) + (runTest "if mise is enabled then lib/mise.sh should exists" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + mise.enable = true; + }; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/mise.sh") + ] + )) + (runTest "if mise is disabled then lib/mise.sh should not exist" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + mise.enable = false; + }; + in + [ + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/mise.sh") + ] + )) (runTest "if a lib-script is set then it should be generated" ( let libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index 80456307..2e93705b 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -6,8 +6,6 @@ ... }: let - cfg = config; - tomlFmt = pkgs.formats.toml { }; direnvToml = tomlFmt.generate "direnv.toml" config.extraConfig; direnvDotdir = "${config.wrapper.${config.outputName}}/${config.configDirname}"; @@ -30,6 +28,10 @@ in enable = lib.mkEnableOption "nix-direnv integration"; package = lib.mkPackageOption pkgs "nix-direnv" { }; }; + mise = { + enable = lib.mkEnableOption "mise integration"; + package = lib.mkPackageOption pkgs "mise" { }; + }; lib = lib.mkOption { type = with lib.types; attrsOf lines; description = '' @@ -62,8 +64,14 @@ in # DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; }; passthru.DIRENV_CONFIG = direnvDotdir; - lib."nix-direnv.sh" = - lib.mkIf (config.nix-direnv.enable) "source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc"; + lib = { + "nix-direnv.sh" = lib.mkIf config.nix-direnv.enable '' + source ${config.nix-direnv.package}/share/nix-direnv/direnvRc + ''; + "mise.sh" = lib.mkIf config.mise.enable '' + eval "$(${lib.getExe config.mise.package} direnv activate)" + ''; + }; extraConfig = { global = lib.mkIf (config.silent) { log_format = "-"; From 7ce14e9bdf48020838ef70a15399f7df6c70aa1c Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 20:18:55 +0200 Subject: [PATCH 14/34] fix maintainers --- maintainers/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/maintainers/default.nix b/maintainers/default.nix index 4ae93165..8a14413f 100644 --- a/maintainers/default.nix +++ b/maintainers/default.nix @@ -60,6 +60,7 @@ github = "nikitawootten"; githubId = 8916363; name = "Nikita Wootten"; + }; zenoli = { name = "Zenoli"; github = "zenoli"; From e7db435ecb704a0b002d3ddba94304d6863feaaa Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sun, 29 Mar 2026 23:13:51 +0200 Subject: [PATCH 15/34] add env.CONFIG_DIRENV --- wrapperModules/d/direnv/module.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index 2e93705b..aa7defd5 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -61,12 +61,12 @@ in # **IMPORTANT** Using `placeholder "out"` here seems to cause issues if this wrapper is # built inside a subWrapperModule (for example within the zshWrapper) as it refers # to the build zsh output in that context. The passthru variants seems to solve this issue. - # DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; + DIRENV_CONFIG = "${placeholder "out"}/${config.configDirname}"; }; passthru.DIRENV_CONFIG = direnvDotdir; lib = { "nix-direnv.sh" = lib.mkIf config.nix-direnv.enable '' - source ${config.nix-direnv.package}/share/nix-direnv/direnvRc + source ${config.nix-direnv.package}/share/nix-direnv/direnvrc ''; "mise.sh" = lib.mkIf config.mise.enable '' eval "$(${lib.getExe config.mise.package} direnv activate)" From 0253039b8d224e585e8cb133a28b4a0492e783e2 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Tue, 31 Mar 2026 00:23:16 +0200 Subject: [PATCH 16/34] remove "key"-transform hack construcFiles sanitizes the key by default now --- wrapperModules/d/direnv/module.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/wrapperModules/d/direnv/module.nix b/wrapperModules/d/direnv/module.nix index aa7defd5..0bfebb59 100644 --- a/wrapperModules/d/direnv/module.nix +++ b/wrapperModules/d/direnv/module.nix @@ -89,8 +89,6 @@ in }; } // lib.mapAttrs (name: value: { - # key must be a valid shell variable name - key = builtins.replaceStrings [ "." "-" ] [ "" "" ] name; content = value; relPath = "${config.configDirname}/lib/${name}"; }) config.lib; From 7e989fe0a5db185681cb85160c96624eefb5cba6 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Wed, 15 Apr 2026 22:10:22 +0200 Subject: [PATCH 17/34] add tlib --- ci/checks/all-modules-have-maintainers.nix | 1 + ci/checks/apply.nix | 1 + ci/checks/formatting.nix | 1 + ci/checks/makeCustomizable.nix | 1 + ci/checks/meta-maintainers.nix | 1 + ci/checks/meta-platforms.nix | 1 + ci/checks/outputName-tests.nix | 1 + ci/checks/subwrappermodule.nix | 1 + ci/checks/toKdl.nix | 1 + ci/checks/types-file.nix | 1 + ci/flake.nix | 5 +- ci/test-lib.nix | 51 +++++++++++++++++++ modules/makeWrapper/checks/args-direct.nix | 1 + modules/makeWrapper/checks/env-null.nix | 1 + .../checks/flags-equals-separator.nix | 1 + modules/makeWrapper/checks/flags-list.nix | 1 + .../makeWrapper/checks/flags-null-false.nix | 1 + .../checks/flags-space-separator.nix | 1 + modules/makeWrapper/checks/flags.nix | 1 + .../checks/filesToExclude-glob.nix | 1 + .../checks/filesToExclude-more.nix | 1 + .../symlinkScript/checks/filesToExclude.nix | 1 + modules/symlinkScript/checks/filesToPatch.nix | 1 + wrapperModules/a/aria2/check.nix | 1 + wrapperModules/a/atool/check.nix | 2 +- wrapperModules/c/cava/check.nix | 1 + wrapperModules/c/claude-code/check.nix | 1 + wrapperModules/d/direnv/check.nix | 14 ++--- wrapperModules/e/emacs/check.nix | 1 + wrapperModules/g/git/check.nix | 1 + wrapperModules/h/helix/check.nix | 1 + wrapperModules/j/jujutsu/check.nix | 1 + wrapperModules/m/mako/check.nix | 1 + wrapperModules/m/mangowc/check.nix | 1 + wrapperModules/m/mpv/check.nix | 1 + wrapperModules/n/niri/check.nix | 1 + wrapperModules/n/notmuch/check.nix | 1 + wrapperModules/n/nushell/check.nix | 1 + wrapperModules/r/rofi/check.nix | 1 + wrapperModules/v/vim/check.nix | 1 + wrapperModules/w/waybar/check.nix | 1 + wrapperModules/w/wezterm/check.nix | 1 + wrapperModules/x/xplr/check.nix | 1 + wrapperModules/y/yazi/check.nix | 1 + wrapperModules/y/yt-dlp/check.nix | 2 +- wrapperModules/z/zsh/check.nix | 1 + 46 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 ci/test-lib.nix diff --git a/ci/checks/all-modules-have-maintainers.nix b/ci/checks/all-modules-have-maintainers.nix index 8331fa51..cb952874 100644 --- a/ci/checks/all-modules-have-maintainers.nix +++ b/ci/checks/all-modules-have-maintainers.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/ci/checks/apply.nix b/ci/checks/apply.nix index 63320c2e..093b1d2a 100644 --- a/ci/checks/apply.nix +++ b/ci/checks/apply.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: # TODO: make sure theres no other stuff passing on accident in here let diff --git a/ci/checks/formatting.nix b/ci/checks/formatting.nix index 9b2c161b..3a7d0e50 100644 --- a/ci/checks/formatting.nix +++ b/ci/checks/formatting.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: pkgs.runCommand "formatting-check" { } '' diff --git a/ci/checks/makeCustomizable.nix b/ci/checks/makeCustomizable.nix index 02d61343..d89f284a 100644 --- a/ci/checks/makeCustomizable.nix +++ b/ci/checks/makeCustomizable.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let luaEnv = self.lib.makeCustomizable "withPackages" { diff --git a/ci/checks/meta-maintainers.nix b/ci/checks/meta-maintainers.nix index f06d7017..3e5504bb 100644 --- a/ci/checks/meta-maintainers.nix +++ b/ci/checks/meta-maintainers.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/ci/checks/meta-platforms.nix b/ci/checks/meta-platforms.nix index acb18953..fdf9af38 100644 --- a/ci/checks/meta-platforms.nix +++ b/ci/checks/meta-platforms.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/ci/checks/outputName-tests.nix b/ci/checks/outputName-tests.nix index 22915fb2..ba3feadc 100644 --- a/ci/checks/outputName-tests.nix +++ b/ci/checks/outputName-tests.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/ci/checks/subwrappermodule.nix b/ci/checks/subwrappermodule.nix index 58aca0e8..613be394 100644 --- a/ci/checks/subwrappermodule.nix +++ b/ci/checks/subwrappermodule.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let evaled = self.lib.evalModule [ diff --git a/ci/checks/toKdl.nix b/ci/checks/toKdl.nix index 3e58b83a..66f29b6f 100644 --- a/ci/checks/toKdl.nix +++ b/ci/checks/toKdl.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let lib = pkgs.lib; diff --git a/ci/checks/types-file.nix b/ci/checks/types-file.nix index 1340b9ae..fb684d60 100644 --- a/ci/checks/types-file.nix +++ b/ci/checks/types-file.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let lib = pkgs.lib; diff --git a/ci/flake.nix b/ci/flake.nix index e0d45780..19508ef4 100644 --- a/ci/flake.nix +++ b/ci/flake.nix @@ -20,6 +20,7 @@ inherit system; config.allowUnfree = true; }; + tlib = pkgs.callPackage ./test-lib.nix {}; # Load checks from ci/checks/ directory coreAndCiChecks = lib.pipe ./checks [ @@ -43,9 +44,9 @@ name = "${prefix}-${name}"; inherit value; }; - result = pkgs.callPackage value { inherit self; }; + result = pkgs.callPackage value { inherit self tlib; }; in - if isNull result then + if result == null then [ ] else if result ? outPath then [ (helper prefix name result) ] diff --git a/ci/test-lib.nix b/ci/test-lib.nix new file mode 100644 index 00000000..843b6c7f --- /dev/null +++ b/ci/test-lib.nix @@ -0,0 +1,51 @@ +{ lib, runCommand, ... }: +let + createAssertion = + { cond, message }: + '' + (${cond}) || (echo "${message}" >&2; return 1) + ''; +in +{ + inherit createAssertion; + isDirectory = + path: + createAssertion { + cond = ''[ -d "${path}" ]''; + message = "No such directory ${path}"; + }; + isFile = + path: + createAssertion { + cond = ''[ -f "${path}" ]''; + message = "No such file ${path}"; + }; + notIsFile = + path: + createAssertion { + cond = ''[ ! -f "${path}" ]''; + message = "File ${path} should not exist"; + }; + + fileContains = + file: pattern: + createAssertion { + cond = ''grep -q '${pattern}' "${file}"''; + message = "Pattern '${pattern}' not found in ${file}"; + }; + + runTests = + name: scripts: + runCommand name { } '' + ${lib.concatStringsSep "\n\n" scripts} + touch $out + ''; + + runTest = name: assertions: '' + run() { + ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} + } + + run || (echo 'test "${name}" failed' >&2 && exit 1) + ''; +} diff --git a/modules/makeWrapper/checks/args-direct.nix b/modules/makeWrapper/checks/args-direct.nix index 554ef1ee..b17bb174 100644 --- a/modules/makeWrapper/checks/args-direct.nix +++ b/modules/makeWrapper/checks/args-direct.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/env-null.nix b/modules/makeWrapper/checks/env-null.nix index 1055d1e2..7c647238 100644 --- a/modules/makeWrapper/checks/env-null.nix +++ b/modules/makeWrapper/checks/env-null.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/flags-equals-separator.nix b/modules/makeWrapper/checks/flags-equals-separator.nix index 2f1ba67f..30cc24a6 100644 --- a/modules/makeWrapper/checks/flags-equals-separator.nix +++ b/modules/makeWrapper/checks/flags-equals-separator.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/flags-list.nix b/modules/makeWrapper/checks/flags-list.nix index c70e6b86..bc57773e 100644 --- a/modules/makeWrapper/checks/flags-list.nix +++ b/modules/makeWrapper/checks/flags-list.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/flags-null-false.nix b/modules/makeWrapper/checks/flags-null-false.nix index 72cce64d..4f4c591d 100644 --- a/modules/makeWrapper/checks/flags-null-false.nix +++ b/modules/makeWrapper/checks/flags-null-false.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/flags-space-separator.nix b/modules/makeWrapper/checks/flags-space-separator.nix index 68e0d929..fe396a63 100644 --- a/modules/makeWrapper/checks/flags-space-separator.nix +++ b/modules/makeWrapper/checks/flags-space-separator.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/makeWrapper/checks/flags.nix b/modules/makeWrapper/checks/flags.nix index 2ebf1213..9e1080e8 100644 --- a/modules/makeWrapper/checks/flags.nix +++ b/modules/makeWrapper/checks/flags.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/symlinkScript/checks/filesToExclude-glob.nix b/modules/symlinkScript/checks/filesToExclude-glob.nix index c630230a..b2606f0c 100644 --- a/modules/symlinkScript/checks/filesToExclude-glob.nix +++ b/modules/symlinkScript/checks/filesToExclude-glob.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/symlinkScript/checks/filesToExclude-more.nix b/modules/symlinkScript/checks/filesToExclude-more.nix index e0309596..3aa00cc7 100644 --- a/modules/symlinkScript/checks/filesToExclude-more.nix +++ b/modules/symlinkScript/checks/filesToExclude-more.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/symlinkScript/checks/filesToExclude.nix b/modules/symlinkScript/checks/filesToExclude.nix index ef6782fd..53e2b073 100644 --- a/modules/symlinkScript/checks/filesToExclude.nix +++ b/modules/symlinkScript/checks/filesToExclude.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/modules/symlinkScript/checks/filesToPatch.nix b/modules/symlinkScript/checks/filesToPatch.nix index 6010a2ff..af1fa392 100644 --- a/modules/symlinkScript/checks/filesToPatch.nix +++ b/modules/symlinkScript/checks/filesToPatch.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/a/aria2/check.nix b/wrapperModules/a/aria2/check.nix index 03462222..657c3b09 100644 --- a/wrapperModules/a/aria2/check.nix +++ b/wrapperModules/a/aria2/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let aria2Wrapper = self.wrappers.aria2.wrap { diff --git a/wrapperModules/a/atool/check.nix b/wrapperModules/a/atool/check.nix index 8ddefd45..88255abb 100644 --- a/wrapperModules/a/atool/check.nix +++ b/wrapperModules/a/atool/check.nix @@ -1,4 +1,4 @@ -{ pkgs, self }: +{ pkgs, self, ... }: let atoolWrapped = self.wrappers.atool.wrap { inherit pkgs; diff --git a/wrapperModules/c/cava/check.nix b/wrapperModules/c/cava/check.nix index 92d36f78..66d4f57b 100644 --- a/wrapperModules/c/cava/check.nix +++ b/wrapperModules/c/cava/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let cavaWrapper = self.wrappers.cava.wrap { inherit pkgs; }; diff --git a/wrapperModules/c/claude-code/check.nix b/wrapperModules/c/claude-code/check.nix index fdf993de..7a27347b 100644 --- a/wrapperModules/c/claude-code/check.nix +++ b/wrapperModules/c/claude-code/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let claudeCodeWrapped = self.wrappers.claude-code.wrap { diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 9c59a9d3..bb1af4b2 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -1,15 +1,18 @@ { pkgs, self, + tlib, + ... }: let lib = pkgs.lib; - createAssertion = - { cond, message }: - '' - (${cond}) || (echo "${message}" >&2; return 1) - ''; + createAssertion = tlib.createAssertion; + # createAssertion = + # { cond, message }: + # '' + # (${cond}) || (echo "${message}" >&2; return 1) + # ''; isDirectory = path: @@ -65,7 +68,6 @@ runTests "direnv-test" [ let wrapper = self.wrappers.direnv.wrap { inherit pkgs; - nix-direnv.enable = true; }; in '' diff --git a/wrapperModules/e/emacs/check.nix b/wrapperModules/e/emacs/check.nix index abeac665..d6e9d9b9 100644 --- a/wrapperModules/e/emacs/check.nix +++ b/wrapperModules/e/emacs/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let emacsWrapped = diff --git a/wrapperModules/g/git/check.nix b/wrapperModules/g/git/check.nix index be284e0d..06966848 100644 --- a/wrapperModules/g/git/check.nix +++ b/wrapperModules/g/git/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/h/helix/check.nix b/wrapperModules/h/helix/check.nix index cadb67f1..6794e29c 100644 --- a/wrapperModules/h/helix/check.nix +++ b/wrapperModules/h/helix/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/j/jujutsu/check.nix b/wrapperModules/j/jujutsu/check.nix index 25393569..abdcb388 100644 --- a/wrapperModules/j/jujutsu/check.nix +++ b/wrapperModules/j/jujutsu/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/m/mako/check.nix b/wrapperModules/m/mako/check.nix index 875c4530..7313b067 100644 --- a/wrapperModules/m/mako/check.nix +++ b/wrapperModules/m/mako/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/m/mangowc/check.nix b/wrapperModules/m/mangowc/check.nix index a981bf26..1fdffa9a 100644 --- a/wrapperModules/m/mangowc/check.nix +++ b/wrapperModules/m/mangowc/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let mangowcWrapped = self.wrappers.mangowc.wrap { diff --git a/wrapperModules/m/mpv/check.nix b/wrapperModules/m/mpv/check.nix index cd3b3872..4c54d9f6 100644 --- a/wrapperModules/m/mpv/check.nix +++ b/wrapperModules/m/mpv/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/n/niri/check.nix b/wrapperModules/n/niri/check.nix index 39fe9e2c..4b509744 100644 --- a/wrapperModules/n/niri/check.nix +++ b/wrapperModules/n/niri/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/n/notmuch/check.nix b/wrapperModules/n/notmuch/check.nix index 467fe962..5d53e138 100644 --- a/wrapperModules/n/notmuch/check.nix +++ b/wrapperModules/n/notmuch/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/n/nushell/check.nix b/wrapperModules/n/nushell/check.nix index 70be36f9..fcea4536 100644 --- a/wrapperModules/n/nushell/check.nix +++ b/wrapperModules/n/nushell/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/r/rofi/check.nix b/wrapperModules/r/rofi/check.nix index c67b9aab..6215e4b2 100644 --- a/wrapperModules/r/rofi/check.nix +++ b/wrapperModules/r/rofi/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/v/vim/check.nix b/wrapperModules/v/vim/check.nix index d21c6ee1..fd0f3c40 100644 --- a/wrapperModules/v/vim/check.nix +++ b/wrapperModules/v/vim/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let diff --git a/wrapperModules/w/waybar/check.nix b/wrapperModules/w/waybar/check.nix index 313fc8d1..a264032c 100644 --- a/wrapperModules/w/waybar/check.nix +++ b/wrapperModules/w/waybar/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let waybarWrapped = self.wrappers.waybar.wrap { diff --git a/wrapperModules/w/wezterm/check.nix b/wrapperModules/w/wezterm/check.nix index 4cff4292..50d25d5c 100644 --- a/wrapperModules/w/wezterm/check.nix +++ b/wrapperModules/w/wezterm/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let weztermWrapped = self.wrappers.wezterm.wrap ( diff --git a/wrapperModules/x/xplr/check.nix b/wrapperModules/x/xplr/check.nix index 712f104e..847a5ba2 100644 --- a/wrapperModules/x/xplr/check.nix +++ b/wrapperModules/x/xplr/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let xplr = self.wrappers.xplr.wrap ( diff --git a/wrapperModules/y/yazi/check.nix b/wrapperModules/y/yazi/check.nix index 15b7aa73..0cb310cb 100644 --- a/wrapperModules/y/yazi/check.nix +++ b/wrapperModules/y/yazi/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let yaziWrapper = self.wrappers.yazi.wrap { inherit pkgs; }; diff --git a/wrapperModules/y/yt-dlp/check.nix b/wrapperModules/y/yt-dlp/check.nix index 769b7fc0..cac06e71 100644 --- a/wrapperModules/y/yt-dlp/check.nix +++ b/wrapperModules/y/yt-dlp/check.nix @@ -1,4 +1,4 @@ -{ pkgs, self }: +{ pkgs, self, ... }: let ytWrapped = self.wrappers.yt-dlp.wrap { inherit pkgs; diff --git a/wrapperModules/z/zsh/check.nix b/wrapperModules/z/zsh/check.nix index a2d2f8b4..80a44b4f 100644 --- a/wrapperModules/z/zsh/check.nix +++ b/wrapperModules/z/zsh/check.nix @@ -1,6 +1,7 @@ { pkgs, self, + ... }: let From 825f1fe61f467484e3b95e50ad785b54954c2ce0 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Wed, 15 Apr 2026 22:15:14 +0200 Subject: [PATCH 18/34] cleanup --- ci/flake.nix | 2 +- ci/test-lib.nix | 4 +-- wrapperModules/d/direnv/check.nix | 56 +++++-------------------------- 3 files changed, 11 insertions(+), 51 deletions(-) diff --git a/ci/flake.nix b/ci/flake.nix index 19508ef4..ed271471 100644 --- a/ci/flake.nix +++ b/ci/flake.nix @@ -20,7 +20,7 @@ inherit system; config.allowUnfree = true; }; - tlib = pkgs.callPackage ./test-lib.nix {}; + tlib = pkgs.callPackage ./test-lib.nix { }; # Load checks from ci/checks/ directory coreAndCiChecks = lib.pipe ./checks [ diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 843b6c7f..9862bfd3 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -1,11 +1,11 @@ -{ lib, runCommand, ... }: +{ lib, runCommand, ... }: let createAssertion = { cond, message }: '' (${cond}) || (echo "${message}" >&2; return 1) ''; -in +in { inherit createAssertion; isDirectory = diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index bb1af4b2..b6748509 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -6,54 +6,14 @@ }: let - lib = pkgs.lib; - createAssertion = tlib.createAssertion; - # createAssertion = - # { cond, message }: - # '' - # (${cond}) || (echo "${message}" >&2; return 1) - # ''; - - isDirectory = - path: - createAssertion { - cond = ''[ -d "${path}" ]''; - message = "No such directory ${path}"; - }; - isFile = - path: - createAssertion { - cond = ''[ -f "${path}" ]''; - message = "No such file ${path}"; - }; - notIsFile = - path: - createAssertion { - cond = ''[ ! -f "${path}" ]''; - message = "File ${path} should not exist"; - }; - - fileContains = - file: pattern: - createAssertion { - cond = ''grep -q '${pattern}' "${file}"''; - message = "Pattern '${pattern}' not found in ${file}"; - }; - - runTests = - name: scripts: - pkgs.runCommand name { } '' - ${lib.concatStringsSep "\n\n" scripts} - touch $out - ''; - - runTest = name: assertions: '' - run() { - ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} - } - - run || (echo 'test "${name}" failed' >&2 && exit 1) - ''; + inherit (tlib) + fileContains + isDirectory + isFile + notIsFile + runTest + runTests + ; getDotdir = wrapper: From 9f67878c633fdd87f69987d354c7fafa22cf7735 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Thu, 16 Apr 2026 22:27:53 +0200 Subject: [PATCH 19/34] pass wrapperModule to runTests (wip) --- ci/flake.nix | 2 +- ci/test-lib.nix | 27 +++++++++++++++++++++------ wrapperModules/d/direnv/check.nix | 3 +-- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/ci/flake.nix b/ci/flake.nix index ed271471..5d6e3965 100644 --- a/ci/flake.nix +++ b/ci/flake.nix @@ -20,7 +20,7 @@ inherit system; config.allowUnfree = true; }; - tlib = pkgs.callPackage ./test-lib.nix { }; + tlib = pkgs.callPackage ./test-lib.nix { inherit self; }; # Load checks from ci/checks/ directory coreAndCiChecks = lib.pipe ./checks [ diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 9862bfd3..35082a28 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -1,4 +1,11 @@ -{ lib, runCommand, ... }: +{ + self, + lib, + runCommand, + stdenv, + pkgs, + ... +}: let createAssertion = { cond, message }: @@ -14,12 +21,14 @@ in cond = ''[ -d "${path}" ]''; message = "No such directory ${path}"; }; + isFile = path: createAssertion { cond = ''[ -f "${path}" ]''; message = "No such file ${path}"; }; + notIsFile = path: createAssertion { @@ -35,11 +44,17 @@ in }; runTests = - name: scripts: - runCommand name { } '' - ${lib.concatStringsSep "\n\n" scripts} - touch $out - ''; + wrapperModule: scripts: + let + wrapper = wrapperModule.apply { inherit pkgs; }; + in + if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then + lib.trace "Running test!" runCommand "${wrapper.binName}-test" { } '' + ${lib.concatStringsSep "\n\n" scripts} + touch $out + '' + else + lib.trace "Skipping test..." null; runTest = name: assertions: '' run() { diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index b6748509..ce15d7ce 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -14,7 +14,6 @@ let runTest runTests ; - getDotdir = wrapper: let @@ -23,7 +22,7 @@ let in dotdir; in -runTests "direnv-test" [ +runTests self.wrappers.direnv [ (runTest "wrapper should output correct version" ( let wrapper = self.wrappers.direnv.wrap { From 92bd5b8629209bd766883359b218d4bed483ac62 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 17 Apr 2026 19:58:09 +0200 Subject: [PATCH 20/34] specify config per test and receive wrapper --- ci/test-lib.nix | 29 ++++++- wrapperModules/d/direnv/check.nix | 131 ++---------------------------- 2 files changed, 34 insertions(+), 126 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 35082a28..a3ba2cd9 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -44,13 +44,13 @@ in }; runTests = - wrapperModule: scripts: + wrapperModule: tests: let wrapper = wrapperModule.apply { inherit pkgs; }; in if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then lib.trace "Running test!" runCommand "${wrapper.binName}-test" { } '' - ${lib.concatStringsSep "\n\n" scripts} + ${lib.concatStringsSep "\n\n" tests} touch $out '' else @@ -63,4 +63,29 @@ in run || (echo 'test "${name}" failed' >&2 && exit 1) ''; + + runTests2 = + wrapperModule: tests: + let + wrapper = wrapperModule.apply { inherit pkgs; }; + testsWithWrapper = lib.map (test: test wrapper) tests; + in + if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then + lib.trace "Running test!" runCommand "${wrapper.binName}-test" { } '' + ${lib.concatStringsSep "\n\n" testsWithWrapper} + touch $out + '' + else + lib.trace "Skipping test..." null; + runTest2 = name: config: assertions: + wrapper: + let + wrapperWithConfig = wrapper.wrap config; + in '' + run() { + ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList (assertions wrapperWithConfig))} + } + + run || (echo 'test "${name}" failed' >&2 && exit 1) + ''; } diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index ce15d7ce..c53a421c 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -13,6 +13,8 @@ let notIsFile runTest runTests + runTest2 + runTests2 ; getDotdir = wrapper: @@ -22,130 +24,11 @@ let in dotdir; in -runTests self.wrappers.direnv [ - (runTest "wrapper should output correct version" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - }; - in - '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - '' - )) - (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = true; - }; - in - [ +runTests2 self.wrappers.direnv [ + (runTest2 "if nix-direnv is enabled then lib/nix-direnv.sh should exists" + { nix-direnv.enable = true; } (wrapper: [ (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") - ] - )) - (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = false; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") - ] - )) - (runTest "if mise is enabled then lib/mise.sh should exists" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - mise.enable = true; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile "${getDotdir wrapper}/lib/mise.sh") - ] - )) - (runTest "if mise is disabled then lib/mise.sh should not exist" ( - let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - mise.enable = false; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (notIsFile "${getDotdir wrapper}/lib/mise.sh") - ] - )) - (runTest "if a lib-script is set then it should be generated" ( - let - libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; - libScriptContent = "echo foo"; - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - lib."foo.sh" = libScriptContent; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile libScriptFile) - (fileContains libScriptFile libScriptContent) - - ] - )) - (runTest "if silent mode is enabled then log settings should be set" ( - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - silent = true; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvTomlFile) - (fileContains direnvTomlFile "log_format") - (fileContains direnvTomlFile "log_filter") - - ] - )) - (runTest "if extraConfig is working" ( - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - extraConfig = { - fooSection.fooKey = "fooValue"; - }; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvTomlFile) - (fileContains direnvTomlFile "\\[fooSection\\]") - (fileContains direnvTomlFile "fooKey.*fooValue") - - ] - )) - (runTest "if direnvrc is working" ( - let - direnvrcFile = "${getDotdir wrapper}/direnvrc"; - direnvrcContent = "echo foo"; - - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - direnvrc = direnvrcContent; - }; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvrcFile) - (fileContains direnvrcFile direnvrcContent) - - ] - )) + ]) + ) ] From 6a6e4baec79bb47c1e1083b04ae030760515ae32 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 17 Apr 2026 20:03:20 +0200 Subject: [PATCH 21/34] remove runTest2 --- ci/test-lib.nix | 23 +---------------------- wrapperModules/d/direnv/check.nix | 6 ++---- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index a3ba2cd9..cb598802 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -44,27 +44,6 @@ in }; runTests = - wrapperModule: tests: - let - wrapper = wrapperModule.apply { inherit pkgs; }; - in - if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then - lib.trace "Running test!" runCommand "${wrapper.binName}-test" { } '' - ${lib.concatStringsSep "\n\n" tests} - touch $out - '' - else - lib.trace "Skipping test..." null; - - runTest = name: assertions: '' - run() { - ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions)} - } - - run || (echo 'test "${name}" failed' >&2 && exit 1) - ''; - - runTests2 = wrapperModule: tests: let wrapper = wrapperModule.apply { inherit pkgs; }; @@ -77,7 +56,7 @@ in '' else lib.trace "Skipping test..." null; - runTest2 = name: config: assertions: + runTest = name: config: assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index c53a421c..6905ae5d 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -13,8 +13,6 @@ let notIsFile runTest runTests - runTest2 - runTests2 ; getDotdir = wrapper: @@ -24,8 +22,8 @@ let in dotdir; in -runTests2 self.wrappers.direnv [ - (runTest2 "if nix-direnv is enabled then lib/nix-direnv.sh should exists" +runTests self.wrappers.direnv [ + (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" { nix-direnv.enable = true; } (wrapper: [ (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") From 2b2128f9aed6b54422ad665ed0f8ca6dc0c44bd9 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 17 Apr 2026 20:18:15 +0200 Subject: [PATCH 22/34] convert direnv tests --- wrapperModules/d/direnv/check.nix | 91 ++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 6905ae5d..62b71cbe 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,10 +23,99 @@ let dotdir; in runTests self.wrappers.direnv [ + (runTest "wrapper should output correct version" + { } + (wrapper: + '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + '') + ) (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" - { nix-direnv.enable = true; } (wrapper: [ + { nix-direnv.enable = true; } + (wrapper: [ (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) + (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" + { nix-direnv.enable = false; } (wrapper: [ + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") + ]) + ) + (runTest "if mise is enabled then lib/mise.sh should exists" + { mise.enable = true; } (wrapper: [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/mise.sh") + ]) + ) + (runTest "if mise is disabled then lib/mise.sh should not exist" + { mise.enable = false; } (wrapper: [ + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/mise.sh") + ]) + ) + (let + libScriptContent = "echo foo"; + in + (runTest "if a lib-script is set then it should be generated" + { lib."foo.sh" = libScriptContent; } (wrapper: + let + libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile libScriptFile) + (fileContains libScriptFile libScriptContent) + + ]) + )) + (runTest "if silent mode is enabled then log settings should be set" + { silent = true; } (wrapper: + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "log_format") + (fileContains direnvTomlFile "log_filter") + ] + ) + ) + (runTest "if extraConfig is working" + { + extraConfig = { + fooSection.fooKey = "fooValue"; + }; + } (wrapper: + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "\\[fooSection\\]") + (fileContains direnvTomlFile "fooKey.*fooValue") + + ] + ) + ) + # (runTest "if direnvrc is working" ( + # let + # direnvrcFile = "${getDotdir wrapper}/direnvrc"; + # direnvrcContent = "echo foo"; + # + # wrapper = self.wrappers.direnv.wrap { + # inherit pkgs; + # direnvrc = direnvrcContent; + # }; + # in + # [ + # (isDirectory (getDotdir wrapper)) + # (isFile direnvrcFile) + # (fileContains direnvrcFile direnvrcContent) + # + # ] + # )) ] From 88ea19da5faa513c36a14b0c1e60f336064ca8e1 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Fri, 17 Apr 2026 20:34:29 +0200 Subject: [PATCH 23/34] apply nix fmt --- ci/test-lib.nix | 7 +- wrapperModules/d/direnv/check.nix | 116 +++++++++++++++--------------- 2 files changed, 60 insertions(+), 63 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index cb598802..a401b20c 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -56,11 +56,12 @@ in '' else lib.trace "Skipping test..." null; - runTest = name: config: assertions: - wrapper: + runTest = + name: config: assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; - in '' + in + '' run() { ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList (assertions wrapperWithConfig))} } diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 62b71cbe..5b8156a8 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,99 +23,95 @@ let dotdir; in runTests self.wrappers.direnv [ - (runTest "wrapper should output correct version" - { } - (wrapper: - '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - '') - ) - (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" - { nix-direnv.enable = true; } + (runTest "wrapper should output correct version" { } (wrapper: '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + '')) + (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" + { nix-direnv.enable = true; } (wrapper: [ (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" - { nix-direnv.enable = false; } (wrapper: [ + { nix-direnv.enable = false; } + (wrapper: [ (isDirectory (getDotdir wrapper)) (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) - (runTest "if mise is enabled then lib/mise.sh should exists" - { mise.enable = true; } (wrapper: [ - (isDirectory (getDotdir wrapper)) - (isFile "${getDotdir wrapper}/lib/mise.sh") - ]) - ) - (runTest "if mise is disabled then lib/mise.sh should not exist" - { mise.enable = false; } (wrapper: [ + (runTest "if mise is enabled then lib/mise.sh should exists" { mise.enable = true; } (wrapper: [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/mise.sh") + ])) + (runTest "if mise is disabled then lib/mise.sh should not exist" { mise.enable = false; } + (wrapper: [ (isDirectory (getDotdir wrapper)) (notIsFile "${getDotdir wrapper}/lib/mise.sh") ]) ) - (let - libScriptContent = "echo foo"; - in - (runTest "if a lib-script is set then it should be generated" - { lib."foo.sh" = libScriptContent; } (wrapper: + ( let - libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + libScriptContent = "echo foo"; in - [ - (isDirectory (getDotdir wrapper)) - (isFile libScriptFile) - (fileContains libScriptFile libScriptContent) - - ]) - )) - (runTest "if silent mode is enabled then log settings should be set" - { silent = true; } (wrapper: + (runTest "if a lib-script is set then it should be generated" { lib."foo.sh" = libScriptContent; } ( + wrapper: let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; in [ (isDirectory (getDotdir wrapper)) - (isFile direnvTomlFile) - (fileContains direnvTomlFile "log_format") - (fileContains direnvTomlFile "log_filter") + (isFile libScriptFile) + (fileContains libScriptFile libScriptContent) + ] - ) + )) ) + (runTest "if silent mode is enabled then log settings should be set" { silent = true; } ( + wrapper: + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "log_format") + (fileContains direnvTomlFile "log_filter") + ] + )) (runTest "if extraConfig is working" { extraConfig = { fooSection.fooKey = "fooValue"; }; - } (wrapper: - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - in + } + ( + wrapper: + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + in [ (isDirectory (getDotdir wrapper)) (isFile direnvTomlFile) (fileContains direnvTomlFile "\\[fooSection\\]") (fileContains direnvTomlFile "fooKey.*fooValue") - ] ) ) - # (runTest "if direnvrc is working" ( - # let - # direnvrcFile = "${getDotdir wrapper}/direnvrc"; - # direnvrcContent = "echo foo"; - # - # wrapper = self.wrappers.direnv.wrap { - # inherit pkgs; - # direnvrc = direnvrcContent; - # }; - # in - # [ - # (isDirectory (getDotdir wrapper)) - # (isFile direnvrcFile) - # (fileContains direnvrcFile direnvrcContent) - # - # ] - # )) + ( + let + direnvrcContent = "echo foo"; + in + (runTest "if direnvrc is working" { direnvrc = direnvrcContent; } ( + wrapper: + let + direnvrcFile = "${getDotdir wrapper}/direnvrc"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvrcFile) + (fileContains direnvrcFile direnvrcContent) + ] + )) + ) ] From bb46111b7683397ef3ffca1fe44d72f7b7de75fa Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 11:02:33 +0200 Subject: [PATCH 24/34] make runTests accept an attrs --- ci/test-lib.nix | 8 +++++--- wrapperModules/d/direnv/check.nix | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index a401b20c..0a9f5490 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -44,18 +44,20 @@ in }; runTests = - wrapperModule: tests: + settings: tests: let - wrapper = wrapperModule.apply { inherit pkgs; }; + wrapper = settings.wrapperModule.apply { inherit pkgs; }; + name = settings.name or "${wrapper.binName}-test"; testsWithWrapper = lib.map (test: test wrapper) tests; in if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then - lib.trace "Running test!" runCommand "${wrapper.binName}-test" { } '' + lib.trace "Running test!" runCommand name { } '' ${lib.concatStringsSep "\n\n" testsWithWrapper} touch $out '' else lib.trace "Skipping test..." null; + runTest = name: config: assertions: wrapper: let diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 5b8156a8..a921f2a0 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -22,7 +22,7 @@ let in dotdir; in -runTests self.wrappers.direnv [ +runTests { wrapperModule = self.wrappers.direnv; } [ (runTest "wrapper should output correct version" { } (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) From 0a99eba9941ee9137eb214edd0b37c3f3a2e7475 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 11:14:06 +0200 Subject: [PATCH 25/34] provide attrs to runTest --- ci/test-lib.nix | 6 +- wrapperModules/d/direnv/check.nix | 171 +++++++++++++++--------------- 2 files changed, 92 insertions(+), 85 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 0a9f5490..f7d0697a 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -59,7 +59,11 @@ in lib.trace "Skipping test..." null; runTest = - name: config: assertions: wrapper: + { + name, + config ? { }, + }: + assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; in diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index a921f2a0..54888b2c 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,95 +23,98 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ - (runTest "wrapper should output correct version" { } (wrapper: '' + (runTest { name = "wrapper should output correct version"; } (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) - (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" - { nix-direnv.enable = true; } + (runTest + { + name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; + config.nix-direnv.enable = true; + } (wrapper: [ (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) - (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" - { nix-direnv.enable = false; } - (wrapper: [ - (isDirectory (getDotdir wrapper)) - (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") - ]) - ) - (runTest "if mise is enabled then lib/mise.sh should exists" { mise.enable = true; } (wrapper: [ - (isDirectory (getDotdir wrapper)) - (isFile "${getDotdir wrapper}/lib/mise.sh") - ])) - (runTest "if mise is disabled then lib/mise.sh should not exist" { mise.enable = false; } - (wrapper: [ - (isDirectory (getDotdir wrapper)) - (notIsFile "${getDotdir wrapper}/lib/mise.sh") - ]) - ) - ( - let - libScriptContent = "echo foo"; - in - (runTest "if a lib-script is set then it should be generated" { lib."foo.sh" = libScriptContent; } ( - wrapper: - let - libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile libScriptFile) - (fileContains libScriptFile libScriptContent) - - ] - )) - ) - (runTest "if silent mode is enabled then log settings should be set" { silent = true; } ( - wrapper: - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvTomlFile) - (fileContains direnvTomlFile "log_format") - (fileContains direnvTomlFile "log_filter") - ] - )) - (runTest "if extraConfig is working" - { - extraConfig = { - fooSection.fooKey = "fooValue"; - }; - } - ( - wrapper: - let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvTomlFile) - (fileContains direnvTomlFile "\\[fooSection\\]") - (fileContains direnvTomlFile "fooKey.*fooValue") - ] - ) - ) - ( - let - direnvrcContent = "echo foo"; - in - (runTest "if direnvrc is working" { direnvrc = direnvrcContent; } ( - wrapper: - let - direnvrcFile = "${getDotdir wrapper}/direnvrc"; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile direnvrcFile) - (fileContains direnvrcFile direnvrcContent) - ] - )) - ) + # (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" + # { nix-direnv.enable = false; } + # (wrapper: [ + # (isDirectory (getDotdir wrapper)) + # (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") + # ]) + # ) + # (runTest "if mise is enabled then lib/mise.sh should exists" { mise.enable = true; } (wrapper: [ + # (isDirectory (getDotdir wrapper)) + # (isFile "${getDotdir wrapper}/lib/mise.sh") + # ])) + # (runTest "if mise is disabled then lib/mise.sh should not exist" { mise.enable = false; } + # (wrapper: [ + # (isDirectory (getDotdir wrapper)) + # (notIsFile "${getDotdir wrapper}/lib/mise.sh") + # ]) + # ) + # ( + # let + # libScriptContent = "echo foo"; + # in + # (runTest "if a lib-script is set then it should be generated" { lib."foo.sh" = libScriptContent; } ( + # wrapper: + # let + # libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + # in + # [ + # (isDirectory (getDotdir wrapper)) + # (isFile libScriptFile) + # (fileContains libScriptFile libScriptContent) + # + # ] + # )) + # ) + # (runTest "if silent mode is enabled then log settings should be set" { silent = true; } ( + # wrapper: + # let + # direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + # in + # [ + # (isDirectory (getDotdir wrapper)) + # (isFile direnvTomlFile) + # (fileContains direnvTomlFile "log_format") + # (fileContains direnvTomlFile "log_filter") + # ] + # )) + # (runTest "if extraConfig is working" + # { + # extraConfig = { + # fooSection.fooKey = "fooValue"; + # }; + # } + # ( + # wrapper: + # let + # direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + # in + # [ + # (isDirectory (getDotdir wrapper)) + # (isFile direnvTomlFile) + # (fileContains direnvTomlFile "\\[fooSection\\]") + # (fileContains direnvTomlFile "fooKey.*fooValue") + # ] + # ) + # ) + # ( + # let + # direnvrcContent = "echo foo"; + # in + # (runTest "if direnvrc is working" { direnvrc = direnvrcContent; } ( + # wrapper: + # let + # direnvrcFile = "${getDotdir wrapper}/direnvrc"; + # in + # [ + # (isDirectory (getDotdir wrapper)) + # (isFile direnvrcFile) + # (fileContains direnvrcFile direnvrcContent) + # ] + # )) + # ) ] From 7310e8dd643e668d0871612576648167f19d39e8 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 12:28:10 +0200 Subject: [PATCH 26/34] make runTest accept both string and attrs --- ci/test-lib.nix | 14 +++++++++----- wrapperModules/d/direnv/check.nix | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index f7d0697a..f0f79116 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -59,12 +59,16 @@ in lib.trace "Skipping test..." null; runTest = - { - name, - config ? { }, - }: - assertions: wrapper: + settings: assertions: wrapper: let + name = + if (lib.isAttrs settings) && (settings ? name) then + settings.name + else if lib.isString settings then + settings + else + throw "No name provided to `runTest`."; + config = if (lib.isAttrs settings) && (settings ? config) then settings.config else { }; wrapperWithConfig = wrapper.wrap config; in '' diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 54888b2c..fed63416 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,7 +23,7 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ - (runTest { name = "wrapper should output correct version"; } (wrapper: '' + (runTest "wrapper should output correct version" (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) (runTest From cd23d75ff7036b7393d18850f1febbfdbcb7c7f2 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:05:55 +0200 Subject: [PATCH 27/34] introduce runTestWithConfig --- ci/test-lib.nix | 57 ++++++++++++++++++++++--------- wrapperModules/d/direnv/check.nix | 2 +- 2 files changed, 41 insertions(+), 18 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index f0f79116..6741d203 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -12,9 +12,24 @@ let '' (${cond}) || (echo "${message}" >&2; return 1) ''; + runTestWithConfig = + { name, config ? { } }: assertions: wrapper: + let + wrapperWithConfig = wrapper.wrap config; + in + '' + run() { + ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList (assertions wrapperWithConfig))} + } + + run || (echo 'test "${name}" failed' >&2 && exit 1) + ''; in { - inherit createAssertion; + inherit + createAssertion + runTestWithConfig + ; isDirectory = path: createAssertion { @@ -57,25 +72,33 @@ in '' else lib.trace "Skipping test..." null; - runTest = - settings: assertions: wrapper: + nameOrSettings: assertions: wrapper: let - name = - if (lib.isAttrs settings) && (settings ? name) then - settings.name - else if lib.isString settings then - settings + # name = + # if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then + # nameOrSettings.name + # else if lib.isString settings then + # nameOrSettings + # else + # throw "No name provided to `runTest`."; + # wrapperWithConfig = wrapper.wrap config; + settings = + if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then + nameOrSettings + else if lib.isString nameOrSettings then + { + name = nameOrSettings; + } else - throw "No name provided to `runTest`."; - config = if (lib.isAttrs settings) && (settings ? config) then settings.config else { }; - wrapperWithConfig = wrapper.wrap config; + throw '' + Invalid argument for `runTest`. + The first argument must be a string (the test name) or an attrs + { name: str, config: Optional[attrs]} but we got: + + ${lib.toJSON nameOrSettings} + ''; in - '' - run() { - ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList (assertions wrapperWithConfig))} - } + runTestWithConfig settings assertions wrapper; - run || (echo 'test "${name}" failed' >&2 && exit 1) - ''; } diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index fed63416..43d955bb 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,7 +23,7 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ - (runTest "wrapper should output correct version" (wrapper: '' + (runTest { blubb = "wrapper should output correct version"; } (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) (runTest From 0d23408d07fe24363ee120567e3b4981c6ba8248 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:08:07 +0200 Subject: [PATCH 28/34] improve error message for runTest --- ci/test-lib.nix | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 6741d203..5ff55ff4 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -75,14 +75,6 @@ in runTest = nameOrSettings: assertions: wrapper: let - # name = - # if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then - # nameOrSettings.name - # else if lib.isString settings then - # nameOrSettings - # else - # throw "No name provided to `runTest`."; - # wrapperWithConfig = wrapper.wrap config; settings = if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then nameOrSettings @@ -92,9 +84,9 @@ in } else throw '' - Invalid argument for `runTest`. - The first argument must be a string (the test name) or an attrs - { name: str, config: Optional[attrs]} but we got: + Invalid argument for `runTest`. + The first argument must be either a string (the test name) or an attrs + matching { name, config ? { } }, but got: ${lib.toJSON nameOrSettings} ''; From 3edad9875c3ab5a1f6e08007ed75e3a8f1899dec Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:10:15 +0200 Subject: [PATCH 29/34] refactor --- ci/test-lib.nix | 72 ++++++++++++++++--------------- wrapperModules/d/direnv/check.nix | 2 +- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 5ff55ff4..9dfa0c67 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -12,6 +12,42 @@ let '' (${cond}) || (echo "${message}" >&2; return 1) ''; + runTests = + settings: tests: + let + wrapper = settings.wrapperModule.apply { inherit pkgs; }; + name = settings.name or "${wrapper.binName}-test"; + testsWithWrapper = lib.map (test: test wrapper) tests; + in + if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then + lib.trace "Running test!" runCommand name { } '' + ${lib.concatStringsSep "\n\n" testsWithWrapper} + touch $out + '' + else + lib.trace "Skipping test..." null; + + runTest = + nameOrSettings: assertions: wrapper: + let + settings = + if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then + nameOrSettings + else if lib.isString nameOrSettings then + { + name = nameOrSettings; + } + else + throw '' + Invalid argument for `runTest`. + The first argument must be either a string (the test name) or an attrs + matching { name, config ? { } }, but got: + + ${lib.toJSON nameOrSettings} + ''; + in + runTestWithConfig settings assertions wrapper; + runTestWithConfig = { name, config ? { } }: assertions: wrapper: let @@ -28,6 +64,8 @@ in { inherit createAssertion + runTests + runTest runTestWithConfig ; isDirectory = @@ -58,39 +96,5 @@ in message = "Pattern '${pattern}' not found in ${file}"; }; - runTests = - settings: tests: - let - wrapper = settings.wrapperModule.apply { inherit pkgs; }; - name = settings.name or "${wrapper.binName}-test"; - testsWithWrapper = lib.map (test: test wrapper) tests; - in - if builtins.elem stdenv.hostPlatform.system wrapper.meta.platforms then - lib.trace "Running test!" runCommand name { } '' - ${lib.concatStringsSep "\n\n" testsWithWrapper} - touch $out - '' - else - lib.trace "Skipping test..." null; - runTest = - nameOrSettings: assertions: wrapper: - let - settings = - if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then - nameOrSettings - else if lib.isString nameOrSettings then - { - name = nameOrSettings; - } - else - throw '' - Invalid argument for `runTest`. - The first argument must be either a string (the test name) or an attrs - matching { name, config ? { } }, but got: - - ${lib.toJSON nameOrSettings} - ''; - in - runTestWithConfig settings assertions wrapper; } diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 43d955bb..54888b2c 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,7 +23,7 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ - (runTest { blubb = "wrapper should output correct version"; } (wrapper: '' + (runTest { name = "wrapper should output correct version"; } (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) (runTest From ae32537bd2de9805781463fafeaa3c28d746c3c0 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:32:34 +0200 Subject: [PATCH 30/34] don't require injected wrapper in assertions --- ci/test-lib.nix | 22 +++++++++++++++------- wrapperModules/d/direnv/check.nix | 19 ++++++++++++++++--- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 9dfa0c67..9199dfe7 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -30,11 +30,11 @@ let runTest = nameOrSettings: assertions: wrapper: let - settings = + settings = if (lib.isAttrs nameOrSettings) && (nameOrSettings ? name) then nameOrSettings else if lib.isString nameOrSettings then - { + { name = nameOrSettings; } else @@ -46,23 +46,32 @@ let ${lib.toJSON nameOrSettings} ''; in - runTestWithConfig settings assertions wrapper; + runTestWithConfig settings assertions wrapper; runTestWithConfig = - { name, config ? { } }: assertions: wrapper: + { + name, + config ? { }, + }: + assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; + assertions' = + if lib.isFunction assertions then + assertions wrapperWithConfig + else + assertions; in '' run() { - ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList (assertions wrapperWithConfig))} + ${lib.concatMapStringsSep " && " (a: "(${a})") (lib.toList assertions')} } run || (echo 'test "${name}" failed' >&2 && exit 1) ''; in { - inherit + inherit createAssertion runTests runTest @@ -96,5 +105,4 @@ in message = "Pattern '${pattern}' not found in ${file}"; }; - } diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 54888b2c..81f92ec3 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,9 +23,22 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ - (runTest { name = "wrapper should output correct version"; } (wrapper: '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - '')) + (runTest + { + name = "wrapper should output correct version"; + } + ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = false; + }; + in + '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + '' + ) + ) (runTest { name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; From b56b132ee5d4e09068f45b1ca08f3fdf21610e2e Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:47:59 +0200 Subject: [PATCH 31/34] convert tests --- ci/test-lib.nix | 6 +- wrapperModules/d/direnv/check.nix | 166 ++++++++++++++++-------------- 2 files changed, 88 insertions(+), 84 deletions(-) diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 9199dfe7..498b3fd5 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -56,11 +56,7 @@ let assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; - assertions' = - if lib.isFunction assertions then - assertions wrapperWithConfig - else - assertions; + assertions' = if lib.isFunction assertions then assertions wrapperWithConfig else assertions; in '' run() { diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index 81f92ec3..b632f2af 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,97 +23,105 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ + (runTest "wrapper should output correct version" (wrapper: '' + "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" + '')) (runTest { - name = "wrapper should output correct version"; + name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; + config.nix-direnv.enable = true; + } + (wrapper: [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") + ]) + ) + (runTest + { + name = "if nix-direnv is disabled then lib/nix-direnv.sh should not exist"; + config.nix-direnv.enable = false; + } + (wrapper: [ + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") + ]) + ) + (runTest + { + name = "if mise is enabled then lib/mise.sh should exists"; + config.mise.enable = true; + } + (wrapper: [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/mise.sh") + ]) + ) + (runTest + { + name = "if mise is disabled then lib/mise.sh should not exist"; + config.mise.enable = false; + } + (wrapper: [ + (isDirectory (getDotdir wrapper)) + (notIsFile "${getDotdir wrapper}/lib/mise.sh") + ]) + ) + ( + (runTest + { + name = "if a lib-script is set then it should be generated"; + config.lib."foo.sh" = "echo foo"; + } + ( + wrapper: + let + libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile libScriptFile) + (fileContains libScriptFile "echo foo") + + ] + ) + ) + ) + (runTest + { + name = "if silent mode is enabled then log settings should be set"; + config.silent = true; } ( + wrapper: let - wrapper = self.wrappers.direnv.wrap { - inherit pkgs; - nix-direnv.enable = false; - }; + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; in - '' - "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" - '' + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "log_format") + (fileContains direnvTomlFile "log_filter") + ] ) ) (runTest { - name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; - config.nix-direnv.enable = true; + name = "if extraConfig is working"; + config.extraConfig.fooSection.fooKey = "fooValue;"; } - (wrapper: [ - (isDirectory (getDotdir wrapper)) - (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") - ]) + ( + wrapper: + let + direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvTomlFile) + (fileContains direnvTomlFile "\\[fooSection\\]") + (fileContains direnvTomlFile "fooKey.*fooValue") + ] + ) ) - # (runTest "if nix-direnv is disabled then lib/nix-direnv.sh should not exist" - # { nix-direnv.enable = false; } - # (wrapper: [ - # (isDirectory (getDotdir wrapper)) - # (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") - # ]) - # ) - # (runTest "if mise is enabled then lib/mise.sh should exists" { mise.enable = true; } (wrapper: [ - # (isDirectory (getDotdir wrapper)) - # (isFile "${getDotdir wrapper}/lib/mise.sh") - # ])) - # (runTest "if mise is disabled then lib/mise.sh should not exist" { mise.enable = false; } - # (wrapper: [ - # (isDirectory (getDotdir wrapper)) - # (notIsFile "${getDotdir wrapper}/lib/mise.sh") - # ]) - # ) - # ( - # let - # libScriptContent = "echo foo"; - # in - # (runTest "if a lib-script is set then it should be generated" { lib."foo.sh" = libScriptContent; } ( - # wrapper: - # let - # libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; - # in - # [ - # (isDirectory (getDotdir wrapper)) - # (isFile libScriptFile) - # (fileContains libScriptFile libScriptContent) - # - # ] - # )) - # ) - # (runTest "if silent mode is enabled then log settings should be set" { silent = true; } ( - # wrapper: - # let - # direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - # in - # [ - # (isDirectory (getDotdir wrapper)) - # (isFile direnvTomlFile) - # (fileContains direnvTomlFile "log_format") - # (fileContains direnvTomlFile "log_filter") - # ] - # )) - # (runTest "if extraConfig is working" - # { - # extraConfig = { - # fooSection.fooKey = "fooValue"; - # }; - # } - # ( - # wrapper: - # let - # direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; - # in - # [ - # (isDirectory (getDotdir wrapper)) - # (isFile direnvTomlFile) - # (fileContains direnvTomlFile "\\[fooSection\\]") - # (fileContains direnvTomlFile "fooKey.*fooValue") - # ] - # ) - # ) # ( # let # direnvrcContent = "echo foo"; From cc60422c17505f01034e30a7ab59c28f88aa89b5 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 13:58:57 +0200 Subject: [PATCH 32/34] use passthru in test --- wrapperModules/d/direnv/check.nix | 75 +++++++++++++++++-------------- 1 file changed, 42 insertions(+), 33 deletions(-) diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index b632f2af..ed0e0c13 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -23,9 +23,11 @@ let dotdir; in runTests { wrapperModule = self.wrappers.direnv; } [ + (runTest "wrapper should output correct version" (wrapper: '' "${wrapper}/bin/direnv" --version | grep -q "${wrapper.version}" '')) + (runTest { name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; @@ -36,6 +38,7 @@ runTests { wrapperModule = self.wrappers.direnv; } [ (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) + (runTest { name = "if nix-direnv is disabled then lib/nix-direnv.sh should not exist"; @@ -46,6 +49,7 @@ runTests { wrapperModule = self.wrappers.direnv; } [ (notIsFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) ) + (runTest { name = "if mise is enabled then lib/mise.sh should exists"; @@ -56,6 +60,7 @@ runTests { wrapperModule = self.wrappers.direnv; } [ (isFile "${getDotdir wrapper}/lib/mise.sh") ]) ) + (runTest { name = "if mise is disabled then lib/mise.sh should not exist"; @@ -66,26 +71,26 @@ runTests { wrapperModule = self.wrappers.direnv; } [ (notIsFile "${getDotdir wrapper}/lib/mise.sh") ]) ) - ( - (runTest - { - name = "if a lib-script is set then it should be generated"; - config.lib."foo.sh" = "echo foo"; - } - ( - wrapper: - let - libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; - in - [ - (isDirectory (getDotdir wrapper)) - (isFile libScriptFile) - (fileContains libScriptFile "echo foo") - ] - ) + (runTest + { + name = "if a lib-script is set then it should be generated"; + config.lib."foo.sh" = "echo foo"; + } + ( + wrapper: + let + libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; + cfg = wrapper.passthru.configuration; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile libScriptFile) + (fileContains libScriptFile cfg.lib."foo.sh") + ] ) ) + (runTest { name = "if silent mode is enabled then log settings should be set"; @@ -104,6 +109,7 @@ runTests { wrapperModule = self.wrappers.direnv; } [ ] ) ) + (runTest { name = "if extraConfig is working"; @@ -122,20 +128,23 @@ runTests { wrapperModule = self.wrappers.direnv; } [ ] ) ) - # ( - # let - # direnvrcContent = "echo foo"; - # in - # (runTest "if direnvrc is working" { direnvrc = direnvrcContent; } ( - # wrapper: - # let - # direnvrcFile = "${getDotdir wrapper}/direnvrc"; - # in - # [ - # (isDirectory (getDotdir wrapper)) - # (isFile direnvrcFile) - # (fileContains direnvrcFile direnvrcContent) - # ] - # )) - # ) + + (runTest + { + name = "if direnvrc is working"; + config.direnvrc = "echo blubb"; + } + ( + wrapper: + let + direnvrcFile = "${getDotdir wrapper}/direnvrc"; + cfg = wrapper.passthru.configuration; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile direnvrcFile) + (fileContains direnvrcFile cfg.direnvrc) + ] + ) + ) ] From ab03d148596cc5ef20b198126386afa74e586705 Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 15:51:30 +0200 Subject: [PATCH 33/34] Update CONTRIBUTING.md --- CONTRIBUTING.md | 122 +++++++++++++++++++++--------- wrapperModules/d/direnv/check.nix | 1 - 2 files changed, 88 insertions(+), 35 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4615ba14..c90b810a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,59 +143,113 @@ or `nix run ./ci#docs` -# Writing tests +# Writing Tests You may also include a `check.nix` file in your module's directory. -It will be called via `pkgs.callPackage`, provided with the flake `self` value. -(i.e. `pkgs.callPackage your_check.nix { inherit self; }`) +It will be called via `pkgs.callPackage`, provided with the flake `self` value, as well as a test-library `tlib` value. +(i.e. `pkgs.callPackage your_check.nix { inherit self tlib; }`) -It should build a derivation which tests the wrapper derivation as best you can. +## Using the testing Library `tlib` -If a command fails, it fails the test. If it builds the derivation successfully, it passes the test. +We provide a testing library `tlib` that provides an easy to use interface to write tests specifically for wrapper modules. -If the program gives options for running the program to check the generated configuration is correct, you should do that. - -Sometimes it is not easily possible to run the program within a derivation, in those cases, searching the wrapper derivation and other generated files and their contents is also acceptable. - -Example: +The general structure is as follows: ```nix { - pkgs, - runCommand, self, + tlib, + ... }: + let - gitWrapped = self.wrappers.git.wrap { - inherit pkgs; - settings = { - user = { - name = "Test User"; - email = "test@example.com"; - }; - }; - }; + inherit (tlib) + runTest + runTests + ; in -runCommand "git-test" { } '' - "${gitWrapped}/bin/git" config user.name | grep -q "Test User" - "${gitWrapped}/bin/git" config user.email | grep -q "test@example.com" - touch $out -'' +runTests { wrapperModule = self.wrappers.; } [ + (runTest "description of test1" [ assertion1, ..., assertionN]) + (runTest "description of test2" [ assertion1, ..., assertionN]) + ... + (runTest "description of testN" [ assertion1, ..., assertionN]) +] + +``` + +Tests will only be run on the systems defined in `wrapperModule.meta.platforms`. + +Individual tests are then specified using `runTest`. +Each test accepts a name as the first argument and a list of assertions +(if a single assertion is provided directly, it will be converted to a list). + +An assertion is a bash command in the form of a string. +If the command is run successfully (exit code 0), the assertion passes. +Use `stderr` to log descriptive messages about the failed assertion. + +We provide a helper method `lib.createAssertion` for this: + +```nix +isDirectory = + path: + createAssertion { + cond = ''[ -d "${path}" ]''; # <-- the condition to be asserted + message = "No such directory ${path}"; # <-- the message to print to stderr if + }; # the assertion is violated + +``` + +Pre-defined assertions like `isDirectory` or `isFile` are already available in tlib. +Feel free to contribute more if you find new ones that other maintainers might benefit from. + +Instead of providing a list of assertions directly, you can also provide a function providing a wrapper: + +```nix +runTest "my test description" (wrapper: [ + (isDirectory wrapper.passthru.configuration.) +]) ``` -If your module declares a list of valid platforms via its `meta.platforms` option, you should disable your test on the relevant platforms like so: +The provided wrapper is instantiated from the `wrapperModule` that was passed to `runTests`. + +This wrapper instance does not set any options apart from `pkgs`. +In most cases, you want to test the wrapper by providing a specific configuration. + +You can do this by providing an `attrs` instead of a string to `runTest` and provide a config there: ```nix -if builtins.elem pkgs.stdenv.hostPlatform.system self.wrappers.waybar.meta.platforms then - pkgs.runCommand "waybar-test" { } '' - "${waybarWrapped}/bin/waybar" --version | grep -q "${waybarWrapped.version}" - touch $out - '' -else - null +(runTest + { + name = "if nix-direnv is enabled then lib/nix-direnv.sh should exists"; # <-- name of the test + config.nix-direnv.enable = true; # <-- provide test-specific config + } + (wrapper: [ # <-- this wrapper has the above config applied + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") + ]) +) +``` + +Of course, nothing keeps you from instantiating your wrappers from scratch. The above direnv example could +equivalently be written as: + +``` +(runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( + let + wrapper = self.wrappers.direnv.wrap { + inherit pkgs; + nix-direnv.enable = true; + }; + in + [ + (isDirectory (getDotdir wrapper)) + (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") + ] +)) ``` + If you are writing a helper module, or something very complex, you may wish to have multiple derivations. Simply return a set of them instead. # Commit Messages diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index ed0e0c13..ecd95c5c 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -1,5 +1,4 @@ { - pkgs, self, tlib, ... From 7bbfab9fcb5efb363c14754cc86d3b3b5e937bef Mon Sep 17 00:00:00 2001 From: Olivier Bitter Date: Sat, 18 Apr 2026 18:43:00 +0200 Subject: [PATCH 34/34] allow passing of config to `runTest` assertions --- CONTRIBUTING.md | 3 ++- ci/test-lib.nix | 13 +++++++++++- wrapperModules/d/direnv/check.nix | 34 ++++++++++++++++--------------- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c90b810a..df7a28c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -225,6 +225,7 @@ You can do this by providing an `attrs` instead of a string to `runTest` and pro config.nix-direnv.enable = true; # <-- provide test-specific config } (wrapper: [ # <-- this wrapper has the above config applied + # ({ wrapper, config }: [ # <-- or like this, if you also want to access the wrapper config (isDirectory (getDotdir wrapper)) (isFile "${getDotdir wrapper}/lib/nix-direnv.sh") ]) @@ -234,7 +235,7 @@ You can do this by providing an `attrs` instead of a string to `runTest` and pro Of course, nothing keeps you from instantiating your wrappers from scratch. The above direnv example could equivalently be written as: -``` +```nix (runTest "if nix-direnv is enabled then lib/nix-direnv.sh should exists" ( let wrapper = self.wrappers.direnv.wrap { diff --git a/ci/test-lib.nix b/ci/test-lib.nix index 498b3fd5..463342a2 100644 --- a/ci/test-lib.nix +++ b/ci/test-lib.nix @@ -56,7 +56,18 @@ let assertions: wrapper: let wrapperWithConfig = wrapper.wrap config; - assertions' = if lib.isFunction assertions then assertions wrapperWithConfig else assertions; + assertions' = + if lib.isFunction assertions then + # Shorthand notation (wrapper: assertions) + if lib.functionArgs assertions == { } then + assertions wrapperWithConfig + else + assertions { + wrapper = wrapperWithConfig; + config = wrapperWithConfig.passthru.configuration; + } + else + assertions; in '' run() { diff --git a/wrapperModules/d/direnv/check.nix b/wrapperModules/d/direnv/check.nix index ecd95c5c..7327031f 100644 --- a/wrapperModules/d/direnv/check.nix +++ b/wrapperModules/d/direnv/check.nix @@ -16,7 +16,7 @@ let getDotdir = wrapper: let - cfg = (wrapper.eval { }).config; + cfg = wrapper.passthru.configuration; dotdir = "${wrapper}/${cfg.configDirname}"; in dotdir; @@ -77,15 +77,15 @@ runTests { wrapperModule = self.wrappers.direnv; } [ config.lib."foo.sh" = "echo foo"; } ( - wrapper: + { wrapper, config }: let - libScriptFile = "${getDotdir wrapper}/lib/foo.sh"; - cfg = wrapper.passthru.configuration; + dotdir = getDotdir wrapper; + libScriptFile = dotdir + "/lib/foo.sh"; in [ - (isDirectory (getDotdir wrapper)) + (isDirectory dotdir) (isFile libScriptFile) - (fileContains libScriptFile cfg.lib."foo.sh") + (fileContains libScriptFile config.lib."foo.sh") ] ) ) @@ -98,10 +98,11 @@ runTests { wrapperModule = self.wrappers.direnv; } [ ( wrapper: let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + dotdir = getDotdir wrapper; + direnvTomlFile = dotdir + "/direnv.toml"; in [ - (isDirectory (getDotdir wrapper)) + (isDirectory dotdir) (isFile direnvTomlFile) (fileContains direnvTomlFile "log_format") (fileContains direnvTomlFile "log_filter") @@ -117,10 +118,11 @@ runTests { wrapperModule = self.wrappers.direnv; } [ ( wrapper: let - direnvTomlFile = "${getDotdir wrapper}/direnv.toml"; + dotdir = getDotdir wrapper; + direnvTomlFile = dotdir + "/direnv.toml"; in [ - (isDirectory (getDotdir wrapper)) + (isDirectory dotdir) (isFile direnvTomlFile) (fileContains direnvTomlFile "\\[fooSection\\]") (fileContains direnvTomlFile "fooKey.*fooValue") @@ -131,18 +133,18 @@ runTests { wrapperModule = self.wrappers.direnv; } [ (runTest { name = "if direnvrc is working"; - config.direnvrc = "echo blubb"; + config.direnvrc = "echo foo"; } ( - wrapper: + { wrapper, config }: let - direnvrcFile = "${getDotdir wrapper}/direnvrc"; - cfg = wrapper.passthru.configuration; + dotdir = getDotdir wrapper; + direnvrcFile = dotdir + "/direnvrc"; in [ - (isDirectory (getDotdir wrapper)) + (isDirectory dotdir) (isFile direnvrcFile) - (fileContains direnvrcFile cfg.direnvrc) + (fileContains direnvrcFile config.direnvrc) ] ) )