From 7c226ce68483d4890204c65e82e7c2898d2d7c7e Mon Sep 17 00:00:00 2001 From: t8y2 <1156263951@qq.com> Date: Sun, 17 May 2026 12:44:34 +0800 Subject: [PATCH] fix(app): support portable data directory --- .github/workflows/release.yml | 1 + src-tauri/src/data_dir.rs | 58 +++++++++++++++++++++++++++++++++++ src-tauri/src/lib.rs | 4 ++- 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src-tauri/src/data_dir.rs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 411ace211..08c0c3fbb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -157,6 +157,7 @@ jobs: Copy-Item $exePath (Join-Path $portableDir "DBX.exe") -Force Copy-Item "LICENSE" (Join-Path $portableDir "LICENSE") -Force Copy-Item "README.md" (Join-Path $portableDir "README.md") -Force + Set-Content -Path (Join-Path $portableDir "portable.dbx") -Value "" -NoNewline Compress-Archive -Path (Join-Path $portableDir "*") -DestinationPath $zipName -Force gh release upload "${env:GITHUB_REF_NAME}" $zipName --repo "${env:GITHUB_REPOSITORY}" --clobber diff --git a/src-tauri/src/data_dir.rs b/src-tauri/src/data_dir.rs new file mode 100644 index 000000000..80a162816 --- /dev/null +++ b/src-tauri/src/data_dir.rs @@ -0,0 +1,58 @@ +use std::path::PathBuf; + +#[cfg(target_os = "windows")] +const PORTABLE_MARKER: &str = "portable.dbx"; + +pub fn resolve_data_dir(default_app_data_dir: PathBuf) -> PathBuf { + if let Some(env_dir) = std::env::var_os("DBX_DATA_DIR").filter(|value| !value.is_empty()) { + return PathBuf::from(env_dir); + } + + #[cfg(target_os = "windows")] + if let Some(exe_dir) = current_exe_dir() { + if exe_dir.join(PORTABLE_MARKER).is_file() { + return exe_dir.join("data"); + } + } + + default_app_data_dir +} + +#[cfg(target_os = "windows")] +fn current_exe_dir() -> Option { + std::env::current_exe().ok().and_then(|path| path.parent().map(std::path::Path::to_path_buf)) +} + +#[cfg(test)] +fn resolve_data_dir_from_inputs( + default_app_data_dir: PathBuf, + exe_dir: Option, + portable_marker_exists: bool, + env_data_dir: Option, +) -> PathBuf { + if let Some(env_dir) = env_data_dir { + return env_dir; + } + + match (exe_dir, portable_marker_exists) { + (Some(dir), true) => dir.join("data"), + _ => default_app_data_dir, + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use super::resolve_data_dir_from_inputs; + + #[test] + fn uses_portable_data_dir_when_marker_exists() { + let default_dir = PathBuf::from(r"C:\Users\Administrator\AppData\Roaming\com.dbx.app"); + let exe_dir = PathBuf::from(r"D:\Apps\DBX"); + + let data_dir = resolve_data_dir_from_inputs(default_dir, Some(exe_dir.clone()), true, None); + + assert_eq!(data_dir, exe_dir.join("data")); + } +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 5eb29ba33..b58440dac 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,5 @@ mod commands; +mod data_dir; mod db; mod models; @@ -29,8 +30,9 @@ pub fn run() { app.handle().plugin(tauri_plugin_log::Builder::default().level(log::LevelFilter::Info).build())?; } - let data_dir = + let default_data_dir = app.path().app_data_dir().map_err(|e| e.to_string()).expect("Failed to resolve app data dir"); + let data_dir = data_dir::resolve_data_dir(default_data_dir); std::fs::create_dir_all(&data_dir).expect("Failed to create data dir"); let db_path = data_dir.join("dbx.db");