diff --git a/.changes/fix-wix-external-bin-id.md b/.changes/fix-wix-external-bin-id.md new file mode 100644 index 000000000000..2a9edd1a71f1 --- /dev/null +++ b/.changes/fix-wix-external-bin-id.md @@ -0,0 +1,7 @@ +--- +"tauri-bundler": patch:bug +"tauri-cli": patch:bug +"@tauri-apps/cli": patch:bug +--- + +Fix MSI bundling when an external binary filename starts with a digit. diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index a719796e1e2a..34d79f5f5bdb 100644 --- a/crates/tauri-bundler/src/bundle.rs +++ b/crates/tauri-bundler/src/bundle.rs @@ -135,9 +135,9 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { // TODO: change this to work on a copy while preserving the main binary unchanged let mut main_binary_copy = tempfile::tempfile().context("failed to create temp file for main binary copy")?; - let mut main_binary_orignal = std::fs::File::open(&main_binary_path) + let mut main_binary_original = std::fs::File::open(&main_binary_path) .fs_context("can't open main binary", &main_binary_path)?; - std::io::copy(&mut main_binary_orignal, &mut main_binary_copy)?; + std::io::copy(&mut main_binary_original, &mut main_binary_copy)?; let mut bundles = Vec::::new(); for package_type in &package_types { diff --git a/crates/tauri-bundler/src/bundle/macos/dmg/bundle_dmg b/crates/tauri-bundler/src/bundle/macos/dmg/bundle_dmg index fee840034f17..158611cb8387 100644 --- a/crates/tauri-bundler/src/bundle/macos/dmg/bundle_dmg +++ b/crates/tauri-bundler/src/bundle/macos/dmg/bundle_dmg @@ -520,7 +520,7 @@ else fi fi -# Make sure it's not world writeable +# Make sure it's not world writable echo "Fixing permissions..." chmod -Rf go-w "${MOUNT_DIR}" &> /dev/null || true echo "Done fixing permissions" diff --git a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs index 2b7452291f40..6ac4e960f569 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs @@ -35,7 +35,7 @@ use std::{ use tauri_utils::{config::WebviewInstallMode, display_path}; use uuid::Uuid; -// URLS for the WIX toolchain. Can be used for cross-platform compilation. +// URLs for the WIX toolchain. Can be used for cross-platform compilation. pub const WIX_URL: &str = "https://github.com/wixtoolset/wix3/releases/download/wix3141rtm/wix314-binaries.zip"; pub const WIX_SHA256: &str = "6ac824e1642d6f7277d0ed7ea09411a508f6116ba6fae0aa5f2c7daa2ff43d31"; @@ -256,6 +256,24 @@ fn generate_guid(key: &[u8]) -> Uuid { Uuid::new_v5(&namespace, key) } +fn wix_identifier(id: &str) -> String { + let mut identifier: String = id + .replace('-', "_") + .chars() + .filter(|c| c.is_ascii_alphanumeric() || *c == '_' || *c == '.') + .collect(); + + if !identifier + .chars() + .next() + .is_some_and(|c| c.is_ascii_alphabetic() || c == '_') + { + identifier.insert(0, '_'); + } + + identifier +} + // Specifically goes and gets Wix and verifies the download via Sha256 pub fn get_and_extract_wix(path: &Path) -> crate::Result<()> { log::info!("Verifying wix package"); @@ -631,7 +649,7 @@ pub fn build_wix_app_installer( let merge_modules = get_merge_modules(settings)?; data.insert("merge_modules", to_json(merge_modules)); - // Note: `main_binary_name` is not used in our template but we keep it as it is potentially useful for custom temples + // Note: `main_binary_name` is not used in our template but we keep it as it is potentially useful for custom templates let main_binary_name = settings.main_binary_name()?; data.insert("main_binary_name", to_json(main_binary_name)); @@ -785,7 +803,7 @@ pub fn build_wix_app_installer( } let mut fragment_extensions = HashSet::new(); - //Default extensions + // Default extensions fragment_extensions.insert(wix_toolset_path.join("WixUIExtension.dll")); fragment_extensions.insert(wix_toolset_path.join("WixUtilExtension.dll")); @@ -899,7 +917,6 @@ fn generate_binaries_data(settings: &Settings) -> crate::Result> { let mut binaries = Vec::new(); let cwd = std::env::current_dir()?; let tmp_dir = std::env::temp_dir(); - let regex = Regex::new(r"[^\w\d\.]")?; for src in settings.external_binaries() { let src = src?; let binary_path = cwd.join(&src); @@ -917,9 +934,7 @@ fn generate_binaries_data(settings: &Settings) -> crate::Result> { .into_os_string() .into_string() .expect("failed to read external binary path"), - id: regex - .replace_all(&dest_filename.replace('-', "_"), "") - .to_string(), + id: wix_identifier(&dest_filename), }); } @@ -932,9 +947,7 @@ fn generate_binaries_data(settings: &Settings) -> crate::Result> { .into_os_string() .into_string() .expect("failed to read binary path"), - id: regex - .replace_all(&bin.name().replace('-', "_"), "") - .to_string(), + id: wix_identifier(bin.name()), }) } } @@ -1153,4 +1166,14 @@ mod tests { assert!(convert_version("1.1.2-alpha.4").is_err()); assert!(convert_version("1.1.2+asd.3").is_err()); } + + #[test] + fn sanitizes_wix_identifiers() { + assert_eq!(wix_identifier("7za.exe"), "_7za.exe"); + assert_eq!(wix_identifier("my-app.exe"), "my_app.exe"); + assert_eq!(wix_identifier("bad name!.exe"), "badname.exe"); + assert_eq!(wix_identifier(".bin"), "_.bin"); + assert_eq!(wix_identifier(""), "_"); + assert_eq!(wix_identifier("app_1.2"), "app_1.2"); + } } diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi b/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi index d372e3c39177..fd863fb4a047 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi +++ b/crates/tauri-bundler/src/bundle/windows/nsis/installer.nsi @@ -260,7 +260,7 @@ Function PageReinstall ; Skip showing the page if passive ; - ; Note that we don't call this earlier at the begining + ; Note that we don't call this earlier at the beginning ; of this function because we need to populate some variables ; related to current installed version if detected and whether ; we are downgrading or not. @@ -377,7 +377,7 @@ Function PageLeaveReinstall Abort ${EndIf} - ; Other erros? show generic error message and return to select un/reinstall page + ; Other errors? show generic error message and return to select un/reinstall page MessageBox MB_ICONEXCLAMATION "$(unableToUninstall)" Abort ${EndIf} diff --git a/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh b/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh index 3c5bf75f5ccc..fd84d2b9b587 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh +++ b/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh @@ -151,7 +151,7 @@ ; use Pop to get the result, 1 is yes, 0 is no, ; note that this macro modifies $0, $1, $2, $3 ; -; Exmaple usage: +; Example usage: ; !insertmacro "IsShortCutTarget" "C:\Users\Public\Desktop\App.lnk" "C:\Program Files\App\App.exe" ; Pop $0 ; ${If} $0 = 1 diff --git a/crates/tauri-runtime-wry/src/undecorated_resizing.rs b/crates/tauri-runtime-wry/src/undecorated_resizing.rs index 66a98710cbbb..7a1dad6ff5c9 100644 --- a/crates/tauri-runtime-wry/src/undecorated_resizing.rs +++ b/crates/tauri-runtime-wry/src/undecorated_resizing.rs @@ -222,7 +222,7 @@ mod windows { SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE, ); } else { - // otherwise updat the cutout region + // otherwise update the cutout region let mut rect = RECT::default(); if GetClientRect(parent, &mut rect).is_ok() { let width = rect.right - rect.left; diff --git a/crates/tauri/src/ipc/authority.rs b/crates/tauri/src/ipc/authority.rs index 8bb81e398f26..4825b9ce1747 100644 --- a/crates/tauri/src/ipc/authority.rs +++ b/crates/tauri/src/ipc/authority.rs @@ -101,7 +101,7 @@ macro_rules! runtime_authority { } impl RuntimeAuthority { - /// Contruct a new [`RuntimeAuthority`] from the ACL + /// Construct a new [`RuntimeAuthority`] from the ACL /// /// **Please prefer using the [`runtime_authority`] macro instead of calling this directly** #[doc(hidden)] @@ -1004,7 +1004,7 @@ mod tests { } #[test] - fn denied_command_takes_precendence() { + fn denied_command_takes_precedence() { let command = "my-command"; let window = "main"; let webview = "main"; diff --git a/crates/tauri/src/ipc/mod.rs b/crates/tauri/src/ipc/mod.rs index aff4d48910f4..addc65c7529f 100644 --- a/crates/tauri/src/ipc/mod.rs +++ b/crates/tauri/src/ipc/mod.rs @@ -156,7 +156,7 @@ impl Request<'_> { self.body } - /// Thr request headers. + /// The request headers. pub fn headers(&self) -> &HeaderMap { self.headers } diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index 8215cf1335c6..12b1df2e4e8a 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -347,7 +347,7 @@ impl AppManager { /// Get the base app URL for [`WebviewUrl::App`](tauri_utils::config::WebviewUrl::App). /// - /// * In dev mode, this is the [`devUrl`](tauri_utils::config::BuildConfig::dev_url) configuration value if it exsits. + /// * In dev mode, this is the [`devUrl`](tauri_utils::config::BuildConfig::dev_url) configuration value if it exists. /// * In production mode, this is the [`frontendDist`](tauri_utils::config::BuildConfig::frontend_dist) configuration value if it's a [`FrontendDist::Url`](tauri_utils::config::FrontendDist::Url). /// * Returns [`Self::tauri_protocol_url`] (e.g. `tauri://localhost`) otherwise. pub(crate) fn get_app_url(&self, https: bool) -> Cow<'_, Url> { diff --git a/packages/api/src/webview.ts b/packages/api/src/webview.ts index 968983c02eda..5d7f735bcf15 100644 --- a/packages/api/src/webview.ts +++ b/packages/api/src/webview.ts @@ -593,7 +593,7 @@ class Webview { /** * Specify the webview background color. * - * #### Platfrom-specific: + * #### Platform-specific: * * - **macOS / iOS**: Not implemented. * - **Windows**: