mirror of
https://github.com/deps-rs/deps.rs.git
synced 2024-11-25 03:26:30 +00:00
Add compact and flat badge styles (#136)
This commit is contained in:
parent
8bdee6b770
commit
262d27dd74
8 changed files with 236 additions and 124 deletions
140
Cargo.lock
generated
140
Cargo.lock
generated
|
@ -38,6 +38,8 @@ dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rusttype",
|
"rusttype",
|
||||||
|
"serde",
|
||||||
|
"serde_urlencoded",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -63,9 +65,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.8.0"
|
version = "3.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c"
|
checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
|
@ -173,9 +175,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-channel"
|
name = "crossbeam-channel"
|
||||||
version = "0.5.1"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
|
checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
|
@ -183,9 +185,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossbeam-utils"
|
name = "crossbeam-utils"
|
||||||
version = "0.8.5"
|
version = "0.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
|
checksum = "cfcae03edb34f947e64acdb1c33ec169824e20657e9ecb61cef6c8c74dcb8120"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
|
@ -263,6 +265,15 @@ dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fastrand"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "779d043b6a0b90cc4c0ed7ee380a6504394cee7efd7db050e3774eee387324b2"
|
||||||
|
dependencies = [
|
||||||
|
"instant",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
|
@ -348,9 +359,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "generic-array"
|
name = "generic-array"
|
||||||
version = "0.14.4"
|
version = "0.14.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
"version_check",
|
"version_check",
|
||||||
|
@ -367,9 +378,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.3"
|
version = "0.2.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
|
checksum = "418d37c8b1d42553c93648be529cb70f920d3baf8ef469b74b9638df426e0b4c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -399,9 +410,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd"
|
checksum = "0c9de88456263e249e241fcd211d3954e2c9b0ef7ccfc235a444eb367cae3689"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
|
@ -451,13 +462,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.5"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b"
|
checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
"itoa 0.4.8",
|
"itoa 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -549,15 +560,24 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.7.0"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
|
checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "instant"
|
||||||
|
version = "0.1.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
@ -800,9 +820,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.4"
|
version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
|
@ -834,9 +854,9 @@ checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-project-lite"
|
name = "pin-project-lite"
|
||||||
version = "0.2.7"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443"
|
checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pin-utils"
|
name = "pin-utils"
|
||||||
|
@ -859,12 +879,6 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.15"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-error"
|
name = "proc-macro-error"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
|
@ -919,46 +933,6 @@ dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
"rand_hc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_hc"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
|
|
||||||
dependencies = [
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.2.10"
|
version = "0.2.10"
|
||||||
|
@ -998,15 +972,16 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.8"
|
version = "0.11.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7c4e0a76dc12a116108933f6301b95e83634e0c47b0afbed6abbaa0601e99258"
|
checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"encoding_rs",
|
"encoding_rs",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"h2",
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
@ -1156,18 +1131,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.132"
|
version = "1.0.133"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b9875c23cf305cd1fd7eb77234cbb705f21ea6a72c637a5c6db5fe4b8e7f008"
|
checksum = "97565067517b60e2d1ea8b268e59ce036de907ac523ad83a0475da04e818989a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.132"
|
version = "1.0.133"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecc0db5cb2556c0e558887d9bbdcf6ac4471e83ff66cf696e5419024d1606276"
|
checksum = "ed201699328568d8d08208fdd080e3ff594e6c422e438b6705905da01005d537"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1176,9 +1151,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.73"
|
version = "1.0.75"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5"
|
checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 1.0.1",
|
"itoa 1.0.1",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -1233,6 +1208,7 @@ dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"serde_urlencoded",
|
||||||
"sha-1",
|
"sha-1",
|
||||||
"slog",
|
"slog",
|
||||||
"slog-async",
|
"slog-async",
|
||||||
|
@ -1306,9 +1282,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.84"
|
version = "1.0.85"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecb2e6da8ee5eb9a61068762a32fa9619cc591ceb055b3687f4cd4051ec2e06b"
|
checksum = "a684ac3dcd8913827e18cd09a68384ee66c1de24157e3c556c9ab16d85695fb7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1323,13 +1299,13 @@ checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.2.0"
|
version = "3.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"fastrand",
|
||||||
"libc",
|
"libc",
|
||||||
"rand",
|
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi",
|
"winapi",
|
||||||
|
@ -1561,9 +1537,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "version_check"
|
name = "version_check"
|
||||||
version = "0.9.3"
|
version = "0.9.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "want"
|
name = "want"
|
||||||
|
|
|
@ -32,6 +32,7 @@ rustsec = "0.25"
|
||||||
semver = { version = "1.0", features = ["serde"] }
|
semver = { version = "1.0", features = ["serde"] }
|
||||||
serde = { version = "1", features = ["derive"] }
|
serde = { version = "1", features = ["derive"] }
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
|
serde_urlencoded = "0.7"
|
||||||
slog = "2"
|
slog = "2"
|
||||||
slog-async = "2"
|
slog-async = "2"
|
||||||
slog-term = "2"
|
slog-term = "2"
|
||||||
|
|
|
@ -15,3 +15,7 @@ path = "badge.rs"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
once_cell = "1"
|
once_cell = "1"
|
||||||
rusttype = "0.9"
|
rusttype = "0.9"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
serde_urlencoded = "0.7"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
use base64::display::Base64Display;
|
use base64::display::Base64Display;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rusttype::{point, Font, Point, PositionedGlyph, Scale};
|
use rusttype::{point, Font, Point, PositionedGlyph, Scale};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
const FONT_DATA: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/DejaVuSans.ttf"));
|
const FONT_DATA: &[u8] = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/DejaVuSans.ttf"));
|
||||||
const FONT_SIZE: f32 = 11.;
|
const FONT_SIZE: f32 = 11.;
|
||||||
|
@ -11,13 +12,37 @@ const SCALE: Scale = Scale {
|
||||||
y: FONT_SIZE,
|
y: FONT_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Badge style name.
|
||||||
|
///
|
||||||
|
/// Default style is "flat".
|
||||||
|
///
|
||||||
|
/// Matches style names from shields.io.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)]
|
||||||
|
#[serde(rename_all = "kebab-case")]
|
||||||
|
pub enum BadgeStyle {
|
||||||
|
Flat,
|
||||||
|
FlatSquare,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for BadgeStyle {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::Flat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
pub struct BadgeOptions {
|
pub struct BadgeOptions {
|
||||||
/// Subject will be displayed on the left side of badge
|
/// Subject will be displayed on the left side of badge
|
||||||
pub subject: String,
|
pub subject: String,
|
||||||
|
|
||||||
/// Status will be displayed on the right side of badge
|
/// Status will be displayed on the right side of badge
|
||||||
pub status: String,
|
pub status: String,
|
||||||
|
|
||||||
/// HTML color of badge
|
/// HTML color of badge
|
||||||
pub color: String,
|
pub color: String,
|
||||||
|
|
||||||
|
/// Style of badge.
|
||||||
|
pub style: BadgeStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BadgeOptions {
|
impl Default for BadgeOptions {
|
||||||
|
@ -26,6 +51,7 @@ impl Default for BadgeOptions {
|
||||||
subject: "build".to_owned(),
|
subject: "build".to_owned(),
|
||||||
status: "passing".to_owned(),
|
status: "passing".to_owned(),
|
||||||
color: "#4c1".to_owned(),
|
color: "#4c1".to_owned(),
|
||||||
|
style: BadgeStyle::Flat,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,48 +92,78 @@ impl Badge {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_svg(&self) -> String {
|
pub fn to_svg(&self) -> String {
|
||||||
|
match self.options.style {
|
||||||
|
BadgeStyle::Flat => self.to_flat_svg(),
|
||||||
|
BadgeStyle::FlatSquare => self.to_flat_square_svg(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_flat_svg(&self) -> String {
|
||||||
let left_width = self.calculate_width(&self.options.subject) + 6;
|
let left_width = self.calculate_width(&self.options.subject) + 6;
|
||||||
let right_width = self.calculate_width(&self.options.status) + 6;
|
let right_width = self.calculate_width(&self.options.status) + 6;
|
||||||
|
let total_width = left_width + right_width;
|
||||||
|
|
||||||
|
let left_center = left_width / 2;
|
||||||
|
let right_center = left_width + (right_width / 2);
|
||||||
|
|
||||||
|
let color = &self.options.color;
|
||||||
|
let subject = &self.options.subject;
|
||||||
|
let status = &self.options.status;
|
||||||
|
|
||||||
let svg = format!(
|
let svg = format!(
|
||||||
r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{}" height="20">
|
r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{total_width}" height="20">
|
||||||
<linearGradient id="smooth" x2="0" y2="100%">
|
<linearGradient id="smooth" x2="0" y2="100%">
|
||||||
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
<stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
|
||||||
<stop offset="1" stop-opacity=".1"/>
|
<stop offset="1" stop-opacity=".1"/>
|
||||||
</linearGradient>
|
</linearGradient>
|
||||||
|
|
||||||
<mask id="round">
|
<mask id="round">
|
||||||
<rect width="{}" height="20" rx="3" fill="#fff"/>
|
<rect width="{total_width}" height="20" rx="3" fill="#fff"/>
|
||||||
</mask>
|
</mask>
|
||||||
|
|
||||||
<g mask="url(#round)">
|
<g mask="url(#round)">
|
||||||
<rect width="{}" height="20" fill="#555"/>
|
<rect width="{left_width}" height="20" fill="#555"/>
|
||||||
<rect x="{}" width="{}" height="20" fill="{}"/>
|
<rect width="{right_width}" height="20" x="{left_width}" fill="{color}"/>
|
||||||
<rect width="{}" height="20" fill="url(#smooth)"/>
|
<rect width="{total_width}" height="20" fill="url(#smooth)"/>
|
||||||
</g>
|
</g>
|
||||||
|
|
||||||
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||||
<text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
|
<text x="{left_center}" y="15" fill="#010101" fill-opacity=".3">{subject}</text>
|
||||||
<text x="{}" y="14">{}</text>
|
<text x="{left_center}" y="14">{subject}</text>
|
||||||
<text x="{}" y="15" fill="#010101" fill-opacity=".3">{}</text>
|
<text x="{right_center}" y="15" fill="#010101" fill-opacity=".3">{status}</text>
|
||||||
<text x="{}" y="14">{}</text>
|
<text x="{right_center}" y="14">{status}</text>
|
||||||
</g>
|
</g>
|
||||||
</svg>"###,
|
</svg>"###
|
||||||
left_width + right_width,
|
);
|
||||||
left_width + right_width,
|
|
||||||
left_width,
|
svg
|
||||||
left_width,
|
}
|
||||||
right_width,
|
|
||||||
self.options.color,
|
pub fn to_flat_square_svg(&self) -> String {
|
||||||
left_width + right_width,
|
let left_width = self.calculate_width(&self.options.subject) + 6;
|
||||||
(left_width) / 2,
|
let right_width = self.calculate_width(&self.options.status) + 6;
|
||||||
self.options.subject,
|
let total_width = left_width + right_width;
|
||||||
(left_width) / 2,
|
|
||||||
self.options.subject,
|
let left_center = left_width / 2;
|
||||||
left_width + (right_width / 2),
|
let right_center = left_width + (right_width / 2);
|
||||||
self.options.status,
|
|
||||||
left_width + (right_width / 2),
|
let color = &self.options.color;
|
||||||
self.options.status
|
let subject = &self.options.subject;
|
||||||
|
let status = &self.options.status;
|
||||||
|
|
||||||
|
let svg = format!(
|
||||||
|
r###"<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="{total_width}" height="20">
|
||||||
|
<g mask="url(#round)">
|
||||||
|
<rect width="{left_width}" height="20" fill="#555"/>
|
||||||
|
<rect width="{right_width}" height="20" x="{left_width}" fill="{color}"/>
|
||||||
|
</g>
|
||||||
|
|
||||||
|
<g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
|
||||||
|
<text x="{left_center}" y="14">{subject}</text>
|
||||||
|
<text x="{right_center}" y="14">{status}</text>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
"###,
|
||||||
);
|
);
|
||||||
|
|
||||||
svg
|
svg
|
||||||
|
@ -158,4 +214,18 @@ mod tests {
|
||||||
let badge = Badge::new(options);
|
let badge = Badge::new(options);
|
||||||
file.write_all(badge.to_svg().as_bytes()).unwrap();
|
file.write_all(badge.to_svg().as_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn deserialize_badge_style() {
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct Foo {
|
||||||
|
style: BadgeStyle,
|
||||||
|
}
|
||||||
|
|
||||||
|
let style = serde_urlencoded::from_str::<Foo>("style=flat").unwrap();
|
||||||
|
assert_eq!(style.style, BadgeStyle::Flat);
|
||||||
|
|
||||||
|
let style = serde_urlencoded::from_str::<Foo>("style=flat-square").unwrap();
|
||||||
|
assert_eq!(style.style, BadgeStyle::FlatSquare);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,10 +72,10 @@ async fn main() {
|
||||||
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port);
|
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), port);
|
||||||
|
|
||||||
let mut managed_index = ManagedIndex::new(Duration::from_secs(20), logger.clone());
|
let mut managed_index = ManagedIndex::new(Duration::from_secs(20), logger.clone());
|
||||||
if let Err(e) = managed_index.initial_clone().await {
|
if let Err(err) = managed_index.initial_clone().await {
|
||||||
error!(
|
error!(
|
||||||
logger,
|
logger,
|
||||||
"failed running initial clone of the crates.io-index: {}", e
|
"failed running initial clone of the crates.io-index: {err}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{env, sync::Arc, time::Instant};
|
use std::{env, sync::Arc, time::Instant};
|
||||||
|
|
||||||
|
use badge::BadgeStyle;
|
||||||
use futures_util::future;
|
use futures_util::future;
|
||||||
use hyper::{
|
use hyper::{
|
||||||
header::{CACHE_CONTROL, CONTENT_TYPE, ETAG, LOCATION},
|
header::{CACHE_CONTROL, CONTENT_TYPE, ETAG, LOCATION},
|
||||||
|
@ -8,6 +9,7 @@ use hyper::{
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use route_recognizer::{Params, Router};
|
use route_recognizer::{Params, Router};
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
|
use serde::Deserialize;
|
||||||
use slog::{error, info, o, Logger};
|
use slog::{error, info, o, Logger};
|
||||||
|
|
||||||
mod assets;
|
mod assets;
|
||||||
|
@ -162,7 +164,7 @@ impl App {
|
||||||
|
|
||||||
async fn repo_status(
|
async fn repo_status(
|
||||||
&self,
|
&self,
|
||||||
_req: Request<Body>,
|
req: Request<Body>,
|
||||||
params: Params,
|
params: Params,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
format: StatusFormat,
|
format: StatusFormat,
|
||||||
|
@ -173,6 +175,8 @@ impl App {
|
||||||
let qual = params.find("qual").expect("route param 'qual' not found");
|
let qual = params.find("qual").expect("route param 'qual' not found");
|
||||||
let name = params.find("name").expect("route param 'name' not found");
|
let name = params.find("name").expect("route param 'name' not found");
|
||||||
|
|
||||||
|
let badge_knobs = BadgeKnobs::from_query_string(req.uri().query());
|
||||||
|
|
||||||
let repo_path_result = RepoPath::from_parts(site, qual, name);
|
let repo_path_result = RepoPath::from_parts(site, qual, name);
|
||||||
|
|
||||||
match repo_path_result {
|
match repo_path_result {
|
||||||
|
@ -195,8 +199,12 @@ impl App {
|
||||||
match analyze_result {
|
match analyze_result {
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(logger, "error: {}", err);
|
error!(logger, "error: {}", err);
|
||||||
let response =
|
let response = App::status_format_analysis(
|
||||||
App::status_format_analysis(None, format, SubjectPath::Repo(repo_path));
|
None,
|
||||||
|
format,
|
||||||
|
SubjectPath::Repo(repo_path),
|
||||||
|
badge_knobs,
|
||||||
|
);
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
Ok(analysis_outcome) => {
|
Ok(analysis_outcome) => {
|
||||||
|
@ -204,6 +212,7 @@ impl App {
|
||||||
Some(analysis_outcome),
|
Some(analysis_outcome),
|
||||||
format,
|
format,
|
||||||
SubjectPath::Repo(repo_path),
|
SubjectPath::Repo(repo_path),
|
||||||
|
badge_knobs,
|
||||||
);
|
);
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
@ -280,7 +289,7 @@ impl App {
|
||||||
|
|
||||||
async fn crate_status(
|
async fn crate_status(
|
||||||
&self,
|
&self,
|
||||||
_req: Request<Body>,
|
req: Request<Body>,
|
||||||
params: Params,
|
params: Params,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
format: StatusFormat,
|
format: StatusFormat,
|
||||||
|
@ -292,6 +301,8 @@ impl App {
|
||||||
.find("version")
|
.find("version")
|
||||||
.expect("route param 'version' not found");
|
.expect("route param 'version' not found");
|
||||||
|
|
||||||
|
let badge_knobs = BadgeKnobs::from_query_string(req.uri().query());
|
||||||
|
|
||||||
let crate_path_result = CratePath::from_parts(name, version);
|
let crate_path_result = CratePath::from_parts(name, version);
|
||||||
|
|
||||||
match crate_path_result {
|
match crate_path_result {
|
||||||
|
@ -317,6 +328,7 @@ impl App {
|
||||||
None,
|
None,
|
||||||
format,
|
format,
|
||||||
SubjectPath::Crate(crate_path),
|
SubjectPath::Crate(crate_path),
|
||||||
|
badge_knobs,
|
||||||
);
|
);
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
|
@ -325,6 +337,7 @@ impl App {
|
||||||
Some(analysis_outcome),
|
Some(analysis_outcome),
|
||||||
format,
|
format,
|
||||||
SubjectPath::Crate(crate_path),
|
SubjectPath::Crate(crate_path),
|
||||||
|
badge_knobs,
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
|
@ -338,9 +351,10 @@ impl App {
|
||||||
analysis_outcome: Option<AnalyzeDependenciesOutcome>,
|
analysis_outcome: Option<AnalyzeDependenciesOutcome>,
|
||||||
format: StatusFormat,
|
format: StatusFormat,
|
||||||
subject_path: SubjectPath,
|
subject_path: SubjectPath,
|
||||||
|
badge_knobs: BadgeKnobs,
|
||||||
) -> Response<Body> {
|
) -> Response<Body> {
|
||||||
match format {
|
match format {
|
||||||
StatusFormat::Svg => views::badge::response(analysis_outcome.as_ref()),
|
StatusFormat::Svg => views::badge::response(analysis_outcome.as_ref(), badge_knobs),
|
||||||
StatusFormat::Html => views::html::status::render(analysis_outcome, subject_path),
|
StatusFormat::Html => views::html::status::render(analysis_outcome, subject_path),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,3 +381,28 @@ fn not_found() -> Response<Body> {
|
||||||
|
|
||||||
static SELF_BASE_URL: Lazy<String> =
|
static SELF_BASE_URL: Lazy<String> =
|
||||||
Lazy::new(|| env::var("BASE_URL").unwrap_or_else(|_| "http://localhost:8080".to_string()));
|
Lazy::new(|| env::var("BASE_URL").unwrap_or_else(|_| "http://localhost:8080".to_string()));
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct BadgeKnobs {
|
||||||
|
style: BadgeStyle,
|
||||||
|
compact: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BadgeKnobs {
|
||||||
|
fn from_query_string(qs: Option<&str>) -> Self {
|
||||||
|
#[derive(Debug, Clone, Default, Deserialize)]
|
||||||
|
struct BadgeKnobsPartial {
|
||||||
|
style: Option<BadgeStyle>,
|
||||||
|
compact: Option<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let badge_knobs = qs
|
||||||
|
.and_then(|qs| serde_urlencoded::from_str::<BadgeKnobsPartial>(qs).ok())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
Self {
|
||||||
|
style: badge_knobs.style.unwrap_or_default(),
|
||||||
|
compact: badge_knobs.compact.unwrap_or_default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,60 +3,80 @@ use hyper::header::CONTENT_TYPE;
|
||||||
use hyper::{Body, Response};
|
use hyper::{Body, Response};
|
||||||
|
|
||||||
use crate::engine::AnalyzeDependenciesOutcome;
|
use crate::engine::AnalyzeDependenciesOutcome;
|
||||||
|
use crate::server::BadgeKnobs;
|
||||||
|
|
||||||
|
pub fn badge(
|
||||||
|
analysis_outcome: Option<&AnalyzeDependenciesOutcome>,
|
||||||
|
badge_knobs: BadgeKnobs,
|
||||||
|
) -> Badge {
|
||||||
|
let subject = if badge_knobs.compact {
|
||||||
|
"deps"
|
||||||
|
} else {
|
||||||
|
"dependencies"
|
||||||
|
}
|
||||||
|
.to_owned();
|
||||||
|
|
||||||
pub fn badge(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> Badge {
|
|
||||||
let opts = match analysis_outcome {
|
let opts = match analysis_outcome {
|
||||||
Some(outcome) => {
|
Some(outcome) => {
|
||||||
if outcome.any_always_insecure() {
|
if outcome.any_always_insecure() {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: "insecure".into(),
|
status: "insecure".into(),
|
||||||
color: "#e05d44".into(),
|
color: "#e05d44".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let (outdated, total) = outcome.outdated_ratio();
|
let (outdated, total) = outcome.outdated_ratio();
|
||||||
|
|
||||||
if outdated > 0 {
|
if outdated > 0 {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: format!("{} of {} outdated", outdated, total),
|
status: format!("{} of {} outdated", outdated, total),
|
||||||
color: "#dfb317".into(),
|
color: "#dfb317".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
}
|
}
|
||||||
} else if total > 0 {
|
} else if total > 0 {
|
||||||
if outcome.any_insecure() {
|
if outcome.any_insecure() {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: "maybe insecure".into(),
|
status: "maybe insecure".into(),
|
||||||
color: "#8b1".into(),
|
color: "#8b1".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: "up to date".into(),
|
status: "up to date".into(),
|
||||||
color: "#4c1".into(),
|
color: "#4c1".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
BadgeOptions {
|
BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: "none".into(),
|
status: "none".into(),
|
||||||
color: "#4c1".into(),
|
color: "#4c1".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => BadgeOptions {
|
None => BadgeOptions {
|
||||||
subject: "dependencies".into(),
|
subject,
|
||||||
status: "unknown".into(),
|
status: "unknown".into(),
|
||||||
color: "#9f9f9f".into(),
|
color: "#9f9f9f".into(),
|
||||||
|
style: badge_knobs.style,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Badge::new(opts)
|
Badge::new(opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn response(analysis_outcome: Option<&AnalyzeDependenciesOutcome>) -> Response<Body> {
|
pub fn response(
|
||||||
let badge = badge(analysis_outcome).to_svg();
|
analysis_outcome: Option<&AnalyzeDependenciesOutcome>,
|
||||||
|
badge_knobs: BadgeKnobs,
|
||||||
|
) -> Response<Body> {
|
||||||
|
let badge = badge(analysis_outcome, badge_knobs).to_svg();
|
||||||
|
|
||||||
Response::builder()
|
Response::builder()
|
||||||
.header(CONTENT_TYPE, "image/svg+xml; charset=utf-8")
|
.header(CONTENT_TYPE, "image/svg+xml; charset=utf-8")
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::models::crates::{AnalyzedDependencies, AnalyzedDependency, CrateName}
|
||||||
use crate::models::repo::RepoSite;
|
use crate::models::repo::RepoSite;
|
||||||
use crate::models::SubjectPath;
|
use crate::models::SubjectPath;
|
||||||
use crate::server::views::badge;
|
use crate::server::views::badge;
|
||||||
|
use crate::server::BadgeKnobs;
|
||||||
|
|
||||||
fn get_crates_url(name: impl AsRef<str>) -> String {
|
fn get_crates_url(name: impl AsRef<str>) -> String {
|
||||||
format!("https://crates.io/crates/{}", name.as_ref())
|
format!("https://crates.io/crates/{}", name.as_ref())
|
||||||
|
@ -343,7 +344,8 @@ fn render_success(
|
||||||
};
|
};
|
||||||
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
let status_base_url = format!("{}/{}", &super::SELF_BASE_URL as &str, self_path);
|
||||||
|
|
||||||
let status_data_uri = badge::badge(Some(&analysis_outcome)).to_svg_data_uri();
|
let status_data_uri =
|
||||||
|
badge::badge(Some(&analysis_outcome), BadgeKnobs::default()).to_svg_data_uri();
|
||||||
|
|
||||||
let hero_class = if analysis_outcome.any_always_insecure() {
|
let hero_class = if analysis_outcome.any_always_insecure() {
|
||||||
"is-danger"
|
"is-danger"
|
||||||
|
|
Loading…
Reference in a new issue