From b10196d0802f9295f83ea966f6bef671f558c5f0 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:06:56 +0100 Subject: [PATCH 01/18] add `gm clean` to clean the store --- src/nu-git-manager/mod.nu | 47 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 488854b1..99027798 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -326,3 +326,50 @@ export def "gm remove" [ null } + +# clean the store +# +# this command will mainly remove empty directory recursively. +# +# /!\ this command will return sanitized paths. /!\ +# +# Examples +# clean the store +# > gm clean +# +# list the leaves of the store that would have to be cleaned +# > gm clean --list +export def "gm clean" [ + --list # only list without cleaning +]: nothing -> list { + let empty_directories_in_store = ls (gm status | get root.path | path join "**") + | where (ls $it.name | is-empty) + | get name + let cached_repos = gm list --full-path + + let empty_non_repo_directories_in_store = $empty_directories_in_store + | where not ($cached_repos | any {|repo| $it | str starts-with $repo}) + + if $list { + return $empty_non_repo_directories_in_store + } + + let deleted = unfold $empty_non_repo_directories_in_store {|directories| + let next = $directories | each {|it| + ^rmdir $it + + let parent = $it | path dirname; + if (ls $parent | is-empty) { + $parent + } + } + + if ($next | is-empty) { + {out: $directories} + } else { + {out: $directories, next: $next} + } + } + + $deleted | flatten +} From 02b8dfc1d56f8f2ddce8c0640c14602616e4101d Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:12:27 +0100 Subject: [PATCH 02/18] move the "empty directory" cleaning to submodule --- src/nu-git-manager/fs/dir.nu | 23 +++++++++++++++++++++++ src/nu-git-manager/mod.nu | 20 ++------------------ 2 files changed, 25 insertions(+), 18 deletions(-) create mode 100644 src/nu-git-manager/fs/dir.nu diff --git a/src/nu-git-manager/fs/dir.nu b/src/nu-git-manager/fs/dir.nu new file mode 100644 index 00000000..247c37f4 --- /dev/null +++ b/src/nu-git-manager/fs/dir.nu @@ -0,0 +1,23 @@ +# clean all empty directories recursively, starting from a list of empty leaves +# +# /!\ this command will return sanitized paths /!\ +export def clean-empty-directories-rec []: list -> list { + let deleted = unfold $in {|directories| + let next = $directories | each {|it| + ^rmdir $it + + let parent = $it | path dirname; + if (ls $parent | is-empty) { + $parent | path sanitize + } + } + + if ($next | is-empty) { + {out: $directories} + } else { + {out: $directories, next: $next} + } + } + + $deleted | flatten +} diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 99027798..a699f6b2 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -5,6 +5,7 @@ use fs/cache.nu [ get-repo-store-cache-path, check-cache-file, add-to-cache, remove-from-cache, open-cache, save-cache, clean-cache-dir ] +use fs/dir.nu [clean-empty-directories-rec] use git/url.nu [parse-git-url, get-fetch-push-urls] use error/error.nu [throw-error] @@ -354,22 +355,5 @@ export def "gm clean" [ return $empty_non_repo_directories_in_store } - let deleted = unfold $empty_non_repo_directories_in_store {|directories| - let next = $directories | each {|it| - ^rmdir $it - - let parent = $it | path dirname; - if (ls $parent | is-empty) { - $parent - } - } - - if ($next | is-empty) { - {out: $directories} - } else { - {out: $directories, next: $next} - } - } - - $deleted | flatten + $empty_non_repo_directories_in_store | clean-empty-directories-rec } From 7876c3a38c2eeece9f774b0b54941339b9328972 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:21:13 +0100 Subject: [PATCH 03/18] add a test for the directory cleaning --- tests/mod.nu | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/mod.nu b/tests/mod.nu index 01b14dde..7a1107bb 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -7,6 +7,7 @@ use ../src/nu-git-manager/fs/cache.nu [ save-cache, clean-cache-dir ] use ../src/nu-git-manager/fs/path.nu "path sanitize" +use ../src/nu-git-manager/fs/dir.nu [clean-empty-directories-rec] export def path-sanitization [] { assert equal ('\foo\bar' | path sanitize) "/foo/bar" @@ -240,3 +241,40 @@ export def install-package [] { rm --recursive --force --verbose $env.NUPM_HOME } } + +export def store-cleaning [] { + with-env {GIT_REPOS_HOME: "/tmp/nu-git-manager/foo"} { + mkdir $env.GIT_REPOS_HOME + touch ($env.GIT_REPOS_HOME | path join ".lock") + + let empty_directories = [ + foo/bar/ + bar/ + baz/foo/bar/ + ] + + let actual = $empty_directories + | each {|it| + let path = $env.GIT_REPOS_HOME | path join $it + mkdir $path + + $path + } + | clean-empty-directories-rec + | str replace $env.GIT_REPOS_HOME '' + | str trim --char '/' + let expected = [ + "foo/bar", + "bar", + "baz/foo/bar", + "foo", + "baz/foo", + "baz", + "", + ] + + assert equal $actual $expected + + rm --recursive --verbose --force $env.GIT_REPOS_HOME + } +} From f64454b537433df7f9ce78f4f7af3c7a0ae3ed4f Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:25:59 +0100 Subject: [PATCH 04/18] add a NOTE about the `.lock` file --- tests/mod.nu | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mod.nu b/tests/mod.nu index 7a1107bb..cbf7cae7 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -245,6 +245,8 @@ export def install-package [] { export def store-cleaning [] { with-env {GIT_REPOS_HOME: "/tmp/nu-git-manager/foo"} { mkdir $env.GIT_REPOS_HOME + # NOTE: this is to make sure the root of the test is not empty + # we don't want the test to go remove empty directories outside... touch ($env.GIT_REPOS_HOME | path join ".lock") let empty_directories = [ From e1d6308ae192fb5cd04b5067ba32d352b7ad463d Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:26:04 +0100 Subject: [PATCH 05/18] rename the test base dir foo is not very... professional --- tests/mod.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mod.nu b/tests/mod.nu index cbf7cae7..a1c4f9ff 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -243,7 +243,7 @@ export def install-package [] { } export def store-cleaning [] { - with-env {GIT_REPOS_HOME: "/tmp/nu-git-manager/foo"} { + with-env {GIT_REPOS_HOME: "/tmp/nu-git-manager/store-cleaning"} { mkdir $env.GIT_REPOS_HOME # NOTE: this is to make sure the root of the test is not empty # we don't want the test to go remove empty directories outside... From 6281419e7e673393df2a8f71360862eaba5d1f39 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:32:41 +0100 Subject: [PATCH 06/18] clean after a `gm remove` --- src/nu-git-manager/mod.nu | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index a699f6b2..83051763 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -319,11 +319,17 @@ export def "gm remove" [ } } - rm --recursive --force --verbose ($root | path join $repo_to_remove) + let repo_to_remove = $root | path join $repo_to_remove + + rm --recursive --force --verbose $repo_to_remove let cache_file = get-repo-store-cache-path check-cache-file $cache_file - remove-from-cache $cache_file ($root | path join $repo_to_remove) + remove-from-cache $cache_file $repo_to_remove + + if (ls ($repo_to_remove | path dirname) | is-empty) { + [($repo_to_remove | path dirname)] | clean-empty-directories-rec + } null } From ec590eb3ef0d442a356d566b7d91e4de494891fd Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:32:49 +0100 Subject: [PATCH 07/18] test the `gm remove` cleaning --- tests/gm.nu | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/gm.nu b/tests/gm.nu index ad23865c..5e00f068 100644 --- a/tests/gm.nu +++ b/tests/gm.nu @@ -231,3 +231,14 @@ export def remove [] { assert equal (gm list) [] } } + +export def store-cleaning [] { + run-with-env --prepare-cache { + gm clone https://github.com/amtoine/nu-git-manager --depth 1 + gm remove "github.com/amtoine/nu-git-manager" --no-confirm + + # NOTE: the root should not exist anymore because there was only one repo in it and it's + # been cleaned + assert not ($env.GIT_REPOS_HOME | path exists) + } +} From 0f3a397dd5d647dfbbc903c46a5dd4a011a6c047 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:37:48 +0100 Subject: [PATCH 08/18] add a test for `gm clean` --- tests/gm.nu | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/gm.nu b/tests/gm.nu index 5e00f068..5f53e7a4 100644 --- a/tests/gm.nu +++ b/tests/gm.nu @@ -232,7 +232,7 @@ export def remove [] { } } -export def store-cleaning [] { +export def store-cleaning-after-remove [] { run-with-env --prepare-cache { gm clone https://github.com/amtoine/nu-git-manager --depth 1 gm remove "github.com/amtoine/nu-git-manager" --no-confirm @@ -242,3 +242,26 @@ export def store-cleaning [] { assert not ($env.GIT_REPOS_HOME | path exists) } } + +export def store-cleaning [] { + run-with-env --prepare-cache { + gm clone https://github.com/amtoine/nu-git-manager --depth 1 + rm --force --recursive --verbose ( + $env.GIT_REPOS_HOME | path join "github.com/amtoine/nu-git-manager" + ) + + let expected = [($env.GIT_REPOS_HOME | path join "github.com/amtoine")] + assert equal (gm clean --list) $expected + + let expected = [ + ($env.GIT_REPOS_HOME | path join "github.com/amtoine") + ($env.GIT_REPOS_HOME | path join "github.com") + $env.GIT_REPOS_HOME + ] + assert equal (gm clean) $expected + + # NOTE: the root should not exist anymore because there was only one repo in it and it's + # been cleaned + assert not ($env.GIT_REPOS_HOME | path exists) + } +} From 02861d631e09e800e49e9f51792b445b7dc82382 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:40:44 +0100 Subject: [PATCH 09/18] sanitize the paths for the Windows CI --- src/nu-git-manager/fs/dir.nu | 2 ++ tests/gm.nu | 15 +++++++++------ tests/mod.nu | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/nu-git-manager/fs/dir.nu b/src/nu-git-manager/fs/dir.nu index 247c37f4..d8a66d08 100644 --- a/src/nu-git-manager/fs/dir.nu +++ b/src/nu-git-manager/fs/dir.nu @@ -1,3 +1,5 @@ +use path.nu ["path sanitize"] + # clean all empty directories recursively, starting from a list of empty leaves # # /!\ this command will return sanitized paths /!\ diff --git a/tests/gm.nu b/tests/gm.nu index 5f53e7a4..bc79aea9 100644 --- a/tests/gm.nu +++ b/tests/gm.nu @@ -246,17 +246,20 @@ export def store-cleaning-after-remove [] { export def store-cleaning [] { run-with-env --prepare-cache { gm clone https://github.com/amtoine/nu-git-manager --depth 1 - rm --force --recursive --verbose ( - $env.GIT_REPOS_HOME | path join "github.com/amtoine/nu-git-manager" + + let repo = ( + $env.GIT_REPOS_HOME | path join "github.com/amtoine/nu-git-manager" | path sanitize ) - let expected = [($env.GIT_REPOS_HOME | path join "github.com/amtoine")] + rm --force --recursive --verbose $repo + + let expected = [($repo | path dirname)] assert equal (gm clean --list) $expected let expected = [ - ($env.GIT_REPOS_HOME | path join "github.com/amtoine") - ($env.GIT_REPOS_HOME | path join "github.com") - $env.GIT_REPOS_HOME + ($repo | path dirname) + ($repo | path dirname --num-levels 2) + ($repo | path dirname --num-levels 3) ] assert equal (gm clean) $expected diff --git a/tests/mod.nu b/tests/mod.nu index a1c4f9ff..9ceabc98 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -257,7 +257,7 @@ export def store-cleaning [] { let actual = $empty_directories | each {|it| - let path = $env.GIT_REPOS_HOME | path join $it + let path = $env.GIT_REPOS_HOME | path join $it | path sanitize mkdir $path $path From 490ae67cdda3094ab97503d4577507980b6674d8 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:52:00 +0100 Subject: [PATCH 10/18] put test files in `~/.local/share/` for Windows permissions --- tests/mod.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mod.nu b/tests/mod.nu index 9ceabc98..67f4b010 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -243,7 +243,7 @@ export def install-package [] { } export def store-cleaning [] { - with-env {GIT_REPOS_HOME: "/tmp/nu-git-manager/store-cleaning"} { + with-env {GIT_REPOS_HOME: ($nu.home-path | path join ".local/share/nu-git-manager-tests")} { mkdir $env.GIT_REPOS_HOME # NOTE: this is to make sure the root of the test is not empty # we don't want the test to go remove empty directories outside... From a539ad3023f2e29b8a1c243c3cd3b719d490c40d Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:56:34 +0100 Subject: [PATCH 11/18] add a debug statement when making directories --- tests/mod.nu | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/mod.nu b/tests/mod.nu index 67f4b010..5b5a0320 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -258,6 +258,8 @@ export def store-cleaning [] { let actual = $empty_directories | each {|it| let path = $env.GIT_REPOS_HOME | path join $it | path sanitize + + print $"making `($path)`" mkdir $path $path From 059e18d3aa6ce10b73b01b6b220cd41dcde6f1c0 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 19:59:28 +0100 Subject: [PATCH 12/18] use `rm` instead of `rmdir` --- src/nu-git-manager/fs/dir.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nu-git-manager/fs/dir.nu b/src/nu-git-manager/fs/dir.nu index d8a66d08..e2c28474 100644 --- a/src/nu-git-manager/fs/dir.nu +++ b/src/nu-git-manager/fs/dir.nu @@ -6,7 +6,7 @@ use path.nu ["path sanitize"] export def clean-empty-directories-rec []: list -> list { let deleted = unfold $in {|directories| let next = $directories | each {|it| - ^rmdir $it + rm --force --verbose $it let parent = $it | path dirname; if (ls $parent | is-empty) { From 7d716f1edc916c84c413a361374c068788fbdd2b Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 20:02:04 +0100 Subject: [PATCH 13/18] fix the root replacement in output of `tests gm store-cleaning` --- tests/mod.nu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mod.nu b/tests/mod.nu index 5b5a0320..716e0d64 100644 --- a/tests/mod.nu +++ b/tests/mod.nu @@ -265,7 +265,7 @@ export def store-cleaning [] { $path } | clean-empty-directories-rec - | str replace $env.GIT_REPOS_HOME '' + | str replace ($env.GIT_REPOS_HOME | path sanitize) '' | str trim --char '/' let expected = [ "foo/bar", From 42036ffd0d56c698736c59c8abb9403dd4f31523 Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 20:07:57 +0100 Subject: [PATCH 14/18] sanitize the paths of `gm clean --list` as advertised :eyes: --- src/nu-git-manager/mod.nu | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 83051763..810e3502 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -352,6 +352,7 @@ export def "gm clean" [ let empty_directories_in_store = ls (gm status | get root.path | path join "**") | where (ls $it.name | is-empty) | get name + | each { path sanitize } let cached_repos = gm list --full-path let empty_non_repo_directories_in_store = $empty_directories_in_store From ce4a9f41073ae76e7034b2b8d5edc0be79260c3f Mon Sep 17 00:00:00 2001 From: amtoine Date: Tue, 7 Nov 2023 20:13:00 +0100 Subject: [PATCH 15/18] expand the paths in `gm clean` for Windows --- src/nu-git-manager/mod.nu | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 810e3502..1a9cc604 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -352,6 +352,7 @@ export def "gm clean" [ let empty_directories_in_store = ls (gm status | get root.path | path join "**") | where (ls $it.name | is-empty) | get name + | path expand | each { path sanitize } let cached_repos = gm list --full-path From 7c28611dad7de675d4db4771f08e38a1f5a85e98 Mon Sep 17 00:00:00 2001 From: amtoine Date: Thu, 9 Nov 2023 18:42:27 +0100 Subject: [PATCH 16/18] print the deleted files at the end of `gm remove` --- src/nu-git-manager/mod.nu | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 1a9cc604..0f3db740 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -328,7 +328,13 @@ export def "gm remove" [ remove-from-cache $cache_file $repo_to_remove if (ls ($repo_to_remove | path dirname) | is-empty) { - [($repo_to_remove | path dirname)] | clean-empty-directories-rec + let deleted = [($repo_to_remove | path dirname)] | clean-empty-directories-rec + + print ( + ["the following empty directories have been removed:"] + | append $deleted + | str join "\n- " + ) } null From 6fb4c3474a68ec1256012100639d0483cbc0a7d2 Mon Sep 17 00:00:00 2001 From: amtoine Date: Fri, 10 Nov 2023 18:44:14 +0100 Subject: [PATCH 17/18] print the deleted empty directories once --- src/nu-git-manager/fs/dir.nu | 2 +- src/nu-git-manager/mod.nu | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/nu-git-manager/fs/dir.nu b/src/nu-git-manager/fs/dir.nu index e2c28474..4cbc5e64 100644 --- a/src/nu-git-manager/fs/dir.nu +++ b/src/nu-git-manager/fs/dir.nu @@ -6,7 +6,7 @@ use path.nu ["path sanitize"] export def clean-empty-directories-rec []: list -> list { let deleted = unfold $in {|directories| let next = $directories | each {|it| - rm --force --verbose $it + rm --force $it let parent = $it | path dirname; if (ls $parent | is-empty) { diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index 0f3db740..da689055 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -330,11 +330,10 @@ export def "gm remove" [ if (ls ($repo_to_remove | path dirname) | is-empty) { let deleted = [($repo_to_remove | path dirname)] | clean-empty-directories-rec - print ( - ["the following empty directories have been removed:"] - | append $deleted - | str join "\n- " - ) + print "the following empty directories have been removed:" + print $deleted + } else { + print "no empty directory to clean" } null From 1ac811d23c60f701eff33a1945beae54152ec2d6 Mon Sep 17 00:00:00 2001 From: amtoine Date: Fri, 10 Nov 2023 18:47:13 +0100 Subject: [PATCH 18/18] add missing import --- src/nu-git-manager/mod.nu | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nu-git-manager/mod.nu b/src/nu-git-manager/mod.nu index da689055..49c5c162 100644 --- a/src/nu-git-manager/mod.nu +++ b/src/nu-git-manager/mod.nu @@ -6,6 +6,7 @@ use fs/cache.nu [ save-cache, clean-cache-dir ] use fs/dir.nu [clean-empty-directories-rec] +use fs/path.nu ["path sanitize"] use git/url.nu [parse-git-url, get-fetch-push-urls] use error/error.nu [throw-error]