mirror of
				https://github.com/tokio-rs/tokio.git
				synced 2025-11-03 14:02:47 +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;
 | 
					mod create_dir_all;
 | 
				
			||||||
pub use self::create_dir_all::create_dir_all;
 | 
					pub use self::create_dir_all::create_dir_all;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod dir_builder;
 | 
				
			||||||
 | 
					pub use self::dir_builder::DirBuilder;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod file;
 | 
					mod file;
 | 
				
			||||||
pub use self::file::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;
 | 
					mod symlink;
 | 
				
			||||||
pub use self::symlink::symlink;
 | 
					pub use self::symlink::symlink;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mod dir_builder_ext;
 | 
				
			||||||
 | 
					pub use self::dir_builder_ext::DirBuilderExt;
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,7 @@
 | 
				
			|||||||
#![cfg(feature = "full")]
 | 
					#![cfg(feature = "full")]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use tokio::fs;
 | 
					use tokio::fs;
 | 
				
			||||||
use tokio_test::assert_ok;
 | 
					use tokio_test::{assert_err, assert_ok};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::sync::{Arc, Mutex};
 | 
					use std::sync::{Arc, Mutex};
 | 
				
			||||||
use tempfile::tempdir;
 | 
					use tempfile::tempdir;
 | 
				
			||||||
@ -28,6 +28,23 @@ async fn create_all() {
 | 
				
			|||||||
    assert!(new_dir_2.is_dir());
 | 
					    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]
 | 
					#[tokio::test]
 | 
				
			||||||
async fn remove() {
 | 
					async fn remove() {
 | 
				
			||||||
    let base_dir = tempdir().unwrap();
 | 
					    let base_dir = tempdir().unwrap();
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user