diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock index 92285f3a..78b631b0 100644 --- a/src/Rust/Cargo.lock +++ b/src/Rust/Cargo.lock @@ -91,9 +91,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca87830a3e3fb156dc96cfbd31cb620265dd053be734723f22b760d6cc3c3051" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" [[package]] name = "as-slice" @@ -234,7 +234,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -517,7 +517,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -999,7 +999,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -1087,18 +1087,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.72" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a293318316cf6478ec1ad2a21c49390a8d5b5eae9fab736467d93fbc0edc29c5" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -1191,7 +1191,7 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "remove_dir_all" version = "0.8.2" -source = "git+https://github.com/caesay/remove_dir_all.git#f70d40ad7b6bb655a7a36268cd7cc5ea8e015c6d" +source = "git+https://github.com/caesay/remove_dir_all.git#c98142b9150c53e6c5f56e752d2bf93433f2e207" dependencies = [ "cfg-if", "cvt", @@ -1277,28 +1277,28 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" [[package]] name = "serde" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.193" +version = "1.0.194" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -1390,7 +1390,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -1406,9 +1406,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" dependencies = [ "proc-macro2", "quote", @@ -1439,22 +1439,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", ] [[package]] @@ -1637,6 +1637,7 @@ dependencies = [ "simple-stopwatch", "simplelog", "strum", + "tempfile", "ureq", "wait-timeout", "waitpid-any", @@ -1717,7 +1718,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", "wasm-bindgen-shared", ] @@ -1739,7 +1740,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.46", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -2028,9 +2029,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.31" +version = "0.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a4882e6b134d6c28953a387571f1acdd3496830d5e36c5e3a1075580ea641c" +checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6" dependencies = [ "memchr", ] diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml index 4be7aca8..0902e25b 100644 --- a/src/Rust/Cargo.toml +++ b/src/Rust/Cargo.toml @@ -72,7 +72,6 @@ enum-flags = "0.3" remove_dir_all = { git = "https://github.com/caesay/remove_dir_all.git", features = [ "log", ] } -ntest = "0.9.0" zstd = "0.13" sha1_smol = "1.0" runas = "1.1" @@ -131,6 +130,10 @@ windows-sys = { version = "0.52", default-features = false, features = [ normpath = "1.0.1" codesign-verify = { git = "https://github.com/caesay/codesign-verify-rs.git" } +[dev-dependencies] +tempfile = "3.9" +ntest = "0.9.0" + [build-dependencies] semver = "1.0" diff --git a/src/Rust/src/commands/install.rs b/src/Rust/src/commands/install.rs index ac2a279d..87bf2dcf 100644 --- a/src/Rust/src/commands/install.rs +++ b/src/Rust/src/commands/install.rs @@ -10,7 +10,7 @@ use std::{ }; use winsafe::{self as w, co}; -pub fn install(debug_pkg: &Option<&PathBuf>, install_to: &Option<&PathBuf>) -> Result<()> { +pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Result<()> { let osinfo = os_info::get(); info!("OS: {}, Arch={}", osinfo, osinfo.architecture().unwrap_or("unknown")); diff --git a/src/Rust/src/commands/patch.rs b/src/Rust/src/commands/patch.rs index a4e849d6..ddb5b22b 100644 --- a/src/Rust/src/commands/patch.rs +++ b/src/Rust/src/commands/patch.rs @@ -25,44 +25,3 @@ pub fn patch(old_file: &PathBuf, patch_file: &PathBuf, output_file: &PathBuf) -> Ok(()) } - -#[test] -fn test_patch_apply() { - - fn find_fixtures() -> PathBuf { - let mut path = std::env::current_exe().unwrap(); - while !path.join("Velopack.sln").exists() { - path.pop(); - } - path.push("test"); - path.push("fixtures"); - path - } - - let path = find_fixtures(); - - let old_file = path.join("obs29.1.2.dll"); - let new_file = path.join("obs30.0.2.dll"); - let p1 = path.join("obs-size.patch"); - let p2 = path.join("obs-speed.patch"); - - fn get_sha1(file: &PathBuf) -> String { - let file_bytes = fs::read(file).unwrap(); - let mut sha1 = sha1_smol::Sha1::new(); - sha1.update(&file_bytes); - sha1.digest().to_string() - } - - let expected_sha1 = get_sha1(&new_file); - let tmp_file = std::path::Path::new("temp.patch").to_path_buf(); - - patch(&old_file, &p1, &tmp_file).unwrap(); - let tmp_sha1 = get_sha1(&tmp_file); - fs::remove_file(&tmp_file).unwrap(); - assert_eq!(expected_sha1, tmp_sha1); - - patch(&old_file, &p2, &tmp_file).unwrap(); - let tmp_sha1 = get_sha1(&tmp_file); - fs::remove_file(&tmp_file).unwrap(); - assert_eq!(expected_sha1, tmp_sha1); -} diff --git a/src/Rust/src/commands/uninstall.rs b/src/Rust/src/commands/uninstall.rs index 6a07d829..1f48f283 100644 --- a/src/Rust/src/commands/uninstall.rs +++ b/src/Rust/src/commands/uninstall.rs @@ -4,9 +4,8 @@ use anyhow::Result; use std::fs::File; use std::path::PathBuf; -pub fn uninstall() -> Result<()> { +pub fn uninstall(root_path: &PathBuf, app: &Manifest, delete_self: bool) -> Result<()> { info!("Command: Uninstall"); - let (root_path, app) = shared::detect_current_manifest()?; fn _uninstall_impl(app: &Manifest, root_path: &PathBuf) -> bool { // the real app could be running at the moment @@ -23,7 +22,7 @@ pub fn uninstall() -> Result<()> { } info!("Removing directory '{}'", root_path.to_string_lossy()); - if let Err(e) = shared::retry_io(|| remove_dir_all::remove_dir_containing_current_executable()) { + if let Err(e) = shared::retry_io(|| remove_dir_all::remove_dir_but_not_self(&root_path)) { error!("Unable to remove directory, some files may be in use ({}).", e); finished_with_errors = true; } @@ -50,8 +49,11 @@ pub fn uninstall() -> Result<()> { let dead_path = root_path.join(".dead"); let _ = File::create(dead_path); - if let Err(e) = windows::register_intent_to_delete_self(3, &root_path) { - warn!("Unable to schedule self delete ({}).", e); + + if delete_self { + if let Err(e) = windows::register_intent_to_delete_self(3, &root_path) { + warn!("Unable to schedule self delete ({}).", e); + } } Ok(()) diff --git a/src/Rust/src/setup.rs b/src/Rust/src/setup.rs index cd2dece5..637fa56e 100644 --- a/src/Rust/src/setup.rs +++ b/src/Rust/src/setup.rs @@ -43,7 +43,7 @@ fn main() -> Result<()> { info!(" Debug: {:?}", debug); } - let res = commands::install(&debug, &installto); + let res = commands::install(debug, installto); if let Err(e) = &res { error!("An error has occurred: {}", e); dialogs::show_error("Setup Error", None, format!("An error has occurred: {}", e).as_str()); diff --git a/src/Rust/src/shared/bundle.rs b/src/Rust/src/shared/bundle.rs index eb2d8aa6..59d7c1ba 100644 --- a/src/Rust/src/shared/bundle.rs +++ b/src/Rust/src/shared/bundle.rs @@ -44,7 +44,7 @@ pub fn header_offset_and_length() -> (i64, i64) { } #[cfg(target_os = "windows")] -pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: &Option<&PathBuf>) -> Result> { +pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: Option<&PathBuf>) -> Result> { info!("Reading bundle header..."); let (offset, length) = header_offset_and_length(); info!("Bundle offset = {}, length = {}", offset, length); @@ -63,7 +63,7 @@ pub fn load_bundle_from_mmap<'a>(mmap: &'a Mmap, debug_pkg: &Option<&PathBuf>) - if cfg!(debug_assertions) { if let Some(pkg) = debug_pkg { info!("Loading bundle from debug nupkg file..."); - return load_bundle_from_file(pkg.to_owned()); + return load_bundle_from_file(pkg); } } diff --git a/src/Rust/src/shared/util_osx.rs b/src/Rust/src/shared/util_osx.rs index c3d2dcf5..32871f84 100644 --- a/src/Rust/src/shared/util_osx.rs +++ b/src/Rust/src/shared/util_osx.rs @@ -43,8 +43,8 @@ pub fn start_package>(_app: &Manifest, root_dir: P, exe_args: Opt Ok(()) } -pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { - let mut manifest_path = std::env::current_exe()?; +pub fn detect_manifest_from_update_path(update_exe: &PathBuf) -> Result<(PathBuf, Manifest)> { + let mut manifest_path = update_exe.clone(); manifest_path.pop(); manifest_path.push("sq.version"); let manifest = load_manifest(&manifest_path)?; @@ -64,6 +64,11 @@ pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { Ok((Path::new(&root_dir).to_path_buf(), manifest)) } +pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { + let me = std::env::current_exe()?; + detect_manifest_from_update_path(&me) +} + fn load_manifest(nuspec_path: &PathBuf) -> Result { if Path::new(&nuspec_path).exists() { if let Ok(nuspec) = super::retry_io(|| std::fs::read_to_string(&nuspec_path)) { diff --git a/src/Rust/src/shared/util_windows.rs b/src/Rust/src/shared/util_windows.rs index 711ecf03..69472582 100644 --- a/src/Rust/src/shared/util_windows.rs +++ b/src/Rust/src/shared/util_windows.rs @@ -156,14 +156,8 @@ pub fn start_package>(app: &Manifest, root_dir: P, exe_args: Opti Ok(()) } -fn get_my_root_dir() -> Result { - let mut my_dir = std::env::current_exe()?; - my_dir.pop(); - Ok(my_dir) -} - -pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { - let root_path = get_my_root_dir()?; +pub fn detect_manifest_from_update_path(update_exe: &PathBuf) -> Result<(PathBuf, Manifest)> { + let root_path = update_exe.parent().unwrap().to_path_buf(); let app = find_manifest_from_root_dir(&root_path) .map_err(|m| anyhow!("Unable to read application manifest ({}). Is this a properly installed application?", m))?; info!("Loaded manifest for application: {}", app.id); @@ -171,6 +165,11 @@ pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { Ok((root_path, app)) } +pub fn detect_current_manifest() -> Result<(PathBuf, Manifest)> { + let me = std::env::current_exe()?; + detect_manifest_from_update_path(&me) +} + fn find_manifest_from_root_dir(root_path: &PathBuf) -> Result { // default to checking current/sq.version let cm = find_current_manifest(root_path); diff --git a/src/Rust/src/update.rs b/src/Rust/src/update.rs index c8ed0557..f9d49925 100644 --- a/src/Rust/src/update.rs +++ b/src/Rust/src/update.rs @@ -160,7 +160,8 @@ fn start(matches: &ArgMatches) -> Result<()> { #[cfg(target_os = "windows")] fn uninstall(_matches: &ArgMatches) -> Result<()> { info!("Command: Uninstall"); - commands::uninstall() + let (root_path, app) = shared::detect_current_manifest()?; + commands::uninstall(&root_path, &app, true) } #[cfg(target_os = "windows")] diff --git a/src/Rust/tests/commands.rs b/src/Rust/tests/commands.rs new file mode 100644 index 00000000..cdb1c62f --- /dev/null +++ b/src/Rust/tests/commands.rs @@ -0,0 +1,75 @@ +mod common; +use common::*; +use std::{fs, path::Path, path::PathBuf}; +use tempfile::tempdir; +use velopack::*; + +#[cfg(target_os = "windows")] +use winsafe::{self as w, co}; + +#[cfg(target_os = "windows")] +#[test] +pub fn test_install_uninstall() { + logging::trace_logger(); + dialogs::set_silent(true); + let fixtures = find_fixtures(); + + let app_id = "AvaloniaCrossPlat"; + let pkg_name = "AvaloniaCrossPlat-1.0.11-win-full.nupkg"; + + let startmenu = w::SHGetKnownFolderPath(&co::KNOWNFOLDERID::StartMenu, co::KF::DONT_UNEXPAND, None).unwrap(); + let lnk_path = Path::new(&startmenu).join("Programs").join(format!("{}.lnk", app_id)); + if lnk_path.exists() { + fs::remove_file(&lnk_path).unwrap(); + } + + let nupkg = fixtures.join(pkg_name); + + let tmp_dir = tempdir().unwrap(); + let tmp_buf = tmp_dir.path().to_path_buf(); + commands::install(Some(&nupkg), Some(&tmp_buf)).unwrap(); + + assert!(lnk_path.exists()); + assert!(tmp_buf.join("Update.exe").exists()); + assert!(tmp_buf.join("current").join("AvaloniaCrossPlat.exe").exists()); + assert!(tmp_buf.join("current").join("sq.version").exists()); + + let (root_dir, app) = shared::detect_manifest_from_update_path(&tmp_buf.join("Update.exe")).unwrap(); + assert_eq!(app_id, app.id); + + commands::uninstall(&root_dir, &app, false).unwrap(); + assert!(!tmp_buf.join("current").exists()); + assert!(tmp_buf.join(".dead").exists()); + assert!(!lnk_path.exists()); +} + +#[test] +pub fn test_patch_apply() { + dialogs::set_silent(true); + let fixtures = find_fixtures(); + + let old_file = fixtures.join("obs29.1.2.dll"); + let new_file = fixtures.join("obs30.0.2.dll"); + let p1 = fixtures.join("obs-size.patch"); + let p2 = fixtures.join("obs-speed.patch"); + + fn get_sha1(file: &PathBuf) -> String { + let file_bytes = fs::read(file).unwrap(); + let mut sha1 = sha1_smol::Sha1::new(); + sha1.update(&file_bytes); + sha1.digest().to_string() + } + + let expected_sha1 = get_sha1(&new_file); + let tmp_file = std::path::Path::new("temp.patch").to_path_buf(); + + commands::patch(&old_file, &p1, &tmp_file).unwrap(); + let tmp_sha1 = get_sha1(&tmp_file); + fs::remove_file(&tmp_file).unwrap(); + assert_eq!(expected_sha1, tmp_sha1); + + commands::patch(&old_file, &p2, &tmp_file).unwrap(); + let tmp_sha1 = get_sha1(&tmp_file); + fs::remove_file(&tmp_file).unwrap(); + assert_eq!(expected_sha1, tmp_sha1); +} diff --git a/src/Rust/tests/common/mod.rs b/src/Rust/tests/common/mod.rs new file mode 100644 index 00000000..acf3d59a --- /dev/null +++ b/src/Rust/tests/common/mod.rs @@ -0,0 +1,11 @@ +use std::path::PathBuf; + +pub fn find_fixtures() -> PathBuf { + let mut path = std::env::current_exe().unwrap(); + while !path.join("Velopack.sln").exists() { + path.pop(); + } + path.push("test"); + path.push("fixtures"); + path +} \ No newline at end of file diff --git a/test/fixtures/AvaloniaCrossPlat-1.0.11-win-full.nupkg b/test/fixtures/AvaloniaCrossPlat-1.0.11-win-full.nupkg new file mode 100644 index 00000000..3de16632 Binary files /dev/null and b/test/fixtures/AvaloniaCrossPlat-1.0.11-win-full.nupkg differ