nu_command/filesystem/
umkdir.rs1use nu_engine::command_prelude::*;
2use nu_protocol::NuGlob;
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!["directory", "folder", "create", "make_dirs", "coreutils"]
33 }
34
35 fn signature(&self) -> Signature {
36 Signature::build("mkdir")
37 .input_output_types(vec![(Type::Nothing, Type::Nothing)])
38 .rest(
39 "rest",
40 SyntaxShape::OneOf(vec![SyntaxShape::GlobPattern, SyntaxShape::Directory]),
41 "The name(s) of the path(s) to create.",
42 )
43 .switch(
44 "verbose",
45 "Print a message for each created directory.",
46 Some('v'),
47 )
48 .category(Category::FileSystem)
49 }
50
51 fn run(
52 &self,
53 engine_state: &EngineState,
54 stack: &mut Stack,
55 call: &Call,
56 _input: PipelineData,
57 ) -> Result<PipelineData, ShellError> {
58 let _ = localized_help_template("mkdir");
60
61 let cwd = engine_state.cwd(Some(stack))?.into_std_path_buf();
62 let mut directories = call
63 .rest::<Spanned<NuGlob>>(engine_state, stack, 0)?
64 .into_iter()
65 .map(|dir| nu_path::expand_path_with(dir.item.as_ref(), &cwd, dir.item.is_expand()))
66 .peekable();
67
68 let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
69
70 if directories.peek().is_none() {
71 return Err(ShellError::MissingParameter {
72 param_name: "requires directory paths".to_string(),
73 span: call.head,
74 });
75 }
76
77 let config = uu_mkdir::Config {
78 recursive: IS_RECURSIVE,
79 mode: get_mode(),
80 verbose: is_verbose,
81 set_security_context: false,
82 context: None,
83 };
84
85 let mut verbose_out = String::new();
86 for dir in directories {
87 if let Err(error) = mkdir(&dir, &config) {
88 return Err(ShellError::GenericError {
89 error: format!("{error}"),
90 msg: translate!(&error.to_string()),
91 span: None,
92 help: None,
93 inner: vec![],
94 });
95 }
96 if is_verbose {
97 verbose_out.push_str(
98 format!(
99 "{} ",
100 &dir.as_path()
101 .file_name()
102 .unwrap_or_default()
103 .to_string_lossy()
104 )
105 .as_str(),
106 );
107 }
108 }
109
110 if is_verbose {
111 Ok(PipelineData::value(
112 Value::string(verbose_out.trim(), call.head),
113 None,
114 ))
115 } else {
116 Ok(PipelineData::empty())
117 }
118 }
119
120 fn examples(&self) -> Vec<Example<'_>> {
121 vec![
122 Example {
123 description: "Make a directory named foo.",
124 example: "mkdir foo",
125 result: None,
126 },
127 Example {
128 description: "Make multiple directories and show the paths created.",
129 example: "mkdir -v foo/bar foo2",
130 result: None,
131 },
132 ]
133 }
134}