diff --git a/Cargo.lock b/Cargo.lock index 8e527ba..e85f6c4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -119,19 +130,24 @@ dependencies = [ [[package]] name = "axoasset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dce2f189800bafe8322ef3a4d361ee7373bfc2f8fe052afda404230166dc45f" +checksum = "5e05853b0d9abfab8e7532cad0d07ec396dd95c1a81926b49ab3cfa121a9d8d6" dependencies = [ "camino", + "flate2", "image", "miette 7.2.0", "mime", "serde", "serde_json", + "tar", "thiserror", "url", "walkdir", + "xz2", + "zip", + "zstd 0.13.1", ] [[package]] @@ -166,7 +182,7 @@ dependencies = [ name = "axoupdater" version = "0.3.3" dependencies = [ - "axoasset 0.9.0", + "axoasset 0.9.1", "axoprocess", "camino", "gazenot", @@ -183,10 +199,15 @@ dependencies = [ name = "axoupdater-cli" version = "0.3.3" dependencies = [ + "axoasset 0.9.1", "axocli", + "axoprocess", "axoupdater", + "camino", "clap", "miette 7.2.0", + "reqwest", + "temp-dir", ] [[package]] @@ -231,6 +252,12 @@ version = "0.21.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c79fed4cdb43e993fcdadc7e58a09fd0e3e649c4436fa11da71c9f1f3ee7feb9" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -243,6 +270,15 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -267,6 +303,27 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "camino" version = "1.1.6" @@ -282,6 +339,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -304,6 +362,16 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.5.4" @@ -369,6 +437,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "core-foundation" version = "0.9.4" @@ -385,6 +459,15 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + [[package]] name = "crc32fast" version = "1.3.2" @@ -394,6 +477,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "dyn-clone" version = "1.0.16" @@ -440,6 +559,18 @@ dependencies = [ "instant", ] +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + [[package]] name = "flate2" version = "1.0.28" @@ -574,6 +705,16 @@ dependencies = [ "url", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -628,6 +769,15 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "homedir" version = "0.2.1" @@ -770,6 +920,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -797,6 +956,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.66" @@ -840,6 +1008,17 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "memchr" version = "2.7.1" @@ -958,6 +1137,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-integer" version = "0.1.45" @@ -1048,6 +1233,29 @@ dependencies = [ "windows-targets 0.48.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest", + "hmac", + "password-hash", + "sha2", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -1086,6 +1294,18 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "proc-macro2" version = "1.0.78" @@ -1104,6 +1324,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + [[package]] name = "redox_syscall" version = "0.4.1" @@ -1329,6 +1555,28 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sharded-slab" version = "0.1.7" @@ -1390,6 +1638,12 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "supports-color" version = "3.0.0" @@ -1460,6 +1714,17 @@ dependencies = [ "libc", ] +[[package]] +name = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "temp-dir" version = "0.1.13" @@ -1517,6 +1782,25 @@ dependencies = [ "once_cell", ] +[[package]] +name = "time" +version = "0.3.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749" +dependencies = [ + "deranged", + "num-conv", + "powerfmt", + "serde", + "time-core", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + [[package]] name = "tinyvec" version = "1.6.0" @@ -1656,6 +1940,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-bidi" version = "0.3.14" @@ -1719,6 +2009,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.4.0" @@ -2060,3 +2356,90 @@ dependencies = [ "thiserror", "windows", ] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" +dependencies = [ + "zstd-safe 7.1.0", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-safe" +version = "7.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd99b45c6bc03a018c8b8a86025678c87e55526064e38f9df301989dce7ec0a" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/axoupdater-cli/Cargo.toml b/axoupdater-cli/Cargo.toml index 01e60da..b80f236 100644 --- a/axoupdater-cli/Cargo.toml +++ b/axoupdater-cli/Cargo.toml @@ -18,5 +18,17 @@ clap = { version = "4.5.4", features = ["derive"] } # errors miette = "7.2.0" +[dev-dependencies] +axoasset = { version = "0.9.1", default-features = false, features = [ + "compression", "compression-tar", "compression-zip" +] } +axoprocess = "0.2.0" +camino = { version = "1.1.6", features = ["serde1"] } +reqwest = { version = ">=0.11.0", default-features = false, features = [ + "blocking", + "rustls-tls", +] } +temp-dir = "0.1.13" + [[bin]] name = "axoupdater" diff --git a/axoupdater-cli/tests/integration.rs b/axoupdater-cli/tests/integration.rs new file mode 100644 index 0000000..63f3a5a --- /dev/null +++ b/axoupdater-cli/tests/integration.rs @@ -0,0 +1,236 @@ +use std::io::Read; + +use axoasset::LocalAsset; +use axoprocess::Cmd; +use camino::{Utf8Path, Utf8PathBuf}; +use temp_dir::TempDir; + +static BIN: &str = env!("CARGO_BIN_EXE_axoupdater"); +static RECEIPT_TEMPLATE: &str = r#"{"binaries":["axolotlsay"],"install_prefix":"INSTALL_PREFIX","provider":{"source":"cargo-dist","version":"0.11.1"},"source":{"app_name":"axolotlsay","name":"cargodisttest","owner":"mistydemeo","release_type":"github"},"version":"VERSION"}"#; + +// Handle aarch64 later +fn triple() -> String { + match std::env::consts::OS { + "windows" => { + if std::env::consts::ARCH == "x86_64" { + "x86_64-pc-windows-msvc".to_owned() + } else { + "aarch64-pc-windows-msvc".to_owned() + } + } + "macos" => { + if std::env::consts::ARCH == "x86_64" { + "x86_64-apple-darwin".to_owned() + } else { + "aarch64-apple-darwin".to_owned() + } + } + "linux" => { + if std::env::consts::ARCH == "x86_64" { + "x86_64-unknown-linux-gnu".to_owned() + } else { + "aarch64-unknown-linux-gnu".to_owned() + } + } + _ => unimplemented!(), + } +} + +fn axolotlsay_tarball_path(version: &str) -> String { + let triple = triple(); + format!("https://github.com/mistydemeo/cargodisttest/releases/download/v{version}/axolotlsay-{triple}.tar.gz") +} + +fn install_receipt(version: &str, prefix: &Utf8PathBuf) -> String { + RECEIPT_TEMPLATE + .replace("INSTALL_PREFIX", prefix.as_ref()) + .replace("VERSION", version) +} + +fn write_receipt(version: &str, prefix: &Utf8PathBuf) -> std::io::Result<()> { + let contents = install_receipt(version, prefix); + let receipt_name = prefix.join("axolotlsay-receipt.json"); + LocalAsset::write_new(&contents, receipt_name).unwrap(); + + Ok(()) +} + +#[test] +fn bails_out_with_default_name() { + let mut command = Cmd::new(BIN, "execute axoupdater"); + command.check(false); + let result = command.output().unwrap(); + assert!(!result.status.success()); + + let stderr_string = String::from_utf8(result.stderr).unwrap(); + assert!(stderr_string.contains("App name calculated as `axoupdater'")); +} + +// Performs an in-place upgrade from an old version to a newer one. +// The process runs like so: +// * Simulate an install of axolotlsay into a temporary directory +// * Write an install receipt to that path +// * Copy this repo's copy of axoupdater into the temporary directory in place of the one that axolotlsay once came with +// * Run axoupdater +// * Confirm that the new binary exists and is a newer version than the one we had before +// +// NOTE: axolotlsay 0.2.115 is a good base version to use because it contains a +// several noteworthy bugfixes in its installer. +#[test] +fn test_upgrade() -> std::io::Result<()> { + let tempdir = TempDir::new()?; + let bindir_path = &tempdir.path().join("bin"); + let bindir = Utf8Path::from_path(bindir_path).unwrap(); + std::fs::create_dir_all(bindir)?; + + let base_version = "0.2.115"; + + let url = axolotlsay_tarball_path(base_version); + + let mut response = reqwest::blocking::get(url) + .unwrap() + .error_for_status() + .unwrap(); + + let compressed_path = + Utf8PathBuf::from_path_buf(tempdir.path().join("axolotlsay.tar.gz")).unwrap(); + let mut contents = vec![]; + response.read_to_end(&mut contents)?; + std::fs::write(&compressed_path, contents)?; + + // Write the receipt for the updater to use + write_receipt(base_version, &bindir.to_path_buf())?; + + LocalAsset::untar_gz_all(&compressed_path, bindir).unwrap(); + + // Now install our copy of the updater instead of the one axolotlsay came with + let updater_path = bindir.join("axolotlsay-update"); + std::fs::copy(BIN, &updater_path)?; + + let mut updater = Cmd::new(&updater_path, "run updater"); + updater.env("AXOUPDATER_CONFIG_PATH", bindir); + // We'll do that manually + updater.check(false); + let result = updater.output(); + assert!(result.is_ok()); + + // Now let's check the version we just updated to + let new_axolotlsay_path = &bindir.join("axolotlsay"); + assert!(new_axolotlsay_path.exists()); + let mut new_axolotlsay = Cmd::new(new_axolotlsay_path, "version test"); + new_axolotlsay.arg("--version"); + let output = new_axolotlsay.output().unwrap(); + let stderr_string = String::from_utf8(output.stdout).unwrap(); + assert!(stderr_string.starts_with("axolotlsay ")); + assert_ne!(stderr_string, format!("axolotlsay {}\n", base_version)); + + Ok(()) +} + +// A similar test to the one above, but it upgrades to a specific version +// instead of whatever's latest. +#[test] +fn test_upgrade_to_specific_version() -> std::io::Result<()> { + let tempdir = TempDir::new()?; + let bindir_path = &tempdir.path().join("bin"); + let bindir = Utf8Path::from_path(bindir_path).unwrap(); + std::fs::create_dir_all(bindir)?; + + let base_version = "0.2.115"; + let target_version = "0.2.116"; + + let url = axolotlsay_tarball_path(base_version); + + let mut response = reqwest::blocking::get(url) + .unwrap() + .error_for_status() + .unwrap(); + + let compressed_path = + Utf8PathBuf::from_path_buf(tempdir.path().join("axolotlsay.tar.gz")).unwrap(); + let mut contents = vec![]; + response.read_to_end(&mut contents)?; + std::fs::write(&compressed_path, contents)?; + + // Write the receipt for the updater to use + write_receipt(base_version, &bindir.to_path_buf())?; + + LocalAsset::untar_gz_all(&compressed_path, bindir).unwrap(); + + // Now install our copy of the updater instead of the one axolotlsay came with + let updater_path = bindir.join("axolotlsay-update"); + std::fs::copy(BIN, &updater_path)?; + + let mut updater = Cmd::new(&updater_path, "run updater"); + updater.arg("--version").arg(target_version); + updater.env("AXOUPDATER_CONFIG_PATH", bindir); + // We'll do that manually + updater.check(false); + let result = updater.output(); + assert!(result.is_ok()); + + // Now let's check the version we just updated to + let new_axolotlsay_path = &bindir.join("axolotlsay"); + assert!(new_axolotlsay_path.exists()); + let mut new_axolotlsay = Cmd::new(new_axolotlsay_path, "version test"); + new_axolotlsay.arg("--version"); + let output = new_axolotlsay.output().unwrap(); + let stderr_string = String::from_utf8(output.stdout).unwrap(); + assert_eq!(stderr_string, format!("axolotlsay {}\n", target_version)); + + Ok(()) +} + +// A similar test to the one above, but it actually downgrades to an older +// version on request instead of upgrading. +#[test] +fn test_downgrade_to_specific_version() -> std::io::Result<()> { + let tempdir = TempDir::new()?; + let bindir_path = &tempdir.path().join("bin"); + let bindir = Utf8Path::from_path(bindir_path).unwrap(); + std::fs::create_dir_all(bindir)?; + + let base_version = "0.2.116"; + let target_version = "0.2.115"; + + let url = axolotlsay_tarball_path(base_version); + + let mut response = reqwest::blocking::get(url) + .unwrap() + .error_for_status() + .unwrap(); + + let compressed_path = + Utf8PathBuf::from_path_buf(tempdir.path().join("axolotlsay.tar.gz")).unwrap(); + let mut contents = vec![]; + response.read_to_end(&mut contents)?; + std::fs::write(&compressed_path, contents)?; + + // Write the receipt for the updater to use + write_receipt(base_version, &bindir.to_path_buf())?; + + LocalAsset::untar_gz_all(&compressed_path, bindir).unwrap(); + + // Now install our copy of the updater instead of the one axolotlsay came with + let updater_path = bindir.join("axolotlsay-update"); + std::fs::copy(BIN, &updater_path)?; + + let mut updater = Cmd::new(&updater_path, "run updater"); + updater.arg("--version").arg(target_version); + updater.env("AXOUPDATER_CONFIG_PATH", bindir); + // We'll do that manually + updater.check(false); + let result = updater.output(); + assert!(result.is_ok()); + + // Now let's check the version we just updated to + let new_axolotlsay_path = &bindir.join("axolotlsay"); + assert!(new_axolotlsay_path.exists()); + let mut new_axolotlsay = Cmd::new(new_axolotlsay_path, "version test"); + new_axolotlsay.arg("--version"); + let output = new_axolotlsay.output().unwrap(); + let stderr_string = String::from_utf8(output.stdout).unwrap(); + assert_eq!(stderr_string, format!("axolotlsay {}\n", target_version)); + + Ok(()) +} diff --git a/axoupdater/src/lib.rs b/axoupdater/src/lib.rs index 68269aa..5d4a9b5 100644 --- a/axoupdater/src/lib.rs +++ b/axoupdater/src/lib.rs @@ -969,6 +969,8 @@ fn get_app_name() -> Option { fn get_config_path(app_name: &str) -> AxoupdateResult { if env::var("AXOUPDATER_CONFIG_WORKING_DIR").is_ok() { Ok(Utf8PathBuf::try_from(current_dir()?)?) + } else if let Ok(path) = env::var("AXOUPDATER_CONFIG_PATH") { + Ok(Utf8PathBuf::from(path)) } else { let home = if cfg!(windows) { env::var("LOCALAPPDATA").map(PathBuf::from).ok()