nu_command/filesystem/
umkdir.rs

1#[allow(deprecated)]
2use nu_engine::{command_prelude::*, current_dir};
3use nu_protocol::NuGlob;
4use uu_mkdir::mkdir;
5#[cfg(not(windows))]
6use uucore::mode;
7use uucore::{localized_help_template, translate};
8
9#[derive(Clone)]
10pub struct UMkdir;
11
12const IS_RECURSIVE: bool = true;
13const DEFAULT_MODE: u32 = 0o777;
14
15#[cfg(not(windows))]
16fn get_mode() -> u32 {
17    !mode::get_umask() & DEFAULT_MODE
18}
19
20#[cfg(windows)]
21fn get_mode() -> u32 {
22    DEFAULT_MODE
23}
24
25impl Command for UMkdir {
26    fn name(&self) -> &str {
27        "mkdir"
28    }
29
30    fn description(&self) -> &str {
31        "Create directories, with intermediary directories if required using uutils/coreutils mkdir."
32    }
33
34    fn search_terms(&self) -> Vec<&str> {
35        vec!["directory", "folder", "create", "make_dirs", "coreutils"]
36    }
37
38    fn signature(&self) -> Signature {
39        Signature::build("mkdir")
40            .input_output_types(vec![(Type::Nothing, Type::Nothing)])
41            .rest(
42                "rest",
43                SyntaxShape::OneOf(vec![SyntaxShape::GlobPattern, SyntaxShape::Directory]),
44                "The name(s) of the path(s) to create.",
45            )
46            .switch(
47                "verbose",
48                "print a message for each created directory.",
49                Some('v'),
50            )
51            .category(Category::FileSystem)
52    }
53
54    fn run(
55        &self,
56        engine_state: &EngineState,
57        stack: &mut Stack,
58        call: &Call,
59        _input: PipelineData,
60    ) -> Result<PipelineData, ShellError> {
61        // setup the uutils error translation
62        let _ = localized_help_template("mkdir");
63
64        #[allow(deprecated)]
65        let cwd = current_dir(engine_state, stack)?;
66        let mut directories = call
67            .rest::<Spanned<NuGlob>>(engine_state, stack, 0)?
68            .into_iter()
69            .map(|dir| nu_path::expand_path_with(dir.item.as_ref(), &cwd, dir.item.is_expand()))
70            .peekable();
71
72        let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
73
74        if directories.peek().is_none() {
75            return Err(ShellError::MissingParameter {
76                param_name: "requires directory paths".to_string(),
77                span: call.head,
78            });
79        }
80
81        let config = uu_mkdir::Config {
82            recursive: IS_RECURSIVE,
83            mode: get_mode(),
84            verbose: is_verbose,
85            set_selinux_context: false,
86            context: None,
87        };
88
89        let mut verbose_out = String::new();
90        for dir in directories {
91            if let Err(error) = mkdir(&dir, &config) {
92                return Err(ShellError::GenericError {
93                    error: format!("{error}"),
94                    msg: translate!(&error.to_string()),
95                    span: None,
96                    help: None,
97                    inner: vec![],
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}