nu_command/filesystem/
umkdir.rs1#[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 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}