From 97444c3572c7fc0b06a8a2227f59e31d6baa4a6d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 8 Jul 2024 13:43:11 -0600 Subject: [PATCH] Use replace dialog in all required places, part of #180 --- Cargo.lock | 80 +++++++++++----------- Cargo.toml | 3 + src/app.rs | 8 +-- src/operation.rs | 174 ++++++++++++++++++++++++++++------------------- 4 files changed, 149 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 578013c..41986c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -502,7 +502,7 @@ checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -537,7 +537,7 @@ checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -772,7 +772,7 @@ checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1381,7 +1381,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1392,7 +1392,7 @@ checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1443,7 +1443,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1532,7 +1532,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1651,7 +1651,7 @@ checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -1977,7 +1977,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -2053,7 +2053,7 @@ dependencies = [ [[package]] name = "fs_extra" version = "1.3.0" -source = "git+https://github.com/pop-os/fs_extra.git#209d2e349842a10366c8c9c3ece72482129d372e" +source = "git+https://github.com/pop-os/fs_extra.git#7e7222eb2b7830d40b67cd02e6ebd156524ee866" [[package]] name = "fsevent-sys" @@ -2149,7 +2149,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -2339,7 +2339,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -2612,7 +2612,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.69", + "syn 2.0.70", "unic-langid", ] @@ -2626,7 +2626,7 @@ dependencies = [ "i18n-config", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -3251,7 +3251,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -4210,7 +4210,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -4393,7 +4393,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -4433,7 +4433,7 @@ dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -4538,7 +4538,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5021,7 +5021,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.69", + "syn 2.0.70", "walkdir", ] @@ -5195,7 +5195,7 @@ checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5218,7 +5218,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5545,9 +5545,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.69" +version = "2.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" +checksum = "2f0209b68b3613b093e0ec905354eccaedcfe83b8cb37cbdeae64026c3064c16" dependencies = [ "proc-macro2", "quote", @@ -5562,7 +5562,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5650,7 +5650,7 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5676,7 +5676,7 @@ checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5833,7 +5833,7 @@ checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -5931,7 +5931,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -6318,7 +6318,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "wasm-bindgen-shared", ] @@ -6352,7 +6352,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -6779,7 +6779,7 @@ checksum = "f6fc35f58ecd95a9b71c4f2329b911016e6bec66b3f2e6a4aad86bd2e99e2f9b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -6801,7 +6801,7 @@ checksum = "08990546bf4edef8f431fa6326e032865f27138718c587dc21bc0265bbcb57cc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -7242,7 +7242,7 @@ checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "synstructure", ] @@ -7350,7 +7350,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "zvariant_utils 2.0.0", ] @@ -7399,7 +7399,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -7419,7 +7419,7 @@ checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "synstructure", ] @@ -7453,7 +7453,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] [[package]] @@ -7515,7 +7515,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", "zvariant_utils 2.0.0", ] @@ -7538,5 +7538,5 @@ checksum = "fc242db087efc22bd9ade7aa7809e4ba828132edc312871584a6b4391bdf8786" dependencies = [ "proc-macro2", "quote", - "syn 2.0.69", + "syn 2.0.70", ] diff --git a/Cargo.toml b/Cargo.toml index d031880..d5976e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,6 +81,9 @@ tempfile = "3" test-log = "0.2" tokio = { version = "1", features = ["rt", "macros"] } +# [patch.'https://github.com/pop-os/fs_extra'] +# fs_extra = { path = "../fs_extra" } + # [patch.'https://github.com/pop-os/libcosmic'] # libcosmic = { path = "../libcosmic" } # cosmic-config = { path = "../libcosmic/cosmic-config" } diff --git a/src/app.rs b/src/app.rs index 41d9a22..3185f18 100644 --- a/src/app.rs +++ b/src/app.rs @@ -51,7 +51,7 @@ use crate::{ key_bind::key_binds, menu, mime_app, mounter::{mounters, MounterItem, MounterItems, MounterKey, Mounters}, - operation::Operation, + operation::{Operation, ReplaceResult}, spawn_detached::spawn_detached, tab::{self, HeadingOptions, ItemMetadata, Location, Tab}, }; @@ -300,7 +300,7 @@ pub enum DialogPage { Replace { from: tab::Item, to: tab::Item, - tx: mpsc::Sender, + tx: mpsc::Sender, }, } @@ -1207,9 +1207,7 @@ impl Application for App { DialogPage::Replace { tx, .. } => { return Command::perform( async move { - let _ = tx - .send(fs_extra::dir::TransitProcessResult::Overwrite) - .await; + let _ = tx.send(ReplaceResult::Replace).await; message::none() }, |x| x, diff --git a/src/operation.rs b/src/operation.rs index cc2e291..8324b62 100644 --- a/src/operation.rs +++ b/src/operation.rs @@ -19,6 +19,86 @@ fn err_str(err: T) -> String { err.to_string() } +fn handle_replace( + msg_tx: &Arc>>, + file_from: PathBuf, + file_to: PathBuf, +) -> ReplaceResult { + let item_from = match tab::item_from_path(file_from, IconSizes::default()) { + Ok(ok) => ok, + Err(err) => { + log::warn!("{}", err); + return ReplaceResult::Cancel; + } + }; + + let item_to = match tab::item_from_path(file_to, IconSizes::default()) { + Ok(ok) => ok, + Err(err) => { + log::warn!("{}", err); + return ReplaceResult::Cancel; + } + }; + + executor::block_on(async { + let (tx, mut rx) = mpsc::channel(1); + let _ = msg_tx + .lock() + .await + .send(Message::DialogPush(DialogPage::Replace { + from: item_from, + to: item_to, + tx, + })) + .await; + rx.recv().await.unwrap_or(ReplaceResult::Cancel) + }) +} + +fn handle_progress_state( + msg_tx: &Arc>>, + progress: &fs_extra::TransitProcess, +) -> fs_extra::dir::TransitProcessResult { + log::warn!("{:?}", progress); + match progress.state { + fs_extra::dir::TransitState::Normal => fs_extra::dir::TransitProcessResult::ContinueOrAbort, + fs_extra::dir::TransitState::Exists => { + let Some(file_from) = progress.file_from.clone() else { + log::warn!("missing file_from in progress"); + return fs_extra::dir::TransitProcessResult::Abort; + }; + + let Some(file_to) = progress.file_to.clone() else { + log::warn!("missing file_to in progress"); + return fs_extra::dir::TransitProcessResult::Abort; + }; + + handle_replace(msg_tx, file_from, file_to).into() + } + fs_extra::dir::TransitState::NoAccess => { + //TODO: permission error dialog + fs_extra::dir::TransitProcessResult::ContinueOrAbort + } + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum ReplaceResult { + Replace, + Skip, + Cancel, +} + +impl From for fs_extra::dir::TransitProcessResult { + fn from(f: ReplaceResult) -> fs_extra::dir::TransitProcessResult { + match f { + ReplaceResult::Replace => fs_extra::dir::TransitProcessResult::Overwrite, + ReplaceResult::Skip => fs_extra::dir::TransitProcessResult::Skip, + ReplaceResult::Cancel => fs_extra::dir::TransitProcessResult::Abort, + } + } +} + #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum Operation { /// Copy items @@ -135,9 +215,6 @@ impl Operation { let msg_tx = msg_tx.clone(); tokio::task::spawn_blocking(move || -> fs_extra::error::Result<()> { log::info!("Copy {:?} to {:?}", paths, to); - //TODO: set options as desired - let dir_options = fs_extra::dir::CopyOptions::default().copy_inside(true); - let file_options = fs_extra::file::CopyOptions::default(); let copied_bytes = AtomicU64::default(); let total_bytes = paths .iter() @@ -164,24 +241,32 @@ impl Operation { let dir_handler = |progress: fs_extra::TransitProcess| { copied_bytes.fetch_add(progress.copied_bytes, atomic::Ordering::Relaxed); handler(); - //TODO: handle exceptions - fs_extra::dir::TransitProcessResult::ContinueOrAbort + handle_progress_state(&msg_tx, &progress) }; for (from, to) in paths.into_iter().zip(to.into_iter()) { if from.is_dir() { - fs_extra::copy_items_with_progress( - &[from], - to, - &dir_options, - dir_handler, - )?; + let options = fs_extra::dir::CopyOptions::default().copy_inside(true); + fs_extra::copy_items_with_progress(&[from], to, &options, dir_handler)?; } else { - fs_extra::file::copy_with_progress( - from, - to, - &file_options, - file_handler, - )?; + let mut options = fs_extra::file::CopyOptions::default(); + if to.exists() { + match handle_replace(&msg_tx, from.clone(), to.clone()) { + ReplaceResult::Replace => { + options.overwrite = true; + } + ReplaceResult::Skip => { + options.skip_exist = true; + } + ReplaceResult::Cancel => { + //TODO: be silent, but collect actual changes made for undo + return Err(fs_extra::error::Error::new( + fs_extra::error::ErrorKind::Interrupted, + "operation cancelled", + )); + } + } + } + fs_extra::file::copy_with_progress(from, to, &options, file_handler)?; } } Ok(()) @@ -239,7 +324,6 @@ impl Operation { tokio::task::spawn_blocking(move || { log::info!("Move {:?} to {:?}", paths, to); let options = fs_extra::dir::CopyOptions::default(); - //TODO: set options as desired fs_extra::move_items_with_progress(&paths, &to, &options, |progress| { executor::block_on(async { let _ = msg_tx @@ -252,59 +336,7 @@ impl Operation { )) .await; }); - - match progress.state { - fs_extra::dir::TransitState::Normal => { - fs_extra::dir::TransitProcessResult::ContinueOrAbort - } - fs_extra::dir::TransitState::Exists => { - let Some(file_from) = progress.file_from.clone() else { - log::warn!("missing file_from in progress"); - return fs_extra::dir::TransitProcessResult::Abort; - }; - let item_from = - match tab::item_from_path(file_from, IconSizes::default()) { - Ok(ok) => ok, - Err(err) => { - log::warn!("{}", err); - return fs_extra::dir::TransitProcessResult::Abort; - } - }; - - let Some(file_to) = progress.file_to.clone() else { - log::warn!("missing file_to in progress"); - return fs_extra::dir::TransitProcessResult::Abort; - }; - let item_to = - match tab::item_from_path(file_to, IconSizes::default()) { - Ok(ok) => ok, - Err(err) => { - log::warn!("{}", err); - return fs_extra::dir::TransitProcessResult::Abort; - } - }; - - executor::block_on(async { - let (tx, mut rx) = mpsc::channel(1); - let _ = msg_tx - .lock() - .await - .send(Message::DialogPush(DialogPage::Replace { - from: item_from, - to: item_to, - tx, - })) - .await; - rx.recv() - .await - .unwrap_or(fs_extra::dir::TransitProcessResult::Abort) - }) - } - fs_extra::dir::TransitState::NoAccess => { - //TODO: permission error dialog - fs_extra::dir::TransitProcessResult::ContinueOrAbort - } - } + handle_progress_state(&msg_tx, &progress) }) }) .await