Skip to content

Commit

Permalink
Clean up file bulk-rename a little
Browse files Browse the repository at this point in the history
- No `file` prefix similar to other filesystem commands
- Optional input especially for globbing
- Record closure param with full path for filtering `--directory` (see examples)
- `--verbose` table output
- `--no-exectute` for dry-run with `--verbose`
- Shorthand flags
- Parallel renaming for large directories
- More tests
  • Loading branch information
texastoland committed Mar 27, 2024
1 parent 7d662ad commit 1e7810b
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 87 deletions.
50 changes: 50 additions & 0 deletions stdlib-candidate/std-rfc/bulk-rename.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Rename bulk input files in parallel 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 | bulk-rename { str append .local }
#
# Rename files in `/foo` with a name that has an id to have 3 digits with 0-padding
# > ls /foo | bulk-rename { |path|
# if $path.input.type == file {
# $path.stem | parse "some_format_{id}"
# | get 0
# | update id { fill --alignment r --character 0 --width 3 }
# | $"some_format_($in.id)"
# }
# # else skip dirs
# }
export def main [
update_stem: closure, # The code to rename the file stem: receives the old stem as input and a record param with both `stem` and `input` keys
--verbose (-v), # Show which files were renamed, if any
--no-execute (-n) # Do not make any changes; add --verbose to see what would be made
# whitespace bug: nushell/nushell#12264
]: [list<any> -> nothing, list<any> -> table<old: path new: path>] {
let renamed = par-each --keep-order { |input|
let update_or_keep_stem = { |parts|
do $update_stem { stem: $in input: $input } | default $parts.stem
}
let old = if ($input | describe) == string {
$input
} else {
$input.name # convenience for ls
}
let new = $old | path parse | update stem $update_or_keep_stem | path join
if $new != $old {
if not $no_execute {
mv --force --verbose=$verbose $old $new
}
{ old: $old new: $new }
}
}
if $verbose {
$renamed
}
}
35 changes: 0 additions & 35 deletions stdlib-candidate/std-rfc/fs.nu

This file was deleted.

2 changes: 1 addition & 1 deletion stdlib-candidate/std-rfc/mod.nu
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
export module record/
export module str.nu
# commands
export use fs.nu *
export use bulk-rename.nu *
export use set-env.nu *
95 changes: 95 additions & 0 deletions stdlib-candidate/tests/bulk-rename.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
use std assert
use ../std-rfc 'bulk-rename'

const fixture = [
.gitignore
Cargo.toml
LICENSE
README.md
src
test.nu
]

export def 'test ls' [] {
let expects = [
.gitignore # hidden by ls
_Cargo.toml
_LICENSE
_README.md
_src
_test.nu
]
test $expects {
ls $in | bulk-rename { '_' + $in }
}
}

export def 'test --no-execute' [] {
test $fixture {
ls $in | bulk-rename --no-execute { '_' + $in }
}
}

export def 'test --verbose' [] {
let expects = [
# .gitignore unchanged
_Cargo.toml
_LICENSE
_README.md
_src
_test.nu
]
let renamed = test $fixture {
ls $in | bulk-rename --verbose --no-execute { '_' + $in }
}
assert equal ($renamed.new | each { path basename }) $expects
}

export def 'test skip-extensions' [] {
let expects = [
.gitignore
Cargo.toml
LICENSE.txt # changed
README.md
src.txt # changed
test.nu
]
test $expects {
ls $in | bulk-rename { |path|
if $path.input.name ends-with $path.stem {
$path.stem + .txt
}
}
}
}

export def 'test glob' [] {
let expects = [
LICENSE # skipped
_.gitignore
_Cargo.toml
_README.md
_test.nu
src # skipped
]
test $expects {
glob ($in | path join *.*) | bulk-rename { '_' + $in }
}
}

def test [expects: list<string> command: closure] {
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 (actual-files) $fixture
# test
let renamed = $test_dir | do $command
assert equal (actual-files) $expects
# after
rm --recursive --force $test_dir
$renamed
}
50 changes: 0 additions & 50 deletions stdlib-candidate/tests/fs.nu

This file was deleted.

2 changes: 1 addition & 1 deletion stdlib-candidate/tests/mod.nu
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export module fs.nu
export module bulk-rename.nu
export module record.nu
export module str.nu

0 comments on commit 1e7810b

Please sign in to comment.