Linux app id: ai.storyteller.solidcraft, with an end-of-life rebase from the old id (#619)
The Flatpak app id, desktop/metainfo/MIME file names, icon name and the window's Wayland app_id / X11 class are now ai.storyteller.solidcraft, the id the ArtCraft launcher expects. Existing Flatpak installs move over: the Pages repo marks app/ai.storyteller.solvecraft end-of-life with a rebase to the new id, so flatpak update offers the switch and Flatpak carries ~/.var/app along. A new install next to the old one copies settings and autosaves on first launch through a read-only grant on the old data folder. The metainfo declares <replaces>/<provides>, the desktop entry X-Flatpak-RenamedFrom, and AppImages drop the menu entry an older AppImage installed. deb/rpm upgrades remove the old-named files. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
bcbfa50eac
commit
e67cc0c747
21 files changed
+194
-68
No files matched your search
@@ -35,10 +35,13 @@ pub fn default_dir() -> Option<PathBuf> {
|
||||
env("XDG_DATA_HOME").or_else(|| env("HOME").map(|h| h.join(".local/share")))?
|
||||
};
|
||||
let (dir, legacy) = dirs_under(&root, cfg!(windows) || cfg!(target_os = "macos"));
|
||||
// Compatibility shim (docs/compatibility.md): autosaves made before the rename are copied
|
||||
// to the new folder on first launch; the old folder is left as it was.
|
||||
if let Err(e) = solidcraft_io::adopt_legacy_dir(&dir, &legacy) {
|
||||
log::warn!("recovery: could not copy {} to {}: {e}", legacy.display(), dir.display());
|
||||
// Compatibility shim (docs/compatibility.md): autosaves made before the rename (or, in the
|
||||
// Flatpak sandbox, under the old app id) are copied to the new folder on first launch; the
|
||||
// old folder is left as it was.
|
||||
for old in solidcraft_io::legacy_flatpak_path(&dir).into_iter().chain([legacy]) {
|
||||
if let Err(e) = solidcraft_io::adopt_legacy_dir(&dir, &old) {
|
||||
log::warn!("recovery: could not copy {} to {}: {e}", old.display(), dir.display());
|
||||
}
|
||||
}
|
||||
Some(dir)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
//! the legacy folder is copied over. The legacy folder is never changed or deleted, so an older
|
||||
//! release installed side by side keeps working.
|
||||
|
||||
use std::path::Path;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// The Linux app id (Flatpak, desktop entry, AppStream, Wayland `app_id`).
|
||||
pub const APP_ID: &str = "ai.storyteller.solidcraft";
|
||||
/// The app id of releases before 0.8 (compatibility shim, docs/compatibility.md).
|
||||
pub const LEGACY_APP_ID: &str = "ai.storyteller.solvecraft";
|
||||
|
||||
/// Most files and nesting copied from a legacy folder (it holds preferences, autosaves and
|
||||
/// small caches; anything bigger is not ours).
|
||||
@@ -22,6 +27,25 @@ pub fn adopt_legacy_dir(current: &Path, legacy: &Path) -> std::io::Result<bool>
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// In the Flatpak sandbox, the same `path` under the pre-rename app's data folder: Flatpak keeps
|
||||
/// each app's XDG folders under `~/.var/app/<app id>`, so after the app id changed, settings and
|
||||
/// autosaves of earlier Flatpak releases sit under the old id. `None` outside the sandbox or for
|
||||
/// paths outside our own `~/.var/app` folder. Flatpak moves that folder itself when an install
|
||||
/// follows the end-of-life rebase; this covers installs made next to the old app, which reach it
|
||||
/// read-only through the manifest's `--filesystem` grant.
|
||||
pub fn legacy_flatpak_path(path: &Path) -> Option<PathBuf> {
|
||||
flatpak_twin(path, &std::env::var_os("FLATPAK_ID")?, Path::new(&std::env::var_os("HOME")?))
|
||||
}
|
||||
|
||||
fn flatpak_twin(path: &Path, flatpak_id: &std::ffi::OsStr, home: &Path) -> Option<PathBuf> {
|
||||
if flatpak_id != APP_ID {
|
||||
return None;
|
||||
}
|
||||
let apps = home.join(".var").join("app");
|
||||
let rel = path.strip_prefix(apps.join(APP_ID)).ok()?;
|
||||
Some(apps.join(LEGACY_APP_ID).join(rel))
|
||||
}
|
||||
|
||||
fn copy_tree(from: &Path, to: &Path, depth: usize, budget: &mut usize) -> std::io::Result<()> {
|
||||
std::fs::create_dir_all(to)?;
|
||||
if depth >= MAX_DEPTH {
|
||||
@@ -75,6 +99,17 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&d);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn flatpak_twin_maps_our_sandbox_data_to_the_old_app_id() {
|
||||
let home = Path::new("/home/u");
|
||||
let ours = home.join(".var/app/ai.storyteller.solidcraft/data/solidcraft");
|
||||
let id = std::ffi::OsStr::new(APP_ID);
|
||||
assert_eq!(flatpak_twin(&ours, id, home), Some(home.join(".var/app/ai.storyteller.solvecraft/data/solidcraft")));
|
||||
// Outside our sandbox folder, or in another app's sandbox, there is nothing to map.
|
||||
assert_eq!(flatpak_twin(&home.join(".local/share/solidcraft"), id, home), None);
|
||||
assert_eq!(flatpak_twin(&ours, std::ffi::OsStr::new("org.example.Other"), home), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nothing_to_adopt() {
|
||||
let d = scratch("none");
|
||||
|
||||
@@ -23,7 +23,7 @@ mod threemf;
|
||||
pub mod vfs;
|
||||
|
||||
pub use dxf::{read_dxf, write_dxf};
|
||||
pub use legacy_dir::adopt_legacy_dir;
|
||||
pub use legacy_dir::{APP_ID, LEGACY_APP_ID, adopt_legacy_dir, legacy_flatpak_path};
|
||||
pub use safe_write::{backup_path, write_atomic};
|
||||
pub use sketch2d::{Geom2, MAX_DRAWING_BYTES};
|
||||
pub use svg::read_svg;
|
||||
|
||||
Reference in new issue
Block a user