summaryrefslogtreecommitdiffstats
path: root/tokio
diff options
context:
space:
mode:
authorDmitri Shkurski <45545354+shkurski@users.noreply.github.com>2020-05-21 13:49:36 +0300
committerGitHub <noreply@github.com>2020-05-21 12:49:36 +0200
commit8fda5f1984e5c56548ea5bb0cf7d0f5c57c3a190 (patch)
tree334caa3afa736147218a55216c609b9305cf4adf /tokio
parent7cb5e3460c67bdfbe29fb6abf02e2d3cfc13625e (diff)
fs: add DirBuilder (#2524)
The initial idea was to implement a thin wrapper around an internally held `std::fs::DirBuilder` instance. This, however, didn't work due to `std::fs::DirBuilder` not having a Copy/Clone traits implemented, which are necessary for constructing an instance to move-capture it into a closure. Instead, we mirror `std::fs::DirBuilder` configuration by storing the `recursive` and (unix-only) `mode` parameters locally, which are then used to construct an `std::fs::DirBuilder` instance on-the-fly. This commit also mirrors the (unix-only) DirBuilderExt trait from std. Fixes: #2369
Diffstat (limited to 'tokio')
-rw-r--r--tokio/src/fs/dir_builder.rs117
-rw-r--r--tokio/src/fs/mod.rs3
-rw-r--r--tokio/src/fs/os/unix/dir_builder_ext.rs29
-rw-r--r--tokio/src/fs/os/unix/mod.rs3
-rw-r--r--tokio/tests/fs_dir.rs19
5 files changed, 170 insertions, 1 deletions
diff --git a/tokio/src/fs/dir_builder.rs b/tokio/src/fs/dir_builder.rs
new file mode 100644
index 00000000..8752a371
--- /dev/null
+++ b/tokio/src/fs/dir_builder.rs
@@ -0,0 +1,117 @@
+use crate::fs::asyncify;
+
+use std::io;
+use std::path::Path;
+
+/// A builder for creating directories in various manners.
+///
+/// Additional Unix-specific options are available via importing the
+/// [`DirBuilderExt`] trait.
+///
+/// This is a specialized version of [`std::fs::DirBuilder`] for usage on
+/// the Tokio runtime.
+///
+/// [std::fs::DirBuilder]: std::fs::DirBuilder
+/// [`DirBuilderExt`]: crate::fs::os::unix::DirBuilderExt
+#[derive(Debug, Default)]
+pub struct DirBuilder {
+ /// Indicates whether to create parent directories if they are missing.
+ recursive: bool,
+
+ /// Set the Unix mode for newly created directories.
+ #[cfg(unix)]
+ pub(super) mode: Option<u32>,
+}
+
+impl DirBuilder {
+ /// Creates a new set of options with default mode/security settings for all
+ /// platforms and also non-recursive.
+ ///
+ /// This is an async version of [`std::fs::DirBuilder::new`][std]
+ ///
+ /// [std]: std::fs::DirBuilder::new
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::DirBuilder;
+ ///
+ /// let builder = DirBuilder::new();
+ /// ```
+ pub fn new() -> Self {
+ Default::default()
+ }
+
+ /// Indicates whether to create directories recursively (including all parent directories).
+ /// Parents that do not exist are created with the same security and permissions settings.
+ ///
+ /// This option defaults to `false`.
+ ///
+ /// This is an async version of [`std::fs::DirBuilder::recursive`][std]
+ ///
+ /// [std]: std::fs::DirBuilder::recursive
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::DirBuilder;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.recursive(true);
+ /// ```
+ pub fn recursive(&mut self, recursive: bool) -> &mut Self {
+ self.recursive = recursive;
+ self
+ }
+
+ /// Creates the specified directory with the configured options.
+ ///
+ /// It is considered an error if the directory already exists unless
+ /// recursive mode is enabled.
+ ///
+ /// This is an async version of [`std::fs::DirBuilder::create`][std]
+ ///
+ /// [std]: std::fs::DirBuilder::create
+ ///
+ /// # Errors
+ ///
+ /// An error will be returned under the following circumstances:
+ ///
+ /// * Path already points to an existing file.
+ /// * Path already points to an existing directory and the mode is
+ /// non-recursive.
+ /// * The calling process doesn't have permissions to create the directory
+ /// or its missing parents.
+ /// * Other I/O error occurred.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::fs::DirBuilder;
+ /// use std::io;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// DirBuilder::new()
+ /// .recursive(true)
+ /// .create("/tmp/foo/bar/baz")
+ /// .await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ pub async fn create<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
+ let path = path.as_ref().to_owned();
+ 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);
+ }
+ }
+
+ asyncify(move || builder.create(path)).await
+ }
+}
diff --git a/tokio/src/fs/mod.rs b/tokio/src/fs/mod.rs
index 3eb03764..a2b062b1 100644
--- a/tokio/src/fs/mod.rs
+++ b/tokio/src/fs/mod.rs
@@ -33,6 +33,9 @@ pub use self::create_dir::create_dir;
mod create_dir_all;
pub use self::create_dir_all::create_dir_all;
+mod dir_builder;
+pub use self::dir_builder::DirBuilder;
+
mod file;
pub use self::file::File;
diff --git a/tokio/src/fs/os/unix/dir_builder_ext.rs b/tokio/src/fs/os/unix/dir_builder_ext.rs
new file mode 100644
index 00000000..e9a25b95
--- /dev/null
+++ b/tokio/src/fs/os/unix/dir_builder_ext.rs
@@ -0,0 +1,29 @@
+use crate::fs::dir_builder::DirBuilder;
+
+/// Unix-specific extensions to [`DirBuilder`].
+///
+/// [`DirBuilder`]: crate::fs::DirBuilder
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with.
+ ///
+ /// This option defaults to 0o777.
+ ///
+ /// # Examples
+ ///
+ ///
+ /// ```no_run
+ /// use tokio::fs::DirBuilder;
+ /// use tokio::fs::os::unix::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o775);
+ /// ```
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+impl DirBuilderExt for DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut Self {
+ self.mode = Some(mode);
+ self
+ }
+}
diff --git a/tokio/src/fs/os/unix/mod.rs b/tokio/src/fs/os/unix/mod.rs
index 3b0bec38..030eaf8a 100644
--- a/tokio/src/fs/os/unix/mod.rs
+++ b/tokio/src/fs/os/unix/mod.rs
@@ -2,3 +2,6 @@
mod symlink;
pub use self::symlink::symlink;
+
+mod dir_builder_ext;
+pub use self::dir_builder_ext::DirBuilderExt;
diff --git a/tokio/tests/fs_dir.rs b/tokio/tests/fs_dir.rs
index eaff59da..6355ef05 100644
--- a/tokio/tests/fs_dir.rs
+++ b/tokio/tests/fs_dir.rs
@@ -2,7 +2,7 @@
#![cfg(feature = "full")]
use tokio::fs;
-use tokio_test::assert_ok;
+use tokio_test::{assert_err, assert_ok};
use std::sync::{Arc, Mutex};
use tempfile::tempdir;
@@ -29,6 +29,23 @@ async fn create_all() {
}
#[tokio::test]
+async fn build_dir() {
+ let base_dir = tempdir().unwrap();
+ let new_dir = base_dir.path().join("foo").join("bar");
+ let new_dir_2 = new_dir.clone();
+
+ assert_ok!(fs::DirBuilder::new().recursive(true).create(new_dir).await);
+
+ assert!(new_dir_2.is_dir());
+ assert_err!(
+ fs::DirBuilder::new()
+ .recursive(false)
+ .create(new_dir_2)
+ .await
+ );
+}
+
+#[tokio::test]
async fn remove() {
let base_dir = tempdir().unwrap();
let new_dir = base_dir.path().join("foo");