diff --git a/Cargo.lock b/Cargo.lock index 0ddb626..b729e06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,6 +32,19 @@ dependencies = [ "libc", ] +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -48,6 +61,7 @@ dependencies = [ "image", "miette", "mime", + "reqwest", "serde", "serde_json", "thiserror", @@ -91,12 +105,26 @@ dependencies = [ "axocli", "axoprocess", "camino", + "gazenot", "homedir", "miette", "reqwest", "serde", "temp-dir", "thiserror", + "tokio", +] + +[[package]] +name = "backon" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c1a6197b2120bb2185a267f6515038558b019e92b832bb0320e96d66268dcf9" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "pin-project", + "tokio", ] [[package]] @@ -237,6 +265,21 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + [[package]] name = "encode_unicode" version = "0.3.6" @@ -268,12 +311,31 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "flate2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + [[package]] name = "fnv" version = "1.0.7" @@ -393,6 +455,37 @@ dependencies = [ "slab", ] +[[package]] +name = "gazenot" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6089542424a1218a8637f37d066850bef5abdfda946464bce8c5865c18425dcb" +dependencies = [ + "axoasset", + "backon", + "camino", + "miette", + "reqwest", + "schemars", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "url", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.28.1" @@ -502,6 +595,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -571,6 +678,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + [[package]] name = "ipnet" version = "2.9.0" @@ -627,6 +743,16 @@ version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + [[package]] name = "log" version = "0.4.20" @@ -858,12 +984,55 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -915,6 +1084,7 @@ version = "0.11.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" dependencies = [ + "async-compression", "base64", "bytes", "encoding_rs", @@ -924,6 +1094,7 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -933,20 +1104,39 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -966,6 +1156,37 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64", +] + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.16" @@ -990,6 +1211,46 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "schemars" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45a28f4c49489add4ce10783f7911893516f15afe45d015608d41faca6bc4d29" +dependencies = [ + "dyn-clone", + "schemars_derive", + "serde", + "serde_json", +] + +[[package]] +name = "schemars_derive" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c767fd6fa65d9ccf9cf026122c1b555f2ef9a4f0cea69da4d7dbc3e258d30967" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 1.0.109", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -1033,6 +1294,17 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_derive_internals" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bf8229e7920a9f636479437026331ce11aa132b4dde37d121944a44d6e5f3c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "serde_json" version = "1.0.111" @@ -1065,6 +1337,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + [[package]] name = "slab" version = "0.4.9" @@ -1096,6 +1377,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "supports-color" version = "2.1.0" @@ -1180,7 +1467,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", - "fastrand", + "fastrand 2.0.1", "redox_syscall", "rustix", "windows-sys 0.52.0", @@ -1263,11 +1550,25 @@ dependencies = [ "libc", "mio", "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "windows-sys 0.48.0", ] +[[package]] +name = "tokio-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -1278,6 +1579,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.10" @@ -1304,6 +1615,7 @@ version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -1394,6 +1706,12 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -1403,6 +1721,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -1518,6 +1837,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + [[package]] name = "widestring" version = "1.0.2" diff --git a/Cargo.toml b/Cargo.toml index 1c08064..e43dee4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ path = "src/lib.rs" [features] standalone = ["axocli"] +axo_releases = ["gazenot", "tokio"] [dependencies] axoasset = { version = "0.6.1", default-features = false, features = ["json-serde"]} @@ -24,10 +25,14 @@ reqwest = { version = "0.11", default-features = false, features = ["blocking", serde = "1.0.195" temp-dir = "0.1.12" +# axo releases +gazenot = { version = "0.2.1", features = ["client_lib"], optional = true } +tokio = { version = "1.12.0", features = ["full"], optional = true } + # errors miette = "5.6.0" thiserror = "1.0.56" [[bin]] name = "axoupdater" -required-features = ["axocli"] +required-features = ["axocli", "axo_releases"] diff --git a/src/lib.rs b/src/lib.rs index 8e713d3..7ee46b2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,8 @@ use std::{fs::File, os::unix::fs::PermissionsExt}; use axoasset::{AxoassetError, LocalAsset, SourceFile}; use axoprocess::{AxoprocessError, Cmd}; use camino::Utf8PathBuf; +#[cfg(feature = "gazenot")] +use gazenot::{error::GazenotError, Gazenot}; use miette::Diagnostic; use reqwest::{ self, @@ -170,7 +172,9 @@ impl AxoUpdater { }); }; - let Some(release) = get_latest_stable_release(&source.name, &source.owner)? else { + let Some(release) = + get_latest_stable_release(&source.name, &source.owner, &source.release_type)? + else { return Err(AxoupdateError::NoStableReleases { app_name: app_name.to_owned(), }); @@ -204,6 +208,14 @@ pub enum AxoupdateError { #[error(transparent)] Axoprocess(#[from] AxoprocessError), + #[cfg(feature = "gazenot")] + #[error(transparent)] + Gazenot(#[from] GazenotError), + + #[error("Release is located on backend {backend}, but it's not enabled")] + #[diagnostic(help("This probably isn't your fault; please open an issue!"))] + BackendDisabled { backend: String }, + #[error("Unable to determine config file path for app {app_name}!")] #[diagnostic(help("This probably isn't your fault; please open an issue!"))] ConfigFetchFailed { app_name: String }, @@ -226,6 +238,9 @@ pub enum AxoupdateError { #[error("There are no stable releases available for {app_name}")] NoStableReleases { app_name: String }, + #[error("No releases were found for the app {app_name}")] + ReleaseNotFound { app_name: String }, + #[error("App name calculated as `axoupdate'")] #[diagnostic(help( "This probably isn't what you meant to update; was the updater installed correctly?" @@ -256,6 +271,25 @@ impl Release { self.tag_name.to_owned() } } + + #[cfg(feature = "gazenot")] + pub fn from_gazenot(release: &gazenot::PublicRelease) -> Release { + Release { + tag_name: release.tag_name.to_owned(), + name: release.name.to_owned(), + url: String::new(), + assets: release + .assets + .iter() + .map(|asset| Asset { + url: asset.browser_download_url.to_owned(), + browser_download_url: asset.browser_download_url.to_owned(), + name: asset.name.to_owned(), + }) + .collect(), + prerelease: release.prerelease, + } + } } #[derive(Clone, Debug, Deserialize)] @@ -287,7 +321,7 @@ pub struct InstallReceipt { pub version: String, } -pub fn get_releases(name: &String, owner: &String) -> AxoupdateResult> { +pub fn get_github_releases(name: &String, owner: &String) -> AxoupdateResult> { let client = reqwest::blocking::Client::new(); let resp: Vec = client .get(format!("{GITHUB_API}/repos/{owner}/{name}/releases")) @@ -302,11 +336,40 @@ pub fn get_releases(name: &String, owner: &String) -> AxoupdateResult AxoupdateResult> { + let abyss = Gazenot::new_unauthed("github".to_string(), owner)?; + let release_lists = tokio::runtime::Handle::current() + .block_on(abyss.list_releases_many(vec![name.to_owned()]))?; + let Some(our_release) = release_lists.iter().find(|rl| &rl.package_name == name) else { + return Err(AxoupdateError::ReleaseNotFound { + app_name: name.to_owned(), + }); + }; + + Ok(our_release + .releases + .iter() + .map(Release::from_gazenot) + .collect()) +} + pub fn get_latest_stable_release( name: &String, owner: &String, + release_type: &ReleaseSourceType, ) -> AxoupdateResult> { - let releases = get_releases(name, owner)?; + let releases = match release_type { + ReleaseSourceType::GitHub => get_github_releases(name, owner)?, + #[cfg(feature = "gazenot")] + ReleaseSourceType::Axo => get_axo_releases(name, owner)?, + #[cfg(not(feature = "gazenot"))] + ReleaseSourceType::Axo => { + return Err(AxoupdateError::BackendDisabled { + backend: "axodotdev".to_owned(), + }) + } + }; Ok(releases.into_iter().find(|r| !r.prerelease)) }