diff options
author | Kamiyaa <jeff.no.zhao@gmail.com> | 2020-06-06 15:00:15 -0400 |
---|---|---|
committer | Kamiyaa <jeff.no.zhao@gmail.com> | 2020-06-06 15:00:15 -0400 |
commit | 4f3842b56f1729dcd8e81c77f98253ed9dfb23b3 (patch) | |
tree | a9cb1b5c300fcbdbcdfad34f0076919e30f03c88 /src/io | |
parent | a462ebe2140323a6085ce5a064727288fa4dff3c (diff) |
shell command now parses correctly
- rework file operations
- simpler model for listening on io_worker progress
- cargo fmt/clippy
Diffstat (limited to 'src/io')
-rw-r--r-- | src/io/io_worker.rs | 147 | ||||
-rw-r--r-- | src/io/mod.rs | 4 | ||||
-rw-r--r-- | src/io/name_resolution.rs | 15 |
3 files changed, 131 insertions, 35 deletions
diff --git a/src/io/io_worker.rs b/src/io/io_worker.rs index a9d2726..228b69d 100644 --- a/src/io/io_worker.rs +++ b/src/io/io_worker.rs @@ -1,18 +1,27 @@ -use std::path; +use std::fs; +use std::path::{Path, PathBuf}; use std::sync::mpsc; use std::thread; -use crate::util::event::Event; +use super::rename_filename_conflict; + +#[derive(Clone, Copy, Debug)] +pub enum FileOp { + Cut, + Copy, +} #[derive(Clone, Debug)] -pub struct Options { +pub struct IOWorkerOptions { + pub kind: FileOp, pub overwrite: bool, pub skip_exist: bool, } -impl std::default::Default for Options { +impl std::default::Default for IOWorkerOptions { fn default() -> Self { Self { + kind: FileOp::Copy, overwrite: false, skip_exist: false, } @@ -20,26 +29,14 @@ impl std::default::Default for Options { } pub struct IOWorkerObserver { - pub src: path::PathBuf, - pub dest: path::PathBuf, - pub handle: std::thread::JoinHandle<()>, + pub handle: thread::JoinHandle<()>, + pub src: PathBuf, + pub dest: PathBuf, } impl IOWorkerObserver { - pub fn new(worker: IOWorkerThread, event_tx: mpsc::Sender<Event>) -> Self { - let src = worker.src.clone(); - let dest = worker.dest.clone(); - - let handle = thread::spawn(move || { - worker.start(); - while let Ok(copied) = worker.recv() { - let _ = event_tx.send(Event::IOWorkerProgress(copied)); - } - let res = worker.join(); - let _ = event_tx.send(Event::IOWorkerResult(res)); - }); - - Self { src, dest, handle } + pub fn new(handle: thread::JoinHandle<()>, src: PathBuf, dest: PathBuf) -> Self { + Self { handle, src, dest } } pub fn join(self) { @@ -48,26 +45,108 @@ impl IOWorkerObserver { } pub struct IOWorkerThread { - pub src: path::PathBuf, - pub dest: path::PathBuf, - pub handle: thread::JoinHandle<std::io::Result<u64>>, - pub tx_start: mpsc::Sender<()>, - pub rx: mpsc::Receiver<u64>, + pub options: IOWorkerOptions, + pub paths: Vec<PathBuf>, + pub dest: PathBuf, } impl IOWorkerThread { - pub fn start(&self) { - self.tx_start.send(()); + pub fn new(options: IOWorkerOptions, paths: Vec<PathBuf>, dest: PathBuf) -> Self { + Self { + options, + paths, + dest, + } + } + + pub fn start(&self, tx: mpsc::Sender<u64>) -> std::io::Result<u64> { + match self.options.kind { + FileOp::Cut => self.paste_cut(tx), + FileOp::Copy => self.paste_copy(tx), + } + } + + fn paste_copy(&self, tx: mpsc::Sender<u64>) -> std::io::Result<u64> { + let mut total = 0; + for path in self.paths.iter() { + total += self.recursive_copy(self.dest.as_path(), path.as_path())?; + tx.send(total); + } + Ok(total) } - pub fn recv(&self) -> Result<u64, mpsc::RecvError> { - self.rx.recv() + fn recursive_copy(&self, dest: &Path, src: &Path) -> std::io::Result<u64> { + let mut dest_buf = dest.to_path_buf(); + if let Some(s) = src.file_name() { + dest_buf.push(s); + } + rename_filename_conflict(&mut dest_buf); + let file_type = fs::symlink_metadata(src)?.file_type(); + if file_type.is_dir() { + fs::create_dir(dest_buf.as_path())?; + let mut total = 0; + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + total += self.recursive_copy(dest_buf.as_path(), entry_path.as_path())?; + } + Ok(total) + } else if file_type.is_file() { + fs::copy(src, dest_buf) + } else if file_type.is_symlink() { + let link_path = fs::read_link(src)?; + std::os::unix::fs::symlink(link_path, dest_buf)?; + Ok(0) + } else { + Ok(0) + } } - pub fn join(self) -> std::io::Result<u64> { - match self.handle.join() { - Ok(s) => s, - Err(_) => Ok(0), + fn paste_cut(&self, tx: mpsc::Sender<u64>) -> std::io::Result<u64> { + let mut total = 0; + for path in self.paths.iter() { + total += self.recursive_cut(self.dest.as_path(), path.as_path())?; + tx.send(total); + } + Ok(total) + } + + pub fn recursive_cut(&self, dest: &Path, src: &Path) -> std::io::Result<u64> { + let mut dest_buf = dest.to_path_buf(); + if let Some(s) = src.file_name() { + dest_buf.push(s); + } + rename_filename_conflict(&mut dest_buf); + let metadata = fs::symlink_metadata(src)?; + let file_type = metadata.file_type(); + if file_type.is_dir() { + match fs::rename(src, dest_buf.as_path()) { + Ok(_) => Ok(metadata.len()), + Err(_) => { + let mut total = 0; + fs::create_dir(dest_buf.as_path())?; + for entry in fs::read_dir(src)? { + let entry = entry?; + let entry_path = entry.path(); + total += self.recursive_cut(dest_buf.as_path(), entry_path.as_path())?; + } + fs::remove_dir(src)?; + Ok(total) + } + } + } else if file_type.is_file() { + if fs::rename(src, dest_buf.as_path()).is_err() { + fs::copy(src, dest_buf.as_path())?; + fs::remove_file(src)?; + } + Ok(metadata.len()) + } else if file_type.is_symlink() { + let link_path = fs::read_link(src)?; + std::os::unix::fs::symlink(link_path, dest_buf)?; + fs::remove_file(src)?; + Ok(metadata.len()) + } else { + Ok(0) } } } diff --git a/src/io/mod.rs b/src/io/mod.rs index 5955b60..dd97f69 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1,3 +1,5 @@ mod io_worker; +mod name_resolution; -pub use self::io_worker::{IOWorkerObserver, IOWorkerThread, Options}; +pub use io_worker::{FileOp, IOWorkerObserver, IOWorkerOptions, IOWorkerThread}; +pub use name_resolution::rename_filename_conflict; diff --git a/src/io/name_resolution.rs b/src/io/name_resolution.rs new file mode 100644 index 0000000..a8e520b --- /dev/null +++ b/src/io/name_resolution.rs @@ -0,0 +1,15 @@ +use std::path; + +pub fn rename_filename_conflict(path: &mut path::PathBuf) { + let file_name = path.file_name().unwrap().to_os_string(); + for i in 0.. { + if !path.exists() { + break; + } + path.pop(); + + let mut file_name = file_name.clone(); + file_name.push(&format!("_{}", i)); + path.push(file_name); + } +} |