nu_command/filesystem/
umkdir.rs1use 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 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}