diff --git a/Cargo.lock b/Cargo.lock index db7ea67..0ca8db7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -30,14 +30,14 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", "version_check", - "zerocopy 0.7.35", + "zerocopy", ] [[package]] @@ -291,9 +291,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.21" +version = "1.2.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8691782945451c1c383942c4874dbe63814f61cb57ef773cda2972682b7bb3c0" +checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" dependencies = [ "jobserver", "libc", @@ -324,9 +324,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eccb054f56cbd38340b380d4a8e69ef1f02f1af43db2f0cc817a4774d80ae071" +checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" dependencies = [ "clap_builder", "clap_derive", @@ -334,9 +334,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.37" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efd9466fac8543255d3b1fcad4762c5e116ffe808c8a3043d4263cd4fd4862a2" +checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" dependencies = [ "anstream", "anstyle", @@ -452,9 +452,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" dependencies = [ "crc-catalog", ] @@ -801,9 +801,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", "js-sys", @@ -1016,9 +1016,9 @@ dependencies = [ [[package]] name = "gix-date" -version = "0.10.1" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a98593f1f1e14b9fa15c5b921b2c465e904d698b9463e21bb377be8376c3c1a" +checksum = "139d1d52b21741e3f0c72b0fc65e1ff34d4eaceb100ef529d182725d2e09b8cb" dependencies = [ "bstr", "itoa", @@ -1159,9 +1159,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.40.0" +version = "0.40.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d505aea7d7c4267a3153cb90c712a89970b4dd02a2cb3205be322891f530b5" +checksum = "b38e919efd59cb8275d23ad2394b2ab9d002007b27620e145d866d546403b665" dependencies = [ "bitflags", "bstr", @@ -1300,9 +1300,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.17" +version = "0.10.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c091d2e887e02c3462f52252c5ea61150270c0f2657b642e8d0d6df56c16e642" +checksum = "567f65fec4ef10dfab97ae71f26a27fd4d7fe7b8e3f90c8a58551c41ff3fb65b" dependencies = [ "bstr", "gix-trace", @@ -1521,9 +1521,9 @@ dependencies = [ [[package]] name = "gix-traverse" -version = "0.46.1" +version = "0.46.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39094185f6d9a4d81101130fbbf7f598a06441d774ae3b3ae7930a613bbe1157" +checksum = "b8648172f85aca3d6e919c06504b7ac26baef54e04c55eb0100fa588c102cc33" dependencies = [ "bitflags", "gix-commitgraph", @@ -1809,21 +1809,22 @@ dependencies = [ [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", @@ -1832,31 +1833,11 @@ dependencies = [ "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -1864,67 +1845,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "2549ca8c7241c82f59c80ba2a6f415d931c5b58d24fb8412caa1a1f02c49139a" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "8197e866e47b68f8f7d95249e172903bec06004b18b2937f1095d40a0c57de04" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - [[package]] name = "idna" version = "1.0.3" @@ -1938,9 +1906,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -2055,7 +2023,7 @@ version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", "libc", ] @@ -2167,9 +2135,9 @@ checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] name = "lock_api" @@ -2210,6 +2178,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lzma-rs" version = "0.3.0" @@ -2484,6 +2458,15 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -2496,7 +2479,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ - "zerocopy 0.8.25", + "zerocopy", ] [[package]] @@ -2584,7 +2567,9 @@ dependencies = [ "serde_json", "symlink", "templatr", + "thiserror 2.0.12", "trycmd", + "ureq", "vergen", "walkdir", "zip", @@ -2615,9 +2600,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.7" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" +checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" dependencies = [ "bytes", "cfg_aliases", @@ -2635,12 +2620,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.11" +version = "0.11.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbafbbdbb0f638fe3f35f3c56739f77a8a1d070cb25603226c83339b391472b" +checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" dependencies = [ "bytes", - "getrandom 0.3.2", + "getrandom 0.3.3", + "lru-slab", "rand", "ring", "rustc-hash", @@ -2708,7 +2694,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ - "getrandom 0.3.2", + "getrandom 0.3.3", ] [[package]] @@ -2880,6 +2866,7 @@ version = "0.23.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -2909,9 +2896,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.2" +version = "0.103.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7149975849f1abb3832b246010ef62ccc80d3a76169517ada7188252b9cfb437" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" dependencies = [ "ring", "rustls-pki-types", @@ -3260,12 +3247,12 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.19.1" +version = "3.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" +checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" dependencies = [ "fastrand", - "getrandom 0.3.2", + "getrandom 0.3.3", "once_cell", "rustix", "windows-sys 0.59.0", @@ -3373,9 +3360,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.7.6" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ "displaydoc", "zerovec", @@ -3588,6 +3575,24 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64", + "flate2", + "log", + "once_cell", + "rustls", + "rustls-pki-types", + "serde", + "serde_json", + "url", + "webpki-roots 0.26.11", +] + [[package]] name = "url" version = "2.5.4" @@ -3599,12 +3604,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4038,17 +4037,11 @@ dependencies = [ "bitflags", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "xml-rs" @@ -4067,9 +4060,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -4079,9 +4072,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -4089,33 +4082,13 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive 0.7.35", -] - [[package]] name = "zerocopy" version = "0.8.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" dependencies = [ - "zerocopy-derive 0.8.25", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", + "zerocopy-derive", ] [[package]] @@ -4170,11 +4143,22 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" dependencies = [ "yoke", "zerofrom", @@ -4183,9 +4167,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", @@ -4206,7 +4190,7 @@ dependencies = [ "crossbeam-utils", "deflate64", "flate2", - "getrandom 0.3.2", + "getrandom 0.3.3", "hmac", "indexmap", "lzma-rs", diff --git a/Cargo.toml b/Cargo.toml index cc43334..f103e3e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,12 @@ required-features = [] [features] -default = ["templatr", "network_test", "cli", "gitoxide"] +default = ["templatr", "network_test", "cli", "gitoxide", "reqwest"] templatr = ["dep:templatr"] + +reqwest = ["dep:reqwest"] +ureq = ["dep:ureq"] + cli = ["dep:clap", "dep:clap_complete", "dep:vergen", "dep:pbr"] gitoxide = ["dep:gix"] network_test = [] @@ -49,6 +53,7 @@ color-eyre = { version = "0.6", default-features = false } pbr = { version = "*", optional = true } #{ git = "https://github.com/a8m/pb.git" } bytes = "*" +ureq = { version = "2", features = ["json"], optional = true } reqwest = { version = "0.12", features = [ "blocking", "json", @@ -56,7 +61,7 @@ reqwest = { version = "0.12", features = [ "deflate", "brotli", "rustls-tls", -], default-features = false } +], default-features = false, optional = true } clap = { version = "4", features = ["derive"], optional = true } clap_complete = { version = "4", optional = true } @@ -80,7 +85,7 @@ gix = { version = "*", features = [ "worktree-mutation", "blocking-network-client", "blocking-http-transport-reqwest-rust-tls", -], optional = true, default-features = false} +], optional = true, default-features = false } # Use PR with symlink fix for Unix systems. zip = "2" @@ -90,6 +95,7 @@ symlink = "0.1.0" fs_extra = "1.2" itertools = "0.14" schemars = { version = "0.8", features = ["semver"] } +thiserror = "2.0.12" [target.aarch64-apple-darwin.dependencies] # Allow cross compiles diff --git a/src/commands/publish/mod.rs b/src/commands/publish/mod.rs index 6a1cd29..b6e72a5 100644 --- a/src/commands/publish/mod.rs +++ b/src/commands/publish/mod.rs @@ -4,8 +4,11 @@ use owo_colors::OwoColorize; use qpm_package::models::{dependency::SharedPackageConfig, package::PackageConfig}; use crate::{ - models::{config::get_publish_keyring, package::PackageConfigExtensions}, - repository::{Repository, qpackages::QPMRepository}, + models::{ + config::get_publish_keyring, + package::{PackageConfigExtensions}, + }, + repository::{qpackages::QPMRepository, Repository}, terminal::colors::QPMColor, }; diff --git a/src/commands/qmod/mod.rs b/src/commands/qmod/mod.rs index a2b3f28..f07f63f 100644 --- a/src/commands/qmod/mod.rs +++ b/src/commands/qmod/mod.rs @@ -1,5 +1,7 @@ use clap::{Args, Subcommand}; -use color_eyre::{Result, owo_colors::OwoColorize}; +use color_eyre::Result; +use owo_colors::OwoColorize; + use super::Command; diff --git a/src/commands/scripts.rs b/src/commands/scripts.rs index 1231d09..afaf4e0 100644 --- a/src/commands/scripts.rs +++ b/src/commands/scripts.rs @@ -1,4 +1,4 @@ -use std::{path::Path, process::Stdio}; +use std::process::Stdio; use clap::Args; diff --git a/src/main.rs b/src/main.rs index 3a5418d..dd41c9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -87,4 +87,4 @@ fn main() -> Result<()> { } Ok(()) -} +} \ No newline at end of file diff --git a/src/network/agent.rs b/src/network/agent.rs index 91ff874..e69de29 100644 --- a/src/network/agent.rs +++ b/src/network/agent.rs @@ -1,116 +0,0 @@ -use std::{ - env, - io::{ErrorKind, Read, Write}, - sync, - thread::sleep, - time::Duration, -}; - -use color_eyre::{ - Result, - eyre::{Context, ensure}, -}; - -use crate::models::config::get_combine_config; - -static AGENT: sync::OnceLock = sync::OnceLock::new(); - -pub fn get_agent() -> &'static reqwest::blocking::Client { - let timeout = get_combine_config().timeout.unwrap_or(5000); - - AGENT.get_or_init(|| { - reqwest::blocking::ClientBuilder::new() - .connect_timeout(Duration::from_millis(timeout.into())) - .tcp_keepalive(Duration::from_secs(5)) - .tcp_nodelay(false) - .https_only(true) - .user_agent(format!("questpackagemanager-rust2/{}", env!("CARGO_PKG_VERSION")).as_str()) - .build() - .expect("Client agent was not buildable") - }) -} - -pub fn download_file(url: &str, buffer: &mut impl Write, mut callback: F) -> Result -where - F: FnMut(usize, usize), -{ - let mut request = get_agent().get(url).build()?; - - request.timeout_mut().take(); // Set to none - - let mut response = get_agent() - .execute(request) - .with_context(|| format!("Unable to download file {url}"))? - .error_for_status()?; - - let expected_amount = response.content_length().unwrap_or(0) as usize; - let mut written: usize = 0; - - let mut temp_buf = vec![0u8; 1024]; - - loop { - let read = response.read(&mut temp_buf); - - match read { - // EOF - Ok(0) => break, - - Ok(amount) => { - written += amount; - buffer.write_all(&temp_buf[0..amount])?; - callback(written, expected_amount); - } - Err(e) if e.kind() == ErrorKind::Interrupted => { - sleep(Duration::from_millis(1)); - } - Err(e) => { - return Err(e) - .with_context(|| format!("Failed to continue reading bytes from {url}")); - } - } - } - - ensure!( - written == expected_amount, - "Read: 0x{written:x} Expected: 0x{expected_amount:x}" - ); - - Ok(expected_amount) -} - -#[inline(always)] -#[cfg(not(feature = "cli"))] -pub fn download_file_report(url: &str, buffer: &mut impl Write, callback: F) -> Result -where - F: FnMut(usize, usize), -{ - download_file(url, buffer, callback) -} - -#[inline(always)] -#[cfg(feature = "cli")] -pub fn download_file_report(url: &str, buffer: &mut impl Write, mut callback: F) -> Result -where - F: FnMut(usize, usize), -{ - use pbr::ProgressBar; - - let mut progress_bar = ProgressBar::new(0); - progress_bar.set_units(pbr::Units::Bytes); - - if env::var("CI") == Ok("true".to_string()) { - progress_bar.set_max_refresh_rate(Some(Duration::from_millis(500))); - } - - let result = download_file(url, buffer, |current, expected| { - progress_bar.total = expected as u64; - progress_bar.set(current as u64); - - callback(current, expected) - }); - - progress_bar.finish_println("Finished download!"); - println!(); - - result -} diff --git a/src/network/agent_common.rs b/src/network/agent_common.rs new file mode 100644 index 0000000..105e9da --- /dev/null +++ b/src/network/agent_common.rs @@ -0,0 +1,11 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum AgentError { + #[error("Agent error")] + AgentError(Box), + #[error("IO Error")] + IoError(std::io::Error), + #[error("Unauthorized")] + Unauthorized, +} \ No newline at end of file diff --git a/src/network/github.rs b/src/network/github.rs index 5812f2a..e8a1b48 100644 --- a/src/network/github.rs +++ b/src/network/github.rs @@ -1,7 +1,7 @@ use color_eyre::Result; use serde::{Deserialize, Serialize}; -use super::agent::get_agent; +use super::agent::{self}; const GITHUB_OWNER: &str = "QuestPackageManager"; const GITHUB_REPO: &str = "QPM.CLI"; @@ -46,24 +46,18 @@ pub struct GithubCommitDiffCommitDataResponse { pub message: String, } -pub fn get_github_branch(branch: &str) -> Result { - get_agent() - .get(format!( - "https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/branches/{branch}" - )) - .send()? - .json() +pub fn get_github_branch(branch: &str) -> Result { + agent::get(&format!( + "https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/branches/{branch}" + )) } pub fn get_github_commit_diff( old: &str, new: &str, -) -> Result { - get_agent() - .get(format!( - "https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/compare/{old}...{new}" - )) - .send()? - .json() +) -> Result { + agent::get(&format!( + "https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}/compare/{old}...{new}" + )) } pub fn download_github_artifact_url(sha: &str) -> String { diff --git a/src/network/mod.rs b/src/network/mod.rs index 277221f..416199a 100644 --- a/src/network/mod.rs +++ b/src/network/mod.rs @@ -1,2 +1,14 @@ -pub mod agent; pub mod github; + + +#[cfg(all(feature = "reqwest", feature = "ureq"))] +compile_error!("feature \"reqwest\" and feature \"ureq\" cannot be enabled at the same time"); + +#[cfg(not(any(feature = "reqwest", feature = "ureq")))] +compile_error!("feature \"reqwest\" or feature \"ureq\" must be enabled, though not both simultaneously"); + +#[cfg_attr(feature = "ureq", path = "ureq_agent.rs")] +#[cfg_attr(feature = "reqwest", path = "reqwest_agent.rs")] +pub mod agent; + +pub mod agent_common; \ No newline at end of file diff --git a/src/network/reqwest_agent.rs b/src/network/reqwest_agent.rs new file mode 100644 index 0000000..583f62c --- /dev/null +++ b/src/network/reqwest_agent.rs @@ -0,0 +1,190 @@ +use std::{ + collections::HashMap, + env, + io::{ErrorKind, Read, Write}, + sync, + thread::sleep, + time::Duration, +}; + +use color_eyre::eyre::{Context, ensure}; +use reqwest::StatusCode; +use serde::de::DeserializeOwned; + +use crate::models::config::get_combine_config; + +use super::agent_common; + +pub type AgentError = agent_common::AgentError; + +static AGENT: sync::OnceLock = sync::OnceLock::new(); + +pub fn get_agent() -> &'static reqwest::blocking::Client { + let timeout = get_combine_config().timeout.unwrap_or(5000); + + AGENT.get_or_init(|| { + reqwest::blocking::ClientBuilder::new() + .connect_timeout(Duration::from_millis(timeout.into())) + .tcp_keepalive(Duration::from_secs(5)) + .tcp_nodelay(false) + .https_only(true) + .user_agent(format!("questpackagemanager-rust2/{}", env!("CARGO_PKG_VERSION")).as_str()) + .build() + .expect("Client agent was not buildable") + }) +} + +pub fn download_file(url: &str, buffer: &mut impl Write, mut callback: F) -> color_eyre::Result +where + F: FnMut(usize, usize), +{ + let mut request = get_agent().get(url).build()?; + + request.timeout_mut().take(); // Set to none + + let mut response = get_agent() + .execute(request) + .with_context(|| format!("Unable to download file {url}"))? + .error_for_status()?; + + let expected_amount = response.content_length().unwrap_or(0) as usize; + let mut written: usize = 0; + + let mut temp_buf = vec![0u8; 1024]; + + loop { + let read = response.read(&mut temp_buf); + + match read { + // EOF + Ok(0) => break, + + Ok(amount) => { + written += amount; + buffer.write_all(&temp_buf[0..amount])?; + callback(written, expected_amount); + } + Err(e) if e.kind() == ErrorKind::Interrupted => { + sleep(Duration::from_millis(1)); + } + Err(e) => { + return Err(e) + .with_context(|| format!("Failed to continue reading bytes from {url}")); + } + } + } + + ensure!( + written == expected_amount, + "Read: 0x{written:x} Expected: 0x{expected_amount:x}" + ); + + Ok(expected_amount) +} + +#[inline(always)] +#[cfg(not(feature = "cli"))] +pub fn download_file_report(url: &str, buffer: &mut impl Write, callback: F) -> Result +where + F: FnMut(usize, usize), +{ + download_file(url, buffer, callback) +} + +#[inline(always)] +#[cfg(feature = "cli")] +pub fn download_file_report(url: &str, buffer: &mut impl Write, mut callback: F) -> color_eyre::Result +where + F: FnMut(usize, usize), +{ + use pbr::ProgressBar; + + let mut progress_bar = ProgressBar::new(0); + progress_bar.set_units(pbr::Units::Bytes); + + if env::var("CI") == Ok("true".to_string()) { + progress_bar.set_max_refresh_rate(Some(Duration::from_millis(500))); + } + + let result = download_file(url, buffer, |current, expected| { + progress_bar.total = expected as u64; + progress_bar.set(current as u64); + + callback(current, expected) + }); + + progress_bar.finish_println("Finished download!"); + println!(); + + result +} + +fn map_err(e: reqwest::Error) -> AgentError { + AgentError::AgentError(Box::new(e)) +} + +pub fn get(url: &str) -> Result +where + T: DeserializeOwned, +{ + get_agent() + .get(url) + .send() + .map_err(map_err)? + .error_for_status() + .map_err(map_err)? + .json::() + .map_err(map_err) +} + +pub fn get_bytes(url: &str) -> Result, AgentError> { + get_agent() + .get(url) + .send() + .map_err(map_err)? + .bytes() + .map(|b| b.into()) + .map_err(map_err) +} +pub fn get_str(url: &str) -> Result { + get_agent() + .get(url) + .send() + .map_err(map_err)? + .text() + .map_err(map_err) +} +pub fn post( + url: &str, + data: impl serde::Serialize, + headers: &HashMap<&str, &str>, +) -> Result<(), AgentError> { + let mut req = get_agent().post(url); + + for (key, val) in headers { + req = req.header(*key, *val); + } + + let res = req.json(&data).send().map_err(map_err)?; + if res.status() == StatusCode::UNAUTHORIZED { + return Err(AgentError::Unauthorized); + } + + res.error_for_status().map_err(map_err)?; + Ok(()) +} + +pub fn get_opt(url: &str) -> Result, AgentError> +where + T: DeserializeOwned, +{ + let req = get_agent().get(url).send().map_err(map_err)?; + + if req.status() == StatusCode::NOT_FOUND { + return Ok(None); + } + + let res = req.json::().map_err(map_err)?; + + Ok(Some(res)) +} diff --git a/src/network/ureq_agent.rs b/src/network/ureq_agent.rs new file mode 100644 index 0000000..05d38ab --- /dev/null +++ b/src/network/ureq_agent.rs @@ -0,0 +1,185 @@ +use std::{ + io::{BufReader, Read}, + sync, + time::Duration, +}; + +use color_eyre::{eyre::Context, Result}; +use ureq::{Agent, AgentBuilder}; + +use crate::models::config::get_combine_config; + +static AGENT: sync::OnceLock = sync::OnceLock::new(); + +pub fn get_agent() -> &'static Agent { + AGENT.get_or_init(|| { + AgentBuilder::new() + .timeout(Duration::from_millis( + get_combine_config().timeout.unwrap().into(), + )) + .https_only(true) + .user_agent(format!("questpackagemanager-rust2/{}", env!("CARGO_PKG_VERSION")).as_str()) + .build() + }) +} + + +use std::collections::HashMap; + +use thiserror::Error; + +use serde::de::DeserializeOwned; + +pub use super::ureq_agent::*; + +pub type AgentError = ureq::Error; + +#[derive(Error, Debug)] + +pub enum Error { + #[error("Agent error")] + AgentError(Box), + #[error("IO Error")] + IoError(std::io::Error), + #[error("Unauthorized")] + Unauthorized, +} + +pub fn get(url: &str) -> Result +where + T: DeserializeOwned, +{ + let res = match get_agent().get(url).call() { + Ok(o) => Ok(o), + Err(e) => Err(Error::AgentError(Box::new(e))), + }?; + match res.into_json::() { + Ok(o) => Ok(o), + Err(e) => Err(Error::IoError(e)), + } +} + +pub fn get_bytes(url: &str) -> Result, Error> { + Ok(get_str(url)?.into_bytes()) +} +pub fn get_str(url: &str) -> Result { + let res = match get_agent().get(url).call() { + Ok(o) => Ok(o), + Err(e) => Err(Error::AgentError(Box::new(e))), + }?; + match res.into_string() { + Ok(o) => Ok(o), + Err(e) => Err(Error::IoError(e)), + } +} +pub fn post( + url: &str, + data: impl serde::Serialize, + headers: &HashMap<&str, &str>, +) -> Result +where + T: DeserializeOwned, +{ + let mut req = get_agent().post(url); + + for (key, val) in headers { + req = req.set(key, val); + } + + let res = match req.send_json(data) { + Ok(o) => Ok(o), + Err(e) => match e { + ureq::Error::Status(code, _) => { + if code == 401 { + Err(Error::Unauthorized) + } else { + Err(Error::AgentError(Box::new(e))) + } + } + ureq::Error::Transport(_) => Err(Error::AgentError(Box::new(e))), + }, + }?; + + match res.into_json::() { + Ok(o) => Ok(o), + Err(e) => Err(Error::IoError(e)), + } +} + +pub fn get_opt(url: &str) -> Result, Error> +where + T: DeserializeOwned, +{ + match get::(url) { + Ok(o) => Ok(Some(o)), + Err(e) => Err(match &e { + Error::AgentError(u) => match u.as_ref() { + ureq::Error::Status(code, _) => { + if *code == 404u16 { + return Ok(None); + } + return Err(e); + } + _ => e, + }, + _ => e, + }), + } +} + +pub fn download_file(url: &str, _callback: F) -> Result> +where + F: FnMut(usize, usize), +{ + let request = get_agent().get(url).timeout(Duration::MAX); + + let response = request + .call() + .with_context(|| format!("Unable to download file {url}"))?; + + let mut bytes: Vec = Vec::with_capacity( + response + .header("Content-Length") + .unwrap_or("0") + .parse::() + .unwrap_or(0), + ); + + let mut reader = BufReader::new(response.into_reader()); + + reader.read_to_end(&mut bytes)?; + + Ok(bytes) + + // TODO: Fix + // let mut bytes = Vec::with_capacity(response.content_length().unwrap_or(0) as usize); + // let mut read_bytes = vec![0u8; 4 * 1024]; + + // loop { + // let read = response.read(&mut read_bytes)?; + // bytes.append(&mut read_bytes); + + // callback(bytes.len(), bytes.capacity()); + // if read == 0 { + // println!("Done!"); + // break; + // } + // } + + // Ok(bytes) +} + +#[inline(always)] +pub fn download_file_report(url: &str, mut callback: F) -> Result> +where + F: FnMut(usize, usize), +{ + // let mut progress_bar = ProgressBar::new(1000); + + // progress_bar.finish_println(""); + download_file(url, |current, expected| { + // progress_bar.set((current / expected) as u64 * 1000); + + callback(current, expected) + }) +} diff --git a/src/repository/qpackages.rs b/src/repository/qpackages.rs index 3206669..3e2ab23 100644 --- a/src/repository/qpackages.rs +++ b/src/repository/qpackages.rs @@ -1,13 +1,12 @@ -use bytes::{BufMut, BytesMut}; use color_eyre::{ Result, Section, - eyre::{Context, OptionExt, bail}, + eyre::{Context, OptionExt, anyhow, bail}, }; use itertools::Itertools; use owo_colors::OwoColorize; -use reqwest::StatusCode; use semver::Version; use std::{ + collections::HashMap, fs::{self, File}, io::{BufWriter, Cursor}, path::Path, @@ -23,7 +22,7 @@ use qpm_package::{ use crate::{ models::{config::get_combine_config, package::PackageConfigExtensions}, - network::agent::{download_file_report, get_agent}, + network::agent::{self, download_file_report}, terminal::colors::QPMColor, utils::git, }; @@ -42,22 +41,9 @@ impl QPMRepository { { let url = format!("{API_URL}/{path}"); - let response = get_agent() - .get(&url) - .send() - .with_context(|| format!("Unable to make request to qpackages.com {url}"))?; - - if response.status() == StatusCode::NOT_FOUND { - return Ok(None); - } - - response.error_for_status_ref()?; - - let result: T = response - .json() - .with_context(|| format!("Into json failed for http request for {url}"))?; - - Ok(Some(result)) + let response = + agent::get_opt::(&url).context("Unable to make request to qpackages.com")?; + Ok(response) } /// Requests the appriopriate package info from qpackage.com @@ -89,20 +75,21 @@ impl QPMRepository { API_URL, &package.config.info.id, &package.config.info.version ); - let resp = get_agent() - .post(&url) - .header("Authorization", auth) - .json(&package) - .send() - .with_context(|| format!("Failed to publish to {url}"))?; - - if resp.status() == StatusCode::UNAUTHORIZED { - bail!( - "Could not publish to {}: Unauthorized! Did you provide the correct key?", - API_URL - ); - } - resp.error_for_status()?; + let mut headers = HashMap::new(); + headers.insert("Authorization", auth); + + match agent::post(&url, package, &headers) { + Ok(o) => Ok(o), + Err(e) => match e { + agent::AgentError::Unauthorized => Err(anyhow!( + "Could not publish to {}: Unauthorized! Did you provide the correct key?", + API_URL + ) + .wrap_err(e)), + _ => Err(anyhow!("Error").wrap_err(e)), + }, + }?; + Ok(()) } @@ -174,13 +161,9 @@ impl QPMRepository { .context("Clone")?; } else { // not a github url, assume it's a zip - let mut bytes = BytesMut::new().writer(); - - download_file_report(url, &mut bytes, |_, _| {}) - .with_context(|| format!("Failed while downloading {}", url.blue()))?; - - let buffer = Cursor::new(bytes.get_ref()); + let response = agent::get_bytes(url)?; + let buffer = Cursor::new(response); // Extract to tmp folder ZipArchive::new(buffer) .context("Reading zip")? diff --git a/src/utils/android.rs b/src/utils/android.rs index 01ada73..e296407 100644 --- a/src/utils/android.rs +++ b/src/utils/android.rs @@ -12,7 +12,7 @@ use crate::{ android_repo::{AndroidRepositoryManifest, Archive, RemotePackage}, config::get_combine_config, }, - network::agent::{download_file, download_file_report, get_agent}, + network::agent::{self, download_file, download_file_report}, terminal::colors::QPMColor, }; @@ -20,9 +20,9 @@ const ANDROID_REPO_MANIFEST: &str = "https://dl.google.com/android/repository/re const ANDROID_DL_URL: &str = "https://dl.google.com/android/repository"; pub fn get_android_manifest() -> Result { - let response = get_agent().get(ANDROID_REPO_MANIFEST).send()?; + let response = agent::get_str(ANDROID_REPO_MANIFEST)?; - Ok(serde_xml_rs::from_reader(response)?) + Ok(serde_xml_rs::from_str(&response)?) } pub fn get_ndk_packages(manifest: &AndroidRepositoryManifest) -> Vec<&RemotePackage> { diff --git a/src/utils/git.rs b/src/utils/git.rs index 9beeec3..3c42ebe 100644 --- a/src/utils/git.rs +++ b/src/utils/git.rs @@ -1,6 +1,6 @@ use std::{ fs::File, - io::{BufReader, BufWriter}, + io::{BufReader, BufWriter, Write}, path::Path, process::{Command, Stdio}, }; @@ -15,8 +15,7 @@ use serde::{Deserialize, Serialize}; use crate::{ models::config::get_keyring, - network::agent::{download_file_report, get_agent}, - terminal::colors::QPMColor, + network::agent::{self}, }; pub fn check_git() -> Result<()> { @@ -60,15 +59,10 @@ pub fn get_release(url: &str, out: &std::path::Path) -> Result { pub fn get_release_without_token(url: &str, out: &std::path::Path) -> Result { let file = File::create(out).context("create so file failed")?; - let mut buf = BufWriter::new(file); - - download_file_report(url, &mut buf, |_, _| {}).with_context(|| { - format!( - "Failed while downloading {} to {}", - url.blue(), - out.display().file_path_color() - ) - })?; + let mut writer = BufWriter::new(file); + writer + .write_all(&agent::get_bytes(url)?) + .context("Failed to write to file")?; Ok(out.exists()) } @@ -93,8 +87,8 @@ pub fn get_release_with_token(url: &str, out: &std::path::Path, token: &str) -> &token, &user, &repo, &tag ); - let data = match get_agent().get(asset_data_link).send() { - Ok(o) => o.json::().unwrap(), + let data = match agent::get::(&asset_data_link) { + Ok(o) => o, Err(e) => { let error_string = e.to_string().replace(token, "***"); bail!("{}", error_string); @@ -109,15 +103,11 @@ pub fn get_release_with_token(url: &str, out: &std::path::Path, token: &str) -> .replace("api.github.com", &format!("{token}@api.github.com")); let file = File::create(out).context("create so file failed")?; - let mut buf = BufWriter::new(file); - - download_file_report(&download, &mut buf, |_, _| {}).with_context(|| { - format!( - "Failed while downloading {} to {}", - download.replace(token, "{token}").blue(), - out.display().file_path_color() - ) - })?; + + let mut writer = BufWriter::new(file); + writer + .write_all(&agent::get_bytes(&download)?) + .context("Failed to write out downloaded bytes")?; break; } }