From d0e56c43992b5e6e27f239fd170d14df76386153 Mon Sep 17 00:00:00 2001 From: Texas Toland Date: Wed, 20 Mar 2024 14:32:02 -0500 Subject: [PATCH] Clean up `file bulk-rename` a little - Rename command conventionally - Optional input especially for globbing - Add shorthand flags - Run in parallel - More tests --- stdlib-candidate/{README.md => _README.md} | 0 stdlib-candidate/std-rfc/batch-rename.nu | 41 ++++++++++++++ stdlib-candidate/std-rfc/fs.nu | 35 ------------ stdlib-candidate/std-rfc/mod.nu | 2 +- stdlib-candidate/tests/batch-rename.nu | 62 ++++++++++++++++++++++ stdlib-candidate/tests/fs.nu | 50 ----------------- stdlib-candidate/tests/mod.nu | 2 +- 7 files changed, 105 insertions(+), 87 deletions(-) rename stdlib-candidate/{README.md => _README.md} (100%) create mode 100644 stdlib-candidate/std-rfc/batch-rename.nu delete mode 100644 stdlib-candidate/std-rfc/fs.nu create mode 100644 stdlib-candidate/tests/batch-rename.nu delete mode 100644 stdlib-candidate/tests/fs.nu diff --git a/stdlib-candidate/README.md b/stdlib-candidate/_README.md similarity index 100% rename from stdlib-candidate/README.md rename to stdlib-candidate/_README.md diff --git a/stdlib-candidate/std-rfc/batch-rename.nu b/stdlib-candidate/std-rfc/batch-rename.nu new file mode 100644 index 000000000..22672464a --- /dev/null +++ b/stdlib-candidate/std-rfc/batch-rename.nu @@ -0,0 +1,41 @@ +# Rename a batch of files using a closure. +# +# The reason behind this command is quite simple: +# - Sometimes one receives a bunch of files with integer ids: 1, 2, 3, ... +# - These ids come rarely with padding... i.e. 1 instead of 001 when there are 3-digit ids +# - This means that file with id 9 will be sorted way after file with id 1000 +# +# This command allows to do such a task! +# +# Examples: +# Rename `.mise.toml` files to `.mise.local.toml` recursively +# > glob **/.mise.toml | batch-rename { str append .local } +# +# Rename files in `/foo` with a name that has an id to have 3 digits with 0-padding +# > batch-rename --dir /foo { +# parse "some_format_{id}" +# | get 0 +# | update id { fill --alignment r --character 0 --width 3 } +# | $"some_format_($in.id)" +# } +export def main [ + update_stem: closure, # The code to run on the stem of the files: should start with parsing the format and end with reconstructing the same format + --directory (-d): path, # The path where non-hidden files need to be renamed in bulk + --verbose (-v), # Be verbose when moving the files around +]: nothing -> nothing { + let paths = if $directory == null { + $in + } else { + # ls instead of glob for hidden file behavior + ls --full-paths $directory | get name + } + if $paths == null { + error make { msg: 'batch-rename expects input paths or a valid --directory' } + } + $paths | par-each { + let old = $in + let new = $old | path parse | update stem $update_stem | path join + mv --force --verbose=$verbose $old $new + } + ignore +} diff --git a/stdlib-candidate/std-rfc/fs.nu b/stdlib-candidate/std-rfc/fs.nu deleted file mode 100644 index e2fce5210..000000000 --- a/stdlib-candidate/std-rfc/fs.nu +++ /dev/null @@ -1,35 +0,0 @@ -# rename a bulk of files in a directory using a closure -# -# the reason behind this command is quite simple -# - sometimes one receives a bunch of files with integer ids: 1, 2, 3, ... -# - these ids come rarely with padding... i.e. 1 instead of 001 when there are 3-digit ids -# - this means that file with id 9 will be sorted way after file with id 1000 -# -# this command allows to do such a task! -# -# # Examples -# rename files in `/foo` with a name that has an id to have 3 digits with 0-padding -# > file bulk-rename /foo { -# parse "some_format_{id}" -# | get 0 -# | update id { fill --alignment r --character 0 --width 3 } -# | $"some_format_($in.id)" -# } -export def "file bulk-rename" [ - directory: path, # the path where files need to be renamed in bulk - stem_update: closure, # the code to run on the stem of the files: should start with parsing the format and end with reconstructing the same format - --verbose, # be verbose when moving the files around -]: nothing -> nothing { - ls --full-paths $directory | insert new {|row| - $row.name | path parse | update stem $stem_update | path join - } - | each { - if $verbose { - mv --force --verbose $in.name $in.new - } else { - mv --force $in.name $in.new - } - } - - null -} diff --git a/stdlib-candidate/std-rfc/mod.nu b/stdlib-candidate/std-rfc/mod.nu index e4e473b67..d990f7258 100644 --- a/stdlib-candidate/std-rfc/mod.nu +++ b/stdlib-candidate/std-rfc/mod.nu @@ -2,5 +2,5 @@ export module record/ export module str.nu # commands -export use fs.nu * +export use batch-rename.nu * export use set-env.nu * diff --git a/stdlib-candidate/tests/batch-rename.nu b/stdlib-candidate/tests/batch-rename.nu new file mode 100644 index 000000000..fee66d1e5 --- /dev/null +++ b/stdlib-candidate/tests/batch-rename.nu @@ -0,0 +1,62 @@ +use std assert +use ../std-rfc 'batch-rename' + +const fixture = [ + .gitignore + Cargo.toml + LICENSE + README.md + src + test.nu +] + +export def 'test batch-rename --directory' [] { + test batch-rename { + batch-rename --directory $in { '_' + $in } + } --expects [ + .gitignore # hidden by default + _Cargo.toml + _LICENSE + _README.md + _src + _test.nu + ] +} + +export def 'test batch-rename where' [] { + test batch-rename { + glob ($in | path join *.*) | batch-rename { '_' + $in } + } --expects [ + LICENSE # skip + _.gitignore + _Cargo.toml + _README.md + _test.nu + src # skip + ] +} + +export def 'test batch-rename missing' [] { + assert error { + test batch-rename { ignore | batch-rename { '_' + $in } } + } +} + +def 'test batch-rename' [ + command: closure + --expects: list +] { + let test_dir = $nu.temp-path | path join (random uuid) + def actual-files [] { + ls --all --short-names $test_dir | get name | sort + } + # before + mkdir $test_dir + $fixture | each { |name| touch ($test_dir | path join $name) } + assert equal $fixture (actual-files) + # test + $test_dir | do $command + assert equal $expects (actual-files) + # after + rm --recursive --force $test_dir +} diff --git a/stdlib-candidate/tests/fs.nu b/stdlib-candidate/tests/fs.nu deleted file mode 100644 index 9af5659f9..000000000 --- a/stdlib-candidate/tests/fs.nu +++ /dev/null @@ -1,50 +0,0 @@ -use std assert -use ../std-rfc "file bulk-rename" - -alias rename = file bulk-rename - -export def "test file bulk-rename" [] { - let test_dir = $nu.temp-path | path join (random uuid) - - mkdir $test_dir - seq 1 10 | each {|i| touch ($test_dir | path join $"some_($i)_format.txt") } - - let expected = [ - "some_10_format.txt", - "some_1_format.txt", - "some_2_format.txt", - "some_3_format.txt", - "some_4_format.txt", - "some_5_format.txt", - "some_6_format.txt", - "some_7_format.txt", - "some_8_format.txt", - "some_9_format.txt", - ] - let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/" - assert equal ($actual | sort) $expected - - rename $test_dir { - parse "some_{i}_format" - | get 0 - | update i { fill --alignment r --character 0 --width 3 } - | $"some_($in.i)_format" - } - - let expected = [ - "some_001_format.txt", - "some_002_format.txt", - "some_003_format.txt", - "some_004_format.txt", - "some_005_format.txt", - "some_006_format.txt", - "some_007_format.txt", - "some_008_format.txt", - "some_009_format.txt", - "some_010_format.txt", - ] - let actual = glob $"($test_dir)/*" | str replace $test_dir "" | str trim --left --char "/" - assert equal ($actual | sort) $expected - - rm -rf $test_dir -} diff --git a/stdlib-candidate/tests/mod.nu b/stdlib-candidate/tests/mod.nu index 8f03760ec..4584351bc 100644 --- a/stdlib-candidate/tests/mod.nu +++ b/stdlib-candidate/tests/mod.nu @@ -1,3 +1,3 @@ -export module fs.nu +export module batch-rename.nu export module record.nu export module str.nu