From 7e76b2e10ab29c4138cd287cab9ab8903d947c3b Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Wed, 19 Oct 2022 16:54:12 +0200 Subject: [PATCH 01/11] remove old gcroots when the environment is updated --- direnvrc | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/direnvrc b/direnvrc index 81fcd90..3de2677 100644 --- a/direnvrc +++ b/direnvrc @@ -112,15 +112,31 @@ _nix_import_env() { export XDG_DATA_DIRS=$XDG_DATA_DIRS${old_xdg_data_dirs:+":"}$old_xdg_data_dirs } +_nix_strip_escape_path() { + local stripped_path=${1/\//} + local escaped_path=${stripped_path//-/--} + local escaped_path=${escaped_path//\//-} + + echo "$escaped_path" +} + _nix_add_gcroot() { local storepath=$1 local symlink=$2 + local escaped_symlink + escaped_symlink=$(_nix_strip_escape_path "$symlink") - local stripped_pwd=${2/\//} - local escaped_pwd=${stripped_pwd//-/--} - local escaped_pwd=${escaped_pwd//\//-} ln -fsn "$storepath" "$symlink" - ln -fsn "$symlink" "/nix/var/nix/gcroots/per-user/$USER/$escaped_pwd" + ln -fsn "$symlink" "/nix/var/nix/gcroots/per-user/$USER/$escaped_symlink" +} + +_nix_clean_old_gcroots() { + local layout_dir=$1 + local escaped_layout_dir + escaped_layout_dir=$(_nix_strip_escape_path "$layout_dir") + + rm -fv "$layout_dir"/nix-{flake,profile}* + rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"--nix--{profile,flake}* } _nix_argsum_suffix() { @@ -180,6 +196,8 @@ use_flake() { || "$need_update" == "1" ]]; then + _nix_clean_old_gcroots "$layout_dir" + # We need to update our cache local tmp_profile="${layout_dir}/flake-profile.$$" local tmp_profile_rc @@ -204,6 +222,7 @@ use_flake() { --no-write-lock-file \ "$flake_dir" | grep -E -o '/nix/store/[^"]+') for path in $flake_input_paths; do + _nix_clean_old_gcroots "$flake_inputs" _nix_add_gcroot "$path" "${flake_inputs}/${path##*/}" done @@ -322,6 +341,8 @@ use_nix() { || "$need_update" -eq "1" ]]; then + _nix_clean_old_gcroots "$layout_dir" + local tmp_profile="${layout_dir}/flake-profile.$$" local tmp_profile_rc From 24d0af43fafe48b90038875ed6dbf683587ec65c Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 13:07:45 +0200 Subject: [PATCH 02/11] test that .direnv/ gets cleaned --- tests/test_gc.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/test_gc.py b/tests/test_gc.py index c951f62..eff25a5 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -38,10 +38,30 @@ def common_test(direnv_project: DirenvProject) -> None: assert "Executing shellHook." in out2.stderr +def common_test_clean(direnv_project: DirenvProject, num_expected_files: int) -> None: + testenv = str(direnv_project.dir) + + out3 = run( + ["direnv", "exec", testenv, "hello"], + stderr=subprocess.PIPE, + check=False, + cwd=direnv_project.dir, + ) + sys.stderr.write(out3.stderr) + + files = list((direnv_project.dir / ".direnv").iterdir()) + assert len(files) == num_expected_files + + def test_use_nix(direnv_project: DirenvProject) -> None: direnv_project.setup_envrc("use nix") common_test(direnv_project) + # --pure here is just a way to make sure the environment changes + direnv_project.setup_envrc("use nix --pure") + # expecting 2 files in .direnv/ : nix-profile-* and nix-profile-*.rc + common_test_clean(direnv_project, num_expected_files=2) + def test_use_flake(direnv_project: DirenvProject) -> None: direnv_project.setup_envrc("use flake") @@ -55,6 +75,12 @@ def test_use_flake(direnv_project: DirenvProject) -> None: for symlink in inputs: assert symlink.is_dir() + # --ignore-environment here is just a way to make sure the environment changes + direnv_project.setup_envrc("use flake --ignore-environment") + # expecting 5 files in .direnv/ : 2 x nix-flake-*, 2 x nix-flake-*.rc + # and flake-inputs + common_test_clean(direnv_project, num_expected_files=5) + if __name__ == "__main__": unittest.main() From ffd6b93c109aeeb932769f19beaa241e8aee43af Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 15:00:54 +0200 Subject: [PATCH 03/11] clean old gcroots: correct prefix of flake profiles (flake-profile-* instead of nix-flake-profile*) --- direnvrc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/direnvrc b/direnvrc index 3de2677..c2d91f7 100644 --- a/direnvrc +++ b/direnvrc @@ -135,8 +135,8 @@ _nix_clean_old_gcroots() { local escaped_layout_dir escaped_layout_dir=$(_nix_strip_escape_path "$layout_dir") - rm -fv "$layout_dir"/nix-{flake,profile}* - rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"--nix--{profile,flake}* + rm -fv "$layout_dir"/{nix,flake}-profile* + rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"--{nix,flake}--profile* } _nix_argsum_suffix() { From 6c18aabfdd5470a7d15ed76e26e9016f22b9aa61 Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 14:16:41 +0200 Subject: [PATCH 04/11] test_gc: check number of profiles and rc files in .direnv separately --- tests/test_gc.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index eff25a5..4523667 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -38,7 +38,7 @@ def common_test(direnv_project: DirenvProject) -> None: assert "Executing shellHook." in out2.stderr -def common_test_clean(direnv_project: DirenvProject, num_expected_files: int) -> None: +def common_test_clean(direnv_project: DirenvProject) -> None: testenv = str(direnv_project.dir) out3 = run( @@ -49,8 +49,15 @@ def common_test_clean(direnv_project: DirenvProject, num_expected_files: int) -> ) sys.stderr.write(out3.stderr) - files = list((direnv_project.dir / ".direnv").iterdir()) - assert len(files) == num_expected_files + files = [ + path for path in (direnv_project.dir / ".direnv").iterdir() if path.is_file() + ] + rcs = [f for f in files if f.match("*.rc")] + profiles = [f for f in files if not f.match("*.rc")] + if len(rcs) != 1 or len(profiles) != 1: + print(list(files)) + assert len(rcs) == 1 + assert len(profiles) == 1 def test_use_nix(direnv_project: DirenvProject) -> None: @@ -59,8 +66,7 @@ def test_use_nix(direnv_project: DirenvProject) -> None: # --pure here is just a way to make sure the environment changes direnv_project.setup_envrc("use nix --pure") - # expecting 2 files in .direnv/ : nix-profile-* and nix-profile-*.rc - common_test_clean(direnv_project, num_expected_files=2) + common_test_clean(direnv_project) def test_use_flake(direnv_project: DirenvProject) -> None: @@ -75,11 +81,11 @@ def test_use_flake(direnv_project: DirenvProject) -> None: for symlink in inputs: assert symlink.is_dir() - # --ignore-environment here is just a way to make sure the environment changes - direnv_project.setup_envrc("use flake --ignore-environment") - # expecting 5 files in .direnv/ : 2 x nix-flake-*, 2 x nix-flake-*.rc - # and flake-inputs - common_test_clean(direnv_project, num_expected_files=5) + files = list((direnv_project.dir / ".direnv").iterdir()) + print(files) + # -ignore-environment here is just a way to make sure the environment changes + direnv_project.setup_envrc("use flake") + common_test_clean(direnv_project) if __name__ == "__main__": From edb067d0f420da03dfa93159277651c15b1a867d Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 15:56:42 +0200 Subject: [PATCH 05/11] test_gc: cleaning: pass --impure to use flake to force update of environment --- tests/test_gc.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index 4523667..ef222da 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -56,6 +56,8 @@ def common_test_clean(direnv_project: DirenvProject) -> None: profiles = [f for f in files if not f.match("*.rc")] if len(rcs) != 1 or len(profiles) != 1: print(list(files)) + print(list(files)) + assert False assert len(rcs) == 1 assert len(profiles) == 1 @@ -83,8 +85,8 @@ def test_use_flake(direnv_project: DirenvProject) -> None: files = list((direnv_project.dir / ".direnv").iterdir()) print(files) - # -ignore-environment here is just a way to make sure the environment changes - direnv_project.setup_envrc("use flake") + # --impure here is just a way to make sure the environment changes + direnv_project.setup_envrc("use flake --impure") common_test_clean(direnv_project) From 391285f590e35297df8892dc80a57f0fdac2f00b Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 16:29:24 +0200 Subject: [PATCH 06/11] test_gc: remove debug prints --- tests/test_gc.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index ef222da..e93a18c 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -56,8 +56,6 @@ def common_test_clean(direnv_project: DirenvProject) -> None: profiles = [f for f in files if not f.match("*.rc")] if len(rcs) != 1 or len(profiles) != 1: print(list(files)) - print(list(files)) - assert False assert len(rcs) == 1 assert len(profiles) == 1 @@ -83,8 +81,6 @@ def test_use_flake(direnv_project: DirenvProject) -> None: for symlink in inputs: assert symlink.is_dir() - files = list((direnv_project.dir / ".direnv").iterdir()) - print(files) # --impure here is just a way to make sure the environment changes direnv_project.setup_envrc("use flake --impure") common_test_clean(direnv_project) From 2b5045d6f3a92fa4fe0ad574c709713634f88fd1 Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Thu, 20 Oct 2022 16:50:56 +0200 Subject: [PATCH 07/11] have the flake_inputs/ directory be cleaned inside clean_old_gc_roots --- direnvrc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/direnvrc b/direnvrc index c2d91f7..dbc470e 100644 --- a/direnvrc +++ b/direnvrc @@ -135,8 +135,10 @@ _nix_clean_old_gcroots() { local escaped_layout_dir escaped_layout_dir=$(_nix_strip_escape_path "$layout_dir") + rm -rfv "$layout_dir/flake_inputs/" rm -fv "$layout_dir"/{nix,flake}-profile* - rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"--{nix,flake}--profile* + rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"-flake--inputs* + rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"-{nix,flake}--profile* } _nix_argsum_suffix() { @@ -214,7 +216,6 @@ use_flake() { # also add garbage collection root for source local flake_input_paths - rm -rf "$flake_inputs" mkdir "$flake_inputs" flake_input_paths=$("${NIX_BIN_PREFIX}nix" flake archive \ --json \ @@ -222,7 +223,6 @@ use_flake() { --no-write-lock-file \ "$flake_dir" | grep -E -o '/nix/store/[^"]+') for path in $flake_input_paths; do - _nix_clean_old_gcroots "$flake_inputs" _nix_add_gcroot "$path" "${flake_inputs}/${path##*/}" done From 64c2b7bff71c627b82923a88094bb0401c2723ac Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Fri, 21 Oct 2022 12:17:59 +0200 Subject: [PATCH 08/11] clean old gcroots: typo in removal of flake-inputs --- direnvrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/direnvrc b/direnvrc index dbc470e..8683cf5 100644 --- a/direnvrc +++ b/direnvrc @@ -135,7 +135,7 @@ _nix_clean_old_gcroots() { local escaped_layout_dir escaped_layout_dir=$(_nix_strip_escape_path "$layout_dir") - rm -rfv "$layout_dir/flake_inputs/" + rm -rfv "$layout_dir/flake-inputs/" rm -fv "$layout_dir"/{nix,flake}-profile* rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"-flake--inputs* rm -fv "/nix/var/nix/gcroots/per-user/$USER/$escaped_layout_dir"-{nix,flake}--profile* From db0e37ea656a1983c21b6bd4529a7365f7d0c26a Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Fri, 21 Oct 2022 12:18:32 +0200 Subject: [PATCH 09/11] test_gc: force change of env by passing arg to shell.nix --- tests/test_gc.py | 4 +--- tests/testenv/shell.nix | 15 ++++++--------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index e93a18c..12240b6 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -64,8 +64,7 @@ def test_use_nix(direnv_project: DirenvProject) -> None: direnv_project.setup_envrc("use nix") common_test(direnv_project) - # --pure here is just a way to make sure the environment changes - direnv_project.setup_envrc("use nix --pure") + direnv_project.setup_envrc("use nix --argstr 'echo Executing hijacked shellHook.'") common_test_clean(direnv_project) @@ -81,7 +80,6 @@ def test_use_flake(direnv_project: DirenvProject) -> None: for symlink in inputs: assert symlink.is_dir() - # --impure here is just a way to make sure the environment changes direnv_project.setup_envrc("use flake --impure") common_test_clean(direnv_project) diff --git a/tests/testenv/shell.nix b/tests/testenv/shell.nix index c5c9d85..05d0a7a 100644 --- a/tests/testenv/shell.nix +++ b/tests/testenv/shell.nix @@ -1,14 +1,11 @@ -{ pkgs ? import {}, someArg ? null }: +{ pkgs ? import { }, someArg ? null, shellHook ? '' + echo "Executing shellHook." +'' }: pkgs.mkShellNoCC { + inherit shellHook; + nativeBuildInputs = [ pkgs.hello ]; - shellHook = '' - echo "Executing shellHook." - ''; SHOULD_BE_SET = someArg; - passthru = { - subshell = pkgs.mkShellNoCC { - THIS_IS_A_SUBSHELL = "OK"; - }; - }; + passthru = { subshell = pkgs.mkShellNoCC { THIS_IS_A_SUBSHELL = "OK"; }; }; } From 05a63253879ce0bcc273a556985fdf1b6be2bfd5 Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Fri, 21 Oct 2022 15:03:02 +0200 Subject: [PATCH 10/11] test_gc: correct use of use_nix --arg --- tests/test_gc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index 12240b6..3593f22 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -64,7 +64,9 @@ def test_use_nix(direnv_project: DirenvProject) -> None: direnv_project.setup_envrc("use nix") common_test(direnv_project) - direnv_project.setup_envrc("use nix --argstr 'echo Executing hijacked shellHook.'") + direnv_project.setup_envrc( + "use nix --argstr shellHook 'echo Executing hijacked shellHook.'" + ) common_test_clean(direnv_project) From f9c23f2c6737937a586e8d7199eeacf0e3434013 Mon Sep 17 00:00:00 2001 From: Quentin Aristote Date: Fri, 21 Oct 2022 15:06:50 +0200 Subject: [PATCH 11/11] test_gc: remove useless call to list --- tests/test_gc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_gc.py b/tests/test_gc.py index 3593f22..fefda77 100644 --- a/tests/test_gc.py +++ b/tests/test_gc.py @@ -55,7 +55,7 @@ def common_test_clean(direnv_project: DirenvProject) -> None: rcs = [f for f in files if f.match("*.rc")] profiles = [f for f in files if not f.match("*.rc")] if len(rcs) != 1 or len(profiles) != 1: - print(list(files)) + print(files) assert len(rcs) == 1 assert len(profiles) == 1