diff --git a/.github/workflows/upstream.yml b/.github/workflows/upstream.yml new file mode 100644 index 0000000..5a17061 --- /dev/null +++ b/.github/workflows/upstream.yml @@ -0,0 +1,41 @@ +name: Check for upstream releases + +on: + schedule: + - cron: '00 16 * * *' + workflow_dispatch: {} + +jobs: + check: + name: Check for upstream releases + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Rust toolchain + run: | + rustup toolchain install stable --no-self-update --profile minimal + rustup target add wasm32-unknown-unknown + + - name: Set up Rust cache + uses: swatinem/rust-cache@v2 + with: + cache-on-failure: true + save-if: ${{ github.ref == 'refs/heads/main' }} + + - name: Install Cargo Binary Install + uses: cargo-bins/cargo-binstall@main + + - name: Install crates + run: cargo binstall --force -y dioxus-cli leptosfmt yew-fmt + + - name: Check for upstream releases + run: cargo run -p scripts --bin upstream + env: + GITHUB_ACTOR: ${{ env.GITHUB_ACTOR }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GIT_USER_NAME: github-actions[bot] + GIT_USER_EMAIL: github-actions[bot]@users.noreply.github.com + RUST_LOG: upstream=info diff --git a/Cargo.lock b/Cargo.lock index a5b15f5..bb7f3db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,6 +26,21 @@ dependencies = [ "memchr", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + [[package]] name = "anstream" version = "0.6.18" @@ -62,7 +77,7 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -73,7 +88,7 @@ checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", "once_cell", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -99,6 +114,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" +[[package]] +name = "arc-swap" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" + [[package]] name = "arrayref" version = "0.3.9" @@ -267,6 +288,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "chrono" +version = "0.4.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", +] + [[package]] name = "ciborium" version = "0.2.2" @@ -430,6 +466,22 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + [[package]] name = "core_maths" version = "0.1.1" @@ -552,6 +604,15 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" +[[package]] +name = "deranged" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +dependencies = [ + "powerfmt", +] + [[package]] name = "derive-where" version = "1.4.0" @@ -1010,7 +1071,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -1655,6 +1716,12 @@ version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.3.9" @@ -1692,6 +1759,29 @@ 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 1.3.1", +] + +[[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 1.3.1", + "http-body", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.10.1" @@ -1712,6 +1802,101 @@ dependencies = [ "throw_error", ] +[[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", + "http 1.3.1", + "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 1.3.1", + "hyper", + "hyper-util", + "log", + "rustls", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tower-service", +] + +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "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 1.3.1", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + [[package]] name = "icu_collections" version = "1.5.0" @@ -1899,6 +2084,16 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" +[[package]] +name = "iri-string" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.1" @@ -1964,6 +2159,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "9.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" +dependencies = [ + "base64", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "keyboard-types" version = "0.7.0" @@ -2350,12 +2560,48 @@ 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 = "next_tuple" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -2394,6 +2640,46 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "octocrab" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86996964f8b721067b6ed238aa0ccee56ecad6ee5e714468aa567992d05d2b91" +dependencies = [ + "arc-swap", + "async-trait", + "base64", + "bytes", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "http 1.3.1", + "http-body", + "http-body-util", + "hyper", + "hyper-rustls", + "hyper-timeout", + "hyper-util", + "jsonwebtoken", + "once_cell", + "percent-encoding", + "pin-project", + "secrecy", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "snafu", + "tokio", + "tower", + "tower-http", + "tracing", + "url", + "web-time", +] + [[package]] name = "once_cell" version = "1.21.3" @@ -2465,6 +2751,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" +[[package]] +name = "pem" +version = "3.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38af38e8470ac9dee3ce1bae1af9c1671fffc44ddfd8bd1d0a3445bf349a8ef3" +dependencies = [ + "base64", + "serde", +] + [[package]] name = "percent-encoding" version = "2.3.1" @@ -2541,6 +2837,12 @@ dependencies = [ "portable-atomic", ] +[[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" @@ -2823,6 +3125,20 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "ring" +version = "0.17.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.16", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + [[package]] name = "roxmltree" version = "0.20.0" @@ -2881,7 +3197,54 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730944ca083c1c233a75c09f199e973ca499344a2b7ba9e755c457e86fb4a321" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pki-types" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +dependencies = [ + "zeroize", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4a72fe2bcf7a6ac6fd7d0b9e5cb68aeb7d4c0a0271730218b3e92d43b4eb435" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] @@ -2923,6 +3286,15 @@ dependencies = [ "winapi-util", ] +[[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" @@ -2937,17 +3309,53 @@ dependencies = [ "env_logger", "git2", "log", + "octocrab", "prettyplease", "proc-macro2", "quote", + "regex", "roxmltree", + "semver", "serde", "serde_json", "syn 2.0.101", "tempfile", + "tokio", "usvg", ] +[[package]] +name = "secrecy" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e891af845473308773346dc847b2c23ee78fe442e0472ac50e22a18a93d3ae5a" +dependencies = [ + "zeroize", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +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 = "semver" version = "1.0.26" @@ -3017,6 +3425,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" +dependencies = [ + "itoa", + "serde", +] + [[package]] name = "serde_qs" version = "0.12.0" @@ -3197,6 +3615,27 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "signal-hook-registry" +version = "1.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +dependencies = [ + "libc", +] + +[[package]] +name = "simple_asn1" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 2.0.12", + "time", +] + [[package]] name = "simplecss" version = "0.2.2" @@ -3266,6 +3705,37 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" +[[package]] +name = "snafu" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223891c85e2a29c3fe8fb900c1fae5e69c2e42415e3177752e8718475efa5019" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03c3c6b7927ffe7ecaa769ee0e3994da3b8cafc8f444578982c83ecb161af917" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[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" @@ -3281,6 +3751,12 @@ dependencies = [ "float-cmp", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "svgtypes" version = "0.15.3" @@ -3324,6 +3800,12 @@ dependencies = [ "syn 2.0.101", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" + [[package]] name = "synstructure" version = "0.13.1" @@ -3380,7 +3862,7 @@ dependencies = [ "getrandom 0.3.2", "once_cell", "rustix", - "windows-sys", + "windows-sys 0.59.0", ] [[package]] @@ -3442,6 +3924,37 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "time" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +dependencies = [ + "deranged", + "itoa", + "num-conv", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" + +[[package]] +name = "time-macros" +version = "0.2.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny-skia-path" version = "0.11.4" @@ -3485,7 +3998,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165" dependencies = [ "backtrace", + "bytes", + "libc", + "mio", + "parking_lot", "pin-project-lite", + "signal-hook-registry", + "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 2.0.101", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +dependencies = [ + "rustls", + "tokio", ] [[package]] @@ -3499,6 +4041,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.8.22" @@ -3544,12 +4099,61 @@ dependencies = [ "winnow 0.7.10", ] +[[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", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fdb0c213ca27a9f57ab69ddb290fd80d970922355b83ae380b395d3986b8a2e" +dependencies = [ + "bitflags", + "bytes", + "futures-util", + "http 1.3.1", + "http-body", + "iri-string", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[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 = [ + "log", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -3597,6 +4201,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "ttf-parser" version = "0.25.1" @@ -3704,6 +4314,12 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.4" @@ -3713,6 +4329,7 @@ dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -3803,6 +4420,15 @@ 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 = "warnings" version = "0.2.1" @@ -3934,13 +4560,92 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "winapi-util" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "windows-core" +version = "0.61.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46ec44dc15085cea82cf9c78f85a9114c463a369786585ad2882d1ff0b0acf40" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] + +[[package]] +name = "windows-link" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" + +[[package]] +name = "windows-result" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b895b5356fc36103d0f64dd1e94dfa7ac5633f1c9dd6e80fe9ec4adef69e09d" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7ab927b2637c19b3dbe0965e75d8f2d30bdd697a1516191cad2ec4df8fb28a" +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", ] [[package]] @@ -4178,6 +4883,12 @@ dependencies = [ "synstructure", ] +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" + [[package]] name = "zerovec" version = "0.10.4" diff --git a/scripts/Cargo.toml b/scripts/Cargo.toml index cfcbc9e..63cde68 100644 --- a/scripts/Cargo.toml +++ b/scripts/Cargo.toml @@ -14,12 +14,16 @@ convert_case = "0.8.0" env_logger = "0.11.5" git2 = "0.20.0" log.workspace = true +octocrab = "0.44.1" prettyplease = "0.2.25" proc-macro2 = "1.0.92" quote = "1.0.37" +regex = "1.11.1" roxmltree = "0.20.0" +semver = "1.0.26" serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" tempfile = "3.14.0" +tokio = { version = "1.37.0", features = ["full"] } syn = "2.0.89" usvg = "0.45.0" diff --git a/scripts/src/bin/generate.rs b/scripts/src/bin/generate.rs index e1e76d7..4040946 100644 --- a/scripts/src/bin/generate.rs +++ b/scripts/src/bin/generate.rs @@ -1,272 +1,9 @@ -use std::{collections::HashSet, error::Error, fs, path::Path}; +use std::{env, error::Error}; -use convert_case::{Case, Casing}; -use git2::Repository; -use log::info; -use scripts::{ - framework::Framework, - frameworks::{dioxus::Dioxus, leptos::Leptos, yew::Yew}, - metadata::Metadata, -}; -use tempfile::tempdir; - -const GIT_URL: &str = "https://github.com/lucide-icons/lucide.git"; -const GIT_REF: &str = "0.507.0"; +use scripts::{UPSTREAM_GIT_REF, generate::generate}; fn main() -> Result<(), Box> { env_logger::init(); - let frameworks: [Box; 3] = [Box::new(Dioxus), Box::new(Leptos), Box::new(Yew)]; - - let repository_path = tempdir()?; - let repository_icons_path = repository_path.path().join("icons"); - - info!( - "Cloning \"{}\" ref \"{}\" into \"{}\".", - GIT_URL, - GIT_REF, - repository_path.path().display() - ); - - git_checkout(&repository_path)?; - - info!("Generating icons."); - - let mut paths = vec![]; - for entry in fs::read_dir(repository_icons_path)? { - let path = entry?.path(); - - if !path.is_file() || path.extension().is_none_or(|extension| extension != "svg") { - continue; - } - - let file_path = path.clone(); - let file_stem = file_path - .file_stem() - .expect("File stem should exist.") - .to_string_lossy() - .to_string(); - - paths.push((file_path, file_stem)); - } - - paths.sort_by_key(|(_, file_stem)| file_stem.clone()); - - let mut modules = vec![]; - let mut component_names = vec![]; - let mut metadatas = vec![]; - - for (path, file_stem) in paths { - let file_contents = fs::read_to_string(&path)?; - - let mut metadata_path = path.clone(); - metadata_path.set_extension("json"); - let metadata = serde_json::from_str::(&fs::read_to_string(&metadata_path)?)?; - metadatas.push(metadata.clone()); - - let module = file_stem.to_case(Case::Snake); - modules.push(module.clone()); - - let component_name = file_stem.to_case(Case::Pascal); - component_names.push(component_name.clone()); - - info!("{module} - {component_name}"); - - for framework in &frameworks { - generate_icon( - &**framework, - module.clone(), - component_name.clone(), - file_contents.clone(), - )?; - } - } - - for framework in &frameworks { - generate_lib(&**framework, &modules, &metadatas)?; - generate_example(&**framework, &component_names)?; - generate_features(&**framework, &metadatas)?; - - framework.format( - format!("lucide-{}", framework.name()), - Path::new("packages").join(framework.name()).join("src"), - )?; - - framework.format( - format!("lucide-{}-book", framework.name()), - Path::new("book-examples") - .join(framework.name()) - .join("src"), - )?; - } - - Ok(()) -} - -fn git_checkout>(path: P) -> Result<(), Box> { - let repository = Repository::clone(GIT_URL, path)?; - let (object, reference) = repository.revparse_ext(GIT_REF)?; - - repository.checkout_tree(&object, None)?; - - match reference { - Some(reference) => { - repository.set_head(reference.name().expect("Reference name should exist."))? - } - None => repository.set_head_detached(object.id())?, - } - - Ok(()) -} - -fn generate_icon( - framework: &dyn Framework, - module: String, - component_name: String, - input: String, -) -> Result<(), Box> { - let output_path = Path::new("packages") - .join(framework.name()) - .join("src") - .join(format!("{module}.rs")); - - let output_tokens = framework.generate(component_name, input)?; - let output = prettyplease::unparse(&syn::parse2(output_tokens)?); - - fs::write(output_path, output)?; - - Ok(()) -} - -fn generate_example( - framework: &dyn Framework, - component_names: &[String], -) -> Result<(), Box> { - let output_path = Path::new("book-examples") - .join(framework.name()) - .join("src") - .join("icons.rs"); - - let output_tokens = framework.generate_example(component_names)?; - let output = prettyplease::unparse(&syn::parse2(output_tokens)?); - - fs::write(output_path, output)?; - - Ok(()) -} - -fn generate_lib( - framework: &dyn Framework, - modules: &[String], - metadatas: &[Metadata], -) -> Result<(), Box> { - let attributes = metadatas - .iter() - .map(|metadata| { - let conditions = metadata - .categories - .iter() - .map(|category| format!("feature = \"{category}\"")) - .collect::>(); - - if conditions.len() == 1 { - format!("#[cfg({})]", conditions.join(", ")) - } else { - format!("#[cfg(any({}))]", conditions.join(", ")) - } - }) - .collect::>(); - - let output_path = Path::new("packages") - .join(framework.name()) - .join("src") - .join("lib.rs"); - - let output_modules = modules - .iter() - .zip(&attributes) - .map(|(module, attribute)| { - format!("{attribute}\nmod {};", sanitize_identifier(module.as_str())) - }) - .collect::>() - .join("\n"); - - let output_uses = modules - .iter() - .zip(&attributes) - .map(|(module, attribute)| { - format!( - "{attribute}\npub use {}::*;", - sanitize_identifier(module.as_str()) - ) - }) - .collect::>() - .join("\n"); - - let output = format!( - "{}{}\n\n{}\n", - match framework.lib_header() { - Some(header) => format!("{header}\n\n"), - None => "".into(), - }, - output_modules, - output_uses - ); - - fs::write(output_path, output)?; - - Ok(()) -} - -fn generate_features( - framework: &dyn Framework, - metadatas: &[Metadata], -) -> Result<(), Box> { - let file_path = Path::new("packages") - .join(framework.name()) - .join("Cargo.toml"); - - let mut file_contents = fs::read_to_string(&file_path)?; - - let index = file_contents.find("[features]"); - if let Some(index) = index { - file_contents = file_contents[0..index].to_string(); - } - file_contents = file_contents.trim_end_matches("\n").to_string(); - - let mut features = metadatas - .iter() - .flat_map(|metadata| metadata.categories.clone()) - .collect::>() - .into_iter() - .collect::>(); - features.sort(); - - let output_all_features = features - .iter() - .map(|feature| format!(" \"{feature}\",")) - .collect::>() - .join("\n"); - let output_features = features - .into_iter() - .map(|feature| format!("{feature} = []")) - .collect::>() - .join("\n"); - - let output = format!( - "{file_contents}\n\n[features]\ndefault = []\n{output_features}\nall-icons = [\n{output_all_features}\n]\n" - ); - - fs::write(&file_path, output)?; - - Ok(()) -} - -fn sanitize_identifier(identifier: &str) -> &str { - match identifier { - "box" => "r#box", - "move" => "r#move", - "type" => "r#type", - identifier => identifier, - } + generate(UPSTREAM_GIT_REF, env::current_dir()?.as_path()) } diff --git a/scripts/src/bin/upstream.rs b/scripts/src/bin/upstream.rs new file mode 100644 index 0000000..ef1014d --- /dev/null +++ b/scripts/src/bin/upstream.rs @@ -0,0 +1,81 @@ +use std::{env, error::Error}; + +use log::info; +use scripts::{ + GIT_URL, UPSTREAM_GIT_REF, UPSTREAM_GIT_URL, UPSTREAM_GITHUB_URL, + generate::generate, + repository::{ + git_checkout, git_commit, git_create_branch, git_has_remote_branch, git_push, + git_version_tags, github_create_pull_request, + }, +}; +use semver::Version; +use tempfile::tempdir; + +#[tokio::main] +async fn main() -> Result<(), Box> { + env_logger::init(); + + octocrab::initialise( + octocrab::OctocrabBuilder::new() + .personal_token(env::var("GITHUB_TOKEN")?) + .build()?, + ); + + let upstream_repository_path = tempdir()?; + let upstream_repository = git_checkout( + &upstream_repository_path, + UPSTREAM_GIT_URL, + UPSTREAM_GIT_REF, + )?; + + let current_version = Version::parse(UPSTREAM_GIT_REF.trim_start_matches("v"))?; + let versions = git_version_tags(&upstream_repository)?; + + let index = versions + .iter() + .position(|version| *version == current_version); + + let new_versions = match index { + Some(index) => &versions[(index + 1)..], + None => &versions, + }; + + info!("Current version: {current_version}"); + + if let Some(new_version) = new_versions.iter().next() { + info!("New version: {new_version}"); + + let next_version = new_version.to_string(); + let branch_name = format!("upstream/v{next_version}"); + + let repository_temp_dir = tempdir()?; + let repository_path = repository_temp_dir.path(); + + let repository = git_checkout(repository_path, GIT_URL, "main")?; + + if git_has_remote_branch(&repository, &branch_name) { + info!("Branch {branch_name} already exists."); + return Ok(()); + } + + git_create_branch(&repository, &branch_name)?; + + generate(&next_version, repository_path)?; + + let message = format!("feat: update to upstream v{new_version}"); + git_commit(&repository, &message)?; + + git_push(&repository, &branch_name)?; + + let body = format!( + "Update to upstream [Lucide v{new_version}]({UPSTREAM_GITHUB_URL}/releases/tag/{new_version})." + ); + + github_create_pull_request(&branch_name, &message, &body).await?; + } else { + info!("No new version."); + } + + Ok(()) +} diff --git a/scripts/src/framework.rs b/scripts/src/framework.rs index d62846b..8192f32 100644 --- a/scripts/src/framework.rs +++ b/scripts/src/framework.rs @@ -1,4 +1,7 @@ -use std::{error::Error, path::PathBuf}; +use std::{ + error::Error, + path::{Path, PathBuf}, +}; use proc_macro2::TokenStream; @@ -11,5 +14,10 @@ pub trait Framework { fn generate_example(&self, component_names: &[String]) -> Result>; - fn format(&self, package: String, path: PathBuf) -> Result<(), Box>; + fn format( + &self, + package: String, + repository_path: &Path, + path: PathBuf, + ) -> Result<(), Box>; } diff --git a/scripts/src/frameworks/dioxus.rs b/scripts/src/frameworks/dioxus.rs index 6f0f4d3..f168fba 100644 --- a/scripts/src/frameworks/dioxus.rs +++ b/scripts/src/frameworks/dioxus.rs @@ -1,4 +1,8 @@ -use std::{error::Error, path::PathBuf, process::Command}; +use std::{ + error::Error, + path::{Path, PathBuf}, + process::Command, +}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; @@ -144,7 +148,12 @@ impl Framework for Dioxus { }) } - fn format(&self, package: String, path: PathBuf) -> Result<(), Box> { + fn format( + &self, + package: String, + repository_path: &Path, + path: PathBuf, + ) -> Result<(), Box> { Command::new("dx") .arg("fmt") .current_dir(path) @@ -155,6 +164,7 @@ impl Framework for Dioxus { .arg("fmt") .arg("-p") .arg(&package) + .current_dir(repository_path) .status()? .exit_ok()?; diff --git a/scripts/src/frameworks/leptos.rs b/scripts/src/frameworks/leptos.rs index f1c698d..144dca3 100644 --- a/scripts/src/frameworks/leptos.rs +++ b/scripts/src/frameworks/leptos.rs @@ -1,4 +1,8 @@ -use std::{error::Error, path::PathBuf, process::Command}; +use std::{ + error::Error, + path::{Path, PathBuf}, + process::Command, +}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; @@ -130,17 +134,24 @@ impl Framework for Leptos { }) } - fn format(&self, package: String, path: PathBuf) -> Result<(), Box> { + fn format( + &self, + package: String, + repository_path: &Path, + path: PathBuf, + ) -> Result<(), Box> { Command::new("cargo") .arg("fmt") .arg("-p") .arg(&package) + .current_dir(repository_path) .status()? .exit_ok()?; Command::new("leptosfmt") .arg("--quiet") .arg(path) + .current_dir(repository_path) .status()? .exit_ok()?; diff --git a/scripts/src/frameworks/yew.rs b/scripts/src/frameworks/yew.rs index dbdfcdf..4d449e5 100644 --- a/scripts/src/frameworks/yew.rs +++ b/scripts/src/frameworks/yew.rs @@ -1,4 +1,8 @@ -use std::{error::Error, path::PathBuf, process::Command}; +use std::{ + error::Error, + path::{Path, PathBuf}, + process::Command, +}; use convert_case::{Case, Casing}; use proc_macro2::TokenStream; @@ -148,12 +152,18 @@ impl Framework for Yew { }) } - fn format(&self, package: String, _path: PathBuf) -> Result<(), Box> { + fn format( + &self, + package: String, + repository_path: &Path, + _path: PathBuf, + ) -> Result<(), Box> { Command::new("cargo") .arg("fmt") .arg("-p") .arg(&package) .env("RUSTFMT", "yew-fmt") + .current_dir(repository_path) .status()? .exit_ok()?; @@ -161,6 +171,7 @@ impl Framework for Yew { .arg("fmt") .arg("-p") .arg(&package) + .current_dir(repository_path) .status()? .exit_ok()?; diff --git a/scripts/src/generate.rs b/scripts/src/generate.rs new file mode 100644 index 0000000..6feabd8 --- /dev/null +++ b/scripts/src/generate.rs @@ -0,0 +1,284 @@ +use std::{collections::HashSet, error::Error, fs, path::Path}; + +use convert_case::{Case, Casing}; +use log::info; +use regex::Regex; +use tempfile::tempdir; + +use crate::{ + UPSTREAM_GIT_URL, + framework::Framework, + frameworks::{dioxus::Dioxus, leptos::Leptos, yew::Yew}, + metadata::Metadata, + repository::git_checkout, +}; + +pub fn generate( + upstream_repository_rev: &str, + repository_path: &Path, +) -> Result<(), Box> { + let frameworks: [Box; 3] = [Box::new(Dioxus), Box::new(Leptos), Box::new(Yew)]; + + let upstream_repository_path = tempdir()?; + let repository_icons_path = upstream_repository_path.path().join("icons"); + + git_checkout( + &upstream_repository_path, + UPSTREAM_GIT_URL, + upstream_repository_rev, + )?; + + info!("Generating icons."); + + let mut paths = vec![]; + for entry in fs::read_dir(repository_icons_path)? { + let path = entry?.path(); + + if !path.is_file() || path.extension().is_none_or(|extension| extension != "svg") { + continue; + } + + let file_path = path.clone(); + let file_stem = file_path + .file_stem() + .expect("File stem should exist.") + .to_string_lossy() + .to_string(); + + paths.push((file_path, file_stem)); + } + + paths.sort_by_key(|(_, file_stem)| file_stem.clone()); + + let mut modules = vec![]; + let mut component_names = vec![]; + let mut metadatas = vec![]; + + for (path, file_stem) in paths { + let file_contents = fs::read_to_string(&path)?; + + let mut metadata_path = path.clone(); + metadata_path.set_extension("json"); + let metadata = serde_json::from_str::(&fs::read_to_string(&metadata_path)?)?; + metadatas.push(metadata.clone()); + + let module = file_stem.to_case(Case::Snake); + modules.push(module.clone()); + + let component_name = file_stem.to_case(Case::Pascal); + component_names.push(component_name.clone()); + + info!("{module} - {component_name}"); + + for framework in &frameworks { + generate_icon( + repository_path, + &**framework, + module.clone(), + component_name.clone(), + file_contents.clone(), + )?; + } + } + + for framework in &frameworks { + generate_lib(repository_path, &**framework, &modules, &metadatas)?; + generate_example(repository_path, &**framework, &component_names)?; + generate_features(repository_path, &**framework, &metadatas)?; + + framework.format( + format!("lucide-{}", framework.name()), + repository_path, + repository_path + .join("packages") + .join(framework.name()) + .join("src"), + )?; + + framework.format( + format!("lucide-{}-book", framework.name()), + repository_path, + repository_path + .join("book-examples") + .join(framework.name()) + .join("src"), + )?; + } + + update_repository_rev(repository_path, upstream_repository_rev)?; + + Ok(()) +} + +fn generate_icon( + path: &Path, + framework: &dyn Framework, + module: String, + component_name: String, + input: String, +) -> Result<(), Box> { + let output_path = path + .join("packages") + .join(framework.name()) + .join("src") + .join(format!("{module}.rs")); + + let output_tokens = framework.generate(component_name, input)?; + let output = prettyplease::unparse(&syn::parse2(output_tokens)?); + + fs::write(output_path, output)?; + + Ok(()) +} + +fn generate_example( + path: &Path, + framework: &dyn Framework, + component_names: &[String], +) -> Result<(), Box> { + let output_path = path + .join("book-examples") + .join(framework.name()) + .join("src") + .join("icons.rs"); + + let output_tokens = framework.generate_example(component_names)?; + let output = prettyplease::unparse(&syn::parse2(output_tokens)?); + + fs::write(output_path, output)?; + + Ok(()) +} + +fn generate_lib( + path: &Path, + framework: &dyn Framework, + modules: &[String], + metadatas: &[Metadata], +) -> Result<(), Box> { + let attributes = metadatas + .iter() + .map(|metadata| { + let conditions = metadata + .categories + .iter() + .map(|category| format!("feature = \"{category}\"")) + .collect::>(); + + if conditions.len() == 1 { + format!("#[cfg({})]", conditions.join(", ")) + } else { + format!("#[cfg(any({}))]", conditions.join(", ")) + } + }) + .collect::>(); + + let output_path = path + .join("packages") + .join(framework.name()) + .join("src") + .join("lib.rs"); + + let output_modules = modules + .iter() + .zip(&attributes) + .map(|(module, attribute)| { + format!("{attribute}\nmod {};", sanitize_identifier(module.as_str())) + }) + .collect::>() + .join("\n"); + + let output_uses = modules + .iter() + .zip(&attributes) + .map(|(module, attribute)| { + format!( + "{attribute}\npub use {}::*;", + sanitize_identifier(module.as_str()) + ) + }) + .collect::>() + .join("\n"); + + let output = format!( + "{}{}\n\n{}\n", + match framework.lib_header() { + Some(header) => format!("{header}\n\n"), + None => "".into(), + }, + output_modules, + output_uses + ); + + fs::write(output_path, output)?; + + Ok(()) +} + +fn generate_features( + path: &Path, + framework: &dyn Framework, + metadatas: &[Metadata], +) -> Result<(), Box> { + let file_path = path + .join("packages") + .join(framework.name()) + .join("Cargo.toml"); + + let mut file_contents = fs::read_to_string(&file_path)?; + + let index = file_contents.find("[features]"); + if let Some(index) = index { + file_contents = file_contents[0..index].to_string(); + } + file_contents = file_contents.trim_end_matches("\n").to_string(); + + let mut features = metadatas + .iter() + .flat_map(|metadata| metadata.categories.clone()) + .collect::>() + .into_iter() + .collect::>(); + features.sort(); + + let output_all_features = features + .iter() + .map(|feature| format!(" \"{feature}\",")) + .collect::>() + .join("\n"); + let output_features = features + .into_iter() + .map(|feature| format!("{feature} = []")) + .collect::>() + .join("\n"); + + let output = format!( + "{file_contents}\n\n[features]\ndefault = []\n{output_features}\nall-icons = [\n{output_all_features}\n]\n" + ); + + fs::write(&file_path, output)?; + + Ok(()) +} + +fn update_repository_rev(path: &Path, repository_rev: &str) -> Result<(), Box> { + let file_path = path.join("scripts").join("src").join("lib.rs"); + + let file_contents = fs::read_to_string(&file_path)?; + + let regex = Regex::new(r"\d+\.\d+\.\d+")?; + let output = regex.replace(&file_contents, repository_rev).to_string(); + + fs::write(&file_path, output)?; + + Ok(()) +} + +fn sanitize_identifier(identifier: &str) -> &str { + match identifier { + "box" => "r#box", + "move" => "r#move", + "type" => "r#type", + identifier => identifier, + } +} diff --git a/scripts/src/lib.rs b/scripts/src/lib.rs index 0f44d9d..153de52 100644 --- a/scripts/src/lib.rs +++ b/scripts/src/lib.rs @@ -1,5 +1,15 @@ #![feature(exit_status_error)] -pub mod framework; -pub mod frameworks; -pub mod metadata; +mod framework; +mod frameworks; +pub mod generate; +mod metadata; +pub mod repository; + +pub const GIT_URL: &str = "https://github.com/RustForWeb/lucide.git"; +pub const GITHUB_OWNER: &str = "RustForWeb"; +pub const GITHUB_REPO: &str = "lucide"; + +pub const UPSTREAM_GIT_URL: &str = "https://github.com/lucide-icons/lucide.git"; +pub const UPSTREAM_GIT_REF: &str = "0.507.0"; +pub const UPSTREAM_GITHUB_URL: &str = "https://github.com/lucide-icons/lucide"; diff --git a/scripts/src/repository.rs b/scripts/src/repository.rs new file mode 100644 index 0000000..b354227 --- /dev/null +++ b/scripts/src/repository.rs @@ -0,0 +1,140 @@ +use std::{env, error::Error, path::Path}; + +use git2::{BranchType, Cred, IndexAddOption, PushOptions, RemoteCallbacks, Repository, Signature}; +use log::info; +use semver::Version; + +use crate::{GITHUB_OWNER, GITHUB_REPO, UPSTREAM_GIT_URL}; + +pub fn git_checkout>( + path: P, + url: &str, + r#ref: &str, +) -> Result> { + info!( + "Cloning \"{}\" ref \"{}\" into \"{}\".", + UPSTREAM_GIT_URL, + r#ref, + path.as_ref().display() + ); + + let repository = Repository::clone(url, path)?; + + { + let (object, reference) = repository.revparse_ext(r#ref)?; + + repository.checkout_tree(&object, None)?; + + match reference { + Some(reference) => { + repository.set_head(reference.name().expect("Reference name should exist."))? + } + None => repository.set_head_detached(object.id())?, + } + } + + Ok(repository) +} + +pub fn git_version_tags(repository: &Repository) -> Result, Box> { + let tag_names = repository.tag_names(None)?; + let mut tag_names = tag_names + .into_iter() + .flat_map(|tag_name| { + tag_name.and_then(|tag_name| Version::parse(tag_name.trim_start_matches("v")).ok()) + }) + .collect::>(); + + tag_names.sort(); + + Ok(tag_names) +} + +pub fn git_has_remote_branch(repository: &Repository, branch_name: &str) -> bool { + repository + .find_branch(branch_name, BranchType::Remote) + .is_ok() +} + +pub fn git_create_branch(repository: &Repository, branch_name: &str) -> Result<(), Box> { + info!("Creating branch {branch_name}."); + + let branch = repository.branch(branch_name, &repository.head()?.peel_to_commit()?, false)?; + + repository.set_head( + branch + .into_reference() + .name() + .expect("Reference name should exist."), + )?; + + Ok(()) +} + +pub fn git_commit(repository: &Repository, message: &str) -> Result<(), Box> { + info!("Committing."); + + repository + .index()? + .add_all(["."], IndexAddOption::DEFAULT, None)?; + repository.index()?.write()?; + + let signature = Signature::now(&env::var("GIT_USER_NAME")?, &env::var("GIT_USER_EMAIL")?)?; + let tree = repository.find_tree(repository.index()?.write_tree()?)?; + let parent = repository.head()?.peel_to_commit()?; + + repository.commit( + Some("HEAD"), + &signature, + &signature, + message, + &tree, + &[&parent], + )?; + + Ok(()) +} + +pub fn git_push(repository: &Repository, branch_name: &str) -> Result<(), Box> { + info!("Pushing branch {branch_name}."); + + let branch = repository.find_branch(branch_name, BranchType::Local)?; + let branch_reference = branch.into_reference(); + let branch_ref = branch_reference + .name() + .expect("Reference name should exist."); + + let username = env::var("GITHUB_ACTOR")?; + let password = env::var("GITHUB_TOKEN")?; + + let mut callbacks = RemoteCallbacks::new(); + callbacks.credentials(|_, _, _| Cred::userpass_plaintext(&username, &password)); + + let mut options = PushOptions::new(); + options.remote_callbacks(callbacks); + + let mut remote = repository.find_remote("origin")?; + remote.push(&[branch_ref], Some(&mut options))?; + + Ok(()) +} + +pub async fn github_create_pull_request( + branch_name: &str, + title: &str, + body: &str, +) -> Result<(), Box> { + let octocrab = octocrab::instance(); + + info!("Creating pull request for branch {branch_name}."); + + octocrab + .pulls(GITHUB_OWNER, GITHUB_REPO) + .create(title, branch_name, "main") + .body(body) + .draft(true) + .send() + .await?; + + Ok(()) +}