mirror of
https://github.com/nushell/nushell.git
synced 2025-02-16 18:41:44 +01:00
Fix: dst error on cp command (#7895)
Fixes #7693 On `cp` commands there were two error which pass error message with invalid detail about source and destination files . there error were for Not exist file and Permission denied . Examples: Before : Copy `source_file_valid` to `destination_invalid_dir` throw this error ; `copy file "/source_file_valid" failed: No such file or directory (os error 2) ` After this PR it will throw this if destination will be invalid : `copying to destination "/destination_invalid_dir" failed: No such file or directory (os error 2) ` it was for Permission denied too . --------- Co-authored-by: Stefan Holderbach <sholderbach@users.noreply.github.com>
This commit is contained in:
parent
4db960c0a6
commit
c130ca1bc6
@ -351,17 +351,38 @@ fn copy_file(src: PathBuf, dst: PathBuf, span: Span) -> Value {
|
|||||||
Value::String { val: msg, span }
|
Value::String { val: msg, span }
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
let message = format!("copy file {src:?} failed: {e}");
|
let message_src = format!(
|
||||||
|
"copying file '{src_display}' failed: {e}",
|
||||||
|
src_display = src.display()
|
||||||
|
);
|
||||||
|
let message_dst = format!(
|
||||||
|
"copying to destination '{dst_display}' failed: {e}",
|
||||||
|
dst_display = dst.display()
|
||||||
|
);
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
let shell_error = match e.kind() {
|
let shell_error = match e.kind() {
|
||||||
ErrorKind::NotFound => ShellError::FileNotFoundCustom(message, span),
|
ErrorKind::NotFound => {
|
||||||
ErrorKind::PermissionDenied => ShellError::PermissionDeniedError(message, span),
|
if std::path::Path::new(&dst).exists() {
|
||||||
ErrorKind::Interrupted => ShellError::IOInterrupted(message, span),
|
ShellError::FileNotFoundCustom(message_src, span)
|
||||||
ErrorKind::OutOfMemory => ShellError::OutOfMemoryError(message, span),
|
} else {
|
||||||
|
ShellError::FileNotFoundCustom(message_dst, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ErrorKind::PermissionDenied => match std::fs::metadata(&dst) {
|
||||||
|
Ok(meta) => {
|
||||||
|
if meta.permissions().readonly() {
|
||||||
|
ShellError::PermissionDeniedError(message_dst, span)
|
||||||
|
} else {
|
||||||
|
ShellError::PermissionDeniedError(message_src, span)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => ShellError::PermissionDeniedError(message_dst, span),
|
||||||
|
},
|
||||||
|
ErrorKind::Interrupted => ShellError::IOInterrupted(message_src, span),
|
||||||
|
ErrorKind::OutOfMemory => ShellError::OutOfMemoryError(message_src, span),
|
||||||
// TODO: handle ExecutableFileBusy etc. when io_error_more is stabilized
|
// TODO: handle ExecutableFileBusy etc. when io_error_more is stabilized
|
||||||
// https://github.com/rust-lang/rust/issues/86442
|
// https://github.com/rust-lang/rust/issues/86442
|
||||||
_ => ShellError::IOErrorSpanned(message, span),
|
_ => ShellError::IOErrorSpanned(message_src, span),
|
||||||
};
|
};
|
||||||
|
|
||||||
Value::Error { error: shell_error }
|
Value::Error { error: shell_error }
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
use nu_test_support::fs::file_contents;
|
use nu_test_support::fs::file_contents;
|
||||||
use nu_test_support::fs::{files_exist_at, AbsoluteFile, Stub::EmptyFile};
|
use nu_test_support::fs::{
|
||||||
|
files_exist_at, AbsoluteFile,
|
||||||
|
Stub::{EmptyFile, FileWithPermission},
|
||||||
|
};
|
||||||
use nu_test_support::nu;
|
use nu_test_support::nu;
|
||||||
use nu_test_support::playground::Playground;
|
use nu_test_support::playground::Playground;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@ -344,3 +347,37 @@ fn copy_ignores_ansi() {
|
|||||||
assert_eq!(actual.out, "success.txt");
|
assert_eq!(actual.out, "success.txt");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_file_not_exists_dst() {
|
||||||
|
Playground::setup("cp_test_17", |_dirs, sandbox| {
|
||||||
|
sandbox.with_files(vec![EmptyFile("valid.txt")]);
|
||||||
|
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: sandbox.cwd(),
|
||||||
|
"cp valid.txt ~/invalid_dir/invalid_dir1"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
actual.err.contains("invalid_dir1") && actual.err.contains("copying to destination")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn copy_file_with_read_permission() {
|
||||||
|
Playground::setup("cp_test_18", |_dirs, sandbox| {
|
||||||
|
sandbox.with_files(vec![
|
||||||
|
EmptyFile("valid.txt"),
|
||||||
|
FileWithPermission("invalid_prem.txt", false),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: sandbox.cwd(),
|
||||||
|
"cp valid.txt invalid_prem.txt",
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
actual.err.contains("invalid_prem.txt")
|
||||||
|
&& actual.err.contains("copying to destination")
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -137,6 +137,7 @@ pub enum Stub<'a> {
|
|||||||
FileWithContent(&'a str, &'a str),
|
FileWithContent(&'a str, &'a str),
|
||||||
FileWithContentToBeTrimmed(&'a str, &'a str),
|
FileWithContentToBeTrimmed(&'a str, &'a str),
|
||||||
EmptyFile(&'a str),
|
EmptyFile(&'a str),
|
||||||
|
FileWithPermission(&'a str, bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_contents(full_path: impl AsRef<Path>) -> String {
|
pub fn file_contents(full_path: impl AsRef<Path>) -> String {
|
||||||
|
@ -202,7 +202,8 @@ impl<'a> Playground<'a> {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let mut path = PathBuf::from(&self.cwd);
|
let mut path = PathBuf::from(&self.cwd);
|
||||||
|
let mut permission_set = false;
|
||||||
|
let mut write_able = true;
|
||||||
let (file_name, contents) = match *f {
|
let (file_name, contents) = match *f {
|
||||||
Stub::EmptyFile(name) => (name, "fake data".to_string()),
|
Stub::EmptyFile(name) => (name, "fake data".to_string()),
|
||||||
Stub::FileWithContent(name, content) => (name, content.to_string()),
|
Stub::FileWithContent(name, content) => (name, content.to_string()),
|
||||||
@ -215,11 +216,24 @@ impl<'a> Playground<'a> {
|
|||||||
.collect::<Vec<&str>>()
|
.collect::<Vec<&str>>()
|
||||||
.join(&endl),
|
.join(&endl),
|
||||||
),
|
),
|
||||||
|
Stub::FileWithPermission(name, is_write_able) => {
|
||||||
|
permission_set = true;
|
||||||
|
write_able = is_write_able;
|
||||||
|
(name, "check permission".to_string())
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
path.push(file_name);
|
path.push(file_name);
|
||||||
|
|
||||||
std::fs::write(path, contents.as_bytes()).expect("can not create file");
|
std::fs::write(&path, contents.as_bytes()).expect("can not create file");
|
||||||
|
if permission_set {
|
||||||
|
let err_perm = "can not set permission";
|
||||||
|
let mut perm = std::fs::metadata(path.clone())
|
||||||
|
.expect(err_perm)
|
||||||
|
.permissions();
|
||||||
|
perm.set_readonly(!write_able);
|
||||||
|
std::fs::set_permissions(path, perm).expect(err_perm);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.for_each(drop);
|
.for_each(drop);
|
||||||
self.back_to_playground();
|
self.back_to_playground();
|
||||||
|
Loading…
Reference in New Issue
Block a user