Skip to content

Commit 9483656

Browse files
authored
Fix issues relating to app directory changes (#5826)
* Fix canceling app directory change * Improve directory moving error messages * tombi
1 parent 7c642f7 commit 9483656

7 files changed

Lines changed: 87 additions & 27 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/app/src/api/settings.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::api::Result;
2+
use tauri::Runtime;
23
use theseus::prelude::*;
34

45
pub fn init<R: tauri::Runtime>() -> tauri::plugin::TauriPlugin<R> {
@@ -28,10 +29,10 @@ pub async fn settings_set(settings: Settings) -> Result<()> {
2829
}
2930

3031
#[tauri::command]
31-
pub async fn cancel_directory_change() -> Result<()> {
32-
let state = State::get().await?;
33-
let identifier = &state.app_identifier;
34-
32+
pub async fn cancel_directory_change<R: Runtime>(
33+
app: tauri::AppHandle<R>,
34+
) -> Result<()> {
35+
let identifier = &app.config().identifier;
3536
settings::cancel_directory_change(identifier).await?;
3637
Ok(())
3738
}

packages/app-lib/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ dunce = { workspace = true }
3737
either = { workspace = true }
3838
encoding_rs = { workspace = true }
3939
enumset = { workspace = true }
40+
eyre = { workspace = true }
4041
flate2 = { workspace = true }
4142
fs4 = { workspace = true, features = ["tokio"] }
4243
futures = { workspace = true, features = ["alloc", "async-await"] }

packages/app-lib/src/error.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ pub struct LabrinthError {
1616

1717
#[derive(thiserror::Error, Debug)]
1818
pub enum ErrorKind {
19+
#[error("{0:?}")]
20+
Any(eyre::Report),
21+
1922
#[error("Filesystem error: {0}")]
2023
FSError(String),
2124

@@ -214,6 +217,17 @@ impl<E: Into<ErrorKind>> From<E> for Error {
214217
}
215218
}
216219

220+
impl From<eyre::Report> for Error {
221+
fn from(value: eyre::Report) -> Self {
222+
let error = Arc::new(ErrorKind::Any(value));
223+
224+
Self {
225+
raw: error.clone(),
226+
source: error.in_current_span(),
227+
}
228+
}
229+
}
230+
217231
impl ErrorKind {
218232
pub fn as_error(self) -> Error {
219233
self.into()

packages/app-lib/src/state/dirs.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -364,10 +364,9 @@ impl DirectoryInfo {
364364
.map_err(|e| {
365365
crate::Error::from(crate::ErrorKind::DirectoryMoveError(
366366
format!(
367-
"Failed to move directory from {} to {}: {}",
367+
"Failed to move directory from {} to {}: {e:?}",
368368
x.old.display(),
369369
x.new.display(),
370-
e
371370
),
372371
))
373372
})?;
@@ -421,7 +420,7 @@ impl DirectoryInfo {
421420
io_semaphore,
422421
)
423422
.await.map_err(|e| { crate::Error::from(
424-
crate::ErrorKind::DirectoryMoveError(format!("Failed to move directory from {} to {}: {}", x.old.display(), x.new.display(), e)))
423+
crate::ErrorKind::DirectoryMoveError(format!("Failed to move directory from {} to {}: {e:?}", x.old.display(), x.new.display())))
425424
})?;
426425

427426
let _ = emit_loading(

packages/app-lib/src/state/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,12 @@ pub struct State {
7474
/// Process manager
7575
pub process_manager: ProcessManager,
7676

77-
/// App identifier string (like com.modrinth.ModrinthApp)
78-
pub app_identifier: String,
79-
77+
// NOTE: we explicitly must NOT store the app identifier in the state object,
78+
// because creating the state object is fallible (e.g. database missing),
79+
// but we rely on the app identifier to create the state (data dir).
80+
//
81+
// /// App identifier string (like com.modrinth.ModrinthApp)
82+
// pub app_identifier: String,
8083
/// Friends socket
8184
pub friends_socket: FriendsSocket,
8285

@@ -188,7 +191,7 @@ impl State {
188191
friends_socket,
189192
pool,
190193
file_watcher,
191-
app_identifier,
194+
// app_identifier,
192195
}))
193196
}
194197
}

packages/app-lib/src/util/io.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// IO error
22
// A wrapper around the tokio IO functions that adds the path to the error message, instead of the uninformative std::io::Error.
33

4+
use eyre::{Context, ContextCompat, Result, eyre};
45
use std::{
56
io::{ErrorKind, Write},
67
path::Path,
@@ -181,17 +182,34 @@ fn sync_write(
181182
std::io::Result::Ok(())
182183
}
183184

184-
pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result<bool, IOError> {
185+
pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result<bool> {
185186
#[cfg(unix)]
186187
{
187188
use std::os::unix::fs::MetadataExt;
188-
Ok(old_dir.metadata()?.dev() == new_dir.metadata()?.dev())
189+
190+
use eyre::eyre;
191+
192+
// we need to use `symlink_metadata` instead of `metadata`, because
193+
// if this file is a symlink, we need to query the symlink file itself,
194+
// rather than the target.
195+
// downloaded JREs use symlinks to point to certain stuff like LICENSE
196+
// files.
197+
// this fixes moving JRE dirs.
198+
199+
let old_meta = std::fs::symlink_metadata(old_dir)
200+
.wrap_err_with(|| eyre!("getting meta of old dir {old_dir:?}"))?;
201+
let new_meta = std::fs::symlink_metadata(new_dir)
202+
.wrap_err_with(|| eyre!("getting meta of new dir {new_dir:?}"))?;
203+
204+
Ok(old_meta.dev() == new_meta.dev())
189205
}
190206

191207
#[cfg(windows)]
192208
{
193-
let old_dir = canonicalize(old_dir)?;
194-
let new_dir = canonicalize(new_dir)?;
209+
let old_dir = canonicalize(old_dir)
210+
.wrap_err_with(|| eyre!("canonicalizing {old_dir:?}"))?;
211+
let new_dir = canonicalize(new_dir)
212+
.wrap_err_with(|| eyre!("canonicalizing {new_dir:?}"))?;
195213

196214
let old_component = old_dir.components().next();
197215
let new_component = new_dir.components().next();
@@ -209,39 +227,62 @@ pub fn is_same_disk(old_dir: &Path, new_dir: &Path) -> Result<bool, IOError> {
209227
pub async fn rename_or_move(
210228
from: impl AsRef<std::path::Path>,
211229
to: impl AsRef<std::path::Path>,
212-
) -> Result<(), IOError> {
230+
) -> Result<()> {
213231
let from = from.as_ref();
214232
let to = to.as_ref();
215233

216-
if to
234+
let to_parent = to
217235
.parent()
218-
.map_or(Ok(false), |to_dir| is_same_disk(from, to_dir))?
219-
{
236+
.wrap_err_with(|| eyre!("getting parent of `to` dir {to:?}"))?;
237+
let same_disk = is_same_disk(from, to_parent).wrap_err_with(|| {
238+
eyre!("checking if `to_parent` ({to_parent:?}) and `from` ({from:?}) are on the same disk")
239+
})?;
240+
241+
if same_disk {
220242
tokio::fs::rename(from, to)
221243
.await
222244
.map_err(|e| IOError::IOPathError {
223245
source: e,
224246
path: from.to_string_lossy().to_string(),
225247
})
248+
.wrap_err_with(|| eyre!("moving {from:?} to {to:?} on same disk"))
226249
} else {
227-
move_recursive(from, to).await
250+
move_recursive(from, to).await.with_context(|| {
251+
eyre!("moving {from:?} to {to:?} on different disks")
252+
})
228253
}
229254
}
230255

231256
#[async_recursion::async_recursion]
232-
async fn move_recursive(from: &Path, to: &Path) -> Result<(), IOError> {
257+
async fn move_recursive(from: &Path, to: &Path) -> Result<()> {
233258
if from.is_file() {
234-
copy(from, to).await?;
235-
remove_file(from).await?;
259+
copy(from, to)
260+
.await
261+
.wrap_err_with(|| eyre!("copying {from:?} to {to:?}"))?;
262+
remove_file(from).await.wrap_err_with(|| {
263+
eyre!("removing {from:?} after copying to {to:?}")
264+
})?;
236265
return Ok(());
237266
}
238267

239-
create_dir(to).await?;
268+
create_dir(to)
269+
.await
270+
.wrap_err_with(|| eyre!("creating dir for {to:?}"))?;
240271

241-
let mut dir = read_dir(from).await?;
242-
while let Some(entry) = dir.next_entry().await? {
272+
let mut dir = read_dir(from)
273+
.await
274+
.wrap_err_with(|| eyre!("reading dir {from:?}"))?;
275+
while let Some(entry) = dir
276+
.next_entry()
277+
.await
278+
.wrap_err_with(|| eyre!("reading dir entry in {from:?}"))?
279+
{
243280
let new_path = to.join(entry.file_name());
244-
move_recursive(&entry.path(), &new_path).await?;
281+
move_recursive(&entry.path(), &new_path)
282+
.await
283+
.with_context(|| {
284+
eyre!("moving {:?} to {new_path:?}", entry.path())
285+
})?;
245286
}
246287

247288
Ok(())

0 commit comments

Comments
 (0)