use std::path::Path;
use askama::Template;
use color_eyre::eyre::{self};
use smol::fs;
use crate::project::Project;
use crate::project_model::assets;
#[derive(Template)]
#[template(path = "linux/app.desktop.tpl", escape = "none")]
struct DesktopEntryTemplate<'a> {
app_name: &'a str,
executable_name: &'a str,
bundle_identifier: &'a str,
}
pub async fn write_linux_share_material(
project: &Project,
app_name: &str,
executable_name: &str,
share_dir: &Path,
) -> eyre::Result<()> {
let applications_dir = share_dir.join("applications");
fs::create_dir_all(&applications_dir).await?;
let entry = DesktopEntryTemplate {
app_name,
executable_name,
bundle_identifier: project.bundle_identifier(),
}
.render()
.map_err(|error| eyre::eyre!("Failed to render desktop entry: {error}"))?;
fs::write(
applications_dir.join(format!("{}.desktop", project.bundle_identifier())),
entry,
)
.await?;
assets::stage_hicolor_icons(project, &share_dir.join("icons")).await?;
Ok(())
}
#[cfg(test)]
mod tests {
use crate::project::{CreateOptions, PackageType, Project};
use crate::project_model::project_types::BundleIdentifier;
#[test]
fn share_tree_carries_desktop_entry_and_hicolor_icons() {
smol::block_on(async {
let dir = tempfile::tempdir().expect("temp dir");
let root = dir.path().join("share-example");
let project = Project::create(
&root,
CreateOptions {
name: "Share Example".to_string(),
bundle_identifier: BundleIdentifier::try_from("dev.waterui.shareexample")
.expect("bundle identifier"),
package_type: PackageType::Playground,
waterui_path: None,
author: "Lexo Liu".to_string(),
},
)
.await
.expect("project creation must succeed");
let share = dir.path().join("share");
super::write_linux_share_material(&project, "Share Example", "share-example", &share)
.await
.expect("share material must be written");
let entry = std::fs::read_to_string(
share.join("applications/dev.waterui.shareexample.desktop"),
)
.expect("desktop entry must exist");
assert!(entry.contains("Name=Share Example"));
assert!(entry.contains("Exec=share-example"));
assert!(entry.contains("Icon=dev.waterui.shareexample"));
let icon_128 = share.join("icons/hicolor/128x128/apps/dev.waterui.shareexample.png");
let decoded = image::open(&icon_128).expect("hicolor icon must decode");
assert_eq!(decoded.width(), 128);
});
}
}