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