diff --git a/src/Rust/src/commands/apply.rs b/src/Rust/src/commands/apply.rs index f202c937..28db4b7e 100644 --- a/src/Rust/src/commands/apply.rs +++ b/src/Rust/src/commands/apply.rs @@ -8,14 +8,20 @@ use glob::glob; use runas::Command as RunAsCommand; use std::path::PathBuf; -pub fn apply<'a>(restart: bool, wait_for_parent: bool, package: Option<&PathBuf>, exe_args: Option>, noelevate: bool) -> Result<()> { +pub fn apply<'a>( + root_path: &PathBuf, + app: &Manifest, + restart: bool, + wait_for_parent: bool, + package: Option<&PathBuf>, + exe_args: Option>, + noelevate: bool, +) -> Result<()> { if wait_for_parent { let _ = shared::wait_for_parent_to_exit(60_000); // 1 minute } - let (root_path, app) = shared::detect_current_manifest()?; - - if let Err(e) = apply_package(package, &app, &root_path, noelevate, restart, exe_args.clone()) { + if let Err(e) = apply_package(&root_path, &app, restart, package, exe_args.clone(), noelevate) { error!("Error applying package: {}", e); if !restart { return Err(e); @@ -30,7 +36,14 @@ pub fn apply<'a>(restart: bool, wait_for_parent: bool, package: Option<&PathBuf> Ok(()) } -fn apply_package<'a>(package: Option<&PathBuf>, app: &Manifest, root_path: &PathBuf, noelevate: bool, restart: bool, exe_args: Option>) -> Result<()> { +fn apply_package<'a>( + root_path: &PathBuf, + app: &Manifest, + restart: bool, + package: Option<&PathBuf>, + exe_args: Option>, + noelevate: bool, +) -> Result<()> { let mut package_manifest: Option = None; let mut package_bundle: Option> = None; diff --git a/src/Rust/src/update.rs b/src/Rust/src/update.rs index f9d49925..48755ad6 100644 --- a/src/Rust/src/update.rs +++ b/src/Rust/src/update.rs @@ -135,7 +135,8 @@ fn apply(matches: &ArgMatches) -> Result<()> { info!(" Exe Args: {:?}", exe_args); info!(" No Elevate: {}", noelevate); - commands::apply(restart, wait_for_parent, package, exe_args, noelevate) + let (root_path, app) = shared::detect_current_manifest()?; + commands::apply(&root_path, &app, restart, wait_for_parent, package, exe_args, noelevate) } #[cfg(target_os = "windows")] diff --git a/src/Rust/src/windows/util.rs b/src/Rust/src/windows/util.rs index 753604a2..44a2d596 100644 --- a/src/Rust/src/windows/util.rs +++ b/src/Rust/src/windows/util.rs @@ -34,14 +34,26 @@ pub fn run_hook(app: &shared::bundle::Manifest, root_path: &PathBuf, hook_name: let _ = shared::force_stop_package(&root_path); } -pub fn create_global_mutex(app: &shared::bundle::Manifest) -> Result { +pub struct MutexDropGuard { + mutex: Foundation::HANDLE, +} + +impl Drop for MutexDropGuard { + fn drop(&mut self) { + unsafe { + Foundation::CloseHandle(self.mutex).ok(); + } + } +} + +pub fn create_global_mutex(app: &shared::bundle::Manifest) -> Result { let mutex_name = format!("velopack-{}", &app.id); info!("Attempting to open global system mutex: '{}'", &mutex_name); let encoded = mutex_name.encode_utf16().chain([0u16]).collect::>(); let pw = PCWSTR(encoded.as_ptr()); let mutex = unsafe { CreateMutexW(None, true, pw) }?; match unsafe { GetLastError() } { - Ok(_) => Ok(mutex), + Ok(_) => Ok(MutexDropGuard { mutex }), Err(err) => { if err == Foundation::ERROR_ALREADY_EXISTS.into() { bail!("Another installer or updater for this application is running, quit that process and try again."); @@ -387,4 +399,4 @@ fn test_authenticode() { assert!(verify_authenticode_against_powershell(r"C:\Users\Caelan\AppData\Local\Programs\Microsoft VS Code\Code.exe")); assert!(!verify_authenticode_against_powershell(r"C:\Users\Caelan\AppData\Local\Clowd\Update.exe")); assert!(!verify_authenticode_against_powershell(r"C:\Users\Caelan\.cargo\bin\cargo.exe")); -} \ No newline at end of file +} diff --git a/src/Rust/tests/commands.rs b/src/Rust/tests/commands.rs index cdb1c62f..f85149db 100644 --- a/src/Rust/tests/commands.rs +++ b/src/Rust/tests/commands.rs @@ -9,8 +9,7 @@ use winsafe::{self as w, co}; #[cfg(target_os = "windows")] #[test] -pub fn test_install_uninstall() { - logging::trace_logger(); +pub fn test_install_apply_uninstall() { dialogs::set_silent(true); let fixtures = find_fixtures(); @@ -36,6 +35,14 @@ pub fn test_install_uninstall() { let (root_dir, app) = shared::detect_manifest_from_update_path(&tmp_buf.join("Update.exe")).unwrap(); assert_eq!(app_id, app.id); + assert!(semver::Version::parse("1.0.11").unwrap() == app.version); + + let pkg_name_apply = "AvaloniaCrossPlat-1.0.15-win-full.nupkg"; + let nupkg_apply = fixtures.join(pkg_name_apply); + commands::apply(&root_dir, &app, false, false, Some(&nupkg_apply), None, true).unwrap(); + + let (root_dir, app) = shared::detect_manifest_from_update_path(&tmp_buf.join("Update.exe")).unwrap(); + assert!(semver::Version::parse("1.0.15").unwrap() == app.version); commands::uninstall(&root_dir, &app, false).unwrap(); assert!(!tmp_buf.join("current").exists()); diff --git a/test/fixtures/AvaloniaCrossPlat-1.0.15-win-full.nupkg b/test/fixtures/AvaloniaCrossPlat-1.0.15-win-full.nupkg new file mode 100644 index 00000000..3d5217d0 Binary files /dev/null and b/test/fixtures/AvaloniaCrossPlat-1.0.15-win-full.nupkg differ