From 28aecb3535cc4ab0e48fcf376414e330c64e7de4 Mon Sep 17 00:00:00 2001 From: amr-crabnebula Date: Wed, 6 Sep 2023 04:10:54 +0300 Subject: [PATCH] feat: implement `nsis` --- crates/config/src/lib.rs | 22 + crates/packager/schema.json | 41 ++ crates/packager/src/deb/main.desktop | 13 + crates/packager/src/error.rs | 2 + crates/packager/src/lib.rs | 44 +- crates/packager/src/main.rs | 54 +- crates/packager/src/nsis/installer.nsi | 8 +- crates/packager/src/nsis/languages/Arabic.nsh | 27 + .../packager/src/nsis/languages/Bulgarian.nsh | 27 + crates/packager/src/nsis/languages/Dutch.nsh | 27 + .../packager/src/nsis/languages/English.nsh | 27 + crates/packager/src/nsis/languages/French.nsh | 27 + .../packager/src/nsis/languages/Japanese.nsh | 27 + crates/packager/src/nsis/languages/Korean.nsh | 27 + .../packager/src/nsis/languages/Persian.nsh | 27 + .../src/nsis/languages/PortugueseBR.nsh | 27 + .../src/nsis/languages/SimpChinese.nsh | 27 + .../packager/src/nsis/languages/Spanish.nsh | 27 + .../nsis/languages/SpanishInternational.nsh | 27 + .../packager/src/nsis/languages/Swedish.nsh | 27 + .../src/nsis/languages/TradChinese.nsh | 27 + .../packager/src/nsis/languages/Turkish.nsh | 27 + crates/packager/src/nsis/mod.rs | 525 +++++++++++++++++- crates/packager/src/sign.rs | 196 +++++++ crates/packager/src/util.rs | 118 +++- examples/dioxus/Cargo.toml | 3 +- examples/dioxus/README.md | 12 + examples/tauri/Cargo.toml | 2 + examples/tauri/README.md | 12 + examples/tauri/build.rs | 2 +- examples/tauri/tauri.conf.json | 2 +- 31 files changed, 1432 insertions(+), 29 deletions(-) create mode 100644 crates/packager/src/deb/main.desktop create mode 100644 crates/packager/src/nsis/languages/Arabic.nsh create mode 100644 crates/packager/src/nsis/languages/Bulgarian.nsh create mode 100644 crates/packager/src/nsis/languages/Dutch.nsh create mode 100644 crates/packager/src/nsis/languages/English.nsh create mode 100644 crates/packager/src/nsis/languages/French.nsh create mode 100644 crates/packager/src/nsis/languages/Japanese.nsh create mode 100644 crates/packager/src/nsis/languages/Korean.nsh create mode 100644 crates/packager/src/nsis/languages/Persian.nsh create mode 100644 crates/packager/src/nsis/languages/PortugueseBR.nsh create mode 100644 crates/packager/src/nsis/languages/SimpChinese.nsh create mode 100644 crates/packager/src/nsis/languages/Spanish.nsh create mode 100644 crates/packager/src/nsis/languages/SpanishInternational.nsh create mode 100644 crates/packager/src/nsis/languages/Swedish.nsh create mode 100644 crates/packager/src/nsis/languages/TradChinese.nsh create mode 100644 crates/packager/src/nsis/languages/Turkish.nsh create mode 100644 crates/packager/src/sign.rs diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index eb679dcf..33f84af0 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -516,6 +516,21 @@ pub enum Resources { Map(HashMap), } +/// Describes a shell command to be executed when a CLI hook is triggered. +#[derive(Debug, Clone, Deserialize, Serialize, JsonSchema)] +#[serde(untagged)] +pub enum HookCommand { + /// Run the given script with the default options. + Script(String), + /// Run the given script with custom options. + ScriptWithOptions { + /// The script to execute. + script: String, + /// The working directory. + dir: Option, + }, +} + /// The packaging config. #[derive(Deserialize, Serialize, Default, Debug, Clone, JsonSchema)] #[serde(rename_all = "camelCase", deny_unknown_fields)] @@ -523,6 +538,13 @@ pub struct Config { /// The JSON schema for the config. #[serde(rename = "$schema")] pub schema: Option, + /// Specify a command to run before starting to package an application. + #[serde( + default, + alias = "before-packaging-command", + alias = "before_packaging_command" + )] + pub before_packaging_command: Option, /// The log level. #[serde(alias = "log-level", alias = "log_level")] pub log_level: Option, diff --git a/crates/packager/schema.json b/crates/packager/schema.json index 40368799..db3b4cec 100644 --- a/crates/packager/schema.json +++ b/crates/packager/schema.json @@ -11,6 +11,18 @@ "null" ] }, + "beforePackagingCommand": { + "description": "Specify a command to run before starting to package an application.", + "default": null, + "anyOf": [ + { + "$ref": "#/definitions/HookCommand" + }, + { + "type": "null" + } + ] + }, "logLevel": { "description": "The log level.", "anyOf": [ @@ -245,6 +257,35 @@ }, "additionalProperties": false, "definitions": { + "HookCommand": { + "description": "Describes a shell command to be executed when a CLI hook is triggered.", + "anyOf": [ + { + "description": "Run the given script with the default options.", + "type": "string" + }, + { + "description": "Run the given script with custom options.", + "type": "object", + "required": [ + "script" + ], + "properties": { + "script": { + "description": "The script to execute.", + "type": "string" + }, + "dir": { + "description": "The working directory.", + "type": [ + "string", + "null" + ] + } + } + } + ] + }, "LogLevel": { "description": "An enum representing the available verbosity levels of the logger.", "oneOf": [ diff --git a/crates/packager/src/deb/main.desktop b/crates/packager/src/deb/main.desktop new file mode 100644 index 00000000..721648d0 --- /dev/null +++ b/crates/packager/src/deb/main.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Categories={{categories}} +{{#if comment}} +Comment={{comment}} +{{/if}} +Exec={{exec}} +Icon={{icon}} +Name={{name}} +Terminal=false +Type=Application +{{#if mime_type}} +MimeType={{mime_type}} +{{/if}} diff --git a/crates/packager/src/error.rs b/crates/packager/src/error.rs index e46fd683..fb5f0a2f 100644 --- a/crates/packager/src/error.rs +++ b/crates/packager/src/error.rs @@ -62,6 +62,8 @@ pub enum Error { NsisFailed(String), #[error("Failed to get parent directory of a path")] ParentDirNotFound, + #[error("{0} `{1}` failed with exit code {2}")] + HookCommandFailure(String, String, i32), } /// Convenient type alias of Result type for cargo-packager. diff --git a/crates/packager/src/lib.rs b/crates/packager/src/lib.rs index 1e802e5c..40e0e1f2 100644 --- a/crates/packager/src/lib.rs +++ b/crates/packager/src/lib.rs @@ -47,9 +47,10 @@ mod nsis; target_os = "openbsd" ))] mod rpm; +mod sign; pub mod util; -use std::path::PathBuf; +use std::{path::PathBuf, process::Command}; use config::Config; pub use config::PackageFormat; @@ -76,6 +77,47 @@ pub fn package(config: &Config) -> Result> { log:: warn!("Cross-platform compilation is experimental and does not support all features. Please use a matching host system for full compatibility."); } + if let Some(hook) = &config.before_packaging_command { + let (mut cmd, script) = match hook { + cargo_packager_config::HookCommand::Script(script) => { + #[cfg(windows)] + let mut cmd = Command::new("cmd"); + #[cfg(windows)] + cmd.arg("/S").arg("/C").arg(&script); + #[cfg(not(windows))] + let mut cmd = Command::new("sh"); + #[cfg(not(windows))] + cmd.arg("-c").arg(&script); + (cmd, script) + } + cargo_packager_config::HookCommand::ScriptWithOptions { script, dir } => { + #[cfg(windows)] + let mut cmd = Command::new("cmd"); + #[cfg(windows)] + cmd.arg("/S").arg("/C").arg(&script); + #[cfg(not(windows))] + let mut cmd = Command::new("sh"); + #[cfg(not(windows))] + cmd.arg("-c").arg(&script); + if let Some(dir) = dir { + cmd.current_dir(dir); + } + (cmd, script) + } + }; + + log::info!(action = "Running"; "beforePackagingCommand `{}`", script); + let status = cmd.status()?; + + if !status.success() { + return Err(crate::Error::HookCommandFailure( + "beforePackagingCommand".into(), + script.into(), + status.code().unwrap_or_default(), + )); + } + } + let mut packages = Vec::new(); let formats = config diff --git a/crates/packager/src/main.rs b/crates/packager/src/main.rs index 3fd5c6f1..a4a5ba53 100644 --- a/crates/packager/src/main.rs +++ b/crates/packager/src/main.rs @@ -9,10 +9,24 @@ use clap::{ArgAction, CommandFactory, FromArgMatches, Parser}; use env_logger::fmt::Color; use log::{log_enabled, Level}; -fn load_configs_from_cwd(profile: &str, verbose: u8) -> Result> { - let metadata = cargo_metadata::MetadataCommand::new().exec()?; +fn load_configs_from_cwd(profile: &str, cli: &Cli) -> Result> { + let mut metadata_cmd = cargo_metadata::MetadataCommand::new(); + if let Some(manifest_path) = &cli.manifest_path { + metadata_cmd.manifest_path(manifest_path); + } + let metadata = metadata_cmd.exec()?; let mut configs = Vec::new(); for package in metadata.workspace_packages() { + // skip if this package was not specified in the explicit packages to build + if !cli + .packages + .as_ref() + .map(|packages| packages.contains(&package.name)) + .unwrap_or(true) + { + continue; + } + if let Some(config) = package.metadata.get("packager") { let mut config: Config = serde_json::from_value(config.to_owned())?; if config.product_name.is_empty() { @@ -41,7 +55,7 @@ fn load_configs_from_cwd(profile: &str, verbose: u8) -> Result LogLevel::Info, 1 => LogLevel::Debug, 2.. => LogLevel::Trace, @@ -79,14 +93,15 @@ fn try_run(cli: Cli) -> Result<()> { use std::fmt::Write; let profile = if cli.release { - "relase" + "release" } else if let Some(profile) = &cli.profile { profile.as_str() } else { "debug" }; - for (manifest_path, config) in load_configs_from_cwd(profile, cli.verbose)? { + let mut packages = Vec::new(); + for (manifest_path, config) in load_configs_from_cwd(profile, &cli)? { std::env::set_current_dir( manifest_path .parent() @@ -94,19 +109,20 @@ fn try_run(cli: Cli) -> Result<()> { )?; // create the packages - let packages = package(&config)?; - - // print information when finished - let len = packages.len(); - let pluralised = if len == 1 { "package" } else { "packages" }; - let mut printable_paths = String::new(); - for p in packages { - for path in &p.paths { - writeln!(printable_paths, " {}", util::display_path(path)).unwrap(); - } + packages.extend(package(&config)?); + } + + // print information when finished + let len = packages.len(); + let pluralised = if len == 1 { "package" } else { "packages" }; + let mut printable_paths = String::new(); + for p in packages { + for path in &p.paths { + writeln!(printable_paths, " {}", util::display_path(path)).unwrap(); } - log::info!(action = "Finished"; "{} {} at:\n{}", len, pluralised, printable_paths); } + log::info!(action = "Finished"; "{} {} at:\n{}", len, pluralised, printable_paths); + Ok(()) } @@ -144,6 +160,12 @@ pub(crate) struct Cli { /// Specify the cargo profile to use for packaging your app. #[clap(long)] profile: Option, + /// Specify the packages to build. + #[clap(short, long)] + packages: Option>, + /// Specify the manifest path to use for reading the configuration. + #[clap(long)] + manifest_path: Option, } fn main() { diff --git a/crates/packager/src/nsis/installer.nsi b/crates/packager/src/nsis/installer.nsi index 46bba96e..2b2ff24a 100644 --- a/crates/packager/src/nsis/installer.nsi +++ b/crates/packager/src/nsis/installer.nsi @@ -597,9 +597,11 @@ Section Uninstall ; Delete app data ${If} $DeleteAppDataCheckboxState == 1 - SetShellVarContext current - RmDir /r "$APPDATA\${BUNDLEID}" - RmDir /r "$LOCALAPPDATA\${BUNDLEID}" + !if "${BUNDLEID}" != "" + SetShellVarContext current + RmDir /r "$APPDATA\${BUNDLEID}" + RmDir /r "$LOCALAPPDATA\${BUNDLEID}" + !endif ${EndIf} ${GetOptions} $CMDLINE "/P" $R0 diff --git a/crates/packager/src/nsis/languages/Arabic.nsh b/crates/packager/src/nsis/languages/Arabic.nsh new file mode 100644 index 00000000..8b138119 --- /dev/null +++ b/crates/packager/src/nsis/languages/Arabic.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_ARABIC} "إضافة أو إزالة المكونات" +LangString alreadyInstalled ${LANG_ARABIC} "التطبيق مثبت بالفعل" +LangString alreadyInstalledLong ${LANG_ARABIC} "${PRODUCTNAME} ${VERSION} مثبت بالفعل. قم باختيار العملية التى تريدها ثم اضغط على التالى." +LangString appRunning ${LANG_ARABIC} "${PRODUCTNAME} مازال يعمل! من فضلك، قم بإغلاق التطبيق أولاً ثم حاول مرة أخرى." +LangString appRunningOkKill ${LANG_ARABIC} "${PRODUCTNAME} مازال يعمل!$\nاضغط OK لإغلاقه" +LangString chooseMaintenanceOption ${LANG_ARABIC} "قم باختيار نوع الصيانة التى تريدها." +LangString choowHowToInstall ${LANG_ARABIC} "قم باختيار طريقة تنصيب ${PRODUCTNAME}." +LangString createDesktop ${LANG_ARABIC} "اضف اختصار على سطح المكتب" +LangString dontUninstall ${LANG_ARABIC} "عدم إزالة" +LangString dontUninstallDowngrade ${LANG_ARABIC} "عدم إزالة (التخفيض بدون إزالة غير مسموح لهذا المثبت)" +LangString failedToKillApp ${LANG_ARABIC} "فشل فى غلف ${PRODUCTNAME}. من فضلك، قم بإغلاق التطبيق أولاً ثم حاول مرة أخرى." +LangString installingWebview2 ${LANG_ARABIC} "تنصيب WebView2..." +LangString newerVersionInstalled ${LANG_ARABIC} "يوجد نسخة جديدة من ${PRODUCTNAME} مثبتة بالغعل! لا ينصح بتنصيب نسخة اقدم من النسخة الحالية. اذا مازلت ترغب فى تنصيب النسخة الأقدم، فينصح بإزالة النسخة الحالية أولاً. قم باختيار العملية التى تريدها ثم اضغط على التالى للاستمرار." +LangString older ${LANG_ARABIC} "أقدم" +LangString olderOrUnknownVersionInstalled ${LANG_ARABIC} "نسخة $R4 من ${PRODUCTNAME} مثبتة بالفعل على نظامك. ينصح بإزالة النسخة الحالية قبل التنصيب. قم باختيار العملية التى تريدها ثم اضغط على التالى للاستمرار." +LangString silentDowngrades ${LANG_ARABIC} "التخفيض غير مسموح لهذا المثبت ولا يمكن الاستمرار فى الوضع الصامت. من فضلك، قم باستخدام الواجهة الرسومية." +LangString unableToUninstall ${LANG_ARABIC} "غير قادر على الإزالة!" +LangString uninstallApp ${LANG_ARABIC} "إزالة ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_ARABIC} "قم بإزالة التطبيق قبل التثبيت" +LangString unknown ${LANG_ARABIC} "غير معروفة" +LangString webview2AbortError ${LANG_ARABIC} "فشل فى تنصيب WebView2! لا يمكن تشغيل التطبيق من غيره. من فضلك، حاول إعادة تشغيل المثبت." +LangString webview2DownloadError ${LANG_ARABIC} "خطأ: فشل تنزيل WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_ARABIC} "تم تنزيل WebView2 bootstrapper بنجاح" +LangString webview2Downloading ${LANG_ARABIC} "يتم تنزيل WebView2 bootstrapper..." +LangString webview2InstallError ${LANG_ARABIC} "خطأ: فشل فى تنصيب WebView2 بكود $1" +LangString webview2InstallSuccess ${LANG_ARABIC} "تم تنصيب WebView2 بنجاح" +LangString deleteAppData ${LANG_ARABIC} "مسح بيانات التطبيق" diff --git a/crates/packager/src/nsis/languages/Bulgarian.nsh b/crates/packager/src/nsis/languages/Bulgarian.nsh new file mode 100644 index 00000000..ea3f2066 --- /dev/null +++ b/crates/packager/src/nsis/languages/Bulgarian.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_BULGARIAN} "Добавяне/Преинсталиране на компоненти" +LangString alreadyInstalled ${LANG_BULGARIAN} "Вече инсталиран" +LangString alreadyInstalledLong ${LANG_BULGARIAN} "${PRODUCTNAME} ${VERSION} е вече е инсталиран. Изберете операцията, която искате да извършите и натиснете Напред, за да продължите." +LangString appRunning ${LANG_BULGARIAN} "${PRODUCTNAME} е отворен! Моля, затворете го първо и опитайте отново." +LangString appRunningOkKill ${LANG_BULGARIAN} "${PRODUCTNAME} е отворен!$\nНатиснете ОК, за да го затворите." +LangString chooseMaintenanceOption ${LANG_BULGARIAN} "Изберете опция за поддръжка." +LangString choowHowToInstall ${LANG_BULGARIAN} "Изберете как искате да инсталирате ${PRODUCTNAME}." +LangString createDesktop ${LANG_BULGARIAN} "Създайте пряк път на работния плот" +LangString dontUninstall ${LANG_BULGARIAN} "Не деинсталирайте" +LangString dontUninstallDowngrade ${LANG_BULGARIAN} "Не деинсталирайте (Понижаването без деинсталация е забранено за този инсталатор)" +LangString failedToKillApp ${LANG_BULGARIAN} "Неуспешно прекратяване на ${PRODUCTNAME}. Моля, затворете го първо и опитайте отново." +LangString installingWebview2 ${LANG_BULGARIAN} "Инсталиране на WebView2..." +LangString newerVersionInstalled ${LANG_BULGARIAN} "Вече е инсталирана по-нова версия на ${PRODUCTNAME}! Не се препоръчва да инсталирате по-стара версия. Ако наистина желаете да инсталирате тази по-стара версия, по-добре е да деинсталирате текущата версия първо. Изберете операцията, която искате да извършите и натиснете Напред, за да продължите." +LangString older ${LANG_BULGARIAN} "по-стара" +LangString olderOrUnknownVersionInstalled ${LANG_BULGARIAN} "На вашата система е инсталирана $R4 версия на ${PRODUCTNAME}. Препоръчително е да деинсталирате текущата версия преди да инсталирате нова. Изберете операцията, която искате да извършите и натиснете Напред, за да продължите." +LangString silentDowngrades ${LANG_BULGARIAN} "Понижаванията не са позволени за този инсталатор. Не е възможно да продължите с безшумен инсталатор. Моля, използвайте графичния интерфейсен инсталатор." +LangString unableToUninstall ${LANG_BULGARIAN} "Неуспешна деинсталация!" +LangString uninstallApp ${LANG_BULGARIAN} "Деинсталиране на ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_BULGARIAN} "Деинсталирай преди инсталиране" +LangString unknown ${LANG_BULGARIAN} "неизвестно" +LangString webview2AbortError ${LANG_BULGARIAN} "Неуспешно инсталиране на WebView2! Приложението не може да работи без него. Опитайте да рестартирате инсталатора." +LangString webview2DownloadError ${LANG_BULGARIAN} "Грешка: Неуспешно изтегляне на WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_BULGARIAN} "Стартиращият файл на WebView2 е изтеглен успешно" +LangString webview2Downloading ${LANG_BULGARIAN} "Изтегляне на стартиращят файл на WebView2..." +LangString webview2InstallError ${LANG_BULGARIAN} "Грешка: Инсталирането на WebView2 неуспешно с код на изход $1" +LangString webview2InstallSuccess ${LANG_BULGARIAN} "WebView2 инсталиран успешно" +LangString deleteAppData ${LANG_BULGARIAN} "Изтриване на данните на приложението" diff --git a/crates/packager/src/nsis/languages/Dutch.nsh b/crates/packager/src/nsis/languages/Dutch.nsh new file mode 100644 index 00000000..927bbd93 --- /dev/null +++ b/crates/packager/src/nsis/languages/Dutch.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_DUTCH} "(Her)installeer componenten" +LangString alreadyInstalled ${LANG_DUTCH} "Al geïnstalleerd" +LangString alreadyInstalledLong ${LANG_DUTCH} "${PRODUCTNAME} ${VERSION} is al geïnstalleerd. Kies een van de volgende opties en klik op Volgende om door te gaan." +LangString appRunning ${LANG_DUTCH} "${PRODUCTNAME} is geopend! Sluit het programma eerst en probeer het dan opnieuw." +LangString appRunningOkKill ${LANG_DUTCH} "${PRODUCTNAME} is geopend!$\nKlik op OK om het te stoppen." +LangString chooseMaintenanceOption ${LANG_DUTCH} "Kies de onderhoudsoptie die u wilt uitvoeren." +LangString choowHowToInstall ${LANG_DUTCH} "Kies hoe u ${PRODUCTNAME} wilt installeren." +LangString createDesktop ${LANG_DUTCH} "Maak een snelkoppeling aan op het bureaublad" +LangString dontUninstall ${LANG_DUTCH} "Deïnstalleer niet" +LangString dontUninstallDowngrade ${LANG_DUTCH} "Deïnstalleer niet (Downgraden zonder deïnstalleren is uitgeschakeld voor deze installer)" +LangString failedToKillApp ${LANG_DUTCH} "Het is niet gelukt ${PRODUCTNAME} te stoppen. Sluit het eerst zelf en probeer het dan nog een keer" +LangString installingWebview2 ${LANG_DUTCH} "WebView2 wordt geïnstalleerd..." +LangString newerVersionInstalled ${LANG_DUTCH} "Een nieuwere versie van ${PRODUCTNAME} is al geïnstalleerd! Het word niet aangeraden om een oudere versie te installeren. Als u echt deze oudere versie wilt installeren, kunt u beter de huidige versie eerst deïnstalleren. Kies een van de volgende opties en klik op Volgende om door te gaan." +LangString older ${LANG_DUTCH} "oudere" +LangString olderOrUnknownVersionInstalled ${LANG_DUTCH} "Een $R4 versie van ${PRODUCTNAME} is al geïnstalleerd. Het word aangeraden om de huidige versie eerst te deïnstalleren. Kies een van de volgende opties en klik op Volgende om door te gaan." +LangString silentDowngrades ${LANG_DUTCH} "Downgrades zijn uitgeschakeld voor deze installer, de stille installatie kan niet worden voltooid, gebruik a.u.b. de grafische installatie methode.$\n" +LangString unableToUninstall ${LANG_DUTCH} "De installatie kan niet ongedaan worden gemaakt." +LangString uninstallApp ${LANG_DUTCH} "Deïnstalleer ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_DUTCH} "Deïnstalleer voor installatie" +LangString unknown ${LANG_DUTCH} "onbekende" +LangString webview2AbortError ${LANG_DUTCH} "De installatie van WebView2 is mislukt! De software kan niet draaien zonder. Probeer de installatie opnieuw te starten." +LangString webview2DownloadError ${LANG_DUTCH} "Error: Het downloaden van WebView2 is mislukt - $0" +LangString webview2DownloadSuccess ${LANG_DUTCH} "De download van WebView2 bootstrapper is gelukt" +LangString webview2Downloading ${LANG_DUTCH} "WebView2 bootstrapper aan het downloaden..." +LangString webview2InstallError ${LANG_DUTCH} "Error: Het installeren van WebView2 is mislukt met exit-code $1" +LangString webview2InstallSuccess ${LANG_DUTCH} "De installatie van WebView2 is gelukt" +LangString deleteAppData ${LANG_DUTCH} "Verwijder de data van de applicatie" diff --git a/crates/packager/src/nsis/languages/English.nsh b/crates/packager/src/nsis/languages/English.nsh new file mode 100644 index 00000000..b9abb988 --- /dev/null +++ b/crates/packager/src/nsis/languages/English.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_ENGLISH} "Add/Reinstall components" +LangString alreadyInstalled ${LANG_ENGLISH} "Already Installed" +LangString alreadyInstalledLong ${LANG_ENGLISH} "${PRODUCTNAME} ${VERSION} is already installed. Select the operation you want to perform and click Next to continue." +LangString appRunning ${LANG_ENGLISH} "${PRODUCTNAME} is running! Please close it first then try again." +LangString appRunningOkKill ${LANG_ENGLISH} "${PRODUCTNAME} is running!$\nClick OK to kill it" +LangString chooseMaintenanceOption ${LANG_ENGLISH} "Choose the maintenance option to perform." +LangString choowHowToInstall ${LANG_ENGLISH} "Choose how you want to install ${PRODUCTNAME}." +LangString createDesktop ${LANG_ENGLISH} "Create desktop shortcut" +LangString dontUninstall ${LANG_ENGLISH} "Do not uninstall" +LangString dontUninstallDowngrade ${LANG_ENGLISH} "Do not uninstall (Downgrading without uninstall is disabled for this installer)" +LangString failedToKillApp ${LANG_ENGLISH} "Failed to kill ${PRODUCTNAME}. Please close it first then try again" +LangString installingWebview2 ${LANG_ENGLISH} "Installing WebView2..." +LangString newerVersionInstalled ${LANG_ENGLISH} "A newer version of ${PRODUCTNAME} is already installed! It is not recommended that you install an older version. If you really want to install this older version, it's better to uninstall the current version first. Select the operation you want to perform and click Next to continue." +LangString older ${LANG_ENGLISH} "older" +LangString olderOrUnknownVersionInstalled ${LANG_ENGLISH} "An $R4 version of ${PRODUCTNAME} is installed on your system. It's recommended that you uninstall the current version before installing. Select the operation you want to perform and click Next to continue." +LangString silentDowngrades ${LANG_ENGLISH} "Downgrades are disabled for this installer, can't proceed with the silent installer, please use the graphical interface installer instead.$\n" +LangString unableToUninstall ${LANG_ENGLISH} "Unable to uninstall!" +LangString uninstallApp ${LANG_ENGLISH} "Uninstall ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_ENGLISH} "Uninstall before installing" +LangString unknown ${LANG_ENGLISH} "unknown" +LangString webview2AbortError ${LANG_ENGLISH} "Failed to install WebView2! The app can't run without it. Try restarting the installer." +LangString webview2DownloadError ${LANG_ENGLISH} "Error: Downloading WebView2 Failed - $0" +LangString webview2DownloadSuccess ${LANG_ENGLISH} "WebView2 bootstrapper downloaded successfully" +LangString webview2Downloading ${LANG_ENGLISH} "Downloading WebView2 bootstrapper..." +LangString webview2InstallError ${LANG_ENGLISH} "Error: Installing WebView2 failed with exit code $1" +LangString webview2InstallSuccess ${LANG_ENGLISH} "WebView2 installed successfully" +LangString deleteAppData ${LANG_ENGLISH} "Delete the application data" diff --git a/crates/packager/src/nsis/languages/French.nsh b/crates/packager/src/nsis/languages/French.nsh new file mode 100644 index 00000000..4795a0b8 --- /dev/null +++ b/crates/packager/src/nsis/languages/French.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_FRENCH} "Ajouter/Réinstaller un composant." +LangString alreadyInstalled ${LANG_FRENCH} "Déja installé." +LangString alreadyInstalledLong ${LANG_FRENCH} "${PRODUCTNAME} ${VERSION} est déja installé. Sélectionnez l'opération que vous souhaitez effectuer, puis cliquez sur Suivant pour continuer." +LangString appRunning ${LANG_FRENCH} "${PRODUCTNAME} est en cours d'exécution. Veuillez fermer l'application avant de réessayer." +LangString appRunningOkKill ${LANG_FRENCH} "${PRODUCTNAME} est en cours d'exécution.$\nCliquez sur OK pour fermer l'application." +LangString chooseMaintenanceOption ${LANG_FRENCH} "Veuillez choisir l'option de maintenance à effectuer." +LangString choowHowToInstall ${LANG_FRENCH} "Veuillez choisir l'emplacement d'installation de ${PRODUCTNAME}." +LangString createDesktop ${LANG_FRENCH} "Créer un raccourci sur le bureau." +LangString dontUninstall ${LANG_FRENCH} "Ne pas désinstaller" +LangString dontUninstallDowngrade ${LANG_FRENCH} "Ne pas désinstaller (revenir à une ancienne version sans désinstallation est désactivé pour cet installateur)" +LangString failedToKillApp ${LANG_FRENCH} "La fermeture de ${PRODUCTNAME} a échoué. Veuillez fermer l'application et réessayer." +LangString installingWebview2 ${LANG_FRENCH} "Installation de WebView2..." +LangString newerVersionInstalled ${LANG_FRENCH} "Une version plus récente de ${PRODUCTNAME} est déja installée. Il n'est pas recommandé d'installer une ancienne version. Si vous souhaitez installer cette ancienne version, il est conseillé de désinstaller la version courante en premier. Veuillez sélectionner l'opération que vous souhaitez effectuer, puis cliquez sur Suivant pour continer." +LangString older ${LANG_FRENCH} "ancien" +LangString olderOrUnknownVersionInstalled ${LANG_FRENCH} "La version $R4 de ${PRODUCTNAME} est installée sur le système. Il est recommandé de désinstaller la version actuelle avant d'installer celle-ci. Sélectionnez l'opération que vous souhaitez effectuer, puis cliquez sur Suivant pour continuer." +LangString silentDowngrades ${LANG_FRENCH} "Revenir à une version antérieure est désactivé pour cet installateur. Impossible de continuer avec l'installation silencieuse, veuillez utiliser l'interface graphique à la place.$\n" +LangString unableToUninstall ${LANG_FRENCH} "Impossible de désinstaller le programme !" +LangString uninstallApp ${LANG_FRENCH} "Désinstaller ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_FRENCH} "Désinstaller avant d'installer" +LangString unknown ${LANG_FRENCH} "inconnu" +LangString webview2AbortError ${LANG_FRENCH} "L'installation de WebView2 a échoué ! L'application ne peut s'éxécuter sans WebView2. Veuillez essayer de redémarrer l'installation." +LangString webview2DownloadError ${LANG_FRENCH} "Erreur : le téléchargement de WebView2 a échoué - $0" +LangString webview2DownloadSuccess ${LANG_FRENCH} "Le composant WebView2 a été téléchargé avec succès !" +LangString webview2Downloading ${LANG_FRENCH} "Téléchargement du composant WebView2..." +LangString webview2InstallError ${LANG_FRENCH} "Erreur : l'installation de WebView2 a échoué avec le code d'erreur $1" +LangString webview2InstallSuccess ${LANG_FRENCH} "L'installation de WebView2 a réussi" +LangString deleteAppData ${LANG_FRENCH} "Supprimer les données de l'application" diff --git a/crates/packager/src/nsis/languages/Japanese.nsh b/crates/packager/src/nsis/languages/Japanese.nsh new file mode 100644 index 00000000..e404fb59 --- /dev/null +++ b/crates/packager/src/nsis/languages/Japanese.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_JAPANESE} "コンポーネントの追加・再インストール" +LangString alreadyInstalled ${LANG_JAPANESE} "既にインストールされています" +LangString alreadyInstalledLong ${LANG_JAPANESE} "${PRODUCTNAME} ${VERSION} は既にインストールされています。実行したい操作を選択し、「次へ」をクリックして続行します。" +LangString appRunning ${LANG_JAPANESE} "${PRODUCTNAME} は動作中です。動作中のプログラムを終了し、もう一度やり直してください。" +LangString appRunningOkKill ${LANG_JAPANESE} "${PRODUCTNAME} は動作中です。$\n「OK」を押すと動作中のプログラムを終了します。" +LangString chooseMaintenanceOption ${LANG_JAPANESE} "メンテナンスオプションを選択して実行します。" +LangString choowHowToInstall ${LANG_JAPANESE} "${PRODUCTNAME} のインストール方法を選択してください。" +LangString createDesktop ${LANG_JAPANESE} "デスクトップショートカットを作成する" +LangString dontUninstall ${LANG_JAPANESE} "アンインストールしない" +LangString dontUninstallDowngrade ${LANG_JAPANESE} "アンインストールしない (このインストーラーでは、アンインストールをせずにダウングレードすることはできません)" +LangString failedToKillApp ${LANG_JAPANESE} "${PRODUCTNAME} の終了に失敗しました。動作中のプログラムを終了し、もう一度やり直してください。" +LangString installingWebview2 ${LANG_JAPANESE} "WebView2 をインストール中です..." +LangString newerVersionInstalled ${LANG_JAPANESE} "既に新しいバージョンの ${PRODUCTNAME} がインストールされています。古いバージョンをインストールすることは推奨されません。どうしてもこの旧バージョンをインストールしたい場合は、先に現行バージョンをアンインストールしておく方がよいでしょう。実行したい操作を選択し、「次へ」をクリックして続行します。" +LangString older ${LANG_JAPANESE} "旧" +LangString olderOrUnknownVersionInstalled ${LANG_JAPANESE} "お使いのシステムには、 ${PRODUCTNAME} のバージョン $R4 がインストールされています。インストールする前に、現在のバージョンをアンインストールすることをお勧めします。実行したい操作を選択し、「次へ」をクリックして続行します。" +LangString silentDowngrades ${LANG_JAPANESE} "このインストーラーではダウングレードはできません。サイレントインストーラーを続行できないので、代わりにグラフィカルインターフェースインストーラーを使用してください。$\n" +LangString unableToUninstall ${LANG_JAPANESE} "アンインストールできません。" +LangString uninstallApp ${LANG_JAPANESE} "${PRODUCTNAME} をアンインストールする" +LangString uninstallBeforeInstalling ${LANG_JAPANESE} "インストールする前にアンインストールする" +LangString unknown ${LANG_JAPANESE} "不明" +LangString webview2AbortError ${LANG_JAPANESE} "WebView2 のインストールに失敗しました。 WebView2 がないとアプリは実行できません。インストーラーを再起動してください。" +LangString webview2DownloadError ${LANG_JAPANESE} "エラー: WebView2 のダウンロードに失敗しました - $0" +LangString webview2DownloadSuccess ${LANG_JAPANESE} "WebView2 ブートストラップ が正常にダウンロードされました" +LangString webview2Downloading ${LANG_JAPANESE} "WebView2 ブートストラップ をダウンロード中です..." +LangString webview2InstallError ${LANG_JAPANESE} "エラー: WebView2 のインストールは終了コード $1 で失敗しました。" +LangString webview2InstallSuccess ${LANG_JAPANESE} "WebView2 が正常にインストールされました" +LangString deleteAppData ${LANG_JAPANESE} "アプリケーションデータを削除する" diff --git a/crates/packager/src/nsis/languages/Korean.nsh b/crates/packager/src/nsis/languages/Korean.nsh new file mode 100644 index 00000000..401e0891 --- /dev/null +++ b/crates/packager/src/nsis/languages/Korean.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_KOREAN} "컴포넌트 추가 및 재설치" +LangString alreadyInstalled ${LANG_KOREAN} "이미 설치되어 있습니다" +LangString alreadyInstalledLong ${LANG_KOREAN} "${PRODUCTNAME} ${VERSION}이(가) 이미 설치되어 있습니다. 수행하고자 하는 작업을 선택하고 '다음'을 클릭하여 계속합니다." +LangString appRunning ${LANG_KOREAN} "${PRODUCTNAME}이(가) 실행 중입니다! 먼저 닫은 후 다시 시도하세요." +LangString appRunningOkKill ${LANG_KOREAN} "${PRODUCTNAME}이(가) 실행 중입니다!$\n'OK'를 누르면 실행 중인 프로그램을 종료합니다." +LangString chooseMaintenanceOption ${LANG_KOREAN} "수행하려는 관리 옵션을 선택합니다." +LangString choowHowToInstall ${LANG_KOREAN} "${PRODUCTNAME}의 설치 방법을 선택하세요.." +LangString createDesktop ${LANG_KOREAN} "바탕화면 바로가기 만들기" +LangString dontUninstall ${LANG_KOREAN} "제거하지 않기" +LangString dontUninstallDowngrade ${LANG_KOREAN} "제거하지 않기 (이 설치 프로그램에서는 제거하지 않고 다운그레이드할 수 없습니다.)" +LangString failedToKillApp ${LANG_KOREAN} "${PRODUCTNAME}을(를) 종료하지 못했습니다. 먼저 닫은 후 다시 시도하세요." +LangString installingWebview2 ${LANG_KOREAN} "WebView2를 설치하는 중입니다..." +LangString newerVersionInstalled ${LANG_KOREAN} "${PRODUCTNAME}의 최신 버전이 이미 설치되어 있습니다! 이전 버전을 설치하지 않는 것이 좋습니다. 이 이전 버전을 꼭 설치하려면 먼저 현재 버전을 제거하는 것이 좋습니다. 수행하려는 작업을 선택하고 '다음'을 클릭하여 계속합니다." +LangString older ${LANG_KOREAN} "구" +LangString olderOrUnknownVersionInstalled ${LANG_KOREAN} "시스템에 ${PRODUCTNAME}의 $R4 버전이 설치되어 있습니다. 설치하기 전에 현재 버전을 제거하는 것이 좋습니다. 수행하려는 작업을 선택하고 다음을 클릭하여 계속합니다." +LangString silentDowngrades ${LANG_KOREAN} "이 설치 프로그램에서는 다운그레이드가 비활성화되어 자동 설치 프로그램을 진행할 수 없습니다. 대신 그래픽 인터페이스 설치 프로그램을 사용하세요.$\n" +LangString unableToUninstall ${LANG_KOREAN} "제거할 수 없습니다!" +LangString uninstallApp ${LANG_KOREAN} "${PRODUCTNAME} 제거하기" +LangString uninstallBeforeInstalling ${LANG_KOREAN} "설치하기 전에 제거하기" +LangString unknown ${LANG_KOREAN} "알 수 없음" +LangString webview2AbortError ${LANG_KOREAN} "WebView2를 설치하지 못했습니다! WebView2가 없으면 앱을 실행할 수 없습니다. 인스톨러를 다시 시작해보세요." +LangString webview2DownloadError ${LANG_KOREAN} "오류: WebView2 다운로드를 실패하였습니다. - $0" +LangString webview2DownloadSuccess ${LANG_KOREAN} "WebView2 부트스트래퍼가 성공적으로 다운로드되었습니다." +LangString webview2Downloading ${LANG_KOREAN} "WebView2 부트스트래퍼 다운로드 중..." +LangString webview2InstallError ${LANG_KOREAN} "오류: 종료 코드 $1로 WebView2를 설치하지 못했습니다." +LangString webview2InstallSuccess ${LANG_KOREAN} "WebView2가 성공적으로 설치되었습니다." +LangString deleteAppData ${LANG_KOREAN} "애플리케이션 데이터 삭제하기" diff --git a/crates/packager/src/nsis/languages/Persian.nsh b/crates/packager/src/nsis/languages/Persian.nsh new file mode 100644 index 00000000..5e509f90 --- /dev/null +++ b/crates/packager/src/nsis/languages/Persian.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_PERSIAN} "اضافه کردن/نصب مجدد کامپونتت" +LangString alreadyInstalled ${LANG_PERSIAN} "قبلا نصب شده است" +LangString alreadyInstalledLong ${LANG_PERSIAN} "${PRODUCTNAME} ${VERSION} قبلا نصب شده است. عملیات مدنظر را انتخاب کنید و بروی بعدی کلیک کنید." +LangString appRunning ${LANG_PERSIAN} "${PRODUCTNAME} در حال اجر می باشد ! لطفا اول الان را ببندید و دوباره تلاش کنید" +LangString appRunningOkKill ${LANG_PERSIAN} "${PRODUCTNAME} در حال اجرا می باشد!$\nبرای از بین بردن اوکی را انتخاب کنید" +LangString chooseMaintenanceOption ${LANG_PERSIAN} "عملیات نگهداری مدنظر را برای اجرا انتخاب کنید" +LangString choowHowToInstall ${LANG_PERSIAN} "نحوه نصب ${PRODUCTNAME} را انتخاب کنید" +LangString createDesktop ${LANG_PERSIAN} "ایجاد میانبر دسکتاپ" +LangString dontUninstall ${LANG_PERSIAN} "حذف نکنید" +LangString dontUninstallDowngrade ${LANG_PERSIAN} "حذف نکنید (تنزل ورژن بدون حذف برای نصب کننده غیرفعال است)" +LangString failedToKillApp ${LANG_PERSIAN} "${PRODUCTNAME} قابل کشته شدن نیست. اول آن را ببندید و دوباره تلاش کنید" +LangString installingWebview2 ${LANG_PERSIAN} "در حال نصب WebView2 ..." +LangString newerVersionInstalled ${LANG_PERSIAN} "ورژن جدید ${PRODUCTNAME} قبلا نصب شده است! نصب ورژن قدیمی تر به هیچ عنوان پیشنهاد نمی شود. اگر از این بابت اطمینان دارید , بهتر است ورژن فعلی را حذف کنید. عملیات مدنظر را انتخاب کنید و بروی بعدی کلیک کنید." +LangString older ${LANG_PERSIAN} "قدیمی تر" +LangString olderOrUnknownVersionInstalled ${LANG_PERSIAN} "ورژن $R4 ${PRODUCTNAME} قبلا بروی سیستم شما نصب شده است. ر. عملیات مدنظر را انتخاب کنید و بروی بعدی کلیک کنید." +LangString silentDowngrades ${LANG_PERSIAN} "تنزل ورژن بدون حذف غیرفعال می باشد, عملیات نصب خاموش غیرقابل انجام است , از رابط گرافیکی برای نصب استفاده کنید.$\n" +LangString unableToUninstall ${LANG_PERSIAN} "قابل نصب نیست!" +LangString uninstallApp ${LANG_PERSIAN} "حذف ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_PERSIAN} "قبل از نصب , حذف کنید" +LangString unknown ${LANG_PERSIAN} "ناشناس" +LangString webview2AbortError ${LANG_PERSIAN} "نصب WebView2 شکست خورد! اپ بدون ان کار نمی کند. نصب کننده را دوباره نصب کنید" +LangString webview2DownloadError ${LANG_PERSIAN} "ارور: دانلود WebView2 شکست خورد - $0" +LangString webview2DownloadSuccess ${LANG_PERSIAN} "WebView2 بوت استرپر با موفقیت نصب شد" +LangString webview2Downloading ${LANG_PERSIAN} "دانلود بوت استرپر WebView2..." +LangString webview2InstallError ${LANG_PERSIAN} "ارور: نصب WebView2 با کد $1 شکست خورد" +LangString webview2InstallSuccess ${LANG_PERSIAN} "WebView2 با موفقیت نصب شد" +LangString deleteAppData ${LANG_PERSIAN} "حذف دیتا های اپلیکیشن" diff --git a/crates/packager/src/nsis/languages/PortugueseBR.nsh b/crates/packager/src/nsis/languages/PortugueseBR.nsh new file mode 100644 index 00000000..3a9f8742 --- /dev/null +++ b/crates/packager/src/nsis/languages/PortugueseBR.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_PORTUGUESEBR} "Adicionar/Reinstalar componentes" +LangString alreadyInstalled ${LANG_PORTUGUESEBR} "Já instalado" +LangString alreadyInstalledLong ${LANG_PORTUGUESEBR} "${PRODUCTNAME} ${VERSION} já está instalado. Selecione a operação que deseja realizar e clique Próximo para continuar." +LangString appRunning ${LANG_PORTUGUESEBR} "${PRODUCTNAME} está aberto! Por favor feche a janela dele e tente novamente." +LangString appRunningOkKill ${LANG_PORTUGUESEBR} "${PRODUCTNAME} está aberto!$\nClique OK para fechar ele." +LangString chooseMaintenanceOption ${LANG_PORTUGUESEBR} "Escolha a opção de manutenção a realizar." +LangString choowHowToInstall ${LANG_PORTUGUESEBR} "Escolha como deseja instalar ${PRODUCTNAME}." +LangString createDesktop ${LANG_PORTUGUESEBR} "Criar atalho na área de trabalho" +LangString dontUninstall ${LANG_PORTUGUESEBR} "Não desinstalar" +LangString dontUninstallDowngrade ${LANG_PORTUGUESEBR} "Não desinstalar (Instalar versão anterior sem desinstalar está desabilitado nesse instalador)" +LangString failedToKillApp ${LANG_PORTUGUESEBR} "Falha ao fechar ${PRODUCTNAME}. Por favor feche a janela dele primeiro e tente novamente" +LangString installingWebview2 ${LANG_PORTUGUESEBR} "Instalando WebView2..." +LangString newerVersionInstalled ${LANG_PORTUGUESEBR} "Uma nova versão do ${PRODUCTNAME} já está instalado! Não é recomendado instalar uma versão anterior. Se realmente deseja instalar essa versão antiga, é recomendado desinstalar a versão atual primeirl. Selecione a operação que deseja executare clique Próximo para continuar." +LangString older ${LANG_PORTUGUESEBR} "mais antiga" +LangString olderOrUnknownVersionInstalled ${LANG_PORTUGUESEBR} "Uma versão $R4 do ${PRODUCTNAME} está instalada no seu sistema. É recomendado desinstalar a versão atual antes de prosseguir com a instalação. Selecione a operação que deseja executare clique Próximo para continuar." +LangString silentDowngrades ${LANG_PORTUGUESEBR} "Instalar versão anterior está desabilitado nesse instalador, não foi possível proceder com a instalação silenciosa, por favor use a interface gráfica.$\n" +LangString unableToUninstall ${LANG_PORTUGUESEBR} "Não foi possível instalar!" +LangString uninstallApp ${LANG_PORTUGUESEBR} "Desinstalar ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_PORTUGUESEBR} "Desinstalar antes de instalar" +LangString unknown ${LANG_PORTUGUESEBR} "desconhecida" +LangString webview2AbortError ${LANG_PORTUGUESEBR} "Falha ao instalar WebView2! O programa não pode executar sem ele. Tente reiniciar o instalador." +LangString webview2DownloadError ${LANG_PORTUGUESEBR} "Erro: Falha ao baixar WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_PORTUGUESEBR} "Bootstrapper do WebView2 baixado com sucesso" +LangString webview2Downloading ${LANG_PORTUGUESEBR} "Baixando o Bootstrapper do WebView2..." +LangString webview2InstallError ${LANG_PORTUGUESEBR} "Erro: Instalação do Webview2 falhou com código $1" +LangString webview2InstallSuccess ${LANG_PORTUGUESEBR} "WebView2 instalado com sucesso" +LangString deleteAppData ${LANG_PORTUGUESEBR} "Remover dados do programa" diff --git a/crates/packager/src/nsis/languages/SimpChinese.nsh b/crates/packager/src/nsis/languages/SimpChinese.nsh new file mode 100644 index 00000000..e4308b41 --- /dev/null +++ b/crates/packager/src/nsis/languages/SimpChinese.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_SIMPCHINESE} "添加/重新安装组件" +LangString alreadyInstalled ${LANG_SIMPCHINESE} "已安装" +LangString alreadyInstalledLong ${LANG_SIMPCHINESE} "${PRODUCTNAME} ${VERSION} 已经安装了。选择你想要执行的操作后点击下一步以继续。" +LangString appRunning ${LANG_SIMPCHINESE} "${PRODUCTNAME} 正在运行!请关闭后再试。" +LangString appRunningOkKill ${LANG_SIMPCHINESE} "${PRODUCTNAME} 正在运行!$\n点击确定以终止运行。" +LangString chooseMaintenanceOption ${LANG_SIMPCHINESE} "选择要执行的操作。" +LangString choowHowToInstall ${LANG_SIMPCHINESE} "选择你想要安装 ${PRODUCTNAME} 的方式。" +LangString createDesktop ${LANG_SIMPCHINESE} "创建桌面快捷方式" +LangString dontUninstall ${LANG_SIMPCHINESE} "不要卸载" +LangString dontUninstallDowngrade ${LANG_SIMPCHINESE} "不要卸载(无需卸载的降级在此安装程序上已禁用)" +LangString failedToKillApp ${LANG_SIMPCHINESE} "无法终止 ${PRODUCTNAME}。请关闭后再试。" +LangString installingWebview2 ${LANG_SIMPCHINESE} "正在安装 WebView2..." +LangString newerVersionInstalled ${LANG_SIMPCHINESE} "有一个更新的 ${PRODUCTNAME} 已经安装了!不推荐你安装旧的版本。如果你真的想要安装这个旧的版本,如果你真的想要安装这个版本,推荐先卸载当前版本。选择你想要执行的操作后点击下一步以继续。" +LangString older ${LANG_SIMPCHINESE} "旧的" +LangString olderOrUnknownVersionInstalled ${LANG_SIMPCHINESE} "系统中已存在版本为 $R4 的 ${PRODUCTNAME}。推荐先卸载当前版本后再进行安装。选择你想要执行的操作后点击下一步以继续。" +LangString silentDowngrades ${LANG_SIMPCHINESE} "降级操作在此安装程序上已禁用,无法进行安静安装,请使用图形操作界面。$\n" +LangString unableToUninstall ${LANG_SIMPCHINESE} "无法卸载!" +LangString uninstallApp ${LANG_SIMPCHINESE} "卸载 ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_SIMPCHINESE} "安装前卸载" +LangString unknown ${LANG_SIMPCHINESE} "未知" +LangString webview2AbortError ${LANG_SIMPCHINESE} "无法安装 WebView2!没有它,此应用就无法运行。尝试重启安装程序。" +LangString webview2DownloadError ${LANG_SIMPCHINESE} "错误:无法下载 WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_SIMPCHINESE} "WebView2 安装程序下载成功" +LangString webview2Downloading ${LANG_SIMPCHINESE} "正在下载 WebView2 安装程序..." +LangString webview2InstallError ${LANG_SIMPCHINESE} "错误:安装 WebView2 时失败,错误代码:$1" +LangString webview2InstallSuccess ${LANG_SIMPCHINESE} "成功安装 WebView2" +LangString deleteAppData ${LANG_SIMPCHINESE} "删除应用程序数据" diff --git a/crates/packager/src/nsis/languages/Spanish.nsh b/crates/packager/src/nsis/languages/Spanish.nsh new file mode 100644 index 00000000..a676fbc7 --- /dev/null +++ b/crates/packager/src/nsis/languages/Spanish.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_SPANISH} "Añadir o reinstalar componentes" +LangString alreadyInstalled ${LANG_SPANISH} "Ya está instalado" +LangString alreadyInstalledLong ${LANG_SPANISH} "${PRODUCTNAME} ${VERSION} ya está instalado. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString appRunning ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto! Por favor ciérrelo e intente de nuevo." +LangString appRunningOkKill ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto!$\nPulse Aceptar para cerrarlo." +LangString chooseMaintenanceOption ${LANG_SPANISH} "Elija la operación de mantenimiento que desee realizar." +LangString choowHowToInstall ${LANG_SPANISH} "Elija cómo desea instalar ${PRODUCTNAME}." +LangString createDesktop ${LANG_SPANISH} "Crear acceso directo en el escritorio" +LangString dontUninstall ${LANG_SPANISH} "No desinstalar" +LangString dontUninstallDowngrade ${LANG_SPANISH} "No desinstalar (Disminuir la versión sin desinstalar está deshabilitado para este instalador)" +LangString failedToKillApp ${LANG_SPANISH} "No se ha podido cerrar ${PRODUCTNAME}. Por favor ciérrelo e intente de nuevo." +LangString installingWebview2 ${LANG_SPANISH} "Instalando WebView2..." +LangString newerVersionInstalled ${LANG_SPANISH} "Ya está instalada una versión más reciente de ${PRODUCTNAME}. No se recomienda que instale una versión anterior. Si realmente desea instalar esta versión anterior, es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString older ${LANG_SPANISH} "anterior" +LangString olderOrUnknownVersionInstalled ${LANG_SPANISH} "Una versión $R4 de ${PRODUCTNAME} está instalada en su sistema. Es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString silentDowngrades ${LANG_SPANISH} "Disminuir la versión está deshabilitado para este instalador. No se puede continuar con el instalador silencioso, por favor use el instalador de interfaz gráfica.$\n" +LangString unableToUninstall ${LANG_SPANISH} "No se ha podido desinstalar." +LangString uninstallApp ${LANG_SPANISH} "Desinstalar ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_SPANISH} "Desinstalar antes de instalar" +LangString unknown ${LANG_SPANISH} "desconocida" +LangString webview2AbortError ${LANG_SPANISH} "No se ha podido instalar WebView2. Intente reiniciar el instalador." +LangString webview2DownloadError ${LANG_SPANISH} "Error: No se ha podido descargar WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_SPANISH} "El bootstrapper de WebView2 fue descargado con éxito." +LangString webview2Downloading ${LANG_SPANISH} "Descargando el bootstrapper de WebView2..." +LangString webview2InstallError ${LANG_SPANISH} "Error: La instalación de WebView2 falló con el código $1." +LangString webview2InstallSuccess ${LANG_SPANISH} "WebView2 fue instalado con éxito." +LangString deleteAppData ${LANG_SPANISH} "Eliminar los datos de aplicación" diff --git a/crates/packager/src/nsis/languages/SpanishInternational.nsh b/crates/packager/src/nsis/languages/SpanishInternational.nsh new file mode 100644 index 00000000..a676fbc7 --- /dev/null +++ b/crates/packager/src/nsis/languages/SpanishInternational.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_SPANISH} "Añadir o reinstalar componentes" +LangString alreadyInstalled ${LANG_SPANISH} "Ya está instalado" +LangString alreadyInstalledLong ${LANG_SPANISH} "${PRODUCTNAME} ${VERSION} ya está instalado. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString appRunning ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto! Por favor ciérrelo e intente de nuevo." +LangString appRunningOkKill ${LANG_SPANISH} "¡${PRODUCTNAME} está abierto!$\nPulse Aceptar para cerrarlo." +LangString chooseMaintenanceOption ${LANG_SPANISH} "Elija la operación de mantenimiento que desee realizar." +LangString choowHowToInstall ${LANG_SPANISH} "Elija cómo desea instalar ${PRODUCTNAME}." +LangString createDesktop ${LANG_SPANISH} "Crear acceso directo en el escritorio" +LangString dontUninstall ${LANG_SPANISH} "No desinstalar" +LangString dontUninstallDowngrade ${LANG_SPANISH} "No desinstalar (Disminuir la versión sin desinstalar está deshabilitado para este instalador)" +LangString failedToKillApp ${LANG_SPANISH} "No se ha podido cerrar ${PRODUCTNAME}. Por favor ciérrelo e intente de nuevo." +LangString installingWebview2 ${LANG_SPANISH} "Instalando WebView2..." +LangString newerVersionInstalled ${LANG_SPANISH} "Ya está instalada una versión más reciente de ${PRODUCTNAME}. No se recomienda que instale una versión anterior. Si realmente desea instalar esta versión anterior, es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString older ${LANG_SPANISH} "anterior" +LangString olderOrUnknownVersionInstalled ${LANG_SPANISH} "Una versión $R4 de ${PRODUCTNAME} está instalada en su sistema. Es recomendable desinstalar la versión actual antes de continuar. Seleccione la operación que desee realizar y pulse Siguiente para continuar." +LangString silentDowngrades ${LANG_SPANISH} "Disminuir la versión está deshabilitado para este instalador. No se puede continuar con el instalador silencioso, por favor use el instalador de interfaz gráfica.$\n" +LangString unableToUninstall ${LANG_SPANISH} "No se ha podido desinstalar." +LangString uninstallApp ${LANG_SPANISH} "Desinstalar ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_SPANISH} "Desinstalar antes de instalar" +LangString unknown ${LANG_SPANISH} "desconocida" +LangString webview2AbortError ${LANG_SPANISH} "No se ha podido instalar WebView2. Intente reiniciar el instalador." +LangString webview2DownloadError ${LANG_SPANISH} "Error: No se ha podido descargar WebView2 - $0" +LangString webview2DownloadSuccess ${LANG_SPANISH} "El bootstrapper de WebView2 fue descargado con éxito." +LangString webview2Downloading ${LANG_SPANISH} "Descargando el bootstrapper de WebView2..." +LangString webview2InstallError ${LANG_SPANISH} "Error: La instalación de WebView2 falló con el código $1." +LangString webview2InstallSuccess ${LANG_SPANISH} "WebView2 fue instalado con éxito." +LangString deleteAppData ${LANG_SPANISH} "Eliminar los datos de aplicación" diff --git a/crates/packager/src/nsis/languages/Swedish.nsh b/crates/packager/src/nsis/languages/Swedish.nsh new file mode 100644 index 00000000..f1c4ecec --- /dev/null +++ b/crates/packager/src/nsis/languages/Swedish.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_SWEDISH} "Lägg till/Installera om komponenter" +LangString alreadyInstalled ${LANG_SWEDISH}} "Redan installerad" +LangString alreadyInstalledLong ${LANG_SWEDISH}} "${PRODUCTNAME} ${VERSION} är redan installerad. Välj åtgärd och klicka på Nästa för att fortsätta." +LangString appRunning ${LANG_SWEDISH} "${PRODUCTNAME} körs! Stäng det först och försök igen." +LangString appRunningOkKill ${LANG_SWEDISH} "${PRODUCTNAME} körs!$\nKlicka på OK för att avsluta det." +LangString chooseMaintenanceOption ${LANG_SWEDISH} "Välj underhållsåtgärd." +LangString choowHowToInstall ${LANG_SWEDISH} "Välj hur du vill installera ${PRODUCTNAME}." +LangString createDesktop ${LANG_SWEDISH} "Skapa genväg på skrivbordet" +LangString dontUninstall ${LANG_SWEDISH} "Avinstallera inte" +LangString dontUninstallDowngrade ${LANG_SWEDISH} "Avinstallera inte (nedgradering utan avinstallation är inaktiverad för den här installationsprogrammet)" +LangString failedToKillApp ${LANG_SWEDISH} "Kunde inte avsluta ${PRODUCTNAME}. Stäng det först och försök igen." +LangString installingWebview2 ${LANG_SWEDISH} "Installerar WebView2..." +LangString newerVersionInstalled ${LANG_SWEDISH} "En nyare version av ${PRODUCTNAME} är redan installerad! Det rekommenderas inte att installera en äldre version. Om du verkligen vill installera denna äldre version är det bättre att avinstallera den nuvarande versionen först. Välj åtgärd och klicka på Nästa för att fortsätta." +LangString older ${LANG_SWEDISH} "äldre" +LangString olderOrUnknownVersionInstalled ${LANG_SWEDISH} "En $R4-version av ${PRODUCTNAME} är installerad på ditt system. Det rekommenderas att du avinstallerar den nuvarande versionen innan du installerar. Välj åtgärd och klicka på Nästa för att fortsätta." +LangString silentDowngrades ${LANG_SWEDISH} "Nedgraderingar är inaktiverade för den här installationsprogrammet. Kan inte fortsätta med installationsprogrammet. Använd det grafiska installationsprogrammet istället.$\n" +LangString unableToUninstall ${LANG_SWEDISH} "Kan inte avinstallera!" +LangString uninstallApp ${LANG_SWEDISH} "Avinstallera ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_SWEDISH} "Avinstallera innan installation" +LangString unknown ${LANG_SWEDISH} "okänd" +LangString webview2AbortError ${LANG_SWEDISH} "Misslyckades med att installera WebView2! Appen kan inte köras utan det. Försök starta om installationsprogrammet." +LangString webview2DownloadError ${LANG_SWEDISH} "Fel: Nedladdning av WebView2 misslyckades - $0" +LangString webview2DownloadSuccess ${LANG_SWEDISH} "WebView2 bootstrapper nedladdad framgångsrikt" +LangString webview2Downloading ${LANG_SWEDISH} "Laddar ner WebView2 bootstrapper..." +LangString webview2InstallError ${LANG_SWEDISH} "Fel: Installation av WebView2 misslyckades med felkod $1" +LangString webview2InstallSuccess ${LANG_SWEDISH} "WebView2 installerades framgångsrikt" +LangString deleteAppData ${LANG_SWEDISH} "Ta bort applikationsdata" diff --git a/crates/packager/src/nsis/languages/TradChinese.nsh b/crates/packager/src/nsis/languages/TradChinese.nsh new file mode 100644 index 00000000..c80c3cd3 --- /dev/null +++ b/crates/packager/src/nsis/languages/TradChinese.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_TRADCHINESE} "增加或重新安裝元件" +LangString alreadyInstalled ${LANG_TRADCHINESE} "已安裝" +LangString alreadyInstalledLong ${LANG_TRADCHINESE} "${PRODUCTNAME} ${VERSION} 已經安裝了。選擇你想要進行的操作並且點選下一步。" +LangString appRunning ${LANG_TRADCHINESE} "${PRODUCTNAME} 正在執行中!請先關閉再進行嘗試。" +LangString appRunningOkKill ${LANG_TRADCHINESE} "${PRODUCTNAME} 正在執行中!點選確定後終止。" +LangString chooseMaintenanceOption ${LANG_TRADCHINESE} "請選擇你要進行的維護選項。" +LangString choowHowToInstall ${LANG_TRADCHINESE} "選擇你要如何安裝 ${PRODUCTNAME}。" +LangString createDesktop ${LANG_TRADCHINESE} "建立桌面捷徑" +LangString dontUninstall ${LANG_TRADCHINESE} "請勿解除安裝" +LangString dontUninstallDowngrade ${LANG_TRADCHINESE} "請勿解除安裝(本安裝程式不允許未解除安裝就進行版本降低的操作)" +LangString failedToKillApp ${LANG_TRADCHINESE} "無法終止 ${PRODUCTNAME}。請先關閉再進行嘗試。" +LangString installingWebview2 ${LANG_TRADCHINESE} "WebView2 安裝中..." +LangString newerVersionInstalled ${LANG_TRADCHINESE} "已安裝更新版本的 ${PRODUCTNAME}!不建議安裝舊版。如果真的想要安裝舊版的話,最好先解除安裝現在的版本。選擇你想要進行的操作後再進行下一步。" +LangString older ${LANG_TRADCHINESE} "舊版" +LangString olderOrUnknownVersionInstalled ${LANG_TRADCHINESE} "你的系統已經安裝 ${PRODUCTNAME} 的 $R4 版本。建議你先解除安裝現在的版本後再進行安裝。選擇你想要進行的操作後再進行下一步。" +LangString silentDowngrades ${LANG_TRADCHINESE} "本安裝程式不允許未解除安裝就進行版本降低的操作,無法繼續無聲安裝,請改用圖形化介面安裝。$\n" +LangString unableToUninstall ${LANG_TRADCHINESE} "無法解除安裝!" +LangString uninstallApp ${LANG_TRADCHINESE} "解除安裝 ${PRODUCTNAME}" +LangString uninstallBeforeInstalling ${LANG_TRADCHINESE} "安裝前先解除安裝" +LangString unknown ${LANG_TRADCHINESE} "未知" +LangString webview2AbortError ${LANG_TRADCHINESE} "無法安裝 WebView2!這個應用程式需要安裝 WebView2 才能執行。請重新啟動安裝程式。" +LangString webview2DownloadError ${LANG_TRADCHINESE} "錯誤:WebView2 下載失敗 - $0" +LangString webview2DownloadSuccess ${LANG_TRADCHINESE} "WebView2 啟動載入器下載成功" +LangString webview2Downloading ${LANG_TRADCHINESE} "正在下載 WebView2 啟動載入器..." +LangString webview2InstallError ${LANG_TRADCHINESE} "錯誤:WebView2 安裝失敗,錯誤碼 $1" +LangString webview2InstallSuccess ${LANG_TRADCHINESE} "WebView2 安裝成功" +LangString deleteAppData ${LANG_TRADCHINESE} "刪除應用程式數據" diff --git a/crates/packager/src/nsis/languages/Turkish.nsh b/crates/packager/src/nsis/languages/Turkish.nsh new file mode 100644 index 00000000..c47665de --- /dev/null +++ b/crates/packager/src/nsis/languages/Turkish.nsh @@ -0,0 +1,27 @@ +LangString addOrReinstall ${LANG_TURKISH} "Bileşen Ekle/Yeniden Yükle" +LangString alreadyInstalled ${LANG_TURKISH} "Daha Önceden Yüklenmiş" +LangString alreadyInstalledLong ${LANG_TURKISH} "${PRODUCTNAME} ${VERSION} daha önceden yüklenmiş. Gerçekleştirmek istediğiniz işlemi seçin ve devam etmek için İleri'ye tıklayın." +LangString appRunning ${LANG_TURKISH} "${PRODUCTNAME} çalışır durumda! Lütfen önce uygulamayı kapatın ve sonra tekrar deneyin." +LangString appRunningOkKill ${LANG_TURKISH} "${PRODUCTNAME} çalışır durumda!$\nUygulamayı sonlandırmak için Tamam'a tıklayın." +LangString chooseMaintenanceOption ${LANG_TURKISH} "Gerçekleştirmek istediğiniz bakım seçeneğini belirleyin." +LangString choowHowToInstall ${LANG_TURKISH} "${PRODUCTNAME} uygulamasını nasıl yüklemek istediğinizi seçin." +LangString createDesktop ${LANG_TURKISH} "Masaüstü kısayolu oluştur" +LangString dontUninstall ${LANG_TURKISH} "Kaldırma işlemini gerçekleştirme" +LangString dontUninstallDowngrade ${LANG_TURKISH} "Kaldırma işlemini gerçekleştirme (Kaldırma işlemi yapmadan sürüm düşürme bu yükleyici için devre dışı bırakılmıştır)" +LangString failedToKillApp ${LANG_TURKISH} "${PRODUCTNAME} sonlandırılamadı. Lütfen önce kapatın sonra tekrar deneyin." +LangString installingWebview2 ${LANG_TURKISH} "WebView2 yükleniyor..." +LangString newerVersionInstalled ${LANG_TURKISH} "${PRODUCTNAME} uygulamasının daha yeni bir sürümü zaten yüklü! Daha eski bir sürümü yüklemeniz önerilmez. Bu eski sürümü gerçekten yüklemek istiyorsanız, önce mevcut sürümü kaldırmanız daha uygundur. Gerçekleştirmek istediğiniz işlemi seçin ve devam etmek için İleri'ye tıklayın." +LangString older ${LANG_TURKISH} "daha eski" +LangString olderOrUnknownVersionInstalled ${LANG_TURKISH} "Sisteminizde ${PRODUCTNAME} uygulamasının $R4 sürümü yüklü. Yükleme işleminden önce mevcut sürümü kaldırmanız önerilir. Gerçekleştirmek istediğiniz işlemi seçin ve devam etmek için İleri'ye tıklayın." +LangString silentDowngrades ${LANG_TURKISH} "Bu yükleyici için sürüm düşürme işlemleri devre dışı bırakıldı, sessiz yükleyici ile devam edilemiyor, lütfen bunun yerine grafik arayüz yükleyicisini kullanın.$\n" +LangString unableToUninstall ${LANG_TURKISH} "Kaldırma işlemi gerçekleştirilemiyor!" +LangString uninstallApp ${LANG_TURKISH} "${PRODUCTNAME}'i kaldır" +LangString uninstallBeforeInstalling ${LANG_TURKISH} "Yükleme yapmadan önce kaldırın" +LangString unknown ${LANG_TURKISH} "bilinmeyen" +LangString webview2AbortError ${LANG_TURKISH} "WebView2 yüklenemedi! Uygulama bu bileşen olmadan çalışamaz. Yükleyiciyi yeniden başlatmayı deneyin." +LangString webview2DownloadError ${LANG_TURKISH} "Hata: WebView2 İndirmesi Başarısız - $0" +LangString webview2DownloadSuccess ${LANG_TURKISH} "WebView2 önyükleyicisi başarıyla indirildi" +LangString webview2Downloading ${LANG_TURKISH} "WebView2 önyükleyicisi indiriliyor..." +LangString webview2InstallError ${LANG_TURKISH} "Hata: WebView2 yüklemesi $1 hata koduyla başarısız oldu." +LangString webview2InstallSuccess ${LANG_TURKISH} "WebView2 başarıyla yüklendi" +LangString deleteAppData ${LANG_TURKISH} "Uygulama verilerini sil" diff --git a/crates/packager/src/nsis/mod.rs b/crates/packager/src/nsis/mod.rs index b379719b..05821962 100644 --- a/crates/packager/src/nsis/mod.rs +++ b/crates/packager/src/nsis/mod.rs @@ -1,8 +1,523 @@ -use std::path::PathBuf; +use std::{ + collections::{BTreeMap, HashMap}, + path::{Path, PathBuf}, + process::Command, +}; -use crate::config::Config; +use handlebars::{to_json, Handlebars}; -pub fn package(_config: &Config) -> crate::Result> { - log::error!("`nsis` format is not implemented yet!"); - std::process::exit(1); +use crate::{ + config::{Config, ConfigExt, ConfigExtInternal, LogLevel, NSISInstallerMode}, + sign::ConfigSignExt, + util::{self, download, download_and_verify, extract_zip, HashAlgorithm}, +}; + +// URLS for the NSIS toolchain. +#[cfg(target_os = "windows")] +const NSIS_URL: &str = + "https://github.com/tauri-apps/binary-releases/releases/download/nsis-3.9/nsis-3.09.zip"; +#[cfg(target_os = "windows")] +const NSIS_SHA1: &str = "586855a743a6e0ade203d8758af303a48ee0716b"; +const NSIS_APPLICATIONID_URL: &str = "https://github.com/tauri-apps/binary-releases/releases/download/nsis-plugins-v0/NSIS-ApplicationID.zip"; +const NSIS_TAURI_UTILS: &str = + "https://github.com/tauri-apps/nsis-tauri-utils/releases/download/nsis_tauri_utils-v0.2.1/nsis_tauri_utils.dll"; +const NSIS_TAURI_UTILS_SHA1: &str = "53A7CFAEB6A4A9653D6D5FBFF02A3C3B8720130A"; + +#[cfg(target_os = "windows")] +const NSIS_REQUIRED_FILES: &[&str] = &[ + "makensis.exe", + "Bin/makensis.exe", + "Stubs/lzma-x86-unicode", + "Stubs/lzma_solid-x86-unicode", + "Plugins/x86-unicode/ApplicationID.dll", + "Plugins/x86-unicode/nsis_tauri_utils.dll", + "Include/MUI2.nsh", + "Include/FileFunc.nsh", + "Include/x64.nsh", + "Include/nsDialogs.nsh", + "Include/WinMessages.nsh", +]; +#[cfg(not(target_os = "windows"))] +const NSIS_REQUIRED_FILES: &[&str] = &[ + "Plugins/x86-unicode/ApplicationID.dll", + "Plugins/x86-unicode/nsis_tauri_utils.dll", +]; + +pub fn package(config: &Config) -> crate::Result> { + let packager_tools_path = dirs::cache_dir().unwrap().join("cargo-packager"); + let nsis_toolset_path = packager_tools_path.join("NSIS"); + + if !nsis_toolset_path.exists() { + get_and_extract_nsis(&nsis_toolset_path, &packager_tools_path)?; + } else if NSIS_REQUIRED_FILES + .iter() + .any(|p| !nsis_toolset_path.join(p).exists()) + { + log::warn!("NSIS directory is missing some files. Recreating it."); + std::fs::remove_dir_all(&nsis_toolset_path)?; + get_and_extract_nsis(&nsis_toolset_path, &packager_tools_path)?; + } + + build_nsis_app_installer(config, &nsis_toolset_path, &packager_tools_path) +} + +fn get_and_extract_nsis( + nsis_toolset_path: &Path, + _packager_tools_path: &Path, +) -> crate::Result<()> { + #[cfg(target_os = "windows")] + { + let data = download_and_verify("nsis-3.09.zip", NSIS_URL, NSIS_SHA1, HashAlgorithm::Sha1)?; + log::info!(action = "Extracting"; "nsis-3.09.zip"); + extract_zip(&data, _packager_tools_path)?; + std::fs::rename(_packager_tools_path.join("nsis-3.09"), nsis_toolset_path)?; + } + + let nsis_plugins = nsis_toolset_path.join("Plugins"); + + let data = download(NSIS_APPLICATIONID_URL)?; + log::info!(action = "Extracting"; "NSIS ApplicationID plugin"); + extract_zip(&data, &nsis_plugins)?; + + std::fs::create_dir_all(nsis_plugins.join("x86-unicode"))?; + + std::fs::copy( + nsis_plugins + .join("ReleaseUnicode") + .join("ApplicationID.dll"), + nsis_plugins.join("x86-unicode").join("ApplicationID.dll"), + )?; + + let data = download_and_verify( + "nsis_tauri_utils.dll", + NSIS_TAURI_UTILS, + NSIS_TAURI_UTILS_SHA1, + HashAlgorithm::Sha1, + )?; + std::fs::write( + nsis_plugins + .join("x86-unicode") + .join("nsis_tauri_utils.dll"), + data, + )?; + + Ok(()) +} + +fn build_nsis_app_installer( + config: &Config, + _nsis_toolset_path: &Path, + _packager_tools_path: &Path, +) -> crate::Result> { + let arch = match config.target_arch()? { + "x86_64" => "x64", + "x86" => "x86", + "aarch64" => "arm64", + target => return Err(crate::Error::UnsupportedArch("nsis".into(), target.into())), + }; + + log::info!("Target: {}", arch); + + #[cfg(target_os = "windows")] + { + let main_binary = config + .binaries + .iter() + .find(|bin| bin.main) + .ok_or_else(|| crate::Error::MainBinaryNotFound)?; + let app_exe_source = config.binary_path(main_binary); + crate::sign::try_sign(&app_exe_source, config)?; + } + + #[cfg(not(target_os = "windows"))] + log::warn!("Code signing is currently only supported on Windows hosts, skipping signing the main binary..."); + + let output_path = config.out_dir.join("nsis").join(arch); + if output_path.exists() { + std::fs::remove_dir_all(&output_path)?; + } + std::fs::create_dir_all(&output_path)?; + + let mut data = BTreeMap::new(); + + #[cfg(not(target_os = "windows"))] + { + let mut dir = dirs::cache_dir().unwrap(); + dir.extend(["tauri", "NSIS", "Plugins", "x86-unicode"]); + data.insert("additional_plugins_path", to_json(dir)); + } + + let bundle_id = config.identifier(); + let manufacturer = config.publisher(); + + data.insert("arch", to_json(arch)); + data.insert("bundle_id", to_json(bundle_id)); + data.insert("manufacturer", to_json(manufacturer)); + data.insert("product_name", to_json(&config.product_name)); + data.insert("short_description", to_json(&config.description)); + data.insert("copyright", to_json(&config.copyright)); + data.insert("version", to_json(&config.version)); + data.insert( + "version_with_build", + to_json(add_build_number_if_needed(&config.version)?), + ); + data.insert( + "allow_downgrades", + to_json(config.windows().map(|w| w.allow_downgrades)), + ); + + #[cfg(target_os = "windows")] + if config.can_sign() { + data.insert( + "uninstaller_sign_cmd", + to_json(format!( + "{:?}", + crate::sign::sign_command("%1", &config.sign_params())?.0 + )), + ); + } + + if let Some(license) = &config.license_file { + data.insert("license", to_json(dunce::canonicalize(license)?)); + } + + let mut install_mode = NSISInstallerMode::CurrentUser; + let mut languages = vec!["English".into()]; + let mut custom_template_path = None; + let mut custom_language_files = None; + + if let Some(nsis) = config.nsis() { + custom_template_path = nsis.template.clone(); + custom_language_files = nsis.custom_language_files.clone(); + install_mode = nsis.install_mode; + if let Some(langs) = &nsis.languages { + languages.clear(); + languages.extend_from_slice(langs); + } + data.insert( + "display_language_selector", + to_json(nsis.display_language_selector && languages.len() > 1), + ); + if let Some(installer_icon) = &nsis.installer_icon { + data.insert( + "installer_icon", + to_json(dunce::canonicalize(installer_icon)?), + ); + } + if let Some(header_image) = &nsis.header_image { + data.insert("header_image", to_json(dunce::canonicalize(header_image)?)); + } + if let Some(sidebar_image) = &nsis.sidebar_image { + data.insert( + "sidebar_image", + to_json(dunce::canonicalize(sidebar_image)?), + ); + } + } + + data.insert("install_mode", to_json(install_mode)); + + let mut languages_data = Vec::new(); + for lang in &languages { + if let Some(data) = get_lang_data(lang, custom_language_files.as_ref())? { + languages_data.push(data); + } else { + log::warn!("Custom cargo-packager messages for {lang} are not translated.\nIf it is a valid language listed on , please open a cargo-packager feature request\n or you can provide a custom language file for it in ` nsis.custom_language_files`"); + } + } + data.insert("languages", to_json(languages.clone())); + data.insert( + "language_files", + to_json( + languages_data + .iter() + .map(|d| d.0.clone()) + .collect::>(), + ), + ); + + let main_binary = config + .binaries + .iter() + .find(|bin| bin.main) + .ok_or_else(|| crate::Error::MainBinaryNotFound)?; + data.insert( + "main_binary_name", + to_json(main_binary.name.replace(".exe", "")), + ); + data.insert( + "main_binary_path", + to_json(config.binary_path(main_binary).with_extension("exe")), + ); + + if let Some(file_associations) = &config.file_associations { + data.insert("file_associations", to_json(file_associations)); + } + + let out_file = "nsis-output.exe"; + data.insert("out_file", to_json(out_file)); + + let resources = generate_resource_data(config); + data.insert("resources", to_json(resources)); + + let binaries = generate_binaries_data(config)?; + data.insert("binaries", to_json(binaries)); + + // TODO: webview2 logic + + let mut handlebars = Handlebars::new(); + handlebars.register_helper("or", Box::new(handlebars_or)); + handlebars.register_helper("association-description", Box::new(association_description)); + handlebars.register_escape_fn(|s| { + let mut output = String::new(); + for c in s.chars() { + match c { + '\"' => output.push_str("$\\\""), + '$' => output.push_str("$$"), + '`' => output.push_str("$\\`"), + '\n' => output.push_str("$\\n"), + '\t' => output.push_str("$\\t"), + '\r' => output.push_str("$\\r"), + _ => output.push(c), + } + } + output + }); + if let Some(path) = custom_template_path { + handlebars + .register_template_string("installer.nsi", std::fs::read_to_string(path)?) + .map_err(|e| e.to_string()) + .expect("Failed to setup custom handlebar template"); + } else { + handlebars + .register_template_string("installer.nsi", include_str!("./installer.nsi")) + .map_err(|e| e.to_string()) + .expect("Failed to setup handlebar template"); + } + + write_ut16_le_with_bom( + &output_path.join("FileAssociation.nsh"), + include_str!("./FileAssociation.nsh"), + )?; + + let installer_nsi_path = output_path.join("installer.nsi"); + write_ut16_le_with_bom( + &installer_nsi_path, + handlebars.render("installer.nsi", &data)?.as_str(), + )?; + + for (lang, data) in languages_data.iter() { + if let Some(content) = data { + write_ut16_le_with_bom(output_path.join(lang).with_extension("nsh"), content)?; + } + } + + let package_base_name = format!( + "{}_{}_{}-setup", + main_binary.name.replace(".exe", ""), + config.version, + arch, + ); + + let nsis_output_path = output_path.join(out_file); + let nsis_installer_path = config + .out_dir + .join(format!("package/nsis/{}.exe", package_base_name)); + std::fs::create_dir_all(nsis_installer_path.parent().unwrap())?; + + log::info!(action = "Running"; "makensis.exe to produce {}", util::display_path(&nsis_installer_path)); + + #[cfg(target_os = "windows")] + let mut nsis_cmd = Command::new(_nsis_toolset_path.join("makensis.exe")); + #[cfg(not(target_os = "windows"))] + let mut nsis_cmd = Command::new("makensis"); + + nsis_cmd + .arg(match config.log_level.unwrap_or_default() { + LogLevel::Error => "-V1", + LogLevel::Warn => "-V2", + LogLevel::Info => "-V3", + LogLevel::Debug => "-V3", + _ => "-V4", + }) + .arg(installer_nsi_path) + .current_dir(output_path) + .status() + .map_err(|e| crate::Error::NsisFailed(e.to_string()))?; + + std::fs::rename(nsis_output_path, &nsis_installer_path)?; + + #[cfg(target_os = "windows")] + crate::sign::try_sign(&nsis_installer_path, config)?; + #[cfg(not(target_os = "windows"))] + log::warn!("Code signing is currently only supported on Windows hosts, skipping signing the installer..."); + + Ok(vec![nsis_installer_path]) +} + +/// BTreeMap +type ResourcesMap = BTreeMap; +fn generate_resource_data(config: &Config) -> ResourcesMap { + let mut resources_map = ResourcesMap::new(); + let mut added_resources = Vec::new(); + if let Some(resources) = config.resources() { + for resource in resources { + // In some glob resource paths like `assets/**/*` a file might appear twice + // because the `tauri_utils::resources::ResourcePaths` iterator also reads a directory + // when it finds one. So we must check it before processing the file. + if added_resources.contains(&resource.src) { + continue; + } + added_resources.push(resource.src.clone()); + + resources_map.insert( + resource.src, + ( + resource + .target + .parent() + .map(|p| p.to_string_lossy().to_string()) + .unwrap_or_default(), + resource.target, + ), + ); + } + } + + resources_map +} + +/// BTreeMap +type BinariesMap = BTreeMap; +fn generate_binaries_data(config: &Config) -> crate::Result { + let mut binaries = BinariesMap::new(); + let cwd = std::env::current_dir()?; + + if let Some(external_binaries) = &config.external_binaries { + for src in external_binaries { + let binary_path = dunce::canonicalize(cwd.join(&src))?; + let dest_filename = binary_path + .file_name() + .expect("failed to extract external binary filename") + .to_string_lossy() + .replace(&format!("-{}", config.target_triple), ""); + binaries.insert(binary_path, dest_filename); + } + } + + for bin in &config.binaries { + if !bin.main { + let bin_path = config.binary_path(bin); + binaries.insert( + bin_path.clone(), + bin_path + .file_name() + .expect("failed to extract binary filename") + .to_string_lossy() + .to_string(), + ); + } + } + + Ok(binaries) +} + +fn get_lang_data( + lang: &str, + custom_lang_files: Option<&HashMap>, +) -> crate::Result)>> { + if let Some(path) = custom_lang_files.and_then(|h| h.get(lang)) { + return Ok(Some((dunce::canonicalize(path)?, None))); + } + + let lang_path = PathBuf::from(format!("{lang}.nsh")); + let lang_content = match lang.to_lowercase().as_str() { + "arabic" => Some(include_str!("./languages/Arabic.nsh")), + "bulgarian" => Some(include_str!("./languages/Bulgarian.nsh")), + "dutch" => Some(include_str!("./languages/Dutch.nsh")), + "english" => Some(include_str!("./languages/English.nsh")), + "japanese" => Some(include_str!("./languages/Japanese.nsh")), + "korean" => Some(include_str!("./languages/Korean.nsh")), + "portuguesebr" => Some(include_str!("./languages/PortugueseBR.nsh")), + "tradchinese" => Some(include_str!("./languages/TradChinese.nsh")), + "simpchinese" => Some(include_str!("./languages/SimpChinese.nsh")), + "french" => Some(include_str!("./languages/French.nsh")), + "spanish" => Some(include_str!("./languages/Spanish.nsh")), + "spanishinternational" => Some(include_str!("./languages/SpanishInternational.nsh")), + "persian" => Some(include_str!("./languages/Persian.nsh")), + "turkish" => Some(include_str!("./languages/Turkish.nsh")), + "swedish" => Some(include_str!("./languages/Swedish.nsh")), + _ => return Ok(None), + }; + + Ok(Some((lang_path, lang_content))) +} + +fn write_ut16_le_with_bom>(path: P, content: &str) -> crate::Result<()> { + use std::fs::File; + use std::io::{BufWriter, Write}; + + let file = File::create(path)?; + let mut output = BufWriter::new(file); + output.write_all(&[0xFF, 0xFE])?; // the BOM part + for utf16 in content.encode_utf16() { + output.write_all(&utf16.to_le_bytes())?; + } + Ok(()) +} + +fn handlebars_or( + h: &handlebars::Helper<'_, '_>, + _: &Handlebars<'_>, + _: &handlebars::Context, + _: &mut handlebars::RenderContext<'_, '_>, + out: &mut dyn handlebars::Output, +) -> handlebars::HelperResult { + let param1 = h.param(0).unwrap().render(); + let param2 = h.param(1).unwrap(); + + out.write(&if param1.is_empty() { + param2.render() + } else { + param1 + })?; + Ok(()) +} + +fn association_description( + h: &handlebars::Helper<'_, '_>, + _: &Handlebars<'_>, + _: &handlebars::Context, + _: &mut handlebars::RenderContext<'_, '_>, + out: &mut dyn handlebars::Output, +) -> handlebars::HelperResult { + let description = h.param(0).unwrap().render(); + let ext = h.param(1).unwrap(); + + out.write(&if description.is_empty() { + format!("{} File", ext.render().to_uppercase()) + } else { + description + })?; + Ok(()) +} + +fn add_build_number_if_needed(version_str: &str) -> crate::Result { + let version = semver::Version::parse(version_str)?; + if !version.build.is_empty() { + let build = version.build.parse::(); + if build.is_ok() { + return Ok(format!( + "{}.{}.{}.{}", + version.major, version.minor, version.patch, version.build + )); + } else { + return Err(crate::Error::NonNumericBuildMetadata); + } + } + + Ok(format!( + "{}.{}.{}.0", + version.major, version.minor, version.patch, + )) } diff --git a/crates/packager/src/sign.rs b/crates/packager/src/sign.rs new file mode 100644 index 00000000..52472a0e --- /dev/null +++ b/crates/packager/src/sign.rs @@ -0,0 +1,196 @@ +#![cfg(windows)] + +// signing code forked from https://github.com/forbjok/rust-codesign + +use once_cell::sync::Lazy; +use std::{ + path::{Path, PathBuf}, + process::Command, +}; +use winreg::{ + enums::{HKEY_LOCAL_MACHINE, KEY_READ, KEY_WOW64_32KEY}, + RegKey, +}; + +use crate::{ + config::{Config, ConfigExt}, + util::{self, Bitness}, +}; + +pub struct SignParams { + pub product_name: String, + pub digest_algorithm: String, + pub certificate_thumbprint: String, + pub timestamp_url: Option, + pub tsp: bool, +} + +static SIGN_TOOL: Lazy> = Lazy::new(|| { + const INSTALLED_ROOTS_REGKEY_PATH: &str = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + const KITS_ROOT_REGVALUE_NAME: &str = r"KitsRoot10"; + + let installed_roots_key_path = Path::new(INSTALLED_ROOTS_REGKEY_PATH); + + // Open 32-bit HKLM "Installed Roots" key + let installed_roots_key = RegKey::predef(HKEY_LOCAL_MACHINE) + .open_subkey_with_flags(installed_roots_key_path, KEY_READ | KEY_WOW64_32KEY)?; + // Get the Windows SDK root path + let kits_root_10_path: String = installed_roots_key.get_value(KITS_ROOT_REGVALUE_NAME)?; + // Construct Windows SDK bin path + let kits_root_10_bin_path = Path::new(&kits_root_10_path).join("bin"); + + let mut installed_kits: Vec = installed_roots_key + .enum_keys() + /* Report and ignore errors, pass on values. */ + .filter_map(|res| match res { + Ok(v) => Some(v), + Err(_) => None, + }) + .collect(); + + // Sort installed kits + installed_kits.sort(); + + /* Iterate through installed kit version keys in reverse (from newest to oldest), + adding their bin paths to the list. + Windows SDK 10 v10.0.15063.468 and later will have their signtools located there. */ + let mut kit_bin_paths: Vec = installed_kits + .iter() + .rev() + .map(|kit| kits_root_10_bin_path.join(kit)) + .collect(); + + /* Add kits root bin path. + For Windows SDK 10 versions earlier than v10.0.15063.468, signtool will be located there. */ + kit_bin_paths.push(kits_root_10_bin_path); + + // Choose which version of SignTool to use based on OS bitness + let arch_dir = match util::os_bitness().expect("failed to get os bitness") { + Bitness::X86_32 => "x86", + Bitness::X86_64 => "x64", + _ => return Err(crate::Error::UnsupportedBitness), + }; + + /* Iterate through all bin paths, checking for existence of a SignTool executable. */ + for kit_bin_path in &kit_bin_paths { + /* Construct SignTool path. */ + let signtool_path = kit_bin_path.join(arch_dir).join("signtool.exe"); + + /* Check if SignTool exists at this location. */ + if signtool_path.exists() { + // SignTool found. Return it. + return Ok(signtool_path); + } + } + + Err(crate::Error::SignToolNotFound) +}); + +fn locate_signtool() -> Option { + (*SIGN_TOOL).as_ref().ok().cloned() +} + +pub fn sign_command(path: &str, params: &SignParams) -> crate::Result<(Command, PathBuf)> { + // Construct SignTool command + let signtool = locate_signtool().ok_or(crate::Error::SignToolNotFound)?; + + let mut cmd = Command::new(&signtool); + cmd.arg("sign"); + cmd.args(["/fd", ¶ms.digest_algorithm]); + cmd.args(["/sha1", ¶ms.certificate_thumbprint]); + cmd.args(["/d", ¶ms.product_name]); + + if let Some(ref timestamp_url) = params.timestamp_url { + if params.tsp { + cmd.args(["/tr", timestamp_url]); + cmd.args(["/td", ¶ms.digest_algorithm]); + } else { + cmd.args(["/t", timestamp_url]); + } + } + + cmd.arg(path); + + Ok((cmd, signtool)) +} + +pub(crate) trait ConfigSignExt { + fn can_sign(&self) -> bool; + fn sign_params(&self) -> SignParams; +} + +impl ConfigSignExt for Config { + fn can_sign(&self) -> bool { + self.windows() + .and_then(|w| w.certificate_thumbprint.as_ref()) + .is_some() + } + + fn sign_params(&self) -> SignParams { + let windows = self.windows(); + SignParams { + product_name: self.product_name.clone(), + digest_algorithm: windows + .and_then(|w| w.digest_algorithm.as_ref()) + .as_ref() + .map(|algorithm| algorithm.to_string()) + .unwrap_or_else(|| "sha256".to_string()), + certificate_thumbprint: windows + .and_then(|w| w.certificate_thumbprint.as_ref()) + .cloned() + .unwrap_or_default(), + timestamp_url: windows + .and_then(|w| w.timestamp_url.as_ref()) + .as_ref() + .map(|url| url.to_string()), + tsp: windows.map(|w| w.tsp).unwrap_or_default(), + } + } +} + +pub fn sign>(path: P, params: &SignParams) -> crate::Result<()> { + // Convert path to string reference, as we need to pass it as a command-line parameter to signtool + let path_str = path.as_ref().to_str().unwrap(); + + log::info!(action = "Signing"; "{} with identity \"{}\"", path_str, params.certificate_thumbprint); + + let (mut cmd, signtool) = sign_command(path_str, params)?; + log::debug!("Running signtool {:?}", signtool); + + let output = cmd.output()?; + let stdout = String::from_utf8_lossy(output.stdout.as_slice()).into_owned(); + log::info!("{:?}", stdout); + + Ok(()) +} + +pub fn try_sign( + file_path: &std::path::PathBuf, + config: &crate::config::Config, +) -> crate::Result<()> { + let windows_config = config.windows(); + if let Some(certificate_thumbprint) = + windows_config.and_then(|c| c.certificate_thumbprint.as_ref()) + { + log::info!(action = "Signing"; "{}", util::display_path(file_path)); + sign( + file_path, + &SignParams { + product_name: config.product_name.clone(), + digest_algorithm: windows_config + .and_then(|c| { + c.digest_algorithm + .as_ref() + .map(|algorithm| algorithm.to_string()) + }) + .unwrap_or_else(|| "sha256".to_string()), + certificate_thumbprint: certificate_thumbprint.to_string(), + timestamp_url: windows_config + .and_then(|c| c.timestamp_url.as_ref()) + .map(|url| url.to_string()), + tsp: windows_config.map(|c| c.tsp).unwrap_or_default(), + }, + )?; + } + Ok(()) +} diff --git a/crates/packager/src/util.rs b/crates/packager/src/util.rs index d05ccb85..c702390b 100644 --- a/crates/packager/src/util.rs +++ b/crates/packager/src/util.rs @@ -1,4 +1,11 @@ -use std::path::{Path, PathBuf}; +use sha2::Digest; +use std::{ + fs::File, + io::{Cursor, Read, Write}, + path::{Path, PathBuf}, +}; + +use zip::ZipArchive; pub fn display_path>(p: P) -> String { dunce::simplified(&p.as_ref().components().collect::()) @@ -58,3 +65,112 @@ pub fn target_triple() -> crate::Result { Ok(format!("{arch}-{os}")) } + +pub fn download(url: &str) -> crate::Result> { + log::info!(action = "Downloading"; "{}", url); + let response = ureq::get(url).call()?; + let mut bytes = Vec::new(); + response.into_reader().read_to_end(&mut bytes)?; + Ok(bytes) +} + +pub enum HashAlgorithm { + #[cfg(target_os = "windows")] + Sha256, + Sha1, +} + +/// Function used to download a file and checks SHA256 to verify the download. +pub fn download_and_verify( + file: &str, + url: &str, + hash: &str, + hash_algorithm: HashAlgorithm, +) -> crate::Result> { + let data = download(url)?; + log::info!(action = "Validating"; "{file} hash"); + + match hash_algorithm { + #[cfg(target_os = "windows")] + HashAlgorithm::Sha256 => { + let hasher = sha2::Sha256::new(); + verify(&data, hash, hasher)?; + } + HashAlgorithm::Sha1 => { + let hasher = sha1::Sha1::new(); + verify(&data, hash, hasher)?; + } + } + + Ok(data) +} + +fn verify(data: &Vec, hash: &str, mut hasher: impl Digest) -> crate::Result<()> { + hasher.update(data); + + let url_hash = hasher.finalize().to_vec(); + let expected_hash = hex::decode(hash)?; + if expected_hash == url_hash { + Ok(()) + } else { + Err(crate::Error::HashError) + } +} + +/// Extracts the zips from memory into a useable path. +pub fn extract_zip(data: &[u8], path: &Path) -> crate::Result<()> { + let cursor = Cursor::new(data); + + let mut zipa = ZipArchive::new(cursor)?; + + for i in 0..zipa.len() { + let mut file = zipa.by_index(i)?; + + if let Some(name) = file.enclosed_name() { + let dest_path = path.join(name); + if file.is_dir() { + std::fs::create_dir_all(&dest_path)?; + continue; + } + + let parent = dest_path.parent().ok_or(crate::Error::ParentDirNotFound)?; + + if !parent.exists() { + std::fs::create_dir_all(parent)?; + } + + let mut buff: Vec = Vec::new(); + file.read_to_end(&mut buff)?; + + let mut fileout = File::create(dest_path)?; + fileout.write_all(&buff)?; + } + } + + Ok(()) +} + +pub enum Bitness { + X86_32, + X86_64, + Unknown, +} + +#[cfg(windows)] +pub fn os_bitness() -> crate::Result { + use windows_sys::Win32::System::{ + Diagnostics::Debug::{PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_INTEL}, + SystemInformation::{GetNativeSystemInfo, SYSTEM_INFO}, + }; + + let mut system_info: SYSTEM_INFO = unsafe { std::mem::zeroed() }; + unsafe { GetNativeSystemInfo(&mut system_info) }; + + Ok( + match unsafe { system_info.Anonymous.Anonymous.wProcessorArchitecture } { + PROCESSOR_ARCHITECTURE_INTEL => Bitness::X86_32, + PROCESSOR_ARCHITECTURE_AMD64 => Bitness::X86_64, + _ => Bitness::Unknown, + }, + ) +} diff --git a/examples/dioxus/Cargo.toml b/examples/dioxus/Cargo.toml index 8355469a..7650a509 100644 --- a/examples/dioxus/Cargo.toml +++ b/examples/dioxus/Cargo.toml @@ -4,9 +4,10 @@ version = "0.0.0" edition = "2021" [package.metadata.packager] +before-packaging-command = "dx build --platform desktop --release" format = ["nsis"] product-name = "Dioxus example" -resources = { "src/*.rs" = "assets" } +identifier = "com.dioxus.example" [dependencies] dioxus = "0.4" diff --git a/examples/dioxus/README.md b/examples/dioxus/README.md index 0995db33..a2d26886 100644 --- a/examples/dioxus/README.md +++ b/examples/dioxus/README.md @@ -1 +1,13 @@ ## Dioxus example + +You need to install `dioxus-cli` first + +```sh +cargo install dioxus-cli --locked +``` + +then package the app + +```sh +cargo r -p cargo-packager -- -p dioxus-example --relase +``` diff --git a/examples/tauri/Cargo.toml b/examples/tauri/Cargo.toml index 1d1159c6..bec1bf50 100644 --- a/examples/tauri/Cargo.toml +++ b/examples/tauri/Cargo.toml @@ -4,8 +4,10 @@ version = "0.0.0" edition = "2021" [package.metadata.packager] +before-packaging-command = "cargo tauri build" format = ["nsis"] product-name = "Tauri example" +identifier = "com.tauri.example" [build-dependencies] tauri-build = { version = "=2.0.0-alpha.7", features = [] } diff --git a/examples/tauri/README.md b/examples/tauri/README.md index 65cfbcf7..96233f56 100644 --- a/examples/tauri/README.md +++ b/examples/tauri/README.md @@ -1 +1,13 @@ ## Tauri example + +You need to install `tauri-cli` first + +```sh +cargo install tauri-cli --version 2.0.0-alpha.10 +``` + +then package the app + +```sh +cargo r -p cargo-packager -- -p tauri-example --relase +``` diff --git a/examples/tauri/build.rs b/examples/tauri/build.rs index 795b9b7c..d860e1e6 100644 --- a/examples/tauri/build.rs +++ b/examples/tauri/build.rs @@ -1,3 +1,3 @@ fn main() { - tauri_build::build() + tauri_build::build() } diff --git a/examples/tauri/tauri.conf.json b/examples/tauri/tauri.conf.json index 087c3367..ce7e4cd6 100644 --- a/examples/tauri/tauri.conf.json +++ b/examples/tauri/tauri.conf.json @@ -7,7 +7,7 @@ "withGlobalTauri": true }, "package": { - "productName": "tauri example", + "productName": "tauri-example", "version": "0.0.0" }, "tauri": {