From 1271de47b54cc085416f9ea2bf52222bd36f7cd0 Mon Sep 17 00:00:00 2001 From: aecsocket Date: Thu, 9 Apr 2026 14:52:04 +0100 Subject: [PATCH 1/3] Fix canceling app directory change --- apps/app/src/api/settings.rs | 9 +++++---- packages/app-lib/src/state/mod.rs | 11 +++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/app/src/api/settings.rs b/apps/app/src/api/settings.rs index ccfcdf38ab..ab11f20d51 100644 --- a/apps/app/src/api/settings.rs +++ b/apps/app/src/api/settings.rs @@ -1,4 +1,5 @@ use crate::api::Result; +use tauri::Runtime; use theseus::prelude::*; pub fn init() -> tauri::plugin::TauriPlugin { @@ -28,10 +29,10 @@ pub async fn settings_set(settings: Settings) -> Result<()> { } #[tauri::command] -pub async fn cancel_directory_change() -> Result<()> { - let state = State::get().await?; - let identifier = &state.app_identifier; - +pub async fn cancel_directory_change( + app: tauri::AppHandle, +) -> Result<()> { + let identifier = &app.config().identifier; settings::cancel_directory_change(identifier).await?; Ok(()) } diff --git a/packages/app-lib/src/state/mod.rs b/packages/app-lib/src/state/mod.rs index b44306f92e..f8b21927fc 100644 --- a/packages/app-lib/src/state/mod.rs +++ b/packages/app-lib/src/state/mod.rs @@ -74,9 +74,12 @@ pub struct State { /// Process manager pub process_manager: ProcessManager, - /// App identifier string (like com.modrinth.ModrinthApp) - pub app_identifier: String, - + // NOTE: we explicitly must NOT store the app identifier in the state object, + // because creating the state object is fallible (e.g. database missing), + // but we rely on the app identifier to create the state (data dir). + // + // /// App identifier string (like com.modrinth.ModrinthApp) + // pub app_identifier: String, /// Friends socket pub friends_socket: FriendsSocket, @@ -188,7 +191,7 @@ impl State { friends_socket, pool, file_watcher, - app_identifier, + // app_identifier, })) } } From 108ac8032c18d1617307201e67f2adc789fbd7d4 Mon Sep 17 00:00:00 2001 From: aecsocket Date: Mon, 13 Apr 2026 17:04:27 +0100 Subject: [PATCH 2/3] Improve directory moving error messages --- Cargo.lock | 1 + packages/app-lib/Cargo.toml | 1 + packages/app-lib/src/error.rs | 14 ++++++ packages/app-lib/src/state/dirs.rs | 5 +- packages/app-lib/src/util/io.rs | 73 +++++++++++++++++++++++------- 5 files changed, 75 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2072ef3b22..ee2157d44c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10155,6 +10155,7 @@ dependencies = [ "either", "encoding_rs", "enumset", + "eyre", "flate2", "fs4", "futures", diff --git a/packages/app-lib/Cargo.toml b/packages/app-lib/Cargo.toml index d2470da7da..5c2ef99584 100644 --- a/packages/app-lib/Cargo.toml +++ b/packages/app-lib/Cargo.toml @@ -22,6 +22,7 @@ async_zip = { workspace = true, features = [ "tokio-fs", "zstd", ] } +eyre = { workspace = true } base64 = { workspace = true } bytemuck = { workspace = true, features = ["extern_crate_alloc"] } bytes = { workspace = true, features = ["serde"] } diff --git a/packages/app-lib/src/error.rs b/packages/app-lib/src/error.rs index f18bf3a44a..ddfa9794a8 100644 --- a/packages/app-lib/src/error.rs +++ b/packages/app-lib/src/error.rs @@ -16,6 +16,9 @@ pub struct LabrinthError { #[derive(thiserror::Error, Debug)] pub enum ErrorKind { + #[error("{0:?}")] + Any(eyre::Report), + #[error("Filesystem error: {0}")] FSError(String), @@ -214,6 +217,17 @@ impl> From for Error { } } +impl From for Error { + fn from(value: eyre::Report) -> Self { + let error = Arc::new(ErrorKind::Any(value)); + + Self { + raw: error.clone(), + source: error.in_current_span(), + } + } +} + impl ErrorKind { pub fn as_error(self) -> Error { self.into() diff --git a/packages/app-lib/src/state/dirs.rs b/packages/app-lib/src/state/dirs.rs index b098dbcac0..3a23da8629 100644 --- a/packages/app-lib/src/state/dirs.rs +++ b/packages/app-lib/src/state/dirs.rs @@ -364,10 +364,9 @@ impl DirectoryInfo { .map_err(|e| { crate::Error::from(crate::ErrorKind::DirectoryMoveError( format!( - "Failed to move directory from {} to {}: {}", + "Failed to move directory from {} to {}: {e:?}", x.old.display(), x.new.display(), - e ), )) })?; @@ -421,7 +420,7 @@ impl DirectoryInfo { io_semaphore, ) .await.map_err(|e| { crate::Error::from( - crate::ErrorKind::DirectoryMoveError(format!("Failed to move directory from {} to {}: {}", x.old.display(), x.new.display(), e))) + crate::ErrorKind::DirectoryMoveError(format!("Failed to move directory from {} to {}: {e:?}", x.old.display(), x.new.display()))) })?; let _ = emit_loading( diff --git a/packages/app-lib/src/util/io.rs b/packages/app-lib/src/util/io.rs index 7bdc358f68..ea40bd9f79 100644 --- a/packages/app-lib/src/util/io.rs +++ b/packages/app-lib/src/util/io.rs @@ -1,6 +1,7 @@ // IO error // A wrapper around the tokio IO functions that adds the path to the error message, instead of the uninformative std::io::Error. +use eyre::{Context, ContextCompat, Result, eyre}; use std::{ io::{ErrorKind, Write}, path::Path, @@ -181,17 +182,34 @@ fn sync_write( std::io::Result::Ok(()) } -pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result { +pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result { #[cfg(unix)] { use std::os::unix::fs::MetadataExt; - Ok(old_dir.metadata()?.dev() == new_dir.metadata()?.dev()) + + use eyre::eyre; + + // we need to use `symlink_metadata` instead of `metadata`, because + // if this file is a symlink, we need to query the symlink file itself, + // rather than the target. + // downloaded JREs use symlinks to point to certain stuff like LICENSE + // files. + // this fixes moving JRE dirs. + + let old_meta = std::fs::symlink_metadata(old_dir) + .wrap_err_with(|| eyre!("getting meta of old dir {old_dir:?}"))?; + let new_meta = std::fs::symlink_metadata(new_dir) + .wrap_err_with(|| eyre!("getting meta of new dir {new_dir:?}"))?; + + Ok(old_meta.dev() == new_meta.dev()) } #[cfg(windows)] { - let old_dir = canonicalize(old_dir)?; - let new_dir = canonicalize(new_dir)?; + let old_dir = canonicalize(old_dir) + .wrap_err_with(|| eyre!("canonicalizing {old_dir:?}"))?; + let new_dir = canonicalize(new_dir) + .wrap_err_with(|| eyre!("canonicalizing {new_dir:?}"))?; let old_component = old_dir.components().next(); let new_component = new_dir.components().next(); @@ -209,39 +227,62 @@ pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result { pub async fn rename_or_move( from: impl AsRef, to: impl AsRef, -) -> Result<(), IOError> { +) -> Result<()> { let from = from.as_ref(); let to = to.as_ref(); - if to + let to_parent = to .parent() - .map_or(Ok(false), |to_dir| is_same_disk(from, to_dir))? - { + .wrap_err_with(|| eyre!("getting parent of `to` dir {to:?}"))?; + let same_disk = is_same_disk(from, to_parent).wrap_err_with(|| { + eyre!("checking if `to_parent` ({to_parent:?}) and `from` ({from:?}) are on the same disk") + })?; + + if same_disk { tokio::fs::rename(from, to) .await .map_err(|e| IOError::IOPathError { source: e, path: from.to_string_lossy().to_string(), }) + .wrap_err_with(|| eyre!("moving {from:?} to {to:?} on same disk")) } else { - move_recursive(from, to).await + move_recursive(from, to).await.with_context(|| { + eyre!("moving {from:?} to {to:?} on different disks") + }) } } #[async_recursion::async_recursion] -async fn move_recursive(from: &Path, to: &Path) -> Result<(), IOError> { +async fn move_recursive(from: &Path, to: &Path) -> Result<()> { if from.is_file() { - copy(from, to).await?; - remove_file(from).await?; + copy(from, to) + .await + .wrap_err_with(|| eyre!("copying {from:?} to {to:?}"))?; + remove_file(from).await.wrap_err_with(|| { + eyre!("removing {from:?} after copying to {to:?}") + })?; return Ok(()); } - create_dir(to).await?; + create_dir(to) + .await + .wrap_err_with(|| eyre!("creating dir for {to:?}"))?; - let mut dir = read_dir(from).await?; - while let Some(entry) = dir.next_entry().await? { + let mut dir = read_dir(from) + .await + .wrap_err_with(|| eyre!("reading dir {from:?}"))?; + while let Some(entry) = dir + .next_entry() + .await + .wrap_err_with(|| eyre!("reading dir entry in {from:?}"))? + { let new_path = to.join(entry.file_name()); - move_recursive(&entry.path(), &new_path).await?; + move_recursive(&entry.path(), &new_path) + .await + .with_context(|| { + eyre!("moving {:?} to {new_path:?}", entry.path()) + })?; } Ok(()) From 0f8da5874558ff66e66d71de5a2315c5bf31d734 Mon Sep 17 00:00:00 2001 From: aecsocket Date: Thu, 16 Apr 2026 13:06:32 +0100 Subject: [PATCH 3/3] tombi --- packages/app-lib/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/app-lib/Cargo.toml b/packages/app-lib/Cargo.toml index 5c2ef99584..39f2ae1a47 100644 --- a/packages/app-lib/Cargo.toml +++ b/packages/app-lib/Cargo.toml @@ -22,7 +22,6 @@ async_zip = { workspace = true, features = [ "tokio-fs", "zstd", ] } -eyre = { workspace = true } base64 = { workspace = true } bytemuck = { workspace = true, features = ["extern_crate_alloc"] } bytes = { workspace = true, features = ["serde"] } @@ -38,6 +37,7 @@ dunce = { workspace = true } either = { workspace = true } encoding_rs = { workspace = true } enumset = { workspace = true } +eyre = { workspace = true } flate2 = { workspace = true } fs4 = { workspace = true, features = ["tokio"] } futures = { workspace = true, features = ["alloc", "async-await"] }