summaryrefslogtreecommitdiffstats
path: root/src/io
diff options
context:
space:
mode:
authorKamiyaa <jeff.no.zhao@gmail.com>2020-06-06 15:00:15 -0400
committerKamiyaa <jeff.no.zhao@gmail.com>2020-06-06 15:00:15 -0400
commit4f3842b56f1729dcd8e81c77f98253ed9dfb23b3 (patch)
treea9cb1b5c300fcbdbcdfad34f0076919e30f03c88 /src/io
parenta462ebe2140323a6085ce5a064727288fa4dff3c (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.rs147
-rw-r--r--src/io/mod.rs4
-rw-r--r--src/io/name_resolution.rs15
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);
+ }
+}