soar_core/package/formats/
appimage.rs

1use std::{fs, path::Path};
2
3use squishy::{appimage::AppImage, EntryKind};
4
5use crate::{
6    constants::PNG_MAGIC_BYTES, database::models::PackageExt, error::ErrorContext,
7    utils::calc_magic_bytes, SoarResult,
8};
9
10use super::common::{symlink_desktop, symlink_icon};
11
12pub async fn integrate_appimage<P: AsRef<Path>, T: PackageExt>(
13    install_dir: P,
14    file_path: P,
15    package: &T,
16    has_icon: bool,
17    has_desktop: bool,
18) -> SoarResult<()> {
19    if has_icon && has_desktop {
20        return Ok(());
21    }
22
23    let install_dir = install_dir.as_ref();
24    let pkg_name = package.pkg_name();
25    let appimage = AppImage::new(None, &file_path, None)?;
26    let squashfs = &appimage.squashfs;
27
28    if !has_icon {
29        if let Some(entry) = appimage.find_icon() {
30            if let EntryKind::File(basic_file) = entry.kind {
31                let dest = format!("{}/{}.DirIcon", install_dir.display(), pkg_name);
32                let _ = squashfs.write_file(basic_file, &dest);
33
34                let magic_bytes = calc_magic_bytes(&dest, 8)?;
35                let ext = if magic_bytes == PNG_MAGIC_BYTES {
36                    "png"
37                } else {
38                    "svg"
39                };
40                let final_path = format!("{}/{}.{ext}", install_dir.display(), pkg_name);
41                fs::rename(&dest, &final_path)
42                    .with_context(|| format!("renaming from {dest} to {final_path}"))?;
43
44                symlink_icon(final_path)?;
45            }
46        }
47    }
48
49    if !has_desktop {
50        if let Some(entry) = appimage.find_desktop() {
51            if let EntryKind::File(basic_file) = entry.kind {
52                let dest = format!("{}/{}.desktop", install_dir.display(), pkg_name);
53                let _ = squashfs.write_file(basic_file, &dest);
54                symlink_desktop(dest, package)?;
55            }
56        }
57    }
58
59    if let Some(entry) = appimage.find_appstream() {
60        if let EntryKind::File(basic_file) = entry.kind {
61            let file_name = if entry
62                .path
63                .file_name()
64                .unwrap()
65                .to_string_lossy()
66                .contains("appdata")
67            {
68                "appdata"
69            } else {
70                "metainfo"
71            };
72            let dest = format!("{}/{}.{file_name}.xml", install_dir.display(), pkg_name);
73            let _ = squashfs.write_file(basic_file, &dest);
74        }
75    }
76    Ok(())
77}