From b0c5b06d06c2b4198f39d9429d903be40ac09c3c Mon Sep 17 00:00:00 2001 From: Andrew Date: Mon, 20 Nov 2023 22:26:02 +0100 Subject: [PATCH] feat(bundler): add dmg settings, closes #4669 (#7964) --- core/tauri-config-schema/schema.json | 157 ++++++++++++++++++++++++ core/tauri-utils/src/config.rs | 95 ++++++++++++++ tooling/bundler/src/bundle.rs | 4 +- tooling/bundler/src/bundle/macos/dmg.rs | 72 ++++++++--- tooling/bundler/src/bundle/settings.rs | 40 ++++++ tooling/bundler/src/error.rs | 3 + tooling/cli/schema.json | 157 ++++++++++++++++++++++++ tooling/cli/src/interface/rust.rs | 26 +++- 8 files changed, 536 insertions(+), 18 deletions(-) diff --git a/core/tauri-config-schema/schema.json b/core/tauri-config-schema/schema.json index b4a96b2847de..573d37924808 100644 --- a/core/tauri-config-schema/schema.json +++ b/core/tauri-config-schema/schema.json @@ -37,6 +37,20 @@ "deb": { "files": {} }, + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, "iOS": {}, "icon": [], "identifier": "", @@ -171,6 +185,20 @@ "deb": { "files": {} }, + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, "iOS": {}, "icon": [], "identifier": "", @@ -1003,6 +1031,28 @@ } ] }, + "dmg": { + "description": "DMG-specific settings.", + "default": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "allOf": [ + { + "$ref": "#/definitions/DmgConfig" + } + ] + }, "macOS": { "description": "Configuration for the macOS bundles.", "default": { @@ -1318,6 +1368,113 @@ }, "additionalProperties": false }, + "DmgConfig": { + "description": "Configuration for Apple Disk Image (.dmg) bundles.\n\nSee more: https://tauri.app/v1/api/config#dmgconfig", + "type": "object", + "properties": { + "background": { + "description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.", + "type": [ + "string", + "null" + ] + }, + "windowPosition": { + "description": "Position of volume window on screen.", + "anyOf": [ + { + "$ref": "#/definitions/Position" + }, + { + "type": "null" + } + ] + }, + "windowSize": { + "description": "Size of volume window.", + "default": { + "height": 400, + "width": 660 + }, + "allOf": [ + { + "$ref": "#/definitions/Size" + } + ] + }, + "appPosition": { + "description": "Position of app file on window.", + "default": { + "x": 180, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + }, + "applicationFolderPosition": { + "description": "Position of application folder on window.", + "default": { + "x": 480, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + } + }, + "additionalProperties": false + }, + "Position": { + "description": "Position coordinates struct.", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "y": { + "description": "Y coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Size": { + "description": "Size of the window.", + "type": "object", + "required": [ + "height", + "width" + ], + "properties": { + "width": { + "description": "Width of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "height": { + "description": "Height of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, "MacConfig": { "description": "Configuration for the macOS bundles.\n\nSee more: ", "type": "object", diff --git a/core/tauri-utils/src/config.rs b/core/tauri-utils/src/config.rs index 5d054c9a2f86..7c46537eaf10 100644 --- a/core/tauri-utils/src/config.rs +++ b/core/tauri-utils/src/config.rs @@ -282,6 +282,95 @@ pub struct DebConfig { pub desktop_template: Option, } +/// Position coordinates struct. +#[derive(Default, Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Position { + /// X coordinate. + pub x: u32, + /// Y coordinate. + pub y: u32, +} + +/// Size of the window. +#[derive(Default, Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct Size { + /// Width of the window. + pub width: u32, + /// Height of the window. + pub height: u32, +} + + + +/// Configuration for Apple Disk Image (.dmg) bundles. +/// +/// See more: https://tauri.app/v1/api/config#dmgconfig +#[skip_serializing_none] +#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "schema", derive(JsonSchema))] +#[serde(rename_all = "camelCase", deny_unknown_fields)] +pub struct DmgConfig { + /// Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`. + pub background: Option, + /// Position of volume window on screen. + pub window_position: Option, + /// Size of volume window. + #[serde( + default = "window_size", + alias = "window-size" + )] + pub window_size: Size, + /// Position of app file on window. + #[serde( + default = "app_position", + alias = "app-position" + )] + pub app_position: Position, + /// Position of application folder on window. + #[serde( + default = "application_folder_position", + alias = "application-folder-position" + )] + pub application_folder_position: Position, +} + +impl Default for DmgConfig { + fn default() -> Self { + Self { + background: None, + window_position: None, + window_size: window_size(), + app_position: app_position(), + application_folder_position: application_folder_position(), + } + } +} + +fn window_size() -> Size { + Size { + width: 660, + height: 400, + } +} + +fn app_position() -> Position { + Position { + x: 180, + y: 170, + } +} + +fn application_folder_position() -> Position { + Position { + x: 480, + y: 170, + } +} + fn de_minimum_system_version<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, @@ -850,6 +939,9 @@ pub struct BundleConfig { /// Configuration for the Debian bundle. #[serde(default)] pub deb: DebConfig, + /// DMG-specific settings. + #[serde(default)] + pub dmg: DmgConfig, /// Configuration for the macOS bundles. #[serde(rename = "macOS", default)] pub macos: MacConfig, @@ -2440,6 +2532,7 @@ mod build { let long_description = quote!(None); let appimage = quote!(Default::default()); let deb = quote!(Default::default()); + let dmg = quote!(Default::default()); let macos = quote!(Default::default()); let external_bin = opt_vec_str_lit(self.external_bin.as_ref()); let windows = &self.windows; @@ -2463,6 +2556,7 @@ mod build { long_description, appimage, deb, + dmg, macos, external_bin, windows, @@ -2771,6 +2865,7 @@ mod test { long_description: None, appimage: Default::default(), deb: Default::default(), + dmg: Default::default(), macos: Default::default(), external_bin: None, windows: Default::default(), diff --git a/tooling/bundler/src/bundle.rs b/tooling/bundler/src/bundle.rs index 763ca75b7696..afc865a763d7 100644 --- a/tooling/bundler/src/bundle.rs +++ b/tooling/bundler/src/bundle.rs @@ -20,8 +20,8 @@ use tauri_utils::display_path; pub use self::{ category::AppCategory, settings::{ - BundleBinary, BundleSettings, DebianSettings, MacOsSettings, PackageSettings, PackageType, - Settings, SettingsBuilder, UpdaterSettings, + BundleBinary, BundleSettings, DebianSettings, DmgSettings, MacOsSettings, PackageSettings, PackageType, + Settings, SettingsBuilder, UpdaterSettings, Position, Size }, }; #[cfg(target_os = "macos")] diff --git a/tooling/bundler/src/bundle/macos/dmg.rs b/tooling/bundler/src/bundle/macos/dmg.rs index 3748a5cfe6de..cc0b768a3f94 100644 --- a/tooling/bundler/src/bundle/macos/dmg.rs +++ b/tooling/bundler/src/bundle/macos/dmg.rs @@ -96,23 +96,62 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result< .output() .expect("Failed to chmod script"); + let dmg_settings = settings.dmg(); + + let app_position = &dmg_settings.app_position; + let application_folder_position = &dmg_settings.application_folder_position; + let window_size = &dmg_settings.window_size; + + let app_position_x = app_position.x.to_string(); + let app_position_y = app_position.y.to_string(); + let application_folder_position_x = application_folder_position.x.to_string(); + let application_folder_position_y = application_folder_position.y.to_string(); + let window_size_width = window_size.width.to_string(); + let window_size_height = window_size.height.to_string(); + let mut args = vec![ "--volname", product_name, "--icon", &bundle_file_name, - "180", - "170", + &app_position_x, + &app_position_y, "--app-drop-link", - "480", - "170", + &application_folder_position_x, + &application_folder_position_y, "--window-size", - "660", - "400", + &window_size_width, + &window_size_height, "--hide-extension", &bundle_file_name, ]; + let window_position = dmg_settings.window_position.as_ref().map(|position| { + (position.x.to_string(), position.y.to_string()) + }); + + if let Some(window_position) = &window_position { + args.push("--window-pos"); + args.push(&window_position.0); + args.push(&window_position.1); + } + + let background_path_string = if let Some(background_path) = &dmg_settings.background { + Some( + env::current_dir()? + .join(background_path) + .to_string_lossy() + .to_string(), + ) + } else { + None + }; + + if let Some(background_path_string) = &background_path_string { + args.push("--background"); + args.push(background_path_string); + } + let icns_icon_path = create_icns_file(&output_path, settings)?.map(|path| path.to_string_lossy().to_string()); if let Some(icon) = &icns_icon_path { @@ -120,15 +159,20 @@ pub fn bundle_project(settings: &Settings, bundles: &[Bundle]) -> crate::Result< args.push(icon); } - #[allow(unused_assignments)] - let mut license_path_ref = "".to_string(); - if let Some(license_path) = &settings.macos().license { + let license_path_string = if let Some(license_path) = &settings.macos().license { + Some( + env::current_dir()? + .join(license_path) + .to_string_lossy() + .to_string(), + ) + } else { + None + }; + + if let Some(license_path) = &license_path_string { args.push("--eula"); - license_path_ref = env::current_dir()? - .join(license_path) - .to_string_lossy() - .to_string(); - args.push(&license_path_ref); + args.push(license_path); } // Issue #592 - Building MacOS dmg files on CI diff --git a/tooling/bundler/src/bundle/settings.rs b/tooling/bundler/src/bundle/settings.rs index 7a5e35d964dd..68934ded1f5e 100644 --- a/tooling/bundler/src/bundle/settings.rs +++ b/tooling/bundler/src/bundle/settings.rs @@ -183,6 +183,39 @@ pub struct DebianSettings { pub desktop_template: Option, } +/// Position coordinates struct. +#[derive(Clone, Debug, Default)] +pub struct Position { + /// X coordinate. + pub x: u32, + /// Y coordinate. + pub y: u32, +} + +/// Size of the window. +#[derive(Clone, Debug, Default)] +pub struct Size { + /// Width of the window. + pub width: u32, + /// Height of the window. + pub height: u32, +} + +/// The DMG bundle settings. +#[derive(Clone, Debug, Default)] +pub struct DmgSettings { + /// Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`. + pub background: Option, + /// Position of volume window on screen. + pub window_position: Option, + /// Size of volume window. + pub window_size: Size, + /// Position of app file on window. + pub app_position: Position, + /// Position of application folder on window. + pub application_folder_position: Position, +} + /// The macOS bundle settings. #[derive(Clone, Debug, Default)] pub struct MacOsSettings { @@ -416,6 +449,8 @@ pub struct BundleSettings { pub external_bin: Option>, /// Debian-specific settings. pub deb: DebianSettings, + /// DMG-specific settings. + pub dmg: DmgSettings, /// MacOS-specific settings. pub macos: MacOsSettings, /// Updater configuration. @@ -850,6 +885,11 @@ impl Settings { &self.bundle_settings.deb } + /// Returns the DMG settings. + pub fn dmg(&self) -> &DmgSettings { + &self.bundle_settings.dmg + } + /// Returns the MacOS settings. pub fn macos(&self) -> &MacOsSettings { &self.bundle_settings.macos diff --git a/tooling/bundler/src/error.rs b/tooling/bundler/src/error.rs index ad73de876813..cc412d85bce1 100644 --- a/tooling/bundler/src/error.rs +++ b/tooling/bundler/src/error.rs @@ -67,6 +67,9 @@ pub enum Error { /// Couldn't find icons. #[error("Could not find Icon paths. Please make sure they exist in the tauri config JSON file")] IconPathError, + /// Couldn't find background file. + #[error("Could not find background file. Make sure it exists in the tauri config JSON file and extension is png/jpg/gif")] + BackgroundPathError, /// Error on path util operation. #[error("Path Error:`{0}`")] PathUtilError(String), diff --git a/tooling/cli/schema.json b/tooling/cli/schema.json index b4a96b2847de..573d37924808 100644 --- a/tooling/cli/schema.json +++ b/tooling/cli/schema.json @@ -37,6 +37,20 @@ "deb": { "files": {} }, + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, "iOS": {}, "icon": [], "identifier": "", @@ -171,6 +185,20 @@ "deb": { "files": {} }, + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, "iOS": {}, "icon": [], "identifier": "", @@ -1003,6 +1031,28 @@ } ] }, + "dmg": { + "description": "DMG-specific settings.", + "default": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "allOf": [ + { + "$ref": "#/definitions/DmgConfig" + } + ] + }, "macOS": { "description": "Configuration for the macOS bundles.", "default": { @@ -1318,6 +1368,113 @@ }, "additionalProperties": false }, + "DmgConfig": { + "description": "Configuration for Apple Disk Image (.dmg) bundles.\n\nSee more: https://tauri.app/v1/api/config#dmgconfig", + "type": "object", + "properties": { + "background": { + "description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.", + "type": [ + "string", + "null" + ] + }, + "windowPosition": { + "description": "Position of volume window on screen.", + "anyOf": [ + { + "$ref": "#/definitions/Position" + }, + { + "type": "null" + } + ] + }, + "windowSize": { + "description": "Size of volume window.", + "default": { + "height": 400, + "width": 660 + }, + "allOf": [ + { + "$ref": "#/definitions/Size" + } + ] + }, + "appPosition": { + "description": "Position of app file on window.", + "default": { + "x": 180, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + }, + "applicationFolderPosition": { + "description": "Position of application folder on window.", + "default": { + "x": 480, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + } + }, + "additionalProperties": false + }, + "Position": { + "description": "Position coordinates struct.", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "y": { + "description": "Y coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Size": { + "description": "Size of the window.", + "type": "object", + "required": [ + "height", + "width" + ], + "properties": { + "width": { + "description": "Width of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "height": { + "description": "Height of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, "MacConfig": { "description": "Configuration for the macOS bundles.\n\nSee more: ", "type": "object", diff --git a/tooling/cli/src/interface/rust.rs b/tooling/cli/src/interface/rust.rs index ef386aef1ad0..319ced86d7e0 100644 --- a/tooling/cli/src/interface/rust.rs +++ b/tooling/cli/src/interface/rust.rs @@ -22,8 +22,8 @@ use notify::RecursiveMode; use notify_debouncer_mini::new_debouncer; use serde::Deserialize; use tauri_bundler::{ - AppCategory, BundleBinary, BundleSettings, DebianSettings, MacOsSettings, PackageSettings, - UpdaterSettings, WindowsSettings, + AppCategory, BundleBinary, BundleSettings, DebianSettings, DmgSettings, MacOsSettings, PackageSettings, + UpdaterSettings, WindowsSettings, Position, Size }; use tauri_utils::config::parse::is_configuration_file; @@ -1177,6 +1177,28 @@ fn tauri_config_to_bundle_settings( files: config.deb.files, desktop_template: config.deb.desktop_template, }, + dmg: DmgSettings { + background: config.dmg.background, + window_position: match config.dmg.window_position { + Some(window_position) => Some(Position { + x: window_position.x, + y: window_position.y, + }), + None => None, + }, + window_size: Size { + width: config.dmg.window_size.width, + height: config.dmg.window_size.height, + }, + app_position: Position { + x: config.dmg.app_position.x, + y: config.dmg.app_position.y, + }, + application_folder_position: Position { + x: config.dmg.application_folder_position.x, + y: config.dmg.application_folder_position.y, + }, + }, macos: MacOsSettings { frameworks: config.macos.frameworks, minimum_system_version: config.macos.minimum_system_version,