mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-09-28 12:10:37 +00:00
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
This commit is contained in:
parent
7cb5e3460c
commit
8fda5f1984
117
tokio/src/fs/dir_builder.rs
Normal file
117
tokio/src/fs/dir_builder.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
|
29
tokio/src/fs/os/unix/dir_builder_ext.rs
Normal file
29
tokio/src/fs/os/unix/dir_builder_ext.rs
Normal file
@ -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
|
||||
}
|
||||
}
|
@ -2,3 +2,6 @@
|
||||
|
||||
mod symlink;
|
||||
pub use self::symlink::symlink;
|
||||
|
||||
mod dir_builder_ext;
|
||||
pub use self::dir_builder_ext::DirBuilderExt;
|
||||
|
@ -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;
|
||||
@ -28,6 +28,23 @@ async fn create_all() {
|
||||
assert!(new_dir_2.is_dir());
|
||||
}
|
||||
|
||||
#[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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user