From 74d4c501a8a79de85915d6add55dfd86f012e6e5 Mon Sep 17 00:00:00 2001 From: xiuxiu62 Date: Tue, 5 Oct 2021 14:08:39 -0700 Subject: [PATCH] add move, recursive fill, and recursive create procedures --- crates/nu-command/src/filesystem/cp.rs | 167 +++++++++++++---------- crates/nu-command/src/filesystem/util.rs | 5 +- crates/nu-protocol/src/shell_error.rs | 14 ++ 3 files changed, 109 insertions(+), 77 deletions(-) diff --git a/crates/nu-command/src/filesystem/cp.rs b/crates/nu-command/src/filesystem/cp.rs index 6c6850c9ee..d2a4fbb81b 100644 --- a/crates/nu-command/src/filesystem/cp.rs +++ b/crates/nu-command/src/filesystem/cp.rs @@ -44,7 +44,7 @@ impl Command for Cp { let source = path.join(source.as_str()); let destination = path.join(destination.as_str()); - let mut sources = + let sources = glob::glob(&source.to_string_lossy()).map_or_else(|_| Vec::new(), Iterator::collect); if sources.is_empty() { return Err(ShellError::FileNotFound(call.positional[0].span)); @@ -60,10 +60,7 @@ impl Command for Cp { } let any_source_is_dir = sources.iter().any(|f| matches!(f, Ok(f) if f.is_dir())); - let recursive = call - .named - .iter() - .fold(false, |acc, p| acc || { &p.0 == "recursive" }); + let recursive = call.named.iter().any(|p| &p.0 == "recursive"); if any_source_is_dir && !recursive { return Err(ShellError::MoveNotPossibleSingle( "Directories must be copied using \"--recursive\"".to_string(), @@ -71,84 +68,106 @@ impl Command for Cp { )); } - // for entry in sources.into_iter().flatten() { - // let mut sources = FileStructure::new(); - // sources.walk_decorate(&entry)?; + for entry in sources.into_iter().flatten() { + let mut sources = FileStructure::new(); + sources.walk_decorate(&entry)?; - // if entry.is_file() { - // let sources = sources.paths_applying_with(|(source_file, _depth_level)| { - // if destination.is_dir() { - // let mut dest = canonicalize_with(&destination.item, &path)?; - // if let Some(name) = entry.file_name() { - // dest.push(name); - // } - // Ok((source_file, dest)) - // } else { - // Ok((source_file, destination.clone())) - // } - // })?; + if entry.is_file() { + let sources = sources.paths_applying_with(|(source_file, _depth_level)| { + if destination.is_dir() { + let mut dest = canonicalize_with(&destination, &path)?; + if let Some(name) = entry.file_name() { + dest.push(name); + } + Ok((source_file, dest)) + } else { + Ok((source_file, destination.clone())) + } + })?; - // for (src, dst) in sources { - // if src.is_file() { - // std::fs::copy(src, dst).map_err(|e| { - // ShellError::labeled_error(e.to_string(), e.to_string(), &name_tag) - // })?; - // } - // } - // } else if entry.is_dir() { - // let destination = if !destination.exists() { - // destination.clone() - // } else { - // match entry.file_name() { - // Some(name) => destination.join(name), - // None => { - // return Err(ShellError::labeled_error( - // "Copy aborted. Not a valid path", - // "not a valid path", - // dst.tag, - // )) - // } - // } - // }; + for (src, dst) in sources { + if src.is_file() { + std::fs::copy(&src, dst).map_err(|e| { + ShellError::MoveNotPossibleSingle( + format!( + "failed to move containing file \"{}\": {}", + src.to_string_lossy(), + e + ), + call.positional[0].span, + ) + })?; + } + } + } else if entry.is_dir() { + let destination = if !destination.exists() { + destination.clone() + } else { + match entry.file_name() { + Some(name) => destination.join(name), + None => { + return Err(ShellError::FileNotFoundCustom( + format!("containing \"{:?}\" is not a valid path", entry), + call.positional[0].span, + )) + } + } + }; - // std::fs::create_dir_all(&destination).map_err(|e| { - // ShellError::labeled_error(e.to_string(), e.to_string(), &dst.tag) - // })?; + std::fs::create_dir_all(&destination).map_err(|e| { + ShellError::MoveNotPossibleSingle( + format!("failed to recursively fill destination: {}", e), + call.positional[1].span, + ) + })?; - // let sources = sources.paths_applying_with(|(source_file, depth_level)| { - // let mut dest = destination.clone(); - // let path = canonicalize_with(&source_file, &path)?; + let sources = sources.paths_applying_with(|(source_file, depth_level)| { + let mut dest = destination.clone(); + let path = canonicalize_with(&source_file, &path)?; - // let comps: Vec<_> = path - // .components() - // .map(|fragment| fragment.as_os_str()) - // .rev() - // .take(1 + depth_level) - // .collect(); + let comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + depth_level) + .collect(); - // for fragment in comps.into_iter().rev() { - // dest.push(fragment); - // } + for fragment in comps.into_iter().rev() { + dest.push(fragment); + } - // Ok((PathBuf::from(&source_file), dest)) - // })?; + Ok((PathBuf::from(&source_file), dest)) + })?; - // let dst_tag = &dst.tag; - // for (src, dst) in sources { - // if src.is_dir() && !dst.exists() { - // std::fs::create_dir_all(&dst).map_err(|e| { - // ShellError::labeled_error(e.to_string(), e.to_string(), dst_tag) - // })?; - // } + for (src, dst) in sources { + if src.is_dir() && !dst.exists() { + std::fs::create_dir_all(&dst).map_err(|e| { + ShellError::MoveNotPossibleSingle( + format!( + "failed to create containing directory \"{}\": {}", + dst.to_string_lossy(), + e + ), + call.positional[1].span, + ) + })?; + } - // if src.is_file() { - // std::fs::copy(&src, &dst).map_err(|e| { - // ShellError::labeled_error(e.to_string(), e.to_string(), &name_tag) - // })?; - // } - // } - // } - // } + if src.is_file() { + std::fs::copy(&src, &dst).map_err(|e| { + ShellError::MoveNotPossibleSingle( + format!( + "failed to move containing file \"{}\": {}", + src.to_string_lossy(), + e + ), + call.positional[0].span, + ) + })?; + } + } + } + } Ok(Value::Nothing { span: call.head }) } diff --git a/crates/nu-command/src/filesystem/util.rs b/crates/nu-command/src/filesystem/util.rs index 86a0bd4c96..a2d217cf05 100644 --- a/crates/nu-command/src/filesystem/util.rs +++ b/crates/nu-command/src/filesystem/util.rs @@ -8,17 +8,16 @@ pub struct FileStructure { pub resources: Vec, } +#[allow(dead_code)] impl FileStructure { pub fn new() -> FileStructure { FileStructure { resources: vec![] } } - #[allow(dead_code)] pub fn contains_more_than_one_file(&self) -> bool { self.resources.len() > 1 } - #[allow(dead_code)] pub fn contains_files(&self) -> bool { !self.resources.is_empty() } @@ -33,7 +32,7 @@ impl FileStructure { self.resources .iter() .map(|f| (PathBuf::from(&f.location), f.at)) - .map(|f| to(f)) + .map(to) .collect() } diff --git a/crates/nu-protocol/src/shell_error.rs b/crates/nu-protocol/src/shell_error.rs index 73f5147fa8..6a7464508e 100644 --- a/crates/nu-protocol/src/shell_error.rs +++ b/crates/nu-protocol/src/shell_error.rs @@ -83,10 +83,18 @@ pub enum ShellError { #[diagnostic(code(nu::shell::file_not_found), url(docsrs))] FileNotFound(#[label("file not found")] Span), + #[error("File not found")] + #[diagnostic(code(nu::shell::file_not_found), url(docsrs))] + FileNotFoundCustom(String, #[label("{0}")] Span), + #[error("Directory not found")] #[diagnostic(code(nu::shell::directory_not_found), url(docsrs))] DirectoryNotFound(#[label("directory not found")] Span), + #[error("File not found")] + #[diagnostic(code(nu::shell::file_not_found), url(docsrs))] + DirectoryNotFoundCustom(String, #[label("{0}")] Span), + #[error("Move not possible")] #[diagnostic(code(nu::shell::move_not_possible), url(docsrs))] MoveNotPossible { @@ -109,6 +117,12 @@ impl From for ShellError { } } +impl std::convert::From> for ShellError { + fn from(input: Box) -> ShellError { + ShellError::InternalError(input.to_string()) + } +} + impl From> for ShellError { fn from(input: Box) -> ShellError { ShellError::InternalError(format!("{:?}", input))