mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-06 13:53:54 +02:00
refactor!(updater): migrate run updater using powershell to ShellExecute (#1054)
* Migrate to ShellExecute * Add change file * Revert cargo.toml style * Remove unused imports * Migrate to windows-sys * Use open instead of runas * Use encode_wide instead of hstring * small cleanup
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"updater": patch
|
||||
---
|
||||
|
||||
Fix Windows powershell window flashing on update
|
||||
Generated
+29
-28
@@ -1039,7 +1039,7 @@ dependencies = [
|
||||
"num-traits",
|
||||
"serde",
|
||||
"wasm-bindgen",
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6793,6 +6793,7 @@ dependencies = [
|
||||
"time",
|
||||
"tokio",
|
||||
"url",
|
||||
"windows-sys 0.52.0",
|
||||
"zip",
|
||||
]
|
||||
|
||||
@@ -8092,7 +8093,7 @@ dependencies = [
|
||||
"windows-core 0.52.0",
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8110,7 +8111,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8172,7 +8173,7 @@ version = "0.52.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8207,17 +8208,17 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
|
||||
checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm 0.52.0",
|
||||
"windows_aarch64_msvc 0.52.0",
|
||||
"windows_i686_gnu 0.52.0",
|
||||
"windows_i686_msvc 0.52.0",
|
||||
"windows_x86_64_gnu 0.52.0",
|
||||
"windows_x86_64_gnullvm 0.52.0",
|
||||
"windows_x86_64_msvc 0.52.0",
|
||||
"windows_aarch64_gnullvm 0.52.4",
|
||||
"windows_aarch64_msvc 0.52.4",
|
||||
"windows_i686_gnu 0.52.4",
|
||||
"windows_i686_msvc 0.52.4",
|
||||
"windows_x86_64_gnu 0.52.4",
|
||||
"windows_x86_64_gnullvm 0.52.4",
|
||||
"windows_x86_64_msvc 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8226,7 +8227,7 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75aa004c988e080ad34aff5739c39d0312f4684699d6d71fc8a198d057b8b9b4"
|
||||
dependencies = [
|
||||
"windows-targets 0.52.0",
|
||||
"windows-targets 0.52.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -8243,9 +8244,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||
checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
@@ -8267,9 +8268,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||
checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
@@ -8291,9 +8292,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||
checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
@@ -8315,9 +8316,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||
checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
@@ -8339,9 +8340,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||
checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
@@ -8357,9 +8358,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||
checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
@@ -8381,9 +8382,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.0"
|
||||
version = "0.52.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
|
||||
@@ -37,6 +37,7 @@ tar = "0.4"
|
||||
|
||||
[target."cfg(target_os = \"windows\")".dependencies]
|
||||
zip = { version = "0.6", default-features = false }
|
||||
windows-sys = { version = "0.52.0", features = ["Win32_Foundation", "Win32_UI_WindowsAndMessaging"] }
|
||||
|
||||
[target."cfg(any(target_os = \"macos\", target_os = \"linux\"))".dependencies]
|
||||
flate2 = "1.0.27"
|
||||
|
||||
@@ -139,14 +139,10 @@
|
||||
},
|
||||
"platforms": {
|
||||
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
|
||||
"default": [
|
||||
"linux",
|
||||
"macOS",
|
||||
"windows",
|
||||
"android",
|
||||
"iOS"
|
||||
"type": [
|
||||
"array",
|
||||
"null"
|
||||
],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Target"
|
||||
}
|
||||
|
||||
+45
-107
@@ -512,7 +512,11 @@ impl Update {
|
||||
// Update server can provide a custom EXE (installer) who can run any task.
|
||||
#[cfg(windows)]
|
||||
fn install_inner(&self, bytes: Vec<u8>) -> Result<()> {
|
||||
use std::{fs, process::Command};
|
||||
use std::fs;
|
||||
use windows_sys::{
|
||||
w,
|
||||
Win32::UI::{Shell::ShellExecuteW, WindowsAndMessaging::SW_SHOW},
|
||||
};
|
||||
|
||||
// FIXME: We need to create a memory buffer with the MSI and then run it.
|
||||
// (instead of extracting the MSI to a temp path)
|
||||
@@ -521,131 +525,54 @@ impl Update {
|
||||
// shouldn't drop but we should be able to pass the reference so we can drop it once the installation
|
||||
// is done, otherwise we have a huge memory leak.
|
||||
|
||||
let archive = Cursor::new(bytes);
|
||||
|
||||
let tmp_dir = tempfile::Builder::new().tempdir()?.into_path();
|
||||
|
||||
// extract the buffer to the tmp_dir
|
||||
// we extract our signed archive into our final directory without any temp file
|
||||
let archive = Cursor::new(bytes);
|
||||
let mut extractor = zip::ZipArchive::new(archive)?;
|
||||
|
||||
// extract the msi
|
||||
extractor.extract(&tmp_dir)?;
|
||||
|
||||
let paths = fs::read_dir(&tmp_dir)?;
|
||||
|
||||
let system_root = std::env::var("SYSTEMROOT");
|
||||
let powershell_path = system_root.as_ref().map_or_else(
|
||||
|_| "powershell.exe".to_string(),
|
||||
|p| format!("{p}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"),
|
||||
);
|
||||
|
||||
let install_mode = self
|
||||
.config
|
||||
.windows
|
||||
.as_ref()
|
||||
.map(|w| w.install_mode.clone())
|
||||
.unwrap_or_default();
|
||||
let mut installer_args = self
|
||||
.installer_args
|
||||
.iter()
|
||||
.map(|a| OsStr::new(a))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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 it's an `exe` we expect an NSIS installer.
|
||||
if found_path.extension() == Some(OsStr::new("exe")) {
|
||||
// we need to wrap the installer path in quotes for Start-Process
|
||||
let mut installer_path = std::ffi::OsString::new();
|
||||
installer_path.push("\"");
|
||||
installer_path.push(&found_path);
|
||||
installer_path.push("\"");
|
||||
|
||||
let installer_args = [
|
||||
install_mode
|
||||
.nsis_args()
|
||||
.iter()
|
||||
.map(OsStr::new)
|
||||
.collect::<Vec<_>>(),
|
||||
self.installer_args
|
||||
.iter()
|
||||
.map(|a| a.as_os_str())
|
||||
.collect::<Vec<_>>(),
|
||||
]
|
||||
.concat();
|
||||
|
||||
// Run the installer
|
||||
let mut cmd = Command::new(powershell_path);
|
||||
|
||||
cmd.args(["-NoProfile", "-WindowStyle", "Hidden"])
|
||||
.args(["Start-Process"])
|
||||
.arg(installer_path);
|
||||
|
||||
if !installer_args.is_empty() {
|
||||
cmd.arg("-ArgumentList")
|
||||
.arg(installer_args.join(OsStr::new(", ")));
|
||||
}
|
||||
cmd.spawn().expect("installer failed to start");
|
||||
|
||||
std::process::exit(0);
|
||||
installer_args.extend(install_mode.nsis_args().iter().map(OsStr::new));
|
||||
} else if found_path.extension() == Some(OsStr::new("msi")) {
|
||||
// we need to wrap the current exe path in quotes for Start-Process
|
||||
let mut current_exe_arg = std::ffi::OsString::new();
|
||||
current_exe_arg.push("\"");
|
||||
current_exe_arg.push(current_exe()?);
|
||||
current_exe_arg.push("\"");
|
||||
|
||||
let mut msi_path = std::ffi::OsString::new();
|
||||
msi_path.push("\"\"\"");
|
||||
msi_path.push(&found_path);
|
||||
msi_path.push("\"\"\"");
|
||||
|
||||
let installer_args = [
|
||||
install_mode
|
||||
.msiexec_args()
|
||||
.iter()
|
||||
.map(OsStr::new)
|
||||
.collect::<Vec<_>>(),
|
||||
self.installer_args
|
||||
.iter()
|
||||
.map(|a| a.as_os_str())
|
||||
.collect::<Vec<_>>(),
|
||||
]
|
||||
.concat();
|
||||
|
||||
// run the installer and relaunch the application
|
||||
let powershell_install_res = Command::new(powershell_path)
|
||||
.args(["-NoProfile", "-WindowStyle", "Hidden"])
|
||||
.args([
|
||||
"Start-Process",
|
||||
"-Wait",
|
||||
"-FilePath",
|
||||
"$Env:SYSTEMROOT\\System32\\msiexec.exe",
|
||||
"-ArgumentList",
|
||||
])
|
||||
.arg("/i,")
|
||||
.arg(&msi_path)
|
||||
.arg(format!(
|
||||
", {}, /promptrestart;",
|
||||
installer_args.join(OsStr::new(", ")).to_string_lossy()
|
||||
))
|
||||
.arg("Start-Process")
|
||||
.arg(current_exe_arg)
|
||||
.spawn();
|
||||
if powershell_install_res.is_err() {
|
||||
// fallback to running msiexec directly - relaunch won't be available
|
||||
// we use this here in case powershell fails in an older machine somehow
|
||||
let msiexec_path = system_root.as_ref().map_or_else(
|
||||
|_| "msiexec.exe".to_string(),
|
||||
|p| format!("{p}\\System32\\msiexec.exe"),
|
||||
);
|
||||
let _ = Command::new(msiexec_path)
|
||||
.arg("/i")
|
||||
.arg(msi_path)
|
||||
.args(installer_args)
|
||||
.arg("/promptrestart")
|
||||
.spawn();
|
||||
}
|
||||
|
||||
std::process::exit(0);
|
||||
installer_args.extend(install_mode.msiexec_args().iter().map(OsStr::new));
|
||||
installer_args.push(OsStr::new("/promptrestart"));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
let file = encode_wide(found_path.as_os_str());
|
||||
let parameters = encode_wide(installer_args.join(OsStr::new(" ")).as_os_str());
|
||||
let ret = unsafe {
|
||||
ShellExecuteW(
|
||||
0,
|
||||
w!("open"),
|
||||
file.as_ptr(),
|
||||
parameters.as_ptr(),
|
||||
std::ptr::null(),
|
||||
SW_SHOW,
|
||||
)
|
||||
};
|
||||
if ret <= 32 {
|
||||
return Err(Error::Io(std::io::Error::last_os_error()));
|
||||
}
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -944,3 +871,14 @@ fn base64_to_string(base64_string: &str) -> Result<String> {
|
||||
.to_string();
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn encode_wide(string: impl AsRef<OsStr>) -> Vec<u16> {
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
|
||||
string
|
||||
.as_ref()
|
||||
.encode_wide()
|
||||
.chain(std::iter::once(0))
|
||||
.collect()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user