summaryrefslogtreecommitdiffstats
path: root/vendor/fs_extra/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /vendor/fs_extra/src
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/fs_extra/src')
-rw-r--r--vendor/fs_extra/src/dir.rs1398
-rw-r--r--vendor/fs_extra/src/error.rs158
-rw-r--r--vendor/fs_extra/src/file.rs413
-rw-r--r--vendor/fs_extra/src/lib.rs802
4 files changed, 2771 insertions, 0 deletions
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<String>,
+ /// List all folders and sub folders directory.
+ pub directories: Vec<String>,
+}
+
+/// 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<DirEntryAttr, DirEntryValue>,
+ /// Collection directory entry with information.
+ pub items: Vec<HashMap<DirEntryAttr, DirEntryValue>>,
+}
+
+/// 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<P>(
+ path: P,
+ config: &HashSet<DirEntryAttr>,
+) -> Result<HashMap<DirEntryAttr, DirEntryValue>>
+where
+ P: AsRef<Path>,
+{
+ let path = path.as_ref();
+ let metadata = path.metadata()?;
+ get_details_entry_with_meta(path, config, metadata)
+}
+
+fn get_details_entry_with_meta<P>(
+ path: P,
+ config: &HashSet<DirEntryAttr>,
+ metadata: Metadata,
+) -> Result<HashMap<DirEntryAttr, DirEntryValue>>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P, config: &HashSet<DirEntryAttr>) -> Result<LsResult>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P, erase: bool) -> Result<()>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P, erase: bool) -> Result<()>
+where
+ P: AsRef<Path>,
+{
+ 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<P, Q>(from: P, to: Q, options: &CopyOptions) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+{
+ 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<u64>;
+ 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<P>(path: P) -> Result<DirContent>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P, options: &DirOptions) -> Result<DirContent>
+where
+ P: AsRef<Path>,
+{
+ let mut depth = 0;
+ if options.depth != 0 {
+ depth = options.depth + 1;
+ }
+ _get_dir_content(path, depth)
+}
+
+fn _get_dir_content<P>(path: P, mut depth: u64) -> Result<DirContent>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P) -> Result<u64>
+where
+ P: AsRef<Path>,
+{
+ // 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<P, Q, F>(
+ from: P,
+ to: Q,
+ options: &CopyOptions,
+ mut progress_handler: F,
+) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+ 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<u64>;
+ 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<P, Q>(from: P, to: Q, options: &CopyOptions) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+{
+ 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<u64>;
+ 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<P, Q, F>(
+ from: P,
+ to: Q,
+ options: &CopyOptions,
+ mut progress_handler: F,
+) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+ 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<u64>;
+ 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<P: AsRef<Path>>(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<T> = ::std::result::Result<T, Error>;
+
+/// 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<StripPrefixError> for Error {
+ fn from(err: StripPrefixError) -> Error {
+ Error::new(
+ ErrorKind::StripPrefix(err),
+ "StripPrefixError. Look inside for more details",
+ )
+ }
+}
+
+impl From<OsString> for Error {
+ fn from(err: OsString) -> Error {
+ Error::new(
+ ErrorKind::OsString(err),
+ "OsString. Look inside for more details",
+ )
+ }
+}
+
+impl From<IoError> 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<P, Q>(from: P, to: Q, options: &CopyOptions) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+{
+ 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<P, Q, F>(
+ from: P,
+ to: Q,
+ options: &CopyOptions,
+ mut progress_handler: F,
+) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+ 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<P, Q>(from: P, to: Q, options: &CopyOptions) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+{
+ 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<P, Q, F>(
+ from: P,
+ to: Q,
+ options: &CopyOptions,
+ progress_handler: F,
+) -> Result<u64>
+where
+ P: AsRef<Path>,
+ Q: AsRef<Path>,
+ 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<P>(path: P) -> Result<()>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P) -> Result<String>
+where
+ P: AsRef<Path>,
+{
+ 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<P>(path: P, content: &str) -> Result<()>
+where
+ P: AsRef<Path>,
+{
+ 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<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(())
+}