nu_command/filesystem/
umkdir.rs

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