tauri_bundler/bundle/
settings.rs

1// Copyright 2016-2019 Cargo-Bundle developers <https://github.com/burtonageo/cargo-bundle>
2// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
3// SPDX-License-Identifier: Apache-2.0
4// SPDX-License-Identifier: MIT
5
6use super::category::AppCategory;
7use crate::{bundle::platform::target_triple, utils::fs_utils};
8use anyhow::Context;
9pub use tauri_utils::config::WebviewInstallMode;
10use tauri_utils::{
11  config::{
12    BundleType, DeepLinkProtocol, FileAssociation, NSISInstallerMode, NsisCompression,
13    RpmCompression,
14  },
15  platform::Target as TargetPlatform,
16  resources::{external_binaries, ResourcePaths},
17};
18
19use std::{
20  collections::HashMap,
21  path::{Path, PathBuf},
22};
23
24/// The type of the package we're bundling.
25#[derive(Clone, Copy, Debug, Eq, PartialEq)]
26#[non_exhaustive]
27pub enum PackageType {
28  /// The macOS application bundle (.app).
29  MacOsBundle,
30  /// The iOS app bundle.
31  IosBundle,
32  /// The Windows bundle (.msi).
33  WindowsMsi,
34  /// The NSIS bundle (.exe).
35  Nsis,
36  /// The Linux Debian package bundle (.deb).
37  Deb,
38  /// The Linux RPM bundle (.rpm).
39  Rpm,
40  /// The Linux AppImage bundle (.AppImage).
41  AppImage,
42  /// The macOS DMG bundle (.dmg).
43  Dmg,
44  /// The Updater bundle.
45  Updater,
46}
47
48impl From<BundleType> for PackageType {
49  fn from(bundle: BundleType) -> Self {
50    match bundle {
51      BundleType::Deb => Self::Deb,
52      BundleType::Rpm => Self::Rpm,
53      BundleType::AppImage => Self::AppImage,
54      BundleType::Msi => Self::WindowsMsi,
55      BundleType::Nsis => Self::Nsis,
56      BundleType::App => Self::MacOsBundle,
57      BundleType::Dmg => Self::Dmg,
58    }
59  }
60}
61
62impl PackageType {
63  /// Maps a short name to a PackageType.
64  /// Possible values are "deb", "ios", "msi", "app", "rpm", "appimage", "dmg", "updater".
65  pub fn from_short_name(name: &str) -> Option<PackageType> {
66    // Other types we may eventually want to support: apk.
67    match name {
68      "deb" => Some(PackageType::Deb),
69      "ios" => Some(PackageType::IosBundle),
70      "msi" => Some(PackageType::WindowsMsi),
71      "nsis" => Some(PackageType::Nsis),
72      "app" => Some(PackageType::MacOsBundle),
73      "rpm" => Some(PackageType::Rpm),
74      "appimage" => Some(PackageType::AppImage),
75      "dmg" => Some(PackageType::Dmg),
76      "updater" => Some(PackageType::Updater),
77      _ => None,
78    }
79  }
80
81  /// Gets the short name of this PackageType.
82  #[allow(clippy::trivially_copy_pass_by_ref)]
83  pub fn short_name(&self) -> &'static str {
84    match *self {
85      PackageType::Deb => "deb",
86      PackageType::IosBundle => "ios",
87      PackageType::WindowsMsi => "msi",
88      PackageType::Nsis => "nsis",
89      PackageType::MacOsBundle => "app",
90      PackageType::Rpm => "rpm",
91      PackageType::AppImage => "appimage",
92      PackageType::Dmg => "dmg",
93      PackageType::Updater => "updater",
94    }
95  }
96
97  /// Gets the list of the possible package types.
98  pub fn all() -> &'static [PackageType] {
99    ALL_PACKAGE_TYPES
100  }
101
102  /// Gets a number representing priority which used to sort package types
103  /// in an order that guarantees that if a certain package type
104  /// depends on another (like Dmg depending on MacOsBundle), the dependency
105  /// will be built first
106  ///
107  /// The lower the number, the higher the priority
108  pub fn priority(&self) -> u32 {
109    match self {
110      PackageType::MacOsBundle => 0,
111      PackageType::IosBundle => 0,
112      PackageType::WindowsMsi => 0,
113      PackageType::Nsis => 0,
114      PackageType::Deb => 0,
115      PackageType::Rpm => 0,
116      PackageType::AppImage => 0,
117      PackageType::Dmg => 1,
118      PackageType::Updater => 2,
119    }
120  }
121}
122
123const ALL_PACKAGE_TYPES: &[PackageType] = &[
124  #[cfg(target_os = "linux")]
125  PackageType::Deb,
126  #[cfg(target_os = "macos")]
127  PackageType::IosBundle,
128  #[cfg(target_os = "windows")]
129  PackageType::WindowsMsi,
130  #[cfg(target_os = "windows")]
131  PackageType::Nsis,
132  #[cfg(target_os = "macos")]
133  PackageType::MacOsBundle,
134  #[cfg(target_os = "linux")]
135  PackageType::Rpm,
136  #[cfg(target_os = "macos")]
137  PackageType::Dmg,
138  #[cfg(target_os = "linux")]
139  PackageType::AppImage,
140  PackageType::Updater,
141];
142
143/// The package settings.
144#[derive(Debug, Clone)]
145pub struct PackageSettings {
146  /// the package's product name.
147  pub product_name: String,
148  /// the package's version.
149  pub version: String,
150  /// the package's description.
151  pub description: String,
152  /// the package's homepage.
153  pub homepage: Option<String>,
154  /// the package's authors.
155  pub authors: Option<Vec<String>>,
156  /// the default binary to run.
157  pub default_run: Option<String>,
158}
159
160/// The updater settings.
161#[derive(Debug, Default, Clone)]
162pub struct UpdaterSettings {
163  /// Should generate v1 compatible zipped updater
164  pub v1_compatible: bool,
165  /// Signature public key.
166  pub pubkey: String,
167  /// Args to pass to `msiexec.exe` to run the updater on Windows.
168  pub msiexec_args: &'static [&'static str],
169}
170
171/// The Linux debian bundle settings.
172#[derive(Clone, Debug, Default)]
173pub struct DebianSettings {
174  // OS-specific settings:
175  /// the list of debian dependencies.
176  pub depends: Option<Vec<String>>,
177  /// the list of debian dependencies recommendations.
178  pub recommends: Option<Vec<String>>,
179  /// the list of dependencies the package provides.
180  pub provides: Option<Vec<String>>,
181  /// the list of package conflicts.
182  pub conflicts: Option<Vec<String>>,
183  /// the list of package replaces.
184  pub replaces: Option<Vec<String>>,
185  /// List of custom files to add to the deb package.
186  /// Maps the path on the debian package to the path of the file to include (relative to the current working directory).
187  pub files: HashMap<PathBuf, PathBuf>,
188  /// Path to a custom desktop file Handlebars template.
189  ///
190  /// Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.
191  ///
192  /// Default file contents:
193  /// ```text
194  #[doc = include_str!("./linux/freedesktop/main.desktop")]
195  /// ```
196  pub desktop_template: Option<PathBuf>,
197  /// Define the section in Debian Control file. See : <https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections>
198  pub section: Option<String>,
199  /// Change the priority of the Debian Package. By default, it is set to `optional`.
200  /// Recognized Priorities as of now are :  `required`, `important`, `standard`, `optional`, `extra`
201  pub priority: Option<String>,
202  /// Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See
203  /// <https://www.debian.org/doc/debian-policy/ch-docs.html#changelog-files-and-release-notes>
204  pub changelog: Option<PathBuf>,
205  /// Path to script that will be executed before the package is unpacked. See
206  /// <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>
207  pub pre_install_script: Option<PathBuf>,
208  /// Path to script that will be executed after the package is unpacked. See
209  /// <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>
210  pub post_install_script: Option<PathBuf>,
211  /// Path to script that will be executed before the package is removed. See
212  /// <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>
213  pub pre_remove_script: Option<PathBuf>,
214  /// Path to script that will be executed after the package is removed. See
215  /// <https://www.debian.org/doc/debian-policy/ch-maintainerscripts.html>
216  pub post_remove_script: Option<PathBuf>,
217}
218
219/// The Linux AppImage bundle settings.
220#[derive(Clone, Debug, Default)]
221pub struct AppImageSettings {
222  /// The files to include in the Appimage Binary.
223  pub files: HashMap<PathBuf, PathBuf>,
224  /// Whether to include gstreamer plugins for audio/media support.
225  pub bundle_media_framework: bool,
226  /// Whether to include the `xdg-open` binary.
227  pub bundle_xdg_open: bool,
228}
229
230/// The RPM bundle settings.
231#[derive(Clone, Debug, Default)]
232pub struct RpmSettings {
233  /// The list of RPM dependencies your application relies on.
234  pub depends: Option<Vec<String>>,
235  /// the list of of RPM dependencies your application recommends.
236  pub recommends: Option<Vec<String>>,
237  /// The list of RPM dependencies your application provides.
238  pub provides: Option<Vec<String>>,
239  /// The list of RPM dependencies your application conflicts with. They must not be present
240  /// in order for the package to be installed.
241  pub conflicts: Option<Vec<String>>,
242  /// The list of RPM dependencies your application supersedes - if this package is installed,
243  /// packages listed as "obsoletes" will be automatically removed (if they are present).
244  pub obsoletes: Option<Vec<String>>,
245  /// The RPM release tag.
246  pub release: String,
247  /// The RPM epoch.
248  pub epoch: u32,
249  /// List of custom files to add to the RPM package.
250  /// Maps the path on the RPM package to the path of the file to include (relative to the current working directory).
251  pub files: HashMap<PathBuf, PathBuf>,
252  /// Path to a custom desktop file Handlebars template.
253  ///
254  /// Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.
255  ///
256  /// Default file contents:
257  /// ```text
258  #[doc = include_str!("./linux/freedesktop/main.desktop")]
259  /// ```
260  pub desktop_template: Option<PathBuf>,
261  /// Path to script that will be executed before the package is unpacked. See
262  /// <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>
263  pub pre_install_script: Option<PathBuf>,
264  /// Path to script that will be executed after the package is unpacked. See
265  /// <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>
266  pub post_install_script: Option<PathBuf>,
267  /// Path to script that will be executed before the package is removed. See
268  /// <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>
269  pub pre_remove_script: Option<PathBuf>,
270  /// Path to script that will be executed after the package is removed. See
271  /// <http://ftp.rpm.org/max-rpm/s1-rpm-inside-scripts.html>
272  pub post_remove_script: Option<PathBuf>,
273  /// Compression algorithm and level. Defaults to `Gzip` with level 6.
274  pub compression: Option<RpmCompression>,
275}
276
277/// Position coordinates struct.
278#[derive(Clone, Debug, Default)]
279pub struct Position {
280  /// X coordinate.
281  pub x: u32,
282  /// Y coordinate.
283  pub y: u32,
284}
285
286/// Size of the window.
287#[derive(Clone, Debug, Default)]
288pub struct Size {
289  /// Width of the window.
290  pub width: u32,
291  /// Height of the window.
292  pub height: u32,
293}
294
295/// The DMG bundle settings.
296#[derive(Clone, Debug, Default)]
297pub struct DmgSettings {
298  /// Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.
299  pub background: Option<PathBuf>,
300  /// Position of volume window on screen.
301  pub window_position: Option<Position>,
302  /// Size of volume window.
303  pub window_size: Size,
304  /// Position of app file on window.
305  pub app_position: Position,
306  /// Position of application folder on window.
307  pub application_folder_position: Position,
308}
309
310/// The iOS bundle settings.
311#[derive(Clone, Debug, Default)]
312pub struct IosSettings {
313  /// The version of the build that identifies an iteration of the bundle.
314  pub bundle_version: Option<String>,
315}
316
317/// The macOS bundle settings.
318#[derive(Clone, Debug, Default)]
319pub struct MacOsSettings {
320  /// MacOS frameworks that need to be bundled with the app.
321  ///
322  /// Each string can either be the name of a framework (without the `.framework` extension, e.g. `"SDL2"`),
323  /// in which case we will search for that framework in the standard install locations (`~/Library/Frameworks/`, `/Library/Frameworks/`, and `/Network/Library/Frameworks/`),
324  /// or a path to a specific framework bundle (e.g. `./data/frameworks/SDL2.framework`).  Note that this setting just makes tauri-bundler copy the specified frameworks into the OS X app bundle
325  /// (under `Foobar.app/Contents/Frameworks/`); you are still responsible for:
326  ///
327  /// - arranging for the compiled binary to link against those frameworks (e.g. by emitting lines like `cargo:rustc-link-lib=framework=SDL2` from your `build.rs` script)
328  ///
329  /// - embedding the correct rpath in your binary (e.g. by running `install_name_tool -add_rpath "@executable_path/../Frameworks" path/to/binary` after compiling)
330  pub frameworks: Option<Vec<String>>,
331  /// List of custom files to add to the application bundle.
332  /// Maps the path in the Contents directory in the app to the path of the file to include (relative to the current working directory).
333  pub files: HashMap<PathBuf, PathBuf>,
334  /// The version of the build that identifies an iteration of the bundle.
335  pub bundle_version: Option<String>,
336  /// The name of the build that identifies a string of the bundle.
337  ///
338  /// If not set, defaults to the package's product name.
339  pub bundle_name: Option<String>,
340  /// A version string indicating the minimum MacOS version that the bundled app supports (e.g. `"10.11"`).
341  /// If you are using this config field, you may also want have your `build.rs` script emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET=10.11`.
342  pub minimum_system_version: Option<String>,
343  /// The exception domain to use on the macOS .app bundle.
344  ///
345  /// This allows communication to the outside world e.g. a web server you're shipping.
346  pub exception_domain: Option<String>,
347  /// Code signing identity.
348  pub signing_identity: Option<String>,
349  /// Preserve the hardened runtime version flag, see <https://developer.apple.com/documentation/security/hardened_runtime>
350  ///
351  /// Settings this to `false` is useful when using an ad-hoc signature, making it less strict.
352  pub hardened_runtime: bool,
353  /// Provider short name for notarization.
354  pub provider_short_name: Option<String>,
355  /// Path to the entitlements.plist file.
356  pub entitlements: Option<String>,
357  /// Path to the Info.plist file for the bundle.
358  pub info_plist_path: Option<PathBuf>,
359}
360
361/// Configuration for a target language for the WiX build.
362#[derive(Debug, Clone, Default)]
363pub struct WixLanguageConfig {
364  /// The path to a locale (`.wxl`) file. See <https://wixtoolset.org/documentation/manual/v3/howtos/ui_and_localization/build_a_localized_version.html>.
365  pub locale_path: Option<PathBuf>,
366}
367
368/// The languages to build using WiX.
369#[derive(Debug, Clone)]
370pub struct WixLanguage(pub Vec<(String, WixLanguageConfig)>);
371
372impl Default for WixLanguage {
373  fn default() -> Self {
374    Self(vec![("en-US".into(), Default::default())])
375  }
376}
377
378/// Settings specific to the WiX implementation.
379#[derive(Clone, Debug, Default)]
380pub struct WixSettings {
381  /// MSI installer version in the format `major.minor.patch.build` (build is optional).
382  ///
383  /// Because a valid version is required for MSI installer, it will be derived from [`PackageSettings::version`] if this field is not set.
384  ///
385  /// The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.
386  /// The third and fourth fields have a maximum value of 65,535.
387  ///
388  /// See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.
389  pub version: Option<String>,
390  /// A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,
391  /// otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.
392  ///
393  /// By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.
394  /// You can use Tauri's CLI to generate and print this code for you by running `tauri inspect wix-upgrade-code`.
395  ///
396  /// It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code
397  /// whenever you want to change your product name.
398  pub upgrade_code: Option<uuid::Uuid>,
399  /// The app languages to build. See <https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables>.
400  pub language: WixLanguage,
401  /// By default, the bundler uses an internal template.
402  /// This option allows you to define your own wix file.
403  pub template: Option<PathBuf>,
404  /// A list of paths to .wxs files with WiX fragments to use.
405  pub fragment_paths: Vec<PathBuf>,
406  /// The ComponentGroup element ids you want to reference from the fragments.
407  pub component_group_refs: Vec<String>,
408  /// The Component element ids you want to reference from the fragments.
409  pub component_refs: Vec<String>,
410  /// The FeatureGroup element ids you want to reference from the fragments.
411  pub feature_group_refs: Vec<String>,
412  /// The Feature element ids you want to reference from the fragments.
413  pub feature_refs: Vec<String>,
414  /// The Merge element ids you want to reference from the fragments.
415  pub merge_refs: Vec<String>,
416  /// Create an elevated update task within Windows Task Scheduler.
417  pub enable_elevated_update_task: bool,
418  /// Path to a bitmap file to use as the installation user interface banner.
419  /// This bitmap will appear at the top of all but the first page of the installer.
420  ///
421  /// The required dimensions are 493px × 58px.
422  pub banner_path: Option<PathBuf>,
423  /// Path to a bitmap file to use on the installation user interface dialogs.
424  /// It is used on the welcome and completion dialogs.
425  ///
426  /// The required dimensions are 493px × 312px.
427  pub dialog_image_path: Option<PathBuf>,
428  /// Enables FIPS compliant algorithms.
429  pub fips_compliant: bool,
430}
431
432/// Settings specific to the NSIS implementation.
433#[derive(Clone, Debug, Default)]
434pub struct NsisSettings {
435  /// A custom .nsi template to use.
436  pub template: Option<PathBuf>,
437  /// The path to a bitmap file to display on the header of installers pages.
438  ///
439  /// The recommended dimensions are 150px x 57px.
440  pub header_image: Option<PathBuf>,
441  /// The path to a bitmap file for the Welcome page and the Finish page.
442  ///
443  /// The recommended dimensions are 164px x 314px.
444  pub sidebar_image: Option<PathBuf>,
445  /// The path to an icon file used as the installer icon.
446  pub installer_icon: Option<PathBuf>,
447  /// Whether the installation will be for all users or just the current user.
448  pub install_mode: NSISInstallerMode,
449  /// A list of installer languages.
450  /// By default the OS language is used. If the OS language is not in the list of languages, the first language will be used.
451  /// To allow the user to select the language, set `display_language_selector` to `true`.
452  ///
453  /// See <https://github.com/kichik/nsis/tree/9465c08046f00ccb6eda985abbdbf52c275c6c4d/Contrib/Language%20files> for the complete list of languages.
454  pub languages: Option<Vec<String>>,
455  /// An key-value pair where the key is the language and the
456  /// value is the path to a custom `.nsi` file that holds the translated text for tauri's custom messages.
457  ///
458  /// See <https://github.com/tauri-apps/tauri/blob/dev/crates/tauri-bundler/src/bundle/windows/nsis/languages/English.nsh> for an example `.nsi` file.
459  ///
460  /// **Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`]languages array,
461  pub custom_language_files: Option<HashMap<String, PathBuf>>,
462  /// Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not.
463  /// By default the OS language is selected, with a fallback to the first language in the `languages` array.
464  pub display_language_selector: bool,
465  /// Set compression algorithm used to compress files in the installer.
466  pub compression: NsisCompression,
467  /// Set the folder name for the start menu shortcut.
468  ///
469  /// Use this option if you have multiple apps and wish to group their shortcuts under one folder
470  /// or if you generally prefer to set your shortcut inside a folder.
471  ///
472  /// Examples:
473  /// - `AwesomePublisher`, shortcut will be placed in `%AppData%\Microsoft\Windows\Start Menu\Programs\AwesomePublisher\<your-app>.lnk`
474  /// - If unset, shortcut will be placed in `%AppData%\Microsoft\Windows\Start Menu\Programs\<your-app>.lnk`
475  pub start_menu_folder: Option<String>,
476  /// A path to a `.nsh` file that contains special NSIS macros to be hooked into the
477  /// main installer.nsi script.
478  ///
479  /// Supported hooks are:
480  /// - `NSIS_HOOK_PREINSTALL`: This hook runs before copying files, setting registry key values and creating shortcuts.
481  /// - `NSIS_HOOK_POSTINSTALL`: This hook runs after the installer has finished copying all files, setting the registry keys and created shortcuts.
482  /// - `NSIS_HOOK_PREUNINSTALL`: This hook runs before removing any files, registry keys and shortcuts.
483  /// - `NSIS_HOOK_POSTUNINSTALL`: This hook runs after files, registry keys and shortcuts have been removed.
484  ///
485  ///
486  /// ### Example
487  ///
488  /// ```nsh
489  /// !macro NSIS_HOOK_PREINSTALL
490  ///   MessageBox MB_OK "PreInstall"
491  /// !macroend
492  ///
493  /// !macro NSIS_HOOK_POSTINSTALL
494  ///   MessageBox MB_OK "PostInstall"
495  /// !macroend
496  ///
497  /// !macro NSIS_HOOK_PREUNINSTALL
498  ///   MessageBox MB_OK "PreUnInstall"
499  /// !macroend
500  ///
501  /// !macro NSIS_HOOK_POSTUNINSTALL
502  ///   MessageBox MB_OK "PostUninstall"
503  /// !macroend
504  /// ```
505  pub installer_hooks: Option<PathBuf>,
506  /// Try to ensure that the WebView2 version is equal to or newer than this version,
507  /// if the user's WebView2 is older than this version,
508  /// the installer will try to trigger a WebView2 update.
509  pub minimum_webview2_version: Option<String>,
510}
511
512/// The Custom Signing Command Settings for Windows exe
513#[derive(Clone, Debug)]
514pub struct CustomSignCommandSettings {
515  /// The command to run to sign the binary.
516  pub cmd: String,
517  /// The arguments to pass to the command.
518  ///
519  /// "%1" will be replaced with the path to the binary to be signed.
520  pub args: Vec<String>,
521}
522
523/// The Windows bundle settings.
524#[derive(Clone, Debug)]
525pub struct WindowsSettings {
526  /// The file digest algorithm to use for creating file signatures. Required for code signing. SHA-256 is recommended.
527  pub digest_algorithm: Option<String>,
528  /// The SHA1 hash of the signing certificate.
529  pub certificate_thumbprint: Option<String>,
530  /// Server to use during timestamping.
531  pub timestamp_url: Option<String>,
532  /// Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may
533  /// use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.
534  pub tsp: bool,
535  /// WiX configuration.
536  pub wix: Option<WixSettings>,
537  /// Nsis configuration.
538  pub nsis: Option<NsisSettings>,
539  /// The path to the application icon. Defaults to `./icons/icon.ico`.
540  #[deprecated = "This is used for the MSI installer and will be removed in 3.0.0, use `BundleSettings::icon` field and make sure a `.ico` icon exists instead."]
541  pub icon_path: PathBuf,
542  /// The installation mode for the Webview2 runtime.
543  pub webview_install_mode: WebviewInstallMode,
544  /// Validates a second app installation, blocking the user from installing an older version if set to `false`.
545  ///
546  /// For instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.
547  ///
548  /// /// The default value of this flag is `true`.
549  pub allow_downgrades: bool,
550
551  /// Specify a custom command to sign the binaries.
552  /// This command needs to have a `%1` in it which is just a placeholder for the binary path,
553  /// which we will detect and replace before calling the command.
554  ///
555  /// Example:
556  /// ```text
557  /// sign-cli --arg1 --arg2 %1
558  /// ```
559  ///
560  /// By Default we use `signtool.exe` which can be found only on Windows so
561  /// if you are on another platform and want to cross-compile and sign you will
562  /// need to use another tool like `osslsigncode`.
563  pub sign_command: Option<CustomSignCommandSettings>,
564}
565
566#[allow(deprecated)]
567mod _default {
568  use super::*;
569
570  impl Default for WindowsSettings {
571    fn default() -> Self {
572      Self {
573        digest_algorithm: None,
574        certificate_thumbprint: None,
575        timestamp_url: None,
576        tsp: false,
577        wix: None,
578        nsis: None,
579        icon_path: PathBuf::from("icons/icon.ico"),
580        webview_install_mode: Default::default(),
581        allow_downgrades: true,
582        sign_command: None,
583      }
584    }
585  }
586}
587
588/// The bundle settings of the BuildArtifact we're bundling.
589#[derive(Clone, Debug, Default)]
590pub struct BundleSettings {
591  /// the app's identifier.
592  pub identifier: Option<String>,
593  /// The app's publisher. Defaults to the second element in the identifier string.
594  ///
595  /// Currently maps to the Manufacturer property of the Windows Installer
596  /// and the Maintainer field of debian packages if the Cargo.toml does not have the authors field.
597  pub publisher: Option<String>,
598  /// A url to the home page of your application. If None, will
599  /// fallback to [PackageSettings::homepage].
600  ///
601  /// Supported bundle targets: `deb`, `rpm`, `nsis` and `msi`
602  pub homepage: Option<String>,
603  /// the app's icon list.
604  pub icon: Option<Vec<String>>,
605  /// the app's resources to bundle.
606  ///
607  /// each item can be a path to a file or a path to a folder.
608  ///
609  /// supports glob patterns.
610  pub resources: Option<Vec<String>>,
611  /// The app's resources to bundle. Takes precedence over `Self::resources` when specified.
612  ///
613  /// Maps each resource path to its target directory in the bundle resources directory.
614  ///
615  /// Supports glob patterns.
616  pub resources_map: Option<HashMap<String, String>>,
617  /// the app's copyright.
618  pub copyright: Option<String>,
619  /// The package's license identifier to be included in the appropriate bundles.
620  /// If not set, defaults to the license from the Cargo.toml file.
621  pub license: Option<String>,
622  /// The path to the license file to be included in the appropriate bundles.
623  pub license_file: Option<PathBuf>,
624  /// the app's category.
625  pub category: Option<AppCategory>,
626  /// the file associations
627  pub file_associations: Option<Vec<FileAssociation>>,
628  /// the app's short description.
629  pub short_description: Option<String>,
630  /// the app's long description.
631  pub long_description: Option<String>,
632  // Bundles for other binaries:
633  /// Configuration map for the apps to bundle.
634  pub bin: Option<HashMap<String, BundleSettings>>,
635  /// External binaries to add to the bundle.
636  ///
637  /// Note that each binary name should have the target platform's target triple appended,
638  /// as well as `.exe` for Windows.
639  /// For example, if you're bundling a sidecar called `sqlite3`, the bundler expects
640  /// a binary named `sqlite3-x86_64-unknown-linux-gnu` on linux,
641  /// and `sqlite3-x86_64-pc-windows-gnu.exe` on windows.
642  ///
643  /// Run `tauri build --help` for more info on targets.
644  ///
645  /// If you are building a universal binary for MacOS, the bundler expects
646  /// your external binary to also be universal, and named after the target triple,
647  /// e.g. `sqlite3-universal-apple-darwin`. See
648  /// <https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary>
649  pub external_bin: Option<Vec<String>>,
650  /// Deep-link protocols.
651  pub deep_link_protocols: Option<Vec<DeepLinkProtocol>>,
652  /// Debian-specific settings.
653  pub deb: DebianSettings,
654  /// AppImage-specific settings.
655  pub appimage: AppImageSettings,
656  /// Rpm-specific settings.
657  pub rpm: RpmSettings,
658  /// DMG-specific settings.
659  pub dmg: DmgSettings,
660  /// iOS-specific settings.
661  pub ios: IosSettings,
662  /// MacOS-specific settings.
663  pub macos: MacOsSettings,
664  /// Updater configuration.
665  pub updater: Option<UpdaterSettings>,
666  /// Windows-specific settings.
667  pub windows: WindowsSettings,
668}
669
670/// A binary to bundle.
671#[derive(Clone, Debug)]
672pub struct BundleBinary {
673  name: String,
674  main: bool,
675  src_path: Option<String>,
676}
677
678impl BundleBinary {
679  /// Creates a new bundle binary.
680  pub fn new(name: String, main: bool) -> Self {
681    Self {
682      name,
683      main,
684      src_path: None,
685    }
686  }
687
688  /// Creates a new bundle binary with path.
689  pub fn with_path(name: String, main: bool, src_path: Option<String>) -> Self {
690    Self {
691      name,
692      src_path,
693      main,
694    }
695  }
696
697  /// Mark the binary as the main executable.
698  pub fn set_main(&mut self, main: bool) {
699    self.main = main;
700  }
701
702  /// Sets the binary name.
703  pub fn set_name(&mut self, name: String) {
704    self.name = name;
705  }
706
707  /// Sets the src path of the binary.
708  #[must_use]
709  pub fn set_src_path(mut self, src_path: Option<String>) -> Self {
710    self.src_path = src_path;
711    self
712  }
713
714  /// Returns the binary `main` flag.
715  pub fn main(&self) -> bool {
716    self.main
717  }
718
719  /// Returns the binary name.
720  pub fn name(&self) -> &str {
721    &self.name
722  }
723
724  /// Returns the binary source path.
725  pub fn src_path(&self) -> Option<&String> {
726    self.src_path.as_ref()
727  }
728}
729
730#[derive(Clone, Copy, Debug, Eq, PartialEq)]
731pub enum Arch {
732  /// For the x86_64 / x64 / AMD64 instruction sets (64 bits).
733  X86_64,
734  /// For the x86 / i686 / i686 / 8086 instruction sets (32 bits).
735  X86,
736  /// For the AArch64 / ARM64 instruction sets (64 bits).
737  AArch64,
738  /// For the AArch32 / ARM32 instruction sets with hard-float (32 bits).
739  Armhf,
740  /// For the AArch32 / ARM32 instruction sets with soft-float (32 bits).
741  Armel,
742  /// For the RISC-V instruction sets (64 bits).
743  Riscv64,
744  /// For universal macOS applications.
745  Universal,
746}
747
748/// The Settings exposed by the module.
749#[derive(Clone, Debug)]
750pub struct Settings {
751  /// The log level.
752  log_level: log::Level,
753  /// the package settings.
754  package: PackageSettings,
755  /// the package types we're bundling.
756  ///
757  /// if not present, we'll use the PackageType list for the target OS.
758  package_types: Option<Vec<PackageType>>,
759  /// the directory where the bundles will be placed.
760  project_out_directory: PathBuf,
761  /// the directory to place tools used by the bundler,
762  /// if `None`, tools are placed in the current user's platform-specific cache directory.
763  local_tools_directory: Option<PathBuf>,
764  /// the bundle settings.
765  bundle_settings: BundleSettings,
766  /// the binaries to bundle.
767  binaries: Vec<BundleBinary>,
768  /// The target platform.
769  target_platform: TargetPlatform,
770  /// The target triple.
771  target: String,
772}
773
774/// A builder for [`Settings`].
775#[derive(Default)]
776pub struct SettingsBuilder {
777  log_level: Option<log::Level>,
778  project_out_directory: Option<PathBuf>,
779  package_types: Option<Vec<PackageType>>,
780  package_settings: Option<PackageSettings>,
781  bundle_settings: BundleSettings,
782  binaries: Vec<BundleBinary>,
783  target: Option<String>,
784  local_tools_directory: Option<PathBuf>,
785}
786
787impl SettingsBuilder {
788  /// Creates the default settings builder.
789  pub fn new() -> Self {
790    Default::default()
791  }
792
793  /// Sets the project output directory. It's used as current working directory.
794  #[must_use]
795  pub fn project_out_directory<P: AsRef<Path>>(mut self, path: P) -> Self {
796    self
797      .project_out_directory
798      .replace(path.as_ref().to_path_buf());
799    self
800  }
801
802  /// Sets the directory to place tools used by the bundler
803  /// when [`BundleSettings::use_local_tools_dir`] is true.
804  #[must_use]
805  pub fn local_tools_directory<P: AsRef<Path>>(mut self, path: P) -> Self {
806    self
807      .local_tools_directory
808      .replace(path.as_ref().to_path_buf());
809    self
810  }
811
812  /// Sets the package types to create.
813  #[must_use]
814  pub fn package_types(mut self, package_types: Vec<PackageType>) -> Self {
815    self.package_types = Some(package_types);
816    self
817  }
818
819  /// Sets the package settings.
820  #[must_use]
821  pub fn package_settings(mut self, settings: PackageSettings) -> Self {
822    self.package_settings.replace(settings);
823    self
824  }
825
826  /// Sets the bundle settings.
827  #[must_use]
828  pub fn bundle_settings(mut self, settings: BundleSettings) -> Self {
829    self.bundle_settings = settings;
830    self
831  }
832
833  /// Sets the binaries to bundle.
834  #[must_use]
835  pub fn binaries(mut self, binaries: Vec<BundleBinary>) -> Self {
836    self.binaries = binaries;
837    self
838  }
839
840  /// Sets the target triple.
841  #[must_use]
842  pub fn target(mut self, target: String) -> Self {
843    self.target.replace(target);
844    self
845  }
846
847  /// Sets the log level for spawned commands. Defaults to [`log::Level::Error`].
848  #[must_use]
849  pub fn log_level(mut self, level: log::Level) -> Self {
850    self.log_level.replace(level);
851    self
852  }
853
854  /// Builds a Settings from the CLI args.
855  ///
856  /// Package settings will be read from Cargo.toml.
857  ///
858  /// Bundle settings will be read from $TAURI_DIR/tauri.conf.json if it exists and fallback to Cargo.toml's [package.metadata.bundle].
859  pub fn build(self) -> crate::Result<Settings> {
860    let target = if let Some(t) = self.target {
861      t
862    } else {
863      target_triple()?
864    };
865    let target_platform = TargetPlatform::from_triple(&target);
866
867    Ok(Settings {
868      log_level: self.log_level.unwrap_or(log::Level::Error),
869      package: self
870        .package_settings
871        .ok_or_else(|| crate::Error::GenericError("package settings is required".into()))?,
872      package_types: self.package_types,
873      project_out_directory: self
874        .project_out_directory
875        .ok_or_else(|| crate::Error::GenericError("out directory is required".into()))?,
876      local_tools_directory: self.local_tools_directory,
877      binaries: self.binaries,
878      bundle_settings: BundleSettings {
879        external_bin: self
880          .bundle_settings
881          .external_bin
882          .as_ref()
883          .map(|bins| external_binaries(bins, &target, &target_platform)),
884        ..self.bundle_settings
885      },
886      target_platform,
887      target,
888    })
889  }
890}
891
892impl Settings {
893  /// Sets the log level for spawned commands.
894  pub fn set_log_level(&mut self, level: log::Level) {
895    self.log_level = level;
896  }
897
898  /// Returns the log level for spawned commands.
899  pub fn log_level(&self) -> log::Level {
900    self.log_level
901  }
902
903  /// Returns the directory where the bundle should be placed.
904  pub fn project_out_directory(&self) -> &Path {
905    &self.project_out_directory
906  }
907
908  /// Returns the target triple.
909  pub fn target(&self) -> &str {
910    &self.target
911  }
912
913  /// Returns the [`TargetPlatform`].
914  pub fn target_platform(&self) -> &TargetPlatform {
915    &self.target_platform
916  }
917
918  /// Returns the architecture for the binary being bundled (e.g. "arm", "x86" or "x86_64").
919  pub fn binary_arch(&self) -> Arch {
920    if self.target.starts_with("x86_64") {
921      Arch::X86_64
922    } else if self.target.starts_with('i') {
923      Arch::X86
924    } else if self.target.starts_with("arm") && self.target.ends_with("hf") {
925      Arch::Armhf
926    } else if self.target.starts_with("arm") {
927      Arch::Armel
928    } else if self.target.starts_with("aarch64") {
929      Arch::AArch64
930    } else if self.target.starts_with("riscv64") {
931      Arch::Riscv64
932    } else if self.target.starts_with("universal") {
933      Arch::Universal
934    } else {
935      panic!("Unexpected target triple {}", self.target)
936    }
937  }
938
939  /// Returns the file name of the binary being bundled.
940  pub fn main_binary(&self) -> crate::Result<&BundleBinary> {
941    self
942      .binaries
943      .iter()
944      .find(|bin| bin.main)
945      .context("failed to find main binary, make sure you have a `package > default-run` in the Cargo.toml file")
946      .map_err(Into::into)
947  }
948
949  /// Returns the file name of the binary being bundled.
950  pub fn main_binary_mut(&mut self) -> crate::Result<&mut BundleBinary> {
951    self
952      .binaries
953      .iter_mut()
954      .find(|bin| bin.main)
955      .context("failed to find main binary, make sure you have a `package > default-run` in the Cargo.toml file")
956      .map_err(Into::into)
957  }
958
959  /// Returns the file name of the binary being bundled.
960  pub fn main_binary_name(&self) -> crate::Result<&str> {
961    self
962      .binaries
963      .iter()
964      .find(|bin| bin.main)
965      .context("failed to find main binary, make sure you have a `package > default-run` in the Cargo.toml file")
966      .map(|b| b.name())
967      .map_err(Into::into)
968  }
969
970  /// Returns the path to the specified binary.
971  pub fn binary_path(&self, binary: &BundleBinary) -> PathBuf {
972    let target_os = self.target_platform();
973
974    let mut path = self.project_out_directory.join(binary.name());
975
976    if matches!(target_os, TargetPlatform::Windows) {
977      // Append the `.exe` extension without overriding the existing extensions
978      let extension = if let Some(extension) = path.extension() {
979        let mut extension = extension.to_os_string();
980        extension.push(".exe");
981        extension
982      } else {
983        "exe".into()
984      };
985      path.set_extension(extension);
986    };
987
988    path
989  }
990
991  /// Returns the list of binaries to bundle.
992  pub fn binaries(&self) -> &Vec<BundleBinary> {
993    &self.binaries
994  }
995
996  /// If a list of package types was specified by the command-line, returns
997  /// that list filtered by the current target OS available targets.
998  ///
999  /// If a target triple was specified by the
1000  /// command-line, returns the native package type(s) for that target.
1001  ///
1002  /// Otherwise returns the native package type(s) for the host platform.
1003  ///
1004  /// Fails if the host/target's native package type is not supported.
1005  pub fn package_types(&self) -> crate::Result<Vec<PackageType>> {
1006    let target_os = self.target_platform();
1007
1008    let platform_types = match target_os {
1009      TargetPlatform::MacOS => vec![PackageType::MacOsBundle, PackageType::Dmg],
1010      TargetPlatform::Ios => vec![PackageType::IosBundle],
1011      TargetPlatform::Linux => vec![PackageType::Deb, PackageType::Rpm, PackageType::AppImage],
1012      TargetPlatform::Windows => vec![PackageType::WindowsMsi, PackageType::Nsis],
1013      os => {
1014        return Err(crate::Error::GenericError(format!(
1015          "Native {os} bundles not yet supported."
1016        )))
1017      }
1018    };
1019
1020    if let Some(package_types) = &self.package_types {
1021      let mut types = vec![];
1022      for package_type in package_types {
1023        let package_type = *package_type;
1024        if platform_types
1025          .clone()
1026          .into_iter()
1027          .any(|t| t == package_type)
1028        {
1029          types.push(package_type);
1030        }
1031      }
1032      Ok(types)
1033    } else {
1034      Ok(platform_types)
1035    }
1036  }
1037
1038  /// Returns the product name.
1039  pub fn product_name(&self) -> &str {
1040    &self.package.product_name
1041  }
1042
1043  /// Returns the bundle's identifier
1044  pub fn bundle_identifier(&self) -> &str {
1045    self.bundle_settings.identifier.as_deref().unwrap_or("")
1046  }
1047
1048  /// Returns the bundle's publisher
1049  pub fn publisher(&self) -> Option<&str> {
1050    self.bundle_settings.publisher.as_deref()
1051  }
1052
1053  /// Returns an iterator over the icon files to be used for this bundle.
1054  pub fn icon_files(&self) -> ResourcePaths<'_> {
1055    match self.bundle_settings.icon {
1056      Some(ref paths) => ResourcePaths::new(paths.as_slice(), false),
1057      None => ResourcePaths::new(&[], false),
1058    }
1059  }
1060
1061  /// Returns an iterator over the resource files to be included in this
1062  /// bundle.
1063  pub fn resource_files(&self) -> ResourcePaths<'_> {
1064    match (
1065      &self.bundle_settings.resources,
1066      &self.bundle_settings.resources_map,
1067    ) {
1068      (Some(paths), None) => ResourcePaths::new(paths.as_slice(), true),
1069      (None, Some(map)) => ResourcePaths::from_map(map, true),
1070      (Some(_), Some(_)) => panic!("cannot use both `resources` and `resources_map`"),
1071      (None, None) => ResourcePaths::new(&[], true),
1072    }
1073  }
1074
1075  /// Returns an iterator over the external binaries to be included in this
1076  /// bundle.
1077  pub fn external_binaries(&self) -> ResourcePaths<'_> {
1078    match self.bundle_settings.external_bin {
1079      Some(ref paths) => ResourcePaths::new(paths.as_slice(), true),
1080      None => ResourcePaths::new(&[], true),
1081    }
1082  }
1083
1084  /// Copies external binaries to a path.
1085  ///
1086  /// Returns the list of destination paths.
1087  pub fn copy_binaries(&self, path: &Path) -> crate::Result<Vec<PathBuf>> {
1088    let mut paths = Vec::new();
1089
1090    for src in self.external_binaries() {
1091      let src = src?;
1092      let dest = path.join(
1093        src
1094          .file_name()
1095          .expect("failed to extract external binary filename")
1096          .to_string_lossy()
1097          .replace(&format!("-{}", self.target), ""),
1098      );
1099      fs_utils::copy_file(&src, &dest)?;
1100      paths.push(dest);
1101    }
1102    Ok(paths)
1103  }
1104
1105  /// Copies resources to a path.
1106  pub fn copy_resources(&self, path: &Path) -> crate::Result<()> {
1107    for resource in self.resource_files().iter() {
1108      let resource = resource?;
1109      let dest = path.join(resource.target());
1110      fs_utils::copy_file(resource.path(), &dest)?;
1111    }
1112    Ok(())
1113  }
1114
1115  /// Returns the version string of the bundle.
1116  pub fn version_string(&self) -> &str {
1117    &self.package.version
1118  }
1119
1120  /// Returns the copyright text.
1121  pub fn copyright_string(&self) -> Option<&str> {
1122    self.bundle_settings.copyright.as_deref()
1123  }
1124
1125  /// Returns the list of authors name.
1126  pub fn author_names(&self) -> &[String] {
1127    match self.package.authors {
1128      Some(ref names) => names.as_slice(),
1129      None => &[],
1130    }
1131  }
1132
1133  /// Returns the authors as a comma-separated string.
1134  pub fn authors_comma_separated(&self) -> Option<String> {
1135    let names = self.author_names();
1136    if names.is_empty() {
1137      None
1138    } else {
1139      Some(names.join(", "))
1140    }
1141  }
1142
1143  /// Returns the bundle license.
1144  pub fn license(&self) -> Option<String> {
1145    self.bundle_settings.license.clone()
1146  }
1147
1148  /// Returns the bundle license file.
1149  pub fn license_file(&self) -> Option<PathBuf> {
1150    self.bundle_settings.license_file.clone()
1151  }
1152
1153  /// Returns the package's homepage URL, defaulting to "" if not defined.
1154  pub fn homepage_url(&self) -> Option<&str> {
1155    self
1156      .bundle_settings
1157      .homepage
1158      .as_deref()
1159      .or(self.package.homepage.as_deref())
1160  }
1161
1162  /// Returns the app's category.
1163  pub fn app_category(&self) -> Option<AppCategory> {
1164    self.bundle_settings.category
1165  }
1166
1167  /// Return file associations.
1168  pub fn file_associations(&self) -> Option<&Vec<FileAssociation>> {
1169    self.bundle_settings.file_associations.as_ref()
1170  }
1171
1172  /// Return the list of deep link protocols to be registered for
1173  /// this bundle.
1174  pub fn deep_link_protocols(&self) -> Option<&Vec<DeepLinkProtocol>> {
1175    self.bundle_settings.deep_link_protocols.as_ref()
1176  }
1177
1178  /// Returns the app's short description.
1179  pub fn short_description(&self) -> &str {
1180    self
1181      .bundle_settings
1182      .short_description
1183      .as_ref()
1184      .unwrap_or(&self.package.description)
1185  }
1186
1187  /// Returns the app's long description.
1188  pub fn long_description(&self) -> Option<&str> {
1189    self.bundle_settings.long_description.as_deref()
1190  }
1191
1192  /// Returns the directory for local tools path.
1193  pub fn local_tools_directory(&self) -> Option<&Path> {
1194    self.local_tools_directory.as_deref()
1195  }
1196
1197  /// Returns the debian settings.
1198  pub fn deb(&self) -> &DebianSettings {
1199    &self.bundle_settings.deb
1200  }
1201
1202  /// Returns the appimage settings.
1203  pub fn appimage(&self) -> &AppImageSettings {
1204    &self.bundle_settings.appimage
1205  }
1206
1207  /// Returns the RPM settings.
1208  pub fn rpm(&self) -> &RpmSettings {
1209    &self.bundle_settings.rpm
1210  }
1211
1212  /// Returns the DMG settings.
1213  pub fn dmg(&self) -> &DmgSettings {
1214    &self.bundle_settings.dmg
1215  }
1216
1217  /// Returns the iOS settings.
1218  pub fn ios(&self) -> &IosSettings {
1219    &self.bundle_settings.ios
1220  }
1221
1222  /// Returns the MacOS settings.
1223  pub fn macos(&self) -> &MacOsSettings {
1224    &self.bundle_settings.macos
1225  }
1226
1227  /// Returns the Windows settings.
1228  pub fn windows(&self) -> &WindowsSettings {
1229    &self.bundle_settings.windows
1230  }
1231
1232  /// Returns the Updater settings.
1233  pub fn updater(&self) -> Option<&UpdaterSettings> {
1234    self.bundle_settings.updater.as_ref()
1235  }
1236}