use anyhow::{anyhow, Result};
use std::fs;
use std::path::Path;
use crate::app::App;
use crate::environment::Platform;
pub struct DesktopGenerator {
entries: Vec<(String, String)>,
}
impl DesktopGenerator {
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
fn add_entry<K, V>(&mut self, key: K, val: V)
where
K: AsRef<str>,
V: AsRef<str>,
{
self.entries
.push((String::from(key.as_ref()), String::from(val.as_ref())));
}
pub fn generate(mut self, app: &App, platform: Platform) -> Result<String> {
let exec_name = app.executable_name(platform)?;
self.add_entry("Name", app.product_name(platform));
self.add_entry("Exec", format!("/usr/bin/{} %U", exec_name));
self.add_entry("Terminal", "false");
self.add_entry("Type", "Application");
self.add_entry("Icon", exec_name);
if let Some(properties) = app.config().desktop_properties(platform) {
for (key, val) in properties {
self.add_entry(key, val);
}
}
if let Some(comment) = app.description(platform) {
self.add_entry("Comment", comment);
}
let mut mimes = vec![];
for protocol in app.config().protocol_associations(platform) {
for scheme in &protocol.schemes {
mimes.push(format!("x-scheme-handler/{}", scheme));
}
}
for file_ass in app.config().file_associations(platform) {
if let Some(mime_type) = &file_ass.mime_type {
mimes.push(mime_type.clone());
}
}
if !mimes.is_empty() {
self.add_entry("MimeType", mimes.join(";"));
}
let categories = app.config().desktop_categories(platform);
if !categories.is_empty() {
self.add_entry("Categories", categories.join(";"));
}
let mut contents = String::from("[Desktop Entry]\n");
for (key, val) in self.entries {
contents.push_str(&format!("{key}={val}\n"));
}
Ok(contents)
}
pub fn write_to_output_dir<P>(
self,
app: &App,
platform: Platform,
output: Option<P>,
) -> Result<()>
where
P: AsRef<Path>,
{
let contents = self.generate(app, platform)?;
let mut target = app.output_dir(platform);
if let Some(out) = output {
target = target.join(out.as_ref());
if target.is_dir() {
target = target.join(app.desktop_name(platform)?);
}
} else {
target = target.join(app.desktop_name(platform)?);
}
fs::create_dir_all(
target
.parent()
.ok_or_else(|| anyhow!("no desktop entry target parent"))?,
)?;
fs::write(target, contents)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::DesktopGenerator;
use crate::app::App;
use crate::environment::Platform;
use anyhow::Result;
static LINUX: Platform = Platform::Linux;
#[test]
fn test_gen_desktop() -> Result<()> {
let app: App = App::new_from_package_file("test_assets/package.json")?;
let generator = DesktopGenerator::new();
assert_eq!(
generator.generate(&app, LINUX)?,
r#"[Desktop Entry]
Name=Tasje
Exec=/usr/bin/tasje %U
Terminal=false
Type=Application
Icon=tasje
CustomField=custom_value
Comment=Packs Electron apps
MimeType=x-scheme-handler/tasje;x-scheme-handler/ebuilder;x-scheme-handler/electron-builder;application/x-tas
Categories=Tools
"#
);
Ok(())
}
}