From b38d54e033c0a6949c7504b557b34f12b5b55698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Tue, 6 Aug 2019 00:34:06 -0500 Subject: [PATCH 1/6] Dont let Nu childs become zombies. --- tests/helpers/mod.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index b441f85254..c7a725ed83 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -21,7 +21,7 @@ macro_rules! nu { $cwd, $commands ); - let process = match Command::new(helpers::executable_path()) + let mut process = match Command::new(helpers::executable_path()) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() @@ -30,22 +30,18 @@ macro_rules! nu { Err(why) => panic!("Can't run test {}", why.description()), }; - match process.stdin.unwrap().write_all(commands.as_bytes()) { - Err(why) => panic!("couldn't write to wc stdin: {}", why.description()), - Ok(_) => {} - } + let stdin = process.stdin.as_mut().expect("couldn't open stdin"); + stdin + .write_all(commands.as_bytes()) + .expect("couldn't write to stdin"); - let mut _s = String::new(); + let output = process + .wait_with_output() + .expect("couldn't read from stdout"); - match process.stdout.unwrap().read_to_string(&mut _s) { - Err(why) => panic!("couldn't read stdout: {}", why.description()), - Ok(_) => { - let _s = _s.replace("\r\n", "\n"); - } - } - - let _s = _s.replace("\r\n", ""); - let $out = _s.replace("\n", ""); + let $out = String::from_utf8_lossy(&output.stdout); + let $out = $out.replace("\r\n", ""); + let $out = $out.replace("\n", ""); }; } @@ -189,6 +185,10 @@ pub fn file_exists_at(full_path: &str) -> bool { PathBuf::from(full_path).exists() } +pub fn dir_exists_at(full_path: &str) -> bool { + PathBuf::from(full_path).exists() +} + pub fn delete_directory_at(full_path: &str) { std::fs::remove_dir_all(PathBuf::from(full_path)).expect("can not remove directory"); } From 1b7dd52713ecac761c7f110340d62d96f3edcf17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Tue, 6 Aug 2019 02:05:47 -0500 Subject: [PATCH 2/6] Tests pass. --- src/commands/cp.rs | 115 +++++++++++++++++++++++++++++++++--- tests/command_cd_tests.rs | 16 +++++ tests/command_clip_tests.rs | 20 +++++++ tests/command_cp_tests.rs | 73 +++++++++++++++++++++++ tests/commands_test.rs | 76 +++++------------------- tests/helpers/mod.rs | 17 ++++-- 6 files changed, 245 insertions(+), 72 deletions(-) create mode 100644 tests/command_cd_tests.rs create mode 100644 tests/command_clip_tests.rs create mode 100644 tests/command_cp_tests.rs diff --git a/src/commands/cp.rs b/src/commands/cp.rs index f1acfc506a..00183647bc 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -35,7 +35,6 @@ pub fn cp(args: CommandArgs) -> Result { let mut source = PathBuf::from(args.shell_manager.path()); let mut destination = PathBuf::from(args.shell_manager.path()); - let mut dst = String::new(); match args .nth(0) @@ -55,26 +54,128 @@ pub fn cp(args: CommandArgs) -> Result { .as_str() { file => { - dst.push_str(file); destination.push(file); } } + let (sources, destinations) = ( + glob::glob(&source.to_string_lossy()), + glob::glob(&destination.to_string_lossy()), + ); + + if sources.is_err() || destinations.is_err() { + return Err(ShellError::string("Invalid pattern.")); + } + + let (sources, destinations): (Vec<_>, Vec<_>) = + (sources.unwrap().collect(), destinations.unwrap().collect()); + + if sources.len() == 1 { + if let Ok(entry) = &sources[0] { + if entry.is_file() { + if destinations.len() == 1 { + if let Ok(dst) = &destinations[0] { + if dst.is_file() { + std::fs::copy(entry, dst); + } + + if dst.is_dir() { + destination.push(entry.file_name().unwrap()); + std::fs::copy(entry, destination); + } + } + } else if destinations.is_empty() { + if destination.is_dir() { + destination.push(entry.file_name().unwrap()); + std::fs::copy(entry, destination); + } else { + std::fs::copy(entry, destination); + } + } + } + + if entry.is_dir() { + if destinations.len() == 1 { + if let Ok(dst) = &destinations[0] { + if dst.is_dir() && !args.has("recursive") { + return Err(ShellError::string(&format!( + "{:?} is a directory (not copied)", + entry.to_string_lossy() + ))); + } + + + if dst.is_dir() && args.has("recursive") { + let entries = std::fs::read_dir(&entry); + + let entries = match entries { + Err(e) => { + if let Some(s) = args.nth(0) { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + s.span(), + )); + } else { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + args.call_info.name_span, + )); + } + } + Ok(o) => o, + }; + + let mut x = dst.clone(); + + //x.pop(); + x.push(entry.file_name().unwrap()); + + + std::fs::create_dir(&x).expect("can not create directory"); + + for entry in entries { + let entry = entry?; + let file_path = entry.path(); + let file_name = file_path.file_name().unwrap(); + + let mut d = PathBuf::new(); + d.push(&x); + d.push(file_name); + + std::fs::copy(entry.path(), d); + } + } + } + } + } + } + } + /* if destination.is_dir() { if source.is_file() { let file_name = source.file_name().expect(""); let file_name = file_name.to_str().expect(""); destination.push(Path::new(file_name)); + + match std::fs::copy(source, destination) { + Err(_error) => return Err(ShellError::string("can not copy file")), + Ok(_) => return Ok(OutputStream::empty()), + } } else if source.is_dir() { - return Err(ShellError::string(&format!( - "{:?} is a directory (not copied)", - source.to_string_lossy() - ))); + + return Err(ShellError::string(&format!( + "{:?} is a directory (not copied)", + source.to_string_lossy() + ))); + } } match std::fs::copy(source, destination) { Err(_error) => Err(ShellError::string("can not copy file")), Ok(_) => Ok(OutputStream::empty()), - } + }*/ + Ok(OutputStream::empty()) } diff --git a/tests/command_cd_tests.rs b/tests/command_cd_tests.rs new file mode 100644 index 0000000000..626a59f795 --- /dev/null +++ b/tests/command_cd_tests.rs @@ -0,0 +1,16 @@ +mod helpers; + +use helpers::in_directory as cwd; +use helpers::Playground; + +#[test] +fn cd_directory_not_found() { + let sandbox = Playground::setup_for("cd_directory_not_found_test").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + + nu_error!(output, cwd(&full_path), "cd dir_that_does_not_exist"); + + assert!(output.contains("dir_that_does_not_exist")); + assert!(output.contains("directory not found")); +} \ No newline at end of file diff --git a/tests/command_clip_tests.rs b/tests/command_clip_tests.rs new file mode 100644 index 0000000000..5d418c9a60 --- /dev/null +++ b/tests/command_clip_tests.rs @@ -0,0 +1,20 @@ +mod helpers; + +use helpers::in_directory as cwd; + +use clipboard::{ClipboardProvider, ClipboardContext}; + +#[test] +fn clip() { + + let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap(); + + nu!( + _output, + cwd("tests/fixtures/formats"), + "open caco3_plastics.csv --raw | lines | clip" + ); + + + assert!(ctx.get_contents().is_ok()); +} \ No newline at end of file diff --git a/tests/command_cp_tests.rs b/tests/command_cp_tests.rs new file mode 100644 index 0000000000..59d145b911 --- /dev/null +++ b/tests/command_cp_tests.rs @@ -0,0 +1,73 @@ +mod helpers; + +use h::{in_directory as cwd, Playground, Stub::*}; +use helpers as h; + +use std::path::{Path, PathBuf}; + +#[test] +fn cp_copies_a_file() { + let sandbox = Playground::setup_for("cp_test").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + let expected_file = format!("{}/{}", full_path, "sample.ini"); + + nu!( + _output, + cwd(&Playground::root()), + "cp ../formats/sample.ini cp_test/sample.ini" + ); + + assert!(h::file_exists_at(PathBuf::from(expected_file))); +} + +#[test] +fn cp_copies_the_file_inside_directory_if_path_to_copy_is_directory() { + let sandbox = Playground::setup_for("cp_test_2").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + let expected_file = format!("{}/{}", full_path, "sample.ini"); + + nu!( + _output, + cwd(&Playground::root()), + "cp ../formats/sample.ini cp_test_2" + ); + + assert!(h::file_exists_at(PathBuf::from(expected_file))); +} + +#[test] +fn cp_error_if_attempting_to_copy_a_directory_to_another_directory() { + Playground::setup_for("cp_test_3"); + + nu_error!(output, cwd(&Playground::root()), "cp ../formats cp_test_3"); + + assert!(output.contains("../formats")); + assert!(output.contains("is a directory (not copied)")); +} + +#[test] +fn cp_copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_with_recursive_flag() { + let sandbox = Playground::setup_for("cp_test_4") + .within("originals") + .with_files(vec![ + EmptyFile("yehuda.txt"), + EmptyFile("jonathan.txt"), + EmptyFile("andres.txt"), + ]) + .within("copies_expected") + .test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + let expected_dir = format!("{}/{}", full_path, "copies_expected/originals"); + + nu!( + _output, + cwd(&full_path), + "cp originals copies_expected --recursive" + ); + + assert!(h::dir_exists_at(PathBuf::from(&expected_dir))); + assert!(h::files_exist_at(vec![Path::new("yehuda.txt"), Path::new("jonathan.txt"), Path::new("andres.txt")], PathBuf::from(&expected_dir))); +} \ No newline at end of file diff --git a/tests/commands_test.rs b/tests/commands_test.rs index a1699a8d85..1457934020 100644 --- a/tests/commands_test.rs +++ b/tests/commands_test.rs @@ -2,7 +2,7 @@ mod helpers; use h::{in_directory as cwd, Playground, Stub::*}; use helpers as h; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; #[test] fn lines() { @@ -129,48 +129,6 @@ fn save_can_write_out_csv() { assert!(actual.contains("[list list],A shell for the GitHub era,2018,ISC,nu,0.2.0")); } -#[test] -fn cp_can_copy_a_file() { - let sandbox = Playground::setup_for("cp_test").test_dir_name(); - - let full_path = format!("{}/{}", Playground::root(), sandbox); - let expected_file = format!("{}/{}", full_path, "sample.ini"); - - nu!( - _output, - cwd(&Playground::root()), - "cp ../formats/sample.ini cp_test/sample.ini" - ); - - assert!(h::file_exists_at(&expected_file)); -} - -#[test] -fn cp_copies_the_file_inside_directory_if_path_to_copy_is_directory() { - let sandbox = Playground::setup_for("cp_test_2").test_dir_name(); - - let full_path = format!("{}/{}", Playground::root(), sandbox); - let expected_file = format!("{}/{}", full_path, "sample.ini"); - - nu!( - _output, - cwd(&Playground::root()), - "cp ../formats/sample.ini cp_test_2" - ); - - assert!(h::file_exists_at(&expected_file)); -} - -#[test] -fn cp_error_if_attempting_to_copy_a_directory_to_another_directory() { - Playground::setup_for("cp_test_3"); - - nu_error!(output, cwd(&Playground::root()), "cp ../formats cp_test_3"); - - assert!(output.contains("../formats")); - assert!(output.contains("is a directory (not copied)")); -} - #[test] fn rm_removes_a_file() { let sandbox = Playground::setup_for("rm_test") @@ -183,12 +141,14 @@ fn rm_removes_a_file() { "rm rm_test/i_will_be_deleted.txt" ); - assert!(!h::file_exists_at(&format!( + let path = &format!( "{}/{}/{}", Playground::root(), sandbox, "i_will_be_deleted.txt" - ))); + ); + + assert!(!h::file_exists_at(PathBuf::from(path))); } #[test] @@ -243,21 +203,13 @@ fn rm_removes_files_with_wildcard() { "rm \"src/*/*/*.rs\"" ); - assert!(!h::file_exists_at(&format!( - "{}/src/parser/parse/token_tree.rs", - full_path - ))); - assert!(!h::file_exists_at(&format!( - "{}/src/parser/hir/baseline_parse.rs", - full_path - ))); - assert!(!h::file_exists_at(&format!( - "{}/src/parser/hir/baseline_parse_tokens.rs", - full_path - ))); + assert!(!h::files_exist_at(vec![ + Path::new("src/parser/parse/token_tree.rs"), + Path::new("src/parser/hir/baseline_parse.rs"), + Path::new("src/parser/hir/baseline_parse_tokens.rs")], PathBuf::from(&full_path))); assert_eq!( - Playground::glob_vec(&format!("{}/src/*/*/*.rs", full_path)), + Playground::glob_vec(&format!("{}/src/*/*/*.rs", &full_path)), Vec::::new() ); } @@ -278,11 +230,13 @@ fn rm_removes_directory_contents_with_recursive_flag() { "rm rm_test_recursive --recursive" ); - assert!(!h::file_exists_at(&format!( + let expected = format!( "{}/{}", Playground::root(), sandbox - ))); + ); + + assert!(!h::file_exists_at(PathBuf::from(expected))); } #[test] @@ -292,7 +246,7 @@ fn rm_errors_if_attempting_to_delete_a_directory_without_recursive_flag() { nu_error!(output, cwd(&Playground::root()), "rm rm_test_2"); - assert!(h::file_exists_at(&full_path)); + assert!(h::file_exists_at(PathBuf::from(full_path))); assert!(output.contains("is a directory")); } diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index c7a725ed83..f4823ad5de 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -181,12 +181,21 @@ pub fn copy_file_to(source: &str, destination: &str) { std::fs::copy(source, destination).expect("can not copy file"); } -pub fn file_exists_at(full_path: &str) -> bool { - PathBuf::from(full_path).exists() +pub fn files_exist_at(files: Vec<&Path>, path: PathBuf) -> bool { + files.iter() + .all(|f| { + let mut loc = path.clone(); + loc.push(f); + loc.exists() + }) } -pub fn dir_exists_at(full_path: &str) -> bool { - PathBuf::from(full_path).exists() +pub fn file_exists_at(path: PathBuf) -> bool { + path.exists() +} + +pub fn dir_exists_at(path: PathBuf) -> bool { + path.exists() } pub fn delete_directory_at(full_path: &str) { From c8b5329c5c0fb9fa269988e509d0f5f6c536f57d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Tue, 6 Aug 2019 21:45:38 -0500 Subject: [PATCH 3/6] mkdir. --- src/cli.rs | 1 + src/commands.rs | 2 ++ src/commands/mkdir.rs | 64 ++++++++++++++++++++++++++++++++++++ tests/command_mkdir_tests.rs | 53 +++++++++++++++++++++++++++++ tests/helpers/mod.rs | 11 +++---- 5 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 src/commands/mkdir.rs create mode 100644 tests/command_mkdir_tests.rs diff --git a/src/cli.rs b/src/cli.rs index f9223f66e8..4fac51167d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -182,6 +182,7 @@ pub async fn cli() -> Result<(), Box> { Arc::new(Remove), Arc::new(Copycp), Arc::new(Open), + Arc::new(Mkdir), Arc::new(Date), Arc::new(Where), Arc::new(Config), diff --git a/src/commands.rs b/src/commands.rs index 6f551421fe..e9ef8b2441 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -23,6 +23,7 @@ crate mod get; crate mod lines; crate mod ls; crate mod next; +crate mod mkdir; crate mod open; crate mod pick; crate mod plugin; @@ -54,6 +55,7 @@ crate use cp::Copycp; crate use date::Date; crate use exit::Exit; crate use open::Open; +crate use mkdir::Mkdir; crate use rm::Remove; crate use save::Save; crate use skip_while::SkipWhile; diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs new file mode 100644 index 0000000000..efa732827a --- /dev/null +++ b/src/commands/mkdir.rs @@ -0,0 +1,64 @@ +use crate::errors::ShellError; +use crate::parser::hir::SyntaxType; +use crate::parser::registry::{CommandConfig, NamedType, PositionalType}; +use crate::prelude::*; +use indexmap::IndexMap; +use std::path::{Path, PathBuf}; + +pub struct Mkdir; + +impl Command for Mkdir { + fn run(&self, args: CommandArgs) -> Result { + mkdir(args) + } + + fn name(&self) -> &str { + "mkdir" + } + + fn config(&self) -> CommandConfig { + let mut named: IndexMap = IndexMap::new(); + named.insert("p".to_string(), NamedType::Switch); + + CommandConfig { + name: self.name().to_string(), + positional: vec![PositionalType::mandatory("file", SyntaxType::Path)], + rest_positional: false, + named, + is_sink: false, + is_filter: false, + } + } +} + +pub fn mkdir(args: CommandArgs) -> Result { + let env = args.env.lock().unwrap(); + let path = env.path.to_path_buf(); + let cwd = path.clone(); + let mut full_path = PathBuf::from(path); + + match &args.nth(0) { + Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)), + _ => {} + } + + if !args.has("p") { + match std::fs::create_dir(full_path) { + Err(_) => Err(ShellError::labeled_error( + "No such file or directory", + "No such file or directory", + args.nth(0).unwrap().span(), + )), + Ok(_) => Ok(OutputStream::empty()), + } + } else { + match std::fs::create_dir_all(full_path) { + Err(reason) => Err(ShellError::labeled_error( + reason.to_string(), + reason.to_string(), + args.nth(0).unwrap().span(), + )), + Ok(_) => Ok(OutputStream::empty()), + } + } +} diff --git a/tests/command_mkdir_tests.rs b/tests/command_mkdir_tests.rs new file mode 100644 index 0000000000..a30f8a243a --- /dev/null +++ b/tests/command_mkdir_tests.rs @@ -0,0 +1,53 @@ +mod helpers; + +use h::{in_directory as cwd, Playground}; +use helpers as h; +use std::path::PathBuf; + +#[test] +fn creates_directory() { + let sandbox = Playground::setup_for("mkdir_test").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + + nu!(_output, cwd(&full_path), "mkdir my_new_directory"); + + let mut expected = PathBuf::from(full_path); + expected.push("my_new_directory"); + + assert!(h::dir_exists_at(expected)); +} + +#[test] +fn error_if_intermediary_directory_doesnt_exist() { + let sandbox = Playground::setup_for("mkdir_test_2").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + + nu_error!( + output, + cwd(&full_path), + "mkdir some_folder/another/deeper_one" + ); + + assert!(output.contains("some_folder/another/deeper_one")); + assert!(output.contains("No such file or directory")); +} + +#[test] +fn creates_intermediary_directories_with_p_flag() { + let sandbox = Playground::setup_for("mkdir_test_3").test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + + nu!( + _output, + cwd(&full_path), + "mkdir some_folder/another/deeper_one --p" + ); + + let mut expected = PathBuf::from(full_path); + expected.push("some_folder/another/deeper_one"); + + assert!(h::dir_exists_at(expected)); +} diff --git a/tests/helpers/mod.rs b/tests/helpers/mod.rs index f4823ad5de..5520edc5ab 100644 --- a/tests/helpers/mod.rs +++ b/tests/helpers/mod.rs @@ -182,12 +182,11 @@ pub fn copy_file_to(source: &str, destination: &str) { } pub fn files_exist_at(files: Vec<&Path>, path: PathBuf) -> bool { - files.iter() - .all(|f| { - let mut loc = path.clone(); - loc.push(f); - loc.exists() - }) + files.iter().all(|f| { + let mut loc = path.clone(); + loc.push(f); + loc.exists() + }) } pub fn file_exists_at(path: PathBuf) -> bool { From e0bacaaf37efa44c1f43d7f326bf7f8c60abd3de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Wed, 7 Aug 2019 09:45:50 -0500 Subject: [PATCH 4/6] clean up. more cp. mkdir. more test coverage. fixes. - Introduced mkdir. - Minor more labelled error improvements. - Fix to avoid leaking child zombies. - cp improvements. - Introduced mkdir. --- README.md | 1 + src/commands/cp.rs | 380 ++++++++++++++++++++++++++++-------- src/commands/mkdir.rs | 1 - src/commands/rm.rs | 2 +- tests/command_clip_tests.rs | 20 -- tests/command_cp_tests.rs | 108 +++++++++- 6 files changed, 403 insertions(+), 109 deletions(-) delete mode 100644 tests/command_clip_tests.rs diff --git a/README.md b/README.md index dfdc899400..10e4985925 100644 --- a/README.md +++ b/README.md @@ -129,6 +129,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | cd path | Change to a new path | | cp source path | Copy files | | ls (path) | View the contents of the current or given path | +| mkdir path | Make directories, (to create intermediary directories append '--p') | | date (--utc) | Get the current datetime | | ps | View current processes | | sys | View information about the current system | diff --git a/src/commands/cp.rs b/src/commands/cp.rs index 00183647bc..fb3b056af8 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -31,10 +31,79 @@ impl Command for Copycp { } } +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct Res { + pub loc: PathBuf, + pub at: usize, +} + +impl Res {} + +pub struct FileStructure { + root: PathBuf, + resources: Vec, +} + +impl FileStructure { + pub fn new() -> FileStructure { + FileStructure { + root: PathBuf::new(), + resources: Vec::::new(), + } + } + + pub fn set_root(&mut self, path: &Path) { + self.root = path.to_path_buf(); + } + + pub fn translate(&mut self, to: F) -> Vec<(PathBuf, PathBuf)> + where + F: Fn((PathBuf, usize)) -> (PathBuf, PathBuf), + { + self.resources + .iter() + .map(|f| (PathBuf::from(&f.loc), f.at)) + .map(|f| to(f)) + .collect() + } + + pub fn walk_decorate(&mut self, start_path: &Path) { + self.set_root(&dunce::canonicalize(start_path).unwrap()); + self.resources = Vec::::new(); + self.build(start_path, 0); + self.resources.sort(); + } + + fn build(&mut self, src: &'a Path, lvl: usize) { + let source = dunce::canonicalize(src).unwrap(); + + if source.is_dir() { + for entry in std::fs::read_dir(&source).unwrap() { + let entry = entry.unwrap(); + let path = entry.path(); + + if path.is_dir() { + self.build(&path, lvl + 1); + } + + self.resources.push(Res { + loc: path.to_path_buf(), + at: lvl, + }); + } + } else { + self.resources.push(Res { + loc: source, + at: lvl, + }); + } + } +} + pub fn cp(args: CommandArgs) -> Result { let mut source = PathBuf::from(args.shell_manager.path()); let mut destination = PathBuf::from(args.shell_manager.path()); - + let name_span = args.call_info.name_span; match args .nth(0) @@ -58,124 +127,273 @@ pub fn cp(args: CommandArgs) -> Result { } } - let (sources, destinations) = ( - glob::glob(&source.to_string_lossy()), - glob::glob(&destination.to_string_lossy()), - ); + let sources = glob::glob(&source.to_string_lossy()); - if sources.is_err() || destinations.is_err() { - return Err(ShellError::string("Invalid pattern.")); + if sources.is_err() { + return Err(ShellError::labeled_error( + "Invalid pattern.", + "Invalid pattern.", + args.nth(0).unwrap().span(), + )); } - let (sources, destinations): (Vec<_>, Vec<_>) = - (sources.unwrap().collect(), destinations.unwrap().collect()); + let sources: Vec<_> = sources.unwrap().collect(); if sources.len() == 1 { - if let Ok(entry) = &sources[0] { - if entry.is_file() { - if destinations.len() == 1 { - if let Ok(dst) = &destinations[0] { - if dst.is_file() { - std::fs::copy(entry, dst); - } + if let Ok(val) = &sources[0] { + if val.is_dir() && !args.has("recursive") { + return Err(ShellError::labeled_error( + "is a directory (not copied). Try using \"--recursive\".", + "is a directory (not copied). Try using \"--recursive\".", + args.nth(0).unwrap().span(), + )); + } - if dst.is_dir() { - destination.push(entry.file_name().unwrap()); - std::fs::copy(entry, destination); - } - } - } else if destinations.is_empty() { - if destination.is_dir() { - destination.push(entry.file_name().unwrap()); - std::fs::copy(entry, destination); + let mut sources: FileStructure = FileStructure::new(); + + sources.walk_decorate(&val); + + if val.is_file() { + for (ref src, ref dst) in sources.translate(|(src, _)| { + if destination.exists() { + let mut dst = dunce::canonicalize(destination.clone()).unwrap(); + dst.push(val.file_name().unwrap()); + (src, dst) } else { - std::fs::copy(entry, destination); + (src, destination.clone()) + } + }) { + 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 destinations.len() == 1 { - if let Ok(dst) = &destinations[0] { - if dst.is_dir() && !args.has("recursive") { - return Err(ShellError::string(&format!( - "{:?} is a directory (not copied)", - entry.to_string_lossy() - ))); + if val.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, + }; + + for (ref src, ref dst) in sources.translate(|(src, loc)| { + let mut final_path = destination.clone(); + let path = dunce::canonicalize(&src).unwrap(); + + let mut comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + loc) + .collect(); + + comps.reverse(); + + for fragment in comps.iter() { + final_path.push(fragment); } - - if dst.is_dir() && args.has("recursive") { - let entries = std::fs::read_dir(&entry); - - let entries = match entries { - Err(e) => { - if let Some(s) = args.nth(0) { + (PathBuf::from(&src), PathBuf::from(final_path)) + }) { + 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(), - s.span(), - )); - } else { - return Err(ShellError::labeled_error( - e.to_string(), - e.to_string(), - args.call_info.name_span, + 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 { + destination.push(val.file_name().unwrap()); - let mut x = dst.clone(); + 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, + }; - //x.pop(); - x.push(entry.file_name().unwrap()); + for (ref src, ref dst) in sources.translate(|(src, loc)| { + let mut final_path = dunce::canonicalize(&destination).unwrap(); + let path = dunce::canonicalize(&src).unwrap(); + let mut comps: Vec<_> = path + .components() + .map(|fragment| fragment.as_os_str()) + .rev() + .take(1 + loc) + .collect(); - std::fs::create_dir(&x).expect("can not create directory"); + comps.reverse(); - for entry in entries { - let entry = entry?; - let file_path = entry.path(); - let file_name = file_path.file_name().unwrap(); + for fragment in comps.iter() { + final_path.push(fragment); + } - let mut d = PathBuf::new(); - d.push(&x); - d.push(file_name); - - std::fs::copy(entry.path(), d); + (PathBuf::from(&src), PathBuf::from(final_path)) + }) { + 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, + }; + } } } } } - } - /* - if destination.is_dir() { - if source.is_file() { - let file_name = source.file_name().expect(""); - let file_name = file_name.to_str().expect(""); - destination.push(Path::new(file_name)); - - match std::fs::copy(source, destination) { - Err(_error) => return Err(ShellError::string("can not copy file")), - Ok(_) => return Ok(OutputStream::empty()), + } else { + if destination.exists() { + if !sources.iter().all(|x| (x.as_ref().unwrap()).is_file()) && !args.has("recursive") { + return Err(ShellError::labeled_error( + "Copy aborted (directories found). Try using \"--recursive\".", + "Copy aborted (directories found). Try using \"--recursive\".", + args.nth(0).unwrap().span(), + )); } - } else if source.is_dir() { - return Err(ShellError::string(&format!( - "{:?} is a directory (not copied)", - source.to_string_lossy() - ))); + for entry in sources { + if let Ok(entry) = entry { + let mut to = PathBuf::from(&destination); + to.push(&entry.file_name().unwrap()); + match std::fs::copy(&entry, &to) { + Err(e) => { + return Err(ShellError::labeled_error( + e.to_string(), + e.to_string(), + name_span, + )); + } + Ok(o) => o, + }; + } + } + } else { + return Err(ShellError::labeled_error( + format!( + "Copy aborted. (Does {:?} exist?)", + &destination.file_name().unwrap() + ), + format!( + "Copy aborted. (Does {:?} exist?)", + &destination.file_name().unwrap() + ), + args.nth(1).unwrap().span(), + )); } } - match std::fs::copy(source, destination) { - Err(_error) => Err(ShellError::string("can not copy file")), - Ok(_) => Ok(OutputStream::empty()), - }*/ Ok(OutputStream::empty()) } + +#[cfg(test)] +mod tests { + + use super::{FileStructure, Res}; + use std::path::PathBuf; + + fn fixtures() -> PathBuf { + let mut sdx = PathBuf::new(); + sdx.push("tests"); + sdx.push("fixtures"); + sdx.push("formats"); + dunce::canonicalize(sdx).unwrap() + } + + #[test] + fn prepares_and_decorates_source_files_for_copying() { + let mut res = FileStructure::new(); + res.walk_decorate(fixtures().as_path()); + + assert_eq!( + res.resources, + vec![ + Res { + loc: fixtures().join("appveyor.yml"), + at: 0 + }, + Res { + loc: fixtures().join("caco3_plastics.csv"), + at: 0 + }, + Res { + loc: fixtures().join("cargo_sample.toml"), + at: 0 + }, + Res { + loc: fixtures().join("jonathan.xml"), + at: 0 + }, + Res { + loc: fixtures().join("sample.ini"), + at: 0 + }, + Res { + loc: fixtures().join("sgml_description.json"), + at: 0 + } + ] + ); + } +} diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index efa732827a..13c8e2ef43 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -34,7 +34,6 @@ impl Command for Mkdir { pub fn mkdir(args: CommandArgs) -> Result { let env = args.env.lock().unwrap(); let path = env.path.to_path_buf(); - let cwd = path.clone(); let mut full_path = PathBuf::from(path); match &args.nth(0) { diff --git a/src/commands/rm.rs b/src/commands/rm.rs index aa0d10c43f..c57446bcf1 100644 --- a/src/commands/rm.rs +++ b/src/commands/rm.rs @@ -61,7 +61,7 @@ pub fn rm(args: CommandArgs) -> Result { if !args.has("recursive") { return Err(ShellError::labeled_error( "is a directory", - "", + "is a directory", args.call_info.name_span, )); } diff --git a/tests/command_clip_tests.rs b/tests/command_clip_tests.rs deleted file mode 100644 index 5d418c9a60..0000000000 --- a/tests/command_clip_tests.rs +++ /dev/null @@ -1,20 +0,0 @@ -mod helpers; - -use helpers::in_directory as cwd; - -use clipboard::{ClipboardProvider, ClipboardContext}; - -#[test] -fn clip() { - - let mut ctx: ClipboardContext = ClipboardProvider::new().unwrap(); - - nu!( - _output, - cwd("tests/fixtures/formats"), - "open caco3_plastics.csv --raw | lines | clip" - ); - - - assert!(ctx.get_contents().is_ok()); -} \ No newline at end of file diff --git a/tests/command_cp_tests.rs b/tests/command_cp_tests.rs index 59d145b911..ef2a68c364 100644 --- a/tests/command_cp_tests.rs +++ b/tests/command_cp_tests.rs @@ -6,7 +6,7 @@ use helpers as h; use std::path::{Path, PathBuf}; #[test] -fn cp_copies_a_file() { +fn copies_a_file() { let sandbox = Playground::setup_for("cp_test").test_dir_name(); let full_path = format!("{}/{}", Playground::root(), sandbox); @@ -22,7 +22,7 @@ fn cp_copies_a_file() { } #[test] -fn cp_copies_the_file_inside_directory_if_path_to_copy_is_directory() { +fn copies_the_file_inside_directory_if_path_to_copy_is_directory() { let sandbox = Playground::setup_for("cp_test_2").test_dir_name(); let full_path = format!("{}/{}", Playground::root(), sandbox); @@ -38,7 +38,7 @@ fn cp_copies_the_file_inside_directory_if_path_to_copy_is_directory() { } #[test] -fn cp_error_if_attempting_to_copy_a_directory_to_another_directory() { +fn error_if_attempting_to_copy_a_directory_to_another_directory() { Playground::setup_for("cp_test_3"); nu_error!(output, cwd(&Playground::root()), "cp ../formats cp_test_3"); @@ -48,7 +48,7 @@ fn cp_error_if_attempting_to_copy_a_directory_to_another_directory() { } #[test] -fn cp_copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_with_recursive_flag() { +fn copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_with_recursive_flag() { let sandbox = Playground::setup_for("cp_test_4") .within("originals") .with_files(vec![ @@ -69,5 +69,101 @@ fn cp_copies_the_directory_inside_directory_if_path_to_copy_is_directory_and_wit ); assert!(h::dir_exists_at(PathBuf::from(&expected_dir))); - assert!(h::files_exist_at(vec![Path::new("yehuda.txt"), Path::new("jonathan.txt"), Path::new("andres.txt")], PathBuf::from(&expected_dir))); -} \ No newline at end of file + assert!(h::files_exist_at( + vec![ + Path::new("yehuda.txt"), + Path::new("jonathan.txt"), + Path::new("andres.txt") + ], + PathBuf::from(&expected_dir) + )); +} + +#[test] +fn deep_copies_with_recursive_flag() { + r#" + Given these files and directories + originals + originals/manifest.txt + originals/contributors + originals/contributors/yehuda.txt + originals/contributors/jonathan.txt + originals/contributors/andres.txt + originals/contributors/jonathan + originals/contributors/jonathan/errors.txt + originals/contributors/jonathan/multishells.txt + originals/contributors/andres + originals/contributors/andres/coverage.txt + originals/contributors/andres/commands.txt + originals/contributors/yehuda + originals/contributors/yehuda/defer-evaluation.txt + "#; + + let sandbox = Playground::setup_for("cp_test_5") + .within("originals") + .with_files(vec![EmptyFile("manifest.txt")]) + .within("originals/contributors") + .with_files(vec![ + EmptyFile("yehuda.txt"), + EmptyFile("jonathan.txt"), + EmptyFile("andres.txt"), + ]) + .within("originals/contributors/jonathan") + .with_files(vec![EmptyFile("errors.txt"), EmptyFile("multishells.txt")]) + .within("originals/contributors/andres") + .with_files(vec![EmptyFile("coverage.txt"), EmptyFile("commands.txt")]) + .within("originals/contributors/yehuda") + .with_files(vec![EmptyFile("defer-evaluation.txt")]) + .within("copies_expected") + .test_dir_name(); + + let full_path = format!("{}/{}", Playground::root(), sandbox); + let expected_dir = format!("{}/{}", full_path, "copies_expected/originals"); + + let jonathans_expected_copied_dir = format!("{}/contributors/jonathan", expected_dir); + let andres_expected_copied_dir = format!("{}/contributors/andres", expected_dir); + let yehudas_expected_copied_dir = format!("{}/contributors/yehuda", expected_dir); + + nu!( + _output, + cwd(&full_path), + "cp originals copies_expected --recursive" + ); + + assert!(h::dir_exists_at(PathBuf::from(&expected_dir))); + assert!(h::files_exist_at( + vec![Path::new("errors.txt"), Path::new("multishells.txt")], + PathBuf::from(&jonathans_expected_copied_dir) + )); + assert!(h::files_exist_at( + vec![Path::new("coverage.txt"), Path::new("commands.txt")], + PathBuf::from(&andres_expected_copied_dir) + )); + assert!(h::files_exist_at( + vec![Path::new("defer-evaluation.txt")], + PathBuf::from(&yehudas_expected_copied_dir) + )); +} + +#[test] +fn copies_using_globs() { + let sandbox = Playground::setup_for("cp_test_6").test_dir_name(); + let expected_copies_path = format!("{}/{}", Playground::root(), sandbox); + + nu!( + _output, + cwd(&Playground::root()), + "cp ../formats/* cp_test_6" + ); + + assert!(h::files_exist_at( + vec![ + Path::new("caco3_plastics.csv"), + Path::new("cargo_sample.toml"), + Path::new("jonathan.xml"), + Path::new("sample.ini"), + Path::new("sgml_description.json") + ], + PathBuf::from(&expected_copies_path) + )); +} From 50393bdf426451d4f997ba692b5b2748dfbc14df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Wed, 7 Aug 2019 13:40:38 -0500 Subject: [PATCH 5/6] Make more visible the strategies for figuring out where to copy files. --- README.md | 2 +- src/commands/cp.rs | 61 ++++++++++++++++++++---------------- src/commands/mkdir.rs | 8 ++--- tests/command_mkdir_tests.rs | 2 +- 4 files changed, 39 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 10e4985925..5cf02bf603 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | cd path | Change to a new path | | cp source path | Copy files | | ls (path) | View the contents of the current or given path | -| mkdir path | Make directories, (to create intermediary directories append '--p') | +| mkdir path | Make directories, (to create intermediary directories append '--create-all') | | date (--utc) | Get the current datetime | | ps | View current processes | | sys | View information about the current system | diff --git a/src/commands/cp.rs b/src/commands/cp.rs index fb3b056af8..2f7c707fe6 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -56,7 +56,7 @@ impl FileStructure { self.root = path.to_path_buf(); } - pub fn translate(&mut self, to: F) -> Vec<(PathBuf, PathBuf)> + pub fn paths_applying_with(&mut self, to: F) -> Vec<(PathBuf, PathBuf)> where F: Fn((PathBuf, usize)) -> (PathBuf, PathBuf), { @@ -140,8 +140,8 @@ pub fn cp(args: CommandArgs) -> Result { let sources: Vec<_> = sources.unwrap().collect(); if sources.len() == 1 { - if let Ok(val) = &sources[0] { - if val.is_dir() && !args.has("recursive") { + if let Ok(entry) = &sources[0] { + if entry.is_dir() && !args.has("recursive") { return Err(ShellError::labeled_error( "is a directory (not copied). Try using \"--recursive\".", "is a directory (not copied). Try using \"--recursive\".", @@ -151,18 +151,21 @@ pub fn cp(args: CommandArgs) -> Result { let mut sources: FileStructure = FileStructure::new(); - sources.walk_decorate(&val); + sources.walk_decorate(&entry); - if val.is_file() { - for (ref src, ref dst) in sources.translate(|(src, _)| { + if entry.is_file() { + + let strategy = |(source_file, _depth_level)| { if destination.exists() { - let mut dst = dunce::canonicalize(destination.clone()).unwrap(); - dst.push(val.file_name().unwrap()); - (src, dst) + let mut new_dst = dunce::canonicalize(destination.clone()).unwrap(); + new_dst.push(entry.file_name().unwrap()); + (source_file, new_dst) } else { - (src, destination.clone()) + (source_file, destination.clone()) } - }) { + }; + + for (ref src, ref dst) in sources.paths_applying_with(strategy) { if src.is_file() { match std::fs::copy(src, dst) { Err(e) => { @@ -178,7 +181,7 @@ pub fn cp(args: CommandArgs) -> Result { } } - if val.is_dir() { + if entry.is_dir() { if !destination.exists() { match std::fs::create_dir_all(&destination) { Err(e) => { @@ -191,25 +194,27 @@ pub fn cp(args: CommandArgs) -> Result { Ok(o) => o, }; - for (ref src, ref dst) in sources.translate(|(src, loc)| { - let mut final_path = destination.clone(); - let path = dunce::canonicalize(&src).unwrap(); + let strategy = |(source_file, depth_level)| { + let mut new_dst = destination.clone(); + let path = dunce::canonicalize(&source_file).unwrap(); let mut comps: Vec<_> = path .components() .map(|fragment| fragment.as_os_str()) .rev() - .take(1 + loc) + .take(1 + depth_level) .collect(); comps.reverse(); for fragment in comps.iter() { - final_path.push(fragment); + new_dst.push(fragment); } - (PathBuf::from(&src), PathBuf::from(final_path)) - }) { + (PathBuf::from(&source_file), PathBuf::from(new_dst)) + }; + + for (ref src, ref dst) in sources.paths_applying_with(strategy) { if src.is_dir() { if !dst.exists() { match std::fs::create_dir_all(dst) { @@ -239,7 +244,7 @@ pub fn cp(args: CommandArgs) -> Result { } } } else { - destination.push(val.file_name().unwrap()); + destination.push(entry.file_name().unwrap()); match std::fs::create_dir_all(&destination) { Err(e) => { @@ -252,25 +257,27 @@ pub fn cp(args: CommandArgs) -> Result { Ok(o) => o, }; - for (ref src, ref dst) in sources.translate(|(src, loc)| { - let mut final_path = dunce::canonicalize(&destination).unwrap(); - let path = dunce::canonicalize(&src).unwrap(); + let strategy = |(source_file, depth_level)| { + let mut new_dst = dunce::canonicalize(&destination).unwrap(); + let path = dunce::canonicalize(&source_file).unwrap(); let mut comps: Vec<_> = path .components() .map(|fragment| fragment.as_os_str()) .rev() - .take(1 + loc) + .take(1 + depth_level) .collect(); comps.reverse(); for fragment in comps.iter() { - final_path.push(fragment); + new_dst.push(fragment); } - (PathBuf::from(&src), PathBuf::from(final_path)) - }) { + (PathBuf::from(&source_file), PathBuf::from(new_dst)) + }; + + for (ref src, ref dst) in sources.paths_applying_with(strategy) { if src.is_dir() { if !dst.exists() { match std::fs::create_dir_all(dst) { diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 13c8e2ef43..9bbd285eb0 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -18,7 +18,7 @@ impl Command for Mkdir { fn config(&self) -> CommandConfig { let mut named: IndexMap = IndexMap::new(); - named.insert("p".to_string(), NamedType::Switch); + named.insert("create-all".to_string(), NamedType::Switch); CommandConfig { name: self.name().to_string(), @@ -32,16 +32,14 @@ impl Command for Mkdir { } pub fn mkdir(args: CommandArgs) -> Result { - let env = args.env.lock().unwrap(); - let path = env.path.to_path_buf(); - let mut full_path = PathBuf::from(path); + let mut full_path = PathBuf::from(args.shell_manager.path()); match &args.nth(0) { Some(Tagged { item: value, .. }) => full_path.push(Path::new(&value.as_string()?)), _ => {} } - if !args.has("p") { + if !args.has("create-all") { match std::fs::create_dir(full_path) { Err(_) => Err(ShellError::labeled_error( "No such file or directory", diff --git a/tests/command_mkdir_tests.rs b/tests/command_mkdir_tests.rs index a30f8a243a..9d78365535 100644 --- a/tests/command_mkdir_tests.rs +++ b/tests/command_mkdir_tests.rs @@ -43,7 +43,7 @@ fn creates_intermediary_directories_with_p_flag() { nu!( _output, cwd(&full_path), - "mkdir some_folder/another/deeper_one --p" + "mkdir some_folder/another/deeper_one --create-all" ); let mut expected = PathBuf::from(full_path); From ba6d62ea0c4b7b51e53eb00f402fc9f390fe86f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20N=2E=20Robalino?= Date: Wed, 7 Aug 2019 14:38:00 -0500 Subject: [PATCH 6/6] mkdir creates intermediary directories as required (the default). --create-all/--deep flag removed. --- README.md | 2 +- src/commands/cp.rs | 1 - src/commands/mkdir.rs | 28 ++++++++-------------------- tests/command_mkdir_tests.rs | 20 ++------------------ 4 files changed, 11 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 5cf02bf603..cb3902b81a 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Nu adheres closely to a set of goals that make up its design philosophy. As feat | cd path | Change to a new path | | cp source path | Copy files | | ls (path) | View the contents of the current or given path | -| mkdir path | Make directories, (to create intermediary directories append '--create-all') | +| mkdir path | Make directories, creates intermediary directories as required. | | date (--utc) | Get the current datetime | | ps | View current processes | | sys | View information about the current system | diff --git a/src/commands/cp.rs b/src/commands/cp.rs index 2f7c707fe6..de0f8129c9 100644 --- a/src/commands/cp.rs +++ b/src/commands/cp.rs @@ -154,7 +154,6 @@ pub fn cp(args: CommandArgs) -> Result { 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()).unwrap(); diff --git a/src/commands/mkdir.rs b/src/commands/mkdir.rs index 9bbd285eb0..5dccb28106 100644 --- a/src/commands/mkdir.rs +++ b/src/commands/mkdir.rs @@ -17,8 +17,7 @@ impl Command for Mkdir { } fn config(&self) -> CommandConfig { - let mut named: IndexMap = IndexMap::new(); - named.insert("create-all".to_string(), NamedType::Switch); + let named: IndexMap = IndexMap::new(); CommandConfig { name: self.name().to_string(), @@ -39,23 +38,12 @@ pub fn mkdir(args: CommandArgs) -> Result { _ => {} } - if !args.has("create-all") { - match std::fs::create_dir(full_path) { - Err(_) => Err(ShellError::labeled_error( - "No such file or directory", - "No such file or directory", - args.nth(0).unwrap().span(), - )), - Ok(_) => Ok(OutputStream::empty()), - } - } else { - match std::fs::create_dir_all(full_path) { - Err(reason) => Err(ShellError::labeled_error( - reason.to_string(), - reason.to_string(), - args.nth(0).unwrap().span(), - )), - Ok(_) => Ok(OutputStream::empty()), - } + match std::fs::create_dir_all(full_path) { + Err(reason) => Err(ShellError::labeled_error( + reason.to_string(), + reason.to_string(), + args.nth(0).unwrap().span(), + )), + Ok(_) => Ok(OutputStream::empty()), } } diff --git a/tests/command_mkdir_tests.rs b/tests/command_mkdir_tests.rs index 9d78365535..9cbb10755c 100644 --- a/tests/command_mkdir_tests.rs +++ b/tests/command_mkdir_tests.rs @@ -19,31 +19,15 @@ fn creates_directory() { } #[test] -fn error_if_intermediary_directory_doesnt_exist() { +fn creates_intermediary_directories() { let sandbox = Playground::setup_for("mkdir_test_2").test_dir_name(); let full_path = format!("{}/{}", Playground::root(), sandbox); - nu_error!( - output, - cwd(&full_path), - "mkdir some_folder/another/deeper_one" - ); - - assert!(output.contains("some_folder/another/deeper_one")); - assert!(output.contains("No such file or directory")); -} - -#[test] -fn creates_intermediary_directories_with_p_flag() { - let sandbox = Playground::setup_for("mkdir_test_3").test_dir_name(); - - let full_path = format!("{}/{}", Playground::root(), sandbox); - nu!( _output, cwd(&full_path), - "mkdir some_folder/another/deeper_one --create-all" + "mkdir some_folder/another/deeper_one" ); let mut expected = PathBuf::from(full_path);