diff --git a/src/install/install.rs b/src/install/install.rs index efb4f28bd..e5ea969fa 100644 --- a/src/install/install.rs +++ b/src/install/install.rs @@ -31,8 +31,13 @@ pub struct Behaviour { #[derive(Clone, Eq, PartialEq)] pub enum MainFunction { + /// Display version information. Version, + /// Display help, including command line arguments. Help, + /// Create directories + Directory, + /// Install files to locations (primary functionality) Standard } @@ -85,6 +90,9 @@ pub fn uumain(args: Vec) -> i32 { help(&usage); 0 }, + MainFunction::Directory => { + directory(&paths[..], behaviour) + }, MainFunction::Standard => { standard(&paths[..], behaviour) } @@ -109,8 +117,7 @@ fn opts() -> getopts::Options { opts.optflag("C", "compare", "(unimplemented) compare each pair of source and destination\n \ files, and in some cases, do not modify the destination at all"); - // TODO implement flag - opts.optflag("d", "directory", "(unimplemented) treat all arguments as directory names;\n \ + opts.optflag("d", "directory", "treat all arguments as directory names;\n \ create all components of the specified directories"); @@ -182,8 +189,6 @@ fn check_unimplemented(matches: &getopts::Matches) -> Result<(), &str> { Err("-b") } else if matches.opt_present("compare") { Err("--compare, -C") - } else if matches.opt_present("directory") { - Err("--directory, -d") } else if matches.opt_present("D") { Err("-D") } else if matches.opt_present("group") { @@ -228,6 +233,8 @@ fn behaviour(matches: &getopts::Matches) -> Result { MainFunction::Version } else if matches.opt_present("help") { MainFunction::Help + } else if matches.opt_present("directory") { + MainFunction::Directory } else { MainFunction::Standard }; @@ -261,6 +268,41 @@ fn help(usage: &str) { {2}", NAME, VERSION, usage); } +/// Creates directories. +/// +/// GNU man pages describe this functionality as creating 'all components of +/// the specified directories'. +/// +/// Returns an integer intended as a program return code. +/// +fn directory(paths: &[PathBuf], b: Behaviour) -> i32 { + if paths.len() < 1 { + println!("{} with -d requires at least one argument.", NAME); + 1 + } else { + let mut all_successful = true; + + for directory in paths.iter() { + let path = directory.as_path(); + + if path.exists() { + show_info!("cannot create directory '{}': File exists", path.display()); + all_successful = false; + } + + if let Err(e) = fs::create_dir(directory) { + show_info!("{}: {}", path.display(), e.to_string()); + all_successful = false; + } + + if b.verbose { + show_info!("created directory '{}'", path.display()); + } + } + if all_successful { 0 } else { 1 } + } +} + /// Perform an install, given a list of paths and behaviour. /// /// Returns an integer intended as a program return code. diff --git a/tests/test_install.rs b/tests/test_install.rs index 0058f763a..f47b6a37d 100644 --- a/tests/test_install.rs +++ b/tests/test_install.rs @@ -14,8 +14,9 @@ fn test_install_help() { let (at, mut ucmd) = testing(UTIL_NAME); let result = ucmd.arg("--help").run(); - assert_empty_stderr!(result); + assert!(result.success); + assert_empty_stderr!(result); assert!(result.stdout.contains("Usage:")); } @@ -32,8 +33,8 @@ fn test_install_basic() { at.mkdir(dir); let result = ucmd.arg(file1).arg(file2).arg(dir).run(); - assert_empty_stderr!(result); assert!(result.success); + assert_empty_stderr!(result); assert!(at.file_exists(file1)); assert!(at.file_exists(file2)); @@ -57,3 +58,34 @@ fn test_install_unimplemented_arg() { assert!(!at.file_exists(&format!("{}/{}", dir, file))); } + +#[test] +fn test_install_component_directories() { + let (at, mut ucmd) = testing(UTIL_NAME); + let component1 = "test_install_target_dir_component_c1"; + let component2 = "test_install_target_dir_component_c2"; + let component3 = "test_install_target_dir_component_c3"; + let directories_arg = "-d"; + + let result = ucmd.arg(directories_arg).arg(component1).arg(component2).arg(component3).run(); + + assert!(result.success); + assert_empty_stderr!(result); + + assert!(at.dir_exists(component1)); + assert!(at.dir_exists(component2)); + assert!(at.dir_exists(component3)); +} + +#[test] +fn test_install_component_directories_failing() { + let (at, mut ucmd) = testing(UTIL_NAME); + let component = "test_install_target_dir_component_d1"; + let directories_arg = "-d"; + + at.mkdir(component); + let result = ucmd.arg(directories_arg).arg(component).run(); + + assert!(!result.success); + assert!(result.stderr.contains("File exists")); +}