diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 6908e83..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,32 +0,0 @@ -# .github/workflows/build.yml -name: Build - -on: - push: - branches: [main] - -jobs: - build: - name: Build - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - include: - - target: x86_64-pc-windows-gnu - - target: x86_64-unknown-linux-musl - steps: - - uses: actions/checkout@master - - name: Compile - id: compile - uses: rust-build/rust-build.action@v1.4.4 - with: - RUSTTARGET: ${{ matrix.target }} - UPLOAD_MODE: none - - name: Upload artifact - uses: actions/upload-artifact@v3 - with: - name: Binary - path: | - ${{ steps.compile.outputs.BUILT_ARCHIVE }} - ${{ steps.compile.outputs.BUILT_CHECKSUM }} diff --git a/.github/workflows/pre-release.yml b/.github/workflows/pre-release.yml new file mode 100644 index 0000000..c219bf2 --- /dev/null +++ b/.github/workflows/pre-release.yml @@ -0,0 +1,56 @@ +on: + push: + branches: + - dev* + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: write + discussions: write + +jobs: + pre-release: + name: Nightly-release + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: aarch64-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: armv7-unknown-linux-musleabi + os: ubuntu-latest + cross: true + - target: x86_64-apple-darwin + os: macos-latest + cross: false + - target: aarch64-apple-darwin + os: macos-latest + cross: false + - target: x86_64-pc-windows-msvc + os: windows-latest + cross: false + steps: + - uses: actions/checkout@main + - uses: dtolnay/rust-toolchain@master + with: + target: ${{ matrix.target }} + toolchain: stable + + - name: Run Cargo | Cross + if: ${{ matrix.cross }} + run: | + cargo install cross --git https://github.com/cross-rs/cross.git --locked --rev 085092ca + cross build --bin utpm -p utpm --release --target ${{ matrix.target }} + + - name: Run Cargo | ${{ matrix.os }} + if: ${{ !matrix.cross }} + run: | + cargo build --bin utpm -p utpm --release --target ${{ matrix.target }} + \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a99d17f..d601d3a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,21 +1,97 @@ on: - release: - types: [created] + push: + branches: + - main + +env: + CARGO_TERM_COLOR: always + +permissions: + contents: write + discussions: write jobs: - release: - name: release ${{ matrix.target }} - runs-on: ubuntu-latest + pre-release: + name: Production-release + runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: - target: [x86_64-pc-windows-gnu, x86_64-unknown-linux-musl] + include: + - target: x86_64-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: aarch64-unknown-linux-musl + os: ubuntu-latest + cross: true + - target: armv7-unknown-linux-musleabi + os: ubuntu-latest + cross: true + - target: x86_64-apple-darwin + os: macos-latest + cross: false + - target: aarch64-apple-darwin + os: macos-latest + cross: false + - target: x86_64-pc-windows-msvc + os: windows-latest + cross: false steps: - - uses: actions/checkout@v3 - - name: Compile and release - uses: rust-build/rust-build.action@v1.4.4 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/checkout@main + - uses: dtolnay/rust-toolchain@master + with: + target: ${{ matrix.target }} + toolchain: stable + + - name: Run Cargo | Cross + if: ${{ matrix.cross }} + run: | + cargo install cross --git https://github.com/cross-rs/cross.git --locked --rev 085092ca + cross build --bin utpm -p utpm --release --target ${{ matrix.target }} + + - name: Run Cargo | ${{ matrix.os }} + if: ${{ !matrix.cross }} + run: | + cargo build --bin utpm -p utpm --release --target ${{ matrix.target }} + + - name: Create artifact directory + shell: bash + run: | + directory=utpm-${{ matrix.target }} + mkdir $directory + cp README.md LICENSE $directory + if [ -f target/${{ matrix.target }}/release/utpm.exe ]; then + cp target/${{ matrix.target }}/release/utpm.exe $directory + 7z a -r $directory.zip $directory + else + cp target/${{ matrix.target }}/release/utpm $directory + tar cJf $directory.tar.xz $directory + fi + + - name: Get Next Version + id: semver + uses: ietf-tools/semver-action@v1 + with: + token: ${{ github.token }} + branch: main + + - name: Create a Release [${{ steps.semver.outputs.next }}] + uses: softprops/action-gh-release@v2 + with: + token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: false + tag_name: ${{ steps.semver.outputs.next }} + generate_release_notes: true + files: | + utpm-${{ matrix.target }}.* + + - name: Create a Release [Latest] + uses: softprops/action-gh-release@v2 with: - RUSTTARGET: ${{ matrix.target }} - EXTRA_FILES: "README.md LICENSE" + token: "${{ secrets.GITHUB_TOKEN }}" + prerelease: false + tag_name: latest + generate_release_notes: true + files: | + utpm-${{ matrix.target }}.* + \ No newline at end of file diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index cc41b6f..0000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,23 +0,0 @@ -name: Rust - -on: - push: - branches: - - "*" - pull_request: - branches: - - main - -env: - CARGO_TERM_COLOR: always - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Build - run: cargo build --verbose - - name: Run tests - run: cargo test --verbose - diff --git a/.gitignore b/.gitignore index 2c644f2..4ac3046 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ /target -.utpm .vscode -utpm -/test \ No newline at end of file + +#nix +.direnv +result diff --git a/Cargo.lock b/Cargo.lock index c195b13..23614a6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,942 +1,4138 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +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" +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 = "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.5.0" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", + "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" -version = "1.0.2" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15c4c2c83f81532e5845a733998b6971faca23490340a418e9b72a3ec9de12ea" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.1" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.0.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "windows-sys", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "2.1.0" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", - "windows-sys", + "once_cell", + "windows-sys 0.59.0", ] [[package]] -name = "autocfg" -version = "1.1.0" +name = "approx" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "arc-swap" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" [[package]] -name = "bitflags" -version = "2.4.0" +name = "arrayref" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] -name = "cc" -version = "1.0.83" +name = "arrayvec" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "jobserver", - "libc", -] +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] -name = "cfg-if" -version = "1.0.0" +name = "async-trait" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "clap" -version = "4.4.2" +name = "autocfg" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6" -dependencies = [ - "clap_builder", - "clap_derive", -] +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] -name = "clap_builder" -version = "4.4.2" +name = "az" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08" -dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", -] +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" [[package]] -name = "clap_derive" -version = "4.4.2" +name = "backtrace" +version = "0.3.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.18", + "addr2line", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", + "windows-targets 0.52.6", ] [[package]] -name = "clap_lex" -version = "0.5.1" +name = "base64" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] -name = "colorchoice" -version = "1.0.0" +name = "base64" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] -name = "crossterm" -version = "0.25.0" +name = "biblatex" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +checksum = "a35a7317fcbdbef94b60d0dd0a658711a936accfce4a631fea4bf8e527eff3c2" dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "signal-hook", - "signal-hook-mio", - "winapi", + "numerals", + "paste", + "strum", + "unicode-normalization", + "unscanny", ] [[package]] -name = "crossterm_winapi" -version = "0.9.1" +name = "bincode" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" dependencies = [ - "winapi", + "serde", ] [[package]] -name = "darling" -version = "0.13.4" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ - "darling_core", - "darling_macro", + "bit-vec", ] [[package]] -name = "darling_core" -version = "0.13.4" +name = "bit-vec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] -name = "darling_macro" -version = "0.13.4" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "dirs" -version = "5.0.1" +name = "bitflags" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" dependencies = [ - "dirs-sys", + "serde", ] [[package]] -name = "dirs-sys" -version = "0.4.1" +name = "bstr" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8" dependencies = [ - "libc", - "option-ext", - "redox_users", - "windows-sys", + "memchr", + "serde", ] [[package]] -name = "dyn-clone" -version = "1.0.13" +name = "bumpalo" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfc4744c1b8f2a09adc0e55242f60b1af195d88596bd8700be74418c056c555" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] -name = "equivalent" -version = "1.0.0" +name = "by_address" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" +checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] -name = "fnv" -version = "1.0.7" +name = "bytemuck" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" [[package]] -name = "form_urlencoded" -version = "1.2.0" +name = "byteorder" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" -dependencies = [ - "percent-encoding", -] +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] -name = "getrandom" -version = "0.2.10" +name = "byteorder-lite" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] -name = "git2" -version = "0.18.0" +name = "bytes" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ef350ba88a33b4d524b1d1c79096c9ade5ef8c59395df0e60d1e1889414c0e" +checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" + +[[package]] +name = "cc" +version = "1.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ - "bitflags 2.4.0", + "jobserver", "libc", - "libgit2-sys", - "log", - "openssl-probe", - "openssl-sys", - "url", + "shlex", ] [[package]] -name = "hashbrown" -version = "0.14.0" +name = "cfg-if" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] -name = "heck" -version = "0.4.1" +name = "chinese-number" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "49fccaef6346f6d6a741908d3b79fe97c2debe2fbb5eb3a7d00ff5981b52bb6c" +dependencies = [ + "chinese-variant", + "enum-ordinalize", + "num-bigint", + "num-traits", +] [[package]] -name = "ident_case" -version = "1.0.1" +name = "chinese-variant" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "7588475145507237ded760e52bf2f1085495245502033756d28ea72ade0e498b" [[package]] -name = "idna" -version = "0.4.0" +name = "chrono" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-link", ] [[package]] -name = "indexmap" -version = "2.0.0" +name = "ciborium" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e" dependencies = [ - "equivalent", - "hashbrown", + "ciborium-io", + "ciborium-ll", + "serde", ] [[package]] -name = "inquire" -version = "0.6.2" +name = "ciborium-io" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33e7c1ddeb15c9abcbfef6029d8e29f69b52b6d6c891031b88ed91b5065803b" -dependencies = [ - "bitflags 1.3.2", - "crossterm", - "dyn-clone", - "lazy_static", - "newline-converter", - "thiserror", - "unicode-segmentation", - "unicode-width", -] +checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757" [[package]] -name = "itoa" -version = "1.0.6" +name = "ciborium-ll" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" +checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9" +dependencies = [ + "ciborium-io", + "half", +] [[package]] -name = "jobserver" -version = "0.1.26" +name = "citationberg" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +checksum = "e4595e03beafb40235070080b5286d3662525efc622cca599585ff1d63f844fa" dependencies = [ - "libc", + "quick-xml 0.36.2", + "serde", ] [[package]] -name = "lazy_static" -version = "1.4.0" +name = "clap" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "fd60e63e9be68e5fb56422e397cf9baddded06dae1d2e523401542383bc72a9f" +dependencies = [ + "clap_builder", + "clap_derive", +] [[package]] -name = "libc" -version = "0.2.146" +name = "clap_builder" +version = "4.5.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +checksum = "89cc6392a1f72bbeb820d71f32108f61fdaf18bc526e1d23954168a67759ef51" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] [[package]] -name = "libgit2-sys" -version = "0.16.2+1.7.2" +name = "clap_complete" +version = "4.5.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +checksum = "8d2267df7f3c8e74e38268887ea5235d4dfadd39bfff2d56ab82d61776be355e" dependencies = [ - "cc", - "libc", - "libssh2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", + "clap", ] [[package]] -name = "libssh2-sys" -version = "0.3.0" +name = "clap_derive" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ - "cc", - "libc", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "libz-sys" -version = "1.1.12" +name = "clap_lex" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d97137b25e321a73eef1418d1d5d2eda4d77e12813f8e6dead84bc52c5870a7b" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] -name = "lock_api" -version = "0.4.10" +name = "cobs" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" -dependencies = [ - "autocfg", - "scopeguard", -] +checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" [[package]] -name = "log" -version = "0.4.20" +name = "codex" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "724d27a0ee38b700e5e164350e79aba601a0db673ac47fce1cb74c3e38864036" [[package]] -name = "memchr" -version = "2.5.0" +name = "color_quant" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" [[package]] -name = "mio" -version = "0.8.8" +name = "colorchoice" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" + +[[package]] +name = "comemo" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "df6916408a724339aa77b18214233355f3eb04c42eb895e5f8909215bd8a7a91" dependencies = [ - "libc", - "log", - "wasi", - "windows-sys", + "comemo-macros", + "once_cell", + "parking_lot", + "siphasher", ] [[package]] -name = "newline-converter" -version = "0.2.2" +name = "comemo-macros" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f71d09d5c87634207f894c6b31b6a2b2c64ea3bdcf71bd5599fdbbe1600c00f" +checksum = "c8936e42f9b4f5bdfaf23700609ac1f11cb03ad4c1ec128a4ee4fd0903e228db" dependencies = [ - "unicode-segmentation", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "openssl-probe" -version = "0.1.5" +name = "const_format" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] [[package]] -name = "openssl-sys" -version = "0.9.93" +name = "const_format_proc_macros" +version = "0.2.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" dependencies = [ - "cc", + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", "libc", - "pkg-config", - "vcpkg", ] [[package]] -name = "option-ext" -version = "0.2.0" +name = "core-foundation" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "owo-colors" -version = "3.5.0" +name = "core-foundation-sys" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "core_maths" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" dependencies = [ - "lock_api", - "parking_lot_core", + "libm", ] [[package]] -name = "parking_lot_core" -version = "0.9.8" +name = "crc32fast" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +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 = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", "libc", - "redox_syscall 0.3.5", - "smallvec", - "windows-targets", + "mio 0.8.11", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", ] [[package]] -name = "percent-encoding" +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" + +[[package]] +name = "csv" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdc4883a9c96732e4733212c01447ebd805833b7275a73ca3ee080fd77afdaf" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d02f3b0da4c6504f86e9cd789d8dbafab48c2321be74e9987593de5a894d93d" +dependencies = [ + "memchr", +] + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "dirs" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e01a3366d27ee9890022452ee61b2b63a67e6f13f58900b651ff5665f0bb1fab" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.59.0", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dyn-clone" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "feeef44e73baff3a26d371801df019877a9866a8c493d315ab00177843314f35" + +[[package]] +name = "ecow" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42fc0a93992b20c58b99e59d61eaf1635a25bfbe49e4275c34ba0aee98119ba" +dependencies = [ + "serde", +] + +[[package]] +name = "either" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" + +[[package]] +name = "email_address" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1019fa28f600f5b581b7a603d515c3f1635da041ca211b5055804788673abfe" +dependencies = [ + "serde", +] + +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "env_proxy" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5019be18538406a43b5419a5501461f0c8b49ea7dfda0cfc32f4e51fc44be1" +dependencies = [ + "log", + "url", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "fancy-regex" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" +dependencies = [ + "bit-set", + "regex", +] + +[[package]] +name = "fast-srgb8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" + +[[package]] +name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[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 = "flate2" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37be9fc20d966be438cd57a45767f73349477fb0f85ce86e000557f787298afb" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[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-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-executor" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" + +[[package]] +name = "futures-macro" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fuzzy-matcher" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54614a3312934d066701a80f20f15fa3b56d67ac7722b39eea5b4c9dd1d66c94" +dependencies = [ + "thread_local", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets 0.52.6", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" + +[[package]] +name = "git2" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2deb07a133b1520dc1a5690e9bd08950108873d7ed5de38dcc74d3b5ebffa110" +dependencies = [ + "bitflags 2.9.0", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hayagriva" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "954907554bb7fcba29a4f917c2d43e289ec21b69d872ccf97db160eca6caeed8" +dependencies = [ + "biblatex", + "ciborium", + "citationberg", + "indexmap", + "numerals", + "paste", + "serde", + "serde_yaml", + "thiserror 1.0.69", + "unic-langid", + "unicode-segmentation", + "unscanny", + "url", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "http" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +dependencies = [ + "bytes", + "fnv", + "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", + "http", + "http-body", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03a01595e11bdcec50946522c32dde3fc6914743000a68b93000965f2f02406d" +dependencies = [ + "http", + "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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c293b6b3d21eca78250dc7dbebd6b9210ec5530e038cbfe0661b5c47ab06e8" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "libc", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "serde", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "serde", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "postcard", + "serde", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_blob" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c24b98d1365f55d78186c205817631a4acf08d7a45bdf5dc9dcf9c5d54dccf51" +dependencies = [ + "icu_provider", + "postcard", + "serde", + "writeable", + "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 = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.25.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "gif", + "num-traits", + "png", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "indexmap" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +dependencies = [ + "equivalent", + "hashbrown", + "serde", +] + +[[package]] +name = "inquire" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" +dependencies = [ + "bitflags 2.9.0", + "crossterm", + "dyn-clone", + "fuzzy-matcher", + "fxhash", + "newline-converter", + "once_cell", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "iri-string" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0f0a572e8ffe56e2ff4f769f32ffe919282c3916799f8b68688b6030063bea" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_debug" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fe266d2e243c931d8190177f20bf7f24eed45e96f39e87dc49a27b32d12d407" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[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 = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "kamadak-exif" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1130d80c7374efad55a117d715a3af9368f0fa7a2c54573afc15a188cd984837" +dependencies = [ + "mutate_once", +] + +[[package]] +name = "kurbo" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +dependencies = [ + "arrayvec", + "smallvec", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.172" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" + +[[package]] +name = "libgit2-sys" +version = "0.18.1+1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1dcb20f84ffcdd825c7a311ae347cce604a6f084a767dec4a4929829645290e" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libm" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" + +[[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 = "libssh2-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "lipsum" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "636860251af8963cc40f6b4baadee105f02e21b28131d76eba8e40ce84ab8064" +dependencies = [ + "rand", + "rand_chacha", +] + +[[package]] +name = "litemap" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" +dependencies = [ + "serde", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[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" +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 = "multi-stash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685a9ac4b61f4e728e1d2c6a7844609c16527aeb5e6c865915c08e619c16410f" + +[[package]] +name = "mutate_once" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16cf681a23b4d0a43fc35024c176437f9dcd818db34e0f42ab456a0ee5ad497b" + +[[package]] +name = "native-tls" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dab59f8e050d5df8e4dd87d9206fb6f65a483e20ac9fda365ade4fab353196c" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework 2.11.1", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "newline-converter" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b6b097ecb1cbfed438542d16e84fd7ad9b0c76c8a65b7f9039212a3d14dc7f" +dependencies = [ + "unicode-segmentation", +] + +[[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-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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "numerals" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e25be21376a772d15f97ae789845340a9651d3c4246ff5ebb6a2b35f9c37bd31" + +[[package]] +name = "object" +version = "0.36.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +dependencies = [ + "memchr", +] + +[[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 0.22.1", + "bytes", + "cfg-if", + "chrono", + "either", + "futures", + "futures-util", + "http", + "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.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" + +[[package]] +name = "openssl" +version = "0.10.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fedfea7d58a1f73118430a55da6a286e7b044961736ce96a16a17068ea25e5da" +dependencies = [ + "bitflags 2.9.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" + +[[package]] +name = "openssl-src" +version = "300.4.2+3.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168ce4e058f975fe43e89d9ccf78ca668601887ae736090aacc23ae353c298e2" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e145e1651e858e820e4860f7b9c5e169bc1d8ce1c86043be79fa7b7634821847" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "palette" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +dependencies = [ + "approx", + "fast-srgb8", + "libm", + "palette_derive", +] + +[[package]] +name = "palette_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +dependencies = [ + "by_address", + "proc-macro2", + "quote", + "syn", +] + +[[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 = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "phf" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" +dependencies = [ + "phf_macros", + "phf_shared", +] + +[[package]] +name = "phf_generator" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" +dependencies = [ + "phf_shared", + "rand", +] + +[[package]] +name = "phf_macros" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" +dependencies = [ + "phf_generator", + "phf_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "phf_shared" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" +dependencies = [ + "siphasher", +] + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64 0.22.1", + "indexmap", + "quick-xml 0.32.0", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82151a2fc869e011c153adc57cf2789ccb8d9906ce52c0b39a6b5697749d7526" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "portable-atomic" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e" + +[[package]] +name = "postcard" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a2601f67cc9dba8edd8c4870b15f71a6a2dc196daec8c83f72b59dff628a8" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro2" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qcms" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edecfcd5d755a5e5d98e24cf43113e7cdaec5a070edd0f6b250c03a573da30fa" + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quote" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "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" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +dependencies = [ + "bitflags 2.9.0", +] + +[[package]] +name = "redox_users" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd6f9d3d47bdd2ad6945c5015a226ec6155d0bcdfd8f7cd29f86b71f8de99d2b" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 2.0.12", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +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.15", + "libc", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "num-traits", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.9.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustls" +version = "0.23.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" +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 3.2.0", +] + +[[package]] +name = "rustls-pki-types" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +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 = "rustybuzz" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" +dependencies = [ + "bitflags 2.9.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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 = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" +dependencies = [ + "bitflags 2.9.0", + "core-foundation 0.10.0", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +dependencies = [ + "serde", +] + +[[package]] +name = "serde" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.218" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.140" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +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 = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "shadow-rs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d5625ed609cf66d7e505e7d487aca815626dc4ebb6c0dd07637ca61a44651a6" +dependencies = [ + "const_format", + "git2", + "is_debug", + "time", + "tzdb", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" +dependencies = [ + "libc", + "mio 0.8.11", + "signal-hook", +] + +[[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 = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9c6883ca9c3c7c90e888de77b7a5c849c779d25d74a1269b0218b14e8b136c" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" + +[[package]] +name = "snafu" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320b01e011bf8d5d7a4a4a4be966d9160968935849c83b918827f6a435e7f627" +dependencies = [ + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1961e2ef424c1424204d3a5d6975f934f56b6d50ff5732382d84ebf460e147f7" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "socket2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "spdx" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58b69356da67e2fc1f542c71ea7e654a361a79c938e4424392ecf4fa065d2193" +dependencies = [ + "smallvec", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "string-interner" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3275464d7a9f2d4cac57c89c2ef96a8524dba2864c8d6f82e3980baf136f9b" +dependencies = [ + "hashbrown", + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68c7541fff44b35860c1a7a47a7cadf3e4a304c457b58f9870d9706ece028afc" +dependencies = [ + "kurbo", + "siphasher", +] + +[[package]] +name = "syn" +version = "2.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syntect" +version = "5.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "874dcfa363995604333cf947ae9f751ca3af4522c60886774c4963943b4746b1" +dependencies = [ + "bincode", + "bitflags 1.3.2", + "fancy-regex", + "flate2", + "fnv", + "once_cell", + "plist", + "regex-syntax", + "serde", + "serde_derive", + "serde_json", + "thiserror 1.0.69", + "walkdir", + "yaml-rust", +] + +[[package]] +name = "tar" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tempfile" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +dependencies = [ + "cfg-if", + "fastrand", + "getrandom 0.3.1", + "once_cell", + "rustix", + "windows-sys 0.59.0", +] + +[[package]] +name = "thin-vec" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a38c90d48152c236a3ab59271da4f4ae63d678c5d7ad6b7714d7cb9760be5e4b" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "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.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb041120f25f8fbe8fd2dbe4671c7c2ed74d83be2e7a77529bf7e0790ae3f472" +dependencies = [ + "deranged", + "itoa", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "765c97a5b985b7c11d7bc27fa927dc4fe6af3a6dfb021d28deb60d3bf51e76ef" + +[[package]] +name = "time-macros" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8093bc3e81c3bc5f7879de09619d06c9a5a5e45ca44dfeeb7225bae38005c5c" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "serde", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.45.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ef51a33ef1da925cea3e4eb122833cb377c61439ca401b770f54902b806779" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio 1.0.3", + "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", +] + +[[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.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +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", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403fa3b783d4b626a8ad51d766ab03cb6d2dbfc46b1c5d4448395e6628dc9697" +dependencies = [ + "bitflags 2.9.0", + "bytes", + "futures-util", + "http", + "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", +] + +[[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" +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 = [ + "nu-ansi-term", + "sharded-slab", + "smallvec", + "thread_local", + "tracing-core", + "tracing-log", +] + +[[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.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" +dependencies = [ + "core_maths", +] + +[[package]] +name = "two-face" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384eda438ddf62e2c6f39a174452d952d9d9df5a8ad5ade22198609f8dcaf852" +dependencies = [ + "once_cell", + "serde", + "syntect", +] + +[[package]] +name = "typed-arena" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" + +[[package]] +name = "typst-assets" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5bf0cc3c2265502b51fcb73147cc7c951ceb694507195b93c2ab0b901abb902" + +[[package]] +name = "typst-kit" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818fa9d54e1663fe20d15f6359945616cc4026d68c4de6c4eb0add7556fe2a90" +dependencies = [ + "dirs", + "ecow", + "env_proxy", + "flate2", + "fontdb", + "native-tls", + "once_cell", + "openssl", + "serde", + "serde_json", + "tar", + "typst-library", + "typst-syntax", + "typst-timing", + "typst-utils", + "ureq", +] + +[[package]] +name = "typst-library" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "722b0d6dfd05aa5bb7da7f282586f624f452e3f285cd3a10ac0d7e99f3bc3048" +dependencies = [ + "az", + "bitflags 2.9.0", + "bumpalo", + "chinese-number", + "ciborium", + "codex", + "comemo", + "csv", + "ecow", + "flate2", + "fontdb", + "hayagriva", + "icu_properties", + "icu_provider", + "icu_provider_blob", + "image", + "indexmap", + "kamadak-exif", + "kurbo", + "lipsum", + "memchr", + "palette", + "phf", + "png", + "qcms", + "rayon", + "regex", + "regex-syntax", + "roxmltree", + "rust_decimal", + "rustybuzz", + "serde", + "serde_json", + "serde_yaml", + "siphasher", + "smallvec", + "syntect", + "time", + "toml", + "ttf-parser", + "two-face", + "typed-arena", + "typst-assets", + "typst-macros", + "typst-syntax", + "typst-timing", + "typst-utils", + "unicode-math-class", + "unicode-segmentation", + "unscanny", + "usvg", + "wasmi", + "xmlwriter", +] + +[[package]] +name = "typst-macros" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a7667bf2ff3111e25744e72abfdbbed5fed9a37476043448e935697e55a6fb" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typst-project" +version = "0.1.0" +source = "git+https://github.com/tingerrr/typst-project?rev=8462942ef0c783acf339e715b5e24b2dba423de1#8462942ef0c783acf339e715b5e24b2dba423de1" +dependencies = [ + "bitflags 2.9.0", + "email_address", + "semver", + "serde", + "spdx", + "strum", + "thiserror 1.0.69", + "toml", + "toml_edit", + "unicode-ident", + "unscanny", +] + +[[package]] +name = "typst-syntax" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba949ac75a374ea6b2f61d32e6c63acb818e6179d16f78b2cba988fbb5e23a8" +dependencies = [ + "ecow", + "serde", + "toml", + "typst-timing", + "typst-utils", + "unicode-ident", + "unicode-math-class", + "unicode-script", + "unicode-segmentation", + "unscanny", +] + +[[package]] +name = "typst-timing" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ba4541664e98be2023db2267d92af206190eb903063a0229c668e1ab9dca976" +dependencies = [ + "parking_lot", + "serde", + "serde_json", +] + +[[package]] +name = "typst-utils" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eb71d59967e0fb32341f8a94f41ced8da520c63705cca2686ae653c9408fd96" +dependencies = [ + "once_cell", + "portable-atomic", + "rayon", + "siphasher", + "thin-vec", + "unicode-math-class", +] + +[[package]] +name = "tz-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1450bf2b99397e72070e7935c89facaa80092ac812502200375f1f7d33c71a1" + +[[package]] +name = "tzdb" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0be2ea5956f295449f47c0b825c5e109022ff1a6a53bb4f77682a87c2341fbf5" +dependencies = [ + "iana-time-zone", + "tz-rs", + "tzdb_data", +] + +[[package]] +name = "tzdb_data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c4c81d75033770e40fbd3643ce7472a1a9fd301f90b7139038228daf8af03ec" +dependencies = [ + "tz-rs", +] + +[[package]] +name = "unic-langid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44" +dependencies = [ + "unic-langid-impl", +] + +[[package]] +name = "unic-langid-impl" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5" +dependencies = [ + "serde", + "tinystr", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f" + +[[package]] +name = "unicode-ccc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42" + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-math-class" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d246cf599d5fae3c8d56e04b20eb519adb89a8af8d0b0fbcded369aa3647d65" + +[[package]] +name = "unicode-normalization" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "unscanny" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9df2af067a7953e9c3831320f35c1cc0600c30d44d9f7a12b01db1cd88d6b47" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "native-tls", + "once_cell", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "usvg" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6803057b5cbb426e9fb8ce2216f3a9b4ca1dd2c705ba3cbebc13006e437735fd" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "utpm" +version = "0.1.0" +dependencies = [ + "clap", + "clap_complete", + "dirs", + "git2", + "ignore", + "inquire", + "octocrab", + "openssl", + "regex", + "semver", + "serde", + "shadow-rs", + "spdx", + "tokio", + "tokio-macros", + "toml", + "tracing", + "tracing-subscriber", + "typst-kit", + "typst-project", + "typst-syntax", + "url", +] + +[[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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "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.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +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-macro" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.100" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] [[package]] -name = "pkg-config" -version = "0.3.27" +name = "wasm-bindgen-shared" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] -name = "proc-macro2" -version = "1.0.60" +name = "wasmi" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "a19af97fcb96045dd1d6b4d23e2b4abdbbe81723dbc5c9f016eb52145b320063" dependencies = [ - "unicode-ident", + "arrayvec", + "multi-stash", + "smallvec", + "spin", + "wasmi_collections", + "wasmi_core", + "wasmi_ir", + "wasmparser", ] [[package]] -name = "quote" -version = "1.0.28" +name = "wasmi_collections" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "e80d6b275b1c922021939d561574bf376613493ae2b61c6963b15db0e8813562" dependencies = [ - "proc-macro2", + "string-interner", ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "wasmi_core" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "3a8c51482cc32d31c2c7ff211cd2bedd73c5bd057ba16a2ed0110e7a96097c33" dependencies = [ - "bitflags 1.3.2", + "downcast-rs", + "libm", ] [[package]] -name = "redox_syscall" -version = "0.3.5" +name = "wasmi_ir" +version = "0.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "6e431a14c186db59212a88516788bd68ed51f87aa1e08d1df742522867b5289a" dependencies = [ - "bitflags 1.3.2", + "wasmi_core", ] [[package]] -name = "redox_users" -version = "0.4.3" +name = "wasmparser" +version = "0.221.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185" dependencies = [ - "getrandom", - "redox_syscall 0.2.16", - "thiserror", + "bitflags 2.9.0", + "indexmap", ] [[package]] -name = "ryu" -version = "1.0.13" +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "weezl" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" [[package]] -name = "semver" -version = "1.0.18" +name = "winapi" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "serde", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "serde" -version = "1.0.164" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" -dependencies = [ - "serde_derive", -] +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] -name = "serde_derive" -version = "1.0.164" +name = "winapi-util" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", + "windows-sys 0.59.0", ] [[package]] -name = "serde_json" -version = "1.0.97" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" -dependencies = [ - "itoa", - "ryu", - "serde", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "serde_spanned" -version = "0.6.3" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "serde", + "windows-targets 0.52.6", ] [[package]] -name = "serde_with" -version = "1.14.0" +name = "windows-link" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" -dependencies = [ - "serde", - "serde_with_macros", -] +checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3" [[package]] -name = "serde_with_macros" -version = "1.5.2" +name = "windows-sys" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 1.0.109", + "windows-targets 0.48.5", ] [[package]] -name = "signal-hook" -version = "0.3.17" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "libc", - "signal-hook-registry", + "windows-targets 0.52.6", ] [[package]] -name = "signal-hook-mio" -version = "0.2.3" +name = "windows-sys" +version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "libc", - "mio", - "signal-hook", + "windows-targets 0.52.6", ] [[package]] -name = "signal-hook-registry" -version = "1.4.1" +name = "windows-targets" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "libc", + "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 = "smallvec" -version = "1.11.0" +name = "windows-targets" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "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 = "spdx" -version = "0.10.2" +name = "windows_aarch64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b19b32ed6d899ab23174302ff105c1577e45a06b08d4fe0a9dd13ce804bbbf71" -dependencies = [ - "smallvec", -] +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "strsim" -version = "0.10.0" +name = "windows_aarch64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] -name = "syn" -version = "1.0.109" +name = "windows_aarch64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "syn" -version = "2.0.18" +name = "windows_aarch64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] -name = "thiserror" -version = "1.0.40" +name = "windows_i686_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "thiserror-impl" -version = "1.0.40" +name = "windows_i686_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.18", -] +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] -name = "tinyvec" -version = "1.6.0" +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "windows_i686_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "toml" -version = "0.7.5" +name = "windows_i686_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime", - "toml_edit", -] +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] -name = "toml_datetime" -version = "0.6.3" +name = "windows_x86_64_gnu" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" -dependencies = [ - "serde", -] +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "toml_edit" -version = "0.19.11" +name = "windows_x86_64_gnu" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] -name = "unicode-bidi" -version = "0.3.13" +name = "windows_x86_64_gnullvm" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "unicode-ident" -version = "1.0.9" +name = "windows_x86_64_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] -name = "unicode-normalization" -version = "0.1.22" +name = "windows_x86_64_msvc" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] -name = "unicode-segmentation" -version = "1.10.1" +name = "windows_x86_64_msvc" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "unicode-width" -version = "0.1.10" +name = "winnow" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] [[package]] -name = "url" -version = "2.4.1" +name = "wit-bindgen-rt" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", + "bitflags 2.9.0", ] [[package]] -name = "utf8parse" -version = "0.2.1" +name = "write16" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] -name = "utpm" -version = "2.1.0" -dependencies = [ - "clap", - "dirs", - "git2", - "inquire", - "owo-colors", - "semver", - "serde", - "serde_json", - "serde_with", - "spdx", - "toml", -] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] -name = "vcpkg" -version = "0.2.15" +name = "xattr" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +checksum = "e105d177a3871454f754b33bb0ee637ecaaac997446375fd3e5d43a2ed00c909" +dependencies = [ + "libc", + "linux-raw-sys", + "rustix", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "xmlwriter" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" [[package]] -name = "winapi" -version = "0.3.9" +name = "yaml-rust" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "linked-hash-map", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "yoke" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "yoke-derive" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "zerocopy" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "windows-targets", + "byteorder", + "zerocopy-derive", ] [[package]] -name = "windows-targets" -version = "0.48.0" +name = "zerocopy-derive" +version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" +name = "zerofrom" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] [[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" +name = "zerofrom-derive" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] [[package]] -name = "windows_i686_gnu" -version = "0.48.0" +name = "zeroize" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" [[package]] -name = "windows_i686_msvc" -version = "0.48.0" +name = "zerotrie" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +checksum = "fb594dd55d87335c5f60177cee24f19457a5ec10a065e0a3014722ad252d0a1f" +dependencies = [ + "displaydoc", + "litemap", + "serde", + "zerovec", +] [[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" +name = "zerovec" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "serde", + "yoke", + "zerofrom", + "zerovec-derive", +] [[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" +name = "zerovec-derive" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +name = "zune-core" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" [[package]] -name = "winnow" -version = "0.4.7" +name = "zune-jpeg" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "99a5bab8d7dedf81405c4bb1f2b83ea057643d9cb28778cea9eecddeedd2e028" dependencies = [ - "memchr", + "zune-core", ] diff --git a/Cargo.toml b/Cargo.toml index 06ef2e9..a6bd276 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,33 +1,69 @@ [package] +build = "build.rs" name = "utpm" -version = "2.1.0" +version = "0.1.0" edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +description = "UTPM is a package manager for local and remote Typst packages. Quickly create and manage projects and templates on your system, and publish them directly to Typst Universe." +authors = ["Thomas QUEMIN "] +documentation = "https://utpm.thumus.eu" # Not working for now +repository = "https://github.com/typst-community/utpm" +license = "MIT" +keywords = ["typst", "packages"] +categories = ["command-line-utilities"] +exclude = ["/target", "/.github"] [dependencies] -dirs = "5.0" -serde_json = "1.0" +dirs = "6.0" serde = { version = "1.0", features = ["derive"] } -serde_with = "1.0" -toml = { version = "0.7.5", features = ["display"] } -inquire = "0.6.2" -semver = { version = "1.0.18", features = ["serde"] } -spdx = { version = "0.10.2", features = ["text"] } -clap = { version = "4.4.2", features = ["derive"] } -git2 = "0.18.0" -owo-colors = "3.5.0" +toml = { version = "^0.8.22", features = ["display"] } +inquire = { version = "0.7.5", optional = true } +semver = { version = "1.0.26", features = ["serde"] } +spdx = { version = "0.10.8", features = ["text"], optional = true } +clap = { version = "4.5.39", features = ["derive"] } +git2 = { version = "^0.20.2", optional = true } +typst-project = { git = "https://github.com/tingerrr/typst-project", rev = "8462942ef0c783acf339e715b5e24b2dba423de1" } +openssl = { version = "0.10", features = ["vendored"] } # ? +tracing = { version = "0.1.41", features = ["attributes"] } +tracing-subscriber = "0.3.19" +clap_complete = { version = "4.5.51", optional = true } +shadow-rs = "1.1.1" +typst-kit = "0.13.1" +typst-syntax = { version = "0.13.1", optional = true } +regex = { version = "1.11.1", optional = true } +ignore = { version = "0.4.23", optional = true } +octocrab = { version = "0.44.1", optional = true } +tokio = { version = "1.45.1", features = ["full"] } +tokio-macros = "2.5.0" +url = "2.5.4" + +[build-dependencies] +shadow-rs = "1.1.1" [[bin]] name = "utpm" path = "src/main.rs" - -[[bin]] -name = "utpm-portable" -path = "src/portable.rs" +build = "build.rs" [features] -portable = [] +default = ["full"] +nightly = [] +full = ["workspace", "packages", "generate"] +add = ["install"] +bulk_delete = ["unlink"] +clone = ["dep:regex", "dep:git2", "dep:typst-syntax"] +init = ["dep:spdx", "dep:inquire"] +delete = [] +generate = ["dep:clap_complete"] +install = ["link", "dep:git2"] +link = [] +list = [] +path = [] +publish = ["dep:git2", "dep:octocrab", "dep:ignore", "dep:regex"] +tree = [] +unlink = ["dep:inquire", "dep:regex"] +workspace = ["link", "init", "install", "add", "delete", "publish", "clone"] +packages = ["tree", "list", "path", "unlink", "bulk_delete"] + # For future dependencies check and other things, it will be usefull # Reduce size diff --git a/README.md b/README.md index 98eb9ae..99fd477 100644 --- a/README.md +++ b/README.md @@ -1,46 +1,150 @@ -# Unofficial Typst Package Manager +
-> Alias "utpm" +![UTPM logo](./assets/logo.svg) -# What is that? +> _Unofficial Typst package manager_ -UTPM is a package manager for [local](https://github.com/typst/packages#local-packages) and remote packages. -The goal is to manage packages to use the new feature of typst, [importing other packages from different folders](https://typst.app/docs/reference/scripting/#packages) +**UTPM** is a _package manager_ for **[local](https://github.com/typst/packages#local-packages)** and **[remote](https://github.com/typst/packages)** Typst packages. Quickly create and manage _projects_ and _templates_ on your system, and publish them directly to **Typst Universe**. -# How to use it? +[![Thumuss - utpm](https://img.shields.io/static/v1?label=Thumuss&message=utpm&color=blue&logo=github)](https://github.com/Thumuss/utpm "Go to GitHub repo") +[![stars - utpm](https://img.shields.io/github/stars/Thumuss/utpm?style=social)](https://github.com/Thumuss/utpm) +[![forks - utpm](https://img.shields.io/github/forks/Thumuss/utpm?style=social)](https://github.com/Thumuss/utpm) +
+[![GitHub tag](https://img.shields.io/github/tag/Thumuss/utpm?include_prereleases=&sort=semver&color=blue)](https://github.com/Thumuss/utpm/releases/) +[![License](https://img.shields.io/badge/License-MIT-blue)](#license) +[![issues - utpm](https://img.shields.io/github/issues/Thumuss/utpm)](https://github.com/Thumuss/utpm/issues) -You need two things, first create an `typst.toml` file by using `utpm create`: +
+ +## 🔥 Features +- [x] ✨Create packages rapidly (`utpm workspace create`) + - [x] ⏯️ Alias shorthand e.g. (`workspace = ws`) + - [x] ⌨️ Intuitive Clap CLI +- [x] 🛠 Manage existing packages (`utpm ws link --no-copy`) + - [x] 🔗 Link remote and local packages (`utpm workspace link`) + - [x] 🗄️ Delete and bulk delete your packages (`utpm pkg unlink`, `utpm pkg bulk-delete`) +- [x] 🌐 Dependencies outside of Typst! + - [x] 📦 Support for third party application and plugins + - [x] 🔒 Portable installer (limited for now) +- [x] 📃 Visualization + - [x] 🗃️ list `utpm pkg list` + - [x] 🌲 tree `utpm pkg tree` +- [ ] 🚀 Automated publication directly to Typst Universe! + +**_...And more soon!_** + +> [!WARNING] +> **UTPM** is still in active development, and some features may not be fully implemented. Contributions are welcome! + +
+ +## ⚡Install +### With cargo +Requires Cargo and Rust. ```bash -$ utpm create +$ cargo install --git https://github.com/Thumuss/utpm ``` -Modify this file to match your project and finally, you need to copy the directory to the "special" directory by using `utpm link`: +
+ + +### With nix + + + +#### Nix with flakes enabled : + +Get utpm for a bash session without installing it : ```bash -$ utpm link +$ nix shell github:Thumuss/utpm ``` -# Install +Or if you use NixOS or home-manager with a flake, install it permanently in your `flake.nix` or your modules : + +```nix +{ + inputs.utpm.url = "github:Thumuss/utpm"; + # ... + + outputs = { self, nixpkgs, ... }@inputs: { + # change `yourhostname` or `yourusername` to your actual hostname or username + nixosConfigurations.yourhostname = nixpkgs.lib.nixosSystem { #or homeConfigurations.yourusername + system = "x86_64-linux"; + modules = [ + # ... + { + environment.systemPackages = [ inputs.utpm.packages.${system}.default ]; #or home.packages + } + ]; + }; + }; +} +``` -You will need Cargo and Rust. +#### Nix without flakes : -Simpliest way : +Clone the repo and then nix-build into the utpm directory : ```bash -git clone https://github.com/Thumuss/utpm.git && -cd utpm && -cargo install --path . +git clone https://github.com/Thumuss/utpm.git +cd utpm +nix-build +./result/bin/utpm ``` +Utpm will be at ./result/bin/utpm -There is a `build.sh` to install/update the project. +
+
-# TODO: +
-See TODO.md +## 🎰 Usage +Further usage information can be found by running `utpm --help` or `utpm --help` on any of the sub commands. Documentation is still in progress, feel free to ask questions in the issues section. Currently the github documentation is pretty much a mirror of the help command. -# Contribution +``` +Usage: utpm [OPTIONS] + +Commands: + workspace Create, edit, delete your workspace for your package [aliases: ws] + packages use packages related to Typst [aliases: pkg] + generate Generate shell completions [aliases: gen] + help Print this message or the help of the given subcommand(s) + +Options: + -v, --verbose Gives you more information, permet debug + -h, --help Print help + -V, --version Print version +``` + +**Workspace** (ws): Manage Your Project Workspace +- `link (l)`: Link your project to existing directories. +- `create (c) (Deprecated)`: Creates a typst.toml file. Use init instead. +- `install (i)`: Install dependencies listed in typst.toml. +- `add (a)`: Add and install new dependencies. +- `delete (d)`: Remove specific dependencies. +- `init`: Initialize a new workspace for a Typst package. +- `publish (p) (WIP)`: Intended for publishing packages. +- `clone (WIP)`: Clone an existing workspace. + +**Packages** (pkg): Manage Typst Packages +- `tree (t)`: Display all packages in a directory as a tree. +- `list (l)`: List all packages in a directory in a flat list. +- `path (p)`: Show the path to the Typst packages folder. +- `unlink (u)`: Remove a previously installed package. +- `bulk-delete (bd)`: Delete multiple packages at once. + +**generate** (gen): Generate Shell Completions -If you want to help me dev this package, simply make an issue or a PR +
+ +
+ +## ❤️ Contribution + +If you want to help me develop this package, simply make an issue or a PR! By using this app, you contribute to it, thank you! <3 + +
diff --git a/TODO.md b/TODO.md deleted file mode 100644 index 0b0f8c1..0000000 --- a/TODO.md +++ /dev/null @@ -1,86 +0,0 @@ -# TODO list - -## V2: - -- [x] Reimpl errors -- [x] Last typst version -- [x] More commands: - - [x] Unlink - - [x] List -- [x] Create `typst.toml` by asking questions -- [x] use semver -- [x] Use custom packages namespace (e.g "@custom/example:1.0.1") -- [x] Fix typo - -## V2.1: - -- [X] ""pre-export"" package by giving them what they need -- [ ] Documentation for developpers - - [ ] utils.rs - - [ ] main.rs - - [ ] commands.rs → remake it? - - [ ] commands/create.rs - - [ ] commands/link.rs - - [ ] commands/list.rs - - [ ] commands/unlink.rs - - [ ] commands/install.rs -- [x] Download packages from unofficial repos, see #3 - - [x] git2-rs - - [x] Dependencies managed - - [x] use utpm namespace to use libs (or portable so without any links) → It wouldn't be as good as it sounds, typst can't use package outside the data folder - - [x] Maybe a launchable version from utpm to link packages? -- [x] Portable version and only installable version - - [x] Integrate install - - [x] And all of todos from above with #3 -- [ ] New commands for install: - - [ ] Info.rs - - [ ] Update, (using semver) - - [x] Bulk delete - - [ ] Clean? -- [ ] Maybe a listing dependencies system? -> Track every dependencies to delete when they aren't used -> Not for now -- [ ] Templates (first impl) -> Not now → V3 -- [ ] JSON only mode - -## V3 - -This update will introduce documentations, a better handling error system, JSON and some commands. - -- [x] Better handling errors (json, string, toml maybe) -- [ ] Maybe a listing dependencies system? -> Track every dependencies to delete when they aren't used -- [ ] Create a global and local configuration instead of using typst.toml file. It can become harder to -- [x] JSON only mode -- [x] Remake clap -- [ ] Documentation for developpers and users - - [ ] utils.rs - - [ ] main.rs - - [ ] commands.rs → remake it? - - [ ] commands/create.rs - - [ ] commands/link.rs - - [ ] commands/list.rs - - [ ] commands/unlink.rs - - [ ] commands/install.rs -- [ ] New commands for install: - - [ ] Info.rs -> Partial impl for now - - [ ] Update, (using semver) → \w listing dependencies - - [ ] Clean? - - -## V4 (2024.03.10) - -As this date, a new version of typst as been release (`v0.11.0-rc1 (fe94bd85)`) with a new system of template. -For now on, this version of `utpm` will focuse on adapting the new system and be compatible with the previous system. - -If time isn't running out, I'll add quality of life improvement such as a `Context` system, new commands to go along with the `typst init` command and Dockerise everything (kubernetes included). - -The main focus will be : -- [ ] Add templates in `utpm` -- [ ] Compatibility with older version of typst -- [ ] Fix current bugs - -If we got time, I'll add theses things: -- [ ] Docker, Compose and Kubernetes files (and examples) -- [ ] `Context`, it will change the actual structure of handling json and errors. -- [ ] ENV compatible. -- [ ] get along with `typst init` - -If you have any ideas to improve `utpm`, i'll take it <3 \ No newline at end of file diff --git a/assets/logo.svg b/assets/logo.svg new file mode 100644 index 0000000..1873689 --- /dev/null +++ b/assets/logo.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..efd1e31 --- /dev/null +++ b/build.rs @@ -0,0 +1,8 @@ +use shadow_rs::{self, BuildPattern, ShadowBuilder}; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + ShadowBuilder::builder() + .build_pattern(BuildPattern::RealTime) + .build().unwrap(); +} diff --git a/build.sh b/build.sh deleted file mode 100644 index 763cb7e..0000000 --- a/build.sh +++ /dev/null @@ -1,7 +0,0 @@ -if [ -d "utpm" ]; then - cd utpm - git pull origin main && - cargo install --path . --bin utpm -else - cargo install --git https://github.com/Thumuss/utpm.git --bin utpm -fi diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..85cb538 --- /dev/null +++ b/default.nix @@ -0,0 +1,13 @@ +(import + ( + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + nodeName = lock.nodes.root.inputs.flake-compat; + in + fetchTarball { + url = lock.nodes.${nodeName}.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.${nodeName}.locked.rev}.tar.gz"; + sha256 = lock.nodes.${nodeName}.locked.narHash; + } + ) + { src = ./.; } +).defaultNix diff --git a/examples/CLI/A/main.typ b/examples/CLI/A/main.typ deleted file mode 100644 index b8f36d3..0000000 --- a/examples/CLI/A/main.typ +++ /dev/null @@ -1 +0,0 @@ -#let var = "Hey I'm from main.typ!" \ No newline at end of file diff --git a/examples/CLI/B/result.typ b/examples/CLI/B/result.typ deleted file mode 100644 index 9811878..0000000 --- a/examples/CLI/B/result.typ +++ /dev/null @@ -1,3 +0,0 @@ -#import "@local/egcli:1.0.0": * - -#var \ No newline at end of file diff --git a/examples/CLI/README.md b/examples/CLI/README.md deleted file mode 100644 index 0a4c743..0000000 --- a/examples/CLI/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# CLI version - -An example of what can do UTPM. - -# Launch -Launch this in a terminal: -```bash -$ bash use.sh -``` \ No newline at end of file diff --git a/examples/CLI/use.sh b/examples/CLI/use.sh deleted file mode 100644 index 6b5a4c9..0000000 --- a/examples/CLI/use.sh +++ /dev/null @@ -1,5 +0,0 @@ -cd A -utpm create -ni --force --name egcli --version 1.0.0 -utpm link --force -cd ../B -typst c result.typ \ No newline at end of file diff --git a/examples/Interactive/A/main.typ b/examples/Interactive/A/main.typ deleted file mode 100644 index b8f36d3..0000000 --- a/examples/Interactive/A/main.typ +++ /dev/null @@ -1 +0,0 @@ -#let var = "Hey I'm from main.typ!" \ No newline at end of file diff --git a/examples/Interactive/B/result.typ b/examples/Interactive/B/result.typ deleted file mode 100644 index 9768a17..0000000 --- a/examples/Interactive/B/result.typ +++ /dev/null @@ -1,3 +0,0 @@ -#import "@local/egi:1.0.0": * - -#var \ No newline at end of file diff --git a/examples/Interactive/README.md b/examples/Interactive/README.md deleted file mode 100644 index 682b2a1..0000000 --- a/examples/Interactive/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# Interactive version - -An example of what can do UTPM.
-You need to interact here, just press enter and set the name `egi` when ask. -# Launch -Launch this in a terminal: -```bash -$ bash use.sh -``` \ No newline at end of file diff --git a/examples/Interactive/use.sh b/examples/Interactive/use.sh deleted file mode 100644 index 3beb9c9..0000000 --- a/examples/Interactive/use.sh +++ /dev/null @@ -1,5 +0,0 @@ -cd A -utpm create --force -utpm link --force -cd ../B -typst c result.typ \ No newline at end of file diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..42aba21 --- /dev/null +++ b/flake.lock @@ -0,0 +1,92 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1739936662, + "narHash": "sha256-x4syUjNUuRblR07nDPeLDP7DpphaBVbUaSoeZkFbGSk=", + "owner": "ipetkov", + "repo": "crane", + "rev": "19de14aaeb869287647d9461cbd389187d8ecdb7", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "flake-compat": { + "locked": { + "lastModified": 1733328505, + "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=", + "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec", + "revCount": 69, + "type": "tarball", + "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1740126099, + "narHash": "sha256-ozoOtE2hGsqh4XkTJFsrTkNxkRgShxpQxDynaPZUGxk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "32fb99ba93fea2798be0e997ea331dd78167f814", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..72d722c --- /dev/null +++ b/flake.nix @@ -0,0 +1,59 @@ +{ + description = "UTPM is a package manager for local and remote Typst packages."; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; + + crane.url = "github:ipetkov/crane"; + + flake-utils.url = "github:numtide/flake-utils"; + + flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"; + }; + + outputs = { self, ... }@inputs: + inputs.flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import inputs.nixpkgs { + inherit system; + }; + + craneLib = inputs.crane.mkLib pkgs; + src = ./.; + + cargoArtifacts = craneLib.buildDepsOnly { + inherit src; + buildInputs = [ pkgs.openssl ]; + nativeBuildInputs = [ pkgs.pkg-config ]; + OPENSSL_NO_VENDOR = 1; + }; + in + { + devShells.default = pkgs.mkShell { + inputsFrom = [ self.packages.${pkgs.system}.default ]; + packages = [ + #lsp + pkgs.rust-analyzer + ]; + }; + + packages = { + utpm = self.packages.${pkgs.system}.default; + + default = craneLib.buildPackage { + buildInputs = [ pkgs.openssl ]; + nativeBuildInputs = [ pkgs.pkg-config ]; + OPENSSL_NO_VENDOR = 1; + inherit cargoArtifacts src; + meta = { + homepage = "https://github.com/Thumuss/utpm"; + licence = pkgs.stdenv.lib.licences.MIT; + description = "UTPM is a package manager for local and remote Typst packages."; + longDescription = "UTPM is a package manager for local and remote Typst packages. Quickly create and manage projects and templates on your system, and publish them directly to Typst Universe."; + mainProgram = "utpm"; + }; + }; + }; + } + ); +} diff --git a/justfile b/justfile new file mode 100644 index 0000000..907032a --- /dev/null +++ b/justfile @@ -0,0 +1,36 @@ +# Aliases +alias b := build-release +alias n := build-nightly +alias u := upx +alias c := copy + +# Variables +builddir := "target/release/utpm" +buildndir := "target/debug/utpm" +bindir := "~/.cargo/bin/utpm" +tjust := "target/just" + +prepare: + mkdir -p {{tjust}} + +# Build UTPM release +build-release: format prepare + cargo build --release --bin utpm + cp {{builddir}} {{tjust}}/utpm + +# Build UTPM nightly +build-nightly: format prepare + cargo build --features nightly --bin utpm + cp {{builddir}} {{tjust}}/utpm + +# Copy utpm if exists. +copy: + cp {{tjust}}/utpm {{bindir}} + +# Compress +upx: + upx --best --lzma {{tjust}}/utpm + +# Format with cargo +format: + cargo fmt diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..ea7b69b --- /dev/null +++ b/shell.nix @@ -0,0 +1,13 @@ +(import + ( + let + lock = builtins.fromJSON (builtins.readFile ./flake.lock); + nodeName = lock.nodes.root.inputs.flake-compat; + in + fetchTarball { + url = lock.nodes.${nodeName}.locked.url or "https://github.com/edolstra/flake-compat/archive/${lock.nodes.${nodeName}.locked.rev}.tar.gz"; + sha256 = lock.nodes.${nodeName}.locked.narHash; + } + ) + { src = ./.; } +).shellNix diff --git a/src/commands.rs b/src/commands.rs index 3925cb8..5f9307b 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -1,17 +1,47 @@ // Linker +#[cfg(feature = "add")] +pub mod add; +#[cfg(feature = "bulk_delete")] pub mod bulk_delete; -pub mod create; -pub mod info; +#[cfg(feature = "clone")] +pub mod clone; +#[cfg(feature = "delete")] +pub mod delete; +#[cfg(feature = "generate")] +pub mod generate; +#[cfg(feature = "init")] +pub mod init; +#[cfg(feature = "install")] pub mod install; +#[cfg(feature = "link")] pub mod link; +#[cfg(feature = "list")] pub mod list; +#[cfg(feature = "path")] pub mod package_path; +#[cfg(feature = "publish")] +pub mod publish; +#[cfg(feature = "tree")] +pub mod tree; +#[cfg(feature = "unlink")] pub mod unlink; +#[cfg(any(feature = "clone", feature = "publish"))] +use std::path::PathBuf; + use clap::{Parser, Subcommand}; +#[cfg(feature = "generate")] +use clap_complete::Shell; +use tracing::level_filters::LevelFilter; + +#[cfg(feature = "init")] +use typst_project::manifest::{categories::Category, disciplines::Discipline}; + +use crate::build; -#[derive(Parser, Clone, Debug)] -pub struct CreateArgs { +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "init")] +pub struct InitArgs { /// Desactivate interactive session #[arg(short = 'm', long, requires = "ni")] cli: bool, @@ -34,6 +64,7 @@ pub struct CreateArgs { /// Authors of the project #[arg(short, long)] + #[clap(value_delimiter = ',')] authors: Option>, /// License @@ -54,6 +85,7 @@ pub struct CreateArgs { /// Keywords to find your project #[arg(short, long)] + #[clap(value_delimiter = ',')] keywords: Option>, /// Minimum compiler version @@ -62,18 +94,40 @@ pub struct CreateArgs { /// Excludes files #[arg(short = 'x', long)] + #[clap(value_delimiter = ',')] exclude: Option>, - /// Namespace + /// Namespace to put your package #[arg(short = 'N', long)] namespace: Option, - /// Populate + /// Add examples file to your projects. #[arg(short = 'p', long)] populate: bool, + + /// Add categories to your typst.toml + #[arg(short = 'C', long)] + #[clap(value_delimiter = ',')] + categories: Option>, + + /// Add disciplines to your typst.toml + #[arg(short = 'D', long)] + #[clap(value_delimiter = ',')] + disciplines: Option>, + + /// Add a link to your template. Example: "./template.typ" + #[arg(long, requires = "template")] + template_path: Option, + + #[arg(long, requires = "template")] + template_entrypoint: Option, + + #[arg(long)] + template_thumbnail: Option, } -#[derive(Parser, Clone, Debug)] +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "link")] pub struct LinkArgs { /// Force the copy of the dir / creation of the symlink #[arg(short, long)] @@ -84,31 +138,108 @@ pub struct LinkArgs { pub no_copy: bool, } -#[derive(Parser, Clone, Debug)] -pub struct UnlinkArgs { - /// The name of the package - name: Option, - - /// Namespace, where your packages are install (default local) +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(any(feature = "list", feature = "tree"))] +pub struct ListTreeArgs { + /// Will list all packages including @preview #[arg(short, long)] - namespace: Option, + pub all: bool, - /// Do you want to delete the namespace or not - #[arg(short, long)] - delete_namespace: bool, + /// List all subdirectory you want + #[arg(short, long, num_args = 1..)] + pub include: Option>, +} - /// The version you want to delete, if nothing has been provided it will be the whole package - #[arg(short, long)] - version: Option, +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "publish")] +pub struct PublishArgs { + #[arg()] + path: Option, + + /// Add rules of .ignore files to the check + #[arg(short = 'i', default_value_t = false)] + ignore: bool, + + #[arg(short = 'g', default_value_t = true)] + git_ignore: bool, + + #[arg(short = 't', default_value_t = true)] + typst_ignore: bool, + + #[arg(short = 'G', default_value_t = true)] + git_global_ignore: bool, + + #[arg(short = 'x', default_value_t = true)] + git_exclude: bool, + + /// Bypass the warning + #[arg(default_value_t = false)] + bypass_warning: bool, + + #[arg(short = 'c')] + custom_ignore: Option, + + /// Specify a message for the new commit. + #[arg(short = 'm')] + message: Option, + + /// Won't create a PR on typst/packages + #[arg(short = 'p', default_value_t = false)] + prepare_only: bool, +} + +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "generate")] +pub struct GenerateArgs { + /// The type of your shell + #[arg(value_enum)] + generator: Shell, +} + +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "clone")] +pub struct CloneArgs { + /// The name of the package you want to clone + #[arg()] + pub package: String, + + /// Path to your dir + #[arg()] + pub path: Option, + + /// Download the package without copying it. + #[arg(short = 'd')] + pub download_only: bool, + + /// Continue without veryfing anything. + #[arg(short = 'f')] + pub force: bool, + + /// Force the redownload of the package. + #[arg(short = 'r')] + pub redownload: bool, + + /// Create a symlink to the package clone (similar to link --no-copy) + #[arg(short = 's')] + pub symlink: bool, +} + +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "unlink")] +pub struct UnlinkArgs { + /// The name of the package + package: String, /// Confirm the deletion of a dir #[arg(short, long)] yes: bool, } -#[derive(Parser, Clone, Debug)] +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "bulk_delete")] pub struct BulkDeleteArgs { /// Names of your packages, use version with this syntax: mypackage:1.0.0 + #[clap(value_delimiter = ',')] names: Vec, /// The namespace you want to bulk-delete @@ -116,16 +247,11 @@ pub struct BulkDeleteArgs { namespace: Option, } -#[derive(Parser, Clone, Debug)] -pub struct InfoArgs { - /// The repository you want to check - #[arg(short, long)] - url: Option, -} - -#[derive(Parser, Clone, Debug)] +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "install")] pub struct InstallArgs { /// If you want to install a specific package + #[arg(num_args = 1..)] pub url: Option, /// Passed force to all link commands @@ -133,37 +259,159 @@ pub struct InstallArgs { pub force: bool, } -#[derive(Subcommand, Debug)] -pub enum Commands { - /// Create a file for your project (typst.toml) - Create(CreateArgs), - /// Link your project to your dirs - Link(LinkArgs), - /// List all of the package in the local folder - List, - /// Display path to typst packages folder - PackagesPath, +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "delete")] +pub struct DeleteArgs { + /// URIs to remove. + pub uri: Vec, +} + +#[derive(Parser, Clone, Debug, PartialEq)] +#[cfg(feature = "add")] +pub struct AddArgs { + /// The url or path of your repository. + pub uri: Vec, +} + +/// Commands to use packages related to typst +#[derive(Subcommand, Debug, PartialEq)] +#[cfg(any( + feature = "tree", + feature = "list", + feature = "path", + feature = "unlink", + feature = "bulk_delete" +))] +pub enum Packages { + /// List all of packages from your dir, in a form of a tree + #[command(visible_alias = "t")] + #[cfg(feature = "tree")] + Tree(ListTreeArgs), + + /// List all of packages from your dir, in a form of a list + #[command(visible_alias = "l")] + #[cfg(feature = "list")] + List(ListTreeArgs), - Info(InfoArgs), + /// Display path to typst packages folder + #[command(visible_alias = "p")] + #[cfg(feature = "path")] + Path, /// Delete package previously install with utpm + #[command(visible_alias = "u")] + #[cfg(feature = "unlink")] Unlink(UnlinkArgs), - /// Delete a bunch of packages + /// Delete multiple packages/namespace at once + #[command(visible_alias = "bd")] + #[cfg(feature = "bulk_delete")] BulkDelete(BulkDeleteArgs), +} + +/// Commands to create, edit, delete your workspace for your package. +#[derive(Subcommand, Debug, PartialEq)] +#[cfg(any( + feature = "link", + feature = "init", + feature = "install", + feature = "add", + feature = "delete", + feature = "init", + feature = "publish", + feature = "clone" +))] +pub enum Workspace { + /// Link your project to your dirs + #[command(visible_alias = "l")] + #[cfg(feature = "link")] + Link(LinkArgs), /// Install all dependencies from the `typst.toml` + #[command(visible_alias = "i")] + #[cfg(feature = "install")] Install(InstallArgs), + + /// Add dependencies and then install them + #[command(visible_alias = "a")] + #[cfg(feature = "add")] + Add(AddArgs), + + /// Delete dependencies + #[command(visible_alias = "d")] + #[cfg(feature = "delete")] + Delete(DeleteArgs), + + /// Create your workspace to start a typst package + #[cfg(feature = "init")] + Init(InitArgs), + + /// Publish directly your packages to typst universe. (WIP) + // #[command(visible_alias = "p")] + // #[cfg(feature = "publish")] + // Publish(PublishArgs), + + /// Clone like a git clone packages from typst universe or your local directory + #[command()] + #[cfg(feature = "clone")] + Clone(CloneArgs), +} + +#[derive(Subcommand, Debug, PartialEq)] +pub enum Commands { + #[command(subcommand)] + #[command(visible_alias = "ws")] + #[cfg(any( + feature = "link", + feature = "init", + feature = "install", + feature = "add", + feature = "delete", + feature = "init", + feature = "publish", + feature = "clone" + ))] + Workspace(Workspace), + + #[command(subcommand)] + #[command(visible_alias = "pkg")] + #[cfg(any( + feature = "tree", + feature = "list", + feature = "path", + feature = "unlink", + feature = "bulk_delete" + ))] + Packages(Packages), + + /// Generate shell completion + #[command(visible_alias = "gen")] + #[cfg(feature = "generate")] + Generate(GenerateArgs), +} + +#[derive(Parser, Debug, PartialEq)] +#[cfg(feature = "nightly")] +#[command(author = "Thumus", version = build::COMMIT_HASH)] +/// An unofficial typst package manager for your projects. +pub struct Cli { + #[command(subcommand)] + pub command: Commands, + + /// Gives you more information, permit debug. + #[arg(short = 'v', long)] + pub verbose: Option, } -#[derive(Parser)] -#[command(author = "Thumus", version = "2.1.0")] +#[derive(Parser, Debug, PartialEq)] +#[cfg(not(feature = "nightly"))] +#[command(author = "Thumus", version = build::PKG_VERSION)] /// An unofficial typst package manager for your projects. pub struct Cli { #[command(subcommand)] pub command: Commands, - /// Output everything into a json format. Available on every commands. - #[arg(short = 'j', long, global = true)] - pub json: bool, + /// Gives you more information, permit debug. + #[arg(short = 'v', long)] + pub verbose: Option, } diff --git a/src/commands/add.rs b/src/commands/add.rs new file mode 100644 index 0000000..bb56d02 --- /dev/null +++ b/src/commands/add.rs @@ -0,0 +1,83 @@ +use std::{collections::BTreeMap, fs}; + +use toml::map::Map; +use tracing::{debug, instrument, trace}; +use typst_project::manifest::{tool::Tool, Manifest}; + +use crate::{ + load_manifest, + utils::{ + paths::get_current_dir, + specs::Extra, + state::{Error, ErrorKind, Result}, + }, + write_manifest, +}; + +use super::{install, AddArgs, InstallArgs}; + +#[instrument] +pub fn run(cmd: &mut AddArgs) -> Result { + let mut config: Manifest = load_manifest!(); + if cmd.uri.len() == 0 { + debug!("0 URI found in cmd.uri"); + return Err(Error::new( + ErrorKind::NotEnoughArgs, + "uri needs more than 0 arguments.", + )); + } + + debug!("{} URIs found: {}", cmd.uri.len(), cmd.uri.join(", ")); + if let Some(mut tool) = config.clone().tool { + trace!("- tool section found"); + if let Some(ex) = tool.keys.get("utpm") { + trace!("- utpm section found in tool"); + let mut extra: Extra = toml::from_str(toml::to_string(ex)?.as_str())?; //Todo: change this hack + trace!("hacky conversion done"); + if let Some(mut dependencies) = extra.dependencies.clone() { + trace!("- dependencies found, adding uris"); + for e in &cmd.uri { + match dependencies.iter().position(|x| x == e) { + Some(_) => { + trace!("{} dependency already in the load_manifest skipping", e); + } + None => { + trace!("{} added", e); + dependencies.push(e.clone()) + } + }; + } + extra.dependencies = Some(dependencies); + } else { + extra.dependencies = Some(cmd.uri.clone()); + } + tool.keys.insert("utpm".to_string(), Map::try_from(extra)?); + } else { + tool.keys.insert( + "utpm".to_string(), + toml::from_str( + toml::to_string(&Extra::new(None, Some(cmd.uri.clone()), None))?.as_str(), + )?, + ); + } + config.tool = Some(tool); + } else { + let mut keys = BTreeMap::new(); + keys.insert( + "utpm".to_string(), + toml::from_str( + toml::to_string(&Extra::new(None, Some(cmd.uri.clone()), None))?.as_str(), + )?, + ); + config.tool = Some(Tool { keys }); + } + + write_manifest!(&config); + + install::run(&InstallArgs { + force: false, + url: None, + })?; + + Ok(true) +} diff --git a/src/commands/bulk_delete.rs b/src/commands/bulk_delete.rs index 2f38316..451f064 100644 --- a/src/commands/bulk_delete.rs +++ b/src/commands/bulk_delete.rs @@ -1,44 +1,31 @@ -use serde_json::json; +use tracing::{error, info, instrument}; -use crate::utils::state::{Error, ResponseKind::*, Responses, Result}; +use crate::utils::state::{Error, Result}; use super::{unlink, BulkDeleteArgs, UnlinkArgs}; -pub fn run(cmd: &BulkDeleteArgs, res: &mut Responses) -> Result { +#[instrument] +pub fn run(cmd: &BulkDeleteArgs) -> Result { let mut vec: Vec = Vec::new(); for name in &cmd.names { - let name_and_version = name - .split(":") - .map(|a| a.to_string()) - .collect::>(); - let ulnk = UnlinkArgs { - delete_namespace: false, - name: Some(name_and_version[0].to_owned()), + match unlink::run(&UnlinkArgs { + package: name.into(), yes: true, - namespace: cmd.namespace.to_owned(), - version: if name_and_version.len() > 1 { - Some(semver::Version::parse(name_and_version[1].as_str()).unwrap()) - } else { - None - }, - }; - match unlink::run(&ulnk, res) { - Ok(_) => (), + }) { + Ok(_) => { + info!("- {name} deleted"); + } Err(err) => { + info!("X {name} not found"); + error!("{err}"); vec.push(err); } }; } - res.pushs(vec![ - Value(json!({ - "success": cmd.names.len() - vec.len(), - "failed": vec.len(), - })), - Message(format!( - "{}/{} successful", - cmd.names.len() - vec.len(), - cmd.names.len() - )), - ]); + println!( + "{}/{} successful", + cmd.names.len() - vec.len(), + cmd.names.len() + ); Ok(true) } diff --git a/src/commands/clone.rs b/src/commands/clone.rs new file mode 100644 index 0000000..3a3727d --- /dev/null +++ b/src/commands/clone.rs @@ -0,0 +1,128 @@ +use std::path::PathBuf; + +use tracing::{debug, error, info, instrument, warn}; +use typst_kit::{download::Downloader, package::PackageStorage}; + +use crate::utils::regex_package; +use crate::{build, utils::ProgressPrint}; + +use crate::utils::{ + copy_dir_all, + paths::{c_packages, check_path_dir, d_packages, get_current_dir, has_content}, + state::{Error, ErrorKind, Result}, + symlink_all, +}; + +use typst_syntax::package::{PackageSpec, PackageVersion}; + +use super::CloneArgs; + +use regex::Regex; + +#[instrument] +pub fn run(cmd: &CloneArgs) -> Result { + let path: PathBuf = if let Some(path) = &cmd.path { + path.clone() + } else { + get_current_dir()?.into() + }; + if has_content(&path)? { + debug!("found content"); + if cmd.force { + warn!("force used, ignore content"); + } else { + return Err(Error::new( + ErrorKind::ContentFound, + "Content found, cancelled", + )); + } + } + let re: Regex = regex_package(); + let package: &String = &cmd.package; + if let Some(cap) = re.captures(package) { + let (_, [namespace, package, major, minor, patch]) = cap.extract(); + let val = format!( + "{}/{namespace}/{package}/{major}.{minor}.{patch}", + if namespace == "preview" { + info!("preview found, cache dir use"); + c_packages()? + } else { + info!("no preview found, data dir use"); + d_packages()? + } + ); + if check_path_dir(&val) { + if cmd.download_only { + info!("download only, nothing to do."); + return Ok(true); + } + if !cmd.redownload || namespace != "preview" { + info!( + namespace = namespace, + redownload = cmd.redownload, + "Skip download..." + ); + if cmd.symlink { + symlink_all(val, path)?; + info!("symlinked!"); + } else { + copy_dir_all(val, path)?; + info!("copied!"); + } + return Ok(true); + } + } + + if cmd.redownload {} + + let pkg_sto = PackageStorage::new( + Some(c_packages()?.into()), + Some(d_packages()?.into()), + Downloader::new(format!("utpm/{}", build::COMMIT_HASH)), + ); + let printer = &mut ProgressPrint {}; + //todo: redownload = rm dir; + return match pkg_sto.prepare_package( + &PackageSpec { + namespace: namespace.into(), + name: package.into(), + version: PackageVersion { + major: major.parse::().unwrap(), + minor: minor.parse::().unwrap(), + patch: patch.parse::().unwrap(), + }, + }, + printer, + ) { + Ok(val) => { + info!(path = val.to_str().unwrap(), "package downloaded"); + if cmd.download_only { + debug!("download complete, nothing to do"); + return Ok(true); + } + + if cmd.symlink { + symlink_all(val, path)?; + info!("symlinked!"); + } else { + copy_dir_all(val, path)?; + info!("copied!"); + } + + Ok(true) + } + Err(_) => { + return Err(Error::new( + ErrorKind::PackageNotExist, + "This package doesn't exist. Verify on https://typst.app/universe to see if the package exist and/or the version is correct.", + )); + } + }; + } else { + error!("package not found, input: {}", package); + return Err(Error::new( + ErrorKind::PackageNotValid, + "Can't extract your package. Example of a package: @namespace/package:1.0.0", + )); + } +} diff --git a/src/commands/create.rs b/src/commands/create.rs deleted file mode 100644 index 9cbfc8d..0000000 --- a/src/commands/create.rs +++ /dev/null @@ -1,209 +0,0 @@ -use std::{ - fs::{create_dir_all, File}, - io::Write, -}; - -use inquire::{required, validator::Validation, Confirm, Text}; -use owo_colors::OwoColorize; -use semver::Version; - -use crate::utils::{ - paths::{check_path_file, get_current_dir}, - state::{ResponseKind::*, Responses, Result}, - Extra, Package, TypstConfig, -}; - -use super::CreateArgs; - -pub fn run(cmd: &CreateArgs, res: &mut Responses) -> Result { - let curr = get_current_dir()?; - let typ = curr.clone() + "/typst.toml"; - - let mut extra = Extra::new(); - extra.namespace = cmd.namespace.to_owned(); - - let mut pkg = Package { - name: cmd.name.to_owned().unwrap_or("temp".into()), - version: cmd.version.to_owned(), - entrypoint: cmd.entrypoint.to_owned(), - authors: cmd.authors.to_owned(), - license: cmd.license.to_owned(), - description: cmd.description.to_owned(), - repository: cmd.repository.to_owned(), - homepage: cmd.homepage.to_owned(), - keywords: cmd.keywords.to_owned(), - compiler: cmd.compiler.to_owned(), - exclude: cmd.exclude.to_owned(), - }; - - if check_path_file(&typ) && !cmd.force { - res.push(Message("Nothing to do".into())); - return Ok(false); - } - - if cmd.force { - res.push(Message(format!( - "{} {}", - "WARNING:".bold().yellow(), - "--force is a dangerous flag, use it cautiously".bold() - ))); - } - - if !cmd.cli { - let public = Confirm::new("Do you want to make your package public? Questions are on authors, license, description").prompt()?; - let more = public && Confirm::new("Do you want more questions to customise your package? Questions are on repository url, homepage url, keywords, compiler version, excluded files").prompt()?; - let extra_opts = Confirm::new( - "Do you want to specify informations of utpm? Questions are on the namespace", - ) - .prompt()?; - - pkg.name = Text::new("Name: ") - .with_validator(required!("This field is required")) - .with_help_message("e.g. my_example") - .prompt()?; - - pkg.version = Version::parse( - Text::new("Version: ") - .with_validator(required!("This field is required")) - .with_validator(&|obj: &str| { - return match Version::parse(&obj) { - Ok(_) => Ok(Validation::Valid), - Err(_) => Ok(Validation::Invalid( - "A correct version must be types (check semVer)".into(), - )), - }; - }) - .with_help_message("e.g. 1.0.0 (SemVer)") - .with_default("1.0.0") - .prompt()? - .as_str(), - )?; - - pkg.entrypoint = Text::new("Entrypoint: ") - .with_validator(required!("This field is required")) - .with_help_message("e.g. main.typ") - .with_default("main.typ") - .prompt()?; - - if public { - pkg.authors = Some( - Text::new("Authors: ") - .with_help_message("e.g. Thumus,Somebody,Somebody Else") - .prompt()? - .split(",") - .map(|f| f.to_string()) - .collect::>(), - ); - - pkg.license = Some( - Text::new("License: ") - .with_help_message("e.g. MIT") - .with_default("Unlicense") - .with_validator(&|obj: &str| match spdx::Expression::parse(obj) { - Ok(val) => { - for x in val.requirements() { - let id = x.req.license.id().unwrap(); - if !id.is_osi_approved() { - return Ok(Validation::Invalid( - "It must be an OSI approved!".into(), - )); - } - } - Ok(Validation::Valid) - } - Err(_) => Ok(Validation::Invalid("Can't parse your expression".into())), - }) - .prompt()?, - ); - - pkg.description = Some( - Text::new("description: ") - .with_help_message("e.g. A package") - .prompt()?, - ); - } - if more { - pkg.repository = Some( - Text::new("URL of the repository: ") - .with_help_message("e.g. https://github.com/Thumuss/utpm") - .prompt()?, - ); - pkg.homepage = Some( - Text::new("Homepage: ") - .with_help_message("e.g. anything") - .prompt()?, - ); - pkg.keywords = Some( - Text::new("Keywords: ") - .with_help_message("e.g. Typst,keyword") - .prompt()? - .split(",") - .map(|f| f.to_string()) - .collect::>(), - ); - pkg.compiler = Some(Version::parse( - Text::new("Compiler version required: ") - .with_help_message("e.g. 0.7.0") - .with_validator(&|obj: &str| { - return match Version::parse(&obj) { - Ok(_) => Ok(Validation::Valid), - Err(_) => Ok(Validation::Invalid( - "A correct version must be types (check semVer)".into(), - )), - }; - }) - .prompt()? - .as_str(), - )?); - pkg.exclude = Some( - Text::new("Exclude: ") - .with_help_message("e.g. backup/mypassword.txt,.env") - .prompt()? - .split(",") - .filter(|f| f.len() > 0) - .map(|f| f.to_string()) - .collect::>(), - ); - } - - if extra_opts { - extra.namespace = Some( - Text::new("Namespace: ") - .with_help_message("e.g. backup/mypassword.txt,.env") - .with_default("local") - .prompt()? - .to_string(), - ) - } - } - - if cmd.populate { - let mut file = File::create(curr.clone() + "/README.md")?; // README.md - file.write_all(("# ".to_string() + pkg.name.clone().as_str()).as_bytes())?; - if let Some(license) = &pkg.license { - if let Some(exp) = spdx::license_id(license.as_str()) { - file = File::create(curr.clone() + "/LICENSE")?; // LICENSE - file.write_all(exp.text().as_bytes())?; - } - } - create_dir_all(curr.clone() + "/examples")?; // examples - let examples = curr.clone() + "/examples"; - file = File::create(examples + "/tests.typ")?; // examples/texts.typ - let fm = format!( - "#import \"@{}/{}:{}\": *\nDo...", - extra.namespace.clone().unwrap_or("preview".to_string()), - pkg.name.clone(), - pkg.version.clone().to_string() - ); - file.write_all(fm.as_bytes())?; - file = File::create(pkg.entrypoint.clone())?; // main.typ - file.write_all(b"// This file is generated by UTPM (https://github.com/Thumuss/utpm)")?; - } - - TypstConfig::new(pkg, extra).write(&typ); // typst.toml - res.push(Message(format!( - "{}", - "File created to {typ}".bold().to_string() - ))); - Ok(true) -} diff --git a/src/commands/delete.rs b/src/commands/delete.rs new file mode 100644 index 0000000..c7790be --- /dev/null +++ b/src/commands/delete.rs @@ -0,0 +1,46 @@ +use std::fs; + +use toml::map::Map; +use tracing::instrument; +use typst_project::manifest::Manifest; + +use crate::{ + load_manifest, + utils::{ + paths::get_current_dir, + specs::Extra, + state::{Error, ErrorKind, Result}, + }, + write_manifest, +}; + +use super::DeleteArgs; + +#[instrument(skip(cmd))] +pub fn run(cmd: &mut DeleteArgs) -> Result { + let mut config = load_manifest!(); + + if let Some(mut tool) = config.clone().tool { + if let Some(ex) = tool.keys.get("utpm") { + let mut extra: Extra = toml::from_str(toml::to_string(ex)?.as_str())?; //Todo: change this hack + if let Some(mut dep) = extra.clone().dependencies { + for e in &cmd.uri { + match dep.iter().position(|x| x == e) { + Some(val) => { + dep.remove(val); + println!("Removed"); + } + None => println!("Can't remove it"), + }; + } + extra.dependencies = Some(dep); + tool.keys.insert("utpm".to_string(), Map::try_from(extra)?); + } + } + config.tool = Some(tool); + } + + write_manifest!(&config); + + Ok(true) +} diff --git a/src/commands/generate.rs b/src/commands/generate.rs new file mode 100644 index 0000000..2cc9d60 --- /dev/null +++ b/src/commands/generate.rs @@ -0,0 +1,22 @@ +use std::io; + +use clap::{Command, CommandFactory}; +use clap_complete::{generate, Generator}; +use tracing::instrument; + +use crate::utils::state::Result; + +use super::{Cli, GenerateArgs}; + +fn print_completions(gen: G, cmd: &mut Command) { + generate(gen, cmd, cmd.get_name().to_string(), &mut io::stdout()); +} + +#[instrument(skip(cmd))] +pub fn run(cmd: &GenerateArgs) -> Result { + let generator = cmd.generator; + let mut cmd: Command = Cli::command(); + eprintln!("Generating completion file for {generator:?}..."); + print_completions(generator, &mut cmd); + Ok(true) +} diff --git a/src/commands/info.rs b/src/commands/info.rs deleted file mode 100644 index d0ce5d7..0000000 --- a/src/commands/info.rs +++ /dev/null @@ -1,89 +0,0 @@ -use std::{env, path::Path}; - -use crate::utils::{ - paths::{check_path_file, current_package, get_ssh_dir}, - state::{Error, ErrorKind, ResponseKind, Responses, Result}, - TypstConfig, -}; -use git2::{Cred, Remote, RemoteCallbacks, Repository}; -use owo_colors::OwoColorize; - -use super::InfoArgs; - -pub fn run(cmd: &InfoArgs, res: &mut Responses) -> Result { - let path = cmd.url.clone().unwrap_or(current_package()?); - if !check_path_file(&path) { - return Err(Error::empty(ErrorKind::ConfigFile)); - } - - let config = TypstConfig::load(&path); - if let Some(utpm) = config.utpm { - for e in utpm.dependencies.unwrap_or(vec![]) { - if e.starts_with(".") { - match Repository::open(&e) { - Ok(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "✔️".green().bold(), - e - ))), - Err(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "❌".red().bold(), - e - ))), - }; - } else if (&e).starts_with("http") { - let mut remote = Remote::create_detached(e.clone())?; - - match remote.connect(git2::Direction::Fetch) { - Ok(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "✔️".green().bold(), - e - ))), - Err(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "❌".red().bold(), - e - ))), - }; - } else if e.starts_with("git") { - let sshpath = get_ssh_dir()?; - let ed = sshpath.clone() + "/id_ed25519"; - let rsa = sshpath + "/id_rsa"; - let val = if check_path_file(&ed) { ed } else { rsa }; - let mut remote = Remote::create_detached(e.clone())?; - let mut callbacks = RemoteCallbacks::new(); - callbacks.credentials(|_, username_from_url, _| { - match Cred::ssh_key_from_agent(username_from_url.unwrap_or("git")) { - Ok(cred) => Ok(cred), - Err(_) => Cred::ssh_key( - username_from_url.unwrap_or("git"), - None, - Path::new(&val), - Some( - env::var("UTPM_PASSPHRASE") - .unwrap_or(String::new()) - .as_str(), - ), - ), - } - }); - match remote.connect_auth(git2::Direction::Fetch, Some(callbacks), None) { - Ok(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "✔️".green().bold(), - e - ))), - Err(_) => res.push(ResponseKind::Message(format!( - "{}: {}", - "❌".red().bold(), - e - ))), - }; - } - } - } - - Ok(true) -} diff --git a/src/commands/init.rs b/src/commands/init.rs new file mode 100644 index 0000000..8ea902e --- /dev/null +++ b/src/commands/init.rs @@ -0,0 +1,328 @@ +use std::{ + collections::{BTreeMap, HashSet}, + fs::{self, create_dir_all, File}, + io::Write, + path::PathBuf, + str::FromStr, +}; + +use inquire::{required, validator::Validation, Select, Text}; +use semver::Version; +use toml::Table; +use tracing::{info, instrument, trace, warn}; +use typst_project::{ + heuristics::MANIFEST_FILE, + manifest::{ + author::{Author, Website}, + categories::Category, + disciplines::Discipline, + ident::Ident, + license::License, + package::Package, + tool::Tool, + Manifest, + }, +}; + +use crate::{ + utils::{ + paths::{check_path_file, get_current_dir}, + specs::Extra, + state::Result, + }, + write_manifest, +}; + +use super::InitArgs; + +#[instrument(skip(cmd))] +pub fn run(cmd: &mut InitArgs) -> Result { + let curr = get_current_dir()?; + info!("Current dir: {}", curr); + let typ = curr.clone() + "/" + MANIFEST_FILE; + info!("Current typst file: {}", typ); + + let mut extra = Extra::default(); + extra.namespace = cmd.namespace.to_owned(); + trace!( + "Namespace extracted? {}", + if extra.namespace.is_none() { + "no".into() + } else { + format!("yes: {}", extra.namespace.clone().unwrap()) + } + ); + let mut authors: HashSet = HashSet::new(); + // temp + if let Some(auts) = &cmd.authors { + trace!("Authors extracted from cli"); + for e in auts { + authors.insert(Author::from_str(&e)?); + } + } + + let mut keywords: HashSet = HashSet::new(); + // temp + if let Some(auts) = &cmd.keywords { + trace!("Keywords extracted from cli"); + for e in auts { + keywords.insert(e.clone()); + } + } + + let mut exclude: HashSet = HashSet::new(); + // temp + if let Some(auts) = &cmd.exclude { + trace!("Exclude extracted from cli"); + for e in auts { + exclude.insert(e.into()); + } + } + + let mut categories: HashSet = HashSet::new(); + // temp + if let Some(auts) = &cmd.categories { + trace!("Catgories extracted from cli"); + + for e in auts { + categories.insert(*e); + } + } + + let mut disciplines: HashSet = HashSet::new(); + // temp + if let Some(auts) = &cmd.disciplines { + trace!("Disciplines extracted from cli"); + for e in auts { + disciplines.insert(*e); + } + } + + let mut pkg = Package { + name: Ident::from_str(if let Some(name) = &cmd.name { + name.as_str() + } else { + "temp" + })?, + version: cmd.version.to_owned(), + entrypoint: cmd.entrypoint.to_owned().into(), + authors, + license: License::from_str(if let Some(license) = &cmd.license { + license.as_str() + } else { + "MIT" + })?, + description: cmd.description.to_owned().unwrap_or("".into()), + repository: if let Some(repository) = &cmd.repository { + Some(Website::from_str(repository.as_str())?) + } else { + None + }, + homepage: if let Some(homepage) = &cmd.homepage { + Some(Website::from_str(homepage.as_str())?) + } else { + None + }, + keywords, + compiler: cmd.compiler.to_owned(), + exclude, + categories, + disciplines, + }; + + //let mut tmpl: Template = Template::new(cmd.template, entrypoint, thumbnail) + + if check_path_file(&typ) && !cmd.force { + return Ok(false); + } + + if cmd.force { + warn!("--force is a dangerous flag, use it cautiously"); + } + + if !cmd.cli { + let choice = vec!["yes", "no"]; + let public = Select::new("Do you want to make your package public? Questions are on authors, license, description", choice.clone()).prompt()?; + let more = Select::new("Do you want more questions to customise your package? Questions are on repository url, homepage url, keywords, compiler version, excluded files, categories and disciplines", choice.clone()).prompt()?; + let extra_opts = Select::new( + "Do you want to specify informations of utpm? Questions are on the namespace", + choice.clone(), + ) + .prompt()?; + let template = Select::new("Do you want to create a template?", choice.clone()).prompt()?; + let popu = Select::new( + "Do you want to populate your package? Files like index.typ will be created", + choice, + ) + .prompt()?; + + if popu == "yes" { + cmd.populate = true; + } + + pkg.name = Ident::from_str( + Text::new("Name: ") + .with_validator(required!("This field is required")) + .with_help_message("e.g. my_example") + .prompt()? + .as_str(), + )?; + + pkg.version = Version::parse( + Text::new("Version: ") + .with_validator(required!("This field is required")) + .with_validator(&|obj: &str| { + return match Version::parse(&obj) { + Ok(_) => Ok(Validation::Valid), + Err(_) => Ok(Validation::Invalid( + "A correct version must be types (check semVer)".into(), + )), + }; + }) + .with_help_message("e.g. 1.0.0 (SemVer)") + .with_default("1.0.0") + .prompt()? + .as_str(), + )?; + + pkg.entrypoint = PathBuf::from( + Text::new("Entrypoint: ") + .with_validator(required!("This field is required")) + .with_help_message("e.g. main.typ") + .with_default("main.typ") + .prompt()?, + ); + + if public == "yes" { + pkg.authors = Text::new("Authors: ") + .with_help_message("e.g. Thumus,Somebody,Somebody Else") + .prompt()? + .split(",") + .map(|f| Author::from_str(f.to_string().as_str()).unwrap()) + .collect::>(); + + pkg.license = License::from_str( + Text::new("License: ") + .with_help_message("e.g. MIT") + .with_default("Unlicense") + .with_validator(&|obj: &str| match spdx::Expression::parse(obj) { + Ok(val) => { + for x in val.requirements() { + let id = x.req.license.id().unwrap(); + if !id.is_osi_approved() { + return Ok(Validation::Invalid( + "It must be an OSI approved!".into(), + )); + } + } + Ok(Validation::Valid) + } + Err(_) => Ok(Validation::Invalid("Can't parse your expression".into())), + }) + .prompt()? + .as_str(), + )?; + + pkg.description = Text::new("description: ") + .with_help_message("e.g. A package") + .prompt()?; + } + if more == "yes" { + pkg.repository = Some(Website::from_str( + Text::new("URL of the repository: ") + .with_help_message("e.g. https://github.com/Thumuss/utpm") + .prompt()? + .as_str(), + )?); + pkg.homepage = Some(Website::from_str( + Text::new("Homepage: ") + .with_help_message("e.g. anything") + .prompt()? + .as_str(), + )?); + pkg.keywords = Text::new("Keywords: ") + .with_help_message("e.g. Typst,keyword") + .prompt()? + .split(",") + .map(|f| f.to_string()) + .collect::>(); + + pkg.compiler = Some(Version::parse( + Text::new("Compiler version required: ") + .with_help_message("e.g. 0.7.0") + .with_validator(&|obj: &str| { + return match Version::parse(&obj) { + Ok(_) => Ok(Validation::Valid), + Err(_) => Ok(Validation::Invalid( + "A correct version must be types (check semVer)".into(), + )), + }; + }) + .prompt()? + .as_str(), + )?); + pkg.exclude = Text::new("Exclude: ") + .with_help_message("e.g. backup/mypassword.txt,.env") + .prompt()? + .split(",") + .filter(|f| f.len() > 0) + .map(|f| PathBuf::from_str(f).unwrap()) + .collect::>(); + } + + if extra_opts == "yes" { + extra.namespace = Some( + Text::new("Namespace: ") + .with_help_message("e.g. backup/mypassword.txt,.env") + .with_default("local") + .prompt()? + .to_string(), + ) + } + + if template == "yes" { + //todo + } + } + + if cmd.populate { + let mut file = File::create(curr.clone() + "/README.md")?; // README.md + file.write_all(("# ".to_string() + &pkg.name.clone()).as_bytes())?; + if let Some(exp) = spdx::license_id(pkg.license.to_string().as_str()) { + file = File::create(curr.clone() + "/LICENSE")?; // LICENSE + file.write_all(exp.text().as_bytes())?; + } + + create_dir_all(curr.clone() + "/examples")?; // examples + let examples = curr.clone() + "/examples"; + file = File::create(examples + "/tests.typ")?; // examples/texts.typ + let fm = format!( + "#import \"@{}/{}:{}\": *\nDo...", + extra.namespace.clone().unwrap_or("preview".to_string()), + pkg.name.clone(), + pkg.version.clone().to_string() + ); + file.write_all(fm.as_bytes())?; + file = File::create(pkg.entrypoint.clone())?; // main.typ + file.write_all(b"// This file is generated by UTPM (https://github.com/Thumuss/utpm)")?; + } + let mut keys: BTreeMap = BTreeMap::new(); + keys.insert("utpm".into(), Table::try_from(extra.clone())?); + + let manif = Manifest { + package: pkg, + tool: if extra.namespace.is_none() + && (extra.dependencies.is_none() || extra.dependencies.unwrap().len() == 0) + { + None + } else { + Some(Tool { keys }) + }, + template: None, + }; + + write_manifest!(&manif); + + println!("{}", format!("File created to {typ}")); + Ok(true) +} diff --git a/src/commands/install.rs b/src/commands/install.rs index 340d58f..9e97510 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -2,49 +2,71 @@ use std::{env, fs, path::Path}; use crate::{ commands::LinkArgs, + load_manifest, utils::{ + copy_dir_all, paths::{ check_path_dir, check_path_file, d_packages, datalocalutpm, get_current_dir, get_ssh_dir, }, - state::{Error, ErrorKind, Responses, Result}, - TypstConfig, + specs::Extra, + state::{Error, ErrorKind, Result}, }, }; -use git2::{build::RepoBuilder, Cred, FetchOptions, RemoteCallbacks, Repository}; -use owo_colors::OwoColorize; + +use git2::{build::RepoBuilder, Cred, FetchOptions, RemoteCallbacks}; +use tracing::{debug, instrument}; +use typst_project::{heuristics::MANIFEST_FILE, manifest::Manifest}; use super::{link, InstallArgs}; -pub fn run(cmd: &InstallArgs, res: &mut Responses) -> Result { - let path = format!("{}/tmp", datalocalutpm()); +#[instrument] +pub fn run(cmd: &InstallArgs) -> Result { + let path = format!("{}/tmp", datalocalutpm()?); if check_path_dir(&path) { fs::remove_dir_all(path)?; } - init(cmd, res, 0)?; + init(cmd, 0)?; Ok(true) } -pub fn init(cmd: &InstallArgs, res: &mut Responses, i: usize) -> Result { - let path = if cmd.url.is_none() { - get_current_dir()? +#[instrument(skip(cmd))] +pub fn init(cmd: &InstallArgs, i: usize) -> Result { + let path = if let Some(url) = &cmd.url { + let dir = format!("{}/tmp/{}", datalocalutpm()?, i); + debug!("url is set to {}, creating {}", url, dir); + dir } else { - format!("{}/tmp/{}", datalocalutpm(), i) + let dir = get_current_dir()?; + debug!("url is none, current dir: {}", dir); + dir }; if let Some(x) = &cmd.url { fs::create_dir_all(&path)?; let sshpath = get_ssh_dir()?; - let ed = sshpath.clone() + "/id_ed25519"; - let rsa = sshpath + "/id_rsa"; - let val = if check_path_file(&ed) { ed } else { rsa }; - if x.starts_with("git") { + let ed: String = sshpath.clone() + "/id_ed25519"; + let rsa: String = sshpath + "/id_rsa"; + let val: String = match env::var("UTPM_KEYPATH") { + Ok(val) => val, + Err(_) => { + if check_path_file(&ed) { + ed + } else { + rsa + } + } + }; + if x.starts_with("git") || x.starts_with("http") { let mut callbacks = RemoteCallbacks::new(); callbacks.credentials(|_, username_from_url, _| { - match Cred::ssh_key_from_agent(username_from_url.unwrap_or("git")) { + let binding = env::var("UTPM_USERNAME") + .unwrap_or(username_from_url.unwrap_or("git").to_string()); + let username = binding.as_str(); + match Cred::ssh_key_from_agent(username) { Ok(cred) => Ok(cred), Err(_) => Cred::ssh_key( - username_from_url.unwrap_or("git"), + username, None, Path::new(&val), Some( @@ -63,82 +85,66 @@ pub fn init(cmd: &InstallArgs, res: &mut Responses, i: usize) -> Result { builder.fetch_options(fo); builder.clone(&x, Path::new(&path))?; } else { - Repository::clone(&x, &path)?; + copy_dir_all(&x, &path)?; } }; - let typstfile = path.clone() + "/typst.toml"; + let typstfile = path.clone() + "/" + MANIFEST_FILE; if !check_path_file(&typstfile) { - return Err(Error::empty(ErrorKind::ConfigFile)); + let origin = cmd.url.clone().unwrap_or("/".into()); + println!("{}", format!("x {}", origin)); + return Ok(false); } - - let file = TypstConfig::load(&typstfile); - let utpm = file.utpm; - let namespace = utpm - .clone() - .unwrap_or(crate::utils::Extra { - version: None, - namespace: Some("local".to_string()), - dependencies: None, - }) - .namespace - .unwrap_or("local".into()); - + let file = load_manifest!(&path); + let utpm = if let Some(value) = file.tool { + value.get_section("utpm")?.unwrap_or(Extra::default()) + } else { + Extra::default() + }; + let namespace = utpm.namespace.unwrap_or("local".into()); if check_path_dir(&format!( "{}/{}/{}/{}", - d_packages(), + d_packages()?, namespace, &file.package.name, &file.package.version )) { println!( "{}", - format!("~ {}:{}", file.package.name, file.package.version).bright_black() + format!("~ {}:{}", file.package.name, file.package.version) ); return Ok(true); } - println!("{}", format!("Installing {}...", file.package.name).bold()); - if let Some(fl) = utpm { - if let Some(vec_depend) = fl.dependencies { - let mut y = 0; - let vec_of_dependencies = vec_depend - .iter() - .map(|a| -> Result { - y += 1; - let ins = InstallArgs { - force: cmd.force, - url: Some(a.to_string()), - }; - init(&ins, res, i * vec_depend.len() + y)?; - Ok(true) - }) - .collect::>>(); - - for result_dependencies in vec_of_dependencies { - result_dependencies?; - } - } + println!("{}", format!("Installing {}...", file.package.name)); + if let Some(vec_depend) = utpm.dependencies { + let mut y = 0; + vec_depend + .iter() + .map(|a| -> Result { + y += 1; + let ins = InstallArgs { + force: cmd.force, + url: Some(a.to_string()), + }; + init(&ins, i * vec_depend.len() + y)?; + Ok(true) + }) + .collect::>>()?; } - if !cmd.url.is_none() { let lnk = LinkArgs { force: cmd.force, no_copy: false, }; - - link::run(&lnk, Some(path.clone()), res)?; //TODO: change here too + link::run(&lnk, Some(path.clone()), false)?; //TODO: change here too fs::remove_dir_all(&path)?; println!( "{}", - format!("+ {}:{}", file.package.name, file.package.version).bright_green() + format!("+ {}:{}", file.package.name, file.package.version) ); } else { - println!( - "{}", - "* Installation complete! If you want to use it as a lib, just do a `utpm link`!" - .bold() - ) + println!("* Installation complete! If you want to use it as a lib, just do a `utpm link`!") } Ok(true) diff --git a/src/commands/link.rs b/src/commands/link.rs index 70f0557..9697314 100644 --- a/src/commands/link.rs +++ b/src/commands/link.rs @@ -1,36 +1,47 @@ -use owo_colors::OwoColorize; -use serde_json::json; use std::fs; +use tracing::instrument; +use typst_project::manifest::Manifest; -use crate::utils::{ - copy_dir_all, - paths::{check_path_dir, d_packages, get_current_dir}, - state::{Error, ErrorKind, ResponseKind::*, Responses, Result}, - symlink_all, Extra, TypstConfig, +use crate::{ + load_manifest, + utils::{ + copy_dir_all, + paths::{c_packages, check_path_dir, d_packages, get_current_dir}, + specs::Extra, + state::{Error, ErrorKind, Result}, + symlink_all, + }, }; use super::LinkArgs; -pub fn run(cmd: &LinkArgs, path: Option, res: &mut Responses) -> Result { +#[instrument(skip(cmd))] +pub fn run(cmd: &LinkArgs, path: Option, pt: bool) -> Result { let curr = path.unwrap_or(get_current_dir()?); - let config = TypstConfig::load(&(curr.clone() + "/typst.toml")); - let namespace = config - .utpm - .unwrap_or(Extra::new()) - .namespace - .unwrap_or("local".into()); + let config = load_manifest!(&curr); + let namespace = if let Some(value) = config.tool { + value + .get_section("utpm")? + .unwrap_or(Extra::default()) + .namespace + .unwrap_or("local".into()) + } else { + "local".into() + }; let name = config.package.name; let version = config.package.version; - let path = format!("{}/{}/{}/{}", d_packages(), namespace, name, version); - let binding = "Info:".yellow(); - let info = binding.bold(); + let path = if namespace != "preview" { + format!("{}/{}/{}/{}", d_packages()?, namespace, name, version) + } else { + format!("{}/{}/{}/{}", c_packages()?, namespace, name, version) + }; if check_path_dir(&path) && !cmd.force { return Err(Error::empty(ErrorKind::AlreadyExist( - name, + name.into(), version, - format!("{}", info), + "Info:".into(), ))); } @@ -42,22 +53,20 @@ pub fn run(cmd: &LinkArgs, path: Option, res: &mut Responses) -> Result< if cmd.no_copy { symlink_all(&curr, &path)?; - let s = format!( - "Project linked to: {} \nTry importing with:\n #import \"@{}/{}:{}\": *", - path, namespace, name, version - ); - res.push(Value(json!({ - "message": s, - }))); + if pt { + println!( + "Project linked to: {} \nTry importing with:\n #import \"@{}/{}:{}\": *", + path, namespace, name, version + ); + } } else { copy_dir_all(&curr, &path)?; - let s = format!( - "Project copied to: {} \nTry importing with:\n #import \"@{}/{}:{}\": *", - path, namespace, name, version - ); - res.push(Value(json!({ - "message": s, - }))); + if pt { + println!( + "Project copied to: {} \nTry importing with:\n #import \"@{}/{}:{}\": *", + path, namespace, name, version + ); + } } Ok(true) } diff --git a/src/commands/list.rs b/src/commands/list.rs index a68dfaa..346865a 100644 --- a/src/commands/list.rs +++ b/src/commands/list.rs @@ -1,65 +1,82 @@ -use owo_colors::OwoColorize; -use serde_json::{json, Map, Value}; use std::fs; +use tracing::instrument; use crate::utils::{ - paths::d_packages, - state::{ResponseKind::*, Responses, Result}, + paths::{c_packages, d_packages}, + state::Result, }; -pub fn run(res: &mut Responses) -> Result { - let typ = d_packages(); - if !res.json { - println!("{}", "Tree listing of your packages\n".bold()) - }; - let dirs = fs::read_dir(&typ)?; +use super::ListTreeArgs; + +#[instrument(skip(cmd))] +pub fn run(cmd: &ListTreeArgs) -> Result { + let typ: String = d_packages()?; + println!("A list of your packages (WIP)\n"); + if cmd.all { + let preview: String = c_packages()?; + read(typ)?; + return read(preview); + } - let mut data: Vec = vec![]; + if let Some(list) = &cmd.include { + let preview: String = c_packages()?; + for e in list { + if e == "preview" { + return read(preview); + } + match package_read(&format!("{}/local/{}", typ, e)) { + Ok(_) => true, + Err(_) => namespace_read(&format!("{}/{}", typ, e))?, + }; + } + Ok(true) + } else { + read(typ) + } +} + +fn read(typ: String) -> Result { + let dirs = fs::read_dir(&typ)?; for dir_res in dirs { let dir = dir_res?; - if !res.json { - println!("@{}:", dir.file_name().to_str().unwrap().green().bold()); - } + println!("@{}: ", dir.file_name().to_str().unwrap()); let subupdirs = fs::read_dir(dir.path())?; - let mut map = Map::new(); - let mut list: Vec = vec![]; - for dir_res in subupdirs { let dir = dir_res?; - if !res.json { - println!(" {}:", dir.file_name().to_str().unwrap().green().bold()); - } + print!("{}: ", dir.file_name().to_str().unwrap()); let subdirs = fs::read_dir(dir.path())?; - - let mut map2 = Map::new(); - let mut list2: Vec = vec![]; - for sub_dir_res in subdirs { let subdir = sub_dir_res?; - list2.push(json!(subdir.file_name().to_str())); - if !res.json { - println!(" - {}", subdir.file_name().to_str().unwrap().green()); - } + print!("{} ", subdir.file_name().to_str().unwrap()); } + println!(); + } + } + Ok(true) +} - let array2 = Value::Array(list2); - map2.insert(dir.file_name().to_str().unwrap().into(), array2); - let dir_dataa: Value = Value::Object(map2); +fn package_read(typ: &String) -> Result { + for dir_res in fs::read_dir(&typ)? { + let dir = dir_res?; + print!("{}: ", dir.file_name().to_str().unwrap()); + } + println!(); + Ok(true) +} - list.push(dir_dataa) +fn namespace_read(typ: &String) -> Result { + for dir_res in fs::read_dir(&typ)? { + let dir = dir_res?; + println!("{}: ", dir.file_name().to_str().unwrap()); + print!("- "); + for dir_res in fs::read_dir(dir.path())? { + let dir = dir_res?; + print!("{} ", dir.file_name().to_str().unwrap()); } - let array = Value::Array(list); - map.insert(dir.file_name().to_str().unwrap().into(), array); - let dir_data: Value = Value::Object(map); - - data.push(dir_data); + println!(); } - // TODO: It's working for now but it will be changed one day - if res.json { - res.push(Value(json!(data))) - }; Ok(true) } diff --git a/src/commands/package_path.rs b/src/commands/package_path.rs index d597efb..992f71e 100644 --- a/src/commands/package_path.rs +++ b/src/commands/package_path.rs @@ -1,16 +1,10 @@ -use serde_json::json; +use tracing::instrument; -use crate::utils::{ - paths::d_packages, - state::{ResponseKind::*, Responses, Result}, -}; +use crate::utils::{paths::d_packages, state::Result}; -pub fn run(res: &mut Responses) -> Result { - res.pushs(vec![ - Value(json!({ - "path": d_packages(), - })), - Message(format!("Packages are located at: '{}'", d_packages())), - ]); +#[instrument] +pub fn run() -> Result { + println!("Packages are located at: '{}'", d_packages()?); + eprintln!("{}", d_packages()?); Ok(true) } diff --git a/src/commands/publish.rs b/src/commands/publish.rs new file mode 100644 index 0000000..3103d29 --- /dev/null +++ b/src/commands/publish.rs @@ -0,0 +1,245 @@ +use crate::utils::specs::Extra; +use crate::utils::state::{Error, ErrorKind}; +use crate::utils::{push_git_packages, regex_package, update_git_packages}; +use std::env; +use std::fs::{copy, create_dir_all}; +use std::path::{Path, PathBuf}; +use std::result::Result as R; +use std::str::FromStr; + +use crate::load_manifest; +use crate::utils::paths::{ + check_path_file, default_typst_packages, has_content, TYPST_PACKAGE_URL, +}; +use crate::utils::{paths::get_current_dir, state::Result}; +use ignore::overrides::OverrideBuilder; +use octocrab::models::{Author, UserProfile}; +use octocrab::Octocrab; +use tracing::{error, info, instrument, trace}; +use typst_project::manifest::Manifest; + +use super::PublishArgs; + +use ignore::WalkBuilder; + +#[tokio::main] +#[instrument(skip(cmd))] +pub async fn run(cmd: &PublishArgs) -> Result { + //todo: github create fork if not exist (checkout and everything), link to local packages, create PR, git push + //todo: Check dependencies, a way to add them? + //todo: check if there are files in the package... + + let config: Manifest = load_manifest!(); + + info!("Manifest load"); + + let path_curr: &PathBuf = if let Some(path) = &cmd.path { + path + } else { + &get_current_dir()?.into() + }; + + info!("Path: {}", path_curr.to_str().unwrap()); + + let version: String = config.package.version.to_string(); + let name: String = config.package.name.into(); + let re: regex::Regex = regex_package(); + + let package_format = format!("@preview/{name}:{version}"); + + info!("Package: {package_format}"); + + if !re.is_match(package_format.as_str()) { + error!("Package didn't match, the name or the version is incorrect."); + return Err(Error::empty(ErrorKind::UnknowError("todo".into()))); // todo: u k + } + + let path_curr_str: &str = path_curr.to_str().unwrap(); + + let path_packages: String = default_typst_packages()?; + let path_packages_new: String = format!("{path_packages}/packages/preview/{name}/{version}"); + + // Github handle + + let crab = Octocrab::builder() + .personal_token( + env::var("UTPM_GITHUB_TOKEN") + .expect("Should have a github token in \"UTPM_GITHUB_TOKEN\""), + ) + .build() + .unwrap(); + + let pages = match crab + .current() + .list_repos_for_authenticated_user() + .visibility("public") + .send() + .await + { + Ok(a) => a, + Err(_) => todo!(), + }; + + let repo: Option<&octocrab::models::Repository> = pages.items.iter().find(|f| match &f.forks_url { + None=>"", + Some(a) => a.as_str() + } == TYPST_PACKAGE_URL ); + + let fork: String; + let name_package = format!("{}-{}", name.clone(), config.package.version.to_string()); + + if let Some(rep) = repo { + fork = rep.url.clone().into(); + } else { + // Format into: "mypackage-1.0.0" + // Github doesn't allow ':' + match crab + .repos("typst", "packages") + .create_fork() + .name(&name_package) + .send() + .await + { + Ok(val) => fork = format!("git@github.com:{}.git", val.full_name.expect("Didn't fork")), + Err(err) => { + println!("{:?}", err); + return Err(Error::empty(ErrorKind::General)); + } + }; + } + + // Download typst/packages + + let repos = update_git_packages(path_packages, fork.as_str())?; + + info!("Path to the new package {}", path_packages_new); + + // Prepare files + + let mut wb: WalkBuilder = WalkBuilder::new(path_curr); + + let mut overr: OverrideBuilder = OverrideBuilder::new(path_curr); + + for exclude in Extra::from(config.tool).exclude.unwrap_or(vec![]) { + overr.add(("!".to_string() + &exclude).as_str())?; + } + + wb.overrides(overr.build()?); + + wb.ignore(cmd.ignore) + .git_ignore(cmd.git_ignore) + .git_global(cmd.git_global_ignore) + .git_exclude(cmd.git_exclude); + + info!( + git_ignore = cmd.git_ignore, + git_global_ignore = cmd.git_global_ignore, + git_exclude = cmd.git_exclude + ); + + let mut path_check = path_curr.clone().into_os_string(); + path_check.push("/.typstignore"); + if check_path_file(path_check) { + info!("Added .typstignore"); + wb.add_custom_ignore_filename(".typstignore"); + } + + if let Some(custom_ignore) = &cmd.custom_ignore { + let filename = custom_ignore.file_name().unwrap().to_str().unwrap(); + info!(custom_ignore = filename, "Trying a new ignore file"); + if check_path_file(custom_ignore) { + info!(custom_ignore = filename, "File exist, adding it"); + wb.add_custom_ignore_filename(filename); + } + } + + // Copy + + for result in wb.build().collect::, _>>()? { + if let Some(file_type) = result.file_type() { + let path: &Path = result.path(); + let name: String = path.to_str().unwrap().to_string(); + let l: String = name.replace::<&str>(path_curr_str, &path_packages_new); + println!("{l}"); + if file_type.is_dir() { + create_dir_all(l)?; + } else { + copy(path, l)?; + } + } + } + + if !has_content(&path_packages_new)? { + error!("There is no files in the new package. Consider to change your ignored files."); + return Err(Error::empty(ErrorKind::UnknowError("".into()))); + } + + if !check_path_file(format!("{path_packages_new}/typst.toml")) { + error!("Can't find `typst.toml` file in {path_packages_new}. Did you omit it in your ignored files?"); + return Err(Error::empty(ErrorKind::UnknowError("".into()))); + } + + let entry = config.package.entrypoint; + let mut entryfile = PathBuf::from_str(&path_packages_new).unwrap(); + entryfile.push(&entry); + let entrystr = entry.to_str().unwrap(); + + trace!(entryfile = entrystr); + if !check_path_file(entryfile) { + error!("Can't find {entrystr} file in {path_packages_new}. Did you omit it in your ignored files?"); + return Err(Error::empty(ErrorKind::UnknowError("".into()))); + } + + info!("files copied to {path_packages_new}"); + + // Push + + info!("Getting information from github"); + + let author_user: Author = crab.current().user().await?; + let user: UserProfile = crab.users_by_id(author_user.id).profile().await?; + + let us = &user; + info!( + email = us.email, + id = us.id.to_string(), + name = us.name.clone().unwrap() + ); + + let name_replaced = name_package.replace('-', ":"); + let msg = cmd + .message + .clone() + .unwrap_or(format!("{} using utpm", &name_replaced)); + + push_git_packages(repos, user.clone(), msg.as_str())?; + + info!("Ended push"); + + // Pull request + + crab.pulls("typst", "packages") + .create(name_replaced.as_str(), format!("{}:main", us.name.clone().unwrap()), "base") + .body(" +I am submitting +- [ ] a new package +- [ ] an update for a package + + +Description: Explain what the package does and why it's useful. + +I have read and followed the submission guidelines and, in particular, I +- [ ] selected a name that isn't the most obvious or canonical name for what the package does +- [ ] added a `typst.toml` file with all required keys +- [ ] added a `README.md` with documentation for my package +- [ ] have chosen a license and added a `LICENSE` file or linked one in my `README.md` +- [ ] tested my package locally on my system and it worked +- [ ] `exclude`d PDFs or README images, if any, but not the LICENSE + +- [ ] ensured that my package is licensed such that users can use and distribute the contents of its template directory without restriction, after modifying them through normal use. +") // todo: body + .send() + .await?; + + Ok(true) +} diff --git a/src/commands/tree.rs b/src/commands/tree.rs new file mode 100644 index 0000000..eef5589 --- /dev/null +++ b/src/commands/tree.rs @@ -0,0 +1,85 @@ +use std::fs; +use tracing::instrument; + +use crate::utils::{ + paths::{c_packages, d_packages}, + state::Result, +}; + +use super::ListTreeArgs; + +use std::result::Result as R; + +#[instrument(skip(cmd))] +pub fn run(cmd: &ListTreeArgs) -> Result { + let typ: String = d_packages()?; + println!("{}", "Tree listing of your packages\n"); + if cmd.all { + let preview: String = c_packages()?; + read(typ)?; + return read(preview); + } + + if let Some(list) = &cmd.include { + let preview: String = c_packages()?; + for e in list { + if e == "preview" { + return read(preview); + } + match package_read(&format!("{}/local/{}", typ, e)) { + Ok(_) => true, + Err(_) => namespace_read(&format!("{}/{}", typ, e))?, + }; + } + Ok(true) + } else { + read(typ) + } +} + +fn read(typ: String) -> Result { + let dirs = fs::read_dir(&typ)?; + + for dir_res in dirs { + let dir = dir_res?; + println!("@{}:", dir.file_name().to_str().unwrap()); + let subupdirs = fs::read_dir(dir.path())?; + + for dir_res in subupdirs { + let dir = dir_res?; + println!(" {}:", dir.file_name().to_str().unwrap()); + + let subdirs = fs::read_dir(dir.path())?; + for sub_dir_res in subdirs { + let subdir = sub_dir_res?; + println!(" - {}", subdir.file_name().to_str().unwrap()); + } + } + } + Ok(true) +} + +fn package_read(typ: &String) -> Result { + let dirs = fs::read_dir(&typ)?; + + for dir_res in dirs { + let dir = dir_res?; + print!("{}", dir.file_name().to_str().unwrap()); + } + println!(); + Ok(true) +} + +fn namespace_read(typ: &String) -> Result { + let dirs = fs::read_dir(&typ)?; + + for dir_res in dirs.into_iter().collect::, _>>()? { + println!("{}:", dir_res.file_name().into_string().unwrap()); + let subupdirs = fs::read_dir(dir_res.path())?; + for dir_res in subupdirs.into_iter().collect::, _>>()? { + println!(" - {}", dir_res.file_name().to_str().unwrap()); + } + println!(); + } + Ok(true) +} diff --git a/src/commands/unlink.rs b/src/commands/unlink.rs index 7f16bb4..9be8b59 100644 --- a/src/commands/unlink.rs +++ b/src/commands/unlink.rs @@ -1,96 +1,53 @@ use inquire::Confirm; -use owo_colors::OwoColorize; use std::fs; - -use crate::utils::{ - paths::d_packages, - state::{Error, ErrorKind, ResponseKind::*, Responses, Result}, +use tracing::{info, instrument}; + +use crate::{ + format_package, + utils::{ + paths::{c_packages, d_packages}, + regex_namespace, regex_package, regex_packagename, + state::{Error, ErrorKind, Result}, + }, }; use super::UnlinkArgs; -pub fn run(cmd: &UnlinkArgs, res: &mut Responses) -> Result { - let mut new_namespace = String::from("local"); - if let Some(nspace) = &cmd.namespace { - new_namespace = nspace.to_owned(); +#[instrument(skip(cmd))] +pub fn run(cmd: &UnlinkArgs) -> Result { + let packages = &cmd.package; + + // RegEx + let re_all = regex_package(); + let re_name = regex_packagename(); + let re_namespace = regex_namespace(); + let path: String; + if let Some(cap) = re_all.captures(packages.as_str()) { + let (_, [namespace, package, major, minor, patch]) = cap.extract(); + path = format_package!(namespace, package, major, minor, patch); + } else if let Some(cap) = re_name.captures(packages.as_str()) { + let (_, [namespace, package]) = cap.extract(); + path = format_package!(namespace, package); + } else if let Some(cap) = re_namespace.captures(packages.as_str()) { + let (_, [namespace]) = cap.extract(); + path = format_package!(namespace); + } else { + return Err(Error::empty(ErrorKind::PackageNotValid)); } - if let Some(ver) = &cmd.version { - if cmd.name.is_none() { - return Err(Error::empty(ErrorKind::Namespace)); - } - let ans = if !(cmd.yes) { - Confirm::new("Are you sure to delete this? This is irreversible.") - .with_help_message( - format!( - "You want to erase {}/{}", - cmd.name.clone().unwrap(), - ver.to_string() - ) - .as_str(), - ) - .prompt() - } else { - Ok(true) - }; - - let bool = ans?; - if !bool { - res.push(Message("Nothing to do".into())); - return Ok(false); - } - - fs::remove_dir_all( - d_packages() - + format!( - "/{}/{}/{}", - new_namespace, - cmd.name.clone().unwrap(), - ver.to_string() - ) - .as_str(), - )?; - } else if cmd.delete_namespace { - let ans = if !(cmd.yes) { - Confirm::new("Are you sure to delete this? This is irreversible.") - .with_help_message( - format!("You want to erase @{new_namespace}, the namespace").as_str(), - ) - .prompt() - } else { - Ok(true) - }; - - let bool = ans?; - if !bool { - res.push(Message("Nothing to do".into())); - return Ok(false); + if !cmd.yes { + match Confirm::new("Are you sure to delete this? This is irreversible.") + .with_help_message(format!("You want to delete {packages}").as_str()) + .prompt() + { + Ok(_) => { + fs::remove_dir_all(path)?; + Ok(true) + } + Err(_) => Ok(false), } - - fs::remove_dir_all(d_packages() + format!("/{new_namespace}").as_str())?; - } else if let Some(nm) = &cmd.name { - let ans = if !(cmd.yes) { - Confirm::new("Are you sure to delete this? This is irreversible.") - .with_help_message(format!("You want to erase {}", nm).as_str()) - .prompt() - } else { - Ok(true) - }; - - let bool = ans?; - if !bool { - res.push(Message("Nothing to do".into())); - - return Ok(false); - } - - fs::remove_dir_all(d_packages() + format!("/{}/{}", new_namespace, nm).as_str())?; - } - if res.json { - res.push(Message(format!("{}", "Removed!".bold()))); } else { - println!("{}", "Removed!".bold()) + fs::remove_dir_all(path)?; + Ok(true) } - - Ok(true) } diff --git a/src/main.rs b/src/main.rs index 73ce729..70de003 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,39 +1,145 @@ +use shadow_rs::shadow; +shadow!(build); + pub mod commands; pub mod utils; +use std::{env, str::FromStr}; + use clap::Parser; -use commands::{ - bulk_delete, create, info, install, link, list, package_path, unlink, Cli, Commands, -}; +#[cfg(feature = "add")] +use commands::add; +#[cfg(feature = "bulk_delete")] +use commands::bulk_delete; +#[cfg(feature = "clone")] +use commands::clone; +#[cfg(feature = "delete")] +use commands::delete; +#[cfg(feature = "generate")] +use commands::generate; +#[cfg(feature = "init")] +use commands::init; +#[cfg(feature = "install")] +use commands::install; +#[cfg(feature = "link")] +use commands::link; +#[cfg(feature = "list")] +use commands::list; +#[cfg(feature = "path")] +use commands::package_path; +// #[cfg(feature = "publish")] +// use commands::publish; +#[cfg(feature = "tree")] +use commands::tree; +#[cfg(feature = "unlink")] +use commands::unlink; +#[cfg(any( + feature = "tree", + feature = "list", + feature = "path", + feature = "unlink", + feature = "bulk_delete" +))] +use commands::Packages; +//todo: workspace +#[cfg(any( + feature = "link", + feature = "init", + feature = "install", + feature = "add", + feature = "delete", + feature = "init", + feature = "publish", + feature = "clone" +))] +use commands::Workspace; +use commands::{Cli, Commands}; + +use utils::state::Error; -use utils::state::{Error, Responses}; +use tracing::{error, instrument, level_filters::LevelFilter}; +use tracing_subscriber::{self, layer::SubscriberExt, util::SubscriberInitExt, Layer}; +#[instrument] fn main() { let x = Cli::parse(); - let json = x.json; - let mut res = Responses::new(json); - let result: Result = match &x.command { - Commands::Create(cmd) => create::run(cmd, &mut res), - Commands::Link(cmd) => link::run(cmd, None, &mut res), - Commands::List => list::run(&mut res), - Commands::PackagesPath => package_path::run(&mut res), - Commands::Unlink(cmd) => unlink::run(cmd, &mut res), - Commands::BulkDelete(cmd) => bulk_delete::run(cmd, &mut res), - Commands::Install(cmd) => install::run(cmd, &mut res), - Commands::Info(cmd) => info::run(cmd, &mut res), + + // Fetching variables from the environment. + let debug_str: String = match env::var("UTPM_DEBUG") { + Err(_) => "warn".into(), + Ok(val) => val, + }; + + // Transform the env var into a levelfilter to + // filter logs from the tracing + let level_filter: LevelFilter = match LevelFilter::from_str(debug_str.as_str()) { + Ok(val) => val, + Err(_) => LevelFilter::WARN, }; - match result { - Ok(_) => { - if json { - print!("{}", res.to_json()) - } - } - Err(val) => { - if json { - eprint!("{}", val.json()) + + tracing_subscriber::registry() + .with( + tracing_subscriber::fmt::layer().with_filter(if let Some(debug) = x.verbose { + debug } else { - eprint!("{}", val.to_str()) - } - } + level_filter + }), + ) + .init(); + + let res: Result = match &x.command { + #[cfg(any( + feature = "link", + feature = "init", + feature = "install", + feature = "add", + feature = "delete", + feature = "init", + feature = "publish", + feature = "clone" + ))] + Commands::Workspace(w) => match w { + #[cfg(feature = "link")] + Workspace::Link(cmd) => link::run(cmd, None, true), + #[cfg(feature = "install")] + Workspace::Install(cmd) => install::run(cmd), + #[cfg(feature = "add")] + Workspace::Add(cmd) => add::run(&mut cmd.clone()), + #[cfg(feature = "delete")] + Workspace::Delete(cmd) => delete::run(&mut cmd.clone()), + #[cfg(feature = "init")] + Workspace::Init(cmd) => init::run(&mut cmd.clone()), + // #[cfg(feature = "publish")] + // Workspace::Publish(cmd) => publish::run(cmd), + #[cfg(feature = "clone")] + Workspace::Clone(cmd) => clone::run(cmd), + }, + #[cfg(any( + feature = "tree", + feature = "list", + feature = "path", + feature = "unlink", + feature = "bulk_delete" + ))] + Commands::Packages(p) => match p { + // Maybe a move command to change namespace? Or name or version + #[cfg(feature = "tree")] + Packages::Tree(cmd) => tree::run(cmd), + #[cfg(feature = "list")] + Packages::List(cmd) => list::run(cmd), + #[cfg(feature = "path")] + Packages::Path => package_path::run(), + #[cfg(feature = "unlink")] + Packages::Unlink(cmd) => unlink::run(cmd), + #[cfg(feature = "bulk_delete")] + Packages::BulkDelete(cmd) => bulk_delete::run(cmd), + }, + #[cfg(feature = "generate")] + Commands::Generate(cmd) => generate::run(cmd), + }; + + match res { + Ok(_) => {} + Err(val) => error!("{}", val), } } diff --git a/src/portable.rs b/src/portable.rs deleted file mode 100644 index 94bd48d..0000000 --- a/src/portable.rs +++ /dev/null @@ -1,23 +0,0 @@ -use std::env; - -use commands::InstallArgs; -use utils::state::Responses; - -#[allow(unused)] -mod commands; - -#[allow(unused)] -mod utils; - -/// Simple version of a portable installer -fn main() { - let args: Vec = env::args().collect(); - let force = args.contains(&"--force".to_string()) || args.contains(&"-f".to_string()); - let json = args.contains(&"--json".to_string()) || args.contains(&"-j".to_string()); - let mut res = Responses::new(json); - let install = InstallArgs { url: None, force }; - match commands::install::run(&install, &mut res) { - Err(err) => println!("{}", err.to_string()), - Ok(_) => println!("Everything is good to go!"), - } -} diff --git a/src/utils.rs b/src/utils.rs index ecc6676..d81a38b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,138 +1,40 @@ -use std::{ - fs::{self, read_to_string}, - path::Path, +use std::ffi::OsStr; +use std::fmt::Debug; +use std::fs::create_dir_all; +use std::{fs, path::Path}; + +#[cfg(any(feature = "publish", feature = "clone", feature = "install"))] +use git2::{ + build::{CheckoutBuilder, RepoBuilder}, + Cred, FetchOptions, RemoteCallbacks, Repository, }; - -use std::io; - -use semver::Version; -use serde::{Deserialize, Serialize}; -use serde_with::skip_serializing_none; - +use paths::{check_path_file, get_ssh_dir, has_content}; +#[cfg(any(feature = "clone", feature = "publish", feature = "unlink"))] +use regex::Regex; +use state::{Error, ErrorKind}; +use std::{env, io, result::Result as R}; +use tracing::{error, info, instrument}; +use typst_kit::download::{DownloadState, Progress}; + +pub mod macros; pub mod paths; +pub mod specs; pub mod state; -#[skip_serializing_none] -#[derive(Serialize, Deserialize, PartialEq, Eq, Clone)] -/// Represent a package from the official `typst.toml` -/// See https://github.com/typst/packages -pub struct Package { - // Required - /// The name of the package - pub name: String, - /// The version (using semver) - pub version: Version, - /// Where is your main file - pub entrypoint: String, - - // Not required with local packages - /// The authors of the package - pub authors: Option>, - /// The license - pub license: Option, - /// A little description for your users - pub description: Option, - - // Not required - /// A link to your repository - pub repository: Option, - /// The link to your website - pub homepage: Option, - /// A list of keywords to research your package - pub keywords: Option>, - /// A minimum version of the compiler (for typst) - pub compiler: Option, - /// A list of excludes files - pub exclude: Option>, -} - -/// Default implementation of a package -impl Package { - pub fn new() -> Self { - Self { - name: "".to_string(), - version: Version::new(1, 0, 0), - entrypoint: "main.typ".to_string(), - - authors: None, - license: None, - description: None, - - repository: None, - homepage: None, - keywords: None, - compiler: None, - exclude: None, - } - } -} - -/// A modify version of the `typst.toml` adding options to utpm -#[derive(Serialize, Deserialize, Clone)] -pub struct Extra { - /// Basic system of version (it will increased over time to keep track of what change or not) - pub version: Option, - /// The name of where you store your packages (default: local) - pub namespace: Option, - - /// List of url's for your dependencies (will be resolved with install command) - pub dependencies: Option>, -} - -impl Extra { - pub fn new() -> Self { - Self { - version: Some("2".to_string()), - namespace: Some("local".to_string()), - dependencies: None, - } - } -} - -/// The file `typst.toml` itself -#[derive(Serialize, Deserialize)] -pub struct TypstConfig { - /// Base of typst package system - pub package: Package, - /// An extra for utpm - pub utpm: Option, -} - -impl TypstConfig { - /// Load the configuration from a file - pub fn load(path: &String) -> Self { - toml::from_str( - read_to_string(path) - .expect("Should have read the file") - .as_str(), - ) - .unwrap() - } - - /// Write a file - pub fn write(&mut self, path: &String) { - let form = toml::to_string_pretty(&self).unwrap(); - fs::write(path, form).expect("aaa"); - } +use self::state::Result; - /// Create a typstConfig - pub fn new(package: Package, extra: Extra) -> Self { - Self { - package, - utpm: Some(extra), - } - } -} +#[cfg(any(feature = "publish"))] +use octocrab::models::UserProfile; /// Copy all subdirectories from a point to an other /// From https://stackoverflow.com/questions/26958489/how-to-copy-a-folder-recursively-in-rust -/// Edited to prepare a portable version +/// Edited to prepare a ci version pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> io::Result<()> { fs::create_dir_all(&dst)?; for entry in fs::read_dir(src)? { let entry = entry?; let ty = entry.file_type()?; - if ty.is_dir() && entry.file_name() != "utpmp" && entry.file_name() != "install" { + if ty.is_dir() && entry.file_name() != ".utpm" && entry.file_name() != "install" { copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?; } else { fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?; @@ -143,14 +45,192 @@ pub fn copy_dir_all(src: impl AsRef, dst: impl AsRef) -> io::Result< /// Implementing a symlink function for all platform (unix version) #[cfg(unix)] -pub fn symlink_all(origin: &str, new_path: &str) -> Result<(), std::io::Error> { +pub fn symlink_all(origin: impl AsRef, new_path: impl AsRef) -> R<(), std::io::Error> { use std::os::unix::fs::symlink; symlink(origin, new_path) } /// Implementing a symlink function for all platform (windows version) #[cfg(windows)] -pub fn symlink_all(origin: &str, new_path: &str) -> Result<(), std::io::Error> { +pub fn symlink_all(origin: impl AsRef, new_path: impl AsRef) -> R<(), std::io::Error> { use std::os::windows::fs::symlink_dir; symlink_dir(origin, new_path) } + +#[cfg(any(feature = "clone", feature = "publish", feature = "unlink"))] +pub fn regex_package() -> Regex { + Regex::new(r"^@([a-z]+)\/([a-z]+(?:\-[a-z]+)?)\:(\d+)\.(\d+)\.(\d+)$").unwrap() +} +#[cfg(any(feature = "unlink"))] +pub fn regex_namespace() -> Regex { + Regex::new(r"^@([a-z]+)$").unwrap() +} + +#[cfg(any(feature = "unlink"))] +pub fn regex_packagename() -> Regex { + Regex::new(r"^@([a-z]+)\/([a-z]+(?:\-[a-z]+)?)$").unwrap() +} + +//todo: impl +/// (Warning) Not implemented yet +/// +/// Create an object to track the progression +/// of downloaded packages from typst for the user +pub struct ProgressPrint {} + +impl Progress for ProgressPrint { + fn print_start(&mut self) {} + + fn print_progress(&mut self, _state: &DownloadState) {} + + fn print_finish(&mut self, _state: &DownloadState) {} +} + +/// Get remote indexes into local indexes +#[cfg(any(feature = "publish", feature = "clone", feature = "install"))] +#[instrument] +pub fn update_git_packages

(path_packages: P, url: &str) -> Result +where + P: AsRef + AsRef + Debug, +{ + use crate::load_creds; + + create_dir_all(&path_packages)?; + let repo: Repository; + let sshpath = get_ssh_dir()?; + let ed: String = sshpath.clone() + "/id_ed25519"; + let rsa: String = sshpath + "/id_rsa"; + let val: String = match env::var("UTPM_KEYPATH") { + Ok(val) => val, + Err(_) => { + if check_path_file(&ed) { + ed + } else { + rsa + } + } + }; + info!(path = val); + let mut callbacks = RemoteCallbacks::new(); + load_creds!(callbacks, val); + let mut fo = FetchOptions::new(); + fo.remote_callbacks(callbacks); + if has_content(&path_packages)? { + info!("Content found, starting a 'git pull origin main'"); + repo = Repository::open(path_packages)?; + let mut remote = repo.find_remote("origin")?; + remote.fetch(&["main"], Some(&mut fo), None)?; + let fetch_head = repo.find_reference("FETCH_HEAD")?; + let fetch_commit = repo.reference_to_annotated_commit(&fetch_head)?; + let analysis = repo.merge_analysis(&[&fetch_commit])?; + if analysis.0.is_up_to_date() { + info!("up to date, nothing to do"); + } else if analysis.0.is_fast_forward() { + let refname = format!("refs/heads/{}", "main"); + let mut reference = repo.find_reference(&refname)?; + reference.set_target(fetch_commit.id(), "Fast-Forward")?; + repo.set_head(&refname)?; + repo.checkout_head(Some(CheckoutBuilder::default().force()))?; + info!("fast forward done"); + } else { + error!("Can't rebase for now."); + return Err(Error::empty(ErrorKind::UnknowError("todo".into()))); + } + } else { + info!("Start cloning"); + let mut builder = RepoBuilder::new(); + builder.fetch_options(fo); + repo = builder.clone(url, Path::new(&path_packages))?; + info!("Package cloned"); + }; + Ok(repo) +} + +#[cfg(any(feature = "publish"))] +pub fn push_git_packages(repo: Repository, user: UserProfile, message: &str) -> Result<()> { + use git2::{IndexAddOption, Oid, PushOptions, Signature}; + use tracing::{span, Level}; + + use crate::load_creds; + + // Can't use instrument here. + let spans = span!(Level::INFO, "push_git_packages"); + let _guard = spans.enter(); + + // Real start + + info!("Starting commit"); + let uid = user.id.to_string(); + + let author = Signature::now( + user.name.unwrap_or(uid.clone()).as_str(), + user.email.unwrap_or(format!("{uid}@github.com")).as_str(), + )?; + + let mut index = repo.index()?; + + index.add_all(&["."], IndexAddOption::DEFAULT, None)?; + + index.write()?; + let oid = index.write_tree()?; + + info!("Index added"); + + let last_commit = repo.head()?.peel_to_commit()?; + let tree = repo.find_tree(oid)?; + + let oid: Oid = repo.commit( + Some("HEAD"), + &author, + &author, + message, + &tree, + &[&last_commit], + )?; + info!(id = oid.to_string(), "Commit created"); + + // From above + let sshpath = get_ssh_dir()?; + let ed: String = sshpath.clone() + "/id_ed25519"; + let rsa: String = sshpath + "/id_rsa"; + let val: String = match env::var("UTPM_KEYPATH") { + Ok(val) => val, + Err(_) => { + if check_path_file(&ed) { + ed + } else { + rsa + } + } + }; + info!(path = val); + let mut callbacks = RemoteCallbacks::new(); + load_creds!(callbacks, val); + + let mut po = PushOptions::new(); + po.remote_callbacks(callbacks); + + repo.find_remote("origin")? + .push::<&str>(&["refs/heads/main"], Some(&mut po))?; + + + return Ok(()); +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn regex() { + let re = regex_package(); + assert!(re.is_match("@preview/package:2.0.1")); + assert!(!re.is_match("@preview/package-:2.0.1")); + assert!(!re.is_match("@local/package-A:2.0.1")); + assert!(re.is_match("@local/package-a:2.0.1")); + assert!(!re.is_match("@local/p:1..1")); + assert!(re.is_match("@a/p:1.0.1")); + assert!(!re.is_match("@/p:1.0.1")); + assert!(!re.is_match("p:1.0.1")); + assert!(!re.is_match("@a/p")); + } +} diff --git a/src/utils/macros.rs b/src/utils/macros.rs new file mode 100644 index 0000000..4e1bad8 --- /dev/null +++ b/src/utils/macros.rs @@ -0,0 +1,89 @@ +/// Load automatically your manifest (typst.toml). +/// Can specify (or not) the path to the manifest. +#[macro_export] +macro_rules! load_manifest { + () => { + match Manifest::try_find(get_current_dir()?)? { + Some(val) => Ok(val), + None => Err(Error::empty(ErrorKind::Manifest)), + }? + }; + ($var:expr) => { + match Manifest::try_find($var)? { + Some(val) => Ok(val), + None => Err(Error::empty(ErrorKind::Manifest)), + }? + }; +} + +/// Write data to your manifest (typst.toml) +/// Can specify (or not) your path. Data must be provided. +#[macro_export] +macro_rules! write_manifest { + ($var:expr => $path:expr) => { + let tomlfy: String = toml::to_string_pretty($var)?; + fs::write($path, tomlfy)? + }; + ($var:expr) => { + let tomlfy: String = toml::to_string_pretty($var)?; + fs::write("./typst.toml", tomlfy)? + }; +} + + +/// Get the path of a package +#[macro_export] +macro_rules! format_package { + ($namespace:expr) => {{ + (format!( + "{}/{}", + if $namespace == "preview" { + info!("preview found, cache dir use"); + c_packages()? + } else { + info!("no preview found, data dir use"); + d_packages()? + }, + $namespace + )) + }}; + + ($namespace:expr, $package:expr) => {{ + (format!("{}/{}", format_package!($namespace), $package)) + }}; + + ($namespace:ident, $package:ident, $major:ident, $minor:ident, $patch:ident) => {{ + (format!( + "{}/{}.{}.{}", + format_package!($namespace, $package), + $major, + $minor, + $patch + )) + }}; +} + +/// Load ssh credentials +#[macro_export] +macro_rules! load_creds { + ($callbacks:expr, $val:expr) => {{ + $callbacks.credentials(|_, username_from_url, _| { + let binding: String = + env::var("UTPM_USERNAME").unwrap_or(username_from_url.unwrap_or("git").to_string()); + let username: &str = binding.as_str(); + match Cred::ssh_key_from_agent(username) { + Ok(cred) => Ok(cred), + Err(_) => Ok(match env::var("UTPM_PASSPHRASE") { + Ok(s) => { + info!(passphrase = true); + Cred::ssh_key(username, None, Path::new(&$val), Some(s.as_str()))? + } + Err(_) => { + info!(passphrase = false); + Cred::ssh_key(username, None, Path::new(&$val), None)? + } + }), + } + }); + }}; +} diff --git a/src/utils/paths.rs b/src/utils/paths.rs index b6bdc34..e0bc6ad 100644 --- a/src/utils/paths.rs +++ b/src/utils/paths.rs @@ -1,82 +1,139 @@ use std::{ - env::current_dir, - fs::{read, read_dir, symlink_metadata}, + env::{self, current_dir}, + fs::{self, read, read_dir, symlink_metadata}, + path::{self, Path}, + result::Result as R, }; +use dirs::cache_dir; + use super::state::{Error, ErrorKind, Result}; -#[cfg(not(feature = "portable"))] -pub fn get_data_dir() -> String { - match dirs::data_local_dir() { - Some(dir) => match dir.to_str() { - Some(string) => String::from(string), - None => String::from("/.local/share"), //default on linux +pub const TYPST_PACKAGE_URL: &str = "https://github.com/typst/packages"; +pub const DATA_HOME_SHARE: &str = "/.local/share"; +pub const CACHE_HOME: &str = "~/.cache"; +pub const SSH_HOME: &str = "/.ssh"; +pub const TYPST_PACKAGE_PATH: &str = "/typst/packages"; +pub const UTPM_PATH: &str = "/utpm"; +pub const MANIFEST_PATH: &str = "/typst.toml"; +pub const LOCAL_PACKAGES: &str = "/git-packages"; + +/// Get the path to your data directory. +/// Can be edited by using `UTPM_DATA_DIR` env. +/// Used for getting your local packages. +pub fn get_data_dir() -> Result { + match env::var("UTPM_DATA_DIR") { + Ok(str) => Ok(path::absolute(str)?.to_str().unwrap().to_string()), + _ => match dirs::data_local_dir() { + Some(dir) => match dir.to_str() { + Some(string) => Ok(String::from(string)), + None => Ok(String::from(DATA_HOME_SHARE)), //default on linux + }, + None => Ok(String::from(DATA_HOME_SHARE)), }, - None => String::from("/.local/share"), } } +/// Get the path to your home directory. +/// Can be edited by using `UTPM_HOME_DIR` env. +/// Used for getting your ssh keys when running `publish` command. pub fn get_home_dir() -> Result { let err_hd = Error::empty(ErrorKind::HomeDir); - match dirs::home_dir() { - Some(val) => match val.to_str() { - Some(v) => Ok(String::from(v)), + match env::var("UTPM_HOME_DIR") { + Ok(str) => Ok(path::absolute(str)?.to_str().unwrap().to_string()), + _ => match dirs::home_dir() { + Some(val) => match val.to_str() { + Some(v) => Ok(String::from(v)), + None => Err(err_hd), + }, None => Err(err_hd), }, - None => Err(err_hd), } } +/// Get the path to your cache directory. +/// Can be edited by using `UTPM_CACHE_DIR` env. +/// Used for getting your downloaded packages from typst registry. +pub fn get_cache_dir() -> Result { + match env::var("UTPM_CACHE_DIR") { + Ok(str) => Ok(path::absolute(str)?.to_str().unwrap().to_string()), + _ => Ok(cache_dir() + .unwrap_or(CACHE_HOME.into()) + .to_str() + .unwrap_or(CACHE_HOME) + .into()), + } +} + +/// Get the path to your ssh directory. +/// Can be edited by using `UTPM_SSH_DIR` env. +/// Used for getting your ssh keys for the `publish` command. pub fn get_ssh_dir() -> Result { - Ok(get_home_dir()? + "/.ssh") + match env::var("UTPM_SSH_DIR") { + Ok(str) => Ok(path::absolute(str)?.to_str().unwrap().to_string()), + _ => Ok(get_home_dir()? + SSH_HOME), + } } -#[cfg(feature = "portable")] -pub fn get_data_dir() -> String { - get_current_dir().unwrap_or("./".to_string()) + "/utpmp" +/// Get the path to your downloaded packages. +pub fn c_packages() -> Result { + Ok(get_cache_dir()? + TYPST_PACKAGE_PATH) } -pub fn d_packages() -> String { - get_data_dir() + "/typst/packages" +/// Get the path to your local packages. +pub fn d_packages() -> Result { + Ok(get_data_dir()? + TYPST_PACKAGE_PATH) } -pub fn datalocalutpm() -> String { - get_data_dir() + "/utpm" +/// Get the path to your utpm files. +/// Used to get and set your temporary files. +pub fn datalocalutpm() -> Result { + Ok(get_data_dir()? + UTPM_PATH) } -pub fn d_utpm() -> String { - d_packages() + "/utpm" +pub fn default_typst_packages() -> Result { + Ok(datalocalutpm()? + LOCAL_PACKAGES) } +/// Get the path to your current directory. +/// Can be edited by using `UTPM_CURRENT_DIR` env. +/// Used to write and read yout `typst.toml` file. pub fn get_current_dir() -> Result { - match current_dir() { - Ok(val) => match val.to_str() { - Some(v) => Ok(String::from(v)), - None => Err(Error::new( - ErrorKind::CurrentDir, - "There is no current directory.".into(), - )), + match env::var("UTPM_CURRENT_DIR") { + Ok(str) => Ok(path::absolute(str)?.to_str().unwrap().to_string()), + _ => match current_dir() { + Ok(val) => match val.to_str() { + Some(v) => Ok(String::from(v)), + None => Err(Error::new( + ErrorKind::CurrentDir, + "There is no current directory.", + )), + }, + Err(val) => Err(Error::new(ErrorKind::CurrentDir, val.to_string())), }, - Err(val) => Err(Error::new(ErrorKind::CurrentDir, val.to_string())), } } +pub fn has_content(path: impl AsRef) -> Result { + Ok(fs::read_dir(path)?.collect::, _>>()?.len() > 0) +} + pub fn current_package() -> Result { - Ok(get_current_dir()? + "/typst.toml") + Ok(get_current_dir()? + MANIFEST_PATH) } -pub fn check_path_dir(path: &String) -> bool { +pub fn check_path_dir(path: impl AsRef) -> bool { read_dir(path).is_ok() } -pub fn check_path_file(path: &String) -> bool { +pub fn check_path_file(path: impl AsRef) -> bool { read(path).is_ok() } -pub fn check_existing_symlink(path: &String) -> bool { +pub fn check_existing_symlink(path: impl AsRef) -> bool { let x = match symlink_metadata(path) { Ok(val) => val, - Err(_) => return false, + _ => return false, }; x.file_type().is_symlink() } diff --git a/src/utils/specs.rs b/src/utils/specs.rs new file mode 100644 index 0000000..e6daa71 --- /dev/null +++ b/src/utils/specs.rs @@ -0,0 +1,51 @@ +use serde::{Deserialize, Serialize}; +use typst_project::manifest::tool::Tool; + +/// A modify version of the `typst.toml` adding options to utpm +#[derive(Serialize, Deserialize, Clone)] +pub struct Extra { + /// The name of where you store your packages (default: local) + pub namespace: Option, + + /// List of url's for your dependencies (will be resolved with install command) + pub dependencies: Option>, + + /// Exclude files when using `publish` command. + pub exclude: Option>, +} + +impl Default for Extra { + fn default() -> Self { + Self { + namespace: Some("local".to_string()), + dependencies: None, + exclude: None, + } + } +} + +impl Extra { + pub fn new( + namespace: Option, + dependencies: Option>, + exclude: Option>, + ) -> Self { + Self { + namespace, + dependencies, + exclude, + } + } +} + +impl From> for Extra { + fn from(op_tool: Option) -> Self { + match op_tool { + Some(tool) => tool + .get_section("utpm") + .unwrap_or(Some(Extra::default())) + .unwrap_or(Extra::default()), + None => Extra::default(), + } + } +} diff --git a/src/utils/state.rs b/src/utils/state.rs index 8feaecd..5cabd87 100644 --- a/src/utils/state.rs +++ b/src/utils/state.rs @@ -1,6 +1,4 @@ -use owo_colors::OwoColorize; use semver::Version; -use serde_json::{json, Value}; use std::{fmt, io::Error as IError}; /// All errors implemented in utpm @@ -20,88 +18,32 @@ pub enum ErrorKind { Questions, Git, SemVer, -} - -/// Types -#[derive(Debug)] -pub enum ResponseKind { - Message(String), - Value(Value), -} + General, -pub struct Responses { - messages: Vec, - pub json: bool, -} + Author, + Website, + Email, + GithubHandle, -impl Responses { - pub fn new(json: bool) -> Self { - Self { - messages: vec![], - json, - } - } - - pub fn pushs(&mut self, vals: Vec) { - for e in vals { - self.push(e); - } - } + Ident, + License, - pub fn push(&mut self, val: ResponseKind) { - if self.json { - self.messages.push(val); - } else { - match val { - ResponseKind::Message(string) => println!("{}", string), - ResponseKind::Value(val) => println!("{}", val.to_string()), - } - } - } + Serialize, + Deserialize, - pub fn to_str(&self) -> String { - let mut string: String = "".into(); - for message in &self.messages { - match message { - ResponseKind::Message(str) => string = format!("{}{}\n", string, str), - ResponseKind::Value(_) => todo!(), - }; - } - string - } + Manifest, - pub fn to_json(&self) -> Value { - serde_json::from_str( - serde_json::to_string( - &self - .messages - .iter() - .map(|a| match a { - ResponseKind::Message(str) => { - println!( - "{:?}", - str.split(" ") - .map(|a| a.to_string() + " ") - .collect::() - ); - json!({ "message": str }) - } - ResponseKind::Value(val) => val.clone(), - }) - .collect::(), - ) - .unwrap() - .as_str(), - ) - .unwrap() - } + NotEnoughArgs, - pub fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_str()) - } + // Clone + PackageNotValid, + PackageNotExist, + ContentFound, } impl ErrorKind { + // TODO: Remake this system + /// Create a message when there isn't one provided (depreciated) pub fn message(&self) -> String { match self { ErrorKind::CurrentDir => "There is no current directory set.".into(), @@ -113,8 +55,10 @@ impl ErrorKind { ErrorKind::ConfigFile => { "There is no typst.toml in this directory. Try to `utpm create -p` to create a package.".into() } + ErrorKind::Manifest => "There is no `typst.toml` here!".into(), ErrorKind::AlreadyExist(name, version, info) => format!("This package ({name}:{version}) already exist!\n{info} Put --force to force the copy or change the version in 'typst.toml'"), ErrorKind::UnknowError(s) => s.into(), + ErrorKind::NotEnoughArgs => "There is not enough args:".into(), _ => "".into(), } } @@ -134,10 +78,10 @@ pub struct Error { pub type Result = std::result::Result; impl Error { - pub fn new(kind: ErrorKind, message: String) -> Self { + pub fn new(kind: ErrorKind, message: impl Into) -> Self { Self { kind, - message: Some(message), + message: Some(message.into()), } } pub fn empty(kind: ErrorKind) -> Self { @@ -146,24 +90,27 @@ impl Error { message: None, } } - pub fn json(&self) -> Value { - let message = self.message.clone().unwrap_or(self.kind.message()); - json!({ - "type": self.kind.to_string(), - "message": message, - }) - } pub fn to_str(&self) -> String { let kind_message = format!("{} Error", self.kind.to_string()); if let Some(message) = &self.message { - format!("{}: {}", kind_message.bold().red(), message) + format!("{}: {}", kind_message, message) } else { - format!("{}: {}", kind_message.bold().red(), self.kind.message()) + format!("{}: {}", kind_message, self.kind.message()) } } pub fn display(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.to_str()) + if self.message.is_none() { + write!(f, "{}", self.to_str()) + } else { + write!( + f, + "{}: {}\n{}", + format!("{} Error", self.kind.to_string()), + self.kind.message(), + self.message.clone().unwrap() + ) + } } } @@ -173,34 +120,33 @@ impl fmt::Display for Error { } } -impl fmt::Display for Responses { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.display(f) - } -} - -//TODO: impl errors. - -impl From for Error { - fn from(err: IError) -> Error { - Error::new(ErrorKind::IO, err.to_string()) - } -} - -impl From for Error { - fn from(err: inquire::InquireError) -> Error { - Error::new(ErrorKind::Questions, err.to_string()) - } -} - -impl From for Error { - fn from(err: git2::Error) -> Error { - Error::new(ErrorKind::Git, err.to_string()) - } -} - -impl From for Error { - fn from(err: semver::Error) -> Error { - Error::new(ErrorKind::SemVer, err.to_string()) - } +// From `https://github.com/tingerrr/typst-project/blob/e19fb3d68b10fce7d2366f4e5969edac6e2f7d34/src/manifest.rs#L182` +macro_rules! impl_from { + ($err:ty => $var:ident) => { + impl From<$err> for Error { + fn from(err: $err) -> Self { + Error::new(ErrorKind::$var, err.to_string()) + } + } + }; } +impl_from!(semver::Error => SemVer); +#[cfg(any(feature = "install", feature = "clone", feature = "publish"))] +impl_from!(git2::Error => Git); +#[cfg(any(feature = "init", feature = "unlink"))] +impl_from!(inquire::InquireError => Questions); +impl_from!(IError => IO); +impl_from!(typst_project::manifest::Error => General); +impl_from!(typst_project::manifest::author::ParseAuthorError => Author); +impl_from!(typst_project::manifest::author::ParseWebsiteError => Website); +impl_from!(typst_project::manifest::author::ParseEmailError => Email); +impl_from!(typst_project::manifest::author::ParseGitHubHandleError => GithubHandle); +impl_from!(typst_project::manifest::ident::ParseIdentError => Ident); +impl_from!(typst_project::manifest::license::ParseLicenseError => License); + +impl_from!(toml::ser::Error => Serialize); +impl_from!(toml::de::Error => Deserialize); +#[cfg(any(feature = "publish"))] +impl_from!(ignore::Error => General); +#[cfg(any(feature = "publish"))] +impl_from!(octocrab::Error => General); // todo