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 {