use anyhow::{bail, Result};
use std::path::Path;
use crate::config::Config;
pub fn write_appimage_bundle(config: &Config, linux_dir: &Path, out_dir: &Path) -> Result<()> {
let app_id = &config.app.id;
let app_name = config.app.name.replace(' ', "_");
let hicolor_dir = linux_dir.join("hicolor");
if !hicolor_dir.exists() {
bail!(
"AppImage packaging requires the Linux hicolor tree — enable [platforms] linux = true"
);
}
let appdir = out_dir.join("appimage").join(format!("{}.AppDir", app_name));
std::fs::create_dir_all(&appdir)?;
let icon_name = format!("{}.png", app_id);
let icon_src = hicolor_dir
.join("256x256")
.join("apps")
.join(&icon_name);
if !icon_src.exists() {
bail!("256×256 PNG not found at {}", icon_src.display());
}
std::fs::copy(&icon_src, appdir.join(&icon_name))?;
let diricon = appdir.join(".DirIcon");
if diricon.exists() || diricon.is_symlink() {
std::fs::remove_file(&diricon)?;
}
#[cfg(unix)]
std::os::unix::fs::symlink(&icon_name, &diricon)?;
#[cfg(not(unix))]
std::fs::copy(&icon_src, &diricon)?;
let desktop_src = linux_dir.join(format!("{}.desktop", app_id));
if !desktop_src.exists() {
bail!(".desktop not found at {}", desktop_src.display());
}
std::fs::copy(&desktop_src, appdir.join(format!("{}.desktop", app_id)))?;
let share = appdir.join("usr").join("share");
let apps_dir = share.join("applications");
std::fs::create_dir_all(&apps_dir)?;
std::fs::copy(&desktop_src, apps_dir.join(format!("{}.desktop", app_id)))?;
let metainfo_src = linux_dir.join(format!("{}.metainfo.xml", app_id));
if metainfo_src.exists() {
let metainfo_dir = share.join("metainfo");
std::fs::create_dir_all(&metainfo_dir)?;
std::fs::copy(&metainfo_src, metainfo_dir.join(format!("{}.metainfo.xml", app_id)))?;
}
copy_hicolor_subset(&hicolor_dir, &share.join("icons").join("hicolor"), app_id)?;
Ok(())
}
fn copy_hicolor_subset(hicolor_src: &Path, hicolor_dst: &Path, app_id: &str) -> Result<()> {
for size in &[128u32, 256] {
let dir_name = format!("{}x{}", size, size);
let src = hicolor_src.join(&dir_name).join("apps").join(format!("{}.png", app_id));
if src.exists() {
let dst = hicolor_dst.join(&dir_name).join("apps").join(format!("{}.png", app_id));
std::fs::create_dir_all(dst.parent().unwrap())?;
std::fs::copy(&src, &dst)?;
}
}
let scalable_src = hicolor_src
.join("scalable")
.join("apps")
.join(format!("{}.svg", app_id));
if scalable_src.exists() {
let scalable_dst = hicolor_dst
.join("scalable")
.join("apps")
.join(format!("{}.svg", app_id));
std::fs::create_dir_all(scalable_dst.parent().unwrap())?;
std::fs::copy(&scalable_src, &scalable_dst)?;
}
Ok(())
}