Skip to main content

nu_command/filesystem/
umkdir.rs

1use 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        // setup the uutils error translation
59        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}