From de4dccaca4ae758d3adde517cc415a002873e642 Mon Sep 17 00:00:00 2001 From: Kevin Boos <1139460+kevinaboos@users.noreply.github.com> Date: Mon, 1 Jul 2024 22:02:36 -0700 Subject: [PATCH] feat(debian): auto-add an Exec arg (field code) in the `.desktop` file (#256) This change adds an `{exec_arg}` field to the default `main.desktop` template. This field is populated by handlebars with a sane default value, which is based on whether `deep_link_protocols` or `file_associations` in the `Config` struct have been specified. This allows an installed Debian package to be invoked by other applications with URLs or files as arguments, as expected. The `main.desktop` template previously did not automatically include an Exec field code even if `deep_link_protocols` or `file_associations` were set, which would confuse new users who incorrectly expected that the Debian package would automatically handle links and file associations upon installation. This change now ensures their expectations are met. --- .changes/pr256.md | 13 ++++++++++++ bindings/packager/nodejs/schema.json | 2 +- crates/packager/schema.json | 2 +- crates/packager/src/config/mod.rs | 21 ++++++++++++++++++-- crates/packager/src/package/deb/main.desktop | 2 +- crates/packager/src/package/deb/mod.rs | 18 +++++++++++++++-- 6 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 .changes/pr256.md diff --git a/.changes/pr256.md b/.changes/pr256.md new file mode 100644 index 00000000..d236459b --- /dev/null +++ b/.changes/pr256.md @@ -0,0 +1,13 @@ +--- +"cargo-packager": "patch" +"@crabnebula/packager": "patch" +--- + +Automatically add an Exec arg (field code) in the `.desktop` file. + +This adds an `{exec_arg}` field to the default `main.desktop` template. +This field is populated with a sane default value, based on the +`deep_link_protocols` or `file_associations` in the `Config` struct. + +This allows an installed Debian package to be invoked by other +applications with URLs or files as arguments, as expected. diff --git a/bindings/packager/nodejs/schema.json b/bindings/packager/nodejs/schema.json index a7692a50..ee823dfe 100644 --- a/bindings/packager/nodejs/schema.json +++ b/bindings/packager/nodejs/schema.json @@ -785,7 +785,7 @@ } }, "desktopTemplate": { - "description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```", + "description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```\n\nThe `{{exec_arg}}` will be set to: * \"%F\", if at least one [Config::file_associations] was specified but no deep link protocols were given. * The \"%F\" arg means that your application can be invoked with multiple file paths. * \"%U\", if at least one [Config::deep_link_protocols] was specified. * The \"%U\" arg means that your application can be invoked with multiple URLs. * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, the \"%U\" arg will be used, causing the file paths to be passed to your app as `file://` URLs. * An empty string \"\" (nothing) if neither are given. * This means that your application will never be invoked with any URLs or file paths.\n\nTo specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: ```text Exec={{exec}} %u ```\n\nSee more here: .", "type": [ "string", "null" diff --git a/crates/packager/schema.json b/crates/packager/schema.json index a7692a50..ee823dfe 100644 --- a/crates/packager/schema.json +++ b/crates/packager/schema.json @@ -785,7 +785,7 @@ } }, "desktopTemplate": { - "description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```", + "description": "Path to a custom desktop file Handlebars template.\n\nAvailable variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.\n\nDefault file contents: ```text [Desktop Entry] Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false Type=Application {{#if mime_type}} MimeType={{mime_type}} {{/if}} ```\n\nThe `{{exec_arg}}` will be set to: * \"%F\", if at least one [Config::file_associations] was specified but no deep link protocols were given. * The \"%F\" arg means that your application can be invoked with multiple file paths. * \"%U\", if at least one [Config::deep_link_protocols] was specified. * The \"%U\" arg means that your application can be invoked with multiple URLs. * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, the \"%U\" arg will be used, causing the file paths to be passed to your app as `file://` URLs. * An empty string \"\" (nothing) if neither are given. * This means that your application will never be invoked with any URLs or file paths.\n\nTo specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: ```text Exec={{exec}} %u ```\n\nSee more here: .", "type": [ "string", "null" diff --git a/crates/packager/src/config/mod.rs b/crates/packager/src/config/mod.rs index e961ea25..b37b2dbf 100644 --- a/crates/packager/src/config/mod.rs +++ b/crates/packager/src/config/mod.rs @@ -194,7 +194,7 @@ pub struct DebianConfig { /// {{#if comment}} /// Comment={{comment}} /// {{/if}} - /// Exec={{exec}} + /// Exec={{exec}} {{exec_arg}} /// Icon={{icon}} /// Name={{name}} /// Terminal=false @@ -203,6 +203,23 @@ pub struct DebianConfig { /// MimeType={{mime_type}} /// {{/if}} /// ``` + /// + /// The `{{exec_arg}}` will be set to: + /// * "%F", if at least one [Config::file_associations] was specified but no deep link protocols were given. + /// * The "%F" arg means that your application can be invoked with multiple file paths. + /// * "%U", if at least one [Config::deep_link_protocols] was specified. + /// * The "%U" arg means that your application can be invoked with multiple URLs. + /// * If both [Config::file_associations] and [Config::deep_link_protocols] were specified, + /// the "%U" arg will be used, causing the file paths to be passed to your app as `file://` URLs. + /// * An empty string "" (nothing) if neither are given. + /// * This means that your application will never be invoked with any URLs or file paths. + /// + /// To specify a custom `exec_arg`, just use plaintext directly instead of `{{exec_arg}}`: + /// ```text + /// Exec={{exec}} %u + /// ``` + /// + /// See more here: . #[serde(alias = "desktop-template", alias = "desktop_template")] pub desktop_template: Option, /// Define the section in Debian Control file. See : @@ -243,7 +260,7 @@ impl DebianConfig { /// {{#if comment}} /// Comment={{comment}} /// {{/if}} - /// Exec={{exec}} + /// Exec={{exec}} {{exec_arg}} /// Icon={{icon}} /// Name={{name}} /// Terminal=false diff --git a/crates/packager/src/package/deb/main.desktop b/crates/packager/src/package/deb/main.desktop index 721648d0..a5f72023 100644 --- a/crates/packager/src/package/deb/main.desktop +++ b/crates/packager/src/package/deb/main.desktop @@ -3,7 +3,7 @@ Categories={{categories}} {{#if comment}} Comment={{comment}} {{/if}} -Exec={{exec}} +Exec={{exec}} {{exec_arg}} Icon={{icon}} Name={{name}} Terminal=false diff --git a/crates/packager/src/package/deb/mod.rs b/crates/packager/src/package/deb/mod.rs index 8390cf43..3c3f29f6 100644 --- a/crates/packager/src/package/deb/mod.rs +++ b/crates/packager/src/package/deb/mod.rs @@ -96,8 +96,8 @@ fn generate_desktop_file(config: &Config, data_dir: &Path) -> crate::Result<()> .join("usr/share/applications") .join(desktop_file_name); - // For more information about the format of this file, see - // https://developer.gnome.org/integration-guide/stable/desktop-files.html.en + // For more information about the format of this file, see: + // let file = &mut util::create_file(&desktop_file_path)?; let mut handlebars = Handlebars::new(); @@ -117,14 +117,22 @@ fn generate_desktop_file(config: &Config, data_dir: &Path) -> crate::Result<()> categories: &'a str, comment: Option<&'a str>, exec: &'a str, + exec_arg: Option<&'a str>, icon: &'a str, name: &'a str, mime_type: Option, } + // Set the argument code at the end of the `Exec` key. + // See the docs for `DebianConfig::desktop_template` for more details. + let mut exec_arg = None; + let mut mime_type: Vec = Vec::new(); if let Some(associations) = &config.file_associations { + if !associations.is_empty() { + exec_arg = Some("%F"); + } mime_type.extend( associations .iter() @@ -133,6 +141,11 @@ fn generate_desktop_file(config: &Config, data_dir: &Path) -> crate::Result<()> } if let Some(protocols) = &config.deep_link_protocols { + if !protocols.is_empty() { + // Use "%U" even if file associations were already provided, + // as it can also accommodate file names in addition to URLs. + exec_arg = Some("%U"); + } mime_type.extend( protocols .iter() @@ -152,6 +165,7 @@ fn generate_desktop_file(config: &Config, data_dir: &Path) -> crate::Result<()> .unwrap_or(""), comment: config.description.as_deref(), exec: &bin_name, + exec_arg, icon: &bin_name, name: config.product_name.as_str(), mime_type,