Skip to main content

nu_command/filesystem/
umkdir.rs

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