From d1b2d29528b7794b41e66fc2136e395a02f8529b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Thu, 30 May 2024 05:59:35 +0200 Subject: Merging upstream version 1.73.0+dfsg1. Signed-off-by: Daniel Baumann --- vendor/fs_extra/src/dir.rs | 1398 ++++++++++++++++++++++++++++++++++++++++++ vendor/fs_extra/src/error.rs | 158 +++++ vendor/fs_extra/src/file.rs | 413 +++++++++++++ vendor/fs_extra/src/lib.rs | 802 ++++++++++++++++++++++++ 4 files changed, 2771 insertions(+) create mode 100644 vendor/fs_extra/src/dir.rs create mode 100644 vendor/fs_extra/src/error.rs create mode 100644 vendor/fs_extra/src/file.rs create mode 100644 vendor/fs_extra/src/lib.rs (limited to 'vendor/fs_extra/src') diff --git a/vendor/fs_extra/src/dir.rs b/vendor/fs_extra/src/dir.rs new file mode 100644 index 000000000..a5d111249 --- /dev/null +++ b/vendor/fs_extra/src/dir.rs @@ -0,0 +1,1398 @@ +use crate::error::*; +use std::collections::{HashMap, HashSet}; +use std::fs::{create_dir, create_dir_all, read_dir, remove_dir_all, Metadata}; +use std::path::{Path, PathBuf}; +use std::time::SystemTime; + +/// Options and flags which can be used to configure how a file will be copied or moved. +#[derive(Clone)] +pub struct CopyOptions { + /// Overwrite existing files if true (default: false). + pub overwrite: bool, + /// Skip existing files if true (default: false). + pub skip_exist: bool, + /// Buffer size that specifies the amount of bytes to be moved or copied before the progress handler is called. This only affects functions with progress handlers. (default: 64000) + pub buffer_size: usize, + /// Recursively copy a directory with a new name or place it inside the destination (default: false, same behaviors as cp -r on Unix) + pub copy_inside: bool, + /// Copy only contents without a creating a new folder in the destination folder (default: false). + pub content_only: bool, + /// Sets levels reading. Set 0 for read all directory folder (default: 0). + /// + /// Warning: Work only for copy operations! + pub depth: u64, +} + +impl CopyOptions { + /// Initialize struct CopyOptions with default value. + /// + /// ```rust,ignore + /// overwrite: false + /// + /// skip_exist: false + /// + /// buffer_size: 64000 // 64kb + /// + /// copy_inside: false + /// ``` + pub fn new() -> CopyOptions { + CopyOptions { + overwrite: false, + skip_exist: false, + buffer_size: 64000, // 64kb + copy_inside: false, + content_only: false, + depth: 0, + } + } + + /// Overwrite existing files if true. + pub fn overwrite(mut self, overwrite: bool) -> Self { + self.overwrite = overwrite; + self + } + + /// Skip existing files if true. + pub fn skip_exist(mut self, skip_exist: bool) -> Self { + self.skip_exist = skip_exist; + self + } + + /// Buffer size that specifies the amount of bytes to be moved or copied before the progress handler is called. This only affects functions with progress handlers. + pub fn buffer_size(mut self, buffer_size: usize) -> Self { + self.buffer_size = buffer_size; + self + } + + /// Recursively copy a directory with a new name or place it inside the destination (default: false, same behaviors as cp -r on Unix) + pub fn copy_inside(mut self, copy_inside: bool) -> Self { + self.copy_inside = copy_inside; + self + } + + /// Copy only contents without a creating a new folder in the destination folder. + pub fn content_only(mut self, content_only: bool) -> Self { + self.content_only = content_only; + self + } + + /// Sets levels reading. Set 0 for read all directory folder + pub fn depth(mut self, depth: u64) -> Self { + self.depth = depth; + self + } +} + +impl Default for CopyOptions { + fn default() -> Self { + CopyOptions::new() + } +} + +// Options and flags which can be used to configure how to read a directory. +#[derive(Clone, Default)] +pub struct DirOptions { + /// Sets levels reading. Set value 0 for read all directory folder. By default 0. + pub depth: u64, +} + +impl DirOptions { + /// Initialize struct DirOptions with default value. + pub fn new() -> DirOptions { + Default::default() + } +} + +/// A structure which include information about directory +pub struct DirContent { + /// Directory size in bytes. + pub dir_size: u64, + /// List all files directory and sub directories. + pub files: Vec, + /// List all folders and sub folders directory. + pub directories: Vec, +} + +/// A structure which include information about the current status of the copy or move directory. +pub struct TransitProcess { + /// Copied bytes on this time for folder + pub copied_bytes: u64, + /// All the bytes which should to copy or move (dir size). + pub total_bytes: u64, + /// Copied bytes on this time for file. + pub file_bytes_copied: u64, + /// Size current copied file. + pub file_total_bytes: u64, + /// Name current copied file. + pub file_name: String, + /// Transit state + pub state: TransitState, +} + +/// +#[derive(Hash, Eq, PartialEq, Clone)] +pub enum TransitState { + /// Standard state. + Normal, + /// Pause state when destination path exists. + Exists, + /// Pause state when current process does not have the permission to access from or to + /// path. + NoAccess, +} + +/// Available returns codes for user decide +pub enum TransitProcessResult { + /// Rewrite exist file or directory. + Overwrite, + /// Rewrite for all exist files or directories. + OverwriteAll, + /// Skip current problem file or directory. + Skip, + /// Skip for all problems file or directory. + SkipAll, + /// Retry current operation. + Retry, + /// Abort current operation. + Abort, + /// Continue execute process if process not have error and abort if process content error. + ContinueOrAbort, +} + +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(), + state: self.state.clone(), + } + } +} + +/// Available attributes for get information about directory entry. +#[derive(Hash, Eq, PartialEq, Clone)] +pub enum DirEntryAttr { + /// Folder name or file name without extension. + Name, + /// File extension. + Ext, + /// Folder name or file name with extension. + FullName, + /// Path to file or directory. + Path, + /// Dos path to file or directory. + DosPath, + /// File size in bytes. + FileSize, + /// Size file or directory in bytes. + /// + /// `Attention!`: This operation very expensive and sometimes required additional rights. + Size, + /// Return whether entry is directory or not. + IsDir, + /// Return whether entry is file or not. + IsFile, + /// Last modification time for directory entry. + Modified, + /// Last access time for directory entry. + Accessed, + /// Created time for directory entry. + /// + /// `Attention!`: Not supported UNIX platform. + Created, + /// Return or not return base information target folder. + BaseInfo, +} + +/// Available types for directory entry. +pub enum DirEntryValue { + /// String type + String(String), + /// Boolean type + Boolean(bool), + /// SystemTime type + SystemTime(SystemTime), + /// u64 type + U64(u64), +} + +/// Result returned by the `ls` function. +pub struct LsResult { + /// Base folder target path + pub base: HashMap, + /// Collection directory entry with information. + pub items: Vec>, +} + +/// Returned information about directory entry with information which you choose in config. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to directory. +/// +/// * `config` - Set attributes which you want see inside return data. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{get_details_entry, DirEntryAttr}; +/// use std::collections::{HashMap, HashSet}; +/// +/// let mut config = HashSet::new(); +/// config.insert(DirEntryAttr::Name); +/// config.insert(DirEntryAttr::Size); +/// +/// let entry_info = get_details_entry("test", &config); +/// assert_eq!(2, entry_info.len()); +/// ``` +pub fn get_details_entry

