From c5bd23ceac17676e7b1d1c5aa1063a1da6405285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 26 Jul 2025 12:10:42 +0200 Subject: [PATCH 01/19] Add rendering of the web into a directory --- Cargo.lock | 399 ++++++++++++----------- Cargo.toml | 5 +- src/cache.rs | 2 +- src/i18n.rs | 2 +- src/main.rs | 109 ++++--- src/render/assets.rs | 125 +++++++ src/render/fs.rs | 11 + src/render/mod.rs | 244 ++++++++++++++ src/rust_version.rs | 4 +- src/teams.rs | 4 +- templates/governance/index-team.html.hbs | 2 +- templates/governance/index.html.hbs | 2 +- 12 files changed, 670 insertions(+), 239 deletions(-) create mode 100644 src/render/assets.rs create mode 100644 src/render/fs.rs create mode 100644 src/render/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a01260ba9..3a626f725 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + [[package]] name = "async-stream" version = "0.3.6" @@ -45,7 +51,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -56,7 +62,7 @@ checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -146,12 +152,6 @@ version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.10.1" @@ -234,6 +234,41 @@ dependencies = [ "typenum", ] +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + [[package]] name = "deranged" version = "0.4.0" @@ -243,6 +278,37 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + [[package]] name = "devise" version = "0.4.2" @@ -273,7 +339,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -294,7 +360,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -367,22 +433,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb74634707bebd0ce645a981148e8fb8c7bccd4c33c652aeffd28bf2f96d555a" dependencies = [ "fluent-bundle 0.15.3", - "unic-langid 0.9.5", -] - -[[package]] -name = "fluent-bundle" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27ade33328521266c81cc0924523988f43ccd7359f64689a1b6e818afca3a646" -dependencies = [ - "fluent-langneg 0.12.1", - "fluent-syntax 0.9.3", - "intl-memoizer 0.4.0", - "intl_pluralrules 6.0.0", - "rental", - "smallvec", - "unic-langid 0.8.0", + "unic-langid", ] [[package]] @@ -391,23 +442,30 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493" dependencies = [ - "fluent-langneg 0.13.0", + "fluent-langneg", "fluent-syntax 0.11.1", - "intl-memoizer 0.5.2", - "intl_pluralrules 7.0.2", - "rustc-hash", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 1.1.0", "self_cell 0.10.3", "smallvec", - "unic-langid 0.9.5", + "unic-langid", ] [[package]] -name = "fluent-langneg" -version = "0.12.1" +name = "fluent-bundle" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe5815efd5542e40841cd34ef9003822352b04c67a70c595c6758597c72e1f56" +checksum = "01203cb8918f5711e73891b347816d932046f95f54207710bda99beaeb423bf4" dependencies = [ - "unic-langid 0.8.0", + "fluent-langneg", + "fluent-syntax 0.12.0", + "intl-memoizer", + "intl_pluralrules", + "rustc-hash 2.1.1", + "self_cell 1.2.0", + "smallvec", + "unic-langid", ] [[package]] @@ -416,22 +474,26 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c4ad0989667548f06ccd0e306ed56b61bd4d35458d54df5ec7587c0e8ed5e94" dependencies = [ - "unic-langid 0.9.5", + "unic-langid", ] [[package]] name = "fluent-syntax" -version = "0.9.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac0f7e83d14cccbf26e165d8881dcac5891af0d85a88543c09dd72ebd31d91ba" +checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +dependencies = [ + "thiserror 1.0.69", +] [[package]] name = "fluent-syntax" -version = "0.11.1" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d" +checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ - "thiserror 1.0.69", + "memchr", + "thiserror 2.0.12", ] [[package]] @@ -538,15 +600,6 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generator" version = "0.7.5" @@ -657,20 +710,37 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "handlebars" +version = "6.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759e2d5aea3287cb1190c8ec394f42866cb5bf74fcbf213f354e3c856ea26098" +dependencies = [ + "derive_builder", + "log", + "num-order", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror 2.0.12", + "walkdir", +] + [[package]] name = "handlebars-fluent" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb39cffd370c96a5de57ec5242f385bfb7d52facd774881d81e89621ce7d87e" +checksum = "37b8edde54ea32a8db20ef42b0b30f8bb3244ec87c4801bdd3db53046b3807eb" dependencies = [ "fluent", - "fluent-bundle 0.11.0", - "fluent-langneg 0.12.1", - "fluent-syntax 0.11.1", - "handlebars", + "fluent-bundle 0.16.0", + "fluent-langneg", + "fluent-syntax 0.12.0", + "handlebars 6.3.2", "lazy_static", "serde_json", - "unic-langid 0.8.0", + "unic-langid", ] [[package]] @@ -876,7 +946,7 @@ checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", - "tinystr 0.7.6", + "tinystr", "writeable", "zerovec", ] @@ -891,7 +961,7 @@ dependencies = [ "icu_locid", "icu_locid_transform_data", "icu_provider", - "tinystr 0.7.6", + "tinystr", "zerovec", ] @@ -936,7 +1006,7 @@ dependencies = [ "icu_locid_transform", "icu_properties_data", "icu_provider", - "tinystr 0.7.6", + "tinystr", "zerovec", ] @@ -956,7 +1026,7 @@ dependencies = [ "icu_locid", "icu_provider_macros", "stable_deref_trait", - "tinystr 0.7.6", + "tinystr", "writeable", "yoke", "zerofrom", @@ -971,9 +1041,15 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "1.0.3" @@ -1034,41 +1110,32 @@ dependencies = [ [[package]] name = "intl-memoizer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9867e2d65d82936ef34217ed0f87b639a94384e93a0676158142c861c705391f" -dependencies = [ - "type-map 0.3.0", - "unic-langid 0.8.0", -] - -[[package]] -name = "intl-memoizer" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda" +checksum = "310da2e345f5eb861e7a07ee182262e94975051db9e4223e909ba90f392f163f" dependencies = [ - "type-map 0.5.0", - "unic-langid 0.9.5", + "type-map", + "unic-langid", ] [[package]] name = "intl_pluralrules" -version = "6.0.0" +version = "7.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82c14d8eece42c03353e0ce86a4d3f97b1f1cef401e4d962dca6c6214a85002" +checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" dependencies = [ - "tinystr 0.3.4", - "unic-langid 0.8.0", + "unic-langid", ] [[package]] -name = "intl_pluralrules" -version = "7.0.2" +name = "io-uring" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972" +checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" dependencies = [ - "unic-langid 0.9.5", + "bitflags 2.9.0", + "cfg-if", + "libc", ] [[package]] @@ -1323,6 +1390,21 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1371,7 +1453,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1441,7 +1523,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1481,7 +1563,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1551,7 +1633,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "version_check", "yansi", ] @@ -1627,7 +1709,7 @@ checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -1674,27 +1756,6 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" -[[package]] -name = "rental" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc89fe2acac36d212474d138aaf939c04a82df5b61d07011571ebce5aef81f2e" -dependencies = [ - "rental-impl", - "stable_deref_trait", -] - -[[package]] -name = "rental-impl" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "475e68978dc5b743f2f40d8e0a8fdc83f1c5e78cbf4b8fa5e74e73beebc340de" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "reqwest" version = "0.12.15" @@ -1802,7 +1863,7 @@ dependencies = [ "proc-macro2", "quote", "rocket_http", - "syn 2.0.100", + "syn", "unicode-xid", "version_check", ] @@ -1813,7 +1874,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bbab919c9e67df3f7ac6624a32ef897df4cd61c0969f4d66f3ced0534660d7a" dependencies = [ - "handlebars", + "handlebars 5.1.2", "normpath", "notify", "rocket", @@ -1868,6 +1929,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + [[package]] name = "rustix" version = "1.0.5" @@ -2039,7 +2106,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2166,21 +2233,16 @@ dependencies = [ ] [[package]] -name = "subtle" -version = "2.6.1" +name = "strsim" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] -name = "syn" -version = "1.0.109" +name = "subtle" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" @@ -2210,7 +2272,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2273,7 +2335,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2284,7 +2346,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2328,12 +2390,6 @@ dependencies = [ "time-core", ] -[[package]] -name = "tinystr" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1" - [[package]] name = "tinystr" version = "0.7.6" @@ -2346,16 +2402,19 @@ dependencies = [ [[package]] name = "tokio" -version = "1.44.2" +version = "1.46.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" +checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" dependencies = [ "backtrace", "bytes", + "io-uring", "libc", "mio 1.0.3", + "parking_lot", "pin-project-lite", "signal-hook-registry", + "slab", "socket2", "tokio-macros", "windows-sys 0.52.0", @@ -2369,7 +2428,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2503,7 +2562,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -2551,22 +2610,13 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "type-map" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2741b1474c327d95c1f1e3b0a2c3977c8e128409c572a33af2914e7d636717" -dependencies = [ - "fxhash", -] - [[package]] name = "type-map" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f" dependencies = [ - "rustc-hash", + "rustc-hash 1.1.0", ] [[package]] @@ -2600,32 +2650,14 @@ dependencies = [ "version_check", ] -[[package]] -name = "unic-langid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d81136159f779c35b10655f45210c71cd5ca5a45aadfe9840a61c7071735ed" -dependencies = [ - "unic-langid-impl 0.8.0", - "unic-langid-macros", -] - [[package]] name = "unic-langid" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" dependencies = [ - "unic-langid-impl 0.9.5", -] - -[[package]] -name = "unic-langid-impl" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43c61e94492eb67f20facc7b025778a904de83d953d8fcb60dd9adfd6e2d0ea" -dependencies = [ - "tinystr 0.3.4", + "unic-langid-impl", + "unic-langid-macros", ] [[package]] @@ -2634,31 +2666,31 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" dependencies = [ - "tinystr 0.7.6", + "tinystr", ] [[package]] name = "unic-langid-macros" -version = "0.8.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49bd90791278634d57e3ed4a4073108e3f79bfb87ab6a7b8664ba097425703df" +checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" dependencies = [ "proc-macro-hack", - "tinystr 0.3.4", - "unic-langid-impl 0.8.0", + "tinystr", + "unic-langid-impl", "unic-langid-macros-impl", ] [[package]] name = "unic-langid-macros-impl" -version = "0.8.0" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0098f77bd754f8fb7850cdf4ab143aa821898c4ac6dc16bcb2aa3e62ce858d1" +checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b" dependencies = [ "proc-macro-hack", "quote", - "syn 1.0.109", - "unic-langid-impl 0.8.0", + "syn", + "unic-langid-impl", ] [[package]] @@ -2776,7 +2808,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.100", + "syn", "wasm-bindgen-shared", ] @@ -2811,7 +2843,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3156,6 +3188,8 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" name = "www-rust-lang-org" version = "0.1.0" dependencies = [ + "anyhow", + "handlebars 6.3.2", "handlebars-fluent", "percent-encoding", "reqwest", @@ -3166,6 +3200,7 @@ dependencies = [ "serde", "serde_json", "time", + "tokio", "toml", ] @@ -3198,7 +3233,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "synstructure", ] @@ -3219,7 +3254,7 @@ checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] [[package]] @@ -3239,7 +3274,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", "synstructure", ] @@ -3268,5 +3303,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.100", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 29c5346ce..50b06cb6b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,10 @@ authors = ["The Rust Project Developers"] edition = "2024" [dependencies] -handlebars-fluent = "0.4.0" +anyhow = "1" +tokio = { version = "1", features = ["full"] } +handlebars = { version = "6", features = ["dir_source"] } +handlebars-fluent = "0.5" rocket = "0.5.1" rocket_dyn_templates = { version = "0.2.0", features = ["handlebars"] } serde = { version = "1.0", features = ["derive"] } diff --git a/src/cache.rs b/src/cache.rs index ec5adb61d..652c7b91d 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -13,7 +13,7 @@ pub type Cache = State>>; pub trait Cached: Send + Sync + Clone + 'static { fn get_timestamp(&self) -> Instant; - fn fetch() -> impl Future>> + Send; + fn fetch() -> impl Future> + Send; async fn get(cache: &Cache) -> Self { let cached = cache.read().await.clone(); let timestamp = cached.get_timestamp(); diff --git a/src/i18n.rs b/src/i18n.rs index 3b2eb75cf..5f2cce7a1 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -1,4 +1,4 @@ -use rocket_dyn_templates::handlebars::{ +use handlebars::{ Context, Handlebars, Helper, HelperDef, HelperResult, Output, RenderContext, RenderErrorReason, }; diff --git a/src/main.rs b/src/main.rs index a7d5c270a..a928eac33 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ mod i18n; mod redirect; mod rust_version; mod teams; +mod render; use cache::Cache; use cache::Cached; @@ -20,11 +21,14 @@ use teams::encode_zulip_stream; use std::collections::hash_map::DefaultHasher; use std::env; use std::fs; +use std::fs::File; use std::hash::Hasher; +use std::io::BufWriter; use std::path::{Path, PathBuf}; use std::sync::Arc; use std::sync::LazyLock; - +use anyhow::Context as _; +use handlebars::{DirectorySourceOptions, Handlebars}; use rocket::{ fs::NamedFile, http::Status, @@ -38,7 +42,7 @@ use sass_rs::{Options, compile_file}; use category::Category; use caching::CachedNamedFile; -use handlebars_fluent::{FluentHelper, loader::Loader}; +use handlebars_fluent::{FluentHelper, loader::Loader, simple_loader}; use i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SupportedLocale, TeamHelper, create_loader}; const ZULIP_DOMAIN: &str = "https://rust-lang.zulipchat.com"; @@ -404,50 +408,59 @@ fn render_subject(category: Category, subject: &str, lang: String) -> Result _ { - let templating = Template::custom(|engine| { - engine - .handlebars - .register_helper("fluent", Box::new(FluentHelper::new(create_loader()))); - engine - .handlebars - .register_helper("team-text", Box::new(TeamHelper::new())); - engine - .handlebars - .register_helper("encode-zulip-stream", Box::new(encode_zulip_stream)); - }); - - let rust_version = RustVersion::fetch().await.unwrap_or_default(); - let teams = RustTeams::fetch().await.unwrap_or_default(); - - rocket::build() - .attach(templating) - .attach(headers::InjectHeaders) - .manage(Arc::new(RwLock::new(rust_version))) - .manage(Arc::new(RwLock::new(teams))) - .mount( - "/", - rocket::routes![ - index, - category_en, - governance, - team, - subject, - files, - robots_txt, - logos, - index_locale, - category_locale, - governance_locale, - team_locale, - subject_locale, - redirect_bare_en_us, - well_known_security, - ], - ) - .register( - "/", - rocket::catchers![not_found, unprocessable_content, catch_error], - ) +// #[rocket::launch] +// async fn rocket() -> _ { +// let templating = Template::custom(|engine| { +// engine +// .handlebars +// .register_helper("fluent", Box::new(FluentHelper::new(create_loader()))); +// engine +// .handlebars +// .register_helper("team-text", Box::new(TeamHelper::new())); +// engine +// .handlebars +// .register_helper("encode-zulip-stream", Box::new(encode_zulip_stream)); +// }); +// +// let rust_version = RustVersion::fetch().await.unwrap_or_default(); +// let teams = RustTeams::fetch().await.unwrap_or_default(); +// +// rocket::build() +// .attach(templating) +// .attach(headers::InjectHeaders) +// .manage(Arc::new(RwLock::new(rust_version))) +// .manage(Arc::new(RwLock::new(teams))) +// .mount( +// "/", +// rocket::routes![ +// index, +// category_en, +// governance, +// team, +// subject, +// files, +// robots_txt, +// logos, +// index_locale, +// category_locale, +// governance_locale, +// team_locale, +// subject_locale, +// redirect_bare_en_us, +// well_known_security, +// ], +// ) +// .register( +// "/", +// rocket::catchers![not_found, unprocessable_content, catch_error], +// ) +// } + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let rust_version = RustVersion::fetch().await?; + let teams = RustTeams::fetch().await?; + render::render(rust_version, teams)?; + + Ok(()) } diff --git a/src/render/assets.rs b/src/render/assets.rs new file mode 100644 index 000000000..4806ba655 --- /dev/null +++ b/src/render/assets.rs @@ -0,0 +1,125 @@ +use crate::render::fs::ensure_directory; +use anyhow::Context; +use rocket::serde::Serialize; +use sass_rs::{Options, compile_file}; +use std::fs; +use std::hash::{DefaultHasher, Hasher}; +use std::path::Path; + +fn write_file(path: &Path, bytes: &[u8]) -> anyhow::Result<()> { + ensure_directory(path)?; + Ok(fs::write(path, bytes)?) +} + +fn hash_string(content: &str) -> String { + let mut hasher = DefaultHasher::new(); + hasher.write(content.as_bytes()); + hasher.finish().to_string() +} + +fn relative_url(path: &Path, out_dir: &Path) -> anyhow::Result { + Ok(path.strip_prefix(out_dir)?.to_str().unwrap().to_string()) +} + +/// Compiles SASS file, stores it in `out_dir` and returns the relative URL to it. +fn compile_sass(root_dir: &Path, out_dir: &Path, filename: &str) -> anyhow::Result { + let scss_file = root_dir + .join("src") + .join("styles") + .join(format!("{filename}.scss")); + + let css = compile_file(&scss_file, Options::default()) + .map_err(|e| anyhow::anyhow!("{e}")) + .with_context(|| anyhow::anyhow!("couldn't compile sass: {}", scss_file.display()))?; + + let css_sha = format!("{filename}_{}", hash_string(&css)); + let out_css_path = out_dir + .join("static") + .join("styles") + .join(format!("{css_sha}.css")); + + write_file(&out_css_path, &css.into_bytes()) + .with_context(|| anyhow::anyhow!("couldn't write css file: {}", out_css_path.display()))?; + + Ok(relative_url(&out_css_path, &out_dir)?) +} + +fn concat_files( + root_dir: &Path, + out_dir: &Path, + files: &[&str], + directory: &str, + extension: &str, +) -> anyhow::Result { + let mut concatted = String::new(); + for filestem in files { + let vendor_path = root_dir + .join("static") + .join(directory) + .join(format!("{filestem}.{extension}")); + let contents = fs::read_to_string(vendor_path) + .with_context(|| anyhow::anyhow!("couldn't read vendor {extension}"))?; + concatted.push_str(&contents); + } + + let file_sha = format!("vendor_{}", hash_string(&concatted)); + let out_file_path = out_dir + .join("static") + .join(directory) + .join(format!("{file_sha}.{extension}")); + + write_file(Path::new(&out_file_path), concatted.as_bytes()) + .with_context(|| anyhow::anyhow!("couldn't write vendor {extension}"))?; + + Ok(relative_url(&out_file_path, &out_dir)?) +} + +fn concat_vendor_css(root_dir: &Path, out_dir: &Path, files: Vec<&str>) -> anyhow::Result { + concat_files(root_dir, out_dir, &files, "styles", "css") +} + +fn concat_app_js(root_dir: &Path, out_dir: &Path, files: Vec<&str>) -> anyhow::Result { + concat_files(root_dir, out_dir, &files, "scripts", "js") +} + +#[derive(Serialize, Debug)] +pub struct CSSFiles { + app: String, + fonts: String, + vendor: String, +} + +#[derive(Serialize, Debug)] +pub struct JSFiles { + app: String, +} + +#[derive(Serialize, Debug)] +pub struct AssetFiles { + css: CSSFiles, + js: JSFiles, +} + +/// Compile all statics JS/CSS assets into the `out_dir` directory and return a structure +/// that holds paths to them, based on the passed `baseurl`. +pub fn compile_assets( + root_dir: &Path, + out_dir: &Path, + baseurl: &str, +) -> anyhow::Result { + let app_css_file = compile_sass(root_dir, out_dir, "app")?; + let fonts_css_file = compile_sass(root_dir, out_dir, "fonts")?; + let vendor_css_file = concat_vendor_css(root_dir, out_dir, vec!["tachyons"])?; + let app_js_file = concat_app_js(root_dir, out_dir, vec!["tools-install"])?; + + Ok(AssetFiles { + css: CSSFiles { + app: format!("{baseurl}{app_css_file}"), + fonts: format!("{baseurl}{fonts_css_file}"), + vendor: format!("{baseurl}{vendor_css_file}"), + }, + js: JSFiles { + app: format!("{baseurl}{app_js_file}"), + }, + }) +} diff --git a/src/render/fs.rs b/src/render/fs.rs new file mode 100644 index 000000000..d6d2e27ea --- /dev/null +++ b/src/render/fs.rs @@ -0,0 +1,11 @@ +use anyhow::Context; +use std::path::Path; + +pub fn ensure_directory(path: &Path) -> anyhow::Result<()> { + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).with_context(|| { + anyhow::anyhow!("Could not create parent directory for {}", path.display()) + })?; + } + Ok(()) +} diff --git a/src/render/mod.rs b/src/render/mod.rs new file mode 100644 index 000000000..bdbf80488 --- /dev/null +++ b/src/render/mod.rs @@ -0,0 +1,244 @@ +mod assets; +mod fs; + +use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES, TeamHelper, create_loader}; +use crate::render::assets::{AssetFiles, compile_assets}; +use crate::render::fs::ensure_directory; +use crate::rust_version::RustVersion; +use crate::teams::RustTeams; +use crate::{ENGLISH, LAYOUT, PONTOON_ENABLED, baseurl}; +use anyhow::Context; +use handlebars::{DirectorySourceOptions, Handlebars}; +use handlebars_fluent::{FluentHelper, Loader, SimpleLoader}; +use rust_team_data::v1::{Team, TeamKind}; +use serde::Serialize; +use std::cmp::Reverse; +use std::fs::File; +use std::io::BufWriter; +use std::path::{Path, PathBuf}; + +#[derive(Serialize)] +struct TemplateCtx<'a, T: Serialize> { + page: String, + title: String, + parent: &'static str, + is_landing: bool, + data: &'a T, + lang: String, + baseurl: String, + pontoon_enabled: bool, + assets: &'a AssetFiles, + locales: &'static [LocaleInfo], + is_translation: bool, +} + +struct PageCtx<'a, T: Serialize> { + template_ctx: TemplateCtx<'a, T>, + output_dir: &'a Path, + handlebars: &'a Handlebars<'a>, +} + +impl<'a, T: Serialize> PageCtx<'a, T> { + fn make_landing(mut self) -> Self { + self.template_ctx.is_landing = true; + self + } + + fn render>(self, template: &str, path: P) -> anyhow::Result<()> { + let path = path.as_ref(); + + let out_path = self.output_dir.join(path); + ensure_directory(&out_path)?; + let mut output_file = BufWriter::new(File::create(&out_path)?); + eprintln!("Rendering `{template}` into {}", out_path.display()); + + self.handlebars + .render_to_write(template, &self.template_ctx, &mut output_file) + .with_context(|| { + anyhow::anyhow!( + "cannot render template {template} into {}", + out_path.display() + ) + })?; + Ok(()) + } +} + +struct RenderCtx<'a> { + handlebars: Handlebars<'a>, + fluent_loader: SimpleLoader, + output_dir: PathBuf, + version: RustVersion, + teams: RustTeams, + assets: AssetFiles, +} + +impl<'a> RenderCtx<'a> { + fn page( + &'a self, + page: &str, + title_id: &str, + data: &'a T, + lang: &str, + ) -> PageCtx<'a, T> { + let title = if title_id.is_empty() { + "".into() + } else { + let lang = lang.parse().expect("lang should be valid"); + self.fluent_loader.lookup(&lang, title_id, None) + }; + PageCtx { + template_ctx: TemplateCtx { + page: page.to_string(), + title, + parent: LAYOUT, + is_landing: false, + data, + baseurl: baseurl(&lang), + is_translation: lang != "en-US", + lang: lang.to_string(), + pontoon_enabled: *PONTOON_ENABLED, + assets: &self.assets, + locales: EXPLICIT_LOCALE_INFO, + }, + output_dir: &self.output_dir, + handlebars: &self.handlebars, + } + } + + fn copy_static_assets>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { + copy_dir_all(src_dir.as_ref(), self.output_dir.join(dst_dir.as_ref()))?; + Ok(()) + } +} + +fn all_langs(path: &str, func: F) -> anyhow::Result<()> +where + F: Fn(&str, &str) -> anyhow::Result<()>, +{ + for lang in SUPPORTED_LOCALES.iter() { + let path = match lang { + l if *l == ENGLISH => path.to_string(), + l => format!("{l}/{path}"), + }; + func(&path, lang).with_context(|| anyhow::anyhow!("could not handle language {lang}"))?; + } + Ok(()) +} + +fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + +pub fn render(version: RustVersion, teams: RustTeams) -> anyhow::Result<()> { + // Prepare build directory + let output_dir = PathBuf::from("html"); + let _ = std::fs::remove_dir_all(&output_dir); + std::fs::create_dir_all(&output_dir)?; + + // Compile assets + let assets = compile_assets(Path::new("."), &output_dir, "/")?; + + // Setup handlebars + let mut template_ctx: Handlebars<'static> = Handlebars::new(); + template_ctx.set_strict_mode(true); + + let mut options = DirectorySourceOptions::default(); + options.tpl_extension = ".html.hbs".to_string(); + template_ctx + .register_templates_directory("templates", options) + .context("cannot register template directory")?; + + let loader = create_loader(); + let helper = FluentHelper::new(loader); + template_ctx.register_helper("fluent", Box::new(helper)); + template_ctx.register_helper("team-text", Box::new(TeamHelper::new())); + + let ctx = RenderCtx { + fluent_loader: create_loader(), + assets, + version, + teams, + handlebars: template_ctx, + output_dir, + }; + ctx.copy_static_assets("static", "static")?; + + render_index(&ctx)?; + render_governance(&ctx)?; + + Ok(()) +} + +fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { + #[derive(Serialize)] + struct IndexData { + rust_version: String, + foo: Vec, + } + let data = IndexData { + rust_version: render_ctx.version.0.clone(), + foo: vec![1, 2, 3], + }; + all_langs("index.html", |path, lang| { + render_ctx + .page("index", "", &data, lang) + .make_landing() + .render("index", path) + }) +} + +fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { + #[derive(Default, Serialize)] + pub struct IndexData { + teams: Vec, + } + + #[derive(Serialize)] + struct IndexTeam { + #[serde(flatten)] + team: Team, + url: String, + } + + let mut data = IndexData::default(); + + render_ctx + .teams + .0 + .as_ref() + .unwrap() + .into_iter() + .filter(|team| team.website_data.is_some()) + // On the main page, show the leadership-council and all top-level + // teams. + .filter(|team| team.kind == TeamKind::Team && team.subteam_of.is_none()) + .map(|team| IndexTeam { + url: format!( + "{}/{}", + crate::teams::kind_to_str(team.kind), + team.website_data.as_ref().unwrap().page + ), + team: team.clone(), + }) + .for_each(|team| data.teams.push(team)); + + data.teams + .sort_by_key(|index_team| Reverse(index_team.team.website_data.as_ref().unwrap().weight)); + + all_langs("governance/index.html", |path, lang| { + render_ctx + .page("governance/index", "governance-page-title", &data, lang) + .render("governance/index", path) + }) +} diff --git a/src/rust_version.rs b/src/rust_version.rs index e1ce547cf..83ddf2856 100644 --- a/src/rust_version.rs +++ b/src/rust_version.rs @@ -10,7 +10,7 @@ enum FetchTarget { Manifest, } -async fn fetch(target: FetchTarget) -> Result> { +async fn fetch(target: FetchTarget) -> anyhow::Result { let proxy_env = env::var("http_proxy") .or_else(|_| env::var("HTTPS_PROXY")) .ok(); @@ -43,7 +43,7 @@ impl Cached for RustVersion { fn get_timestamp(&self) -> Instant { self.1 } - async fn fetch() -> Result> { + async fn fetch() -> anyhow::Result { let manifest = fetch(FetchTarget::Manifest) .await? .text() diff --git a/src/teams.rs b/src/teams.rs index bc0c65f28..e26d9bfb3 100644 --- a/src/teams.rs +++ b/src/teams.rs @@ -253,7 +253,7 @@ impl Cached for RustTeams { fn get_timestamp(&self) -> Instant { self.1 } - async fn fetch() -> Result> { + async fn fetch() -> anyhow::Result { let resp: Teams = reqwest::get(format!("{BASE_URL}/teams.json")) .await? .error_for_status()? @@ -272,7 +272,7 @@ impl Cached for RustTeams { } } -fn kind_to_str(kind: TeamKind) -> &'static str { +pub(crate) fn kind_to_str(kind: TeamKind) -> &'static str { match kind { TeamKind::Team => "teams", TeamKind::WorkingGroup => "wgs", diff --git a/templates/governance/index-team.html.hbs b/templates/governance/index-team.html.hbs index e5967a5c7..371a32a23 100644 --- a/templates/governance/index-team.html.hbs +++ b/templates/governance/index-team.html.hbs @@ -1,7 +1,7 @@

{{team-text team name}}

{{team-text team description}}

- + {{fluent "governance-members"}}
diff --git a/templates/governance/index.html.hbs b/templates/governance/index.html.hbs index 20ae88fdb..82492294e 100644 --- a/templates/governance/index.html.hbs +++ b/templates/governance/index.html.hbs @@ -31,7 +31,7 @@
{{#each data.teams as |team| ~}} - {{> governance/index-team}} + {{> governance/index-team team=team baseurl=baseurl}} {{/each~}}
From aed991f04fccddd0538b62434383e66fb56669f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 5 Aug 2025 21:39:50 +0200 Subject: [PATCH 02/19] Remove old code and render individual categories --- src/{render => }/assets.rs | 2 +- src/cache.rs | 32 -- src/caching.rs | 21 -- src/category.rs | 37 --- src/{render => }/fs.rs | 0 src/main.rs | 610 ++++++++++++------------------------- src/render/mod.rs | 244 --------------- src/rust_version.rs | 69 +---- src/teams.rs | 219 +++++-------- 9 files changed, 299 insertions(+), 935 deletions(-) rename src/{render => }/assets.rs (98%) delete mode 100644 src/cache.rs delete mode 100644 src/caching.rs delete mode 100644 src/category.rs rename src/{render => }/fs.rs (100%) delete mode 100644 src/render/mod.rs diff --git a/src/render/assets.rs b/src/assets.rs similarity index 98% rename from src/render/assets.rs rename to src/assets.rs index 4806ba655..dcbd5f10e 100644 --- a/src/render/assets.rs +++ b/src/assets.rs @@ -1,4 +1,4 @@ -use crate::render::fs::ensure_directory; +use crate::fs::ensure_directory; use anyhow::Context; use rocket::serde::Serialize; use sass_rs::{Options, compile_file}; diff --git a/src/cache.rs b/src/cache.rs deleted file mode 100644 index 652c7b91d..000000000 --- a/src/cache.rs +++ /dev/null @@ -1,32 +0,0 @@ -use std::error::Error; -use std::future::Future; -use std::sync::Arc; -use std::time::Instant; - -use rocket::State; -use rocket::tokio::sync::RwLock; -use rocket::tokio::task; - -const CACHE_TTL_SECS: u64 = 120; - -pub type Cache = State>>; - -pub trait Cached: Send + Sync + Clone + 'static { - fn get_timestamp(&self) -> Instant; - fn fetch() -> impl Future> + Send; - async fn get(cache: &Cache) -> Self { - let cached = cache.read().await.clone(); - let timestamp = cached.get_timestamp(); - if timestamp.elapsed().as_secs() > CACHE_TTL_SECS { - // Update the cache in the background - let cache: Arc<_> = cache.inner().clone(); - task::spawn(async move { - match Self::fetch().await { - Ok(data) => *cache.write().await = data, - Err(e) => eprintln!("failed to update cache: {e}"), - } - }); - } - cached - } -} diff --git a/src/caching.rs b/src/caching.rs deleted file mode 100644 index 0de9e88a1..000000000 --- a/src/caching.rs +++ /dev/null @@ -1,21 +0,0 @@ -use rocket::fs::NamedFile; -use rocket::http::{Header, hyper}; -use rocket::response::Responder; - -#[derive(Responder)] -pub struct CachedNamedFile { - file: NamedFile, - header: Header<'static>, -} - -impl CachedNamedFile { - pub fn max_age(file: NamedFile, max_age: u32) -> Self { - Self { - file, - header: Header::new( - hyper::header::CACHE_CONTROL.as_str(), - format!("max-age={max_age}"), - ), - } - } -} diff --git a/src/category.rs b/src/category.rs deleted file mode 100644 index 174ce0610..000000000 --- a/src/category.rs +++ /dev/null @@ -1,37 +0,0 @@ -use std::path::PathBuf; - -use rocket::request::FromParam; - -fn is_category(name: &str) -> bool { - let mut path = PathBuf::from("templates"); - path.push(name); - path.push("index.html.hbs"); - path.exists() -} - -pub struct Category { - name: String, -} - -impl Category { - pub fn name(&self) -> &str { - self.name.as_str() - } - - pub fn index(&self) -> String { - format!("{}/index", self.name()) - } -} - -impl<'r> FromParam<'r> for Category { - type Error = String; - - fn from_param(param: &'r str) -> Result { - let url = param.to_string(); - if is_category(&url) { - Ok(Category { name: url }) - } else { - Err(format!("No category called <{url}>")) - } - } -} diff --git a/src/render/fs.rs b/src/fs.rs similarity index 100% rename from src/render/fs.rs rename to src/fs.rs diff --git a/src/main.rs b/src/main.rs index a928eac33..c4937b753 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,466 +1,260 @@ -mod cache; -mod caching; -mod category; -mod headers; -mod i18n; -mod redirect; -mod rust_version; -mod teams; -mod render; - -use cache::Cache; -use cache::Cached; -use rocket::catch; -use rocket::get; -use rocket::tokio::sync::RwLock; -use rust_version::RustVersion; +use crate::assets::{AssetFiles, compile_assets}; +use crate::category::Category; +use crate::fs::ensure_directory; +use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES, TeamHelper, create_loader}; +use crate::rust_version::{RustVersion, fetch_rust_version}; +use crate::teams::{RustTeams, load_rust_teams}; +use anyhow::Context; +use handlebars::{DirectorySourceOptions, Handlebars}; +use handlebars_fluent::{FluentHelper, Loader, SimpleLoader}; use serde::Serialize; -use teams::RustTeams; -use teams::encode_zulip_stream; - -use std::collections::hash_map::DefaultHasher; -use std::env; -use std::fs; use std::fs::File; -use std::hash::Hasher; use std::io::BufWriter; use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::sync::LazyLock; -use anyhow::Context as _; -use handlebars::{DirectorySourceOptions, Handlebars}; -use rocket::{ - fs::NamedFile, - http::Status, - request::{FromParam, Request}, - response::{Redirect, content}, -}; -use rocket_dyn_templates::Template; - -use sass_rs::{Options, compile_file}; -use category::Category; +mod assets; +mod category; +mod fs; +mod i18n; +mod rust_version; +mod teams; -use caching::CachedNamedFile; -use handlebars_fluent::{FluentHelper, loader::Loader, simple_loader}; -use i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SupportedLocale, TeamHelper, create_loader}; +static PONTOON_ENABLED: bool = false; const ZULIP_DOMAIN: &str = "https://rust-lang.zulipchat.com"; -static ASSETS: LazyLock = LazyLock::new(|| { - let app_css_file = compile_sass("app"); - let fonts_css_file = compile_sass("fonts"); - let vendor_css_file = concat_vendor_css(vec!["tachyons"]); - let app_js_file = concat_app_js(vec!["tools-install"]); +static LAYOUT: &str = "components/layout"; +static ENGLISH: &str = "en-US"; - AssetFiles { - css: CSSFiles { - app: app_css_file, - fonts: fonts_css_file, - vendor: vendor_css_file, - }, - js: JSFiles { app: app_js_file }, +fn baseurl(lang: &str) -> String { + if lang == "en-US" { + String::new() + } else { + format!("/{lang}") } -}); -static PONTOON_ENABLED: LazyLock = LazyLock::new(|| env::var("RUST_WWW_PONTOON").is_ok()); -static ROBOTS_TXT_DISALLOW_ALL: LazyLock = - LazyLock::new(|| env::var("ROBOTS_TXT_DISALLOW_ALL").is_ok()); +} #[derive(Serialize)] -struct Context { +struct TemplateCtx<'a, T: Serialize> { page: String, title: String, parent: &'static str, is_landing: bool, - data: T, + data: &'a T, lang: String, baseurl: String, pontoon_enabled: bool, - assets: &'static AssetFiles, + assets: &'a AssetFiles, locales: &'static [LocaleInfo], is_translation: bool, } -impl Context { - fn new(page: &str, title_id: &str, is_landing: bool, data: T, lang: String) -> Self { - let helper = create_loader(); - let title = if title_id.is_empty() { - "".into() - } else { - let lang = lang.parse().expect("lang should be valid"); - helper.lookup(&lang, title_id, None) - }; - Self { - page: page.to_owned(), - title, - parent: LAYOUT, - is_landing, - data, - baseurl: baseurl(&lang), - is_translation: lang != "en-US", - lang, - pontoon_enabled: *PONTOON_ENABLED, - assets: &ASSETS, - locales: EXPLICIT_LOCALE_INFO, - } - } -} - -#[derive(Clone, Serialize)] -struct CSSFiles { - app: String, - fonts: String, - vendor: String, -} -#[derive(Clone, Serialize)] -struct JSFiles { - app: String, +struct PageCtx<'a, T: Serialize> { + template_ctx: TemplateCtx<'a, T>, + output_dir: &'a Path, + handlebars: &'a Handlebars<'a>, } -#[derive(Clone, Serialize)] -struct AssetFiles { - css: CSSFiles, - js: JSFiles, -} - -static LAYOUT: &str = "components/layout"; -static ENGLISH: &str = "en-US"; -fn baseurl(lang: &str) -> String { - if lang == "en-US" { - String::new() - } else { - format!("/{lang}") +impl<'a, T: Serialize> PageCtx<'a, T> { + fn make_landing(mut self) -> Self { + self.template_ctx.is_landing = true; + self } -} -#[get("/logos/", rank = 1)] -async fn logos(file: PathBuf) -> Option { - NamedFile::open(Path::new("static/logos").join(file)) - .await - .ok() - .map(|file| CachedNamedFile::max_age(file, 3600)) -} - -#[get("/static/", rank = 1)] -async fn files(file: PathBuf) -> Option { - NamedFile::open(Path::new("static/").join(file)) - .await - .ok() - .map(|file| CachedNamedFile::max_age(file, 3600)) -} - -#[get("/robots.txt", rank = 1)] -fn robots_txt() -> Option> { - if *ROBOTS_TXT_DISALLOW_ALL { - Some(content::RawText("User-agent: *\nDisallow: /")) - } else { - None + fn render>(self, dst_path: P) -> anyhow::Result<()> { + let path = dst_path.as_ref(); + let template = &self.template_ctx.page; + + let out_path = self.output_dir.join(path); + ensure_directory(&out_path)?; + let mut output_file = BufWriter::new(File::create(&out_path)?); + eprintln!("Rendering `{template}` into {}", out_path.display()); + + self.handlebars + .render_to_write(template, &self.template_ctx, &mut output_file) + .with_context(|| { + anyhow::anyhow!( + "cannot render template {template} into {}", + out_path.display() + ) + })?; + Ok(()) } } -#[get("/")] -async fn index(version_cache: &Cache) -> Template { - render_index(ENGLISH.into(), version_cache).await -} - -#[get("/", rank = 3)] -async fn index_locale(locale: SupportedLocale, version_cache: &Cache) -> Template { - render_index(locale.0, version_cache).await -} - -#[get("/")] -fn category_en(category: Category) -> Template { - render_category(category, ENGLISH.into()) -} - -#[get("//", rank = 9)] -fn category_locale(category: Category, locale: SupportedLocale) -> Template { - render_category(category, locale.0) -} - -#[get("/governance")] -async fn governance(teams_cache: &Cache) -> Result { - render_governance(ENGLISH.into(), teams_cache).await -} - -#[get("/governance/
/", rank = 2)] -async fn team( - section: &str, - team: &str, - teams_cache: &Cache, -) -> Result { - render_team(section, team, ENGLISH.into(), teams_cache).await -} - -#[get("//governance", rank = 8)] -async fn governance_locale( - locale: SupportedLocale, - teams_cache: &Cache, -) -> Result { - render_governance(locale.0, teams_cache).await -} - -#[get("//governance/
/", rank = 12)] -async fn team_locale( - section: &str, - team: &str, - locale: SupportedLocale, - teams_cache: &Cache, -) -> Result { - render_team(section, team, locale.0, teams_cache).await -} - -#[get("//", rank = 4)] -fn subject(category: Category, subject: &str) -> Result { - render_subject(category, subject, ENGLISH.into()) -} - -#[get("///", rank = 14)] -fn subject_locale( - category: Category, - subject: &str, - locale: SupportedLocale, -) -> Result { - render_subject(category, subject, locale.0) -} - -#[get("/en-US", rank = 1)] -fn redirect_bare_en_us() -> Redirect { - Redirect::permanent("/") +struct RenderCtx<'a> { + handlebars: Handlebars<'a>, + fluent_loader: SimpleLoader, + output_dir: PathBuf, + rust_version: RustVersion, + teams: RustTeams, + assets: AssetFiles, } -#[get("/.well-known/security.txt")] -fn well_known_security() -> &'static str { - include_str!("../static/text/well_known_security.txt") -} - -#[catch(404)] -#[allow(clippy::result_large_err)] -fn not_found(req: &Request) -> Result { - if let Some(redirect) = crate::redirect::maybe_redirect(req.uri().path()) { - return Err(redirect); - } - - let lang = if let Some(next) = req.uri().path().segments().next() { - if let Ok(lang) = SupportedLocale::from_param(next) { - lang.0 +impl<'a> RenderCtx<'a> { + fn page( + &'a self, + page: &str, + title_id: &str, + data: &'a T, + lang: &str, + ) -> PageCtx<'a, T> { + let title = if title_id.is_empty() { + "".into() } else { - ENGLISH.into() + let lang = lang.parse().expect("lang should be valid"); + self.fluent_loader.lookup(&lang, title_id, None) + }; + PageCtx { + template_ctx: TemplateCtx { + page: page.to_string(), + title, + parent: LAYOUT, + is_landing: false, + data, + baseurl: baseurl(&lang), + is_translation: lang != "en-US", + lang: lang.to_string(), + pontoon_enabled: PONTOON_ENABLED, + assets: &self.assets, + locales: EXPLICIT_LOCALE_INFO, + }, + output_dir: &self.output_dir, + handlebars: &self.handlebars, } - } else { - ENGLISH.into() - }; - - Ok(not_found_locale(lang)) -} - -#[catch(422)] -#[allow(clippy::result_large_err)] -fn unprocessable_content(req: &Request) -> Result { - not_found(req) -} - -fn not_found_locale(lang: String) -> Template { - let page = "404"; - let context = Context::new(page, "error404-page-title", false, (), lang); - Template::render(page, context) -} - -#[catch(500)] -fn catch_error() -> Template { - not_found_locale(ENGLISH.into()) -} + } -fn hash_css(css: &str) -> String { - let mut hasher = DefaultHasher::new(); - hasher.write(css.as_bytes()); - hasher.finish().to_string() + fn copy_static_assets>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { + let dst = self.output_dir.join(dst_dir.as_ref()); + println!( + "Copying static assets from {} to {}", + src_dir.as_ref().display(), + dst.display() + ); + copy_dir_all(src_dir.as_ref(), dst)?; + Ok(()) + } } -fn compile_sass(filename: &str) -> String { - let scss_file = format!("./src/styles/{filename}.scss"); - - let css = compile_file(&scss_file, Options::default()) - .unwrap_or_else(|_| panic!("couldn't compile sass: {}", &scss_file)); - - let css_sha = format!("{}_{}", filename, hash_css(&css)); - let css_file = format!("./static/styles/{css_sha}.css"); - - fs::write(&css_file, css.into_bytes()) - .unwrap_or_else(|_| panic!("couldn't write css file: {}", &css_file)); - - String::from(&css_file[1..]) +/// Calls `func` for all supported languages. +/// Passes it the destination path into which should a given page be rendered, and the language +/// in which it should be rendered. +fn all_langs(dst_path: &str, func: F) -> anyhow::Result<()> +where + F: Fn(&str, &str) -> anyhow::Result<()>, +{ + for lang in SUPPORTED_LOCALES.iter() { + let path = match lang { + l if *l == ENGLISH => dst_path.to_string(), + l => format!("{l}/{dst_path}"), + }; + func(&path, lang).with_context(|| anyhow::anyhow!("could not handle language {lang}"))?; + } + Ok(()) } -fn concat_vendor_css(files: Vec<&str>) -> String { - let mut concatted = String::new(); - for filestem in files { - let vendor_path = format!("./static/styles/{filestem}.css"); - let contents = fs::read_to_string(vendor_path).expect("couldn't read vendor css"); - concatted.push_str(&contents); +fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } } + Ok(()) +} - let css_sha = format!("vendor_{}", hash_css(&concatted)); - let css_path = format!("./static/styles/{}.css", &css_sha); +fn setup_handlebars() -> anyhow::Result> { + let mut handlebars: Handlebars<'static> = Handlebars::new(); + handlebars.set_strict_mode(true); - fs::write(&css_path, &concatted).expect("couldn't write vendor css"); + let mut options = DirectorySourceOptions::default(); + options.tpl_extension = ".html.hbs".to_string(); + handlebars + .register_templates_directory("templates", options) + .context("cannot register template directory")?; - String::from(&css_path[1..]) + let loader = create_loader(); + let helper = FluentHelper::new(loader); + handlebars.register_helper("fluent", Box::new(helper)); + handlebars.register_helper("team-text", Box::new(TeamHelper::new())); + Ok(handlebars) } -fn concat_app_js(files: Vec<&str>) -> String { - let mut concatted = String::new(); - for filestem in files { - let vendor_path = format!("./static/scripts/{filestem}.js"); - let contents = fs::read_to_string(vendor_path).expect("couldn't read app js"); - concatted.push_str(&contents); - } +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let rust_version = fetch_rust_version().await?; + let teams = load_rust_teams().await?; + + // Prepare build directory + let output_dir = PathBuf::from("html"); + let _ = std::fs::remove_dir_all(&output_dir); + std::fs::create_dir_all(&output_dir)?; + + let assets = compile_assets(Path::new("."), &output_dir, "/")?; + let handlebars = setup_handlebars()?; + + let ctx = RenderCtx { + fluent_loader: create_loader(), + assets, + rust_version, + teams, + handlebars, + output_dir, + }; + ctx.copy_static_assets("static", "static")?; - let js_sha = format!("app_{}", hash_css(&concatted)); - let js_path = format!("./static/scripts/{}.js", &js_sha); + render_index(&ctx)?; + render_governance(&ctx)?; + render_category(&ctx, "community")?; + render_category(&ctx, "learn")?; + render_category(&ctx, "policies")?; + render_category(&ctx, "tools")?; + render_category(&ctx, "what")?; - fs::write(&js_path, &concatted).expect("couldn't write app js"); + // TODO: 404, redirects - String::from(&js_path[1..]) + Ok(()) } -async fn render_index(lang: String, version_cache: &Cache) -> Template { +fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { #[derive(Serialize)] struct IndexData { rust_version: String, } - - let page = "index"; let data = IndexData { - rust_version: rust_version::rust_version(version_cache).await, + rust_version: render_ctx.rust_version.0.clone(), }; - let context = Context::new(page, "", true, data, lang); - Template::render(page, context) -} - -fn render_category(category: Category, lang: String) -> Template { - let page = category.index(); - let title_id = format!("{}-page-title", category.name()); - let context = Context::new(category.name(), &title_id, false, (), lang); - - Template::render(page, context) -} - -async fn render_governance( - lang: String, - teams_cache: &Cache, -) -> Result { - match teams::index_data(teams_cache).await { - Ok(data) => { - let page = "governance/index"; - let context = Context::new(page, "governance-page-title", false, data, lang); - - Ok(Template::render(page, context)) - } - Err(err) => { - eprintln!("error while loading the governance page: {err}"); - Err(Status::InternalServerError) - } - } -} - -async fn render_team( - section: &str, - team: &str, - lang: String, - teams_cache: &Cache, -) -> Result { - match teams::page_data(section, team, teams_cache).await { - Ok(data) => { - let page = "governance/group"; - let name = format!("governance-team-{}-name", data.team.name); - let context = Context::new(page, &name, false, data, lang); - Ok(Template::render(page, context)) - } - Err(err) => { - if err.is::() { - Err(Status::NotFound) - } else { - eprintln!("error while loading the team page: {err}"); - Err(Status::InternalServerError) - } - } - } -} - -fn render_subject(category: Category, subject: &str, lang: String) -> Result { - // Rocket's Template::render method is not really designed to accept arbitrary templates: if a - // template is missing, it just returns a Status::InternalServerError, without a way to - // distinguish it from a syntax error in the template itself. - // - // To work around the problem we check whether the template exists beforehand. - let path = Path::new("templates") - .join(category.name()) - .join(format!("{subject}.html.hbs")); - if !path.is_file() { - return Err(Status::NotFound); - } - - let page = format!("{}/{}", category.name(), subject); - let title_id = format!("{}-{}-page-title", category.name(), subject); - let context = Context::new(subject, &title_id, false, (), lang); - - Ok(Template::render(page, context)) -} - -// #[rocket::launch] -// async fn rocket() -> _ { -// let templating = Template::custom(|engine| { -// engine -// .handlebars -// .register_helper("fluent", Box::new(FluentHelper::new(create_loader()))); -// engine -// .handlebars -// .register_helper("team-text", Box::new(TeamHelper::new())); -// engine -// .handlebars -// .register_helper("encode-zulip-stream", Box::new(encode_zulip_stream)); -// }); -// -// let rust_version = RustVersion::fetch().await.unwrap_or_default(); -// let teams = RustTeams::fetch().await.unwrap_or_default(); -// -// rocket::build() -// .attach(templating) -// .attach(headers::InjectHeaders) -// .manage(Arc::new(RwLock::new(rust_version))) -// .manage(Arc::new(RwLock::new(teams))) -// .mount( -// "/", -// rocket::routes![ -// index, -// category_en, -// governance, -// team, -// subject, -// files, -// robots_txt, -// logos, -// index_locale, -// category_locale, -// governance_locale, -// team_locale, -// subject_locale, -// redirect_bare_en_us, -// well_known_security, -// ], -// ) -// .register( -// "/", -// rocket::catchers![not_found, unprocessable_content, catch_error], -// ) -// } - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - let rust_version = RustVersion::fetch().await?; - let teams = RustTeams::fetch().await?; - render::render(rust_version, teams)?; - - Ok(()) + all_langs("index.html", |path, lang| { + render_ctx + .page("index", "", &data, lang) + .make_landing() + .render(path) + }) +} + +fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { + let data = render_ctx.teams.index_data(); + + all_langs("governance/index.html", |dst_path, lang| { + render_ctx + .page("governance/index", "governance-page-title", &data, lang) + .render(dst_path) + }) +} + +fn render_category(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { + all_langs(&format!("{category}/index.html"), |dst_path, lang| { + render_ctx + .page( + &format!("{category}/index"), + &format!("{category}-page-title"), + &(), + lang, + ) + .render(dst_path) + }) } diff --git a/src/render/mod.rs b/src/render/mod.rs deleted file mode 100644 index bdbf80488..000000000 --- a/src/render/mod.rs +++ /dev/null @@ -1,244 +0,0 @@ -mod assets; -mod fs; - -use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES, TeamHelper, create_loader}; -use crate::render::assets::{AssetFiles, compile_assets}; -use crate::render::fs::ensure_directory; -use crate::rust_version::RustVersion; -use crate::teams::RustTeams; -use crate::{ENGLISH, LAYOUT, PONTOON_ENABLED, baseurl}; -use anyhow::Context; -use handlebars::{DirectorySourceOptions, Handlebars}; -use handlebars_fluent::{FluentHelper, Loader, SimpleLoader}; -use rust_team_data::v1::{Team, TeamKind}; -use serde::Serialize; -use std::cmp::Reverse; -use std::fs::File; -use std::io::BufWriter; -use std::path::{Path, PathBuf}; - -#[derive(Serialize)] -struct TemplateCtx<'a, T: Serialize> { - page: String, - title: String, - parent: &'static str, - is_landing: bool, - data: &'a T, - lang: String, - baseurl: String, - pontoon_enabled: bool, - assets: &'a AssetFiles, - locales: &'static [LocaleInfo], - is_translation: bool, -} - -struct PageCtx<'a, T: Serialize> { - template_ctx: TemplateCtx<'a, T>, - output_dir: &'a Path, - handlebars: &'a Handlebars<'a>, -} - -impl<'a, T: Serialize> PageCtx<'a, T> { - fn make_landing(mut self) -> Self { - self.template_ctx.is_landing = true; - self - } - - fn render>(self, template: &str, path: P) -> anyhow::Result<()> { - let path = path.as_ref(); - - let out_path = self.output_dir.join(path); - ensure_directory(&out_path)?; - let mut output_file = BufWriter::new(File::create(&out_path)?); - eprintln!("Rendering `{template}` into {}", out_path.display()); - - self.handlebars - .render_to_write(template, &self.template_ctx, &mut output_file) - .with_context(|| { - anyhow::anyhow!( - "cannot render template {template} into {}", - out_path.display() - ) - })?; - Ok(()) - } -} - -struct RenderCtx<'a> { - handlebars: Handlebars<'a>, - fluent_loader: SimpleLoader, - output_dir: PathBuf, - version: RustVersion, - teams: RustTeams, - assets: AssetFiles, -} - -impl<'a> RenderCtx<'a> { - fn page( - &'a self, - page: &str, - title_id: &str, - data: &'a T, - lang: &str, - ) -> PageCtx<'a, T> { - let title = if title_id.is_empty() { - "".into() - } else { - let lang = lang.parse().expect("lang should be valid"); - self.fluent_loader.lookup(&lang, title_id, None) - }; - PageCtx { - template_ctx: TemplateCtx { - page: page.to_string(), - title, - parent: LAYOUT, - is_landing: false, - data, - baseurl: baseurl(&lang), - is_translation: lang != "en-US", - lang: lang.to_string(), - pontoon_enabled: *PONTOON_ENABLED, - assets: &self.assets, - locales: EXPLICIT_LOCALE_INFO, - }, - output_dir: &self.output_dir, - handlebars: &self.handlebars, - } - } - - fn copy_static_assets>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { - copy_dir_all(src_dir.as_ref(), self.output_dir.join(dst_dir.as_ref()))?; - Ok(()) - } -} - -fn all_langs(path: &str, func: F) -> anyhow::Result<()> -where - F: Fn(&str, &str) -> anyhow::Result<()>, -{ - for lang in SUPPORTED_LOCALES.iter() { - let path = match lang { - l if *l == ENGLISH => path.to_string(), - l => format!("{l}/{path}"), - }; - func(&path, lang).with_context(|| anyhow::anyhow!("could not handle language {lang}"))?; - } - Ok(()) -} - -fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - -pub fn render(version: RustVersion, teams: RustTeams) -> anyhow::Result<()> { - // Prepare build directory - let output_dir = PathBuf::from("html"); - let _ = std::fs::remove_dir_all(&output_dir); - std::fs::create_dir_all(&output_dir)?; - - // Compile assets - let assets = compile_assets(Path::new("."), &output_dir, "/")?; - - // Setup handlebars - let mut template_ctx: Handlebars<'static> = Handlebars::new(); - template_ctx.set_strict_mode(true); - - let mut options = DirectorySourceOptions::default(); - options.tpl_extension = ".html.hbs".to_string(); - template_ctx - .register_templates_directory("templates", options) - .context("cannot register template directory")?; - - let loader = create_loader(); - let helper = FluentHelper::new(loader); - template_ctx.register_helper("fluent", Box::new(helper)); - template_ctx.register_helper("team-text", Box::new(TeamHelper::new())); - - let ctx = RenderCtx { - fluent_loader: create_loader(), - assets, - version, - teams, - handlebars: template_ctx, - output_dir, - }; - ctx.copy_static_assets("static", "static")?; - - render_index(&ctx)?; - render_governance(&ctx)?; - - Ok(()) -} - -fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { - #[derive(Serialize)] - struct IndexData { - rust_version: String, - foo: Vec, - } - let data = IndexData { - rust_version: render_ctx.version.0.clone(), - foo: vec![1, 2, 3], - }; - all_langs("index.html", |path, lang| { - render_ctx - .page("index", "", &data, lang) - .make_landing() - .render("index", path) - }) -} - -fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { - #[derive(Default, Serialize)] - pub struct IndexData { - teams: Vec, - } - - #[derive(Serialize)] - struct IndexTeam { - #[serde(flatten)] - team: Team, - url: String, - } - - let mut data = IndexData::default(); - - render_ctx - .teams - .0 - .as_ref() - .unwrap() - .into_iter() - .filter(|team| team.website_data.is_some()) - // On the main page, show the leadership-council and all top-level - // teams. - .filter(|team| team.kind == TeamKind::Team && team.subteam_of.is_none()) - .map(|team| IndexTeam { - url: format!( - "{}/{}", - crate::teams::kind_to_str(team.kind), - team.website_data.as_ref().unwrap().page - ), - team: team.clone(), - }) - .for_each(|team| data.teams.push(team)); - - data.teams - .sort_by_key(|index_team| Reverse(index_team.team.website_data.as_ref().unwrap().weight)); - - all_langs("governance/index.html", |path, lang| { - render_ctx - .page("governance/index", "governance-page-title", &data, lang) - .render("governance/index", path) - }) -} diff --git a/src/rust_version.rs b/src/rust_version.rs index 83ddf2856..a805497d7 100644 --- a/src/rust_version.rs +++ b/src/rust_version.rs @@ -1,60 +1,17 @@ -use std::env; -use std::error::Error; -use std::time::Instant; - -use crate::cache::{Cache, Cached}; - static MANIFEST_URL: &str = "https://static.rust-lang.org/dist/channel-rust-stable.toml"; -enum FetchTarget { - Manifest, -} - -async fn fetch(target: FetchTarget) -> anyhow::Result { - let proxy_env = env::var("http_proxy") - .or_else(|_| env::var("HTTPS_PROXY")) - .ok(); - - let client = match proxy_env { - Some(proxy_env) => { - let proxy = reqwest::Proxy::https(proxy_env).unwrap(); - reqwest::ClientBuilder::new().proxy(proxy).build().unwrap() - } - None => reqwest::Client::new(), - }; - - let url = match target { - FetchTarget::Manifest => MANIFEST_URL, - }; - - Ok(client.get(url).send().await?) -} - #[derive(Debug, Clone)] -pub struct RustVersion(pub String, pub Instant); - -impl Default for RustVersion { - fn default() -> Self { - Self(Default::default(), Instant::now()) - } -} - -impl Cached for RustVersion { - fn get_timestamp(&self) -> Instant { - self.1 - } - async fn fetch() -> anyhow::Result { - let manifest = fetch(FetchTarget::Manifest) - .await? - .text() - .await? - .parse::()?; - let rust_version = manifest["pkg"]["rust"]["version"].as_str().unwrap(); - let version: String = rust_version.split(' ').next().unwrap().to_owned(); - Ok(RustVersion(version, Instant::now())) - } -} - -pub async fn rust_version(version_cache: &Cache) -> String { - RustVersion::get(version_cache).await.0 +pub struct RustVersion(pub String); + +/// Fetch the latest stable version of Rust. +pub async fn fetch_rust_version() -> anyhow::Result { + println!("Downloading Rust version"); + let manifest = reqwest::get(MANIFEST_URL) + .await? + .text() + .await? + .parse::()?; + let rust_version = manifest["pkg"]["rust"]["version"].as_str().unwrap(); + let version: String = rust_version.split(' ').next().unwrap().to_owned(); + Ok(RustVersion(version)) } diff --git a/src/teams.rs b/src/teams.rs index e26d9bfb3..2a64005ee 100644 --- a/src/teams.rs +++ b/src/teams.rs @@ -8,59 +8,58 @@ use std::cmp::Reverse; use std::collections::HashMap; use std::error::Error; use std::fmt; -use std::time::Instant; -use crate::cache::{Cache, Cached}; - -#[derive(Default, Serialize)] -pub struct IndexData { - teams: Vec, -} +const ENCODING_SET: AsciiSet = NON_ALPHANUMERIC.remove(b'-').remove(b'_'); -#[derive(Serialize)] -struct IndexTeam { - #[serde(flatten)] - team: Team, - url: String, -} +pub fn encode_zulip_stream( + h: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + let zulip_stream = if let Some(p) = h.param(0) { + p.value() + } else { + return Err(RenderErrorReason::ParamNotFoundForIndex( + "{{encode-zulip-stream takes 1 parameter}}", + 0, + ) + .into()); + }; + let zulip_stream = if let Some(s) = zulip_stream.as_str() { + s + } else { + return Err(RenderErrorReason::ParamTypeMismatchForName( + "encode-zulip-stream", + "0".into(), + "string".into(), + ) + .into()); + }; -#[derive(Serialize)] -pub struct PageData { - pub team: Team, - zulip_domain: &'static str, - subteams: Vec, - wgs: Vec, - project_groups: Vec, - // Marker teams and other kinds of groups that have a website entry - other_teams: Vec, -} + // https://github.com/zulip/zulip/blob/159641bab8c248f5b72a4e736462fb0b48e7fa24/static/js/hash_util.js#L20-L25 + let stream_encoded = utf8_percent_encode(zulip_stream, &ENCODING_SET) + .to_string() + .replace('%', "."); -#[derive(Clone)] -struct Data { - teams: Vec, + out.write(&stream_encoded)?; + Ok(()) } -const ENCODING_SET: AsciiSet = NON_ALPHANUMERIC.remove(b'-').remove(b'_'); - -impl Data { - async fn load(teams_cache: &Cache) -> Result> { - Ok(Data { - teams: RustTeams::get(teams_cache) - .await - .0 - .ok_or_else(|| Box::::from("failed to load teams"))?, - }) - } +#[derive(Debug, Clone)] +pub struct RustTeams(pub Vec); +impl RustTeams { #[cfg(test)] fn dummy(teams: Vec) -> Self { - Data { teams } + RustTeams(teams) } - fn index_data(self) -> Result> { - let mut data = IndexData::default(); - - self.teams + pub fn index_data(&self) -> IndexData { + let mut teams = self + .0 + .clone() .into_iter() .filter(|team| team.website_data.is_some()) // On the main page, show the leadership-council and all top-level @@ -74,22 +73,19 @@ impl Data { ), team, }) - .for_each(|team| data.teams.push(team)); + .collect::>(); - data.teams.sort_by_key(|index_team| { + teams.sort_by_key(|index_team| { Reverse(index_team.team.website_data.as_ref().unwrap().weight) }); - Ok(data) + IndexData { teams } } - pub fn page_data( - self, - section: &str, - team_name: &str, - ) -> Result> { + pub fn page_data(&self, section: &str, team_name: &str) -> anyhow::Result { + let teams = self.0.clone(); + // Find the main team first - let main_team = self - .teams + let main_team = teams .iter() .filter(|team| team.website_data.as_ref().map(|ws| ws.page.as_str()) == Some(team_name)) .find(|team| kind_to_str(team.kind) == section) @@ -116,13 +112,12 @@ impl Data { let mut project_groups = Vec::new(); let mut other_teams = Vec::new(); - let superteams: HashMap<_, _> = self - .teams + let superteams: HashMap<_, _> = teams .iter() .filter_map(|team| Some((team.name.clone(), team.subteam_of.clone()?))) .collect(); - self.teams + teams .into_iter() .filter(|team| team.website_data.is_some()) .filter(|team| { @@ -190,86 +185,38 @@ impl Data { } } -pub fn encode_zulip_stream( - h: &Helper, - _: &Handlebars, - _: &Context, - _: &mut RenderContext, - out: &mut dyn Output, -) -> HelperResult { - let zulip_stream = if let Some(p) = h.param(0) { - p.value() - } else { - return Err(RenderErrorReason::ParamNotFoundForIndex( - "{{encode-zulip-stream takes 1 parameter}}", - 0, - ) - .into()); - }; - let zulip_stream = if let Some(s) = zulip_stream.as_str() { - s - } else { - return Err(RenderErrorReason::ParamTypeMismatchForName( - "encode-zulip-stream", - "0".into(), - "string".into(), - ) - .into()); - }; - - // https://github.com/zulip/zulip/blob/159641bab8c248f5b72a4e736462fb0b48e7fa24/static/js/hash_util.js#L20-L25 - let stream_encoded = utf8_percent_encode(zulip_stream, &ENCODING_SET) - .to_string() - .replace('%', "."); - - out.write(&stream_encoded)?; - Ok(()) +#[derive(Serialize)] +pub struct IndexData { + teams: Vec, } -pub async fn index_data( - teams_cache: &Cache, -) -> Result> { - Data::load(teams_cache).await?.index_data() +#[derive(Serialize)] +pub struct IndexTeam { + #[serde(flatten)] + team: Team, + url: String, } -pub async fn page_data( - section: &str, - team_name: &str, - teams_cache: &Cache, -) -> Result> { - Data::load(teams_cache).await?.page_data(section, team_name) +#[derive(Serialize)] +pub struct PageData { + pub team: Team, + zulip_domain: &'static str, + subteams: Vec, + wgs: Vec, + project_groups: Vec, + // Marker teams and other kinds of groups that have a website entry + other_teams: Vec, } -#[derive(Debug, Clone)] -pub struct RustTeams(pub Option>, pub Instant); +pub async fn load_rust_teams() -> anyhow::Result { + println!("Downloading Team API data"); + let resp: Teams = reqwest::get(format!("{BASE_URL}/teams.json")) + .await? + .error_for_status()? + .json() + .await?; -impl Default for RustTeams { - fn default() -> Self { - Self(Default::default(), Instant::now()) - } -} - -impl Cached for RustTeams { - fn get_timestamp(&self) -> Instant { - self.1 - } - async fn fetch() -> anyhow::Result { - let resp: Teams = reqwest::get(format!("{BASE_URL}/teams.json")) - .await? - .error_for_status()? - .json() - .await?; - - Ok(RustTeams( - Some( - resp.teams - .into_iter() - .map(|(_key, value)| value) - .collect::>(), - ), - Instant::now(), - )) - } + Ok(RustTeams(resp.teams.into_values().collect())) } pub(crate) fn kind_to_str(kind: TeamKind) -> &'static str { @@ -299,7 +246,7 @@ impl fmt::Display for TeamNotFound { #[cfg(test)] mod tests { - use super::{Data, TeamNotFound}; + use super::{RustTeams, TeamNotFound}; use rust_team_data::v1::{Team, TeamKind, TeamMember, TeamWebsite}; fn dummy_team(name: &str) -> Team { @@ -353,9 +300,9 @@ mod tests { fn test_index_data() { let mut foo = dummy_team("foo"); foo.kind = TeamKind::WorkingGroup; - let data = Data::dummy(vec![foo, dummy_team("bar")]); + let data = RustTeams::dummy(vec![foo, dummy_team("bar")]); - let res = data.index_data().unwrap(); + let res = data.index_data(); assert_eq!(res.teams.len(), 1); assert_eq!(res.teams[0].url, "teams/bar"); assert_eq!(res.teams[0].team.name, "bar"); @@ -365,9 +312,9 @@ mod tests { fn test_index_subteams_are_hidden() { let mut foo = dummy_team("foo"); foo.subteam_of = Some(String::new()); - let data = Data::dummy(vec![foo]); + let data = RustTeams::dummy(vec![foo]); - assert_eq!(data.index_data().unwrap().teams.len(), 0); + assert_eq!(data.index_data().teams.len(), 0); } #[test] @@ -390,7 +337,7 @@ mod tests { other_wg.subteam_of = Some("other".into()); other_wg.kind = TeamKind::WorkingGroup; - let data = Data::dummy(vec![ + let data = RustTeams::dummy(vec![ main, subteam, subteam2, @@ -419,7 +366,7 @@ mod tests { let foo = dummy_team("foo"); let mut bar = dummy_team("bar"); bar.kind = TeamKind::WorkingGroup; - let data = Data::dummy(vec![foo, bar]); + let data = RustTeams::dummy(vec![foo, bar]); assert!( data.clone() @@ -447,7 +394,7 @@ mod tests { fn test_subteams_cant_be_loaded() { let mut foo = dummy_team("foo"); foo.subteam_of = Some("bar".into()); - let data = Data::dummy(vec![foo, dummy_team("bar")]); + let data = RustTeams::dummy(vec![foo, dummy_team("bar")]); assert!( data.page_data("teams", "foo") From ef1ab10e2bc6d357cfa9401e7cc3bfcd1ea7e86b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 12:00:58 +0200 Subject: [PATCH 03/19] Add governance pages --- src/main.rs | 135 ++++++++++++++---- src/teams.rs | 24 ++-- templates/governance/group-team.html.hbs | 172 +++++++++++------------ templates/governance/group.html.hbs | 10 +- 4 files changed, 215 insertions(+), 126 deletions(-) diff --git a/src/main.rs b/src/main.rs index c4937b753..abc34b469 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,18 @@ use crate::assets::{AssetFiles, compile_assets}; -use crate::category::Category; use crate::fs::ensure_directory; use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES, TeamHelper, create_loader}; use crate::rust_version::{RustVersion, fetch_rust_version}; -use crate::teams::{RustTeams, load_rust_teams}; +use crate::teams::{PageData, RustTeams, encode_zulip_stream, load_rust_teams}; use anyhow::Context; use handlebars::{DirectorySourceOptions, Handlebars}; use handlebars_fluent::{FluentHelper, Loader, SimpleLoader}; use serde::Serialize; +use std::ffi::OsStr; use std::fs::File; use std::io::BufWriter; use std::path::{Path, PathBuf}; mod assets; -mod category; mod fs; mod i18n; mod rust_version; @@ -67,7 +66,10 @@ impl<'a, T: Serialize> PageCtx<'a, T> { let out_path = self.output_dir.join(path); ensure_directory(&out_path)?; - let mut output_file = BufWriter::new(File::create(&out_path)?); + let mut output_file = BufWriter::new( + File::create(&out_path) + .with_context(|| anyhow::anyhow!("Cannot create file at {}", path.display()))?, + ); eprintln!("Rendering `{template}` into {}", out_path.display()); self.handlebars @@ -84,6 +86,7 @@ impl<'a, T: Serialize> PageCtx<'a, T> { struct RenderCtx<'a> { handlebars: Handlebars<'a>, + template_dir: PathBuf, fluent_loader: SimpleLoader, output_dir: PathBuf, rust_version: RustVersion, @@ -124,16 +127,28 @@ impl<'a> RenderCtx<'a> { } } - fn copy_static_assets>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { + fn copy_asset_dir>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { let dst = self.output_dir.join(dst_dir.as_ref()); println!( - "Copying static assets from {} to {}", + "Copying static asset directory from {} to {}", src_dir.as_ref().display(), dst.display() ); copy_dir_all(src_dir.as_ref(), dst)?; Ok(()) } + + fn copy_asset_file>(&self, src: P, dst: P) -> anyhow::Result<()> { + let dst = self.output_dir.join(dst.as_ref()); + println!( + "Copying static asset file from {} to {}", + src.as_ref().display(), + dst.display() + ); + ensure_directory(&dst)?; + std::fs::copy(src.as_ref(), dst)?; + Ok(()) + } } /// Calls `func` for all supported languages. @@ -181,6 +196,7 @@ fn setup_handlebars() -> anyhow::Result> { let helper = FluentHelper::new(loader); handlebars.register_helper("fluent", Box::new(helper)); handlebars.register_helper("team-text", Box::new(TeamHelper::new())); + handlebars.register_helper("encode-zulip-stream", Box::new(encode_zulip_stream)); Ok(handlebars) } @@ -194,10 +210,12 @@ async fn main() -> anyhow::Result<()> { let _ = std::fs::remove_dir_all(&output_dir); std::fs::create_dir_all(&output_dir)?; - let assets = compile_assets(Path::new("."), &output_dir, "/")?; + let root_dir = Path::new("."); + let assets = compile_assets(root_dir, &output_dir, "/")?; let handlebars = setup_handlebars()?; let ctx = RenderCtx { + template_dir: root_dir.join("templates"), fluent_loader: create_loader(), assets, rust_version, @@ -205,17 +223,22 @@ async fn main() -> anyhow::Result<()> { handlebars, output_dir, }; - ctx.copy_static_assets("static", "static")?; + ctx.copy_asset_dir("static", "static")?; + ctx.copy_asset_file( + "static/text/well_known_security.txt", + ".well-known/security.txt", + )?; render_index(&ctx)?; render_governance(&ctx)?; - render_category(&ctx, "community")?; - render_category(&ctx, "learn")?; - render_category(&ctx, "policies")?; - render_category(&ctx, "tools")?; - render_category(&ctx, "what")?; + render_directory(&ctx, "community")?; + render_directory(&ctx, "learn")?; + render_directory(&ctx, "policies")?; + render_directory(&ctx, "tools")?; + render_directory(&ctx, "what")?; + ctx.page("404", "", &(), ENGLISH).render("404.html")?; - // TODO: 404, redirects + // TODO: redirects Ok(()) } @@ -243,18 +266,78 @@ fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { render_ctx .page("governance/index", "governance-page-title", &data, lang) .render(dst_path) - }) + })?; + for team in data.teams { + let data: PageData = render_ctx + .teams + .page_data(team.section, &team.page_name) + .unwrap_or_else(|error| panic!("Page data for team {team:?} not found: {error:?}")); + + // We need to render into index.html to have an extensionless URL + all_langs( + &format!("governance/{}/index.html", team.url), + |dst_path, lang| { + render_ctx + .page( + "governance/group", + &format!("governance-team-{}-title", team.team.name), + &data, + lang, + ) + .render(dst_path) + }, + )?; + } + + Ok(()) } -fn render_category(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { - all_langs(&format!("{category}/index.html"), |dst_path, lang| { - render_ctx - .page( - &format!("{category}/index"), - &format!("{category}-page-title"), - &(), - lang, - ) - .render(dst_path) - }) +/// Render all templates found in the given directory. +fn render_directory(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { + for dir in std::fs::read_dir(render_ctx.template_dir.join(category))? { + let path = dir?.path(); + if path.is_file() && path.extension() == Some(OsStr::new("hbs")) { + // foo.html.hbs => foo + let subject = path + .file_stem() + .unwrap() + .to_str() + .unwrap() + .split(".") + .next() + .unwrap(); + + // The "root" page of a category + if subject == "index" { + all_langs(&format!("{category}/index.html"), |dst_path, lang| { + render_ctx + .page( + &format!("{category}/index"), + &format!("{category}-page-title"), + &(), + lang, + ) + .render(dst_path) + })?; + } else { + // A subpage (subject) of the category + // We need to render the page into a subdirectory, so that /foo/bar works without + // needing a HTML suffix. + all_langs( + &format!("{category}/{subject}/index.html"), + |dst_path, lang| { + render_ctx + .page( + &format!("{category}/{subject}"), + &format!("{category}-{subject}-page-title"), + &(), + lang, + ) + .render(dst_path) + }, + )?; + } + } + } + Ok(()) } diff --git a/src/teams.rs b/src/teams.rs index 2a64005ee..7a7f79bf5 100644 --- a/src/teams.rs +++ b/src/teams.rs @@ -1,7 +1,7 @@ -use percent_encoding::{AsciiSet, NON_ALPHANUMERIC, utf8_percent_encode}; -use rocket_dyn_templates::handlebars::{ +use handlebars::{ Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderErrorReason, }; +use percent_encoding::{AsciiSet, NON_ALPHANUMERIC, utf8_percent_encode}; use rust_team_data::v1::{BASE_URL, Team, TeamKind, Teams}; use serde::Serialize; use std::cmp::Reverse; @@ -66,6 +66,8 @@ impl RustTeams { // teams. .filter(|team| team.kind == TeamKind::Team && team.subteam_of.is_none()) .map(|team| IndexTeam { + section: kind_to_str(team.kind), + page_name: team.website_data.clone().unwrap().page, url: format!( "{}/{}", kind_to_str(team.kind), @@ -81,13 +83,15 @@ impl RustTeams { IndexData { teams } } - pub fn page_data(&self, section: &str, team_name: &str) -> anyhow::Result { + pub fn page_data(&self, section: &str, team_page_name: &str) -> anyhow::Result { let teams = self.0.clone(); // Find the main team first let main_team = teams .iter() - .filter(|team| team.website_data.as_ref().map(|ws| ws.page.as_str()) == Some(team_name)) + .filter(|team| { + team.website_data.as_ref().map(|ws| ws.page.as_str()) == Some(team_page_name) + }) .find(|team| kind_to_str(team.kind) == section) .cloned() .ok_or(TeamNotFound)?; @@ -187,19 +191,21 @@ impl RustTeams { #[derive(Serialize)] pub struct IndexData { - teams: Vec, + pub teams: Vec, } -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct IndexTeam { #[serde(flatten)] - team: Team, - url: String, + pub team: Team, + pub url: String, + pub section: &'static str, + pub page_name: String, } #[derive(Serialize)] pub struct PageData { - pub team: Team, + team: Team, zulip_domain: &'static str, subteams: Vec, wgs: Vec, diff --git a/templates/governance/group-team.html.hbs b/templates/governance/group-team.html.hbs index 8bc133216..3da321283 100644 --- a/templates/governance/group-team.html.hbs +++ b/templates/governance/group-team.html.hbs @@ -1,106 +1,106 @@
-
- -

{{team-text team name}}

-
-
-
-
- +
+ +

{{team-text team name}}

+
+
+
+ + {{#if team.members}}
-

{{fluent "governance-members-header"}}

+

{{fluent "governance-members-header"}}

- {{#each team.members as |member|}} + {{#each team.members as |member|}}
- - {{member.name}} - -
-

{{member.name}}

-
- {{#fluent "governance-user-github"}} - {{#fluentparam "link"}} - {{member.github}} - {{/fluentparam}} - {{/fluent}} -
- {{#if member.is_lead}} -
{{fluent "governance-user-team-leader"}}
- {{else}} - {{#if member.roles}} -
{{team-text team role (lookup member.roles 0)}}
- {{/if}} - {{/if}} + + {{member.name}} + +
+

{{member.name}}

+
+ {{#fluent "governance-user-github"}} + {{#fluentparam "link"}} + {{member.github}} + {{/fluentparam}} + {{/fluent}}
+ {{#if member.is_lead}} +
{{fluent "governance-user-team-leader"}}
+ {{else}} + {{#if member.roles}} +
{{team-text ../team role (lookup member.roles 0)}}
+ {{/if}} + {{/if}} +
- {{/each}} + {{/each}}
{{#if team.alumni}} -
+

{{fluent "governance-alumni-header"}}

-
-

{{fluent "governance-alumni-thanks"}}

-
+
+

{{fluent "governance-alumni-thanks"}}

+
{{#each team.alumni as |member|}} -
+
- {{member.name}} + {{member.name}}
- {{member.name}} -
- GitHub: {{member.github}} -
- {{#if member.roles}} -
{{team-text team role (lookup member.roles 0)}}
- {{/if}} + {{member.name}} +
+ GitHub: {{member.github}} +
+ {{#if member.roles}} +
{{team-text ../team role (lookup member.roles 0)}}
+ {{/if}}
-
+
{{/each}} -
- {{/if}} +
{{/if}} + {{/if}}
diff --git a/templates/governance/group.html.hbs b/templates/governance/group.html.hbs index dd67bcec5..9f135ee0a 100644 --- a/templates/governance/group.html.hbs +++ b/templates/governance/group.html.hbs @@ -2,34 +2,34 @@ {{#with data.team as |team|}}
- {{> governance/group-team}} + {{> governance/group-team team=team zulip_domain=data.zulip_domain}}
{{/with}} {{#if data.subteams}}
{{#each data.subteams as |team|}} - {{> governance/group-team}} + {{> governance/group-team team=team zulip_domain=data.zulip_domain}} {{/each}}
{{/if}} {{#if data.project_groups}}
{{#each data.project_groups as |team|}} - {{> governance/group-team}} + {{> governance/group-team team=team zulip_domain=data.zulip_domain}} {{/each}}
{{/if}} {{#if data.wgs}}
{{#each data.wgs as |team|}} - {{> governance/group-team}} + {{> governance/group-team team=team zulip_domain=data.zulip_domain}} {{/each}}
{{/if}} {{#if data.other_teams}}
{{#each data.other_teams as |team|}} - {{> governance/group-team}} + {{> governance/group-team team=team zulip_domain=data.zulip_domain}} {{/each}}
{{/if}} From c3701454dc43943c6028e8b321c07a86c946cd77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 12:06:48 +0200 Subject: [PATCH 04/19] Remove rocket --- Cargo.lock | 1081 +++---------------------------------------------- Cargo.toml | 2 - src/assets.rs | 2 +- src/i18n.rs | 15 - 4 files changed, 55 insertions(+), 1045 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3a626f725..c91e9a2dd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,69 +17,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "anyhow" version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-trait" -version = "0.1.88" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" -dependencies = [ - "bytemuck", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -113,18 +56,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "binascii" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - [[package]] name = "bitflags" version = "2.9.0" @@ -146,12 +77,6 @@ version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" -[[package]] -name = "bytemuck" -version = "1.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" - [[package]] name = "bytes" version = "1.10.1" @@ -173,17 +98,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - [[package]] name = "core-foundation" version = "0.9.4" @@ -209,21 +123,6 @@ dependencies = [ "libc", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" - [[package]] name = "crypto-common" version = "0.1.6" @@ -309,39 +208,6 @@ dependencies = [ "syn", ] -[[package]] -name = "devise" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d90b0c4c777a2cad215e3c7be59ac7c15adf45cf76317009b7d096d46f651d" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71b28680d8be17a570a2334922518be6adc3f58ecc880cbb404eaeb8624fd867" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b035a542cf7abf01f2e3c4d5a7acbaebfefe120ae4efc7bde3df98186e4b8af7" -dependencies = [ - "bitflags 2.9.0", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - [[package]] name = "digest" version = "0.10.7" @@ -363,12 +229,6 @@ dependencies = [ "syn", ] -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "encoding_rs" version = "0.8.35" @@ -400,32 +260,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "figment" -version = "0.10.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" -dependencies = [ - "atomic 0.6.0", - "pear", - "serde", - "toml", - "uncased", - "version_check", -] - -[[package]] -name = "filetime" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" -dependencies = [ - "cfg-if", - "libc", - "libredox", - "windows-sys 0.59.0", -] - [[package]] name = "fluent" version = "0.16.1" @@ -526,29 +360,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "fsevent-sys" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" -dependencies = [ - "libc", -] - -[[package]] -name = "futures" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -556,7 +367,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -565,12 +375,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" -[[package]] -name = "futures-io" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" - [[package]] name = "futures-sink" version = "0.3.31" @@ -589,28 +393,10 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ - "futures-channel", "futures-core", - "futures-io", - "futures-sink", "futures-task", - "memchr", "pin-project-lite", "pin-utils", - "slab", -] - -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows", ] [[package]] @@ -652,31 +438,6 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" -[[package]] -name = "glob" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" - -[[package]] -name = "h2" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - [[package]] name = "h2" version = "0.4.9" @@ -688,7 +449,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http 1.3.1", + "http", "indexmap", "slab", "tokio", @@ -696,20 +457,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "handlebars" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" -dependencies = [ - "log", - "pest", - "pest_derive", - "serde", - "serde_json", - "thiserror 1.0.69", -] - [[package]] name = "handlebars" version = "6.3.2" @@ -737,7 +484,7 @@ dependencies = [ "fluent-bundle 0.16.0", "fluent-langneg", "fluent-syntax 0.12.0", - "handlebars 6.3.2", + "handlebars", "lazy_static", "serde_json", "unic-langid", @@ -755,23 +502,6 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" -[[package]] -name = "hermit-abi" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbd780fe5cc30f81464441920d82ac8740e2e46b29a6fad543ddd075229ce37e" - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.3.1" @@ -783,17 +513,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -801,7 +520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http", ] [[package]] @@ -812,8 +531,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -823,36 +542,6 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "httpdate" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" - -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.26", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.6.0" @@ -862,9 +551,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2 0.4.9", - "http 1.3.1", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "itoa", "pin-project-lite", @@ -880,8 +569,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", - "http 1.3.1", - "hyper 1.6.0", + "http", + "hyper", "hyper-util", "rustls", "rustls-pki-types", @@ -898,7 +587,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper", "hyper-util", "native-tls", "tokio", @@ -915,9 +604,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http 1.3.1", - "http-body 1.0.1", - "hyper 1.6.0", + "http", + "http-body", + "hyper", "libc", "pin-project-lite", "socket2", @@ -1082,32 +771,6 @@ dependencies = [ "serde", ] -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - -[[package]] -name = "inotify" -version = "0.9.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" -dependencies = [ - "bitflags 1.3.2", - "inotify-sys", - "libc", -] - -[[package]] -name = "inotify-sys" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" -dependencies = [ - "libc", -] - [[package]] name = "intl-memoizer" version = "0.5.3" @@ -1133,7 +796,7 @@ version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cfg-if", "libc", ] @@ -1144,17 +807,6 @@ version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" -[[package]] -name = "is-terminal" -version = "0.4.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" -dependencies = [ - "hermit-abi 0.5.0", - "libc", - "windows-sys 0.59.0", -] - [[package]] name = "itoa" version = "1.0.15" @@ -1171,26 +823,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "kqueue" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" -dependencies = [ - "kqueue-sys", - "libc", -] - -[[package]] -name = "kqueue-sys" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" -dependencies = [ - "bitflags 1.3.2", - "libc", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -1203,17 +835,6 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -[[package]] -name = "libredox" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" -dependencies = [ - "bitflags 2.9.0", - "libc", - "redox_syscall", -] - [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -1242,30 +863,6 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "memchr" version = "2.7.4" @@ -1287,18 +884,6 @@ dependencies = [ "adler2", ] -[[package]] -name = "mio" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" -dependencies = [ - "libc", - "log", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", -] - [[package]] name = "mio" version = "1.0.3" @@ -1310,25 +895,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "multer" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.3.1", - "httparse", - "memchr", - "mime", - "spin", - "tokio", - "tokio-util", - "version_check", -] - [[package]] name = "native-tls" version = "0.2.14" @@ -1346,44 +912,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "normpath" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8911957c4b1549ac0dc74e30db9c8b0e66ddcd6d7acc33098f4c63a64a6d7ed" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "notify" -version = "6.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" -dependencies = [ - "bitflags 2.9.0", - "crossbeam-channel", - "filetime", - "fsevent-sys", - "inotify", - "kqueue", - "libc", - "log", - "mio 0.8.11", - "walkdir", - "windows-sys 0.48.0", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -1411,7 +939,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi", "libc", ] @@ -1436,7 +964,7 @@ version = "0.10.72" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" dependencies = [ - "bitflags 2.9.0", + "bitflags", "cfg-if", "foreign-types", "libc", @@ -1474,12 +1002,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - [[package]] name = "parking_lot" version = "0.12.3" @@ -1503,29 +1025,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "pear" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - [[package]] name = "percent-encoding" version = "2.3.1" @@ -1587,174 +1086,58 @@ checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" name = "pin-utils" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.20+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "version_check", - "yansi", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[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.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.15", -] - -[[package]] -name = "redox_syscall" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" -dependencies = [ - "bitflags 2.9.0", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] -name = "ref-cast" -version = "1.0.24" +name = "pkg-config" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" -dependencies = [ - "ref-cast-impl", -] +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] -name = "ref-cast-impl" -version = "1.0.24" +name = "powerfmt" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] -name = "regex" -version = "1.11.1" +name = "proc-macro-hack" +version = "0.5.20+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata 0.4.9", - "regex-syntax 0.8.5", -] +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" [[package]] -name = "regex-automata" -version = "0.1.10" +name = "proc-macro2" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ - "regex-syntax 0.6.29", + "unicode-ident", ] [[package]] -name = "regex-automata" -version = "0.4.9" +name = "quote" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax 0.8.5", + "proc-macro2", ] [[package]] -name = "regex-syntax" -version = "0.6.29" +name = "r-efi" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] -name = "regex-syntax" -version = "0.8.5" +name = "redox_syscall" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" +dependencies = [ + "bitflags", +] [[package]] name = "reqwest" @@ -1767,11 +1150,11 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2 0.4.9", - "http 1.3.1", - "http-body 1.0.1", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.6.0", + "hyper", "hyper-rustls", "hyper-tls", "hyper-util", @@ -1814,100 +1197,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rocket" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a516907296a31df7dc04310e7043b61d71954d703b603cc6867a026d7e72d73f" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap", - "log", - "memchr", - "multer", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "575d32d7ec1a9770108c879fc7c47815a80073f96ca07ff9525a94fcede1dd46" -dependencies = [ - "devise", - "glob", - "indexmap", - "proc-macro2", - "quote", - "rocket_http", - "syn", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_dyn_templates" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bbab919c9e67df3f7ac6624a32ef897df4cd61c0969f4d66f3ced0534660d7a" -dependencies = [ - "handlebars 5.1.2", - "normpath", - "notify", - "rocket", - "walkdir", -] - -[[package]] -name = "rocket_http" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e274915a20ee3065f611c044bd63c40757396b6dbc057d6046aec27f14f882b9" -dependencies = [ - "cookie", - "either", - "futures", - "http 0.2.12", - "hyper 0.14.32", - "indexmap", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - [[package]] name = "rust_team_data" version = "1.0.0" @@ -1941,7 +1230,7 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" dependencies = [ - "bitflags 2.9.0", + "bitflags", "errno", "libc", "linux-raw-sys", @@ -2039,12 +1328,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "scoped-tls" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" - [[package]] name = "scopeguard" version = "1.2.0" @@ -2057,7 +1340,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.0", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -2153,15 +1436,6 @@ dependencies = [ "digest", ] -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - [[package]] name = "shlex" version = "1.3.0" @@ -2202,36 +1476,12 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" - -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - [[package]] name = "strsim" version = "0.11.1" @@ -2281,7 +1531,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.0", + "bitflags", "core-foundation", "system-configuration-sys", ] @@ -2349,16 +1599,6 @@ dependencies = [ "syn", ] -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - [[package]] name = "time" version = "0.3.41" @@ -2366,7 +1606,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde", @@ -2410,7 +1649,7 @@ dependencies = [ "bytes", "io-uring", "libc", - "mio 1.0.3", + "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -2451,17 +1690,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.14" @@ -2550,21 +1778,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", - "tracing-attributes", "tracing-core", ] -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "tracing-core" version = "0.1.33" @@ -2572,36 +1788,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "matchers", - "nu-ansi-term", - "once_cell", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", ] [[package]] @@ -2625,31 +1811,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" -[[package]] -name = "ubyte" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" -dependencies = [ - "serde", -] - [[package]] name = "ucd-trie" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" -[[package]] -name = "uncased" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" -dependencies = [ - "serde", - "version_check", -] - [[package]] name = "unic-langid" version = "0.9.5" @@ -2699,12 +1866,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" -[[package]] -name = "unicode-xid" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" - [[package]] name = "untrusted" version = "0.9.0" @@ -2734,12 +1895,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - [[package]] name = "vcpkg" version = "0.2.15" @@ -2867,22 +2022,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[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-util" version = "0.1.9" @@ -2892,21 +2031,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[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 = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-link" version = "0.1.1" @@ -2942,15 +2066,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows-sys" version = "0.52.0" @@ -2969,21 +2084,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-targets" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" -dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", -] - [[package]] name = "windows-targets" version = "0.52.6" @@ -3016,12 +2116,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -3034,12 +2128,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" @@ -3052,12 +2140,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -3082,12 +2164,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" @@ -3100,12 +2176,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" @@ -3118,12 +2188,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" @@ -3136,12 +2200,6 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -3169,7 +2227,7 @@ version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" dependencies = [ - "bitflags 2.9.0", + "bitflags", ] [[package]] @@ -3189,12 +2247,10 @@ name = "www-rust-lang-org" version = "0.1.0" dependencies = [ "anyhow", - "handlebars 6.3.2", + "handlebars", "handlebars-fluent", "percent-encoding", "reqwest", - "rocket", - "rocket_dyn_templates", "rust_team_data", "sass-rs", "serde", @@ -3204,15 +2260,6 @@ dependencies = [ "toml", ] -[[package]] -name = "yansi" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -dependencies = [ - "is-terminal", -] - [[package]] name = "yoke" version = "0.7.5" @@ -3237,26 +2284,6 @@ dependencies = [ "synstructure", ] -[[package]] -name = "zerocopy" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "zerofrom" version = "0.1.6" diff --git a/Cargo.toml b/Cargo.toml index 50b06cb6b..b5f98900c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,6 @@ anyhow = "1" tokio = { version = "1", features = ["full"] } handlebars = { version = "6", features = ["dir_source"] } handlebars-fluent = "0.5" -rocket = "0.5.1" -rocket_dyn_templates = { version = "0.2.0", features = ["handlebars"] } serde = { version = "1.0", features = ["derive"] } sass-rs = "0.2.1" reqwest = { version = "0.12.15", features = ["json"] } diff --git a/src/assets.rs b/src/assets.rs index dcbd5f10e..f486d5ff3 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -1,7 +1,7 @@ use crate::fs::ensure_directory; use anyhow::Context; -use rocket::serde::Serialize; use sass_rs::{Options, compile_file}; +use serde::Serialize; use std::fs; use std::hash::{DefaultHasher, Hasher}; use std::path::Path; diff --git a/src/i18n.rs b/src/i18n.rs index 5f2cce7a1..c29f84540 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -2,7 +2,6 @@ use handlebars::{ Context, Handlebars, Helper, HelperDef, HelperResult, Output, RenderContext, RenderErrorReason, }; -use rocket::request::FromParam; use serde::Serialize; use std::{collections::HashSet, sync::LazyLock}; @@ -235,17 +234,3 @@ impl HelperDef for TeamHelper { Ok(()) } } - -pub struct SupportedLocale(pub String); - -impl<'r> FromParam<'r> for SupportedLocale { - type Error = (); - - fn from_param(param: &'r str) -> Result { - if SUPPORTED_LOCALES.contains(param) { - Ok(SupportedLocale(param.parse().map_err(|_| ())?)) - } else { - Err(()) - } - } -} From c3c85fca99c1843e2ce1120fd0706009fb18169e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 12:44:45 +0200 Subject: [PATCH 05/19] Restructure code around and add redirect template --- src/fs.rs | 14 ++ src/main.rs | 270 ++--------------------------------- src/redirect.rs | 103 +++++++------- src/render.rs | 275 ++++++++++++++++++++++++++++++++++++ templates/redirect.html.hbs | 6 + 5 files changed, 357 insertions(+), 311 deletions(-) create mode 100644 src/render.rs create mode 100644 templates/redirect.html.hbs diff --git a/src/fs.rs b/src/fs.rs index d6d2e27ea..06bc864f1 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -9,3 +9,17 @@ pub fn ensure_directory(path: &Path) -> anyhow::Result<()> { } Ok(()) } + +pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { + std::fs::create_dir_all(&dst)?; + for entry in std::fs::read_dir(src)? { + let entry = entry?; + let ty = entry.file_type()?; + if ty.is_dir() { + copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index abc34b469..1f43357df 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,19 @@ -use crate::assets::{AssetFiles, compile_assets}; -use crate::fs::ensure_directory; -use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES, TeamHelper, create_loader}; -use crate::rust_version::{RustVersion, fetch_rust_version}; -use crate::teams::{PageData, RustTeams, encode_zulip_stream, load_rust_teams}; +use crate::assets::compile_assets; +use crate::i18n::{TeamHelper, create_loader}; +use crate::redirect::create_redirects; +use crate::render::{RenderCtx, render_directory, render_governance, render_index}; +use crate::rust_version::RustVersion; +use crate::teams::{encode_zulip_stream, load_rust_teams}; use anyhow::Context; use handlebars::{DirectorySourceOptions, Handlebars}; -use handlebars_fluent::{FluentHelper, Loader, SimpleLoader}; -use serde::Serialize; -use std::ffi::OsStr; -use std::fs::File; -use std::io::BufWriter; +use handlebars_fluent::FluentHelper; use std::path::{Path, PathBuf}; mod assets; mod fs; mod i18n; +mod redirect; +mod render; mod rust_version; mod teams; @@ -33,155 +32,6 @@ fn baseurl(lang: &str) -> String { } } -#[derive(Serialize)] -struct TemplateCtx<'a, T: Serialize> { - page: String, - title: String, - parent: &'static str, - is_landing: bool, - data: &'a T, - lang: String, - baseurl: String, - pontoon_enabled: bool, - assets: &'a AssetFiles, - locales: &'static [LocaleInfo], - is_translation: bool, -} - -struct PageCtx<'a, T: Serialize> { - template_ctx: TemplateCtx<'a, T>, - output_dir: &'a Path, - handlebars: &'a Handlebars<'a>, -} - -impl<'a, T: Serialize> PageCtx<'a, T> { - fn make_landing(mut self) -> Self { - self.template_ctx.is_landing = true; - self - } - - fn render>(self, dst_path: P) -> anyhow::Result<()> { - let path = dst_path.as_ref(); - let template = &self.template_ctx.page; - - let out_path = self.output_dir.join(path); - ensure_directory(&out_path)?; - let mut output_file = BufWriter::new( - File::create(&out_path) - .with_context(|| anyhow::anyhow!("Cannot create file at {}", path.display()))?, - ); - eprintln!("Rendering `{template}` into {}", out_path.display()); - - self.handlebars - .render_to_write(template, &self.template_ctx, &mut output_file) - .with_context(|| { - anyhow::anyhow!( - "cannot render template {template} into {}", - out_path.display() - ) - })?; - Ok(()) - } -} - -struct RenderCtx<'a> { - handlebars: Handlebars<'a>, - template_dir: PathBuf, - fluent_loader: SimpleLoader, - output_dir: PathBuf, - rust_version: RustVersion, - teams: RustTeams, - assets: AssetFiles, -} - -impl<'a> RenderCtx<'a> { - fn page( - &'a self, - page: &str, - title_id: &str, - data: &'a T, - lang: &str, - ) -> PageCtx<'a, T> { - let title = if title_id.is_empty() { - "".into() - } else { - let lang = lang.parse().expect("lang should be valid"); - self.fluent_loader.lookup(&lang, title_id, None) - }; - PageCtx { - template_ctx: TemplateCtx { - page: page.to_string(), - title, - parent: LAYOUT, - is_landing: false, - data, - baseurl: baseurl(&lang), - is_translation: lang != "en-US", - lang: lang.to_string(), - pontoon_enabled: PONTOON_ENABLED, - assets: &self.assets, - locales: EXPLICIT_LOCALE_INFO, - }, - output_dir: &self.output_dir, - handlebars: &self.handlebars, - } - } - - fn copy_asset_dir>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { - let dst = self.output_dir.join(dst_dir.as_ref()); - println!( - "Copying static asset directory from {} to {}", - src_dir.as_ref().display(), - dst.display() - ); - copy_dir_all(src_dir.as_ref(), dst)?; - Ok(()) - } - - fn copy_asset_file>(&self, src: P, dst: P) -> anyhow::Result<()> { - let dst = self.output_dir.join(dst.as_ref()); - println!( - "Copying static asset file from {} to {}", - src.as_ref().display(), - dst.display() - ); - ensure_directory(&dst)?; - std::fs::copy(src.as_ref(), dst)?; - Ok(()) - } -} - -/// Calls `func` for all supported languages. -/// Passes it the destination path into which should a given page be rendered, and the language -/// in which it should be rendered. -fn all_langs(dst_path: &str, func: F) -> anyhow::Result<()> -where - F: Fn(&str, &str) -> anyhow::Result<()>, -{ - for lang in SUPPORTED_LOCALES.iter() { - let path = match lang { - l if *l == ENGLISH => dst_path.to_string(), - l => format!("{l}/{dst_path}"), - }; - func(&path, lang).with_context(|| anyhow::anyhow!("could not handle language {lang}"))?; - } - Ok(()) -} - -fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> std::io::Result<()> { - std::fs::create_dir_all(&dst)?; - for entry in std::fs::read_dir(src)? { - let entry = entry?; - let ty = entry.file_type()?; - if ty.is_dir() { - copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; - } else { - std::fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; - } - } - Ok(()) -} - fn setup_handlebars() -> anyhow::Result> { let mut handlebars: Handlebars<'static> = Handlebars::new(); handlebars.set_strict_mode(true); @@ -237,107 +87,7 @@ async fn main() -> anyhow::Result<()> { render_directory(&ctx, "tools")?; render_directory(&ctx, "what")?; ctx.page("404", "", &(), ENGLISH).render("404.html")?; + create_redirects(&ctx)?; - // TODO: redirects - - Ok(()) -} - -fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { - #[derive(Serialize)] - struct IndexData { - rust_version: String, - } - let data = IndexData { - rust_version: render_ctx.rust_version.0.clone(), - }; - all_langs("index.html", |path, lang| { - render_ctx - .page("index", "", &data, lang) - .make_landing() - .render(path) - }) -} - -fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { - let data = render_ctx.teams.index_data(); - - all_langs("governance/index.html", |dst_path, lang| { - render_ctx - .page("governance/index", "governance-page-title", &data, lang) - .render(dst_path) - })?; - for team in data.teams { - let data: PageData = render_ctx - .teams - .page_data(team.section, &team.page_name) - .unwrap_or_else(|error| panic!("Page data for team {team:?} not found: {error:?}")); - - // We need to render into index.html to have an extensionless URL - all_langs( - &format!("governance/{}/index.html", team.url), - |dst_path, lang| { - render_ctx - .page( - "governance/group", - &format!("governance-team-{}-title", team.team.name), - &data, - lang, - ) - .render(dst_path) - }, - )?; - } - - Ok(()) -} - -/// Render all templates found in the given directory. -fn render_directory(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { - for dir in std::fs::read_dir(render_ctx.template_dir.join(category))? { - let path = dir?.path(); - if path.is_file() && path.extension() == Some(OsStr::new("hbs")) { - // foo.html.hbs => foo - let subject = path - .file_stem() - .unwrap() - .to_str() - .unwrap() - .split(".") - .next() - .unwrap(); - - // The "root" page of a category - if subject == "index" { - all_langs(&format!("{category}/index.html"), |dst_path, lang| { - render_ctx - .page( - &format!("{category}/index"), - &format!("{category}-page-title"), - &(), - lang, - ) - .render(dst_path) - })?; - } else { - // A subpage (subject) of the category - // We need to render the page into a subdirectory, so that /foo/bar works without - // needing a HTML suffix. - all_langs( - &format!("{category}/{subject}/index.html"), - |dst_path, lang| { - render_ctx - .page( - &format!("{category}/{subject}"), - &format!("{category}-{subject}-page-title"), - &(), - lang, - ) - .render(dst_path) - }, - )?; - } - } - } Ok(()) } diff --git a/src/redirect.rs b/src/redirect.rs index 74f751a3e..c0aba45c3 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -1,10 +1,7 @@ use crate::i18n::SUPPORTED_LOCALES; -use rocket::http::uri::Path; -use rocket::response::Redirect; +use crate::render::RenderCtx; -static PAGE_REDIRECTS: &[(&str, &str)] = &[ - // Migrate pre-2018 locale for the index page - ("", ""), +pub static PAGE_REDIRECTS: &[(&str, &str)] = &[ // Pre-2018 website pages ("community.html", "community"), ("conduct.html", "policies/code-of-conduct"), @@ -47,7 +44,7 @@ static PAGE_REDIRECTS: &[(&str, &str)] = &[ ("governance/wgs", "governance#working-groups"), ]; -static STATIC_FILES_REDIRECTS: &[(&str, &str)] = &[ +pub static STATIC_FILES_REDIRECTS: &[(&str, &str)] = &[ // Pre-2018 whitepaper locations ( "pdfs/Rust-npm-Whitepaper.pdf", @@ -84,52 +81,56 @@ static PRE_2018_LOCALES: &[&str] = &[ "ru-RU", "sv-SE", "vi-VN", ]; -pub(crate) fn maybe_redirect(path: Path) -> Option { - let path = path.segments().collect::>().join("/"); +pub fn create_redirects(ctx: &RenderCtx) -> anyhow::Result<()> { + // Static file redirects, no need to support languages + // for (src, dst) in STATIC_FILES_REDIRECTS { + // render_redirect(ctx, src, dst)?; + // } - if let Some((_, dest)) = STATIC_FILES_REDIRECTS.iter().find(|(src, _)| src == &path) { - return Some(Redirect::permanent(*dest)); - } - - let (locale, path) = if let Some((first, rest)) = path.split_once('/') { - if SUPPORTED_LOCALES.contains(&first) { - (Locale::Present(first), rest) - // After the 2018 website redesign some of the locales were removed and some were - // renamed (removing the country code). This handles both cases, either calculating the - // renamed locale or marking the locale as "specified but missing", which triggers a - // temporary redirect instead of a permanent redirect. - } else if PRE_2018_LOCALES.contains(&first) { - if let Some(locale) = convert_locale_from_pre_2018(first) { - (Locale::Present(locale), rest) - } else { - (Locale::SpecifiedButMissing, rest) - } - } else { - (Locale::NotSpecified, path.as_str()) - } - } else if PRE_2018_LOCALES.contains(&path.as_str()) { - // If the whole path is a pre-2018 locale handle it as a localized index page. - if let Some(locale) = convert_locale_from_pre_2018(&path) { - (Locale::Present(locale), "") - } else { - (Locale::SpecifiedButMissing, "") - } - } else { - (Locale::NotSpecified, path.as_str()) - }; - - if let Some((_, dest)) = EXTERNAL_REDIRECTS.iter().find(|(src, _)| *src == path) { - Some(Redirect::permanent(*dest)) - } else if let Some((_, dest)) = PAGE_REDIRECTS.iter().find(|(src, _)| *src == path) { - let dest = format!("/{dest}"); - match locale { - Locale::Present("en-US") | Locale::NotSpecified => Some(Redirect::permanent(dest)), - Locale::Present(locale) => Some(Redirect::permanent(format!("/{locale}{dest}"))), - Locale::SpecifiedButMissing => Some(Redirect::temporary(dest)), - } - } else { - None - } + // if let Some((_, dest)) = STATIC_FILES_REDIRECTS.iter().find(|(src, _)| src == &path) { + // return Some(Redirect::permanent(*dest)); + // } + // + // let (locale, path) = if let Some((first, rest)) = path.split_once('/') { + // if SUPPORTED_LOCALES.contains(&first) { + // (Locale::Present(first), rest) + // // After the 2018 website redesign some of the locales were removed and some were + // // renamed (removing the country code). This handles both cases, either calculating the + // // renamed locale or marking the locale as "specified but missing", which triggers a + // // temporary redirect instead of a permanent redirect. + // } else if PRE_2018_LOCALES.contains(&first) { + // if let Some(locale) = convert_locale_from_pre_2018(first) { + // (Locale::Present(locale), rest) + // } else { + // (Locale::SpecifiedButMissing, rest) + // } + // } else { + // (Locale::NotSpecified, path.as_str()) + // } + // } else if PRE_2018_LOCALES.contains(&path.as_str()) { + // // If the whole path is a pre-2018 locale handle it as a localized index page. + // if let Some(locale) = convert_locale_from_pre_2018(&path) { + // (Locale::Present(locale), "") + // } else { + // (Locale::SpecifiedButMissing, "") + // } + // } else { + // (Locale::NotSpecified, path.as_str()) + // }; + // + // if let Some((_, dest)) = EXTERNAL_REDIRECTS.iter().find(|(src, _)| *src == path) { + // Some(Redirect::permanent(*dest)) + // } else if let Some((_, dest)) = PAGE_REDIRECTS.iter().find(|(src, _)| *src == path) { + // let dest = format!("/{dest}"); + // match locale { + // Locale::Present("en-US") | Locale::NotSpecified => Some(Redirect::permanent(dest)), + // Locale::Present(locale) => Some(Redirect::permanent(format!("/{locale}{dest}"))), + // Locale::SpecifiedButMissing => Some(Redirect::temporary(dest)), + // } + // } else { + // None + // } + Ok(()) } fn convert_locale_from_pre_2018(pre_2018: &str) -> Option<&str> { diff --git a/src/render.rs b/src/render.rs new file mode 100644 index 000000000..0ee8d8568 --- /dev/null +++ b/src/render.rs @@ -0,0 +1,275 @@ +use crate::assets::AssetFiles; +use crate::fs::{copy_dir_all, ensure_directory}; +use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES}; +use crate::rust_version::RustVersion; +use crate::teams::{PageData, RustTeams}; +use crate::{ENGLISH, LAYOUT, PONTOON_ENABLED, baseurl}; +use anyhow::Context; +use handlebars::Handlebars; +use handlebars_fluent::{Loader, SimpleLoader}; +use serde::Serialize; +use std::ffi::OsStr; +use std::fs::File; +use std::io::BufWriter; +use std::path::{Path, PathBuf}; + +#[derive(Serialize)] +pub struct TemplateCtx<'a, T: Serialize> { + page: String, + title: String, + parent: &'static str, + is_landing: bool, + data: &'a T, + lang: String, + baseurl: String, + pontoon_enabled: bool, + assets: &'a AssetFiles, + locales: &'static [LocaleInfo], + is_translation: bool, +} + +pub struct PageCtx<'a, T: Serialize> { + template_ctx: TemplateCtx<'a, T>, + output_dir: &'a Path, + handlebars: &'a Handlebars<'a>, +} + +impl<'a, T: Serialize> PageCtx<'a, T> { + fn make_landing(mut self) -> Self { + self.template_ctx.is_landing = true; + self + } + + pub fn render>(self, dst_path: P) -> anyhow::Result<()> { + let path = dst_path.as_ref(); + let template = &self.template_ctx.page; + + let out_path = self.output_dir.join(path); + ensure_directory(&out_path)?; + let mut output_file = BufWriter::new( + File::create(&out_path) + .with_context(|| anyhow::anyhow!("Cannot create file at {}", path.display()))?, + ); + eprintln!("Rendering `{template}` into {}", out_path.display()); + + self.handlebars + .render_to_write(template, &self.template_ctx, &mut output_file) + .with_context(|| { + anyhow::anyhow!( + "cannot render template {template} into {}", + out_path.display() + ) + })?; + Ok(()) + } +} + +pub struct RenderCtx<'a> { + pub handlebars: Handlebars<'a>, + pub template_dir: PathBuf, + pub fluent_loader: SimpleLoader, + pub output_dir: PathBuf, + pub rust_version: RustVersion, + pub teams: RustTeams, + pub assets: AssetFiles, +} + +impl<'a> RenderCtx<'a> { + pub fn page( + &'a self, + page: &str, + title_id: &str, + data: &'a T, + lang: &str, + ) -> PageCtx<'a, T> { + let title = if title_id.is_empty() { + "".into() + } else { + let lang = lang.parse().expect("lang should be valid"); + self.fluent_loader.lookup(&lang, title_id, None) + }; + PageCtx { + template_ctx: TemplateCtx { + page: page.to_string(), + title, + parent: LAYOUT, + is_landing: false, + data, + baseurl: baseurl(&lang), + is_translation: lang != "en-US", + lang: lang.to_string(), + pontoon_enabled: PONTOON_ENABLED, + assets: &self.assets, + locales: EXPLICIT_LOCALE_INFO, + }, + output_dir: &self.output_dir, + handlebars: &self.handlebars, + } + } + + pub fn copy_asset_dir>(&self, src_dir: P, dst_dir: P) -> anyhow::Result<()> { + let dst = self.output_dir.join(dst_dir.as_ref()); + println!( + "Copying static asset directory from {} to {}", + src_dir.as_ref().display(), + dst.display() + ); + copy_dir_all(src_dir.as_ref(), dst)?; + Ok(()) + } + + pub fn copy_asset_file>(&self, src: P, dst: P) -> anyhow::Result<()> { + let dst = self.output_dir.join(dst.as_ref()); + println!( + "Copying static asset file from {} to {}", + src.as_ref().display(), + dst.display() + ); + ensure_directory(&dst)?; + std::fs::copy(src.as_ref(), dst)?; + Ok(()) + } +} + +/// Calls `func` for all supported languages. +/// Passes it the destination path into which should a given page be rendered, and the language +/// in which it should be rendered. +pub fn for_all_langs(dst_path: &str, func: F) -> anyhow::Result<()> +where + F: Fn(&str, &str) -> anyhow::Result<()>, +{ + for lang in SUPPORTED_LOCALES.iter() { + let path = match lang { + l if *l == ENGLISH => dst_path.to_string(), + l => format!("{l}/{dst_path}"), + }; + func(&path, lang).with_context(|| anyhow::anyhow!("could not handle language {lang}"))?; + } + Ok(()) +} + +pub fn render_index(render_ctx: &RenderCtx) -> anyhow::Result<()> { + #[derive(Serialize)] + struct IndexData { + rust_version: String, + } + let data = IndexData { + rust_version: render_ctx.rust_version.0.clone(), + }; + for_all_langs("index.html", |path, lang| { + render_ctx + .page("index", "", &data, lang) + .make_landing() + .render(path) + }) +} + +pub fn render_governance(render_ctx: &RenderCtx) -> anyhow::Result<()> { + let data = render_ctx.teams.index_data(); + + for_all_langs("governance/index.html", |dst_path, lang| { + render_ctx + .page("governance/index", "governance-page-title", &data, lang) + .render(dst_path) + })?; + for team in data.teams { + let data: PageData = render_ctx + .teams + .page_data(team.section, &team.page_name) + .unwrap_or_else(|error| panic!("Page data for team {team:?} not found: {error:?}")); + + // We need to render into index.html to have an extensionless URL + for_all_langs( + &format!("governance/{}/index.html", team.url), + |dst_path, lang| { + render_ctx + .page( + "governance/group", + &format!("governance-team-{}-title", team.team.name), + &data, + lang, + ) + .render(dst_path) + }, + )?; + } + + Ok(()) +} + +/// Render all templates found in the given directory. +pub fn render_directory(render_ctx: &RenderCtx, category: &str) -> anyhow::Result<()> { + for dir in std::fs::read_dir(render_ctx.template_dir.join(category))? { + let path = dir?.path(); + if path.is_file() && path.extension() == Some(OsStr::new("hbs")) { + // foo.html.hbs => foo + let subject = path + .file_stem() + .unwrap() + .to_str() + .unwrap() + .split(".") + .next() + .unwrap(); + + // The "root" page of a category + if subject == "index" { + for_all_langs(&format!("{category}/index.html"), |dst_path, lang| { + render_ctx + .page( + &format!("{category}/index"), + &format!("{category}-page-title"), + &(), + lang, + ) + .render(dst_path) + })?; + } else { + // A subpage (subject) of the category + // We need to render the page into a subdirectory, so that /foo/bar works without + // needing a HTML suffix. + for_all_langs( + &format!("{category}/{subject}/index.html"), + |dst_path, lang| { + render_ctx + .page( + &format!("{category}/{subject}"), + &format!("{category}-{subject}-page-title"), + &(), + lang, + ) + .render(dst_path) + }, + )?; + } + } + } + Ok(()) +} + +pub fn render_redirect(render_ctx: &RenderCtx, from: &str, to: &str) -> anyhow::Result<()> { + #[derive(Serialize)] + struct Data { + url: String, + } + + let url = if !to.starts_with("http") { + format!("/{to}") + } else { + to.to_string() + }; + let data = Data { url }; + + let from = if Path::new(from).extension().is_none() { + // We need to add /index.html to make the extensionless URL work + format!("{from}/index.html") + } else { + from.to_string() + }; + + println!("Redirecting {from} to {to}"); + render_ctx + .page("redirect", "", &data, ENGLISH) + .make_landing() + .render(from) +} diff --git a/templates/redirect.html.hbs b/templates/redirect.html.hbs new file mode 100644 index 000000000..5f6b3b126 --- /dev/null +++ b/templates/redirect.html.hbs @@ -0,0 +1,6 @@ + + + + Please go to {{ data.url }} + + From b51ddd7ed0715e32e4bffb0be5b2065f42f8a5e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 14:01:17 +0200 Subject: [PATCH 06/19] Fill missing `baseurl` prefixes in templates --- templates/404.html.hbs | 2 +- templates/community/index.html.hbs | 2 +- templates/components/footer.html.hbs | 8 +++---- templates/components/layout.html.hbs | 22 +++++++++---------- templates/components/nav.html.hbs | 2 +- templates/components/panels/domains.html.hbs | 8 +++---- .../components/what/cli/maintainable.html.hbs | 4 ++-- templates/components/what/cli/pitch.html.hbs | 12 +++++----- .../components/what/cli/production.html.hbs | 4 ++-- .../what/embedded/get-started.html.hbs | 6 ++--- .../components/what/embedded/pitch.html.hbs | 12 +++++----- .../what/embedded/testimonials.html.hbs | 8 +++---- .../components/what/networking/pitch.html.hbs | 6 ++--- .../what/networking/production.html.hbs | 4 ++-- .../components/what/wasm/get-started.html.hbs | 6 ++--- templates/components/what/wasm/pitch.html.hbs | 6 ++--- .../components/what/wasm/production.html.hbs | 6 ++--- templates/learn/get-started.html.hbs | 2 +- templates/learn/index.html.hbs | 6 ++--- 19 files changed, 63 insertions(+), 63 deletions(-) diff --git a/templates/404.html.hbs b/templates/404.html.hbs index e2e252718..eb5174920 100644 --- a/templates/404.html.hbs +++ b/templates/404.html.hbs @@ -7,7 +7,7 @@

{{fluent "error404-subtitle"}}

- {{fluent "error404-img-alt"}} + {{fluent "error404-img-alt"}}
diff --git a/templates/community/index.html.hbs b/templates/community/index.html.hbs index ef90ebf9c..c58828d43 100644 --- a/templates/community/index.html.hbs +++ b/templates/community/index.html.hbs @@ -170,7 +170,7 @@ - {{fluent + {{fluent
diff --git a/templates/components/footer.html.hbs b/templates/components/footer.html.hbs index 38f1ac9cf..32006872a 100644 --- a/templates/components/footer.html.hbs +++ b/templates/components/footer.html.hbs @@ -33,13 +33,13 @@

{{fluent "footer-social"}}

- {{fluent {{fluent + src="{{baseurl}}/static/images/bluesky.svg" alt="{{fluent "bluesky"}}" title="{{fluent "bluesky"}}" /> {{fluent - github logo + github logo
diff --git a/templates/components/layout.html.hbs b/templates/components/layout.html.hbs index a85ebcab4..ac3144b25 100644 --- a/templates/components/layout.html.hbs +++ b/templates/components/layout.html.hbs @@ -28,20 +28,20 @@ - + - - - - - - + + + + + + - + {{#if is_landing}} @@ -54,8 +54,8 @@ - - + + {{> components/nav}} @@ -66,6 +66,6 @@ {{#if pontoon_enabled}} {{/if}} - + diff --git a/templates/components/nav.html.hbs b/templates/components/nav.html.hbs index e8311d871..d3440c7fa 100644 --- a/templates/components/nav.html.hbs +++ b/templates/components/nav.html.hbs @@ -1,7 +1,7 @@
{{/inline}} diff --git a/templates/learn/index.html.hbs b/templates/learn/index.html.hbs index 75dc864df..611b81cf4 100644 --- a/templates/learn/index.html.hbs +++ b/templates/learn/index.html.hbs @@ -154,7 +154,7 @@
- {{fluent
@@ -168,7 +168,7 @@
- {{fluent
@@ -184,7 +184,7 @@
- {{fluent
From b5c7db8f93d77e77f872b434fa7a4a7fe1f9b806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 14:01:54 +0200 Subject: [PATCH 07/19] Handle base URL in fonts and allow changing it --- src/assets.rs | 27 +++++++++++++++++---------- src/i18n.rs | 3 ++- src/main.rs | 33 ++++++++++++++++++++++++++------- src/render.rs | 7 ++++--- src/styles/fonts.scss | 2 +- static/scripts/languages.js | 1 + 6 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index f486d5ff3..3222e6a5a 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -1,3 +1,4 @@ +use crate::BaseUrl; use crate::fs::ensure_directory; use anyhow::Context; use sass_rs::{Options, compile_file}; @@ -22,7 +23,12 @@ fn relative_url(path: &Path, out_dir: &Path) -> anyhow::Result { } /// Compiles SASS file, stores it in `out_dir` and returns the relative URL to it. -fn compile_sass(root_dir: &Path, out_dir: &Path, filename: &str) -> anyhow::Result { +fn compile_sass( + root_dir: &Path, + out_dir: &Path, + filename: &str, + base_url: &str, +) -> anyhow::Result { let scss_file = root_dir .join("src") .join("styles") @@ -31,6 +37,7 @@ fn compile_sass(root_dir: &Path, out_dir: &Path, filename: &str) -> anyhow::Resu let css = compile_file(&scss_file, Options::default()) .map_err(|e| anyhow::anyhow!("{e}")) .with_context(|| anyhow::anyhow!("couldn't compile sass: {}", scss_file.display()))?; + let css = css.replace("$BASEURL", base_url); let css_sha = format!("{filename}_{}", hash_string(&css)); let out_css_path = out_dir @@ -41,7 +48,7 @@ fn compile_sass(root_dir: &Path, out_dir: &Path, filename: &str) -> anyhow::Resu write_file(&out_css_path, &css.into_bytes()) .with_context(|| anyhow::anyhow!("couldn't write css file: {}", out_css_path.display()))?; - Ok(relative_url(&out_css_path, &out_dir)?) + relative_url(&out_css_path, out_dir) } fn concat_files( @@ -71,7 +78,7 @@ fn concat_files( write_file(Path::new(&out_file_path), concatted.as_bytes()) .with_context(|| anyhow::anyhow!("couldn't write vendor {extension}"))?; - Ok(relative_url(&out_file_path, &out_dir)?) + relative_url(&out_file_path, out_dir) } fn concat_vendor_css(root_dir: &Path, out_dir: &Path, files: Vec<&str>) -> anyhow::Result { @@ -105,21 +112,21 @@ pub struct AssetFiles { pub fn compile_assets( root_dir: &Path, out_dir: &Path, - baseurl: &str, + base_url: &str, ) -> anyhow::Result { - let app_css_file = compile_sass(root_dir, out_dir, "app")?; - let fonts_css_file = compile_sass(root_dir, out_dir, "fonts")?; + let app_css_file = compile_sass(root_dir, out_dir, "app", base_url)?; + let fonts_css_file = compile_sass(root_dir, out_dir, "fonts", base_url)?; let vendor_css_file = concat_vendor_css(root_dir, out_dir, vec!["tachyons"])?; let app_js_file = concat_app_js(root_dir, out_dir, vec!["tools-install"])?; Ok(AssetFiles { css: CSSFiles { - app: format!("{baseurl}{app_css_file}"), - fonts: format!("{baseurl}{fonts_css_file}"), - vendor: format!("{baseurl}{vendor_css_file}"), + app: format!("{base_url}/{app_css_file}"), + fonts: format!("{base_url}/{fonts_css_file}"), + vendor: format!("{base_url}/{vendor_css_file}"), }, js: JSFiles { - app: format!("{baseurl}{app_js_file}"), + app: format!("{base_url}/{app_js_file}"), }, }) } diff --git a/src/i18n.rs b/src/i18n.rs index c29f84540..b868201f4 100644 --- a/src/i18n.rs +++ b/src/i18n.rs @@ -5,6 +5,7 @@ use handlebars::{ use serde::Serialize; use std::{collections::HashSet, sync::LazyLock}; +use crate::ENGLISH; use handlebars_fluent::{ fluent_bundle::{FluentResource, FluentValue, concurrent::FluentBundle}, loader::SimpleLoader, @@ -215,7 +216,7 @@ impl HelperDef for TeamHelper { let team_name = team.as_json()["name"].as_str().unwrap(); // English uses the team data directly, so that it gets autoupdated - if lang == "en-US" { + if lang == ENGLISH { let english = param.english(team.as_json()); out.write(english) .map_err(|e| RenderErrorReason::NestedError(Box::new(e)))?; diff --git a/src/main.rs b/src/main.rs index 1f43357df..f6594c5c8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ +#![allow(unused)] + use crate::assets::compile_assets; use crate::i18n::{TeamHelper, create_loader}; use crate::redirect::create_redirects; use crate::render::{RenderCtx, render_directory, render_governance, render_index}; -use crate::rust_version::RustVersion; +use crate::rust_version::fetch_rust_version; use crate::teams::{encode_zulip_stream, load_rust_teams}; use anyhow::Context; use handlebars::{DirectorySourceOptions, Handlebars}; @@ -24,11 +26,24 @@ const ZULIP_DOMAIN: &str = "https://rust-lang.zulipchat.com"; static LAYOUT: &str = "components/layout"; static ENGLISH: &str = "en-US"; -fn baseurl(lang: &str) -> String { - if lang == "en-US" { - String::new() - } else { - format!("/{lang}") +/// Relative base url from the root of the website +/// `url` can be e.g. `` or `/foo-bar`. +struct BaseUrl { + url: String, +} + +impl BaseUrl { + fn new(url: &str) -> Self { + let url = url.strip_suffix('/').unwrap_or(url).to_string(); + Self { url } + } + + fn resolve(&self, lang: &str) -> String { + if lang == ENGLISH { + self.url.clone() + } else { + format!("{}/{lang}", self.url) + } } } @@ -52,6 +67,9 @@ fn setup_handlebars() -> anyhow::Result> { #[tokio::main] async fn main() -> anyhow::Result<()> { + let base_url = std::env::var("BASE_URL").unwrap_or_else(|_| "".to_string()); + let base_url = BaseUrl::new(&base_url); + let rust_version = fetch_rust_version().await?; let teams = load_rust_teams().await?; @@ -61,7 +79,7 @@ async fn main() -> anyhow::Result<()> { std::fs::create_dir_all(&output_dir)?; let root_dir = Path::new("."); - let assets = compile_assets(root_dir, &output_dir, "/")?; + let assets = compile_assets(root_dir, &output_dir, &base_url.resolve(ENGLISH))?; let handlebars = setup_handlebars()?; let ctx = RenderCtx { @@ -72,6 +90,7 @@ async fn main() -> anyhow::Result<()> { teams, handlebars, output_dir, + base_url, }; ctx.copy_asset_dir("static", "static")?; ctx.copy_asset_file( diff --git a/src/render.rs b/src/render.rs index 0ee8d8568..1f7114ca7 100644 --- a/src/render.rs +++ b/src/render.rs @@ -3,7 +3,7 @@ use crate::fs::{copy_dir_all, ensure_directory}; use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES}; use crate::rust_version::RustVersion; use crate::teams::{PageData, RustTeams}; -use crate::{ENGLISH, LAYOUT, PONTOON_ENABLED, baseurl}; +use crate::{BaseUrl, ENGLISH, LAYOUT, PONTOON_ENABLED}; use anyhow::Context; use handlebars::Handlebars; use handlebars_fluent::{Loader, SimpleLoader}; @@ -72,6 +72,7 @@ pub struct RenderCtx<'a> { pub rust_version: RustVersion, pub teams: RustTeams, pub assets: AssetFiles, + pub base_url: BaseUrl, } impl<'a> RenderCtx<'a> { @@ -95,8 +96,8 @@ impl<'a> RenderCtx<'a> { parent: LAYOUT, is_landing: false, data, - baseurl: baseurl(&lang), - is_translation: lang != "en-US", + baseurl: self.base_url.resolve(lang), + is_translation: lang != ENGLISH, lang: lang.to_string(), pontoon_enabled: PONTOON_ENABLED, assets: &self.assets, diff --git a/src/styles/fonts.scss b/src/styles/fonts.scss index 0b940d2f7..f73e4a511 100644 --- a/src/styles/fonts.scss +++ b/src/styles/fonts.scss @@ -119,7 +119,7 @@ $format-names: ( @function urls($filename, $range, $extensions) { $urls: (); @each $extension in $extensions { - $url: url("/static/fonts/#{$extension}/#{$filename}.#{$range}.#{$extension}"); + $url: url("$BASEURL/static/fonts/#{$extension}/#{$filename}.#{$range}.#{$extension}"); $format: format(map-get($format-names, $extension)); $urls: append($urls, $url $format, comma); diff --git a/static/scripts/languages.js b/static/scripts/languages.js index bcacd4391..b755a1127 100644 --- a/static/scripts/languages.js +++ b/static/scripts/languages.js @@ -21,3 +21,4 @@ function langChange() { nav_dropdown.onchange = langChange; footer_dropdown.onchange = langChange; +// TODO: language redirect From 667e8d771f5e22893d75de59ec58a43fde8d786f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 14:02:51 +0200 Subject: [PATCH 08/19] Add CI pipeline --- .github/workflows/main.yml | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index eb61fe8a5..d490bbe7d 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,5 +1,5 @@ name: CI -on: [push, pull_request] +on: [ push, pull_request ] env: RUST_BACKTRACE: 1 jobs: @@ -12,8 +12,7 @@ jobs: with: components: rustfmt - - name: Formatting - run: cargo fmt --all -- --check + - uses: Swatinem/rust-cache@v2 - name: Test run: | @@ -22,3 +21,33 @@ jobs: cargo build --all --locked cargo clippy -- --deny warnings cargo test --all --locked + + - name: Formatting + run: cargo fmt --all -- --check + + - name: Build website + run: cargo run + env: + BASE_URL: "/www.rust-lang.org" + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Upload website + uses: actions/upload-pages-artifact@v3 + with: + path: html + + deploy: + needs: [ build ] + if: github.ref == 'refs/heads/master' + environment: + name: github-pages + permissions: + contents: read + pages: write + id-token: write + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + uses: actions/deploy-pages@v4 From 1df6b4110bf15629d7c58c718262eeb95d73657d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 6 Aug 2025 14:05:23 +0200 Subject: [PATCH 09/19] Fix baseurl --- templates/governance/index.html.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/governance/index.html.hbs b/templates/governance/index.html.hbs index 82492294e..c8ca3293e 100644 --- a/templates/governance/index.html.hbs +++ b/templates/governance/index.html.hbs @@ -31,7 +31,7 @@
{{#each data.teams as |team| ~}} - {{> governance/index-team team=team baseurl=baseurl}} + {{> governance/index-team team=team baseurl=../baseurl}} {{/each~}}
From 543d130fa8ec48fb23c2a8c76b8651587f3a3185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:43:45 +0200 Subject: [PATCH 10/19] Remove async and tokio --- Cargo.lock | 1259 +++++++------------------------------------ Cargo.toml | 3 +- src/main.rs | 7 +- src/rust_version.rs | 17 +- src/teams.rs | 18 +- 5 files changed, 224 insertions(+), 1080 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c91e9a2dd..6e5f26741 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,20 +2,11 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "anyhow" @@ -23,45 +14,12 @@ version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" -[[package]] -name = "atomic-waker" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" - -[[package]] -name = "autocfg" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" - -[[package]] -name = "backtrace" -version = "0.3.74" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - [[package]] name = "block-buffer" version = "0.10.4" @@ -71,12 +29,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "bumpalo" -version = "3.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" - [[package]] name = "bytes" version = "1.10.1" @@ -99,20 +51,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "core-foundation" -version = "0.9.4" +name = "cookie" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" dependencies = [ - "core-foundation-sys", - "libc", + "percent-encoding", + "time", + "version_check", ] [[package]] -name = "core-foundation-sys" -version = "0.8.7" +name = "cookie_store" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +checksum = "2eac901828f88a5241ee0600950ab981148a18f2f756900ffba1b125ca6a3ef9" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] [[package]] name = "cpufeatures" @@ -123,6 +88,15 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -230,12 +204,12 @@ dependencies = [ ] [[package]] -name = "encoding_rs" -version = "0.8.35" +name = "document-features" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" dependencies = [ - "cfg-if", + "litrs", ] [[package]] @@ -245,21 +219,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "errno" -version = "0.3.11" +name = "flate2" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" dependencies = [ - "libc", - "windows-sys 0.59.0", + "crc32fast", + "miniz_oxide", ] -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - [[package]] name = "fluent" version = "0.16.1" @@ -336,21 +304,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[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 = "form_urlencoded" version = "1.2.1" @@ -360,45 +313,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "futures-channel" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" -dependencies = [ - "futures-core", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-sink" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -411,50 +325,13 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.3.2" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", -] - -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "h2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75249d144030531f8dee69fe9cea04d3edf809a017ae445e2abdff6629e86633" -dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", + "wasi", ] [[package]] @@ -513,158 +390,43 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" -dependencies = [ - "bytes", - "http", -] - -[[package]] -name = "http-body-util" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" -dependencies = [ - "bytes", - "futures-core", - "http", - "http-body", - "pin-project-lite", -] - [[package]] name = "httparse" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" -[[package]] -name = "hyper" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "itoa", - "pin-project-lite", - "smallvec", - "tokio", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.27.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" -dependencies = [ - "futures-util", - "http", - "hyper", - "hyper-util", - "rustls", - "rustls-pki-types", - "tokio", - "tokio-rustls", - "tower-service", -] - -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes", - "http-body-util", - "hyper", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "http", - "http-body", - "hyper", - "libc", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", -] - [[package]] name = "icu_collections" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" dependencies = [ "displaydoc", + "potential_utf", "yoke", "zerofrom", "zerovec", ] [[package]] -name = "icu_locid" -version = "1.5.0" +name = "icu_locale_core" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" dependencies = [ "displaydoc", "litemap", - "tinystr", + "tinystr 0.8.1", "writeable", "zerovec", ] -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider", - "tinystr", - "zerovec", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - [[package]] name = "icu_normalizer" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" dependencies = [ "displaydoc", "icu_collections", @@ -672,67 +434,54 @@ dependencies = [ "icu_properties", "icu_provider", "smallvec", - "utf16_iter", - "utf8_iter", - "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" -version = "1.5.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" +checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" [[package]] name = "icu_properties" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" dependencies = [ "displaydoc", "icu_collections", - "icu_locid_transform", + "icu_locale_core", "icu_properties_data", "icu_provider", - "tinystr", + "potential_utf", + "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "1.5.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" +checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" [[package]] name = "icu_provider" -version = "1.5.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" dependencies = [ "displaydoc", - "icu_locid", - "icu_provider_macros", + "icu_locale_core", "stable_deref_trait", - "tinystr", + "tinystr 0.8.1", "writeable", "yoke", "zerofrom", + "zerotrie", "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "ident_case" version = "1.0.1" @@ -752,9 +501,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -790,39 +539,12 @@ dependencies = [ "unic-langid", ] -[[package]] -name = "io-uring" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" -dependencies = [ - "bitflags", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" - [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -835,27 +557,17 @@ version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" -[[package]] -name = "linux-raw-sys" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" - [[package]] name = "litemap" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" [[package]] -name = "lock_api" -version = "0.4.12" +name = "litrs" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" [[package]] name = "log" @@ -869,49 +581,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "miniz_oxide" -version = "0.8.8" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be647b768db090acb35d5ec5db2b0e1f1de11133ca123b9eacf5137868f892a" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", ] -[[package]] -name = "mio" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" -dependencies = [ - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", -] - -[[package]] -name = "native-tls" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" -dependencies = [ - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - [[package]] name = "num-conv" version = "0.1.0" @@ -943,15 +621,6 @@ dependencies = [ "libc", ] -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -959,94 +628,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] -name = "openssl" -version = "0.10.72" +name = "percent-encoding" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] -name = "openssl-macros" -version = "0.1.1" +name = "pest" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "memchr", + "thiserror 2.0.12", + "ucd-trie", ] [[package]] -name = "openssl-probe" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" - -[[package]] -name = "openssl-sys" -version = "0.9.107" +name = "pest_derive" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8288979acd84749c744a9014b4382d42b8f7b2592847b5afb2ed29e5d16ede07" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets 0.52.6", -] - -[[package]] -name = "percent-encoding" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "pest" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "198db74531d58c70a361c42201efde7e2591e976d518caf7662a47dc5720e7b6" -dependencies = [ - "memchr", - "thiserror 2.0.12", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" +checksum = "d725d9cfd79e87dccc9341a2ef39d1b6f6353d68c4b33c177febbe1a402c97c5" dependencies = [ "pest", "pest_generator", @@ -1076,24 +678,21 @@ dependencies = [ "sha2", ] -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - [[package]] name = "pkg-config" version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "potential_utf" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +dependencies = [ + "zerovec", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1124,65 +723,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "redox_syscall" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2f103c6d277498fbceb16e84d317e2a400f160f46904d5f5410848c829511a3" -dependencies = [ - "bitflags", -] - -[[package]] -name = "reqwest" -version = "0.12.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" -dependencies = [ - "base64", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "sync_wrapper", - "system-configuration", - "tokio", - "tokio-native-tls", - "tower", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows-registry", -] - [[package]] name = "ring" version = "0.17.14" @@ -1191,7 +731,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.15", + "getrandom", "libc", "untrusted", "windows-sys 0.52.0", @@ -1206,12 +746,6 @@ dependencies = [ "serde", ] -[[package]] -name = "rustc-demangle" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" - [[package]] name = "rustc-hash" version = "1.1.0" @@ -1224,26 +758,15 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustix" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97817398dd4bb2e6da002002db259209759911da105da92bec29ccb12cf58bf" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys", - "windows-sys 0.59.0", -] - [[package]] name = "rustls" -version = "0.23.26" +version = "0.23.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df51b5869f3a441595eac5e8ff14d486ff285f7b8c0df8770e49c3b56351f0f0" +checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" dependencies = [ + "log", "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -1261,27 +784,24 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] [[package]] name = "rustls-webpki" -version = "0.103.1" +version = "0.103.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" +checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" dependencies = [ "ring", "rustls-pki-types", "untrusted", ] -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - [[package]] name = "ryu" version = "1.0.20" @@ -1319,44 +839,6 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "schannel" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "self_cell" version = "0.10.3" @@ -1413,18 +895,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha2" version = "0.10.8" @@ -1442,40 +912,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook-registry" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" -dependencies = [ - "libc", -] - -[[package]] -name = "slab" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] - [[package]] name = "smallvec" version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" -[[package]] -name = "socket2" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" @@ -1505,60 +947,17 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sync_wrapper" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" -dependencies = [ - "futures-core", -] - [[package]] name = "synstructure" -version = "0.13.1" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "tempfile" -version = "3.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" -dependencies = [ - "fastrand", - "getrandom 0.3.2", - "once_cell", - "rustix", - "windows-sys 0.59.0", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -1606,6 +1005,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" dependencies = [ "deranged", + "itoa", "num-conv", "powerfmt", "serde", @@ -1636,71 +1036,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", - "zerovec", -] - -[[package]] -name = "tokio" -version = "1.46.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17" -dependencies = [ - "backtrace", - "bytes", - "io-uring", - "libc", - "mio", - "parking_lot", - "pin-project-lite", - "signal-hook-registry", - "slab", - "socket2", - "tokio-macros", - "windows-sys 0.52.0", -] - -[[package]] -name = "tokio-macros" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tokio-native-tls" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" -dependencies = [ - "native-tls", - "tokio", -] - -[[package]] -name = "tokio-rustls" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" -dependencies = [ - "rustls", - "tokio", ] [[package]] -name = "tokio-util" -version = "0.7.14" +name = "tinystr" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9590b93e6fcc1739458317cccd391ad3955e2bde8913edf6f95f9e65a8f034" +checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", + "displaydoc", + "zerovec", ] [[package]] @@ -1744,58 +1089,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" -[[package]] -name = "tower" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" -dependencies = [ - "futures-core", - "futures-util", - "pin-project-lite", - "sync_wrapper", - "tokio", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-layer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" - -[[package]] -name = "tower-service" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", -] - -[[package]] -name = "try-lock" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" - [[package]] name = "type-map" version = "0.5.0" @@ -1833,7 +1126,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" dependencies = [ - "tinystr", + "tinystr 0.7.6", ] [[package]] @@ -1843,7 +1136,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e" dependencies = [ "proc-macro-hack", - "tinystr", + "tinystr 0.7.6", "unic-langid-impl", "unic-langid-macros-impl", ] @@ -1872,6 +1165,39 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +[[package]] +name = "ureq" +version = "3.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0fde9bc91026e381155f8c67cb354bcd35260b2f4a29bcc84639f762760c39" +dependencies = [ + "base64", + "cookie_store", + "flate2", + "log", + "percent-encoding", + "rustls", + "rustls-pemfile", + "rustls-pki-types", + "serde", + "serde_json", + "ureq-proto", + "utf-8", + "webpki-roots 0.26.11", +] + +[[package]] +name = "ureq-proto" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59db78ad1923f2b1be62b6da81fe80b173605ca0d57f85da2e005382adf693f7" +dependencies = [ + "base64", + "http", + "httparse", + "log", +] + [[package]] name = "url" version = "2.5.4" @@ -1884,10 +1210,10 @@ dependencies = [ ] [[package]] -name = "utf16_iter" -version = "1.0.5" +name = "utf-8" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] name = "utf8_iter" @@ -1895,12 +1221,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.5" @@ -1917,109 +1237,28 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "want" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" -dependencies = [ - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.50" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" -dependencies = [ - "cfg-if", - "js-sys", - "once_cell", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" +name = "webpki-roots" +version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", + "webpki-roots 1.0.2", ] [[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "web-sys" -version = "0.3.77" +name = "webpki-roots" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "7e8983c3ab33d6fb807cfcdad2491c4ea8cbc8ed839181c7dfd9c67c83e261b2" dependencies = [ - "js-sys", - "wasm-bindgen", + "rustls-pki-types", ] [[package]] @@ -2031,48 +1270,13 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "windows-link" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" - -[[package]] -name = "windows-registry" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" -dependencies = [ - "windows-result", - "windows-strings", - "windows-targets 0.53.0", -] - -[[package]] -name = "windows-result" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" -dependencies = [ - "windows-link", -] - -[[package]] -name = "windows-strings" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" -dependencies = [ - "windows-link", -] - [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2081,7 +1285,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -2090,30 +1294,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" -dependencies = [ - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -2122,96 +1310,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" - [[package]] name = "winnow" version = "0.7.6" @@ -2221,26 +1361,11 @@ dependencies = [ "memchr", ] -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - [[package]] name = "writeable" -version = "0.5.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" [[package]] name = "www-rust-lang-org" @@ -2250,21 +1375,20 @@ dependencies = [ "handlebars", "handlebars-fluent", "percent-encoding", - "reqwest", "rust_team_data", "sass-rs", "serde", "serde_json", "time", - "tokio", "toml", + "ureq", ] [[package]] name = "yoke" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" dependencies = [ "serde", "stable_deref_trait", @@ -2274,9 +1398,9 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.5" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" dependencies = [ "proc-macro2", "quote", @@ -2311,11 +1435,22 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +[[package]] +name = "zerotrie" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + [[package]] name = "zerovec" -version = "0.10.4" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +checksum = "e7aa2bd55086f1ab526693ecbe444205da57e25f4489879da80635a46d90e73b" dependencies = [ "yoke", "zerofrom", @@ -2324,9 +1459,9 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index b5f98900c..672e17569 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,12 +6,11 @@ edition = "2024" [dependencies] anyhow = "1" -tokio = { version = "1", features = ["full"] } handlebars = { version = "6", features = ["dir_source"] } handlebars-fluent = "0.5" serde = { version = "1.0", features = ["derive"] } sass-rs = "0.2.1" -reqwest = { version = "0.12.15", features = ["json"] } +ureq = { version = "3", features = ["json"] } toml = "0.8" serde_json = "1.0" rust_team_data = { git = "https://github.com/rust-lang/team" } diff --git a/src/main.rs b/src/main.rs index f6594c5c8..b5e900214 100644 --- a/src/main.rs +++ b/src/main.rs @@ -65,13 +65,12 @@ fn setup_handlebars() -> anyhow::Result> { Ok(handlebars) } -#[tokio::main] -async fn main() -> anyhow::Result<()> { +fn main() -> anyhow::Result<()> { let base_url = std::env::var("BASE_URL").unwrap_or_else(|_| "".to_string()); let base_url = BaseUrl::new(&base_url); - let rust_version = fetch_rust_version().await?; - let teams = load_rust_teams().await?; + let rust_version = fetch_rust_version()?; + let teams = load_rust_teams()?; // Prepare build directory let output_dir = PathBuf::from("html"); diff --git a/src/rust_version.rs b/src/rust_version.rs index a805497d7..299c9ae9c 100644 --- a/src/rust_version.rs +++ b/src/rust_version.rs @@ -4,13 +4,18 @@ static MANIFEST_URL: &str = "https://static.rust-lang.org/dist/channel-rust-stab pub struct RustVersion(pub String); /// Fetch the latest stable version of Rust. -pub async fn fetch_rust_version() -> anyhow::Result { +pub fn fetch_rust_version() -> anyhow::Result { println!("Downloading Rust version"); - let manifest = reqwest::get(MANIFEST_URL) - .await? - .text() - .await? - .parse::()?; + let mut response = ureq::get(MANIFEST_URL).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Failed to download Rust version (HTTP status {}): {}", + response.status(), + response.body_mut().read_to_string()? + )); + } + + let manifest: toml::Value = toml::from_str(&response.body_mut().read_to_string()?)?; let rust_version = manifest["pkg"]["rust"]["version"].as_str().unwrap(); let version: String = rust_version.split(' ').next().unwrap().to_owned(); Ok(RustVersion(version)) diff --git a/src/teams.rs b/src/teams.rs index 7a7f79bf5..853732fb6 100644 --- a/src/teams.rs +++ b/src/teams.rs @@ -214,13 +214,19 @@ pub struct PageData { other_teams: Vec, } -pub async fn load_rust_teams() -> anyhow::Result { +pub fn load_rust_teams() -> anyhow::Result { println!("Downloading Team API data"); - let resp: Teams = reqwest::get(format!("{BASE_URL}/teams.json")) - .await? - .error_for_status()? - .json() - .await?; + + let mut response = ureq::get(format!("{BASE_URL}/teams.json")).call()?; + if !response.status().is_success() { + return Err(anyhow::anyhow!( + "Failed to download team API (HTTP status {}): {}", + response.status(), + response.body_mut().read_to_string()? + )); + } + + let resp: Teams = response.body_mut().read_json()?; Ok(RustTeams(resp.teams.into_values().collect())) } From 43cafbc7789a1deab59ac1172b5317e6b25d4034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:44:09 +0200 Subject: [PATCH 11/19] Remove unused file --- src/headers.rs | 46 ---------------------------------------------- 1 file changed, 46 deletions(-) delete mode 100644 src/headers.rs diff --git a/src/headers.rs b/src/headers.rs deleted file mode 100644 index 79e2e38ee..000000000 --- a/src/headers.rs +++ /dev/null @@ -1,46 +0,0 @@ -use rocket::fairing::{Fairing, Info, Kind}; -use rocket::http::{ContentType, Header}; -use rocket::{Request, Response}; - -static HEADERS: &[(&str, &str)] = &[ - ("x-xss-protection", "1; mode=block"), - ("strict-transport-security", "max-age=63072000"), - ("x-content-type-options", "nosniff"), - ( - "referrer-policy", - "no-referrer, strict-origin-when-cross-origin", - ), -]; - -static HEADER_CSP_NORMAL: &str = "default-src 'self'; frame-ancestors 'self'; img-src 'self' avatars.githubusercontent.com; frame-src 'self' player.vimeo.com"; -static HEADER_CSP_SVG: &str = - "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'none'"; -static HEADER_CSP_PONTOON: &str = "default-src 'self' pontoon.rust-lang.org pontoon.mozilla.org; frame-ancestors 'self' pontoon.rust-lang.org; img-src 'self' avatars.githubusercontent.com pontoon.rust-lang.org pontoon.mozilla.org; frame-src 'self' pontoon.rust-lang.org player.vimeo.com"; - -pub(crate) struct InjectHeaders; - -#[rocket::async_trait] -impl Fairing for InjectHeaders { - fn info(&self) -> Info { - Info { - name: "HTTP headers injector", - kind: Kind::Response, - } - } - - async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mut Response<'r>) { - for (key, value) in HEADERS { - response.set_header(Header::new(*key, *value)); - } - let csp = if response.content_type() == Some(ContentType::SVG) { - // SVGs adhere to Content Security Policy, and they often include inline styles. - // This uses a custom CSP when the Content-Type is SVG. - HEADER_CSP_SVG - } else if *super::PONTOON_ENABLED { - HEADER_CSP_PONTOON - } else { - HEADER_CSP_NORMAL - }; - response.set_header(Header::new("content-security-policy", csp)); - } -} From 89329d451ccdb68ab257116ab819bbc0310c4610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:44:34 +0200 Subject: [PATCH 12/19] Remove Pontoon --- src/main.rs | 2 -- src/render.rs | 4 +--- templates/components/layout.html.hbs | 3 --- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/main.rs b/src/main.rs index b5e900214..710036072 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,8 +19,6 @@ mod render; mod rust_version; mod teams; -static PONTOON_ENABLED: bool = false; - const ZULIP_DOMAIN: &str = "https://rust-lang.zulipchat.com"; static LAYOUT: &str = "components/layout"; diff --git a/src/render.rs b/src/render.rs index 1f7114ca7..c33fc0bbb 100644 --- a/src/render.rs +++ b/src/render.rs @@ -3,7 +3,7 @@ use crate::fs::{copy_dir_all, ensure_directory}; use crate::i18n::{EXPLICIT_LOCALE_INFO, LocaleInfo, SUPPORTED_LOCALES}; use crate::rust_version::RustVersion; use crate::teams::{PageData, RustTeams}; -use crate::{BaseUrl, ENGLISH, LAYOUT, PONTOON_ENABLED}; +use crate::{BaseUrl, ENGLISH, LAYOUT}; use anyhow::Context; use handlebars::Handlebars; use handlebars_fluent::{Loader, SimpleLoader}; @@ -22,7 +22,6 @@ pub struct TemplateCtx<'a, T: Serialize> { data: &'a T, lang: String, baseurl: String, - pontoon_enabled: bool, assets: &'a AssetFiles, locales: &'static [LocaleInfo], is_translation: bool, @@ -99,7 +98,6 @@ impl<'a> RenderCtx<'a> { baseurl: self.base_url.resolve(lang), is_translation: lang != ENGLISH, lang: lang.to_string(), - pontoon_enabled: PONTOON_ENABLED, assets: &self.assets, locales: EXPLICIT_LOCALE_INFO, }, diff --git a/templates/components/layout.html.hbs b/templates/components/layout.html.hbs index ac3144b25..03237d1ad 100644 --- a/templates/components/layout.html.hbs +++ b/templates/components/layout.html.hbs @@ -63,9 +63,6 @@ {{~> page}} {{> components/footer}} - {{#if pontoon_enabled}} - - {{/if}} From 79932831c573b7402922afb0fde4ae89eeb4f948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:47:46 +0200 Subject: [PATCH 13/19] Revert group-team whitespace changes --- templates/governance/group-team.html.hbs | 170 +++++++++++------------ 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/templates/governance/group-team.html.hbs b/templates/governance/group-team.html.hbs index 3da321283..e8599b954 100644 --- a/templates/governance/group-team.html.hbs +++ b/templates/governance/group-team.html.hbs @@ -1,106 +1,106 @@
-
- -

{{team-text team name}}

-
-
-
-
-
-

{{team-text team description}}

- +
+ +

{{team-text team name}}

+
+
+
+ -
- {{#if team.members}} + {{#if team.members}}
-

{{fluent "governance-members-header"}}

+

{{fluent "governance-members-header"}}

- {{#each team.members as |member|}} + {{#each team.members as |member|}}
- - {{member.name}} - -
-

{{member.name}}

-
- {{#fluent "governance-user-github"}} - {{#fluentparam "link"}} - {{member.github}} - {{/fluentparam}} - {{/fluent}} -
- {{#if member.is_lead}} -
{{fluent "governance-user-team-leader"}}
- {{else}} - {{#if member.roles}} + + {{member.name}} + +
+

{{member.name}}

+
+ {{#fluent "governance-user-github"}} + {{#fluentparam "link"}} + {{member.github}} + {{/fluentparam}} + {{/fluent}} +
+ {{#if member.is_lead}} +
{{fluent "governance-user-team-leader"}}
+ {{else}} + {{#if member.roles}}
{{team-text ../team role (lookup member.roles 0)}}
- {{/if}} - {{/if}} -
+ {{/if}} + {{/if}} +
- {{/each}} + {{/each}}
{{#if team.alumni}} -
+

{{fluent "governance-alumni-header"}}

-
-

{{fluent "governance-alumni-thanks"}}

-
+
+

{{fluent "governance-alumni-thanks"}}

+
{{#each team.alumni as |member|}} -
+
- {{member.name}} + {{member.name}}
- {{member.name}} -
- GitHub: {{member.github}} -
- {{#if member.roles}} + {{member.name}} +
+ GitHub: {{member.github}} +
+ {{#if member.roles}}
{{team-text ../team role (lookup member.roles 0)}}
- {{/if}} + {{/if}}
-
+
{{/each}} -
+
+ {{/if}} {{/if}} - {{/if}}
From 1d3d79ea9ee09468218f510083fb972dc7b32af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:50:36 +0200 Subject: [PATCH 14/19] Change redirection placeholder text --- templates/redirect.html.hbs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/redirect.html.hbs b/templates/redirect.html.hbs index 5f6b3b126..e828aecf3 100644 --- a/templates/redirect.html.hbs +++ b/templates/redirect.html.hbs @@ -1,6 +1,6 @@ - Please go to {{ data.url }} + Redirecting to {{ data.url }}... From 18f21ff69c265d6d09d6f77107b44f25513c4064 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 10:54:33 +0200 Subject: [PATCH 15/19] Implement static file "redirects" --- src/redirect.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/redirect.rs b/src/redirect.rs index c0aba45c3..15e8cc9dd 100644 --- a/src/redirect.rs +++ b/src/redirect.rs @@ -48,11 +48,11 @@ pub static STATIC_FILES_REDIRECTS: &[(&str, &str)] = &[ // Pre-2018 whitepaper locations ( "pdfs/Rust-npm-Whitepaper.pdf", - "/static/pdfs/Rust-npm-Whitepaper.pdf", + "static/pdfs/Rust-npm-Whitepaper.pdf", ), ( "pdfs/Rust-Tilde-Whitepaper.pdf", - "/static/pdfs/Rust-Tilde-Whitepaper.pdf", + "static/pdfs/Rust-Tilde-Whitepaper.pdf", ), ]; @@ -83,9 +83,11 @@ static PRE_2018_LOCALES: &[&str] = &[ pub fn create_redirects(ctx: &RenderCtx) -> anyhow::Result<()> { // Static file redirects, no need to support languages - // for (src, dst) in STATIC_FILES_REDIRECTS { - // render_redirect(ctx, src, dst)?; - // } + // We cannot really make non-HTML redirects easily, so we just duplicate the file contents + // under both paths. + for (src, dst) in STATIC_FILES_REDIRECTS { + ctx.copy_asset_file(dst, src)?; + } // if let Some((_, dest)) = STATIC_FILES_REDIRECTS.iter().find(|(src, _)| src == &path) { // return Some(Redirect::permanent(*dest)); From d6553f7edc69c30ab06598654ffed0a642f0afe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 15 Aug 2025 11:50:44 +0200 Subject: [PATCH 16/19] Use correct base URL for static (untranslated) assets. --- src/main.rs | 8 +++++-- src/render.rs | 8 ++++++- templates/404.html.hbs | 2 +- templates/community/index.html.hbs | 2 +- templates/components/footer.html.hbs | 8 +++---- templates/components/layout.html.hbs | 22 +++++++++---------- templates/components/nav.html.hbs | 2 +- templates/components/panels/domains.html.hbs | 8 +++---- .../components/what/cli/maintainable.html.hbs | 4 ++-- templates/components/what/cli/pitch.html.hbs | 12 +++++----- .../components/what/cli/production.html.hbs | 4 ++-- .../what/embedded/get-started.html.hbs | 6 ++--- .../components/what/embedded/pitch.html.hbs | 12 +++++----- .../what/embedded/testimonials.html.hbs | 8 +++---- .../components/what/networking/pitch.html.hbs | 6 ++--- .../what/networking/production.html.hbs | 4 ++-- .../components/what/wasm/get-started.html.hbs | 6 ++--- templates/components/what/wasm/pitch.html.hbs | 6 ++--- .../components/what/wasm/production.html.hbs | 6 ++--- templates/learn/get-started.html.hbs | 2 +- templates/learn/index.html.hbs | 6 ++--- 21 files changed, 76 insertions(+), 66 deletions(-) diff --git a/src/main.rs b/src/main.rs index 710036072..73cf3d53a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,7 +36,11 @@ impl BaseUrl { Self { url } } - fn resolve(&self, lang: &str) -> String { + fn get(&self) -> &str { + &self.url + } + + fn resolve_translated(&self, lang: &str) -> String { if lang == ENGLISH { self.url.clone() } else { @@ -76,7 +80,7 @@ fn main() -> anyhow::Result<()> { std::fs::create_dir_all(&output_dir)?; let root_dir = Path::new("."); - let assets = compile_assets(root_dir, &output_dir, &base_url.resolve(ENGLISH))?; + let assets = compile_assets(root_dir, &output_dir, &base_url.get())?; let handlebars = setup_handlebars()?; let ctx = RenderCtx { diff --git a/src/render.rs b/src/render.rs index c33fc0bbb..c990eec66 100644 --- a/src/render.rs +++ b/src/render.rs @@ -21,7 +21,12 @@ pub struct TemplateCtx<'a, T: Serialize> { is_landing: bool, data: &'a T, lang: String, + /// Base URL for the current page, e.g. /foo/bar + /// This includes translations, so it can be also /foo/bar/es baseurl: String, + /// Base URL for the current page, e.g. /foo/bar + /// This **does not** include translations, and is used for the <...>/static links. + baseurl_assets: String, assets: &'a AssetFiles, locales: &'static [LocaleInfo], is_translation: bool, @@ -95,7 +100,8 @@ impl<'a> RenderCtx<'a> { parent: LAYOUT, is_landing: false, data, - baseurl: self.base_url.resolve(lang), + baseurl: self.base_url.resolve_translated(lang), + baseurl_assets: self.base_url.get().to_string(), is_translation: lang != ENGLISH, lang: lang.to_string(), assets: &self.assets, diff --git a/templates/404.html.hbs b/templates/404.html.hbs index eb5174920..24285a699 100644 --- a/templates/404.html.hbs +++ b/templates/404.html.hbs @@ -7,7 +7,7 @@

{{fluent "error404-subtitle"}}

- {{fluent "error404-img-alt"}} + {{fluent "error404-img-alt"}}
diff --git a/templates/community/index.html.hbs b/templates/community/index.html.hbs index c58828d43..a802feff8 100644 --- a/templates/community/index.html.hbs +++ b/templates/community/index.html.hbs @@ -170,7 +170,7 @@
- {{fluent + {{fluent
diff --git a/templates/components/footer.html.hbs b/templates/components/footer.html.hbs index 32006872a..dae0ca34e 100644 --- a/templates/components/footer.html.hbs +++ b/templates/components/footer.html.hbs @@ -33,13 +33,13 @@

{{fluent "footer-social"}}

- {{fluent {{fluent + src="{{baseurl_assets}}/static/images/bluesky.svg" alt="{{fluent "bluesky"}}" title="{{fluent "bluesky"}}" /> {{fluent - github logo + github logo
diff --git a/templates/components/layout.html.hbs b/templates/components/layout.html.hbs index 03237d1ad..05f4ca036 100644 --- a/templates/components/layout.html.hbs +++ b/templates/components/layout.html.hbs @@ -28,20 +28,20 @@ - + - - - - - - + + + + + + - + {{#if is_landing}} @@ -54,8 +54,8 @@ - - + + {{> components/nav}} @@ -63,6 +63,6 @@ {{~> page}} {{> components/footer}} - + diff --git a/templates/components/nav.html.hbs b/templates/components/nav.html.hbs index d3440c7fa..5d5df4b5c 100644 --- a/templates/components/nav.html.hbs +++ b/templates/components/nav.html.hbs @@ -1,7 +1,7 @@