Explorar o código

feat: add `upgradeCode` config option (#11039)

* feat: add `upgradeCode` config option

* fix build on other platforms

* Update crates/tauri-bundler/src/bundle/settings.rs [skip ci]

* move to subcommand, use same product name fallback as the bundler

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
Amr Bashir hai 10 meses
pai
achega
f57a729cd8

+ 6 - 0
.changes/tauri-cli-generate-upgrade-code.md

@@ -0,0 +1,6 @@
+---
+"tauri-cli": "patch:feat"
+"@tauri-apps/cli": "patch:feat"
+---
+
+Add `tauri inspect wix-upgrade-code` to print default Upgrade Code for your MSI installer derived from `productName`.

+ 6 - 0
.changes/upgrade-code-option.md

@@ -0,0 +1,6 @@
+---
+"tauri-utils": "patch:feat"
+"tauri-bundler": "patch:feat"
+---
+
+Add `upgradeCode` in `wix` configuration to set an upgrade code for your MSI installer. This is recommended to be set if you plan to change your `productName`.

+ 4 - 0
Cargo.lock

@@ -6242,6 +6242,7 @@ dependencies = [
  "serde",
  "serde_json",
  "url",
+ "uuid",
 ]
 
 [[package]]
@@ -7421,6 +7422,7 @@ dependencies = [
  "toml_edit 0.22.20",
  "ureq",
  "url",
+ "uuid",
  "walkdir",
  "windows-sys 0.59.0",
 ]
@@ -7760,6 +7762,7 @@ dependencies = [
  "toml 0.8.19",
  "url",
  "urlpattern",
+ "uuid",
  "walkdir",
 ]
 
@@ -8496,6 +8499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314"
 dependencies = [
  "getrandom 0.2.15",
+ "serde",
  "sha1_smol",
 ]
 

+ 1 - 1
crates/tauri-bundler/Cargo.toml

@@ -43,9 +43,9 @@ sha2 = "0.10"
 zip = { version = "2.0", default-features = false, features = ["deflate"] }
 dunce = "1"
 url = "2"
+uuid = { version = "1", features = ["v4", "v5"] }
 
 [target."cfg(target_os = \"windows\")".dependencies]
-uuid = { version = "1", features = ["v4", "v5"] }
 bitness = "0.4"
 windows-registry = "0.2.0"
 glob = "0.3"

+ 9 - 0
crates/tauri-bundler/src/bundle/settings.rs

@@ -351,6 +351,15 @@ impl Default for WixLanguage {
 /// Settings specific to the WiX implementation.
 #[derive(Clone, Debug, Default)]
 pub struct WixSettings {
+  /// A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,
+  /// otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.
+  ///
+  /// By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.
+  /// You can use Tauri's CLI to generate and print this code for you by running `tauri inspect wix-upgrade-code`.
+  ///
+  /// It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code
+  /// whenever you want to change your product name.
+  pub upgrade_code: Option<uuid::Uuid>,
   /// The app languages to build. See <https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables>.
   pub language: WixLanguage,
   /// By default, the bundler uses an internal template.

+ 14 - 6
crates/tauri-bundler/src/bundle/windows/msi/mod.rs

@@ -548,13 +548,21 @@ pub fn build_wix_app_installer(
     .unwrap_or_else(|| bundle_id.split('.').nth(1).unwrap_or(bundle_id));
   data.insert("bundle_id", to_json(bundle_id));
   data.insert("manufacturer", to_json(manufacturer));
-  let upgrade_code = Uuid::new_v5(
-    &Uuid::NAMESPACE_DNS,
-    format!("{}.exe.app.x64", &settings.product_name()).as_bytes(),
-  )
-  .to_string();
 
-  data.insert("upgrade_code", to_json(upgrade_code.as_str()));
+  // NOTE: if this is ever changed, make sure to also update `tauri inspect wix-upgrade-code` subcommand
+  let upgrade_code = settings
+    .windows()
+    .wix
+    .as_ref()
+    .and_then(|w| w.upgrade_code)
+    .unwrap_or_else(|| {
+      Uuid::new_v5(
+        &Uuid::NAMESPACE_DNS,
+        format!("{}.exe.app.x64", &settings.product_name()).as_bytes(),
+      )
+    });
+  data.insert("upgrade_code", to_json(upgrade_code.to_string()));
+
   let product_code = Uuid::new_v5(
     &Uuid::NAMESPACE_DNS,
     settings.bundle_identifier().as_bytes(),

+ 1 - 0
crates/tauri-cli/Cargo.toml

@@ -111,6 +111,7 @@ walkdir = "2"
 elf = "0.7"
 memchr = "2"
 tempfile = "3"
+uuid = { version = "1", features = ["v5"] }
 
 [dev-dependencies]
 insta = "1"

+ 8 - 0
crates/tauri-cli/config.schema.json

@@ -2170,6 +2170,14 @@
       "description": "Configuration for the MSI bundle using WiX.\n\n See more: <https://tauri.app/v1/api/config#wixconfig>",
       "type": "object",
       "properties": {
+        "upgradeCode": {
+          "description": "A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,\n otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.\n\n By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.\n You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.\n\n It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code\n whenever you want to change your product name.",
+          "type": [
+            "string",
+            "null"
+          ],
+          "format": "uuid"
+        },
         "language": {
           "description": "The installer languages to build. See <https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables>.",
           "default": "en-US",

+ 1 - 0
crates/tauri-cli/src/helpers/config.rs

@@ -62,6 +62,7 @@ pub type ConfigHandle = Arc<Mutex<Option<ConfigMetadata>>>;
 
 pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings {
   tauri_bundler::WixSettings {
+    upgrade_code: config.upgrade_code,
     language: tauri_bundler::WixLanguage(match config.language {
       WixLanguage::One(lang) => vec![(lang, Default::default())],
       WixLanguage::List(languages) => languages

+ 58 - 0
crates/tauri-cli/src/inspect.rs

@@ -0,0 +1,58 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use anyhow::Result;
+use clap::{Parser, Subcommand};
+
+use crate::interface::{AppInterface, AppSettings, Interface};
+
+#[derive(Debug, Parser)]
+#[clap(about = "Manage or create permissions for your app or plugin")]
+pub struct Cli {
+  #[clap(subcommand)]
+  command: Commands,
+}
+
+#[derive(Subcommand, Debug)]
+enum Commands {
+  /// Print the default Upgrade Code used by MSI installer derived from productName.
+  WixUpgradeCode,
+}
+
+pub fn command(cli: Cli) -> Result<()> {
+  match cli.command {
+    Commands::WixUpgradeCode => wix_upgrade_code(),
+  }
+}
+
+// NOTE: if this is ever changed, make sure to also update Wix upgrade code generation in tauri-bundler
+fn wix_upgrade_code() -> Result<()> {
+  crate::helpers::app_paths::resolve();
+
+  let target = tauri_utils::platform::Target::Windows;
+  let config = crate::helpers::config::get(target, None)?;
+
+  let interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap(), None)?;
+
+  let product_name = interface.app_settings().get_package_settings().product_name;
+
+  let upgrade_code = uuid::Uuid::new_v5(
+    &uuid::Uuid::NAMESPACE_DNS,
+    format!("{product_name}.exe.app.x64").as_bytes(),
+  )
+  .to_string();
+
+  log::info!("Default WiX Upgrade Code, derived from {product_name}: {upgrade_code}");
+  if let Some(code) = config.lock().unwrap().as_ref().and_then(|c| {
+    c.bundle
+      .windows
+      .wix
+      .as_ref()
+      .and_then(|wix| wix.upgrade_code)
+  }) {
+    log::info!("Application Upgrade Code override: {code}");
+  }
+
+  Ok(())
+}

+ 3 - 0
crates/tauri-cli/src/lib.rs

@@ -25,6 +25,7 @@ mod helpers;
 mod icon;
 mod info;
 mod init;
+mod inspect;
 mod interface;
 mod migrate;
 mod mobile;
@@ -151,6 +152,7 @@ enum Commands {
   Completions(completions::Options),
   Permission(acl::permission::Cli),
   Capability(acl::capability::Cli),
+  Inspect(inspect::Cli),
 }
 
 fn format_error<I: CommandFactory>(err: clap::Error) -> clap::Error {
@@ -268,6 +270,7 @@ where
     #[cfg(target_os = "macos")]
     Commands::Ios(c) => mobile::ios::command(c, cli.verbose)?,
     Commands::Migrate => migrate::command()?,
+    Commands::Inspect(cli) => inspect::command(cli)?,
   }
 
   Ok(())

+ 8 - 0
crates/tauri-schema-generator/schemas/config.schema.json

@@ -2170,6 +2170,14 @@
       "description": "Configuration for the MSI bundle using WiX.\n\n See more: <https://tauri.app/v1/api/config#wixconfig>",
       "type": "object",
       "properties": {
+        "upgradeCode": {
+          "description": "A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,\n otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.\n\n By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.\n You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.\n\n It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code\n whenever you want to change your product name.",
+          "type": [
+            "string",
+            "null"
+          ],
+          "format": "uuid"
+        },
         "language": {
           "description": "The installer languages to build. See <https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables>.",
           "default": "en-US",

+ 2 - 1
crates/tauri-utils/Cargo.toml

@@ -25,7 +25,7 @@ html5ever = "0.26"
 kuchiki = { package = "kuchikiki", version = "0.8" }
 proc-macro2 = { version = "1", optional = true }
 quote = { version = "1", optional = true }
-schemars = { version = "0.8.18", features = ["url"], optional = true }
+schemars = { version = "0.8.18", features = ["url", "uuid1"], optional = true }
 serde_with = "3"
 aes-gcm = { version = "0.10", optional = true }
 getrandom = { version = "0.2", optional = true, features = ["std"] }
@@ -45,6 +45,7 @@ dunce = "1"
 log = "0.4.21"
 cargo_metadata = { version = "0.18", optional = true }
 serde-untagged = "0.1"
+uuid = { version = "1", features = ["serde"] }
 
 [target."cfg(target_os = \"macos\")".dependencies]
 swift-rs = { version = "1.0.7", optional = true, features = ["build"] }

+ 10 - 0
crates/tauri-utils/src/config.rs

@@ -658,6 +658,16 @@ impl Default for WixLanguage {
 #[cfg_attr(feature = "schema", derive(JsonSchema))]
 #[serde(rename_all = "camelCase", deny_unknown_fields)]
 pub struct WixConfig {
+  /// A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,
+  /// otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.
+  ///
+  /// By default, tauri generates this code by generating a Uuid v5 using the string `<productName>.exe.app.x64` in the DNS namespace.
+  /// You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.
+  ///
+  /// It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code
+  /// whenever you want to change your product name.
+  #[serde(alias = "upgrade-code")]
+  pub upgrade_code: Option<uuid::Uuid>,
   /// The installer languages to build. See <https://docs.microsoft.com/en-us/windows/win32/msi/localizing-the-error-and-actiontext-tables>.
   #[serde(default)]
   pub language: WixLanguage,