From 1298a026b6ebbc899d1917e581eaf56ea0cab883 Mon Sep 17 00:00:00 2001 From: Fabio Valentini Date: Wed, 15 Jan 2020 21:48:13 +0100 Subject: [PATCH] Release 0.0.1: finish initial implementation --- Cargo.lock | 1750 ++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 11 +- README.md | 4 +- rustfmt.toml | 9 + src/main.rs | 1360 ++++++++++++++++++++++++++++++++++++++- 5 files changed, 3128 insertions(+), 6 deletions(-) create mode 100644 Cargo.lock create mode 100644 rustfmt.toml diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..e148504 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1750 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "anyhow" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" + +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "backtrace" +version = "0.3.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4b1549d804b6c73f4817df2ba073709e96e426f12987127c48e6745568c350b" +dependencies = [ + "backtrace-sys", + "cfg-if", + "libc", + "rustc-demangle", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "bodhi" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a1668e6974d6c3f4df098ee0d011d873149bea95b5b80e27a063fdea3c265e" +dependencies = [ + "chrono", + "failure", + "fedora", + "reqwest", + "retry", + "serde", + "serde_json", + "serde_repr", + "serde_url_params", + "url 2.1.1", +] + +[[package]] +name = "bodhi-cli" +version = "0.0.1" +dependencies = [ + "bodhi", + "chrono", + "dirs", + "rpassword", + "serde", + "serde_json", + "structopt", + "term_size", + "toml", +] + +[[package]] +name = "bumpalo" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb8038c1ddc0a5f73787b130f4cc75151e96ed33e417fde765eb5a81e3532f4" + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" + +[[package]] +name = "bytes" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10004c15deb332055f7a4a208190aed362cf9a7c2f6ab70a305fba50e1105f38" + +[[package]] +name = "c2-chacha" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" +dependencies = [ + "ppv-lite86", +] + +[[package]] +name = "cc" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" +dependencies = [ + "num-integer", + "num-traits", + "serde", + "time", +] + +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "cookie" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "888604f00b3db336d2af898ec3c1d5d0ddf5e6d462220f2ededc33a87ac4bbd5" +dependencies = [ + "time", + "url 1.7.2", +] + +[[package]] +name = "cookie_store" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d3b52e7c82f1af00203337cd15c56be6fac37397a26439d03cedbbdbc487ef" +dependencies = [ + "cookie", + "idna 0.2.0", + "log", + "publicsuffix", + "serde", + "serde_json", + "time", + "url 2.1.1", +] + +[[package]] +name = "core-foundation" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25b9e03f145fd4f2bf705e07b900cd41fc636598fe5dc452fd0db1441c3f496d" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi 0.3.8", +] + +[[package]] +name = "dtoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" + +[[package]] +name = "encoding_rs" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8d03faa7fe0c1431609dfad7bbe827af30f82e1e2ae6f7ee4fca6bd764bc28" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "error-chain" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" +dependencies = [ + "version_check 0.1.5", +] + +[[package]] +name = "failure" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +dependencies = [ + "backtrace", + "failure_derive", +] + +[[package]] +name = "failure_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "fedora" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf9727e7dc0306634d12d963c3fc1c56da437a835f93e596e3db3574601084bc" +dependencies = [ + "failure", + "reqwest", + "serde", + "serde_json", + "url 2.1.1", +] + +[[package]] +name = "fnv" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "fuchsia-zircon" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" +dependencies = [ + "bitflags", + "fuchsia-zircon-sys", +] + +[[package]] +name = "fuchsia-zircon-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" + +[[package]] +name = "futures-channel" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcae98ca17d102fd8a3603727b9259fcf7fa4239b603d2142926189bc8999b86" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79564c427afefab1dfb3298535b21eda083ef7935b4f0ecbfcb121f0aec10866" + +[[package]] +name = "futures-io" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e676577d229e70952ab25f3945795ba5b16d63ca794ca9d2c860e5595d20b5ff" + +[[package]] +name = "futures-sink" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "171be33efae63c2d59e6dbba34186fe0d6394fb378069a76dfd80fdcffd43c16" + +[[package]] +name = "futures-task" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bae52d6b29cf440e298856fec3965ee6fa71b06aa7495178615953fd669e5f9" + +[[package]] +name = "futures-util" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0d66274fb76985d3c62c886d1da7ac4c0903a8c9f754e8fe0f35a6a6cc39e76" +dependencies = [ + "futures-core", + "futures-io", + "futures-task", + "memchr", + "pin-utils", + "slab", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "h2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9433d71e471c1736fd5a61b671fc0b148d7a2992f666c958d03cd8feb3b88d1" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "log", + "slab", + "tokio", + "tokio-util", +] + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2656d88f158ce120947499e971d743c05dbcbed62e5bd2f38f1698bbc3772" +dependencies = [ + "libc", +] + +[[package]] +name = "http" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b708cc7f06493459026f53b9a61a7a121a5d1ec6238dee58ea4941132b30156b" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13d5ff830006f7646652e057693569bfe0d51760c0085a071769d142a205111b" +dependencies = [ + "bytes", + "http", +] + +[[package]] +name = "httparse" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd179ae861f0c2e53da70d892f5f3029f9594be0c41dc5269cd371691b1dc2f9" + +[[package]] +name = "hyper" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bf49cfb32edee45d890537d9057d1b02ed55f53b7b6a30bae83a38c9231749e" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "itoa", + "log", + "net2", + "pin-project", + "time", + "tokio", + "tower-service", + "want", +] + +[[package]] +name = "hyper-tls" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3adcd308402b9553630734e9c36b77a7e48b3821251ca2493e8cd596763aafaa" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-tls", +] + +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "idna" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "indexmap" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b54058f0a6ff80b6803da8faf8997cde53872b38f4023728f6830b06cd3c0dc" +dependencies = [ + "autocfg 1.0.0", +] + +[[package]] +name = "iovec" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +dependencies = [ + "libc", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" + +[[package]] +name = "js-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7889c7c36282151f6bf465be4700359318aef36baa951462382eae49e9577cf9" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + +[[package]] +name = "memchr" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3197e20c7edb283f87c071ddfc7a2cca8f8e0b888c242959846a6fce03c72223" + +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0ed03949aef72dbdf3116a383d7b38b4768e6f960528cd6a6044aa9ed68599" +dependencies = [ + "mime", + "unicase", +] + +[[package]] +name = "mio" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" +dependencies = [ + "cfg-if", + "fuchsia-zircon", + "fuchsia-zircon-sys", + "iovec", + "kernel32-sys", + "libc", + "log", + "miow", + "net2", + "slab", + "winapi 0.2.8", +] + +[[package]] +name = "miow" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" +dependencies = [ + "kernel32-sys", + "net2", + "winapi 0.2.8", + "ws2_32-sys", +] + +[[package]] +name = "native-tls" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "net2" +version = "0.2.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +dependencies = [ + "cfg-if", + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "nom" +version = "4.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" +dependencies = [ + "memchr", + "version_check 0.1.5", +] + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg 1.0.0", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg 1.0.0", +] + +[[package]] +name = "num_cpus" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "openssl" +version = "0.10.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3cc5799d98e1088141b8e01ff760112bbd9f19d850c124500566ca6901a585" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "lazy_static", + "libc", + "openssl-sys", +] + +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" + +[[package]] +name = "openssl-sys" +version = "0.9.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "465d16ae7fc0e313318f7de5cecf57b2fbe7511fd213978b457e1c96ff46736f" +dependencies = [ + "autocfg 0.1.7", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" + +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94b90146c7216e4cb534069fb91366de4ea0ea353105ee45ed297e2d1619e469" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44ca92f893f0656d3cba8158dd0f2b99b94de256a4a54e870bd6922fcc6c8355" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8822eb8bb72452f038ebf6048efa02c3fe22bf83f76519c9583e47fc194a422" + +[[package]] +name = "pin-utils" +version = "0.1.0-alpha.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5894c618ce612a3fa23881b152b608bafb8c56cfc22f434a3ba3120b40f7b587" + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "ppv-lite86" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" + +[[package]] +name = "proc-macro-error" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53c98547ceaea14eeb26fcadf51dc70d01a2479a7839170eae133721105e4428" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "proc-macro-error-attr" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2bf5d493cf5d3e296beccfd61794e445e830dfc8070a9c248ad3ee071392c6c" +dependencies = [ + "proc-macro2", + "quote", + "rustversion", + "syn", + "syn-mid", +] + +[[package]] +name = "proc-macro2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "publicsuffix" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bbaa49075179162b49acac1c6aa45fb4dafb5f13cf6794276d77bc7fd95757b" +dependencies = [ + "error-chain", + "idna 0.2.0", + "lazy_static", + "regex", + "url 2.1.1", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha 0.1.1", + "rand_core 0.4.2", + "rand_hc 0.1.0", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi 0.3.8", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha 0.2.1", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +dependencies = [ + "c2-chacha", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi 0.3.8", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi 0.3.8", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_users" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" +dependencies = [ + "failure", + "rand_os", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "regex" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5508c1941e4e7cb19965abef075d35a9a8b5cdf0846f30b4050e9b55dc55e87" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e734e891f5b408a29efbf8309e656876276f49ab6a6ac208600b4419bd893d90" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "reqwest" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0e798e19e258bf6c30a304622e3e9ac820e483b06a1857a026e1f109b113fe4" +dependencies = [ + "base64 0.11.0", + "bytes", + "cookie", + "cookie_store", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-tls", + "js-sys", + "lazy_static", + "log", + "mime", + "mime_guess", + "native-tls", + "percent-encoding 2.1.0", + "pin-project-lite", + "serde", + "serde_urlencoded", + "time", + "tokio", + "tokio-tls", + "url 2.1.1", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + +[[package]] +name = "retry" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ac83b31b3831aa4b07608db4170f6555ab12942197037c38570dc4c5ba5028" +dependencies = [ + "rand 0.6.5", +] + +[[package]] +name = "rpassword" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59f0e97173c514b9036cd450c195a6483ba81055c6fa0f1bff3ab563f47d44a" +dependencies = [ + "libc", + "winapi 0.3.8", +] + +[[package]] +name = "rust-argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +dependencies = [ + "base64 0.10.1", + "blake2b_simd", + "crossbeam-utils", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" + +[[package]] +name = "rustversion" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0538bd897e17257b0128d2fd95c2ed6df939374073a36166051a79e2eb7986" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ryu" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" + +[[package]] +name = "schannel" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021" +dependencies = [ + "lazy_static", + "winapi 0.3.8", +] + +[[package]] +name = "security-framework" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ef2429d7cefe5fd28bd1d2ed41c944547d4ff84776f5935b456da44593a16df" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31493fc37615debb8c5090a7aeb4a9730bc61e77ab10b9af59f1a202284f895" +dependencies = [ + "core-foundation-sys", +] + +[[package]] +name = "serde" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_url_params" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ac0ebb23d01336fa49b70d73f6d9347293510b6ec4f631f4faa3c5c5de0f7e" +dependencies = [ + "serde", + "url 1.7.2", +] + +[[package]] +name = "serde_urlencoded" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ec5d77e2d4c73717816afac02670d5c4f534ea95ed430442cad02e7a6e32c97" +dependencies = [ + "dtoa", + "itoa", + "serde", + "url 2.1.1", +] + +[[package]] +name = "slab" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" + +[[package]] +name = "smallvec" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4" + +[[package]] +name = "sourcefile" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884ae79d6aad1e738f4a70dff314203fd498490a63ebc4d03ea83323c40b7b72" +dependencies = [ + "clap", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a97f829a34a0a9d5b353a881025a23b8c9fd09d46be6045df6b22920dbd7a93" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e4ff033220a41d1a57d8125eab57bf5263783dfdcc18688b1dacc6ce9651ef8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "syn-mid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd3937748a7eccff61ba5b90af1a20dbf610858923a9192ea0ecb0cb77db1d0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand 0.7.3", + "redox_syscall", + "remove_dir_all", + "winapi 0.3.8", +] + +[[package]] +name = "term_size" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b6c1ac5b3fffd75073276bca1ceed01f67a28537097a2a9539e116e50fb21a" +dependencies = [ + "kernel32-sys", + "libc", + "winapi 0.2.8", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +dependencies = [ + "libc", + "redox_syscall", + "winapi 0.3.8", +] + +[[package]] +name = "tokio" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffa2fdcfa937b20cb3c822a635ceecd5fc1a27a6a474527e5516aa24b8c8820a" +dependencies = [ + "bytes", + "fnv", + "iovec", + "lazy_static", + "memchr", + "mio", + "num_cpus", + "pin-project-lite", + "slab", +] + +[[package]] +name = "tokio-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bde02a3a5291395f59b06ec6945a3077602fac2b07eeeaf0dee2122f3619828" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-util" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "571da51182ec208780505a32528fc5512a8fe1443ab960b3f2f3ef093cd16930" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" +dependencies = [ + "serde", +] + +[[package]] +name = "tower-service" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e987b6bf443f4b5b3b6f38704195592cca41c5bb7aedd3c3693c7081f8289860" + +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check 0.9.1", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" +dependencies = [ + "smallvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" + +[[package]] +name = "unicode-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" +dependencies = [ + "idna 0.1.5", + "matches", + "percent-encoding 1.0.1", +] + +[[package]] +name = "url" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829d4a8476c35c9bf0bbce5a3b23f4106f79728039b726d292bb93bc106787cb" +dependencies = [ + "idna 0.2.0", + "matches", + "percent-encoding 2.1.0", +] + +[[package]] +name = "vcpkg" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fc439f2794e98976c88a2a2dafce96b930fe8010b0a256b3c2199a773933168" + +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" + +[[package]] +name = "version_check" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" + +[[package]] +name = "version_check" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce" + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasm-bindgen" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5205e9afdf42282b192e2310a5b463a6d1c1d774e30dc3c791ac37ab42d2616c" +dependencies = [ + "cfg-if", + "serde", + "serde_json", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11cdb95816290b525b32587d76419facd99662a07e59d3cdb560488a819d9a45" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bbdd49e3e28b40dec6a9ba8d17798245ce32b019513a845369c641b275135d9" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "574094772ce6921576fb6f2e3f7497b8a76273b6db092be18fc48a082de09dc3" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e85031354f25eaebe78bb7db1c3d86140312a911a106b2e29f9cc440ce3e7668" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e7e61fc929f4c0dddb748b102ebf9f632e2b8d739f2016542b4de2965a9601" + +[[package]] +name = "wasm-bindgen-webidl" +version = "0.2.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef012a0d93fc0432df126a8eaf547b2dce25a8ce9212e1d3cbeef5c11157975d" +dependencies = [ + "anyhow", + "heck", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "weedle", +] + +[[package]] +name = "web-sys" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaf97caf6aa8c2b1dac90faf0db529d9d63c93846cca4911856f78a83cebf53b" +dependencies = [ + "anyhow", + "js-sys", + "sourcefile", + "wasm-bindgen", + "wasm-bindgen-webidl", +] + +[[package]] +name = "weedle" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164" +dependencies = [ + "nom", +] + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi 0.3.8", +] + +[[package]] +name = "ws2_32-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] diff --git a/Cargo.toml b/Cargo.toml index 99bbceb..2cc8768 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,15 @@ name = "bodhi-cli" path = "src/main.rs" [dependencies] -clap = { version = "^2.33.0", features = ["yaml"] } -bodhi = "^0.0.8" +bodhi = "^0.3.0" +chrono = "^0.4.10" +dirs = "^2.0.2" +rpassword = "^4.0.3" +serde = { version = "^1.0.104", features = ["derive"] } +serde_json = "^1.0.44" +structopt = "^0.3.7" +term_size = "^0.2.1" +toml = "^0.5.5" [profile.release] codegen-units = 1 diff --git a/README.md b/README.md index f9bb75f..b69da89 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ ## bodhi CLI client based on bodhi-rs -(work in progress) - +This CLI client for `bodhi-rs` exposes almost all functionality of the official `bodhi` python client, and almost all +features of the `bodhi-rs` rust bindings. diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..c136e50 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,9 @@ +blank_lines_lower_bound = 0 +blank_lines_upper_bound = 2 +comment_width = 100 +format_code_in_doc_comments = true +imports_layout = "HorizontalVertical" +match_block_trailing_comma = true +max_width = 120 +use_field_init_shorthand = true +wrap_comments = true diff --git a/src/main.rs b/src/main.rs index e7a11a9..5b0d1d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,1359 @@ -fn main() { - println!("Hello, world!"); +use std::convert::TryFrom; +use std::fs::read_to_string; +use std::io::Write; + +use bodhi::*; +use serde::Deserialize; +use structopt::StructOpt; + +#[derive(Debug, Deserialize)] +struct FedoraConfig { + #[serde(rename(deserialize = "FAS"))] + fas: FASConfig, +} + +#[derive(Debug, Deserialize)] +struct FASConfig { + username: String, +} + +enum Format { + JSON, + Plain, +} + +impl TryFrom<&str> for Format { + type Error = String; + + fn try_from(value: &str) -> Result { + match value.to_lowercase().as_str() { + "JSON" | "json" => Ok(Format::JSON), + "plain" => Ok(Format::Plain), + _ => return Err(format!("Not a recognised value for format: {}", &value)), + } + } +} + +fn str_to_compose_request(request: &str) -> Result { + match request { + "stable" => Ok(ComposeRequest::Stable), + "testing" => Ok(ComposeRequest::Testing), + _ => return Err(format!("Not a recognised value for compose request: {}", request)), + } +} + +#[derive(Debug, StructOpt)] +#[structopt(setting = structopt::clap::AppSettings::DisableHelpSubcommand)] +struct BaseCommand { + /// Use the fedora staging instance of bodhi + #[structopt(long)] + staging: bool, + /// Manually specify bodhi server URL + #[structopt(long, requires("login_url"), conflicts_with("staging"))] + bodhi_url: Option, + /// Manually specify OpenID endpoint URL + #[structopt(long, requires("bodhi_url"), conflicts_with("staging"))] + login_url: Option, + #[structopt(subcommand)] + subcommand: BodhiCommand, +} + +#[derive(Debug, StructOpt)] +enum BodhiCommand { + /// Comment on an update + Comment { + /// ID of the update to comment on + #[structopt(long)] + update: String, + /// Publicly visible comment text + #[structopt(long)] + text: String, + /// Karma submitted with this comment (-1/0/+1) + #[structopt(long)] + karma: Option, + }, + /// Query bodhi for information about a compose + ComposeInfo { + /// release string + release: String, + /// request string ("stable" or "testing") + request: String, + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + }, + /// Query bodhi for running composes + ComposeList { + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + }, + /// Create a new buildroot override + CreateOverride { + /// NVR of the override + nvr: String, + /// duration it will still be active + #[structopt(long)] + duration: u32, + /// publicly visible notes + #[structopt(long)] + notes: String, + }, + /// Create a new update + CreateUpdate { + /// Push to stable based on karma + #[structopt(long)] + autokarma: Option, + /// Push to stable based on time + #[structopt(long)] + autotime: Option, + /// Bugs fixed by this update + #[structopt(long)] + bugs: Option>, + /// Builds that are part of this update + #[structopt(long, conflicts_with = "from_tag")] + builds: Option>, + /// Close bugs when pushed to stable + #[structopt(long)] + close_bugs: Option, + /// Override displayed update name + #[structopt(long)] + display_name: Option, + /// Koji tag to create this update from + #[structopt(long, conflicts_with = "builds")] + from_tag: Option, + /// Publicly visible update notes + #[structopt(long)] + notes: String, + /// List of required taskotron tests + #[structopt(long)] + requirements: Option>, + /// Update severity + #[structopt(long)] + severity: Option, + /// Days until it can be pushed to stable + #[structopt(long)] + stable_days: Option, + /// Karma until it can be pushed to stable + #[structopt(long)] + stable_karma: Option, + /// Logout / reboot suggestion + #[structopt(long)] + suggestion: Option, + /// Karma until it will be unpushed + #[structopt(long)] + unstable_karma: Option, + /// Type of the update + #[structopt(long, name = "type")] + update_type: Option, + }, + /// Edit an existing buildroot override + EditOverride { + /// NVR of the override + nvr: String, + /// duration it will still be active + #[structopt(long)] + duration: u32, + /// publicly visible notes + #[structopt(long)] + notes: String, + }, + /// Edit an existing update + EditUpdate { + /// Alias of the edited update + alias: String, + /// Add bugs to this update + #[structopt(long)] + add_bugs: Option>, + /// Add builds to this update + #[structopt(long)] + add_builds: Option>, + /// Push to stable based on karma + #[structopt(long)] + autokarma: Option, + /// Push to stable based on time + #[structopt(long)] + autotime: Option, + /// Close bugs when pushed to stable + #[structopt(long)] + close_bugs: Option, + /// Override displayed update name + #[structopt(long)] + display_name: Option, + /// Publicly visible update notes + #[structopt(long)] + notes: Option, + /// Remove bugs from this update + #[structopt(long)] + remove_bugs: Option>, + /// Remove builds from this update + #[structopt(long)] + remove_builds: Option>, + /// List of required taskotron tests + #[structopt(long)] + requirements: Option>, + /// Update severity + #[structopt(long)] + severity: Option, + /// Days until it can be pushed to stable + #[structopt(long)] + stable_days: Option, + /// Karma until it can be pushed to stable + #[structopt(long)] + stable_karma: Option, + /// Logout / reboot suggestion + #[structopt(long)] + suggestion: Option, + /// Karma until it will be unpushed + #[structopt(long)] + unstable_karma: Option, + /// Type of the update + #[structopt(long, name = "type")] + update_type: Option, + }, + /// Expire an existing buildroot override + ExpireOverride { + /// NVR of the override + nvr: String, + }, + /// Query bodhi for buildroot overrides + QueryOverrides { + /// Query for this build / these builds + #[structopt(long)] + builds: Option>, + /// Query for expired overrides + #[structopt(long)] + expired: Option, + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + /// Query for this release / these releases + #[structopt(long)] + releases: Option>, + /// Query for overrides submitted by these users + #[structopt(long)] + users: Option>, + }, + /// Query bodhi for updates + QueryUpdates { + /// update with this alias + #[structopt(long)] + alias: Option, + /// updates approved before this date + #[structopt(long)] + approved_before: Option, + /// updates approved after this date + #[structopt(long)] + approved_since: Option, + /// updates associated with these bugs + #[structopt(long)] + bugs: Option>, + /// updates associated with these builds + #[structopt(long)] + builds: Option>, + /// updates for critpath packages + #[structopt(long)] + critpath: Option, + /// RPM / module / flatpak updates + #[structopt(long)] + content_type: Option, + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + /// locked updates + #[structopt(long)] + locked: Option, + /// updates modified before this date + #[structopt(long)] + modified_before: Option, + /// updates modified after this date + #[structopt(long)] + modified_since: Option, + /// updates for these packages + #[structopt(long)] + packages: Option>, + /// pushed updates + #[structopt(long)] + pushed: Option, + /// updates pushed before this date + #[structopt(long)] + pushed_before: Option, + /// updates pushed after this date + #[structopt(long)] + pushed_since: Option, + /// updates for these releases + #[structopt(long)] + releases: Option>, + /// updates with this status request + #[structopt(long)] + request: Option, + /// updates with this severity + #[structopt(long)] + severity: Option, + /// updates with this status + #[structopt(long)] + status: Option, + /// updates submitted before this date + #[structopt(long)] + submitted_before: Option, + /// updates submitted after this date + #[structopt(long)] + submitted_since: Option, + /// updates with logout / reboot suggestion + #[structopt(long)] + suggestion: Option, + /// updates with this type + #[structopt(name = "type", long)] + update_type: Option, + /// updates submitted by this user + #[structopt(long)] + users: Option>, + }, + /// Query bodhi for information about a release + ReleaseInfo { + /// ID of the release + release: String, + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + }, + /// Query bodhi for active releases + ReleaseList { + /// Output format (plain, JSON) + #[structopt(long)] + format: Option, + }, + /// Submit an update status request + UpdateRequest { + /// ID of the update + alias: String, + /// (obsolete, revoke, stable, testing, unpush) + request: String, + }, + /// Waive an update's test results + WaiveTests { + /// ID of the update + alias: String, + /// comment submitted with the waiver + comment: String, + }, +} + +fn get_config() -> Result { + let home = match dirs::home_dir() { + Some(path) => path, + None => { + return Err(String::from("Unable to determine $HOME.")); + }, + }; + + let config_path = home.join(".config/fedora.toml"); + + let config_str = match read_to_string(&config_path) { + Ok(string) => string, + Err(_) => { + return Err(String::from( + "Unable to read configuration file from ~/.config/fedora.toml", + )); + }, + }; + + let config: FedoraConfig = match toml::from_str(&config_str) { + Ok(config) => config, + Err(_) => { + return Err(String::from( + "Unable to parse configuration file from ~/.config/fedora.toml", + )); + }, + }; + + Ok(config) +} + +fn progress_bar(p: u32, ps: u32) { + let columns: u32 = match term_size::dimensions() { + Some((w, _)) => w as u32, + None => return, + }; + + let width: u32 = columns - 11; + + let progress = ((p as f64) / (ps as f64) * (width as f64)) as u32; + let remaining = width - progress; + + let bar = format!( + " [ {}{} ] {:>3}% ", + "=".repeat(progress as usize), + " ".repeat(remaining as usize), + ((p as f64) / (ps as f64) * 100f64) as u32, + ); + + print!("\r{}", &bar); + std::io::stdout().flush().unwrap(); +} + +fn main() -> Result<(), String> { + let args: BaseCommand = BaseCommand::from_args(); + + let authenticated = match &args.subcommand { + BodhiCommand::Comment { .. } => true, + BodhiCommand::ComposeInfo { .. } => false, + BodhiCommand::ComposeList { .. } => false, + BodhiCommand::CreateOverride { .. } => true, + BodhiCommand::CreateUpdate { .. } => true, + BodhiCommand::EditOverride { .. } => true, + BodhiCommand::EditUpdate { .. } => true, + BodhiCommand::ExpireOverride { .. } => true, + BodhiCommand::QueryOverrides { .. } => false, + BodhiCommand::QueryUpdates { .. } => false, + BodhiCommand::ReleaseInfo { .. } => false, + BodhiCommand::ReleaseList { .. } => false, + BodhiCommand::UpdateRequest { .. } => true, + BodhiCommand::WaiveTests { .. } => true, + }; + + let config = get_config()?; + + let mut builder = match (&args.staging, &args.bodhi_url, &args.login_url) { + (false, None, None) => BodhiServiceBuilder::default(), + (true, None, None) => BodhiServiceBuilder::staging(), + (false, Some(url), Some(login_url)) => BodhiServiceBuilder::custom(url.to_owned(), login_url.to_owned()), + _ => unreachable!(), + }; + + let bodhi = if authenticated { + let password = + rpassword::prompt_password_stdout("FAS Password: ").expect("Failed to read password from command line."); + + builder = builder.authentication(&config.fas.username, &password); + + match builder.build() { + Ok(bodhi) => bodhi, + Err(error) => return Err(error.to_string()), + } + } else { + match builder.build() { + Ok(bodhi) => bodhi, + Err(error) => return Err(error.to_string()), + } + }; + + match args.subcommand { + BodhiCommand::Comment { update, text, karma } => { + let update: Update = match bodhi.query(UpdateIDQuery::new(&update)) { + Ok(update) => match update { + Some(update) => update, + None => return Err(String::from("Update not found.")), + }, + Err(error) => return Err(error.to_string()), + }; + + let karma = if let Some(karma) = &karma { + match karma.as_str() { + "1" | "+1" => Some(Karma::Positive), + "0" => Some(Karma::Neutral), + "-1" => Some(Karma::Negative), + _ => return Err(format!("Not a recognised value for karma: {}", karma)), + } + } else { + None + }; + + let mut commenter = update.comment().text(&text); + + if let Some(karma) = karma { + commenter = commenter.karma(karma); + } + + match bodhi.create(&commenter) { + Ok(_) => { + println!("Comment created."); + Ok(()) + }, + Err(error) => Err(error.to_string()), + } + }, + BodhiCommand::ComposeInfo { + release, + request, + format, + } => { + let release = FedoraRelease::try_from(release.as_str())?; + let request = str_to_compose_request(request.as_str())?; + + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let result: Option = match bodhi.query(ComposeReleaseRequestQuery::new(release, request)) { + Ok(compose) => compose, + Err(_) => return Err(format!("Failed to query composes.")), + }; + + match format { + Format::Plain => match result { + Some(compose) => println!("{}", compose), + None => println!("No running compose found for: {}/{}", release, request), + }, + Format::JSON => match result { + Some(compose) => { + let pretty = match serde_json::to_string_pretty(&compose) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + None => {}, + }, + } + + Ok(()) + }, + BodhiCommand::ComposeList { format } => { + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let result: Vec = match bodhi.query(ComposeQuery::new()) { + Ok(composes) => composes, + Err(_) => return Err(format!("Failed to query composes.")), + }; + + match format { + Format::Plain => { + for compose in result { + println!("{}", compose); + } + }, + Format::JSON => { + let pretty = match serde_json::to_string_pretty(&result) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + } + + Ok(()) + }, + BodhiCommand::CreateOverride { nvr, duration, notes } => { + let current_date = chrono::Utc::now(); + let expiration_date = (current_date + chrono::Duration::days(duration as i64)).into(); + + let builder = OverrideBuilder::new(&nvr, ¬es, &expiration_date); + + let result: NewOverride = match bodhi.create(&builder) { + Ok(o) => o, + Err(error) => return Err(error.to_string()), + }; + + if !result.caveats.is_empty() { + println!("Server messages:"); + for caveat in result.caveats { + for (key, value) in caveat { + println!("{}: {}", key, value); + } + } + }; + + println!("{}", result.over_ride); + + Ok(()) + }, + BodhiCommand::CreateUpdate { + autokarma, + autotime, + bugs, + builds, + close_bugs, + display_name, + from_tag, + notes, + requirements, + severity, + stable_days, + stable_karma, + suggestion, + unstable_karma, + update_type, + } => { + let builds: Option> = match &builds { + Some(builds) => Some(builds.iter().map(|b| b.as_str()).collect()), + None => None, + }; + + let mut builder = match (&builds, &from_tag) { + (Some(_), Some(_)) => unreachable!(), + (Some(builds), None) => UpdateBuilder::from_builds(&builds, ¬es), + (None, Some(tag)) => UpdateBuilder::from_tag(&tag, ¬es), + (None, None) => return Err(String::from("Neither builds nor koji tag specified.")), + }; + + if let Some(autokarma) = autokarma { + builder = builder.autokarma(autokarma); + }; + + if let Some(autotime) = autotime { + builder = builder.autotime(autotime); + }; + + if let Some(bugs) = bugs { + for bug in bugs { + builder = builder.bugs(bug); + } + }; + + if let Some(close_bugs) = close_bugs { + builder = builder.close_bugs(close_bugs); + }; + + if let Some(display_name) = display_name { + builder = builder.title(display_name); + }; + + if let Some(requirements) = &requirements { + if !requirements.is_empty() { + builder = builder.requirements(requirements.join(",")); + }; + }; + + if let Some(severity) = severity { + let severity = match severity.to_lowercase().as_str() { + "unspecified" => UpdateSeverity::Unspecified, + "low" => UpdateSeverity::Low, + "medium" => UpdateSeverity::Medium, + "high" => UpdateSeverity::High, + "urgent" => UpdateSeverity::Urgent, + _ => return Err(format!("Not a recognised value for severity: {}", severity)), + }; + + builder = builder.severity(severity); + }; + + if let Some(stable_days) = stable_days { + builder = builder.stable_days(stable_days); + }; + + if let Some(stable_karma) = stable_karma { + builder = builder.stable_karma(stable_karma); + }; + + if let Some(suggestion) = suggestion { + let suggestion = match suggestion.to_lowercase().as_str() { + "unspecified" => UpdateSuggestion::Unspecified, + "reboot" => UpdateSuggestion::Reboot, + "logout" => UpdateSuggestion::Logout, + _ => return Err(format!("Not a recognised value for suggestion: {}", suggestion)), + }; + + builder = builder.suggest(suggestion); + }; + + if let Some(unstable_karma) = unstable_karma { + builder = builder.unstable_karma(unstable_karma); + }; + + if let Some(update_type) = update_type { + let update_type = match update_type.to_lowercase().as_str() { + "unspecified" => UpdateType::Unspecified, + "enhancement" => UpdateType::Enhancement, + "newpackage" => UpdateType::NewPackage, + "bugfix" => UpdateType::BugFix, + "security" => UpdateType::Security, + _ => return Err(format!("Not a recognised value for update type: {}", update_type)), + }; + + builder = builder.update_type(update_type); + }; + + let result: NewUpdate = match bodhi.create(&builder) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + if !result.caveats.is_empty() { + println!("Server messages:"); + for caveat in result.caveats { + for (key, value) in caveat { + println!("{}: {}", key, value); + } + } + }; + + println!("{}", result.update); + + Ok(()) + }, + BodhiCommand::EditOverride { nvr, duration, notes } => { + let over_ride = match bodhi.query(OverrideNVRQuery::new(&nvr)) { + Ok(value) => match value { + Some(over_ride) => over_ride, + None => return Err(format!("No override found for NVR: {}", nvr)), + }, + Err(error) => return Err(error.to_string()), + }; + + let current_date = chrono::Utc::now(); + let expiration_date = (current_date + chrono::Duration::days(duration as i64)).into(); + + let editor = OverrideEditor::from_override(&over_ride) + .expiration_date(&expiration_date) + .notes(¬es); + + let result: EditedOverride = match bodhi.edit(&editor) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + if !result.caveats.is_empty() { + println!("Server messages:"); + for caveat in result.caveats { + for (key, value) in caveat { + println!("{}: {}", key, value); + } + } + }; + + println!("{}", result.over_ride); + + Ok(()) + }, + BodhiCommand::EditUpdate { + alias, + add_bugs, + add_builds, + autokarma, + autotime, + close_bugs, + display_name, + notes, + remove_bugs, + remove_builds, + requirements, + severity, + stable_days, + stable_karma, + suggestion, + unstable_karma, + update_type, + } => { + let update = match bodhi.query(UpdateIDQuery::new(&alias)) { + Ok(value) => match value { + Some(update) => update, + None => return Err(format!("No update found with this alias: {}", alias)), + }, + Err(error) => return Err(error.to_string()), + }; + + let mut editor = UpdateEditor::from_update(&update); + + if let Some(add_bugs) = add_bugs { + for bug in add_bugs { + editor = editor.add_bug(bug); + } + }; + + if let Some(add_builds) = &add_builds { + for build in add_builds { + editor = editor.add_build(build); + } + }; + + if let Some(autokarma) = autokarma { + editor = editor.autokarma(autokarma); + }; + + if let Some(autotime) = autotime { + editor = editor.autotime(autotime); + }; + + if let Some(close_bugs) = close_bugs { + editor = editor.close_bugs(close_bugs); + }; + + if let Some(display_name) = &display_name { + editor = editor.set_title(display_name); + }; + + if let Some(notes) = ¬es { + editor = editor.notes(notes); + } + + if let Some(remove_bugs) = remove_bugs { + for bug in remove_bugs { + editor = editor.remove_bug(bug); + } + }; + + if let Some(remove_builds) = &remove_builds { + for build in remove_builds { + editor = editor.remove_build(build); + } + }; + + let requirements = match &requirements { + Some(reqs) => Some(reqs.join(",")), + None => None, + }; + if let Some(requirements) = &requirements { + editor = editor.requirements(&requirements); + } + + if let Some(severity) = severity { + let severity = match severity.to_lowercase().as_str() { + "unspecified" => UpdateSeverity::Unspecified, + "low" => UpdateSeverity::Low, + "medium" => UpdateSeverity::Medium, + "high" => UpdateSeverity::High, + "urgent" => UpdateSeverity::Urgent, + _ => return Err(format!("Not a recognised value for severity: {}", severity)), + }; + + editor = editor.severity(severity); + }; + + + if let Some(stable_days) = stable_days { + editor = editor.stable_days(stable_days); + }; + + if let Some(stable_karma) = stable_karma { + editor = editor.stable_karma(stable_karma); + }; + + if let Some(suggestion) = suggestion { + let suggestion = match suggestion.to_lowercase().as_str() { + "unspecified" => UpdateSuggestion::Unspecified, + "reboot" => UpdateSuggestion::Reboot, + "logout" => UpdateSuggestion::Logout, + _ => return Err(format!("Not a recognised value for suggestion: {}", suggestion)), + }; + + editor = editor.suggest(suggestion); + }; + + if let Some(unstable_karma) = unstable_karma { + editor = editor.unstable_karma(unstable_karma); + }; + + if let Some(update_type) = update_type { + let update_type = match update_type.to_lowercase().as_str() { + "unspecified" => UpdateType::Unspecified, + "enhancement" => UpdateType::Enhancement, + "newpackage" => UpdateType::NewPackage, + "bugfix" => UpdateType::BugFix, + "security" => UpdateType::Security, + _ => return Err(format!("Not a recognised value for update type: {}", update_type)), + }; + + editor = editor.update_type(update_type); + } + + let result: EditedUpdate = match bodhi.edit(&editor) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + if !result.caveats.is_empty() { + println!("Server messages:"); + for caveat in result.caveats { + for (key, value) in caveat { + println!("{}: {}", key, value); + } + } + }; + + println!("{}", result.update); + + Ok(()) + }, + BodhiCommand::ExpireOverride { nvr } => { + let over_ride = match bodhi.query(OverrideNVRQuery::new(&nvr)) { + Ok(value) => match value { + Some(over_ride) => over_ride, + None => return Err(format!("No override found for NVR: {}", nvr)), + }, + Err(error) => return Err(error.to_string()), + }; + + let editor = OverrideEditor::from_override(&over_ride).expired(true); + + let result: EditedOverride = match bodhi.edit(&editor) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + if !result.caveats.is_empty() { + println!("Server messages:"); + for caveat in result.caveats { + for (key, value) in caveat { + println!("{}: {}", key, value); + } + } + }; + + println!("{}", result.over_ride); + + Ok(()) + }, + BodhiCommand::QueryOverrides { + builds, + expired, + format, + releases, + users, + } => { + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let mut query = OverrideQuery::new(); + + if let Some(builds) = &builds { + for build in builds { + query = query.builds(build); + } + }; + + if let Some(expired) = expired { + query = query.expired(expired); + }; + + if let Some(releases) = releases { + for release in releases { + let release = match FedoraRelease::try_from(release.as_str()) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + query = query.releases(release); + } + }; + + if let Some(users) = &users { + for user in users { + query = query.users(user); + } + }; + + if let Format::Plain = format { + query = query.callback(progress_bar) + }; + + let result: Vec = match bodhi.query(query) { + Ok(overrides) => overrides, + Err(_) => return Err(format!("Failed to query overrides.")), + }; + + match format { + Format::Plain => { + for over_ride in result { + println!("{}", over_ride); + } + }, + Format::JSON => { + let pretty = match serde_json::to_string_pretty(&result) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + } + + Ok(()) + }, + BodhiCommand::QueryUpdates { + alias, + approved_before, + approved_since, + bugs, + builds, + critpath, + content_type, + format, + locked, + modified_before, + modified_since, + packages, + pushed, + pushed_before, + pushed_since, + releases, + request, + severity, + status, + submitted_before, + submitted_since, + suggestion, + update_type, + users, + } => { + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let mut query = UpdateQuery::new(); + + if let Some(alias) = &alias { + query = query.aliases(alias); + }; + + let approved_before = match approved_before { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(approved_before) = approved_before { + query = query.approved_before(approved_before); + }; + + let approved_since = match approved_since { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(approved_since) = approved_since { + query = query.approved_since(approved_since); + }; + + if let Some(bugs) = bugs { + for bug in bugs { + query = query.bugs(bug); + } + }; + + if let Some(builds) = &builds { + for build in builds { + query = query.builds(build); + } + }; + + if let Some(critpath) = critpath { + query = query.critpath(critpath); + }; + + if let Some(content_type) = content_type { + let content_type = match content_type.to_lowercase().as_str() { + "rpm" => ContentType::RPM, + "module" => ContentType::Module, + "flatpak" => ContentType::Flatpak, + "container" => ContentType::Container, + _ => return Err(format!("Not a recognised content type: {}", content_type)), + }; + + query = query.content_type(content_type); + }; + + if let Some(locked) = locked { + query = query.locked(locked); + }; + + let modified_before = match modified_before { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(modified_before) = modified_before { + query = query.modified_before(modified_before); + }; + + let modified_since = match modified_since { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(modified_since) = modified_since { + query = query.modified_since(modified_since); + }; + + if let Some(packages) = &packages { + for package in packages { + query = query.packages(package); + } + }; + + if let Some(pushed) = pushed { + query = query.pushed(pushed); + }; + + let pushed_before = match pushed_before { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(pushed_before) = pushed_before { + query = query.pushed_before(pushed_before); + }; + + let pushed_since = match pushed_since { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(pushed_since) = pushed_since { + query = query.pushed_since(pushed_since); + }; + + if let Some(releases) = releases { + for release in releases { + let release = match FedoraRelease::try_from(release.as_str()) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + query = query.releases(release); + } + }; + + if let Some(request) = request { + let request = match request.to_lowercase().as_str() { + "obsolete" => UpdateRequest::Obsolete, + "revoke" => UpdateRequest::Revoke, + "stable" => UpdateRequest::Stable, + "testing" => UpdateRequest::Testing, + "unpush" => UpdateRequest::Unpush, + _ => return Err(format!("Not a recognised value for update request: {}", request)), + }; + + query = query.request(request); + }; + + if let Some(severity) = severity { + let severity = match severity.to_lowercase().as_str() { + "unspecified" => UpdateSeverity::Unspecified, + "low" => UpdateSeverity::Low, + "medium" => UpdateSeverity::Medium, + "high" => UpdateSeverity::High, + "urgent" => UpdateSeverity::Urgent, + _ => return Err(format!("Not a recognised value for severity: {}", severity)), + }; + + query = query.severity(severity); + }; + + if let Some(status) = status { + let status = match status.to_lowercase().as_str() { + "obsolete" => UpdateStatus::Obsolete, + "pending" => UpdateStatus::Pending, + "side_tag_active" => UpdateStatus::SideTagActive, + "side_tag_expired" => UpdateStatus::SideTagExpired, + "stable" => UpdateStatus::Stable, + "testing" => UpdateStatus::Testing, + "unpushed" => UpdateStatus::Unpushed, + _ => return Err(format!("Not a recognised value for status: {}", status)), + }; + + query = query.status(status); + }; + + let submitted_before = match submitted_before { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(submitted_before) = submitted_before { + query = query.submitted_before(submitted_before); + }; + + let submitted_since = match submitted_since { + Some(date) => match BodhiDate::try_from(date.as_str()) { + Ok(value) => Some(value), + Err(_) => return Err(format!("Date in invalid format: {}", date)), + }, + None => None, + }; + if let Some(submitted_since) = submitted_since { + query = query.submitted_since(submitted_since); + }; + + if let Some(suggestion) = suggestion { + let suggestion = match suggestion.to_lowercase().as_str() { + "unspecified" => UpdateSuggestion::Unspecified, + "reboot" => UpdateSuggestion::Reboot, + "logout" => UpdateSuggestion::Logout, + _ => return Err(format!("Not a recognised value for suggestion: {}", suggestion)), + }; + + query = query.suggest(suggestion); + } + + if let Some(update_type) = update_type { + let update_type = match update_type.to_lowercase().as_str() { + "unspecified" => UpdateType::Unspecified, + "enhancement" => UpdateType::Enhancement, + "newpackage" => UpdateType::NewPackage, + "bugfix" => UpdateType::BugFix, + "security" => UpdateType::Security, + _ => return Err(format!("Not a recognised value for update type: {}", update_type)), + }; + + query = query.update_type(update_type); + }; + + if let Some(users) = &users { + for user in users { + query = query.users(user); + } + }; + + if let Format::Plain = format { + query = query.callback(progress_bar) + }; + + let result: Vec = match bodhi.query(query) { + Ok(updates) => updates, + Err(_) => return Err(format!("Failed to query updates.")), + }; + + match format { + Format::Plain => { + for update in result { + println!("{}", update); + } + }, + Format::JSON => { + let pretty = match serde_json::to_string_pretty(&result) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + } + + Ok(()) + }, + BodhiCommand::ReleaseInfo { release, format } => { + FedoraRelease::try_from(release.as_str())?; + + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let result: Option = match bodhi.query(ReleaseNameQuery::new(&release)) { + Ok(compose) => compose, + Err(_) => return Err(String::from("Failed to query releases.")), + }; + + match format { + Format::Plain => match result { + Some(release) => println!("{}", release), + None => println!("No release found with name: {}", &release), + }, + Format::JSON => match result { + Some(release) => { + let pretty = match serde_json::to_string_pretty(&release) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + None => {}, + }, + } + + Ok(()) + }, + BodhiCommand::ReleaseList { format } => { + let format = match format { + Some(format) => Format::try_from(format.as_str())?, + None => Format::Plain, + }; + + let result: Vec = match bodhi.query(ReleaseQuery::new()) { + Ok(releases) => releases, + Err(_) => return Err(format!("Failed to query releases.")), + }; + + match format { + Format::Plain => { + for release in result { + println!("{}", release); + } + }, + Format::JSON => { + let pretty = match serde_json::to_string_pretty(&result) { + Ok(string) => string, + Err(_) => return Err(String::from("Failed to format output as JSON.")), + }; + + println!("{}", &pretty); + }, + } + + Ok(()) + }, + BodhiCommand::UpdateRequest { alias, request } => { + let request = match request.to_lowercase().as_str() { + "obsolete" => UpdateRequest::Obsolete, + "revoke" => UpdateRequest::Revoke, + "stable" => UpdateRequest::Stable, + "testing" => UpdateRequest::Testing, + "unpush" => UpdateRequest::Unpush, + _ => return Err(format!("Not a recognised value for update request: {}", request)), + }; + + let update: Update = match bodhi.query(UpdateIDQuery::new(&alias)) { + Ok(value) => match value { + Some(update) => update, + None => return Err(format!("No update found with this alias: {}", alias)), + }, + Err(error) => return Err(error.to_string()), + }; + + let editor = UpdateStatusRequester::from_update(&update, request); + + let result: Update = match bodhi.edit(&editor) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + println!("{}", result); + + Ok(()) + }, + BodhiCommand::WaiveTests { alias, comment } => { + let update: Update = match bodhi.query(UpdateIDQuery::new(&alias)) { + Ok(value) => match value { + Some(update) => update, + None => return Err(format!("No update found with this alias: {}", alias)), + }, + Err(error) => return Err(error.to_string()), + }; + + let editor = UpdateTestResultWaiver::from_update(&update, &comment); + + let result: Update = match bodhi.edit(&editor) { + Ok(value) => value, + Err(error) => return Err(error.to_string()), + }; + + println!("{}", result); + + Ok(()) + }, + } }