1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use std::path::Path;

use cfg_if::cfg_if;

use crate::future::Future;
use crate::io;
use crate::task::blocking;

/// A builder for creating directories with configurable options.
///
/// For Unix-specific options, import the [`os::unix::fs::DirBuilderExt`] trait.
///
/// This type is an async version of [`std::fs::DirBuilder`].
///
/// [`os::unix::fs::DirBuilderExt`]: ../os/unix/fs/trait.DirBuilderExt.html
/// [`std::fs::DirBuilder`]: https://doc.rust-lang.org/std/fs/struct.DirBuilder.html
#[derive(Debug, Default)]
pub struct DirBuilder {
    /// Set to `true` if non-existent parent directories should be created.
    recursive: bool,

    /// Unix mode for newly created directories.
    #[cfg(unix)]
    mode: Option<u32>,
}

impl DirBuilder {
    /// Creates a blank set of options.
    ///
    /// The [`recursive`] option is initially set to `false`.
    ///
    /// [`recursive`]: #method.recursive
    ///
    /// # Examples
    ///
    /// ```
    /// use async_std::fs::DirBuilder;
    ///
    /// let builder = DirBuilder::new();
    /// ```
    pub fn new() -> DirBuilder {
        #[cfg(not(unix))]
        let builder = DirBuilder { recursive: false };

        #[cfg(unix)]
        let builder = DirBuilder {
            recursive: false,
            mode: None,
        };

        builder
    }

    /// Sets the option for recursive mode.
    ///
    /// When set to `true`, this option means all parent directories should be created recursively
    /// if they don't exist. Parents are created with the same permissions as the final directory.
    ///
    /// This option is initially set to `false`.
    ///
    /// # Examples
    ///
    /// ```
    /// use async_std::fs::DirBuilder;
    ///
    /// let mut builder = DirBuilder::new();
    /// builder.recursive(true);
    /// ```
    pub fn recursive(&mut self, recursive: bool) -> &mut Self {
        self.recursive = recursive;
        self
    }

    /// Creates a directory with the configured options.
    ///
    /// It is considered an error if the directory already exists unless recursive mode is enabled.
    ///
    /// # Errors
    ///
    /// An error will be returned in the following situations:
    ///
    /// * `path` already points to an existing file or directory.
    /// * The current process lacks permissions to create the directory or its missing parents.
    /// * Some other I/O error occurred.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// # fn main() -> std::io::Result<()> { async_std::task::block_on(async {
    /// #
    /// use async_std::fs::DirBuilder;
    ///
    /// DirBuilder::new()
    ///     .recursive(true)
    ///     .create("./some/directory")
    ///     .await?;
    /// #
    /// # Ok(()) }) }
    /// ```
    pub fn create<P: AsRef<Path>>(&self, path: P) -> impl Future<Output = io::Result<()>> {
        let mut builder = std::fs::DirBuilder::new();
        builder.recursive(self.recursive);

        #[cfg(unix)]
        {
            if let Some(mode) = self.mode {
                std::os::unix::fs::DirBuilderExt::mode(&mut builder, mode);
            }
        }

        let path = path.as_ref().to_owned();
        async move { blocking::spawn(async move { builder.create(path) }).await }
    }
}

cfg_if! {
    if #[cfg(feature = "docs")] {
        use crate::os::unix::fs::DirBuilderExt;
    } else if #[cfg(unix)] {
        use std::os::unix::fs::DirBuilderExt;
    }
}

#[cfg_attr(feature = "docs", doc(cfg(unix)))]
cfg_if! {
    if #[cfg(any(unix, feature = "docs"))] {
        impl DirBuilderExt for DirBuilder {
            fn mode(&mut self, mode: u32) -> &mut Self {
                self.mode = Some(mode);
                self
            }
        }
    }
}