From e012e04da04122548e4691f8c4dcb42cd60e9bf2 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 22 Aug 2019 05:03:59 +1200 Subject: [PATCH 1/5] Disallow fileops on values --- src/commands/cp.rs | 283 +------------ src/commands/mkdir.rs | 44 +- src/commands/mv.rs | 310 +------------- src/commands/rm.rs | 104 +---- src/shell/filesystem_shell.rs | 733 +++++++++++++++++++++++++++++++++- src/shell/shell.rs | 27 +- src/shell/shell_manager.rs | 45 ++- src/shell/value_shell.rs | 54 ++- 8 files changed, 879 insertions(+), 721 deletions(-) diff --git a/src/commands/cp.rs b/src/commands/cp.rs index 5e1ac6d26..29e14357a 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -3,16 +3,15 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxType; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; -use crate::utils::FileStructure; use std::path::PathBuf; pub struct Cpy; #[derive(Deserialize)] pub struct CopyArgs { - src: Tagged, - dst: Tagged, - recursive: Tagged, + pub src: Tagged, + pub dst: Tagged, + pub recursive: Tagged, } impl PerItemCommand for Cpy { @@ -40,277 +39,9 @@ impl PerItemCommand for Cpy { } fn cp( - CopyArgs { - src, - dst, - recursive, - }: CopyArgs, - RunnablePerItemContext { name, .. }: &RunnablePerItemContext, + args: CopyArgs, + context: &RunnablePerItemContext, ) -> Result, ShellError> { - let source = src.item.clone(); - let mut destination = dst.item.clone(); - let name_span = name; - - let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) { - Ok(files) => files.collect(), - Err(_) => { - return Err(ShellError::labeled_error( - "Invalid pattern.", - "Invalid pattern.", - src.tag, - )) - } - }; - - if sources.len() == 1 { - if let Ok(entry) = &sources[0] { - if entry.is_dir() && !recursive.item { - return Err(ShellError::labeled_error( - "is a directory (not copied). Try using \"--recursive\".", - "is a directory (not copied). Try using \"--recursive\".", - src.tag, - )); - } - - let mut sources: FileStructure = FileStructure::new(); - - sources.walk_decorate(&entry)?; - - if entry.is_file() { - let strategy = |(source_file, _depth_level)| { - if destination.exists() { - let mut new_dst = dunce::canonicalize(destination.clone())?; - if let Some(name) = entry.file_name() { - new_dst.push(name); - } - Ok((source_file, new_dst)) - } else { - Ok((source_file, destination.clone())) - } - }; - - let sources = sources.paths_applying_with(strategy)?; - - for (ref src, ref dst) in sources { - if src.is_file() { - match std::fs::copy(src, dst) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - } - } - } - - if entry.is_dir() { - if !destination.exists() { - match std::fs::create_dir_all(&destination) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - - let strategy = |(source_file, depth_level)| { - let mut new_dst = destination.clone(); - let path = dunce::canonicalize(&source_file)?; - - let mut comps: Vec<_> = path - .components() - .map(|fragment| fragment.as_os_str()) - .rev() - .take(1 + depth_level) - .collect(); - - comps.reverse(); - - for fragment in comps.iter() { - new_dst.push(fragment); - } - - Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) - }; - - let sources = sources.paths_applying_with(strategy)?; - - for (ref src, ref dst) in sources { - if src.is_dir() { - if !dst.exists() { - match std::fs::create_dir_all(dst) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - } - } - - if src.is_file() { - match std::fs::copy(src, dst) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - } - } - } else { - match entry.file_name() { - Some(name) => destination.push(name), - None => { - return Err(ShellError::labeled_error( - "Copy aborted. Not a valid path", - "Copy aborted. Not a valid path", - name_span, - )) - } - } - - match std::fs::create_dir_all(&destination) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - - let strategy = |(source_file, depth_level)| { - let mut new_dst = dunce::canonicalize(&destination)?; - let path = dunce::canonicalize(&source_file)?; - - let mut comps: Vec<_> = path - .components() - .map(|fragment| fragment.as_os_str()) - .rev() - .take(1 + depth_level) - .collect(); - - comps.reverse(); - - for fragment in comps.iter() { - new_dst.push(fragment); - } - - Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) - }; - - let sources = sources.paths_applying_with(strategy)?; - - for (ref src, ref dst) in sources { - if src.is_dir() { - if !dst.exists() { - match std::fs::create_dir_all(dst) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - } - } - - if src.is_file() { - match std::fs::copy(src, dst) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - name_span, - )); - } - Ok(o) => o, - }; - } - } - } - } - } - } else { - if destination.exists() { - if !sources.iter().all(|x| match x { - Ok(f) => f.is_file(), - Err(_) => false, - }) { - return Err(ShellError::labeled_error( - "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", - "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", - src.tag, - )); - } - - for entry in sources { - if let Ok(entry) = entry { - let mut to = PathBuf::from(&destination); - - match entry.file_name() { - Some(name) => to.push(name), - None => { - return Err(ShellError::labeled_error( - "Copy aborted. Not a valid path", - "Copy aborted. Not a valid path", - name_span, - )) - } - } - - if entry.is_file() { - match std::fs::copy(&entry, &to) { - Err(e) => { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - src.tag, - )); - } - Ok(o) => o, - }; - } - } - } - } else { - let destination_file_name = { - match destination.file_name() { - Some(name) => PathBuf::from(name), - None => { - return Err(ShellError::labeled_error( - "Copy aborted. Not a valid destination", - "Copy aborted. Not a valid destination", - name_span, - )) - } - } - }; - - return Err(ShellError::labeled_error( - format!("Copy aborted. (Does {:?} exist?)", destination_file_name), - format!("Copy aborted. (Does {:?} exist?)", destination_file_name), - &dst.span(), - )); - } - } - - Ok(VecDeque::new()) + let shell_manager = context.shell_manager.clone(); + shell_manager.cp(args, context) } diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 0e8cfd6f8..56fec8777 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -7,8 +7,8 @@ use std::path::PathBuf; pub struct Mkdir; #[derive(Deserialize)] -struct MkdirArgs { - rest: Vec>, +pub struct MkdirArgs { + pub rest: Vec>, } impl PerItemCommand for Mkdir { @@ -32,41 +32,9 @@ impl PerItemCommand for Mkdir { } fn mkdir( - MkdirArgs { rest: directories }: MkdirArgs, - RunnablePerItemContext { - name, - shell_manager, - .. - }: &RunnablePerItemContext, + args: MkdirArgs, + context: &RunnablePerItemContext, ) -> Result, ShellError> { - let full_path = PathBuf::from(shell_manager.path()); - - if directories.len() == 0 { - return Err(ShellError::labeled_error( - "mkdir requires directory paths", - "needs parameter", - name, - )); - } - - for dir in directories.iter() { - let create_at = { - let mut loc = full_path.clone(); - loc.push(&dir.item); - loc - }; - - match std::fs::create_dir_all(create_at) { - Err(reason) => { - return Err(ShellError::labeled_error( - reason.to_string(), - reason.to_string(), - dir.span(), - )) - } - Ok(_) => {} - } - } - - Ok(VecDeque::new()) + let shell_manager = context.shell_manager.clone(); + shell_manager.mkdir(args, context) } diff --git a/src/commands/mv.rs b/src/commands/mv.rs index fc00248b4..65616079c 100644 --- a/src/commands/mv.rs +++ b/src/commands/mv.rs @@ -9,8 +9,8 @@ pub struct Move; #[derive(Deserialize)] pub struct MoveArgs { - src: Tagged, - dst: Tagged, + pub src: Tagged, + pub dst: Tagged, } impl PerItemCommand for Move { @@ -37,307 +37,9 @@ impl PerItemCommand for Move { } fn mv( - MoveArgs { src, dst }: MoveArgs, - RunnablePerItemContext { - name, - shell_manager, - }: &RunnablePerItemContext, + args: MoveArgs, + context: &RunnablePerItemContext, ) -> Result, ShellError> { - let source = src.item.clone(); - let mut destination = dst.item.clone(); - let name_span = name; - - let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) { - Ok(files) => files.collect(), - Err(_) => { - return Err(ShellError::labeled_error( - "Invalid pattern.", - "Invalid pattern.", - src.tag, - )) - } - }; - - if "." == destination.to_string_lossy() { - destination = PathBuf::from(shell_manager.path()); - } - - let destination_file_name = { - match destination.file_name() { - Some(name) => PathBuf::from(name), - None => { - return Err(ShellError::labeled_error( - "Rename aborted. Not a valid destination", - "Rename aborted. Not a valid destination", - dst.span(), - )) - } - } - }; - - if sources.len() == 1 { - if let Ok(entry) = &sources[0] { - let entry_file_name = match entry.file_name() { - Some(name) => name, - None => { - return Err(ShellError::labeled_error( - "Rename aborted. Not a valid entry name", - "Rename aborted. Not a valid entry name", - name_span, - )) - } - }; - - if destination.exists() && destination.is_dir() { - destination = match dunce::canonicalize(&destination) { - Ok(path) => path, - Err(e) => { - return Err(ShellError::labeled_error( - format!("Rename aborted. {:}", e.to_string()), - format!("Rename aborted. {:}", e.to_string()), - name_span, - )) - } - }; - - destination.push(entry_file_name); - } - - if entry.is_file() { - match std::fs::rename(&entry, &destination) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - }; - } - - if entry.is_dir() { - match std::fs::create_dir_all(&destination) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - }; - #[cfg(not(windows))] - { - match std::fs::rename(&entry, &destination) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - }; - } - #[cfg(windows)] - { - use crate::utils::FileStructure; - - let mut sources: FileStructure = FileStructure::new(); - - sources.walk_decorate(&entry)?; - - let strategy = |(source_file, depth_level)| { - let mut new_dst = destination.clone(); - - let path = dunce::canonicalize(&source_file)?; - - let mut comps: Vec<_> = path - .components() - .map(|fragment| fragment.as_os_str()) - .rev() - .take(1 + depth_level) - .collect(); - - comps.reverse(); - - for fragment in comps.iter() { - new_dst.push(fragment); - } - - Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) - }; - - let sources = sources.paths_applying_with(strategy)?; - - for (ref src, ref dst) in sources { - if src.is_dir() { - if !dst.exists() { - match std::fs::create_dir_all(dst) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - } - } - } - - if src.is_file() { - match std::fs::rename(src, dst) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - } - } - } - - match std::fs::remove_dir_all(entry) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - }; - } - } - } - } else { - if destination.exists() { - if !sources.iter().all(|x| { - if let Ok(entry) = x.as_ref() { - entry.is_file() - } else { - false - } - }) { - return Err(ShellError::labeled_error( - "Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)", - "Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)", - src.tag, - )); - } - - for entry in sources { - if let Ok(entry) = entry { - let entry_file_name = match entry.file_name() { - Some(name) => name, - None => { - return Err(ShellError::labeled_error( - "Rename aborted. Not a valid entry name", - "Rename aborted. Not a valid entry name", - name_span, - )) - } - }; - - let mut to = PathBuf::from(&destination); - to.push(entry_file_name); - - if entry.is_file() { - match std::fs::rename(&entry, &to) { - Err(e) => { - return Err(ShellError::labeled_error( - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - format!( - "Rename {:?} to {:?} aborted. {:}", - entry_file_name, - destination_file_name, - e.to_string(), - ), - name_span, - )); - } - Ok(o) => o, - }; - } - } - } - } else { - return Err(ShellError::labeled_error( - format!("Rename aborted. (Does {:?} exist?)", destination_file_name), - format!("Rename aborted. (Does {:?} exist?)", destination_file_name), - dst.span(), - )); - } - } - - Ok(VecDeque::new()) + let shell_manager = context.shell_manager.clone(); + shell_manager.mv(args, context) } diff --git a/src/commands/rm.rs b/src/commands/rm.rs index 9493bd94d..05c248897 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -3,15 +3,14 @@ use crate::errors::ShellError; use crate::parser::hir::SyntaxType; use crate::parser::registry::{CommandRegistry, Signature}; use crate::prelude::*; -use crate::utils::FileStructure; use std::path::PathBuf; pub struct Remove; #[derive(Deserialize)] pub struct RemoveArgs { - target: Tagged, - recursive: Tagged, + pub target: Tagged, + pub recursive: Tagged, } impl PerItemCommand for Remove { @@ -37,100 +36,9 @@ impl PerItemCommand for Remove { } fn rm( - RemoveArgs { target, recursive }: RemoveArgs, - RunnablePerItemContext { name, .. }: &RunnablePerItemContext, + args: RemoveArgs, + context: &RunnablePerItemContext, ) -> Result, ShellError> { - let path = target.item.clone(); - let name_span = name; - - let file = path.to_string_lossy(); - - if file == "." || file == ".." { - return Err(ShellError::labeled_error( - "Remove aborted. \".\" or \"..\" may not be removed.", - "Remove aborted. \".\" or \"..\" may not be removed.", - target.span(), - )); - } - - let entries: Vec<_> = match glob::glob(&path.to_string_lossy()) { - Ok(files) => files.collect(), - Err(_) => { - return Err(ShellError::labeled_error( - "Invalid pattern.", - "Invalid pattern.", - target.tag, - )) - } - }; - - if entries.len() == 1 { - if let Ok(entry) = &entries[0] { - if entry.is_dir() { - let mut source_dir: FileStructure = FileStructure::new(); - - source_dir.walk_decorate(&entry)?; - - if source_dir.contains_files() && !recursive.item { - return Err(ShellError::labeled_error( - format!("{:?} is a directory. Try using \"--recursive\".", file), - format!("{:?} is a directory. Try using \"--recursive\".", file), - target.span(), - )); - } - } - } - } - - for entry in entries { - match entry { - Ok(path) => { - let path_file_name = { - match path.file_name() { - Some(name) => PathBuf::from(name), - None => { - return Err(ShellError::labeled_error( - "Remove aborted. Not a valid path", - "Remove aborted. Not a valid path", - name_span, - )) - } - } - }; - - let mut source_dir: FileStructure = FileStructure::new(); - - source_dir.walk_decorate(&path)?; - - if source_dir.contains_more_than_one_file() && !recursive.item { - return Err(ShellError::labeled_error( - format!( - "Directory {:?} found somewhere inside. Try using \"--recursive\".", - path_file_name - ), - format!( - "Directory {:?} found somewhere inside. Try using \"--recursive\".", - path_file_name - ), - target.span(), - )); - } - - if path.is_dir() { - std::fs::remove_dir_all(&path)?; - } else if path.is_file() { - std::fs::remove_file(&path)?; - } - } - Err(e) => { - return Err(ShellError::labeled_error( - format!("Remove aborted. {:}", e.to_string()), - format!("Remove aborted. {:}", e.to_string()), - name_span, - )) - } - } - } - - Ok(VecDeque::new()) + let shell_manager = context.shell_manager.clone(); + shell_manager.rm(args, context) } diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 949c972c5..cc9221020 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -1,13 +1,17 @@ -use crate::commands::command::EvaluatedWholeStreamCommandArgs; +use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::cp::CopyArgs; +use crate::commands::mkdir::MkdirArgs; +use crate::commands::mv::MoveArgs; +use crate::commands::rm::RemoveArgs; use crate::context::SourceMap; use crate::object::dir_entry_dict; use crate::prelude::*; use crate::shell::completer::NuCompleter; use crate::shell::shell::Shell; +use crate::utils::FileStructure; use rustyline::completion::FilenameCompleter; use rustyline::hint::{Hinter, HistoryHinter}; use std::path::{Path, PathBuf}; - pub struct FilesystemShell { crate path: String, completer: NuCompleter, @@ -189,6 +193,731 @@ impl Shell for FilesystemShell { Ok(stream.into()) } + fn cp( + &self, + CopyArgs { + src, + dst, + recursive, + }: CopyArgs, + RunnablePerItemContext { name, .. }: &RunnablePerItemContext, + ) -> Result, ShellError> { + let source = src.item.clone(); + let mut destination = dst.item.clone(); + let name_span = name; + + let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) { + Ok(files) => files.collect(), + Err(_) => { + return Err(ShellError::labeled_error( + "Invalid pattern.", + "Invalid pattern.", + src.tag, + )) + } + }; + + if sources.len() == 1 { + if let Ok(entry) = &sources[0] { + if entry.is_dir() && !recursive.item { + return Err(ShellError::labeled_error( + "is a directory (not copied). Try using \"--recursive\".", + "is a directory (not copied). Try using \"--recursive\".", + src.tag, + )); + } + + let mut sources: FileStructure = FileStructure::new(); + + sources.walk_decorate(&entry)?; + + if entry.is_file() { + let strategy = |(source_file, _depth_level)| { + if destination.exists() { + let mut new_dst = dunce::canonicalize(destination.clone())?; + if let Some(name) = entry.file_name() { + new_dst.push(name); + } + Ok((source_file, new_dst)) + } else { + Ok((source_file, destination.clone())) + } + }; + + let sources = sources.paths_applying_with(strategy)?; + + for (ref src, ref dst) in sources { + if src.is_file() { + match std::fs::copy(src, dst) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } + + if entry.is_dir() { + if !destination.exists() { + match std::fs::create_dir_all(&destination) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + + let strategy = |(source_file, depth_level)| { + let mut new_dst = destination.clone(); + let path = dunce::canonicalize(&source_file)?; + + let mut comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + depth_level) + .collect(); + + comps.reverse(); + + for fragment in comps.iter() { + new_dst.push(fragment); + } + + Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) + }; + + let sources = sources.paths_applying_with(strategy)?; + + for (ref src, ref dst) in sources { + if src.is_dir() { + if !dst.exists() { + match std::fs::create_dir_all(dst) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + + if src.is_file() { + match std::fs::copy(src, dst) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } else { + match entry.file_name() { + Some(name) => destination.push(name), + None => { + return Err(ShellError::labeled_error( + "Copy aborted. Not a valid path", + "Copy aborted. Not a valid path", + name_span, + )) + } + } + + match std::fs::create_dir_all(&destination) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + + let strategy = |(source_file, depth_level)| { + let mut new_dst = dunce::canonicalize(&destination)?; + let path = dunce::canonicalize(&source_file)?; + + let mut comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + depth_level) + .collect(); + + comps.reverse(); + + for fragment in comps.iter() { + new_dst.push(fragment); + } + + Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) + }; + + let sources = sources.paths_applying_with(strategy)?; + + for (ref src, ref dst) in sources { + if src.is_dir() { + if !dst.exists() { + match std::fs::create_dir_all(dst) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + + if src.is_file() { + match std::fs::copy(src, dst) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } + } + } + } else { + if destination.exists() { + if !sources.iter().all(|x| match x { + Ok(f) => f.is_file(), + Err(_) => false, + }) { + return Err(ShellError::labeled_error( + "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", + "Copy aborted (directories found). Recursive copying in patterns not supported yet (try copying the directory directly)", + src.tag, + )); + } + + for entry in sources { + if let Ok(entry) = entry { + let mut to = PathBuf::from(&destination); + + match entry.file_name() { + Some(name) => to.push(name), + None => { + return Err(ShellError::labeled_error( + "Copy aborted. Not a valid path", + "Copy aborted. Not a valid path", + name_span, + )) + } + } + + if entry.is_file() { + match std::fs::copy(&entry, &to) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + src.tag, + )); + } + Ok(o) => o, + }; + } + } + } + } else { + let destination_file_name = { + match destination.file_name() { + Some(name) => PathBuf::from(name), + None => { + return Err(ShellError::labeled_error( + "Copy aborted. Not a valid destination", + "Copy aborted. Not a valid destination", + name_span, + )) + } + } + }; + + return Err(ShellError::labeled_error( + format!("Copy aborted. (Does {:?} exist?)", destination_file_name), + format!("Copy aborted. (Does {:?} exist?)", destination_file_name), + &dst.span(), + )); + } + } + + Ok(VecDeque::new()) + } + + fn mkdir( + &self, + MkdirArgs { rest: directories }: MkdirArgs, + RunnablePerItemContext { + name, + shell_manager, + .. + }: &RunnablePerItemContext, + ) -> Result, ShellError> { + let full_path = PathBuf::from(shell_manager.path()); + + if directories.len() == 0 { + return Err(ShellError::labeled_error( + "mkdir requires directory paths", + "needs parameter", + name, + )); + } + + for dir in directories.iter() { + let create_at = { + let mut loc = full_path.clone(); + loc.push(&dir.item); + loc + }; + + match std::fs::create_dir_all(create_at) { + Err(reason) => { + return Err(ShellError::labeled_error( + reason.to_string(), + reason.to_string(), + dir.span(), + )) + } + Ok(_) => {} + } + } + + Ok(VecDeque::new()) + } + + fn mv( + &self, + MoveArgs { src, dst }: MoveArgs, + RunnablePerItemContext { + name, + shell_manager, + }: &RunnablePerItemContext, + ) -> Result, ShellError> { + let source = src.item.clone(); + let mut destination = dst.item.clone(); + let name_span = name; + + let sources: Vec<_> = match glob::glob(&source.to_string_lossy()) { + Ok(files) => files.collect(), + Err(_) => { + return Err(ShellError::labeled_error( + "Invalid pattern.", + "Invalid pattern.", + src.tag, + )) + } + }; + + if "." == destination.to_string_lossy() { + destination = PathBuf::from(shell_manager.path()); + } + + let destination_file_name = { + match destination.file_name() { + Some(name) => PathBuf::from(name), + None => { + return Err(ShellError::labeled_error( + "Rename aborted. Not a valid destination", + "Rename aborted. Not a valid destination", + dst.span(), + )) + } + } + }; + + if sources.len() == 1 { + if let Ok(entry) = &sources[0] { + let entry_file_name = match entry.file_name() { + Some(name) => name, + None => { + return Err(ShellError::labeled_error( + "Rename aborted. Not a valid entry name", + "Rename aborted. Not a valid entry name", + name_span, + )) + } + }; + + if destination.exists() && destination.is_dir() { + destination = match dunce::canonicalize(&destination) { + Ok(path) => path, + Err(e) => { + return Err(ShellError::labeled_error( + format!("Rename aborted. {:}", e.to_string()), + format!("Rename aborted. {:}", e.to_string()), + name_span, + )) + } + }; + + destination.push(entry_file_name); + } + + if entry.is_file() { + match std::fs::rename(&entry, &destination) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + }; + } + + if entry.is_dir() { + match std::fs::create_dir_all(&destination) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + }; + #[cfg(not(windows))] + { + match std::fs::rename(&entry, &destination) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + }; + } + #[cfg(windows)] + { + use crate::utils::FileStructure; + + let mut sources: FileStructure = FileStructure::new(); + + sources.walk_decorate(&entry)?; + + let strategy = |(source_file, depth_level)| { + let mut new_dst = destination.clone(); + + let path = dunce::canonicalize(&source_file)?; + + let mut comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + depth_level) + .collect(); + + comps.reverse(); + + for fragment in comps.iter() { + new_dst.push(fragment); + } + + Ok((PathBuf::from(&source_file), PathBuf::from(new_dst))) + }; + + let sources = sources.paths_applying_with(strategy)?; + + for (ref src, ref dst) in sources { + if src.is_dir() { + if !dst.exists() { + match std::fs::create_dir_all(dst) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + } + } + } + + if src.is_file() { + match std::fs::rename(src, dst) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + } + } + } + + match std::fs::remove_dir_all(entry) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } + } else { + if destination.exists() { + if !sources.iter().all(|x| { + if let Ok(entry) = x.as_ref() { + entry.is_file() + } else { + false + } + }) { + return Err(ShellError::labeled_error( + "Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)", + "Rename aborted (directories found). Renaming in patterns not supported yet (try moving the directory directly)", + src.tag, + )); + } + + for entry in sources { + if let Ok(entry) = entry { + let entry_file_name = match entry.file_name() { + Some(name) => name, + None => { + return Err(ShellError::labeled_error( + "Rename aborted. Not a valid entry name", + "Rename aborted. Not a valid entry name", + name_span, + )) + } + }; + + let mut to = PathBuf::from(&destination); + to.push(entry_file_name); + + if entry.is_file() { + match std::fs::rename(&entry, &to) { + Err(e) => { + return Err(ShellError::labeled_error( + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + format!( + "Rename {:?} to {:?} aborted. {:}", + entry_file_name, + destination_file_name, + e.to_string(), + ), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } + } else { + return Err(ShellError::labeled_error( + format!("Rename aborted. (Does {:?} exist?)", destination_file_name), + format!("Rename aborted. (Does {:?} exist?)", destination_file_name), + dst.span(), + )); + } + } + + Ok(VecDeque::new()) + } + + fn rm( + &self, + RemoveArgs { target, recursive }: RemoveArgs, + RunnablePerItemContext { name, .. }: &RunnablePerItemContext, + ) -> Result, ShellError> { + let path = target.item.clone(); + let name_span = name; + + let file = path.to_string_lossy(); + + if file == "." || file == ".." { + return Err(ShellError::labeled_error( + "Remove aborted. \".\" or \"..\" may not be removed.", + "Remove aborted. \".\" or \"..\" may not be removed.", + target.span(), + )); + } + + let entries: Vec<_> = match glob::glob(&path.to_string_lossy()) { + Ok(files) => files.collect(), + Err(_) => { + return Err(ShellError::labeled_error( + "Invalid pattern.", + "Invalid pattern.", + target.tag, + )) + } + }; + + if entries.len() == 1 { + if let Ok(entry) = &entries[0] { + if entry.is_dir() { + let mut source_dir: FileStructure = FileStructure::new(); + + source_dir.walk_decorate(&entry)?; + + if source_dir.contains_files() && !recursive.item { + return Err(ShellError::labeled_error( + format!("{:?} is a directory. Try using \"--recursive\".", file), + format!("{:?} is a directory. Try using \"--recursive\".", file), + target.span(), + )); + } + } + } + } + + for entry in entries { + match entry { + Ok(path) => { + let path_file_name = { + match path.file_name() { + Some(name) => PathBuf::from(name), + None => { + return Err(ShellError::labeled_error( + "Remove aborted. Not a valid path", + "Remove aborted. Not a valid path", + name_span, + )) + } + } + }; + + let mut source_dir: FileStructure = FileStructure::new(); + + source_dir.walk_decorate(&path)?; + + if source_dir.contains_more_than_one_file() && !recursive.item { + return Err(ShellError::labeled_error( + format!( + "Directory {:?} found somewhere inside. Try using \"--recursive\".", + path_file_name + ), + format!( + "Directory {:?} found somewhere inside. Try using \"--recursive\".", + path_file_name + ), + target.span(), + )); + } + + if path.is_dir() { + std::fs::remove_dir_all(&path)?; + } else if path.is_file() { + std::fs::remove_file(&path)?; + } + } + Err(e) => { + return Err(ShellError::labeled_error( + format!("Remove aborted. {:}", e.to_string()), + format!("Remove aborted. {:}", e.to_string()), + name_span, + )) + } + } + } + + Ok(VecDeque::new()) + } + fn path(&self) -> String { self.path.clone() } diff --git a/src/shell/shell.rs b/src/shell/shell.rs index 9701d4749..a641d84a5 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -1,12 +1,37 @@ -use crate::commands::command::EvaluatedWholeStreamCommandArgs; +use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::cp::CopyArgs; +use crate::commands::mkdir::MkdirArgs; +use crate::commands::mv::MoveArgs; +use crate::commands::rm::RemoveArgs; use crate::context::SourceMap; use crate::errors::ShellError; +use crate::prelude::*; use crate::stream::OutputStream; pub trait Shell: std::fmt::Debug { fn name(&self, source_map: &SourceMap) -> String; fn ls(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; fn cd(&self, args: EvaluatedWholeStreamCommandArgs) -> Result; + fn cp( + &self, + args: CopyArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError>; + fn mkdir( + &self, + args: MkdirArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError>; + fn mv( + &self, + args: MoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError>; + fn rm( + &self, + args: RemoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError>; fn path(&self) -> String; fn set_path(&mut self, path: String); diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index d8f63ceb0..4b822dde9 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -1,4 +1,8 @@ -use crate::commands::command::EvaluatedWholeStreamCommandArgs; +use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::cp::CopyArgs; +use crate::commands::mkdir::MkdirArgs; +use crate::commands::mv::MoveArgs; +use crate::commands::rm::RemoveArgs; use crate::errors::ShellError; use crate::prelude::*; use crate::shell::filesystem_shell::FilesystemShell; @@ -108,4 +112,43 @@ impl ShellManager { env[self.current_shell].cd(args) } + pub fn cp( + &self, + args: CopyArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + let env = self.shells.lock().unwrap(); + + env[self.current_shell].cp(args, context) + } + + pub fn rm( + &self, + args: RemoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + let env = self.shells.lock().unwrap(); + + env[self.current_shell].rm(args, context) + } + + pub fn mkdir( + &self, + args: MkdirArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + let env = self.shells.lock().unwrap(); + + env[self.current_shell].mkdir(args, context) + } + + pub fn mv( + &self, + args: MoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + let env = self.shells.lock().unwrap(); + + env[self.current_shell].mv(args, context) + } } diff --git a/src/shell/value_shell.rs b/src/shell/value_shell.rs index e0ec77c35..d6d80168a 100644 --- a/src/shell/value_shell.rs +++ b/src/shell/value_shell.rs @@ -1,4 +1,8 @@ -use crate::commands::command::EvaluatedWholeStreamCommandArgs; +use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::cp::CopyArgs; +use crate::commands::mkdir::MkdirArgs; +use crate::commands::mv::MoveArgs; +use crate::commands::rm::RemoveArgs; use crate::context::SourceMap; use crate::prelude::*; use crate::shell::shell::Shell; @@ -99,6 +103,54 @@ impl Shell for ValueShell { Ok(stream.into()) } + fn cp( + &self, + _args: CopyArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + Err(ShellError::labeled_error( + "cp not currently supported on values", + "not currently supported", + context.name, + )) + } + + fn mv( + &self, + _args: MoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + Err(ShellError::labeled_error( + "mv not currently supported on values", + "not currently supported", + context.name, + )) + } + + fn mkdir( + &self, + _args: MkdirArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + Err(ShellError::labeled_error( + "mkdir not currently supported on values", + "not currently supported", + context.name, + )) + } + + fn rm( + &self, + _args: RemoveArgs, + context: &RunnablePerItemContext, + ) -> Result, ShellError> { + Err(ShellError::labeled_error( + "rm not currently supported on values", + "not currently supported", + context.name, + )) + } + fn path(&self) -> String { self.path.clone() } From 78ca297e47abc71f492e9cd148429686466ea7d3 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 22 Aug 2019 07:38:09 +1200 Subject: [PATCH 2/5] WIP --- src/commands/mkdir.rs | 2 ++ src/shell/filesystem_shell.rs | 14 ++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 56fec8777..668b2111a 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -35,6 +35,8 @@ fn mkdir( args: MkdirArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { + println!("shell clone"); let shell_manager = context.shell_manager.clone(); + println!("mkdir"); shell_manager.mkdir(args, context) } diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index b3b05f682..732b07743 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -476,13 +476,14 @@ impl Shell for FilesystemShell { fn mkdir( &self, - MkdirArgs { rest: directories }: MkdirArgs, + mkdir_args: MkdirArgs, RunnablePerItemContext { name, shell_manager, .. }: &RunnablePerItemContext, ) -> Result, ShellError> { + println!("full path"); let full_path = PathBuf::from(shell_manager.path()); if directories.len() == 0 { @@ -493,13 +494,17 @@ impl Shell for FilesystemShell { )); } + println!("dirs"); for dir in directories.iter() { + println!("create at:"); let create_at = { let mut loc = full_path.clone(); loc.push(&dir.item); loc }; + println!("{:?}", create_at); + match std::fs::create_dir_all(create_at) { Err(reason) => { return Err(ShellError::labeled_error( @@ -508,10 +513,15 @@ impl Shell for FilesystemShell { dir.span(), )) } - Ok(_) => {} + Ok(_) => { + println!("OK"); + } } + println!("End loop"); } + println!("Done"); + Ok(VecDeque::new()) } From 303d27d4b6b5f0a27396c2dcb4ac62e25bacf122 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 22 Aug 2019 16:13:40 +1200 Subject: [PATCH 3/5] Finish adding support for protecting value shells --- src/commands/mkdir.rs | 2 -- src/shell/filesystem_shell.rs | 55 ++++++++++++++++------------------ src/shell/shell.rs | 14 +++++---- src/shell/shell_manager.rs | 56 ++++++++++++++++++++++++++++++----- src/shell/value_shell.rs | 22 ++++++++------ 5 files changed, 95 insertions(+), 54 deletions(-) diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 668b2111a..56fec8777 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -35,8 +35,6 @@ fn mkdir( args: MkdirArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { - println!("shell clone"); let shell_manager = context.shell_manager.clone(); - println!("mkdir"); shell_manager.mkdir(args, context) } diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 732b07743..e7038c40c 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -1,4 +1,4 @@ -use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::mv::MoveArgs; @@ -200,12 +200,13 @@ impl Shell for FilesystemShell { dst, recursive, }: CopyArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError> { - let name_span = context.name; + let name_span = name; - let mut source = PathBuf::from(context.shell_manager.path()); - let mut destination = PathBuf::from(context.shell_manager.path()); + let mut source = PathBuf::from(path); + let mut destination = PathBuf::from(path); source.push(&src.item); destination.push(&dst.item); @@ -476,15 +477,16 @@ impl Shell for FilesystemShell { fn mkdir( &self, - mkdir_args: MkdirArgs, - RunnablePerItemContext { - name, - shell_manager, - .. - }: &RunnablePerItemContext, + MkdirArgs { rest: directories }: MkdirArgs, + // RunnablePerItemContext { + // name, + // shell_manager, + // .. + // }: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError> { - println!("full path"); - let full_path = PathBuf::from(shell_manager.path()); + let full_path = PathBuf::from(path); if directories.len() == 0 { return Err(ShellError::labeled_error( @@ -494,17 +496,13 @@ impl Shell for FilesystemShell { )); } - println!("dirs"); for dir in directories.iter() { - println!("create at:"); let create_at = { let mut loc = full_path.clone(); loc.push(&dir.item); loc }; - println!("{:?}", create_at); - match std::fs::create_dir_all(create_at) { Err(reason) => { return Err(ShellError::labeled_error( @@ -513,27 +511,23 @@ impl Shell for FilesystemShell { dir.span(), )) } - Ok(_) => { - println!("OK"); - } + Ok(_) => {} } - println!("End loop"); } - println!("Done"); - Ok(VecDeque::new()) } fn mv( &self, MoveArgs { src, dst }: MoveArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError> { - let name_span = context.name; + let name_span = name; - let mut source = PathBuf::from(context.shell_manager.path()); - let mut destination = PathBuf::from(context.shell_manager.path()); + let mut source = PathBuf::from(path); + let mut destination = PathBuf::from(path); source.push(&src.item); destination.push(&dst.item); @@ -832,11 +826,12 @@ impl Shell for FilesystemShell { fn rm( &self, RemoveArgs { target, recursive }: RemoveArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError> { - let name_span = context.name; + let name_span = name; - let mut path = PathBuf::from(context.shell_manager.path()); + let mut path = PathBuf::from(path); path.push(&target.item); diff --git a/src/shell/shell.rs b/src/shell/shell.rs index a641d84a5..442bb351f 100644 --- a/src/shell/shell.rs +++ b/src/shell/shell.rs @@ -1,4 +1,4 @@ -use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::mv::MoveArgs; @@ -15,22 +15,26 @@ pub trait Shell: std::fmt::Debug { fn cp( &self, args: CopyArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError>; fn mkdir( &self, args: MkdirArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError>; fn mv( &self, args: MoveArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError>; fn rm( &self, args: RemoveArgs, - context: &RunnablePerItemContext, + name: Span, + path: &str, ) -> Result, ShellError>; fn path(&self) -> String; fn set_path(&mut self, path: String); diff --git a/src/shell/shell_manager.rs b/src/shell/shell_manager.rs index 4b822dde9..cc10351db 100644 --- a/src/shell/shell_manager.rs +++ b/src/shell/shell_manager.rs @@ -117,9 +117,19 @@ impl ShellManager { args: CopyArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { - let env = self.shells.lock().unwrap(); + let env = self.shells.lock(); - env[self.current_shell].cp(args, context) + match env { + Ok(x) => { + let path = x[self.current_shell].path(); + x[self.current_shell].cp(args, context.name, &path) + } + Err(e) => Err(ShellError::labeled_error( + format!("Internal error: could not lock {}", e), + "Internal error: could not lock", + context.name, + )), + } } pub fn rm( @@ -127,9 +137,19 @@ impl ShellManager { args: RemoveArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { - let env = self.shells.lock().unwrap(); + let env = self.shells.lock(); - env[self.current_shell].rm(args, context) + match env { + Ok(x) => { + let path = x[self.current_shell].path(); + x[self.current_shell].rm(args, context.name, &path) + } + Err(e) => Err(ShellError::labeled_error( + format!("Internal error: could not lock {}", e), + "Internal error: could not lock", + context.name, + )), + } } pub fn mkdir( @@ -137,9 +157,19 @@ impl ShellManager { args: MkdirArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { - let env = self.shells.lock().unwrap(); + let env = self.shells.lock(); - env[self.current_shell].mkdir(args, context) + match env { + Ok(x) => { + let path = x[self.current_shell].path(); + x[self.current_shell].mkdir(args, context.name, &path) + } + Err(e) => Err(ShellError::labeled_error( + format!("Internal error: could not lock {}", e), + "Internal error: could not lock", + context.name, + )), + } } pub fn mv( @@ -147,8 +177,18 @@ impl ShellManager { args: MoveArgs, context: &RunnablePerItemContext, ) -> Result, ShellError> { - let env = self.shells.lock().unwrap(); + let env = self.shells.lock(); - env[self.current_shell].mv(args, context) + match env { + Ok(x) => { + let path = x[self.current_shell].path(); + x[self.current_shell].mv(args, context.name, &path) + } + Err(e) => Err(ShellError::labeled_error( + format!("Internal error: could not lock {}", e), + "Internal error: could not lock", + context.name, + )), + } } } diff --git a/src/shell/value_shell.rs b/src/shell/value_shell.rs index d6d80168a..62b7de9a1 100644 --- a/src/shell/value_shell.rs +++ b/src/shell/value_shell.rs @@ -1,4 +1,4 @@ -use crate::commands::command::{EvaluatedWholeStreamCommandArgs, RunnablePerItemContext}; +use crate::commands::command::EvaluatedWholeStreamCommandArgs; use crate::commands::cp::CopyArgs; use crate::commands::mkdir::MkdirArgs; use crate::commands::mv::MoveArgs; @@ -106,48 +106,52 @@ impl Shell for ValueShell { fn cp( &self, _args: CopyArgs, - context: &RunnablePerItemContext, + name: Span, + _path: &str, ) -> Result, ShellError> { Err(ShellError::labeled_error( "cp not currently supported on values", "not currently supported", - context.name, + name, )) } fn mv( &self, _args: MoveArgs, - context: &RunnablePerItemContext, + name: Span, + _path: &str, ) -> Result, ShellError> { Err(ShellError::labeled_error( "mv not currently supported on values", "not currently supported", - context.name, + name, )) } fn mkdir( &self, _args: MkdirArgs, - context: &RunnablePerItemContext, + name: Span, + _path: &str, ) -> Result, ShellError> { Err(ShellError::labeled_error( "mkdir not currently supported on values", "not currently supported", - context.name, + name, )) } fn rm( &self, _args: RemoveArgs, - context: &RunnablePerItemContext, + name: Span, + _path: &str, ) -> Result, ShellError> { Err(ShellError::labeled_error( "rm not currently supported on values", "not currently supported", - context.name, + name, )) } From 87930ba35aa23901aa6c67977fe015565f89ec51 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 22 Aug 2019 16:23:57 +1200 Subject: [PATCH 4/5] Fix tests --- src/shell/filesystem_shell.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index e7038c40c..98f51d095 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -831,13 +831,7 @@ impl Shell for FilesystemShell { ) -> Result, ShellError> { let name_span = name; - let mut path = PathBuf::from(path); - - path.push(&target.item); - - let file = path.to_string_lossy(); - - if file == "." || file == ".." { + if target.item.to_str() == Some(".") || target.item.to_str() == Some("..") { return Err(ShellError::labeled_error( "Remove aborted. \".\" or \"..\" may not be removed.", "Remove aborted. \".\" or \"..\" may not be removed.", @@ -845,6 +839,12 @@ impl Shell for FilesystemShell { )); } + let mut path = PathBuf::from(path); + + path.push(&target.item); + + let file = path.to_string_lossy(); + let entries: Vec<_> = match glob::glob(&path.to_string_lossy()) { Ok(files) => files.collect(), Err(_) => { From b9b462ffeb2159c74f2797a19408721ca25d90b1 Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 22 Aug 2019 17:15:14 +1200 Subject: [PATCH 5/5] Remove dep import --- src/shell/filesystem_shell.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shell/filesystem_shell.rs b/src/shell/filesystem_shell.rs index 98f51d095..2ba27e764 100644 --- a/src/shell/filesystem_shell.rs +++ b/src/shell/filesystem_shell.rs @@ -12,6 +12,7 @@ use crate::utils::FileStructure; use rustyline::completion::FilenameCompleter; use rustyline::hint::{Hinter, HistoryHinter}; use std::path::{Path, PathBuf}; + pub struct FilesystemShell { crate path: String, completer: NuCompleter, @@ -653,8 +654,6 @@ impl Shell for FilesystemShell { } #[cfg(windows)] { - use crate::utils::FileStructure; - let mut sources: FileStructure = FileStructure::new(); sources.walk_decorate(&entry)?;