Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bundler): add nsis, closes #4450, closes #2319 #4674

Merged
merged 50 commits into from Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5dc506c
feat(bundler): add `nsis`, closes #4450, closes #2319
amrbashir Jul 14, 2022
221cbc9
remove invalid doc comment
amrbashir Jul 15, 2022
6c1b1c6
look for webview2 x64 per machine installation
amrbashir Jul 15, 2022
ba83871
remove unnecessary pub
amrbashir Jul 15, 2022
77d893c
bundle resources
amrbashir Jul 15, 2022
ed6fe40
bundle externalBinaries
amrbashir Jul 15, 2022
2404f04
fix launch after install option
amrbashir Jul 15, 2022
f6f2a18
set AppUserModelID
amrbashir Jul 15, 2022
e5b72f7
set AppUserModelID for desktop shortcut too
amrbashir Jul 15, 2022
7d9f88e
add `allowDowngrades`, x32, lzma compression and reinstall page
amrbashir Jul 16, 2022
ab4e3c6
fix `allowDowngrades` and disable moving on without uninstalling first
amrbashir Jul 16, 2022
bdb7d96
abort silent installer if allowdowngrades is disabled
amrbashir Jul 17, 2022
8fba86a
webview2 install modes
amrbashir Jul 17, 2022
a4df69d
Prompt to kill if app is running
amrbashir Jul 18, 2022
7915944
fix NSIS warning
amrbashir Jul 18, 2022
2662ac6
updater
amrbashir Jul 18, 2022
d0b7250
remove a stray dbg!
amrbashir Jul 18, 2022
397c070
changefile
amrbashir Jul 18, 2022
d97e380
Merge branch 'dev' into nsis
amrbashir Jul 18, 2022
b8825b7
adjust bump to minor
amrbashir Jul 20, 2022
a5def17
Merge branch 'dev' into nsis
amrbashir Nov 1, 2022
f6ac3fd
fix APR display icon path
amrbashir Nov 1, 2022
3e371ed
Merge branch 'dev' into nsis
amrbashir Dec 8, 2022
e9904a7
fmt
amrbashir Dec 8, 2022
8f3c939
fix `!define` call
amrbashir Dec 8, 2022
bfbe0e7
fix bundling updater for multiple bundle targets
amrbashir Dec 8, 2022
cf145be
remove console window from api example on Windows
amrbashir Dec 8, 2022
ce0dea5
strip unc on windows only
amrbashir Dec 8, 2022
9413ee6
fix cli build on unix
amrbashir Dec 8, 2022
6279fea
download NSIS plugins from `tauri-apps/binary-releases`
amrbashir Dec 8, 2022
e36610f
fmt docs [skip ci]
lucasfernog Dec 14, 2022
e57a2b4
use constants [skip ci]
lucasfernog Dec 14, 2022
3c352b1
add HashAlgorithm enum [skip ci]
lucasfernog Dec 14, 2022
f5aaed7
add missing license header [skip ci]
lucasfernog Dec 14, 2022
9d10c0f
fix consts [skip ci]
lucasfernog Dec 15, 2022
4b2cc74
silent updater install
lucasfernog Dec 15, 2022
92cc7dc
installerargs option for updater
lucasfernog Dec 15, 2022
5df4876
add updater test
lucasfernog Dec 15, 2022
04391bd
optimize test
lucasfernog Dec 15, 2022
3eb73d1
fix wix test [skip ci]
lucasfernog Dec 15, 2022
6d09c29
Allow `major.minor.patch-pre` in NSIS
amrbashir Dec 16, 2022
91c20bc
Merge branch 'dev' into nsis
amrbashir Dec 16, 2022
70b06b6
switch to `NSIS-SemverCompare` plugin
amrbashir Dec 21, 2022
a8cfd7d
add support for both modes
amrbashir Dec 21, 2022
38a60fe
hide `installmode` file and make it readonly
amrbashir Dec 22, 2022
50ba0e3
Update core/tauri-utils/src/config.rs
amrbashir Dec 22, 2022
e36f74a
update schema.json
amrbashir Dec 22, 2022
51dcd14
use the new rust veresion of `nsis-semvercompare`
amrbashir Jan 2, 2023
b678c97
insert `install_mode` even if the `nsis` object is not defined in tau…
amrbashir Jan 2, 2023
d1179c7
delete only the files we install, no recursive
amrbashir Jan 2, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changes/nsis.md
@@ -0,0 +1,8 @@
---
"tauri-bundler": minor
"tauri-utils": minor
"cli.rs": minor
"cli.js": minor
---

