mirror of
https://github.com/t8y2/dbx.git
synced 2026-10-02 02:34:42 +08:00
@@ -170,6 +170,11 @@ fn sha256_hex(bytes: &[u8]) -> String {
|
||||
Sha256::digest(bytes).iter().map(|byte| format!("{byte:02x}")).collect()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "windows", test))]
|
||||
fn portable_update_staging_dir(executable_dir: &std::path::Path, update_id: &str) -> std::path::PathBuf {
|
||||
executable_dir.join(format!(".dbx-portable-update-{update_id}"))
|
||||
}
|
||||
|
||||
/// Windows PowerShell lives in a versioned directory that Rust's executable
|
||||
/// search order never visits (it only probes the `System32` root), so a machine
|
||||
/// whose `PATH` lost that entry fails with "program not found" even though
|
||||
@@ -215,7 +220,10 @@ pub(super) fn launch_portable_update_helper(archive: &[u8], version: &Version) -
|
||||
fs::remove_file(&write_probe)
|
||||
.map_err(|error| format!("Failed to finish portable directory write check: {error}"))?;
|
||||
|
||||
let staging_dir = std::env::temp_dir().join(format!("dbx-portable-update-{update_id}"));
|
||||
// Keep the replacement and helper on the target volume. Windows
|
||||
// PowerShell cannot reliably Move-Item an executable across volumes after
|
||||
// the running target has already been renamed to its backup.
|
||||
let staging_dir = portable_update_staging_dir(exe_dir, &update_id);
|
||||
fs::create_dir(&staging_dir)
|
||||
.map_err(|error| format!("Failed to create portable update staging directory: {error}"))?;
|
||||
let staged_exe = staging_dir.join("DBX.exe.new");
|
||||
@@ -273,7 +281,7 @@ pub(super) fn launch_portable_update_helper(_archive: &[u8], _version: &Version)
|
||||
Err("Portable updates are only supported on Windows.".to_string())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(any(target_os = "windows", test))]
|
||||
const PORTABLE_UPDATE_SCRIPT: &str = r#"param(
|
||||
[Parameter(Mandatory = $true)][int]$ParentProcessId,
|
||||
[Parameter(Mandatory = $true)][string]$SourceExe,
|
||||
@@ -337,9 +345,9 @@ exit 0
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{
|
||||
decode_tauri_text, portable_asset_name, sha256_hex, validate_requested_portable_version,
|
||||
validated_portable_executable, PORTABLE_EXECUTABLE_NAME, PORTABLE_UPDATE_MANIFEST_NAME,
|
||||
PORTABLE_UPDATE_MANIFEST_SCHEMA_VERSION,
|
||||
decode_tauri_text, portable_asset_name, portable_update_staging_dir, sha256_hex,
|
||||
validate_requested_portable_version, validated_portable_executable, PORTABLE_EXECUTABLE_NAME,
|
||||
PORTABLE_UPDATE_MANIFEST_NAME, PORTABLE_UPDATE_MANIFEST_SCHEMA_VERSION, PORTABLE_UPDATE_SCRIPT,
|
||||
};
|
||||
use base64::{engine::general_purpose::STANDARD as BASE64_STANDARD, Engine as _};
|
||||
use semver::Version;
|
||||
@@ -371,6 +379,38 @@ mod tests {
|
||||
assert!(portable_asset_name("../../0.5.64", "x86_64").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stages_portable_replacement_beside_the_target() {
|
||||
let executable_dir = std::path::Path::new("portable-install");
|
||||
let staging_dir = portable_update_staging_dir(executable_dir, "123-456");
|
||||
|
||||
assert_eq!(staging_dir.parent(), Some(executable_dir));
|
||||
assert_eq!(staging_dir.file_name().and_then(|name| name.to_str()), Some(".dbx-portable-update-123-456"));
|
||||
assert_eq!(staging_dir.join("DBX.exe.new").parent(), Some(staging_dir.as_path()));
|
||||
assert_eq!(staging_dir.join("apply-update.ps1").parent(), Some(staging_dir.as_path()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn portable_update_script_preserves_replacement_and_rollback_order() {
|
||||
let backup = PORTABLE_UPDATE_SCRIPT
|
||||
.find("Move-Item -LiteralPath $TargetExe -Destination $BackupExe -Force")
|
||||
.expect("script must back up the running executable");
|
||||
let replacement = PORTABLE_UPDATE_SCRIPT
|
||||
.find("Move-Item -LiteralPath $SourceExe -Destination $TargetExe -Force")
|
||||
.expect("script must install the staged executable");
|
||||
let relaunch = PORTABLE_UPDATE_SCRIPT
|
||||
.find("Start-Process -FilePath $TargetExe")
|
||||
.expect("script must relaunch the portable executable");
|
||||
let cleanup = PORTABLE_UPDATE_SCRIPT
|
||||
.find("Remove-Item -LiteralPath $StagingDir -Recurse -Force")
|
||||
.expect("script must clean the staging directory after relaunch");
|
||||
|
||||
assert!(backup < replacement);
|
||||
assert!(replacement < relaunch);
|
||||
assert!(relaunch < cleanup);
|
||||
assert!(PORTABLE_UPDATE_SCRIPT.contains("Copy-Item -LiteralPath $BackupExe -Destination $TargetExe -Force"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_newer_portable_update_requests() {
|
||||
assert_eq!(validate_requested_portable_version("0.5.64", "0.5.63").unwrap(), Version::parse("0.5.64").unwrap());
|
||||
|
||||
Reference in New Issue
Block a user