( + path: P, + config: &HashSet, +) -> Result> +where + P: AsRef, +{ + let path = path.as_ref(); + let metadata = path.metadata()?; + get_details_entry_with_meta(path, config, metadata) +} + +fn get_details_entry_with_meta

( + path: P, + config: &HashSet, + metadata: Metadata, +) -> Result> +where + P: AsRef, +{ + let path = path.as_ref(); + let mut item = HashMap::new(); + if config.contains(&DirEntryAttr::Name) { + if metadata.is_dir() { + if let Some(file_name) = path.file_name() { + item.insert( + DirEntryAttr::Name, + DirEntryValue::String(file_name.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Name, DirEntryValue::String(String::new())); + } + } else if let Some(file_stem) = path.file_stem() { + item.insert( + DirEntryAttr::Name, + DirEntryValue::String(file_stem.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Name, DirEntryValue::String(String::new())); + } + } + if config.contains(&DirEntryAttr::Ext) { + if let Some(value) = path.extension() { + item.insert( + DirEntryAttr::Ext, + DirEntryValue::String(value.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::Ext, DirEntryValue::String(String::from(""))); + } + } + if config.contains(&DirEntryAttr::FullName) { + if let Some(file_name) = path.file_name() { + item.insert( + DirEntryAttr::FullName, + DirEntryValue::String(file_name.to_os_string().into_string()?), + ); + } else { + item.insert(DirEntryAttr::FullName, DirEntryValue::String(String::new())); + } + } + if config.contains(&DirEntryAttr::Path) { + let mut result_path: PathBuf; + match path.canonicalize() { + Ok(new_path) => { + result_path = new_path; + } + Err(_) => { + if let Some(parent_path) = path.parent() { + if let Some(name) = path.file_name() { + result_path = parent_path.canonicalize()?; + result_path.push(name); + } else { + err!("Error get part name path", ErrorKind::Other); + } + } else { + err!("Error get parent path", ErrorKind::Other); + } + } + } + let mut path = result_path.as_os_str().to_os_string().into_string()?; + if path.find("\\\\?\\") == Some(0) { + path = path[4..].to_string(); + } + item.insert(DirEntryAttr::Path, DirEntryValue::String(path)); + } + if config.contains(&DirEntryAttr::DosPath) { + let mut result_path: PathBuf; + match path.canonicalize() { + Ok(new_path) => { + result_path = new_path; + } + Err(_) => { + if let Some(parent_path) = path.parent() { + if let Some(name) = path.file_name() { + result_path = parent_path.canonicalize()?; + result_path.push(name); + } else { + err!("Error get part name path", ErrorKind::Other); + } + } else { + err!("Error get parent path", ErrorKind::Other); + } + } + } + let path = result_path.as_os_str().to_os_string().into_string()?; + item.insert(DirEntryAttr::DosPath, DirEntryValue::String(path)); + } + if config.contains(&DirEntryAttr::Size) { + item.insert(DirEntryAttr::Size, DirEntryValue::U64(get_size(&path)?)); + } + if config.contains(&DirEntryAttr::FileSize) { + item.insert(DirEntryAttr::FileSize, DirEntryValue::U64(metadata.len())); + } + if config.contains(&DirEntryAttr::IsDir) { + item.insert( + DirEntryAttr::IsDir, + DirEntryValue::Boolean(metadata.is_dir()), + ); + } + if config.contains(&DirEntryAttr::IsFile) { + item.insert( + DirEntryAttr::IsFile, + DirEntryValue::Boolean(metadata.is_file()), + ); + } + if config.contains(&DirEntryAttr::Modified) { + item.insert( + DirEntryAttr::Modified, + DirEntryValue::SystemTime(metadata.modified()?), + ); + } + if config.contains(&DirEntryAttr::Accessed) { + item.insert( + DirEntryAttr::Accessed, + DirEntryValue::SystemTime(metadata.accessed()?), + ); + } + if config.contains(&DirEntryAttr::Created) { + item.insert( + DirEntryAttr::Created, + DirEntryValue::SystemTime(metadata.created()?), + ); + } + Ok(item) +} + +/// Returns a collection of directory entries with attributes specifying the information that should be returned. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to directory. +/// +/// * `config` - Set attributes which you want see in return data. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{ls, DirEntryAttr, LsResult}; +/// use std::collections::HashSet; +/// +/// let mut config = HashSet::new(); +/// config.insert(DirEntryAttr::Name); +/// config.insert(DirEntryAttr::Size); +/// config.insert(DirEntryAttr::BaseInfo); +/// +/// let result = ls("test", &config); +/// assert_eq!(2, ls_result.items.len()); +/// assert_eq!(2, ls_result.base.len()); +/// ``` +pub fn ls

(path: P, config: &HashSet) -> Result +where + P: AsRef, +{ + let mut items = Vec::new(); + let path = path.as_ref(); + if !path.is_dir() { + err!("Path does not directory", ErrorKind::InvalidFolder); + } + for entry in read_dir(&path)? { + let entry = entry?; + let path = entry.path(); + let metadata = entry.metadata()?; + let item = get_details_entry_with_meta(path, &config, metadata)?; + items.push(item); + } + let mut base = HashMap::new(); + if config.contains(&DirEntryAttr::BaseInfo) { + base = get_details_entry(&path, &config)?; + } + Ok(LsResult { items, base }) +} + +/// Creates a new, empty directory at the provided path. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to new directory. +/// +/// * `erase` - If set true and folder exist, then folder will be erased. +/// +/// #Errors +/// +/// This function will return an error in the following situations, +/// but is not limited to just these cases: +/// +/// * User lacks permissions to create directory at `path`. +/// +/// * `path` already exists if `erase` set false. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create; +/// +/// create("dir", false); // create directory +/// ``` +pub fn create

(path: P, erase: bool) -> Result<()> +where + P: AsRef, +{ + if erase && path.as_ref().exists() { + remove(&path)?; + } + Ok(create_dir(&path)?) +} + +/// Recursively create a directory and all of its parent components if they are missing. +/// +/// This function takes to arguments: +/// +/// * `path` - Path to new directory. +/// +/// * `erase` - If set true and folder exist, then folder will be erased. +/// +///#Errors +/// +/// This function will return an error in the following situations, +/// but is not limited to just these cases: +/// +/// * User lacks permissions to create directory at `path`. +/// +/// * `path` already exists if `erase` set false. +/// +/// #Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create_all; +/// +/// create_all("/some/dir", false); // create directory some and dir +pub fn create_all

(path: P, erase: bool) -> Result<()> +where + P: AsRef, +{ + if erase && path.as_ref().exists() { + remove(&path)?; + } + Ok(create_dir_all(&path)?) +} + +/// Copies the directory contents from one place to another using recursive method. +/// 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 cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// // options.mirror_copy = true; // To mirror copy the whole structure of the source directory +/// +/// +/// // copy source/dir1 to target/dir1 +/// copy("source/dir1", "target/dir1", &options)?; +/// +/// ``` +pub fn copy(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist Or you don't have access!", + ErrorKind::NotFound + ); + } + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + let mut to: PathBuf = to.as_ref().to_path_buf(); + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + + let mut read_options = DirOptions::new(); + if options.depth > 0 { + read_options.depth = options.depth; + } + + let dir_content = get_dir_content2(from, &read_options)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + let mut result: u64 = 0; + for file in dir_content.files { + let to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + let mut result_copy: Result; + let mut work = true; + + while work { + result_copy = super::file::copy(&file, &path, &file_options); + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + } + Ok(result) +} + +/// Return DirContent which contains information about directory: +/// +/// * Size of the directory in bytes. +/// * List of source paths of files in the directory (files inside subdirectories included too). +/// * List of source paths of all directories and subdirectories. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::get_dir_content; +/// +/// let dir_content = get_dir_content("dir")?; +/// for directory in dir_content.directories { +/// println!("{}", directory); // print directory path +/// } +/// ``` +/// +pub fn get_dir_content

(path: P) -> Result +where + P: AsRef, +{ + let options = DirOptions::new(); + get_dir_content2(path, &options) +} + +/// Return DirContent which contains information about directory: +/// +/// * Size directory. +/// * List all files source directory(files subdirectories included too). +/// * List all directory and subdirectories source path. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::{DirOptions, get_dir_content2}; +/// +/// let mut options = DirOptions::new(); +/// options.depth = 3; // Get 3 levels of folder. +/// let dir_content = get_dir_content2("dir", &options)?; +/// for directory in dir_content.directories { +/// println!("{}", directory); // print directory path +/// } +/// ``` +/// +pub fn get_dir_content2

(path: P, options: &DirOptions) -> Result +where + P: AsRef, +{ + let mut depth = 0; + if options.depth != 0 { + depth = options.depth + 1; + } + _get_dir_content(path, depth) +} + +fn _get_dir_content

(path: P, mut depth: u64) -> Result +where + P: AsRef, +{ + let mut directories = Vec::new(); + let mut files = Vec::new(); + let mut dir_size; + let item = path.as_ref().to_str(); + if item.is_none() { + err!("Invalid path", ErrorKind::InvalidPath); + } + let item = item.unwrap().to_string(); + + if path.as_ref().is_dir() { + dir_size = path.as_ref().metadata()?.len(); + directories.push(item); + if depth == 0 || depth > 1 { + if depth > 1 { + depth -= 1; + } + for entry in read_dir(&path)? { + let _path = entry?.path(); + + match _get_dir_content(_path, depth) { + Ok(items) => { + let mut _files = items.files; + let mut _directories = items.directories; + dir_size += items.dir_size; + files.append(&mut _files); + directories.append(&mut _directories); + } + Err(err) => return Err(err), + } + } + } + } else { + dir_size = path.as_ref().metadata()?.len(); + files.push(item); + } + Ok(DirContent { + dir_size, + files, + directories, + }) +} + +/// Returns the size of the file or directory in bytes.(!important: folders size not count) +/// +/// If used on a directory, this function will recursively iterate over every file and every +/// directory inside the directory. This can be very time consuming if used on large directories. +/// +/// Does not follow symlinks. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` directory does not exist. +/// * Invalid `path`. +/// * The current process does not have the permission to access `path`. +/// +/// # Examples +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::get_size; +/// +/// let folder_size = get_size("dir")?; +/// println!("{}", folder_size); // print directory size in bytes +/// ``` +pub fn get_size

(path: P) -> Result +where + P: AsRef, +{ + // Using `fs::symlink_metadata` since we don't want to follow symlinks, + // as we're calculating the exact size of the requested path itself. + let path_metadata = path.as_ref().symlink_metadata()?; + + let mut size_in_bytes = 0; + + if path_metadata.is_dir() { + for entry in read_dir(&path)? { + let entry = entry?; + // `DirEntry::metadata` does not follow symlinks (unlike `fs::metadata`), so in the + // case of symlinks, this is the size of the symlink itself, not its target. + let entry_metadata = entry.metadata()?; + + if entry_metadata.is_dir() { + // The size of the directory entry itself will be counted inside the `get_size()` call, + // so we intentionally don't also add `entry_metadata.len()` to the total here. + size_in_bytes += get_size(entry.path())?; + } else { + size_in_bytes += entry_metadata.len(); + } + } + } else { + size_in_bytes = path_metadata.len(); + } + + Ok(size_in_bytes) +} + +/// Copies the directory contents from one place to another using recursive method, +/// 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 cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// // copy source/dir1 to target/dir1 +/// copy_with_progress("source/dir1", "target/dir1", &options, handle)?; +/// +/// ``` +pub fn copy_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> TransitProcessResult, +{ + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + + let mut read_options = DirOptions::new(); + if options.depth > 0 { + read_options.depth = options.depth; + } + + let dir_content = get_dir_content2(from, &read_options)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: dir_content.dir_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + state: TransitState::Normal, + }; + + let mut options = options.clone(); + for file in dir_content.files { + let mut to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_name = path.file_name(); + if file_name.is_none() { + err!("No file name"); + } + let file_name = file_name.unwrap(); + to.push(file_name); + + let mut file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + + let mut result_copy: Result; + let mut work = true; + let copied_bytes = result; + while work { + { + let _progress_handler = |info: super::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 = + super::file::copy_with_progress(&file, &path, &file_options, _progress_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 = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + 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 = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::Skip => { + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + 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 the directory contents from one place to another. +/// 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 cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::move_dir; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// +/// // move source/dir1 to target/dir1 +/// move_dir("source/dir1", "target/dir1", &options)?; +/// +/// ``` +pub fn move_dir(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!( + "Path \"{}\" is not a directory or you don't have access!", + msg + ); + err!(&msg, ErrorKind::InvalidFolder); + } + err!( + "Path is not a directory or you don't have access!", + ErrorKind::InvalidFolder + ); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + + if (to.exists() || !options.copy_inside) && !options.content_only { + to.push(dir_name); + } + let dir_content = get_dir_content(from)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + let mut result: u64 = 0; + for file in dir_content.files { + let to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + let mut result_copy: Result; + let mut work = true; + while work { + { + result_copy = super::file::move_file(&file, &path, &file_options); + match result_copy { + Ok(val) => { + result += val; + work = false; + } + Err(err) => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + } + } + } + } + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Moves the directory contents from one place to another 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 cases: +/// +/// * This `from` path is not a directory. +/// * This `from` directory does not exist. +/// * Invalid folder name for `from` or `to`. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::move_dir_with_progress; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| { +/// println!("{}", process_info.total_bytes); +/// fs_extra::dir::TransitProcessResult::ContinueOrAbort +/// } +/// +/// // move source/dir1 to target/dir1 +/// move_dir_with_progress("source/dir1", "target/dir1", &options, handle)?; +/// +/// ``` +pub fn move_dir_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess) -> TransitProcessResult, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let from = from.as_ref(); + + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + let mut to: PathBuf = to.as_ref().to_path_buf(); + if !from.is_dir() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a directory!", msg); + err!(&msg, ErrorKind::InvalidFolder); + } + err!("Path is not a directory!", ErrorKind::InvalidFolder); + } + let dir_name; + if let Some(val) = from.components().last() { + dir_name = val.as_os_str(); + } else { + err!("Invalid folder from", ErrorKind::InvalidFolder); + } + if !(options.content_only || options.copy_inside && !to.exists()) { + to.push(dir_name); + } + + let dir_content = get_dir_content(from)?; + for directory in dir_content.directories { + let tmp_to = Path::new(&directory).strip_prefix(from)?; + let dir = to.join(&tmp_to); + if !dir.exists() { + if options.copy_inside { + create_all(dir, false)?; + } else { + create(dir, false)?; + } + } + } + + let mut result: u64 = 0; + let mut info_process = TransitProcess { + copied_bytes: 0, + total_bytes: dir_content.dir_size, + file_bytes_copied: 0, + file_total_bytes: 0, + file_name: String::new(), + state: TransitState::Normal, + }; + + let mut options = options.clone(); + for file in dir_content.files { + let mut to = to.to_path_buf(); + let tp = Path::new(&file).strip_prefix(from)?; + let path = to.join(&tp); + + let file_name = path.file_name(); + if file_name.is_none() { + err!("No file name"); + } + let file_name = file_name.unwrap(); + to.push(file_name); + + let mut file_options = super::file::CopyOptions { + overwrite: options.overwrite, + skip_exist: options.skip_exist, + buffer_size: options.buffer_size, + }; + + if let Some(file_name) = file_name.to_str() { + info_process.file_name = file_name.to_string(); + } else { + err!("Invalid file name", ErrorKind::InvalidFileName); + } + + info_process.file_bytes_copied = 0; + info_process.file_total_bytes = Path::new(&file).metadata()?.len(); + + let mut result_copy: Result; + let mut work = true; + let copied_bytes = result; + while work { + { + let _progress_handler = |info: super::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 = super::file::move_file_with_progress( + &file, + &path, + &file_options, + _progress_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 = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + file_options.overwrite = true; + } + TransitProcessResult::OverwriteAll => { + file_options.overwrite = true; + options.overwrite = true; + } + TransitProcessResult::Skip => { + is_remove = false; + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + is_remove = false; + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + 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 = TransitState::Exists; + let user_decide = progress_handler(info_process); + match user_decide { + TransitProcessResult::Overwrite => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::OverwriteAll => { + err!("Overwrite denied for this situation!", ErrorKind::Other); + } + TransitProcessResult::Skip => { + is_remove = false; + file_options.skip_exist = true; + } + TransitProcessResult::SkipAll => { + file_options.skip_exist = true; + options.skip_exist = true; + } + TransitProcessResult::Retry => {} + TransitProcessResult::ContinueOrAbort => { + let err_msg = err.to_string(); + err!(err_msg.as_str(), err.kind) + } + 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) + } + }, + } + } + } + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Removes directory. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::remove; +/// +/// remove("source/dir1"); // remove dir1 +/// ``` +pub fn remove>(path: P) -> Result<()> { + if path.as_ref().exists() { + Ok(remove_dir_all(path)?) + } else { + Ok(()) + } +} diff --git a/vendor/fs_extra/src/error.rs b/vendor/fs_extra/src/error.rs new file mode 100644 index 000000000..f26613e90 --- /dev/null +++ b/vendor/fs_extra/src/error.rs @@ -0,0 +1,158 @@ +use std::error::Error as StdError; +use std::ffi::OsString; +use std::fmt; +use std::io::Error as IoError; +use std::io::ErrorKind as IoErrorKind; +use std::path::StripPrefixError; + +/// A list specifying general categories of fs_extra error. +#[derive(Debug)] +pub enum ErrorKind { + /// An entity was not found. + NotFound, + /// The operation lacked the necessary privileges to complete. + PermissionDenied, + /// An entity already exists. + AlreadyExists, + /// This operation was interrupted. + Interrupted, + /// Path does not a directory. + InvalidFolder, + /// Path does not a file. + InvalidFile, + /// Invalid file name. + InvalidFileName, + /// Invalid path. + InvalidPath, + /// Any I/O error. + Io(IoError), + /// Any StripPrefix error. + StripPrefix(StripPrefixError), + /// Any OsString error. + OsString(OsString), + /// Any fs_extra error not part of this list. + Other, +} + +impl ErrorKind { + fn as_str(&self) -> &str { + match *self { + ErrorKind::NotFound => "entity not found", + ErrorKind::PermissionDenied => "permission denied", + ErrorKind::AlreadyExists => "entity already exists", + ErrorKind::Interrupted => "operation interrupted", + ErrorKind::Other => "other os error", + ErrorKind::InvalidFolder => "invalid folder error", + ErrorKind::InvalidFile => "invalid file error", + ErrorKind::InvalidFileName => "invalid file name error", + ErrorKind::InvalidPath => "invalid path error", + ErrorKind::Io(_) => "Io error", + ErrorKind::StripPrefix(_) => "Strip prefix error", + ErrorKind::OsString(_) => "OsString error", + } + } +} + +/// A specialized Result type for fs_extra operations. +/// +/// This typedef is generally used to avoid writing out fs_extra::Error directly +/// and is otherwise a direct mapping to Result. +/// +///#Examples +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::dir::create; +/// +///fn get_string() -> io::Result<()> { +/// +/// create("test_dir")?; +/// +/// Ok(()) +/// } +/// ``` +pub type Result = ::std::result::Result; + +/// The error type for fs_extra operations with files and folder. +/// +/// Errors mostly originate from the underlying OS, but custom instances of +/// `Error` can be created with crafted error messages and a particular value of +/// [`ErrorKind`]. +/// +/// [`ErrorKind`]: enum.ErrorKind.html +#[derive(Debug)] +pub struct Error { + /// Type error + pub kind: ErrorKind, + message: String, +} + +impl Error { + /// Create a new fs_extra error from a kind of error error as well as an arbitrary error payload. + /// + ///#Examples + /// ```rust,ignore + /// + /// extern crate fs_extra; + /// use fs_extra::error::{Error, ErrorKind}; + /// + /// errors can be created from strings + /// let custom_error = Error::new(ErrorKind::Other, "Other Error!"); + /// // errors can also be created from other errors + /// let custom_error2 = Error::new(ErrorKind::Interrupted, custom_error); + /// + /// ``` + pub fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind, + message: message.to_string(), + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.message) + } +} + +impl StdError for Error { + fn description(&self) -> &str { + self.kind.as_str() + } +} +impl From for Error { + fn from(err: StripPrefixError) -> Error { + Error::new( + ErrorKind::StripPrefix(err), + "StripPrefixError. Look inside for more details", + ) + } +} + +impl From for Error { + fn from(err: OsString) -> Error { + Error::new( + ErrorKind::OsString(err), + "OsString. Look inside for more details", + ) + } +} + +impl From for Error { + fn from(err: IoError) -> Error { + let err_kind: ErrorKind; + match err.kind() { + IoErrorKind::NotFound => err_kind = ErrorKind::NotFound, + IoErrorKind::PermissionDenied => err_kind = ErrorKind::PermissionDenied, + IoErrorKind::AlreadyExists => err_kind = ErrorKind::AlreadyExists, + IoErrorKind::Interrupted => err_kind = ErrorKind::Interrupted, + IoErrorKind::Other => err_kind = ErrorKind::Other, + _ => { + err_kind = ErrorKind::Io(err); + return Error::new(err_kind, "Io error. Look inside err_kind for more details."); + } + } + Error::new(err_kind, &err.to_string()) + } +} diff --git a/vendor/fs_extra/src/file.rs b/vendor/fs_extra/src/file.rs new file mode 100644 index 000000000..2b62576bc --- /dev/null +++ b/vendor/fs_extra/src/file.rs @@ -0,0 +1,413 @@ +use crate::error::{Error, ErrorKind, Result}; +use std; +use std::fs::{remove_file, File}; +use std::io::{Read, Write}; +use std::path::Path; + +// Options and flags which can be used to configure how a file will be copied or moved. +pub struct CopyOptions { + /// Sets the option true for overwrite existing files. + pub overwrite: bool, + /// Sets the option true for skip existing files. + pub skip_exist: bool, + /// Sets buffer size for copy/move work only with receipt information about process work. + pub buffer_size: usize, +} + +impl CopyOptions { + /// Initialize struct CopyOptions with default value. + /// + /// ```rust,ignore + /// + /// overwrite: false + /// + /// skip_exist: false + /// + /// buffer_size: 64000 //64kb + /// ``` + pub fn new() -> CopyOptions { + CopyOptions { + overwrite: false, + skip_exist: false, + buffer_size: 64000, //64kb + } + } + + /// Sets the option true for overwrite existing files. + pub fn overwrite(mut self, overwrite: bool) -> Self { + self.overwrite = overwrite; + self + } + + /// Sets the option true for skip existing files. + pub fn skip_exist(mut self, skip_exist: bool) -> Self { + self.skip_exist = skip_exist; + self + } + + /// Sets buffer size for copy/move work only with receipt information about process work. + pub fn buffer_size(mut self, buffer_size: usize) -> Self { + self.buffer_size = buffer_size; + self + } +} + +impl Default for CopyOptions { + fn default() -> Self { + CopyOptions::new() + } +} + +/// A structure which stores information about the current status of a file that's copied or moved. . +pub struct TransitProcess { + /// Copied bytes on this time. + pub copied_bytes: u64, + /// All the bytes which should to copy or move. + pub total_bytes: u64, +} + +/// Copies the contents of one file to another. This function will also copy the permission +/// bits of the original file to the destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::copy; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// copy("dir1/foo.txt", "dir2/bar.txt", &options)?; // Copy dir1/foo.txt to dir2/bar.txt +/// +/// ``` +pub fn copy(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let from = from.as_ref(); + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + if !from.is_file() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + if !options.overwrite && to.as_ref().exists() { + if options.skip_exist { + return Ok(0); + } + + if let Some(msg) = to.as_ref().to_str() { + let msg = format!("Path \"{}\" exists", msg); + err!(&msg, ErrorKind::AlreadyExists); + } + } + + Ok(std::fs::copy(from, to)?) +} + +/// Copies the contents of one file to another file with information about progress. +/// This function will also copy the permission bits of the original file to the +/// destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::copy_with_progress; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); +/// +/// // Copy dir1/foo.txt to dir2/foo.txt +/// copy_with_progress("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; +/// +/// ``` +pub fn copy_with_progress( + from: P, + to: Q, + options: &CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess), +{ + let from = from.as_ref(); + if !from.exists() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" does not exist or you don't have access!", msg); + err!(&msg, ErrorKind::NotFound); + } + err!( + "Path does not exist or you don't have access!", + ErrorKind::NotFound + ); + } + + if !from.is_file() { + if let Some(msg) = from.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + if !options.overwrite && to.as_ref().exists() { + if options.skip_exist { + return Ok(0); + } + + if let Some(msg) = to.as_ref().to_str() { + let msg = format!("Path \"{}\" exists", msg); + err!(&msg, ErrorKind::AlreadyExists); + } + } + let mut file_from = File::open(from)?; + let mut buf = vec![0; options.buffer_size]; + let file_size = file_from.metadata()?.len(); + let mut copied_bytes: u64 = 0; + + let mut file_to = File::create(to)?; + while !buf.is_empty() { + match file_from.read(&mut buf) { + Ok(0) => break, + Ok(n) => { + let written_bytes = file_to.write(&buf[..n])?; + if written_bytes != n { + err!("Couldn't write the whole buffer to file", ErrorKind::Other); + } + copied_bytes += n as u64; + let data = TransitProcess { + copied_bytes, + total_bytes: file_size, + }; + progress_handler(data); + } + Err(ref e) if e.kind() == ::std::io::ErrorKind::Interrupted => {} + Err(e) => return Err(::std::convert::From::from(e)), + } + } + Ok(file_size) +} + +/// Moves a file from one place to another. This function will also copy the permission +/// bits of the original file to the destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::move_file; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// move_file("dir1/foo.txt", "dir2/foo.txt", &options)?; // Move dir1/foo.txt to dir2/foo.txt +/// +/// ``` +pub fn move_file(from: P, to: Q, options: &CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let result = copy(&from, to, options)?; + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Moves a file from one place to another with information about progress. +/// This function will also copy the permission bits of the original file to the +/// destination file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `from` path is not a file. +/// * This `from` file does not exist. +/// * The current process does not have the permission to access `from` or write `to`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::move_file; +/// +/// let options = CopyOptions::new(); //Initialize default values for CopyOptions +/// let handle = |process_info: TransitProcess| println!("{}", process_info.total_bytes); +/// +/// // Move dir1/foo.txt to dir2/foo.txt +/// move_file("dir1/foo.txt", "dir2/foo.txt", &options, handle)?; +/// +/// ``` +pub fn move_file_with_progress( + from: P, + to: Q, + options: &CopyOptions, + progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + F: FnMut(TransitProcess), +{ + let mut is_remove = true; + if options.skip_exist && to.as_ref().exists() && !options.overwrite { + is_remove = false; + } + let result = copy_with_progress(&from, to, options, progress_handler)?; + if is_remove { + remove(from)?; + } + + Ok(result) +} + +/// Removes a file from the filesystem. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::remove; +/// +/// remove("foo.txt" )?; // Remove foo.txt +/// +/// ``` +pub fn remove

(path: P) -> Result<()> +where + P: AsRef, +{ + if path.as_ref().exists() { + Ok(remove_file(path)?) + } else { + Ok(()) + } +} + +/// Read file contents, placing them into `String`. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` is not a file. +/// * This `path` file does not exist. +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::read_to_string; +/// +/// let file_content = read_to_string("foo.txt" )?; // Get file content from foo.txt +/// println!("{}", file_content); +/// +/// ``` +pub fn read_to_string

(path: P) -> Result +where + P: AsRef, +{ + let path = path.as_ref(); + if path.exists() && !path.is_file() { + if let Some(msg) = path.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + let mut file = File::open(path)?; + let mut result = String::new(); + file.read_to_string(&mut result)?; + + Ok(result) +} + +/// Write `String` content into file. +/// +/// # Errors +/// +/// This function will return an error in the following situations, but is not limited to just +/// these cases: +/// +/// * This `path` is not a file. +/// * This `path` file does not exist. +/// * The current process does not have the permission to access `path`. +/// +/// # Example +/// ```rust,ignore +/// extern crate fs_extra; +/// use fs_extra::file::read_to_string; +/// +/// write_all("foo.txt", "contents" )?; // Create file foo.txt and send content inside +/// +/// ``` +pub fn write_all

(path: P, content: &str) -> Result<()> +where + P: AsRef, +{ + let path = path.as_ref(); + if path.exists() && !path.is_file() { + if let Some(msg) = path.to_str() { + let msg = format!("Path \"{}\" is not a file!", msg); + err!(&msg, ErrorKind::InvalidFile); + } + err!("Path is not a file!", ErrorKind::InvalidFile); + } + + let mut f = File::create(path)?; + + Ok(f.write_all(content.as_bytes())?) +} 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(from: &[P], to: Q, options: &dir::CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + 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( + from: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + 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; + 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(from_items: &[P], to: Q, options: &dir::CopyOptions) -> Result +where + P: AsRef, + Q: AsRef, +{ + 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( + from_items: &[P], + to: Q, + options: &dir::CopyOptions, + mut progress_handler: F, +) -> Result +where + P: AsRef, + Q: AsRef, + 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; + 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

(from_items: &[P]) -> Result<()> +where + P: AsRef, +{ + for item in from_items { + let item = item.as_ref(); + if item.is_dir() { + dir::remove(item)?; + } else { + file::remove(item)? + } + } + + Ok(()) +} -- cgit v1.2.3