chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

1398
vendor/fs_extra/src/dir.rs vendored Normal file

File diff suppressed because it is too large Load Diff

158
vendor/fs_extra/src/error.rs vendored Normal file
View File

@@ -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())
}
}

413
vendor/fs_extra/src/file.rs vendored Normal file
View File

@@ -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())?)
}

802
vendor/fs_extra/src/lib.rs vendored Normal file
View File

@@ -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(())
}