From cd6881c9fe88dfe73d91980829fd371f5eeec242 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E9=9B=85=20misaki=20masa?= Date: Fri, 3 Oct 2025 22:35:48 +0800 Subject: [PATCH] feat: support task initialization failure status (#3227) --- yazi-actor/src/lives/task.rs | 1 + yazi-scheduler/src/file/file.rs | 14 ++++---- yazi-scheduler/src/file/out.rs | 43 +++++++++++++--------- yazi-scheduler/src/file/progress.rs | 50 ++++++++++++++++++-------- yazi-scheduler/src/ongoing.rs | 2 +- yazi-scheduler/src/plugin/progress.rs | 2 ++ yazi-scheduler/src/prework/progress.rs | 6 ++++ yazi-scheduler/src/process/progress.rs | 6 ++++ yazi-scheduler/src/progress.rs | 21 +++++++++++ yazi-scheduler/src/scheduler.rs | 14 +++----- 10 files changed, 110 insertions(+), 49 deletions(-) diff --git a/yazi-actor/src/lives/task.rs b/yazi-actor/src/lives/task.rs index 12b5f560..9003c252 100644 --- a/yazi-actor/src/lives/task.rs +++ b/yazi-actor/src/lives/task.rs @@ -32,6 +32,7 @@ impl UserData for TaskSnap { fields.add_field_method_get("running", |_, me| Ok(me.prog.running())); fields.add_field_method_get("success", |_, me| Ok(me.prog.success())); + fields.add_field_method_get("failed", |_, me| Ok(me.prog.failed())); fields.add_field_method_get("percent", |_, me| Ok(me.prog.percent())); } } diff --git a/yazi-scheduler/src/file/file.rs b/yazi-scheduler/src/file/file.rs index 26676ae2..4eb3f18e 100644 --- a/yazi-scheduler/src/file/file.rs +++ b/yazi-scheduler/src/file/file.rs @@ -27,7 +27,7 @@ impl File { pub(crate) async fn paste(&self, mut task: FileInPaste) -> Result<(), FileOutPaste> { if task.cut && ok_or_not_found(provider::rename(&task.from, &task.to).await).is_ok() { - return Ok(self.ops.out(task.id, FileOutPaste::Init)); + return Ok(self.ops.out(task.id, FileOutPaste::Succ)); } if task.cha.is_none() { @@ -44,7 +44,7 @@ impl File { self.ops.out(id, FileOutPaste::New(cha.len)); self.queue(task, LOW); } - return Ok(self.ops.out(id, FileOutPaste::Init)); + return Ok(self.ops.out(id, FileOutPaste::Succ)); } macro_rules! continue_unless_ok { @@ -91,7 +91,7 @@ impl File { } } - Ok(self.ops.out(task.id, FileOutPaste::Init)) + Ok(self.ops.out(task.id, FileOutPaste::Succ)) } pub(crate) async fn paste_do(&self, mut task: FileInPaste) -> Result<(), FileOutPasteDo> { @@ -175,7 +175,7 @@ impl File { let id = task.id; self.ops.out(id, FileOutHardlink::New); self.queue(task, NORMAL); - self.ops.out(id, FileOutHardlink::Init); + self.ops.out(id, FileOutHardlink::Succ); return Ok(()); } @@ -218,7 +218,7 @@ impl File { } } - Ok(self.ops.out(task.id, FileOutHardlink::Init)) + Ok(self.ops.out(task.id, FileOutHardlink::Succ)) } pub(crate) async fn hardlink_do(&self, task: FileInHardlink) -> Result<(), FileOutHardlinkDo> { @@ -243,7 +243,7 @@ impl File { task.length = cha.len; self.ops.out(id, FileOutDelete::New(cha.len)); self.queue(task, NORMAL); - self.ops.out(id, FileOutDelete::Init); + self.ops.out(id, FileOutDelete::Succ); return Ok(()); } @@ -266,7 +266,7 @@ impl File { } } - Ok(self.ops.out(task.id, FileOutDelete::Init)) + Ok(self.ops.out(task.id, FileOutDelete::Succ)) } pub(crate) async fn delete_do(&self, task: FileInDelete) -> Result<(), FileOutDeleteDo> { diff --git a/yazi-scheduler/src/file/out.rs b/yazi-scheduler/src/file/out.rs index 75ed34d4..39409521 100644 --- a/yazi-scheduler/src/file/out.rs +++ b/yazi-scheduler/src/file/out.rs @@ -5,12 +5,13 @@ use crate::{Task, TaskProg}; pub(crate) enum FileOutPaste { New(u64), Deform(String), - Init, + Succ, + Fail(String), Clean, } impl From for FileOutPaste { - fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) } + fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) } } impl FileOutPaste { @@ -26,8 +27,12 @@ impl FileOutPaste { prog.failed_files += 1; task.log(reason); } - Self::Init => { - prog.collected = true; + Self::Succ => { + prog.collected = Some(true); + } + Self::Fail(reason) => { + prog.collected = Some(false); + task.log(reason); } Self::Clean => { prog.cleaned = true; @@ -116,11 +121,12 @@ impl FileOutLink { pub(crate) enum FileOutHardlink { New, Deform(String), - Init, + Succ, + Fail(String), } impl From for FileOutHardlink { - fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) } + fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) } } impl FileOutHardlink { @@ -135,8 +141,12 @@ impl FileOutHardlink { prog.failed += 1; task.log(reason); } - Self::Init => { - prog.collected = true; + Self::Succ => { + prog.collected = Some(true); + } + Self::Fail(reason) => { + prog.collected = Some(false); + task.log(reason); } } } @@ -172,13 +182,13 @@ impl FileOutHardlinkDo { #[derive(Debug)] pub(crate) enum FileOutDelete { New(u64), - Deform(String), - Init, + Succ, + Fail(String), Clean, } impl From for FileOutDelete { - fn from(value: std::io::Error) -> Self { Self::Deform(value.to_string()) } + fn from(value: std::io::Error) -> Self { Self::Fail(value.to_string()) } } impl FileOutDelete { @@ -189,13 +199,12 @@ impl FileOutDelete { prog.total_files += 1; prog.total_bytes += size; } - Self::Deform(reason) => { - prog.total_files += 1; - prog.failed_files += 1; - task.log(reason); + Self::Succ => { + prog.collected = Some(true); } - Self::Init => { - prog.collected = true; + Self::Fail(reason) => { + prog.collected = Some(false); + task.log(reason); } Self::Clean => { prog.cleaned = true; diff --git a/yazi-scheduler/src/file/progress.rs b/yazi-scheduler/src/file/progress.rs index 4486db54..61a44efe 100644 --- a/yazi-scheduler/src/file/progress.rs +++ b/yazi-scheduler/src/file/progress.rs @@ -9,7 +9,7 @@ pub struct FileProgPaste { pub failed_files: u32, pub total_bytes: u64, pub processed_bytes: u64, - pub collected: bool, + pub collected: Option, pub cleaned: bool, } @@ -26,20 +26,26 @@ impl From for TaskSummary { impl FileProgPaste { pub fn running(self) -> bool { - !self.collected || self.success_files + self.failed_files != self.total_files + self.collected.is_none() || self.success_files + self.failed_files != self.total_files } - pub fn success(self) -> bool { self.collected && self.success_files == self.total_files } + pub fn success(self) -> bool { + self.collected == Some(true) && self.success_files == self.total_files + } + + pub fn failed(self) -> bool { self.collected == Some(false) } pub fn cleaned(self) -> bool { self.cleaned } pub fn percent(self) -> Option { Some(if self.success() { 100.0 - } else if self.total_bytes == 0 { - 99.99 - } else { + } else if self.failed() { + 0.0 + } else if self.total_bytes != 0 { 99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0) + } else { + 99.99 }) } } @@ -66,6 +72,8 @@ impl FileProgLink { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } @@ -77,7 +85,7 @@ pub struct FileProgHardlink { pub total: u32, pub success: u32, pub failed: u32, - pub collected: bool, + pub collected: Option, } impl From for TaskSummary { @@ -92,9 +100,13 @@ impl From for TaskSummary { } impl FileProgHardlink { - pub fn running(self) -> bool { !self.collected || self.success + self.failed != self.total } + pub fn running(self) -> bool { + self.collected.is_none() || self.success + self.failed != self.total + } - pub fn success(self) -> bool { self.collected && self.success == self.total } + pub fn success(self) -> bool { self.collected == Some(true) && self.success == self.total } + + pub fn failed(self) -> bool { self.collected == Some(false) } pub fn cleaned(self) -> bool { false } @@ -109,7 +121,7 @@ pub struct FileProgDelete { pub failed_files: u32, pub total_bytes: u64, pub processed_bytes: u64, - pub collected: bool, + pub collected: Option, pub cleaned: bool, } @@ -126,20 +138,26 @@ impl From for TaskSummary { impl FileProgDelete { pub fn running(self) -> bool { - !self.collected || self.success_files + self.failed_files != self.total_files + self.collected.is_none() || self.success_files + self.failed_files != self.total_files } - pub fn success(self) -> bool { self.collected && self.success_files == self.total_files } + pub fn success(self) -> bool { + self.collected == Some(true) && self.success_files == self.total_files + } + + pub fn failed(self) -> bool { self.collected == Some(false) } pub fn cleaned(self) -> bool { self.cleaned } pub fn percent(self) -> Option { Some(if self.success() { 100.0 - } else if self.total_bytes == 0 { - 99.99 - } else { + } else if self.failed() { + 0.0 + } else if self.total_bytes != 0 { 99.99f32.min(self.processed_bytes as f32 / self.total_bytes as f32 * 100.0) + } else { + 99.99 }) } } @@ -166,6 +184,8 @@ impl FileProgTrash { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } diff --git a/yazi-scheduler/src/ongoing.rs b/yazi-scheduler/src/ongoing.rs index 769f2824..285632db 100644 --- a/yazi-scheduler/src/ongoing.rs +++ b/yazi-scheduler/src/ongoing.rs @@ -59,7 +59,7 @@ impl Ongoing { for task in self.values() { let s: TaskSummary = task.prog.into(); - if s.total == 0 { + if s.total == 0 && !task.prog.failed() { continue; } diff --git a/yazi-scheduler/src/plugin/progress.rs b/yazi-scheduler/src/plugin/progress.rs index b22ff85c..d6255c5a 100644 --- a/yazi-scheduler/src/plugin/progress.rs +++ b/yazi-scheduler/src/plugin/progress.rs @@ -23,6 +23,8 @@ impl PluginProgEntry { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } diff --git a/yazi-scheduler/src/prework/progress.rs b/yazi-scheduler/src/prework/progress.rs index 91200ff4..9174ef82 100644 --- a/yazi-scheduler/src/prework/progress.rs +++ b/yazi-scheduler/src/prework/progress.rs @@ -23,6 +23,8 @@ impl PreworkProgFetch { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } @@ -50,6 +52,8 @@ impl PreworkProgLoad { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } @@ -77,6 +81,8 @@ impl PreworkProgSize { pub fn success(self) -> bool { self.done } + pub fn failed(self) -> bool { false } + pub fn cleaned(self) -> bool { false } pub fn percent(self) -> Option { None } diff --git a/yazi-scheduler/src/process/progress.rs b/yazi-scheduler/src/process/progress.rs index e4ddc657..81980e1d 100644 --- a/yazi-scheduler/src/process/progress.rs +++ b/yazi-scheduler/src/process/progress.rs @@ -24,6 +24,8 @@ impl ProcessProgBlock { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { self.cleaned } pub fn percent(self) -> Option { None } @@ -52,6 +54,8 @@ impl ProcessProgOrphan { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { self.cleaned } pub fn percent(self) -> Option { None } @@ -80,6 +84,8 @@ impl ProcessProgBg { pub fn success(self) -> bool { self.state == Some(true) } + pub fn failed(self) -> bool { self.state == Some(false) } + pub fn cleaned(self) -> bool { self.cleaned } pub fn percent(self) -> Option { None } diff --git a/yazi-scheduler/src/progress.rs b/yazi-scheduler/src/progress.rs index d52c4eea..60536fe1 100644 --- a/yazi-scheduler/src/progress.rs +++ b/yazi-scheduler/src/progress.rs @@ -101,6 +101,27 @@ impl TaskProg { } } + pub fn failed(self) -> bool { + match self { + // File + Self::FilePaste(p) => p.failed(), + Self::FileLink(p) => p.failed(), + Self::FileHardlink(p) => p.failed(), + Self::FileDelete(p) => p.failed(), + Self::FileTrash(p) => p.failed(), + // Plugin + Self::PluginEntry(p) => p.failed(), + // Prework + Self::PreworkFetch(p) => p.failed(), + Self::PreworkLoad(p) => p.failed(), + Self::PreworkSize(p) => p.failed(), + // Process + Self::ProcessBlock(p) => p.failed(), + Self::ProcessOrphan(p) => p.failed(), + Self::ProcessBg(p) => p.failed(), + } + } + pub fn cleaned(self) -> bool { match self { // File diff --git a/yazi-scheduler/src/scheduler.rs b/yazi-scheduler/src/scheduler.rs index 93e818bd..ab334854 100644 --- a/yazi-scheduler/src/scheduler.rs +++ b/yazi-scheduler/src/scheduler.rs @@ -81,7 +81,7 @@ impl Scheduler { let id = ongoing.add::(format!("Cut {} to {}", from.display(), to.display())); if to.starts_with(&from) && !to.covariant(&from) { - return self.ops.out(id, FileOutPaste::Deform("Cannot cut directory into itself".to_owned())); + return self.ops.out(id, FileOutPaste::Fail("Cannot cut directory into itself".to_owned())); } ongoing.hooks.add_async(id, { @@ -114,9 +114,7 @@ impl Scheduler { )); if to.starts_with(&from) && !to.covariant(&from) { - return self - .ops - .out(id, FileOutPaste::Deform("Cannot copy directory into itself".to_owned())); + return self.ops.out(id, FileOutPaste::Fail("Cannot copy directory into itself".to_owned())); } let file = self.file.clone(); @@ -154,7 +152,7 @@ impl Scheduler { if to.starts_with(&from) && !to.covariant(&from) { return self .ops - .out(id, FileOutHardlink::Deform("Cannot hardlink directory into itself".to_owned())); + .out(id, FileOutHardlink::Fail("Cannot hardlink directory into itself".to_owned())); } let file = self.file.clone(); @@ -212,16 +210,14 @@ impl Scheduler { pub fn file_download(&self, from: UrlBuf, done: Option>) { let mut ongoing = self.ongoing.lock(); - let id = self.ongoing.lock().add::(format!("Download {}", from.display())); + let id = ongoing.add::(format!("Download {}", from.display())); if let Some(tx) = done { ongoing.hooks.add_sync(id, move |canceled| _ = tx.send(canceled)); } let Some(to) = from.cache().map(UrlBuf::from) else { - return self - .ops - .out(id, FileOutPaste::Deform("Unable to download non-remote file".to_owned())); + return self.ops.out(id, FileOutPaste::Fail("Cannot download non-remote file".to_owned())); }; let file = self.file.clone();