nu_command/filesystem/
umkdir.rs1use nu_engine::command_prelude::*;
2use nu_protocol::{NuGlob, shell_error::generic::GenericError};
3use uu_mkdir::mkdir;
4use uucore::{localized_help_template, translate};
5
6#[derive(Clone)]
7pub struct UMkdir;
8
9const IS_RECURSIVE: bool = true;
10const DEFAULT_MODE: u32 = 0o777;
11
12#[cfg(target_family = "unix")]
13fn get_mode() -> u32 {
14 !nu_system::get_umask() & DEFAULT_MODE
15}
16
17#[cfg(not(target_family = "unix"))]
18fn get_mode() -> u32 {
19 DEFAULT_MODE
20}
21
22impl Command for UMkdir {
23 fn name(&self) -> &str {
24 "mkdir"
25 }
26
27 fn description(&self) -> &str {
28 "Create directories, with intermediary directories if required using uutils/coreutils mkdir."
29 }
30
31 fn search_terms(&self) -> Vec<&str> {
32 vec![
33 "directory",
34 "folder",
35 "create",
36 "make_dirs",
37 "coreutils",
38 "md",
39 ]
40 }
41
42 fn signature(&self) -> Signature {
43 Signature::build("mkdir")
44 .input_output_types(vec![(Type::Nothing, Type::Nothing)])
45 .rest(
46 "rest",
47 SyntaxShape::OneOf(vec![SyntaxShape::GlobPattern, SyntaxShape::Directory]),
48 "The name(s) of the path(s) to create.",
49 )
50 .switch(
51 "verbose",
52 "Print a message for each created directory.",
53 Some('v'),
54 )
55 .category(Category::FileSystem)
56 }
57
58 fn run(
59 &self,
60 engine_state: &EngineState,
61 stack: &mut Stack,
62 call: &Call,
63 _input: PipelineData,
64 ) -> Result<PipelineData, ShellError> {
65 let _ = localized_help_template("mkdir");
67
68 let cwd = engine_state.cwd(Some(stack))?.into_std_path_buf();
69 let mut directories = call
70 .rest::<Spanned<NuGlob>>(engine_state, stack, 0)?
71 .into_iter()
72 .map(|dir| nu_path::expand_path_with(dir.item.as_ref(), &cwd, dir.item.is_expand()))
73 .peekable();
74
75 let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
76
77 if directories.peek().is_none() {
78 return Err(ShellError::MissingParameter {
79 param_name: "requires directory paths".to_string(),
80 span: call.head,
81 });
82 }
83
84 let config = uu_mkdir::Config {
85 recursive: IS_RECURSIVE,
86 mode: get_mode(),
87 verbose: is_verbose,
88 set_security_context: false,
89 context: None,
90 };
91
92 let mut verbose_out = String::new();
93 for dir in directories {
94 if let Err(error) = mkdir(&dir, &config) {
95 return Err(ShellError::Generic(GenericError::new_internal(
96 format!("{error}"),
97 translate!(&error.to_string()),
98 )));
99 }
100 if is_verbose {
101 verbose_out.push_str(
102 format!(
103 "{} ",
104 &dir.as_path()
105 .file_name()
106 .unwrap_or_default()
107 .to_string_lossy()
108 )
109 .as_str(),
110 );
111 }
112 }
113
114 if is_verbose {
115 Ok(PipelineData::value(
116 Value::string(verbose_out.trim(), call.head),
117 None,
118 ))
119 } else {
120 Ok(PipelineData::empty())
121 }
122 }
123
124 fn examples(&self) -> Vec<Example<'_>> {
125 vec![
126 Example {
127 description: "Make a directory named foo.",
128 example: "mkdir foo",
129 result: None,
130 },
131 Example {
132 description: "Make multiple directories and show the paths created.",
133 example: "mkdir -v foo/bar foo2",
134 result: None,
135 },
136 ]
137 }
138}