diff options
Diffstat (limited to 'vendor/fs_extra/src/lib.rs')
-rw-r--r-- | vendor/fs_extra/src/lib.rs | 802 |
1 files changed, 802 insertions, 0 deletions
diff --git a/vendor/fs_extra/src/lib.rs b/vendor/fs_extra/src/lib.rs new file mode 100644 index 000000000..118643ab8 --- /dev/null +++ b/vendor/fs_extra/src/lib.rs @@ -0,0 +1,802 @@ +macro_rules! err { + ($text:expr, $kind:expr) => { + return Err(Error::new($kind, $text)) + }; + + ($text:expr) => { + err!($text, ErrorKind::Other) + }; +} + +/// The error type for fs_extra operations on files and directories. +pub mod error; +/// This module includes additional methods for working with files. +/// +/// One of the distinguishing features is receipt information +/// about process work with files. +/// +/// # Example +/// ```rust,ignore +/// use std::path::Path; +/// use std::{thread, time}; +/// use std::sync::mpsc::{self, TryRecvError}; +/// +/// extern crate fs_extra; +/// use fs_extra::file::*; +/// use fs_extra::error::*; +/// +/// fn example_copy() -> Result<()> { +/// let path_from = Path::new("./temp"); +/// let path_to = path_from.join("out"); +/// let test_file = (path_from.join("test_file.txt"), path_to.join("test_file.txt")); +/// +/// +/// fs_extra::dir::create_all(&path_from, true)?; +/// fs_extra::dir::create_all(&path_to, true)?; +/// +/// write_all(&test_file.0, "test_data")?; +/// assert!(test_file.0.exists()); +/// assert!(!test_file.1.exists()); +/// +/// +/// let options = CopyOptions { +/// buffer_size: 1, +/// ..Default::default() +/// } +/// let (tx, rx) = mpsc::channel(); +/// thread::spawn(move || { +/// let handler = |process_info: TransitProcess| { +/// tx.send(process_info).unwrap(); +/// thread::sleep(time::Duration::from_millis(500)); +/// }; +/// copy_with_progress(&test_file.0, &test_file.1, &options, handler).unwrap(); +/// assert!(test_file.0.exists()); +/// assert!(test_file.1.exists()); +/// +/// }); +/// loop { +/// match rx.try_recv() { +/// Ok(process_info) => { +/// println!("{} of {} bytes", +/// process_info.copied_bytes, +/// process_info.total_bytes); +/// } +/// Err(TryRecvError::Disconnected) => { +/// println!("finished"); +/// break; +/// } +/// Err(TryRecvError::Empty) => {} +/// } +/// } +/// Ok(()) +/// +/// } +/// +/// +/// fn main() { +/// example_copy(); +/// } +/// +/// ``` +pub mod file; + +/// This module includes additional methods for working with directories. +/// +/// One of the additional features is information +/// about process and recursion operations. +/// +/// # Example +/// ```rust,ignore +/// use std::path::Path; +/// use std::{thread, time}; +/// use std::sync::mpsc::{self, TryRecvError}; +/// +/// extern crate fs_extra; +/// use fs_extra::dir::*; +/// use fs_extra::error::*; +/// +/// fn example_copy() -> Result<()> { +/// +/// let path_from = Path::new("./temp"); +/// let path_to = path_from.join("out"); +/// let test_folder = path_from.join("test_folder"); +/// let dir = test_folder.join("dir"); +/// let sub = dir.join("sub"); +/// let file1 = dir.join("file1.txt"); +/// let file2 = sub.join("file2.txt"); +/// +/// create_all(&sub, true)?; +/// create_all(&path_to, true)?; +/// fs_extra::file::write_all(&file1, "content1")?; +/// fs_extra::file::write_all(&file2, "content2")?; +/// +/// assert!(dir.exists()); +/// assert!(sub.exists()); +/// assert!(file1.exists()); +/// assert!(file2.exists()); +/// +/// +/// let options = CopyOptions { +/// buffer_size: 1, +/// ..Default::default(), +/// }; +/// let (tx, rx) = mpsc::channel(); +/// thread::spawn(move || { +/// let handler = |process_info: TransitProcess| { +/// tx.send(process_info).unwrap(); +/// thread::sleep(time::Duration::from_millis(500)); +/// }; +/// copy_with_progress(&test_folder, &path_to, &options, handler).unwrap(); +/// }); +/// +/// loop { +/// match rx.try_recv() { +/// Ok(process_info) => { +/// println!("{} of {} bytes", +/// process_info.copied_bytes, +/// process_info.total_bytes); +/// } +/// Err(TryRecvError::Disconnected) => { +/// println!("finished"); +/// break; +/// } +/// Err(TryRecvError::Empty) => {} +/// } +/// } +/// Ok(()) +/// +/// } +/// fn main() { +/// example_copy(); +/// } +/// ``` +/// +pub mod dir; + +use crate::error::*; +use std::path::Path; + +/// Copies a list of directories and files to another place recursively. This function will +/// also copy the permission bits of the original files to destination files (not for +/// directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // copy dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// copy_items(&from_paths, "target", &options)?; +/// ``` +/// +pub fn copy_items<P, Q>(from: &[P], to: Q, options: &dir::CopyOptions) -> Result<u64> +where + P: AsRef<Path>, + Q: AsRef<Path>, +{ + let mut result: u64 = 0; + if options.content_only { + err!( + "Options 'content_only' not acccess for copy_items function", + ErrorKind::Other + ); + } + for item in from { + let item = item.as_ref(); + if item.is_dir() { + result += dir::copy(item, &to, options)?; + } else if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + let file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + ..Default::default() + }; + result += file::copy(item, to.as_ref().join(file_name), &file_options)?; + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } + + Ok(result) +} + +/// A structure which includes information about the current status of copying or moving a directory. +pub struct TransitProcess { + /// Already copied bytes + pub copied_bytes: u64, + /// All the bytes which should be copied or moved (dir size). + pub total_bytes: u64, + /// Copied bytes on this time for file. + pub file_bytes_copied: u64, + /// Size of currently copied file. + pub file_total_bytes: u64, + /// Name of currently copied file. + pub file_name: String, + /// Name of currently copied folder. + pub dir_name: String, + /// Transit state + pub state: dir::TransitState, +} + +impl Clone for TransitProcess { + fn clone(&self) -> TransitProcess { + TransitProcess { + copied_bytes: self.copied_bytes, + total_bytes: self.total_bytes, + file_bytes_copied: self.file_bytes_copied, + file_total_bytes: self.file_total_bytes, + file_name: self.file_name.clone(), + dir_name: self.dir_name.clone(), + state: self.state.clone(), + } + } +} + +/// Copies a list of directories and files to another place recursively, with +/// information about progress. This function will also copy the permission bits of the +/// original files to destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// ```rust,ignore +/// +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // copy dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// copy_items_with_progress(&from_paths, "target", &options, handle)?; +/// ``` +/// +pub fn copy_items_with_progress<P, Q, F>( + from: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result<u64> +where + P: AsRef<Path>, + Q: AsRef<Path>, + F: FnMut(TransitProcess) -> dir::TransitProcessResult, +{ + if options.content_only { + err!( + "Options 'content_only' not access for copy_items_with_progress function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + + let mut options = options.clone(); + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + let copied_bytes = result; + let dir_options = options.clone(); + let handler = |info: dir::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.state = info.state; + let result = progress_handler(info_process.clone()); + match result { + dir::TransitProcessResult::OverwriteAll => options.overwrite = true, + dir::TransitProcessResult::SkipAll => options.skip_exist = true, + _ => {} + } + result + }; + result += dir::copy_with_progress(item, &to, &dir_options, handler)?; + } else { + let mut file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let copied_bytes = result; + let file_name = to.as_ref().join(info_process.file_name.clone()); + let mut work = true; + + let mut result_copy: Result<u64>; + while work { + { + let handler = |info: file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + result_copy = + file::copy_with_progress(item, &file_name, &file_options, handler); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + dir::TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + } + + Ok(result) +} + +/// Moves a list of directories and files to another place recursively. This function will +/// also copy the permission bits of the original files to destination files (not for +/// directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // move dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// move_items(&from_paths, "target", &options)?; +/// ``` +/// +pub fn move_items<P, Q>(from_items: &[P], to: Q, options: &dir::CopyOptions) -> Result<u64> +where + P: AsRef<Path>, + Q: AsRef<Path>, +{ + if options.content_only { + err!( + "Options 'content_only' not access for move_items function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from_items { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + result += dir::move_dir(item, &to, options)?; + } else { + let file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let file_name = to.as_ref().join(info_process.file_name.clone()); + result += file::move_file(item, &file_name, &file_options)?; + } + } + + Ok(result) +} + +/// Moves a list of directories and files to another place recursively, with +/// information about progress. This function will also copy the permission bits of the +/// original files to destination files (not for directories). +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these case: +/// +/// * List `from` contains file or directory does not exist. +/// +/// * List `from` contains file or directory with invalid name. +/// +/// * The current process does not have the permission to access to file from `lists from` or +/// `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = dir::CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // move dir1 and file1.txt to target/dir1 and target/file1.txt +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// move_items_with_progress(&from_paths, "target", &options, handle)?; +/// ``` +/// +pub fn move_items_with_progress<P, Q, F>( + from_items: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result<u64> +where + P: AsRef<Path>, + Q: AsRef<Path>, + F: FnMut(TransitProcess) -> dir::TransitProcessResult, +{ + if options.content_only { + err!( + "Options 'content_only' not access for move_items_with_progress function", + ErrorKind::Other + ); + } + let mut total_size = 0; + let mut list_paths = Vec::new(); + for item in from_items { + let item = item.as_ref(); + total_size += dir::get_size(item)?; + list_paths.push(item); + } + + let mut result = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: total_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + dir_name: String::new(), + state: dir::TransitState::Normal, + }; + let mut options = options.clone(); + + for item in list_paths { + if item.is_dir() { + if let Some(dir_name) = item.components().last() { + if let Ok(dir_name) = dir_name.as_os_str().to_os_string().into_string() { + info_process.dir_name = dir_name; + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + let copied_bytes = result; + let dir_options = options.clone(); + let handler = |info: dir::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.state = info.state; + let result = progress_handler(info_process.clone()); + match result { + dir::TransitProcessResult::OverwriteAll => options.overwrite = true, + dir::TransitProcessResult::SkipAll => options.skip_exist = true, + _ => {} + } + result + }; + result += dir::move_dir_with_progress(item, &to, &dir_options, handler)?; + } else { + let mut file_options = file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = item.file_name() { + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = item.metadata()?.len(); + + let copied_bytes = result; + let file_name = to.as_ref().join(info_process.file_name.clone()); + let mut work = true; + + let mut result_copy: Result<u64>; + while work { + { + let handler = |info: file::TransitProcess| { + info_process.copied_bytes = copied_bytes + info.copied_bytes; + info_process.file_bytes_copied = info.copied_bytes; + progress_handler(info_process.clone()); + }; + result_copy = + file::move_file_with_progress(item, &file_name, &file_options, handler); + } + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => match err.kind { + ErrorKind::AlreadyExists => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + dir::TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + ErrorKind::PermissionDenied => { + let mut info_process = info_process.clone(); + info_process.state = dir::TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + dir::TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + dir::TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + dir::TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + dir::TransitProcessResult::Retry => {} + dir::TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + dir::TransitProcessResult::Abort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + _ => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + }, + } + } + } + } + Ok(result) +} + +/// Removes a list of files or directories. +/// +/// # Example +/// +/// ```rust,ignore +/// let mut from_paths = Vec::new(); +/// from_paths.push("source/dir1"); +/// from_paths.push("source/file.txt"); +/// +/// remove_items(&from_paths).unwrap(); +/// ``` +/// +pub fn remove_items<P>(from_items: &[P]) -> Result<()> +where + P: AsRef<Path>, +{ + for item in from_items { + let item = item.as_ref(); + if item.is_dir() { + dir::remove(item)?; + } else { + file::remove(item)? + } + } + + Ok(()) +} |