diff --git a/crates/nu-cli/src/shell/filesystem_shell.rs b/crates/nu-cli/src/shell/filesystem_shell.rs index ebae43532b..76cb0ac230 100644 --- a/crates/nu-cli/src/shell/filesystem_shell.rs +++ b/crates/nu-cli/src/shell/filesystem_shell.rs @@ -446,7 +446,7 @@ impl Shell for FilesystemShell { let source = path.join(&src.item); let destination = path.join(&dst.item); - let sources = + let mut sources = glob::glob(&source.to_string_lossy()).map_or_else(|_| Vec::new(), Iterator::collect); if sources.is_empty() { @@ -477,6 +477,29 @@ impl Shell for FilesystemShell { )); } + let some_if_source_is_destination = sources + .iter() + .find(|f| matches!(f, Ok(f) if destination.starts_with(f))); + if destination.exists() && destination.is_dir() && sources.len() == 1 { + if let Some(Ok(filename)) = some_if_source_is_destination { + return Err(ShellError::labeled_error( + format!( + "Not possible to move {:?} to itself", + filename.file_name().expect("Invalid file name") + ), + "cannot move to itself", + dst.tag, + )); + } + } + + if let Some(Ok(_filename)) = some_if_source_is_destination { + sources = sources + .into_iter() + .filter(|f| matches!(f, Ok(f) if !destination.starts_with(f))) + .collect(); + } + for entry in sources { if let Ok(entry) = entry { move_file( diff --git a/crates/nu-cli/tests/commands/move_/mv.rs b/crates/nu-cli/tests/commands/move_/mv.rs index 41c0e99c43..5debb64b38 100644 --- a/crates/nu-cli/tests/commands/move_/mv.rs +++ b/crates/nu-cli/tests/commands/move_/mv.rs @@ -257,6 +257,20 @@ fn errors_if_renaming_directory_to_an_existing_file() { }) } +#[test] +fn errors_if_moving_to_itself() { + Playground::setup("mv_test_10_4", |dirs, sandbox| { + sandbox.mkdir("mydir").mkdir("mydir/mydir_2"); + + let actual = nu!( + cwd: dirs.test(), + "mv mydir mydir/mydir_2/" + ); + + assert!(actual.err.contains("cannot move to itself")); + }) +} + #[test] fn does_not_error_on_relative_parent_path() { Playground::setup("mv_test_11", |dirs, sandbox| { @@ -331,3 +345,17 @@ fn move_file_from_two_parents_up_using_multiple_dots_to_current_dir() { assert!(!original.exists()); }) } + +#[test] +fn does_not_error_when_some_file_is_moving_into_itself() { + Playground::setup("mv_test_13", |dirs, sandbox| { + sandbox.mkdir("11").mkdir("12"); + + let original_dir = dirs.test().join("11"); + let expected = dirs.test().join("12/11"); + nu!(cwd: dirs.test(), "mv 1* 12"); + + assert!(!original_dir.exists()); + assert!(expected.exists()); + }) +}