From 81a48d6d0e416a2db0d5626c9e2c2af5d2bc83f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Grythe=20St=C3=B8dle?= Date: Tue, 24 Mar 2020 02:00:48 +0100 Subject: [PATCH] Fix '/' and '..' not being valid mv targets (#1519) * Fix '/' and '..' not being valid mv targets If `/` or `../` is specified as the destination for `mv`, it will fail with an error message saying it's not a valid destination. This fixes it to account for the fact that `Path::file_name` return `None` when the file name evaluates to `/` or `..`. It will only take the slow(er) path if `Path::file_name` returns `None` in its initial check. Fixes #1291 * Add test --- crates/nu-cli/src/shell/filesystem_shell.rs | 26 +++++++++++++++++---- crates/nu-cli/tests/commands/mv.rs | 20 ++++++++++++++++ 2 files changed, 41 insertions(+), 5 deletions(-) diff --git a/crates/nu-cli/src/shell/filesystem_shell.rs b/crates/nu-cli/src/shell/filesystem_shell.rs index 9c39f13e36..1554c5f7a5 100644 --- a/crates/nu-cli/src/shell/filesystem_shell.rs +++ b/crates/nu-cli/src/shell/filesystem_shell.rs @@ -631,11 +631,27 @@ impl Shell for FilesystemShell { match destination.file_name() { Some(name) => PathBuf::from(name), None => { - return Err(ShellError::labeled_error( - "Rename aborted. Not a valid destination", - "not a valid destination", - dst.tag, - )) + let name_maybe = + destination.components().next_back().and_then( + |component| match component { + Component::RootDir => Some(PathBuf::from("/")), + Component::ParentDir => destination + .parent() + .and_then(|parent| parent.file_name()) + .map(PathBuf::from), + _ => None, + }, + ); + + if let Some(name) = name_maybe { + name + } else { + return Err(ShellError::labeled_error( + "Rename aborted. Not a valid destination", + "not a valid destination", + dst.tag, + )); + } } } }; diff --git a/crates/nu-cli/tests/commands/mv.rs b/crates/nu-cli/tests/commands/mv.rs index d4fa014809..c49c27bec7 100644 --- a/crates/nu-cli/tests/commands/mv.rs +++ b/crates/nu-cli/tests/commands/mv.rs @@ -230,3 +230,23 @@ fn errors_if_source_doesnt_exist() { assert!(actual.contains("Invalid File or Pattern")); }) } + +#[test] +fn does_not_error_on_relative_parent_path() { + Playground::setup("mv_test_11", |dirs, sandbox| { + sandbox + .mkdir("first") + .with_files(vec![EmptyFile("first/william_hartnell.txt")]); + + let original = dirs.test().join("first/william_hartnell.txt"); + let expected = dirs.test().join("william_hartnell.txt"); + + nu!( + cwd: dirs.test().join("first"), + "mv william_hartnell.txt ./.." + ); + + assert!(!original.exists()); + assert!(expected.exists()); + }) +}