Add `nsis` bundle target
82 changes: 77 additions & 5 deletions core/config-schema/schema.json
Expand Up @@ -146,6 +146,7 @@
"allowDowngrades": true,
"certificateThumbprint": null,
"digestAlgorithm": null,
"nsis": null,
"timestampUrl": null,
"tsp": false,
"webviewFixedRuntimePath": null,
Expand All @@ -169,7 +170,8 @@
"dialog": true,
"pubkey": "",
"windows": {
"installMode": "passive"
"installMode": "passive",
"installerArgs": []
}
},
"windows": []
Expand Down Expand Up @@ -282,6 +284,7 @@
"allowDowngrades": true,
"certificateThumbprint": null,
"digestAlgorithm": null,
"nsis": null,
"timestampUrl": null,
"tsp": false,
"webviewFixedRuntimePath": null,
Expand Down Expand Up @@ -427,7 +430,8 @@
"dialog": true,
"pubkey": "",
"windows": {
"installMode": "passive"
"installMode": "passive",
"installerArgs": []
}
},
"allOf": [
Expand Down Expand Up @@ -1018,7 +1022,7 @@
"type": "boolean"
},
"targets": {
"description": "The bundle targets, currently supports [\"deb\", \"appimage\", \"msi\", \"app\", \"dmg\", \"updater\"] or \"all\".",
"description": "The bundle targets, currently supports [\"deb\", \"appimage\", \"nsis\", \"msi\", \"app\", \"dmg\", \"updater\"] or \"all\".",
"default": "all",
"allOf": [
{
Expand Down Expand Up @@ -1132,6 +1136,7 @@
"allowDowngrades": true,
"certificateThumbprint": null,
"digestAlgorithm": null,
"nsis": null,
"timestampUrl": null,
"tsp": false,
"webviewFixedRuntimePath": null,
Expand Down Expand Up @@ -1200,6 +1205,13 @@
"msi"
]
},
{
"description": "The NSIS bundle (.exe).",
"type": "string",
"enum": [
"nsis"
]
},
{
"description": "The macOS application bundle (.app).",
"type": "string",
Expand Down Expand Up @@ -1384,6 +1396,17 @@
"type": "null"
}
]
},
"nsis": {
"description": "Configuration for the installer generated with NSIS.",
"anyOf": [
{
"$ref": "#/definitions/NsisConfig"
},
{
"type": "null"
}
]
}
},
"additionalProperties": false
Expand Down Expand Up @@ -1632,6 +1655,46 @@
},
"additionalProperties": false
},
"NsisConfig": {
"description": "Configuration for the Installer bundle using NSIS.",
"type": "object",
"properties": {
"license": {
"description": "The path to the license file to render on the installer.",
"type": [
"string",
"null"
]
},
"headerImage": {
"description": "The path to a bitmap file to display on the header of installers pages.\n\nThe recommended dimensions are 150px x 57px.",
"type": [
"string",
"null"
]
},
"sidebarImage": {
"description": "The path to a bitmap file for the Welcome page and the Finish page.\n\nThe recommended dimensions are 164px x 314px.",
"type": [
"string",
"null"
]
},
"installerIcon": {
"description": "The path to an icon file used as the installer icon.",
"type": [
"string",
"null"
]
},
"perMachine": {
"description": "Whether the installation will be for all users or just the current user.",
"default": false,
"type": "boolean"
}
amrbashir marked this conversation as resolved.
Show resolved Hide resolved
},
"additionalProperties": false
},
"AllowlistConfig": {
"description": "Allowlist configuration.",
"type": "object",
Expand Down Expand Up @@ -2579,7 +2642,8 @@
"windows": {
"description": "The Windows configuration for the updater.",
"default": {
"installMode": "passive"
"installMode": "passive",
"installerArgs": []
},
"allOf": [
{
Expand All @@ -2599,6 +2663,14 @@
"description": "The updater configuration for Windows.",
"type": "object",
"properties": {
"installerArgs": {
"description": "Additional arguments given to the NSIS or WiX installer.",
"default": [],
"type": "array",
"items": {
"type": "string"
}
},
"installMode": {
"description": "The installation mode for the update on Windows. Defaults to `passive`.",
"default": "passive",
Expand All @@ -2622,7 +2694,7 @@
]
},
{
"description": "The quiet mode means there's no user interaction required. Requires admin privileges if the installer does.",
"description": "The quiet mode means there's no user interaction required. Requires admin privileges if the installer does (WiX).",
"type": "string",
"enum": [
"quiet"
Expand Down
39 changes: 36 additions & 3 deletions core/tauri-utils/src/config.rs
Expand Up @@ -78,6 +78,8 @@ pub enum BundleType {
AppImage,
/// The Microsoft Installer bundle (.msi).
Msi,
/// The NSIS bundle (.exe).
Nsis,
/// The macOS application bundle (.app).
App,
/// The Apple Disk Image bundle (.dmg).
Expand All @@ -95,6 +97,7 @@ impl Display for BundleType {
Self::Deb => "deb",
Self::AppImage => "appimage",
Self::Msi => "msi",
Self::Nsis => "nsis",
Self::App => "app",
Self::Dmg => "dmg",
Self::Updater => "updater",
Expand Down Expand Up @@ -122,6 +125,7 @@ impl<'de> Deserialize<'de> for BundleType {
"deb" => Ok(Self::Deb),
"appimage" => Ok(Self::AppImage),
"msi" => Ok(Self::Msi),
"nsis" => Ok(Self::Nsis),
"app" => Ok(Self::App),
"dmg" => Ok(Self::Dmg),
"updater" => Ok(Self::Updater),
Expand Down Expand Up @@ -416,6 +420,28 @@ pub struct WixConfig {
pub dialog_image_path: Option<PathBuf>,
}

/// Configuration for the Installer bundle using NSIS.
#[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct NsisConfig {
/// The path to the license file to render on the installer.
pub license: Option<PathBuf>,
/// The path to a bitmap file to display on the header of installers pages.
///
/// The recommended dimensions are 150px x 57px.
pub header_image: Option<PathBuf>,
/// The path to a bitmap file for the Welcome page and the Finish page.
///
/// The recommended dimensions are 164px x 314px.
pub sidebar_image: Option<PathBuf>,
/// The path to an icon file used as the installer icon.
pub installer_icon: Option<PathBuf>,
/// Whether the installation will be for all users or just the current user.
#[serde(default)]
pub per_machine: bool,
}

/// Install modes for the Webview2 runtime.
/// Note that for the updater bundle [`Self::DownloadBootstrapper`] is used.
///
Expand Down Expand Up @@ -512,6 +538,8 @@ pub struct WindowsConfig {
pub allow_downgrades: bool,
/// Configuration for the MSI generated with WiX.
pub wix: Option<WixConfig>,
/// Configuration for the installer generated with NSIS.
pub nsis: Option<NsisConfig>,
}

impl Default for WindowsConfig {
Expand All @@ -525,6 +553,7 @@ impl Default for WindowsConfig {
webview_fixed_runtime_path: None,
allow_downgrades: default_allow_downgrades(),
wix: None,
nsis: None,
}
}
}
Expand All @@ -542,7 +571,7 @@ pub struct BundleConfig {
/// Whether Tauri should bundle your application or just output the executable.
#[serde(default)]
pub active: bool,
/// The bundle targets, currently supports ["deb", "appimage", "msi", "app", "dmg", "updater"] or "all".
/// The bundle targets, currently supports ["deb", "appimage", "nsis", "msi", "app", "dmg", "updater"] or "all".
#[serde(default)]
pub targets: BundleTarget,
/// The application identifier in reverse domain name notation (e.g. `com.tauri.example`).
Expand Down Expand Up @@ -2306,7 +2335,7 @@ pub enum WindowsUpdateInstallMode {
/// Specifies there's a basic UI during the installation process, including a final dialog box at the end.
BasicUi,
/// The quiet mode means there's no user interaction required.
/// Requires admin privileges if the installer does.
/// Requires admin privileges if the installer does (WiX).
Quiet,
/// Specifies unattended mode, which means the installation only shows a progress bar.
Passive,
Expand Down Expand Up @@ -2377,6 +2406,9 @@ impl<'de> Deserialize<'de> for WindowsUpdateInstallMode {
#[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct UpdaterWindowsConfig {
/// Additional arguments given to the NSIS or WiX installer.
#[serde(default, alias = "installer-args")]
pub installer_args: Vec<String>,
/// The installation mode for the update on Windows. Defaults to `passive`.
#[serde(default, alias = "install-mode")]
pub install_mode: WindowsUpdateInstallMode,
Expand Down Expand Up @@ -3355,7 +3387,8 @@ mod build {
impl ToTokens for UpdaterWindowsConfig {
fn to_tokens(&self, tokens: &mut TokenStream) {
let install_mode = &self.install_mode;
literal_struct!(tokens, UpdaterWindowsConfig, install_mode);
let installer_args = vec_lit(&self.installer_args, str_lit);
literal_struct!(tokens, UpdaterWindowsConfig, install_mode, installer_args);
}
}

Expand Down
46 changes: 28 additions & 18 deletions core/tauri/src/updater/core.rs
Expand Up @@ -612,15 +612,7 @@ impl<R: Runtime> Update<R> {
archive_buffer,
&self.extract_path,
self.with_elevated_task,
self
.app
.config()
.tauri
.updater
.windows
.install_mode
.clone()
.msiexec_args(),
&self.app.config(),
)?;
#[cfg(not(target_os = "windows"))]
copy_files_and_run(archive_buffer, &self.extract_path)?;
Expand Down Expand Up @@ -698,17 +690,19 @@ fn copy_files_and_run<R: Read + Seek>(archive_buffer: R, extract_path: &Path) ->
}

// Windows

//
// ### Expected structure:
// ├── [AppName]_[version]_x64.msi.zip # ZIP generated by tauri-bundler
// │ └──[AppName]_[version]_x64.msi # Application MSI
// ├── [AppName]_[version]_x64-setup.exe.zip # ZIP generated by tauri-bundler
// │ └──[AppName]_[version]_x64-setup.exe # NSIS installer
// └── ...

//
// ## MSI
// Update server can provide a MSI for Windows. (Generated with tauri-bundler from *Wix*)
// To replace current version of the application. In later version we'll offer
// incremental update to push specific binaries.

//
// ## EXE
// Update server can provide a custom EXE (installer) who can run any task.
#[cfg(target_os = "windows")]
Expand All @@ -717,7 +711,7 @@ fn copy_files_and_run<R: Read + Seek>(
archive_buffer: R,
_extract_path: &Path,
with_elevated_task: bool,
msiexec_args: &[&str],
config: &crate::Config,
) -> Result {
// FIXME: We need to create a memory buffer with the MSI and then run it.
// (instead of extracting the MSI to a temp path)
Expand All @@ -736,18 +730,22 @@ fn copy_files_and_run<R: Read + Seek>(
extractor.extract_into(&tmp_dir)?;

let paths = read_dir(&tmp_dir)?;
// This consumes the TempDir without deleting directory on the filesystem,
// meaning that the directory will no longer be automatically deleted.

for path in paths {
let found_path = path?.path();
// we support 2 type of files exe & msi for now
// If it's an `exe` we expect an installer not a runtime.
if found_path.extension() == Some(OsStr::new("exe")) {
// Run the EXE
Command::new(found_path)
.spawn()
.expect("installer failed to start");
let mut installer = Command::new(found_path);
if crate::utils::config::WindowsUpdateInstallMode::Quiet
== config.tauri.updater.windows.install_mode
{
installer.arg("/S");
}
installer.args(&config.tauri.updater.windows.installer_args);

installer.spawn().expect("installer failed to start");

exit(0);
} else if found_path.extension() == Some(OsStr::new("msi")) {
Expand Down Expand Up @@ -801,6 +799,18 @@ fn copy_files_and_run<R: Read + Seek>(
msi_path_arg.push(&found_path);
msi_path_arg.push("\"\"\"");

let mut msiexec_args = config
.tauri
.updater
.windows
.install_mode
.clone()
.msiexec_args()
.iter()
.map(|p| p.to_string())
.collect::<Vec<String>>();
msiexec_args.extend(config.tauri.updater.windows.installer_args.clone());

// run the installer and relaunch the application
let system_root = std::env::var("SYSTEMROOT");
let powershell_path = system_root.as_ref().map_or_else(
Expand Down