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](https://www.nushell.sh/commands/categories/filesystem.html)
- Optional input especially for globbing
- Record closure param with full path for skipping dirs for example
- Add shorthand flags
- Run in parallel
- More tests
  • Loading branch information
texastoland committed Mar 23, 2024
1 parent 7d662ad commit 559ef2e
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 87 deletions.
57 changes: 57 additions & 0 deletions stdlib-candidate/std-rfc/bulk-rename.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Rename a bulk 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 | bulk-rename { str append .local }
#
# Rename files in `/foo` with a name that has an id to have 3 digits with 0-padding
# > bulk-rename --directory /foo { |path|
# if ($path.full | path type) == file {
# $path.stem | parse "some_format_{id}"
# | get 0
# | update id { fill --alignment r --character 0 --width 3 }
# | $"some_format_($in.id)"
# } else {
# $path.stem # skip if dir
# }
# }
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 `full` path keys
--directory (-d): path, # The path where non-hidden files need to be renamed
--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
]: [nothing -> nothing, nothing -> table<old: path new: path>, list<
path> -> nothing, list<path> -> table<old: path new: path>] {
let paths = if $directory == null {
$in
} else {
# ls instead of glob to omit hidden files
ls --full-paths $directory | get name
}
if $paths == null {
error make { msg: 'bulk-rename expects input paths or a valid --directory' }
}
let renamed = $paths | par-each --keep-order { |old|
let new = $old
| path parse
| update stem { do $update_stem { stem: $in full: $old } }
| 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 *
104 changes: 104 additions & 0 deletions stdlib-candidate/tests/bulk-rename.nu
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use std assert
use ../std-rfc 'bulk-rename'

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

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

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

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

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

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 }
}
}

export def 'test missing-args' [] {
assert error { 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 559ef2e

Please sign in to comment.