collective

Browse / github.com/storytold/craft-launcher / patch

Linux: detect versions of renamed AppImages (#471)

launcher does not seem to be able to detect versions in AppImage nor suggest update I have 0.7.0 photocraft as indicated by gear level (reload meta data button) <img width="1418" height="1127" alt="Image" src="https://github.com/user-attachments/assets/076a04e1-65ba-4175-8cdf-4dab322d7272" /> the latest is 0.9.0, but the launcher thinks i'm on the latest <img width="2379" height="1576" alt="Image" src="https://github.com/user-attachments/assets/a1b21c6d-a961-4f32-9172-5e4daeb330ca" /> both photocraft and launcher were app image note: the flatpak launcher is also have the same issue with app image photocraft.

Status
open
Score
0.00
Adopters
0 other operators
Author
FredApps (imported from pull request #499, open)
Base
3fd2d56999fa00a7b90f159cb686a5fc64347e7e
Size
+59 −1 in 1 file
Review
pending
Shared
2026-10-28
Id
b5312a6d96d06451eb8a1583

How it went

No other operator has reported using it yet.

Diff

raw · crates/native/src/detect.rs

diff --git a/crates/native/src/detect.rs b/crates/native/src/detect.rs--- a/crates/native/src/detect.rs+++ b/crates/native/src/detect.rs@@ -374,7 +374,12 @@ pub mod linux {      pub fn detect(app: &CraftApp, snapshot: &Snapshot) -> Option<Installed> {         if let Some((path, version)) = appimages(app).into_iter().next() {-            return Some(Installed { version, source: InstallSource::AppImage, location: path.display().to_string(), package: None });+            return Some(appimage_install(app, path, version, |bin, app| {+                let (program, args) = appimage_probe_command(bin, crate::process::in_sandbox())?;+                let args: Vec<&str> = args.iter().map(String::as_str).collect();+                let out = crate::process::capture(&program, &args, Duration::from_secs(5))?;+                parse_cli_version(out.trim(), app)+            }));         }         let order = [InstallSource::Deb, InstallSource::Rpm, InstallSource::Pacman, InstallSource::Flatpak];         if let Some(p) = packages::find(app, &snapshot.packages, &order) {@@ -384,6 +389,25 @@ pub mod linux {         detect_system_install(app)     } +    /// Bare AppImage names (for example Gear Lever's rename) carry no version (#471).+    /// Probe only the selected unknown-version app; release filenames need no execution.+    pub(crate) fn appimage_install(+        app: &CraftApp,+        path: PathBuf,+        version: Option<version::Version>,+        probe: impl FnOnce(&Path, &CraftApp) -> Option<version::Version>,+    ) -> Installed {+        let version = version.or_else(|| probe(&path, app));+        Installed { version, source: InstallSource::AppImage, location: path.display().to_string(), package: None }+    }++    /// A host AppImage must be queried on the host when the launcher runs inside Flatpak,+    /// just as launching it is. Paths remain individual arguments, never shell commands.+    pub(crate) fn appimage_probe_command(bin: &Path, sandbox: bool) -> Option<(String, Vec<String>)> {+        let path = bin.to_str()?.to_string();+        Some(if sandbox { ("flatpak-spawn".into(), vec!["--host".into(), path, "--version".into()]) } else { (path, vec!["--version".into()]) })+    }+     /// When the package managers don't report the app (a query timed out or was locked, an     /// unlisted package name, or a sandbox that can't see them) but its binary is there. It is     /// reported as a system binary: the launcher can open it but leaves updating and removing it@@ -431,6 +455,40 @@ pub mod freebsd { mod linux_tests {     use super::*; +    #[test]+    fn renamed_appimage_reports_its_cli_version_and_offers_the_update() {+        use artcraft_launcher_core::status::{AppStatus, Latest, status};+        let app = CraftApp::by_id("photocraft").unwrap();+        let installed = linux::appimage_install(app, PathBuf::from("/tmp/My Apps/photocraft.appimage"), None, |_, app| {+            parse_cli_version("photocraft 0.7.0 (792616159, 2026-10-11)", app)+        });+        let latest = version::parse("0.9.0").unwrap();+        assert_eq!(installed.version.as_ref().unwrap().to_string(), "0.7.0");+        assert_eq!(status(Some(&installed), Latest::Found { version: Some(&latest), has_asset: true }), AppStatus::UpdateAvailable);+    }++    #[test]+    fn known_appimage_versions_skip_the_probe_and_failed_probes_stay_unknown() {+        let app = CraftApp::by_id("photocraft").unwrap();+        let known = linux::appimage_install(app, PathBuf::from("photocraft-0.7.0-linux-x86_64.AppImage"), version::parse("0.7.0"), |_, _| {+            panic!("release filename already gives the version")+        });+        assert_eq!(known.version.unwrap().to_string(), "0.7.0");+        let unknown = linux::appimage_install(app, PathBuf::from("photocraft.appimage"), None, |_, _| None);+        assert!(unknown.version.is_none());+        assert_eq!(unknown.source, InstallSource::AppImage);+    }++    #[test]+    fn appimage_version_probe_uses_host_arguments_in_flatpak() {+        let path = Path::new("/home/user/My Apps/photo;craft.appimage");+        assert_eq!(linux::appimage_probe_command(path, false), Some((path.display().to_string(), vec!["--version".into()])));+        assert_eq!(+            linux::appimage_probe_command(path, true),+            Some(("flatpak-spawn".into(), vec!["--host".into(), path.display().to_string(), "--version".into()]))+        );+    }+     #[test]     fn ours_filter_matches_rpm_packages() {         let ours = |name: &str| {