Compare main … identical-sides
0 changes in identical-sides not in main; 29 the other way. 57 files differ between the two states.
removed .flow/checks.wasm +0 −0
No line changes.
modified .flow/pipeline.kdl +0 −20
| … | 2 unchanged lines |
||
| 3 | 3 | // Earth; the jobs appear as checks on the change. |
|
| 4 | 4 | schema-version 1 |
|
| 5 | 5 | ||
| 6 | - | // Cheap checks on the WASM tier (oxygenflow#96): OxygenFlow's checks module, |
|
| 7 | - | // copied from oxygenflow/.flow/checks.wasm (built there from |
|
| 8 | - | // crates/flow-checks; copy it again when it changes). No image and no KVM, |
|
| 9 | - | // so any runner with the WASM tier takes it: a phone, plex, windows-1. |
|
| 10 | - | sandbox "wasm" { |
|
| 11 | - | runtime "wasm" |
|
| 12 | - | memory-limit "64MiB" |
|
| 13 | - | } |
|
| 14 | - | ||
| 15 | - | // The changelog's shape, and a section for the version Cargo.toml says, so a |
|
| 16 | - | // release never finds its notes missing. |
|
| 17 | - | job "changelog" { |
|
| 18 | - | sandbox "wasm" |
|
| 19 | - | scope "CHANGELOG.md" "Cargo.toml" ".flow/checks.wasm" |
|
| 20 | - | exec ".flow/checks.wasm" "changelog" "CHANGELOG.md" "Cargo.toml" |
|
| 21 | - | } |
|
| 22 | - | ||
| 23 | 6 | // The OxygenFlow build image: Rust with rustfmt and clippy, Node, and every |
|
| 24 | 7 | // crate of Cargo.lock vendored (oxygenflow/images/rust). Rebuild and re-pin |
|
| 25 | 8 | // it when Cargo.lock changes. |
|
| … | 170 unchanged lines |
||
| 196 | 179 | } |
|
| 197 | 180 | artifact "oxy_riscv64.deb" { |
|
| 198 | 181 | path "/src/target/dist-flat/oxy_riscv64.deb" |
|
| 199 | - | } |
|
| 200 | - | artifact "oxy-src.tar.gz" { |
|
| 201 | - | path "/src/target/dist-flat/oxy-src.tar.gz" |
|
| 202 | 182 | } |
|
| 203 | 183 | artifact "SHA256SUMS" { |
|
| 204 | 184 | path "/src/target/dist-flat/SHA256SUMS" |
|
| … | 31 unchanged lines |
modified CHANGELOG.md +1 −32
| 1 | 1 | # Changelog |
|
| 2 | 2 | ||
| 3 | - | ## 0.11.0 (2026-11-04) |
|
| 4 | - | ||
| 5 | - | - **Changed: the changelog is checked on the WASM tier.** A `changelog` job in the pipeline runs OxygenFlow's checks module on any runner with the WASM tier, failing when the changelog's sections are out of shape or Cargo.toml's version has none. |
|
| 6 | - | - **Changed: moved subrepo pins are named (#162).** A pin moved by work inside a subrepo is a pin bump the parent's next commit records, and it used to go in unsaid. `oxy status` now lists it under *Subrepo pins* (old → new), and a subrepo's own uncommitted edits, which the parent does not record; a bare `oxy commit` that records a moved pin says so and how to leave it out (`oxy commit PATHS`). |
|
| 7 | - | - **Added: `oxy submodule remove --delete` (#164).** It deletes the subrepo's directory too, read-only object files and all, and refuses while the subrepo has uncommitted edits (`--force` to delete them anyway); without it, removal says the directory is left and how to delete it. A directory moved by hand used to fail halfway, after the copy, on the read-only files. |
|
| 8 | - | - **Changed: an agent's commit says "awaiting seal", not "unsigned" (#165).** In a checkout that signs keyless under an agent grant, a change of its own author that the next push will seal shows `◌ awaiting seal` in `oxy log` and `oxy show`; "unsigned" is kept for changes nothing will sign. |
|
| 9 | - | - **Fixed: a stale `author.key` can no longer fork your identity (#163).** A checkout that pinned `author.key` to a key a rotation made elsewhere had already succeeded built a second successor of it on `oxy identity delegate add`, splitting the identity in two. `rotate`, `renew` and `delegate add`/`remove` now refuse to start from a key that already has a successor in your home, naming the newest key and the `oxy config` that points at it; their report says which key they started from and which config named it; and `oxy identity show` warns when the configured key is not the newest, and names the key where an identity forks. |
|
| 10 | - | ||
| 11 | - | ## 0.10.0 (2026-11-01) |
|
| 12 | - | ||
| 13 | - | - **Fixed: fetch, pull and clone are far faster with many bookmarks (#158).** They fetched each bookmark in its own exchange with the hub, and changes that bookmarks share were sent again for each one; a pull with nothing new still asked for a bundle per bookmark. Now every bookmark's heads are fetched in one exchange, and none when nothing is new. On a 47 MB repository with 160 bookmarks: a pull with nothing new 169 s → 3.5 s, a clone 324 s → 26 s. `OXY_TIMINGS` now also shows the refs, transparency log and per-bookmark checks of a fetch. |
|
| 14 | - | - **Added: `oxy git colocate`, a `.git` beside `.oxy` (oxygenhub#355).** Your editor's Git features (blame, history, gutter marks) and other Git tools now work on an Oxygen checkout: oxy keeps a `.git` there with the current bookmark exported after every command, Git's index at its tree so `git status` shows only your uncommitted work, and `.oxy/` excluded. One way: commit with oxy. `--off` stops it. |
|
| 15 | - | - **Changed: `.git` is never content.** oxy no longer picks up a `.git` directory at a checkout's top, and checkout refuses a path with a `.git` component at any depth (as Git does), so a change cannot plant Git hooks. |
|
| 16 | - | - **Added: a Git export from the change graph (oxygenhub#355).** oxy-core's `git_export_graph` writes every bookmark and tag to a bare Git repository so that the same changes give the same commits wherever it runs: each change a commit whose parents are its dependencies, each bookmark a branch (a merge of its heads when it has several), tags as tags, incrementally. It is what OxygenHub serves to `git clone`. (`oxy git export` still follows the checkout's own history.) |
|
| 17 | - | - **Added: `oxy mcp`, Oxygen for AI agents (#159).** An MCP server over stdio for a repository: an agent calls typed tools (status, diff, log, show, cat, blame, bookmarks, tags, conflicts, op log, identity, commit, amend, describe, fetch, pull, push, tlog verify) and gets each command's JSON back instead of reading a shell. It signs as the identity its environment configures, so started with an agent home every change is sealed via the agent with nothing to forget per command, and says who in its `initialize` reply. Commits name their paths (or `all: true`); undo and forced pushes are off unless started with `--allow-destructive`. The protocol itself is oxy-core's `mcp` module, for `oh mcp` to reuse. See docs/mcp.md. |
|
| 18 | - | - **Icons for HaikuDepot (#157).** `packaging/haikuports/icons/` has oxy's and oh's icons as HVIF (Haiku's vector format) with 16, 32 and 64 px PNGs, written by `make-icons.py`: the Oxygen mark on a pale tile for oxy, on OxygenHub's dark tile for oh, the same family as the VS Code extensions. |
|
| 19 | - | ||
| 20 | - | ## 0.9.0 (2026-10-29) |
|
| 21 | - | ||
| 22 | - | - **Releases carry their source (#157).** Each release now has `oxy-VERSION-src.tar.gz`, the source as released, reproducible (sorted, fixed times and owners, gzip without a timestamp), listed in SHA256SUMS, for packagers to fetch at a fixed checksum. `packaging/haikuports/make-recipe.py oxy|oh TARBALL VERSION` writes the haikuports recipe from it (oh's from OxygenHub's source tarball); the 0.8.0 recipe, which used the on-demand archive, is gone. |
|
| 23 | - | - **Added: a haikuports recipe for oxy (#156).** `packaging/haikuports/` holds the recipe that builds oxy for HaikuDepot from the release source and every crate in `Cargo.lock`, and the script that writes it for a new release; the 0.8.0 recipe builds with haikuporter on Haiku R1/beta6. |
|
| 24 | - | - **Fixed: an expired checkout token no longer hides your sign-in (#155).** A checkout's own token for a remote (`remote.NAME.token`) is used first, so when it expired every fetch, pull and push answered 401 although `oxy auth login` had a good sign-in for the same hub. A checkout token the hub no longer knows (401) now falls back to that sign-in, with a warning naming `oxy config --unset remote.NAME.token` to drop the stale one; never to another checkout's token, and not when the token is refused for permission (403, 404), so a narrowly scoped token is never swapped for a wider sign-in. When both are refused, the error says to sign in again and unset it. |
|
| 25 | - | - **Added: the `artifact` object type (Cylinder C1, #108).** An artifact is now an object of its own in the store (oxy-core's `artifact` module), named by its object hash as every object is, and `oxy fsck` checks it; its tree stays a blob. Stores written before read as they did: the type is a new one at the end of the list. |
|
| 26 | - | - **Added: artifacts (Cylinder, step C1, #108).** `oxy artifact pack DIR --kind archive|package|container|runner-image|report [--arch --os --entrypoint --env K=V --label K=V]` packs a directory into an artifact: each file an ordinary blob of the repository's store, so files and chunks it holds already cost nothing, under a tree and an artifact encoding in canonical CBOR, named by the BLAKE3 of that encoding (docs/cylinder.md §4.1). `oxy artifact list | show NAME | unpack NAME DEST | verify NAME` (any unique prefix of six characters or more; `--json` on list, show and pack), and `oxy gc` keeps every artifact's blobs. The new `cylinder` crate holds the model. |
|
| 27 | - | - **Added: oxy on Haiku (#154).** oxy builds and runs on Haiku R1/beta6 (x86_64) with HaikuPorts' Rust; `oxy-VERSION-haiku-x86_64.tar.gz` is on the releases page from 0.8.0, with its own `SHA256SUMS-haiku`. The README says how to install it and how to build it (`ZSTD_SYS_USE_PKG_CONFIG=1`). |
|
| 28 | - | ||
| 29 | - | - **Fixed: a subrepo put back after its removal is pinned in the change that registers it (#152).** `oxy submodule remove` leaves a marker so the next snapshot drops the node while the directory stays; the snapshot cleared it only after reading it, so when nothing looked at the working copy between the removal's commit and the subrepo's return, the change that registered it again in `.oxymodules` left it out and a second commit was needed. A marker is now dropped before it is read once the removal is recorded or the path is registered again. |
|
| 30 | - | - **Fixed: `oxy identity create` needs no repository (#144).** Outside one it makes a user identity: the secret and identity go to the oxy home's keys and the user file names it as the author, so a new user or machine sets up an identity first; a repository made or cloned afterwards signs with it. Only `--local` needs a repository, and inside one it is kept there too, as before. |
|
| 3 | + | ## Unreleased |
|
| 31 | 4 | ||
| 32 | - | ## 0.8.0 (2026-10-27) |
|
| 33 | - | ||
| 34 | 5 | - **A server can add a note to a reference a push moved (#148).** `oxy-server`'s `Backend` has a `push_notes` step: each note is added to that accepted reference's result, which `oxy push` shows in place of "updated". OxygenHub will use it to say when a push moves the bookmark of a proposal that has already landed (oxygenhub#329). |
|
| 35 | 6 | ||
| 36 | 7 | - **Identical sides settle by themselves (#146).** Two bookmarks that each resolved the same conflict to the same text conflicted again when merged, both sides the identical lines. A conflict whose sides are byte-identical now settles as `merge=union` adjacent insertions do (#145), in any file and keeping one side: a checkout writes it once ("kept one of its identical sides") and the next commit records the resolution, and a host landing a proposal settles it too. |
|
| 37 | - | ||
| 38 | - | - **A subrepo at its pinned state is unmodified on any bookmark (#147).** A subrepo whose heads were exactly its pin's but which sat on another bookmark than the pin named counted as modified, so `oxy bookmark switch` refused ("the working copy has changes"). Only the state counts now: the same repository at the same heads, or the same Git commit; the recorded pin stands. |
|
| 39 | 8 | ||
| 40 | 9 | - **A shallow clone fetches its checkpoint in parts (#137).** The checkpoint of a big state came as one answer, the whole state's graph blobs in one body (about 2 GB for the VS Code history), built and held whole on both sides. A server now answers `checkpoint-index` (the checkpoint and its history, no graphs), and the client fetches the graph blobs it lacks with `objects`, 2,048 at a time; `objects` reads them in pack order. An older server answers 404 and gets the one-piece request as before. |
|
| 41 | 10 | ||
| … | 284 unchanged lines |
modified Cargo.lock +4 −15
| … | 571 unchanged lines |
||
| 572 | 572 | ] |
|
| 573 | 573 | ||
| 574 | 574 | [[package]] |
|
| 575 | - | name = "cylinder" |
|
| 576 | - | version = "0.11.0" |
|
| 577 | - | dependencies = [ |
|
| 578 | - | "blake3", |
|
| 579 | - | "oxy-core", |
|
| 580 | - | "tempfile", |
|
| 581 | - | "thiserror 1.0.69", |
|
| 582 | - | ] |
|
| 583 | - | ||
| 584 | - | [[package]] |
|
| 585 | 575 | name = "data-encoding" |
|
| 586 | 576 | version = "2.11.1" |
|
| 587 | 577 | source = "registry+https://github.com/rust-lang/crates.io-index" |
|
| … | 911 unchanged lines |
||
| 1499 | 1489 | ||
| 1500 | 1490 | [[package]] |
|
| 1501 | 1491 | name = "oxy" |
|
| 1502 | - | version = "0.11.0" |
|
| 1492 | + | version = "0.7.0" |
|
| 1503 | 1493 | dependencies = [ |
|
| 1504 | 1494 | "anyhow", |
|
| 1505 | 1495 | "clap", |
|
| 1506 | 1496 | "clap_complete", |
|
| 1507 | 1497 | "clap_mangen", |
|
| 1508 | 1498 | "console", |
|
| 1509 | - | "cylinder", |
|
| 1510 | 1499 | "indicatif", |
|
| 1511 | 1500 | "libc", |
|
| 1512 | 1501 | "mimalloc", |
|
| … | 6 unchanged lines |
||
| 1519 | 1508 | ||
| 1520 | 1509 | [[package]] |
|
| 1521 | 1510 | name = "oxy-core" |
|
| 1522 | - | version = "0.11.0" |
|
| 1511 | + | version = "0.7.0" |
|
| 1523 | 1512 | dependencies = [ |
|
| 1524 | 1513 | "blake3", |
|
| 1525 | 1514 | "ed25519-dalek", |
|
| … | 20 unchanged lines |
||
| 1546 | 1535 | ||
| 1547 | 1536 | [[package]] |
|
| 1548 | 1537 | name = "oxy-server" |
|
| 1549 | - | version = "0.11.0" |
|
| 1538 | + | version = "0.7.0" |
|
| 1550 | 1539 | dependencies = [ |
|
| 1551 | 1540 | "axum", |
|
| 1552 | 1541 | "axum-server", |
|
| … | 7 unchanged lines |
||
| 1560 | 1549 | ||
| 1561 | 1550 | [[package]] |
|
| 1562 | 1551 | name = "oxy-strata" |
|
| 1563 | - | version = "0.11.0" |
|
| 1552 | + | version = "0.7.0" |
|
| 1564 | 1553 | dependencies = [ |
|
| 1565 | 1554 | "async-trait", |
|
| 1566 | 1555 | "bytes", |
|
| … | 1419 unchanged lines |
modified Cargo.toml +2 −3
| 1 | 1 | [workspace] |
|
| 2 | - | members = ["crates/oxy-core", "crates/oxy-server", "crates/oxy-strata", "crates/cylinder", "."] |
|
| 2 | + | members = ["crates/oxy-core", "crates/oxy-server", "crates/oxy-strata", "."] |
|
| 3 | 3 | resolver = "2" |
|
| 4 | 4 | ||
| 5 | 5 | [workspace.package] |
|
| 6 | - | version = "0.11.0" |
|
| 6 | + | version = "0.7.0" |
|
| 7 | 7 | edition = "2021" |
|
| 8 | 8 | license = "MIT OR Apache-2.0" |
|
| 9 | 9 | ||
| … | 13 unchanged lines |
||
| 23 | 23 | oxy-core = { path = "crates/oxy-core" } |
|
| 24 | 24 | oxy-server = { path = "crates/oxy-server" } |
|
| 25 | 25 | oxy-strata = { path = "crates/oxy-strata" } |
|
| 26 | - | cylinder = { path = "crates/cylinder" } |
|
| 27 | 26 | clap = { version = "4", features = ["derive"] } |
|
| 28 | 27 | anyhow = "1" |
|
| 29 | 28 | libc = "0.2" |
|
| … | 19 unchanged lines |
modified README.md +1 −7
| … | 15 unchanged lines |
||
| 16 | 16 | ||
| 17 | 17 | Every change the agent makes is attributed to you and signed by the agent. `oxy log`, `oxy verify` and the hub therefore show who did the work, such as "Andy McCall · via Claude Code", and a policy can require that a person has approved it before it lands. |
|
| 18 | 18 | ||
| 19 | - | An agent can also work through `oxy mcp`, an MCP server for the repository: typed tools instead of a shell, signing as the identity it was started with, and nothing destructive unless you allow it (see [docs/mcp.md](docs/mcp.md)). |
|
| 20 | - | ||
| 21 | 19 | See [docs/ai_native_agent_workflows.md](docs/ai_native_agent_workflows.md) for the design and [docs/guide.md](docs/guide.md) §9 for the setup. |
|
| 22 | 20 | ||
| 23 | 21 | ## What is different |
|
| … | 13 unchanged lines |
||
| 37 | 35 | ||
| 38 | 36 | ## Install |
|
| 39 | 37 | ||
| 40 | - | Builds for Linux, macOS, Windows and Haiku are on the [releases page](https://oxygenhub.io/andymccall/oxygen/releases). These are early releases: the macOS and Windows builds are not signed and have had little testing. |
|
| 38 | + | Builds for Linux, macOS and Windows are on the [releases page](https://oxygenhub.io/andymccall/oxygen/releases). These are early releases: the macOS and Windows builds are not signed and have had little testing. |
|
| 41 | 39 | ||
| 42 | 40 | - **Debian, Ubuntu and other Linux with apt** (x86_64, arm64 or riscv64): add the repository at https://oxygenhub.io/apt and install with apt, so `apt upgrade` keeps oxy current: |
|
| 43 | 41 | ||
| … | 13 unchanged lines |
||
| 57 | 55 | - **Other Linux:** unpack `oxy-VERSION-linux-x86_64.tar.gz` (or `-linux-arm64`) and put `oxy` on your `PATH`. |
|
| 58 | 56 | - **macOS** (Apple Silicon or Intel): unpack `oxy-VERSION-macos-arm64.tar.gz` (or `-macos-x86_64`), then `xattr -d com.apple.quarantine oxy`, since the build is not notarised, and put it on your `PATH`. |
|
| 59 | 57 | - **Windows:** unzip `oxy-VERSION-windows-x86_64.zip` and put the folder on your `PATH`. SmartScreen may warn on first run, since the build is not signed. |
|
| 60 | - | - **Haiku** (R1/beta6, x86_64): unpack `oxy-VERSION-haiku-x86_64.tar.gz` and copy `oxy` to `~/config/non-packaged/bin`. It is built in a Haiku guest rather than by OxygenFlow, so it has its own `SHA256SUMS-haiku` and no build attestation. |
|
| 61 | 58 | ||
| 62 | 59 | `oh`, the OxygenHub command line, is released the same way from [OxygenHub's releases](https://oxygenhub.io/andymccall/oxygenhub/releases). |
|
| 63 | 60 | ||
| … | 7 unchanged lines |
||
| 71 | 68 | ``` |
|
| 72 | 69 | ||
| 73 | 70 | The binary is `target/release/oxy`. |
|
| 74 | - | ||
| 75 | - | On Haiku, install `rust_bin` and `zstd_devel` with pkgman and build with `ZSTD_SYS_USE_PKG_CONFIG=1 cargo build --release`: zstd-sys then links Haiku's libzstd, since a system library also references zstd and ld refuses the bundled copy's hidden symbols. |
|
| 76 | 71 | ||
| 77 | 72 | **Changelog:** a commit that changes code adds a line under `## Unreleased` in CHANGELOG.md (Added, Changed, Fixed or Security, with the issue number); versions change only at release. `scripts/changelog-check.sh [PATH...]` checks it for the paths a commit takes (the working copy's changes without any) and runs in the gate; `NO_CHANGELOG=1` for code changes users won't notice. |
|
| 78 | 73 | ||
| … | 78 unchanged lines |
||
| 157 | 152 | | `docs/strata.md` | Keeping a repository on your own storage: S3, GCS, Azure, a directory | |
|
| 158 | 153 | | `docs/protocol.md` | Wire protocol for other implementers | |
|
| 159 | 154 | | `docs/prompt.md` | Shell prompt integration | |
|
| 160 | - | | `docs/mcp.md` | `oxy mcp`: the repository as tools for AI agents | |
|
| 161 | 155 | ||
| 162 | 156 | ## Licence |
|
| 163 | 157 | ||
| … | 1 unchanged lines |
removed crates/cylinder/Cargo.toml +0 −14
| 1 | - | [package] |
|
| 2 | - | name = "cylinder" |
|
| 3 | - | version.workspace = true |
|
| 4 | - | edition.workspace = true |
|
| 5 | - | license.workspace = true |
|
| 6 | - | description = "Cylinder: artifacts as trees of Oxygen chunks (docs/cylinder.md)" |
|
| 7 | - | ||
| 8 | - | [dependencies] |
|
| 9 | - | oxy-core = { path = "../oxy-core" } |
|
| 10 | - | blake3 = "1" |
|
| 11 | - | thiserror = "1" |
|
| 12 | - | ||
| 13 | - | [dev-dependencies] |
|
| 14 | - | tempfile = "3" |
removed crates/cylinder/src/lib.rs +0 −454
| 1 | - | //! Cylinder, step C1 (docs/cylinder.md §4.1): an **artifact** is an |
|
| 2 | - | //! immutable, content-addressed object naming a tree of files, each kept as |
|
| 3 | - | //! an ordinary Oxygen blob of FastCDC BLAKE3 chunks. An image rebuilt with |
|
| 4 | - | //! one changed file moves only that file's changed chunks, and a binary in |
|
| 5 | - | //! a release archive and in a runner image is the same chunks. |
|
| 6 | - | //! |
|
| 7 | - | //! The model is oxy-core's ([`oxy_core::artifact`]): an `artifact` object |
|
| 8 | - | //! in canonical CBOR, named by its object hash, whose tree is a blob. This |
|
| 9 | - | //! crate packs a directory into one, opens, verifies and unpacks it, and |
|
| 10 | - | //! keeps it: `.oxy/artifacts/NAME` records each artifact this repository |
|
| 11 | - | //! keeps, which garbage collection keeps with its tree and files |
|
| 12 | - | //! ([`roots`]). |
|
| 13 | - | ||
| 14 | - | use oxy_core::hash::{ObjectRef, ObjectType}; |
|
| 15 | - | use oxy_core::repo::Repo; |
|
| 16 | - | use std::collections::BTreeMap; |
|
| 17 | - | use std::path::{Path, PathBuf}; |
|
| 18 | - | ||
| 19 | - | pub use oxy_core::artifact::{ |
|
| 20 | - | Artifact, DirTree, Entry, Kind, MODE_EXEC, MODE_FILE, MODE_LINK, VERSION, |
|
| 21 | - | }; |
|
| 22 | - | ||
| 23 | - | #[derive(Debug, thiserror::Error)] |
|
| 24 | - | pub enum Error { |
|
| 25 | - | #[error(transparent)] |
|
| 26 | - | Repo(#[from] oxy_core::repo::RepoError), |
|
| 27 | - | #[error("io: {0}")] |
|
| 28 | - | Io(#[from] std::io::Error), |
|
| 29 | - | #[error("not an artifact: {0}")] |
|
| 30 | - | Object(#[from] oxy_core::objects::ObjectError), |
|
| 31 | - | #[error("store: {0}")] |
|
| 32 | - | Store(#[from] oxy_core::store::StoreError), |
|
| 33 | - | #[error("{0}")] |
|
| 34 | - | Bad(String), |
|
| 35 | - | } |
|
| 36 | - | ||
| 37 | - | pub type Result<T> = std::result::Result<T, Error>; |
|
| 38 | - | ||
| 39 | - | fn bad<T>(msg: impl Into<String>) -> Result<T> { |
|
| 40 | - | Err(Error::Bad(msg.into())) |
|
| 41 | - | } |
|
| 42 | - | ||
| 43 | - | /// What to pack a directory as. |
|
| 44 | - | #[derive(Clone, Debug)] |
|
| 45 | - | pub struct Spec { |
|
| 46 | - | pub kind: Kind, |
|
| 47 | - | pub arch: Option<String>, |
|
| 48 | - | pub os: Option<String>, |
|
| 49 | - | pub entrypoint: Option<Vec<String>>, |
|
| 50 | - | pub env: BTreeMap<String, String>, |
|
| 51 | - | pub labels: BTreeMap<String, String>, |
|
| 52 | - | } |
|
| 53 | - | ||
| 54 | - | impl Spec { |
|
| 55 | - | pub fn new(kind: Kind) -> Spec { |
|
| 56 | - | Spec { |
|
| 57 | - | kind, |
|
| 58 | - | arch: None, |
|
| 59 | - | os: None, |
|
| 60 | - | entrypoint: None, |
|
| 61 | - | env: BTreeMap::new(), |
|
| 62 | - | labels: BTreeMap::new(), |
|
| 63 | - | } |
|
| 64 | - | } |
|
| 65 | - | } |
|
| 66 | - | ||
| 67 | - | /// An artifact kept in a repository, with its name. |
|
| 68 | - | #[derive(Clone, Debug)] |
|
| 69 | - | pub struct Kept { |
|
| 70 | - | pub name: String, |
|
| 71 | - | pub artifact: Artifact, |
|
| 72 | - | /// Its object (its name, as a reference). |
|
| 73 | - | pub object: ObjectRef, |
|
| 74 | - | } |
|
| 75 | - | ||
| 76 | - | fn kept_dir(repo: &Repo) -> PathBuf { |
|
| 77 | - | repo.oxy_dir().join("artifacts") |
|
| 78 | - | } |
|
| 79 | - | ||
| 80 | - | /// Every file under `dir`, by relative path: regular files and links, in |
|
| 81 | - | /// path order. `.oxy` and `.git` directories are not part of an artifact. |
|
| 82 | - | fn walk(dir: &Path) -> Result<Vec<(String, PathBuf, std::fs::Metadata)>> { |
|
| 83 | - | let mut out = Vec::new(); |
|
| 84 | - | let mut stack = vec![(dir.to_path_buf(), String::new())]; |
|
| 85 | - | while let Some((d, rel)) = stack.pop() { |
|
| 86 | - | for e in std::fs::read_dir(&d)? { |
|
| 87 | - | let e = e?; |
|
| 88 | - | let name = e |
|
| 89 | - | .file_name() |
|
| 90 | - | .into_string() |
|
| 91 | - | .map_err(|n| Error::Bad(format!("{n:?} is not UTF-8")))?; |
|
| 92 | - | let path = if rel.is_empty() { |
|
| 93 | - | name.clone() |
|
| 94 | - | } else { |
|
| 95 | - | format!("{rel}/{name}") |
|
| 96 | - | }; |
|
| 97 | - | let md = std::fs::symlink_metadata(e.path())?; |
|
| 98 | - | if md.is_dir() { |
|
| 99 | - | if name != ".oxy" && name != ".git" { |
|
| 100 | - | stack.push((e.path(), path)); |
|
| 101 | - | } |
|
| 102 | - | } else if md.is_file() || md.file_type().is_symlink() { |
|
| 103 | - | out.push((path, e.path(), md)); |
|
| 104 | - | } |
|
| 105 | - | } |
|
| 106 | - | } |
|
| 107 | - | out.sort_by(|a, b| a.0.cmp(&b.0)); |
|
| 108 | - | Ok(out) |
|
| 109 | - | } |
|
| 110 | - | ||
| 111 | - | #[cfg(unix)] |
|
| 112 | - | fn mode_of(md: &std::fs::Metadata) -> u32 { |
|
| 113 | - | use std::os::unix::fs::PermissionsExt; |
|
| 114 | - | if md.file_type().is_symlink() { |
|
| 115 | - | MODE_LINK |
|
| 116 | - | } else if md.permissions().mode() & 0o111 != 0 { |
|
| 117 | - | MODE_EXEC |
|
| 118 | - | } else { |
|
| 119 | - | MODE_FILE |
|
| 120 | - | } |
|
| 121 | - | } |
|
| 122 | - | ||
| 123 | - | #[cfg(not(unix))] |
|
| 124 | - | fn mode_of(md: &std::fs::Metadata) -> u32 { |
|
| 125 | - | if md.file_type().is_symlink() { |
|
| 126 | - | MODE_LINK |
|
| 127 | - | } else { |
|
| 128 | - | MODE_FILE |
|
| 129 | - | } |
|
| 130 | - | } |
|
| 131 | - | ||
| 132 | - | /// Pack the files under `dir` into an artifact of `spec`'s kind in |
|
| 133 | - | /// `repo`'s store: each file a blob, so files and chunks the store holds |
|
| 134 | - | /// already cost nothing; then its tree and its encoding, kept under its |
|
| 135 | - | /// name. |
|
| 136 | - | pub fn pack(repo: &Repo, dir: &Path, spec: &Spec) -> Result<Kept> { |
|
| 137 | - | if !dir.is_dir() { |
|
| 138 | - | return bad(format!("{} is not a directory", dir.display())); |
|
| 139 | - | } |
|
| 140 | - | let mut tree = DirTree::default(); |
|
| 141 | - | for (path, full, md) in walk(dir)? { |
|
| 142 | - | let mode = mode_of(&md); |
|
| 143 | - | let bytes = if mode == MODE_LINK { |
|
| 144 | - | std::fs::read_link(&full)? |
|
| 145 | - | .to_string_lossy() |
|
| 146 | - | .into_owned() |
|
| 147 | - | .into_bytes() |
|
| 148 | - | } else { |
|
| 149 | - | std::fs::read(&full)? |
|
| 150 | - | }; |
|
| 151 | - | let blob = repo.store_blob(&bytes)?; |
|
| 152 | - | tree.entries.push(Entry { |
|
| 153 | - | path, |
|
| 154 | - | mode, |
|
| 155 | - | blob, |
|
| 156 | - | size: bytes.len() as u64, |
|
| 157 | - | }); |
|
| 158 | - | } |
|
| 159 | - | let artifact = Artifact { |
|
| 160 | - | kind: spec.kind, |
|
| 161 | - | arch: spec.arch.clone(), |
|
| 162 | - | os: spec.os.clone(), |
|
| 163 | - | tree: repo.store_blob(&tree.encode())?, |
|
| 164 | - | entrypoint: spec.entrypoint.clone(), |
|
| 165 | - | env: spec.env.clone(), |
|
| 166 | - | labels: spec.labels.clone(), |
|
| 167 | - | total_size: tree.entries.iter().map(|e| e.size).sum(), |
|
| 168 | - | receipt: None, |
|
| 169 | - | }; |
|
| 170 | - | let object = repo.store().put(ObjectType::Artifact, &artifact.encode())?; |
|
| 171 | - | let name = object.to_hex(); |
|
| 172 | - | std::fs::create_dir_all(kept_dir(repo))?; |
|
| 173 | - | std::fs::write(kept_dir(repo).join(&name), b"")?; |
|
| 174 | - | Ok(Kept { |
|
| 175 | - | name, |
|
| 176 | - | artifact, |
|
| 177 | - | object, |
|
| 178 | - | }) |
|
| 179 | - | } |
|
| 180 | - | ||
| 181 | - | /// The names of the artifacts kept in `repo`, sorted. |
|
| 182 | - | pub fn list(repo: &Repo) -> Result<Vec<String>> { |
|
| 183 | - | let mut out = Vec::new(); |
|
| 184 | - | match std::fs::read_dir(kept_dir(repo)) { |
|
| 185 | - | Ok(rd) => { |
|
| 186 | - | for e in rd { |
|
| 187 | - | let n = e?.file_name().to_string_lossy().into_owned(); |
|
| 188 | - | if n.len() == 64 && n.bytes().all(|b| b.is_ascii_hexdigit()) { |
|
| 189 | - | out.push(n); |
|
| 190 | - | } |
|
| 191 | - | } |
|
| 192 | - | } |
|
| 193 | - | Err(e) if e.kind() == std::io::ErrorKind::NotFound => {} |
|
| 194 | - | Err(e) => return Err(e.into()), |
|
| 195 | - | } |
|
| 196 | - | out.sort(); |
|
| 197 | - | Ok(out) |
|
| 198 | - | } |
|
| 199 | - | ||
| 200 | - | /// The kept artifact `name` names, or a unique prefix of it (at least six |
|
| 201 | - | /// characters), read from the store, which checks it against its name. |
|
| 202 | - | pub fn open(repo: &Repo, name: &str) -> Result<Kept> { |
|
| 203 | - | let name = name.to_ascii_lowercase(); |
|
| 204 | - | if name.len() < 6 { |
|
| 205 | - | return bad("name an artifact by at least six characters of its name"); |
|
| 206 | - | } |
|
| 207 | - | let found: Vec<String> = list(repo)? |
|
| 208 | - | .into_iter() |
|
| 209 | - | .filter(|n| n.starts_with(&name)) |
|
| 210 | - | .collect(); |
|
| 211 | - | let full = match found.as_slice() { |
|
| 212 | - | [one] => one.clone(), |
|
| 213 | - | [] => { |
|
| 214 | - | return bad(format!( |
|
| 215 | - | "no artifact {name} here; `oxy artifact list` shows them" |
|
| 216 | - | )) |
|
| 217 | - | } |
|
| 218 | - | _ => { |
|
| 219 | - | return bad(format!( |
|
| 220 | - | "{name} names {} artifacts: give more of the name", |
|
| 221 | - | found.len() |
|
| 222 | - | )) |
|
| 223 | - | } |
|
| 224 | - | }; |
|
| 225 | - | let object = ObjectRef::from_hex(&full).map_or_else( |
|
| 226 | - | || bad(format!("artifact {full}: its record is damaged")), |
|
| 227 | - | Ok, |
|
| 228 | - | )?; |
|
| 229 | - | // The store checks the bytes against the object's name as it reads. |
|
| 230 | - | let bytes = repo.store().get_typed(&object, ObjectType::Artifact)?; |
|
| 231 | - | Ok(Kept { |
|
| 232 | - | name: full, |
|
| 233 | - | artifact: Artifact::decode(&bytes)?, |
|
| 234 | - | object, |
|
| 235 | - | }) |
|
| 236 | - | } |
|
| 237 | - | ||
| 238 | - | /// An artifact's tree. |
|
| 239 | - | pub fn tree(repo: &Repo, a: &Artifact) -> Result<DirTree> { |
|
| 240 | - | Ok(DirTree::decode(&repo.read_blob(&a.tree)?)?) |
|
| 241 | - | } |
|
| 242 | - | ||
| 243 | - | /// Check that every file of `k` is in the store whole: its bytes read, at |
|
| 244 | - | /// the size its tree says. Answers how many files were read. |
|
| 245 | - | pub fn verify(repo: &Repo, k: &Kept) -> Result<usize> { |
|
| 246 | - | let t = tree(repo, &k.artifact)?; |
|
| 247 | - | let mut total = 0; |
|
| 248 | - | for e in &t.entries { |
|
| 249 | - | let n = repo.read_blob(&e.blob)?.len() as u64; |
|
| 250 | - | if n != e.size { |
|
| 251 | - | return bad(format!( |
|
| 252 | - | "{}: {n} bytes, but the tree says {}", |
|
| 253 | - | e.path, e.size |
|
| 254 | - | )); |
|
| 255 | - | } |
|
| 256 | - | total += n; |
|
| 257 | - | } |
|
| 258 | - | if total != k.artifact.total_size { |
|
| 259 | - | return bad(format!( |
|
| 260 | - | "the files are {total} bytes together, but the artifact says {}", |
|
| 261 | - | k.artifact.total_size |
|
| 262 | - | )); |
|
| 263 | - | } |
|
| 264 | - | Ok(t.entries.len()) |
|
| 265 | - | } |
|
| 266 | - | ||
| 267 | - | /// Write `k`'s files under `dest`, which must not exist or be empty. |
|
| 268 | - | pub fn unpack(repo: &Repo, k: &Kept, dest: &Path) -> Result<usize> { |
|
| 269 | - | if dest.exists() && std::fs::read_dir(dest)?.next().is_some() { |
|
| 270 | - | return bad(format!("{} is not empty", dest.display())); |
|
| 271 | - | } |
|
| 272 | - | let t = tree(repo, &k.artifact)?; |
|
| 273 | - | for e in &t.entries { |
|
| 274 | - | let out = dest.join(&e.path); |
|
| 275 | - | if let Some(p) = out.parent() { |
|
| 276 | - | std::fs::create_dir_all(p)?; |
|
| 277 | - | } |
|
| 278 | - | let bytes = repo.read_blob(&e.blob)?; |
|
| 279 | - | if e.mode == MODE_LINK { |
|
| 280 | - | #[cfg(unix)] |
|
| 281 | - | std::os::unix::fs::symlink(String::from_utf8_lossy(&bytes).as_ref(), &out)?; |
|
| 282 | - | #[cfg(not(unix))] |
|
| 283 | - | std::fs::write(&out, &bytes)?; |
|
| 284 | - | continue; |
|
| 285 | - | } |
|
| 286 | - | std::fs::write(&out, &bytes)?; |
|
| 287 | - | #[cfg(unix)] |
|
| 288 | - | if e.mode == MODE_EXEC { |
|
| 289 | - | use std::os::unix::fs::PermissionsExt; |
|
| 290 | - | std::fs::set_permissions(&out, std::fs::Permissions::from_mode(0o755))?; |
|
| 291 | - | } |
|
| 292 | - | } |
|
| 293 | - | Ok(t.entries.len()) |
|
| 294 | - | } |
|
| 295 | - | ||
| 296 | - | /// The blobs garbage collection must keep for the kept artifacts: each |
|
| 297 | - | /// one's encoding, its tree and its files (`Repo::gc_keeping`). |
|
| 298 | - | pub fn roots(repo: &Repo) -> Result<Vec<ObjectRef>> { |
|
| 299 | - | let mut out = Vec::new(); |
|
| 300 | - | for name in list(repo)? { |
|
| 301 | - | let k = open(repo, &name)?; |
|
| 302 | - | out.push(k.object); |
|
| 303 | - | out.push(k.artifact.tree); |
|
| 304 | - | out.extend(tree(repo, &k.artifact)?.entries.iter().map(|e| e.blob)); |
|
| 305 | - | } |
|
| 306 | - | Ok(out) |
|
| 307 | - | } |
|
| 308 | - | ||
| 309 | - | #[cfg(test)] |
|
| 310 | - | mod tests { |
|
| 311 | - | use super::*; |
|
| 312 | - | use oxy_core::cbor::{self, Value}; |
|
| 313 | - | ||
| 314 | - | fn repo(dir: &Path) -> Repo { |
|
| 315 | - | Repo::init(&dir.join("repo")).unwrap() |
|
| 316 | - | } |
|
| 317 | - | ||
| 318 | - | #[test] |
|
| 319 | - | fn a_directory_packs_into_an_artifact_and_back() { |
|
| 320 | - | let t = tempfile::tempdir().unwrap(); |
|
| 321 | - | let r = repo(t.path()); |
|
| 322 | - | let src = t.path().join("out"); |
|
| 323 | - | std::fs::create_dir_all(src.join("bin")).unwrap(); |
|
| 324 | - | std::fs::write(src.join("README"), b"hello\n").unwrap(); |
|
| 325 | - | std::fs::write(src.join("bin/tool"), vec![7u8; 300_000]).unwrap(); |
|
| 326 | - | #[cfg(unix)] |
|
| 327 | - | { |
|
| 328 | - | use std::os::unix::fs::PermissionsExt; |
|
| 329 | - | std::fs::set_permissions(src.join("bin/tool"), std::fs::Permissions::from_mode(0o755)) |
|
| 330 | - | .unwrap(); |
|
| 331 | - | std::os::unix::fs::symlink("bin/tool", src.join("tool")).unwrap(); |
|
| 332 | - | } |
|
| 333 | - | let mut spec = Spec::new(Kind::Archive); |
|
| 334 | - | spec.arch = Some("x86_64".into()); |
|
| 335 | - | spec.labels.insert("version".into(), "0.1.0".into()); |
|
| 336 | - | let k = pack(&r, &src, &spec).unwrap(); |
|
| 337 | - | assert_eq!(k.name, k.artifact.name().to_hex()); |
|
| 338 | - | assert_eq!( |
|
| 339 | - | k.artifact.total_size, |
|
| 340 | - | 300_006 + if cfg!(unix) { 8 } else { 0 } |
|
| 341 | - | ); |
|
| 342 | - | assert_eq!(list(&r).unwrap(), vec![k.name.clone()]); |
|
| 343 | - | ||
| 344 | - | let again = open(&r, &k.name[..10]).unwrap(); |
|
| 345 | - | assert_eq!(again.artifact, k.artifact); |
|
| 346 | - | let paths: Vec<(String, u32)> = tree(&r, &again.artifact) |
|
| 347 | - | .unwrap() |
|
| 348 | - | .entries |
|
| 349 | - | .into_iter() |
|
| 350 | - | .map(|e| (e.path, e.mode)) |
|
| 351 | - | .collect(); |
|
| 352 | - | assert_eq!(paths[0], ("README".into(), MODE_FILE)); |
|
| 353 | - | assert_eq!( |
|
| 354 | - | paths[1], |
|
| 355 | - | ( |
|
| 356 | - | "bin/tool".into(), |
|
| 357 | - | if cfg!(unix) { MODE_EXEC } else { MODE_FILE } |
|
| 358 | - | ) |
|
| 359 | - | ); |
|
| 360 | - | assert_eq!(verify(&r, &again).unwrap(), paths.len()); |
|
| 361 | - | ||
| 362 | - | let dest = t.path().join("back"); |
|
| 363 | - | unpack(&r, &again, &dest).unwrap(); |
|
| 364 | - | assert_eq!( |
|
| 365 | - | std::fs::read(dest.join("bin/tool")).unwrap(), |
|
| 366 | - | vec![7u8; 300_000] |
|
| 367 | - | ); |
|
| 368 | - | #[cfg(unix)] |
|
| 369 | - | assert_eq!( |
|
| 370 | - | std::fs::read_link(dest.join("tool")).unwrap(), |
|
| 371 | - | Path::new("bin/tool") |
|
| 372 | - | ); |
|
| 373 | - | assert!(unpack(&r, &again, &dest) |
|
| 374 | - | .unwrap_err() |
|
| 375 | - | .to_string() |
|
| 376 | - | .contains("not empty")); |
|
| 377 | - | ||
| 378 | - | // The same files pack to the same name; garbage collection keeps it. |
|
| 379 | - | assert_eq!(pack(&r, &src, &spec).unwrap().name, k.name); |
|
| 380 | - | let keep = roots(&r).unwrap(); |
|
| 381 | - | assert!(keep.contains(&k.object) && keep.contains(&k.artifact.tree)); |
|
| 382 | - | r.gc_keeping(true, &keep, &mut |_| {}).unwrap(); |
|
| 383 | - | // An artifact is an object of its own, which fsck reads and accepts. |
|
| 384 | - | let report = r.fsck().unwrap(); |
|
| 385 | - | let errors: Vec<_> = report |
|
| 386 | - | .problems |
|
| 387 | - | .iter() |
|
| 388 | - | .filter(|p| p.severity == oxy_core::repo::Severity::Error) |
|
| 389 | - | .collect(); |
|
| 390 | - | assert!(errors.is_empty(), "{errors:?}"); |
|
| 391 | - | assert_eq!( |
|
| 392 | - | verify(&r, &open(&r, &k.name).unwrap()).unwrap(), |
|
| 393 | - | paths.len() |
|
| 394 | - | ); |
|
| 395 | - | } |
|
| 396 | - | ||
| 397 | - | #[test] |
|
| 398 | - | fn encodings_are_canonical_and_checked() { |
|
| 399 | - | let a = Artifact { |
|
| 400 | - | kind: Kind::RunnerImage, |
|
| 401 | - | arch: Some("riscv64".into()), |
|
| 402 | - | os: Some("linux".into()), |
|
| 403 | - | tree: ObjectRef([1; 32]), |
|
| 404 | - | entrypoint: Some(vec!["/sbin/init".into()]), |
|
| 405 | - | env: [("PATH".to_string(), "/bin".to_string())].into(), |
|
| 406 | - | labels: BTreeMap::new(), |
|
| 407 | - | total_size: 42, |
|
| 408 | - | receipt: Some(ObjectRef([2; 32])), |
|
| 409 | - | }; |
|
| 410 | - | let bytes = a.encode(); |
|
| 411 | - | assert_eq!(Artifact::decode(&bytes).unwrap(), a); |
|
| 412 | - | assert_eq!( |
|
| 413 | - | a.name(), |
|
| 414 | - | oxy_core::hash::hash_object(ObjectType::Artifact, &bytes) |
|
| 415 | - | ); |
|
| 416 | - | assert!(Kind::parse("tarball") |
|
| 417 | - | .unwrap_err() |
|
| 418 | - | .to_string() |
|
| 419 | - | .contains("runner-image")); |
|
| 420 | - | ||
| 421 | - | let wrong = |v: Value| Artifact::decode(&cbor::encode(&v)).unwrap_err().to_string(); |
|
| 422 | - | assert!(wrong(Value::map([(0, Value::Uint(2))])).contains("version")); |
|
| 423 | - | assert!(wrong(Value::map([(0, Value::Uint(1)), (10, Value::Null)])).contains("key 10")); |
|
| 424 | - | ||
| 425 | - | let t = DirTree { |
|
| 426 | - | entries: vec![Entry { |
|
| 427 | - | path: "a".into(), |
|
| 428 | - | mode: MODE_FILE, |
|
| 429 | - | blob: ObjectRef([3; 32]), |
|
| 430 | - | size: 1, |
|
| 431 | - | }], |
|
| 432 | - | }; |
|
| 433 | - | assert_eq!(DirTree::decode(&t.encode()).unwrap(), t); |
|
| 434 | - | let entry = |p: &str, mode: u32| { |
|
| 435 | - | Value::Array(vec![ |
|
| 436 | - | Value::Text(p.into()), |
|
| 437 | - | Value::Uint(mode as u64), |
|
| 438 | - | Value::Bytes(vec![0; 32]), |
|
| 439 | - | Value::Uint(0), |
|
| 440 | - | ]) |
|
| 441 | - | }; |
|
| 442 | - | let tree = |items: Vec<Value>| { |
|
| 443 | - | DirTree::decode(&cbor::encode(&Value::map([ |
|
| 444 | - | (0, Value::Uint(1)), |
|
| 445 | - | (1, Value::Array(items)), |
|
| 446 | - | ]))) |
|
| 447 | - | .unwrap_err() |
|
| 448 | - | .to_string() |
|
| 449 | - | }; |
|
| 450 | - | assert!(tree(vec![entry("../x", MODE_FILE)]).contains("clean")); |
|
| 451 | - | assert!(tree(vec![entry("b", MODE_FILE), entry("a", MODE_FILE)]).contains("order")); |
|
| 452 | - | assert!(tree(vec![entry("a", 0o040000)]).contains("mode")); |
|
| 453 | - | } |
|
| 454 | - | } |
removed crates/oxy-core/src/artifact.rs +0 −303
| 1 | - | //! Artifacts (Cylinder, docs/cylinder.md §4.1, oxygen#108): an immutable |
|
| 2 | - | //! object naming a tree of files, each an ordinary blob of FastCDC BLAKE3 |
|
| 3 | - | //! chunks, so an image rebuilt with one changed file moves only that file's |
|
| 4 | - | //! changed chunks, and a binary in an archive and in an image is the same |
|
| 5 | - | //! chunks. An artifact is an object of its own (`artifact`) in canonical |
|
| 6 | - | //! CBOR; its tree is a blob. The `cylinder` crate packs, unpacks and keeps |
|
| 7 | - | //! them. |
|
| 8 | - | ||
| 9 | - | use crate::cbor::{self, Value}; |
|
| 10 | - | use crate::hash::{hash_object, ObjectRef, ObjectType}; |
|
| 11 | - | use crate::objects::{schema, ObjectError}; |
|
| 12 | - | use std::collections::BTreeMap; |
|
| 13 | - | ||
| 14 | - | type R<T> = std::result::Result<T, ObjectError>; |
|
| 15 | - | ||
| 16 | - | /// The encoding's version this crate writes and reads. |
|
| 17 | - | pub const VERSION: u64 = 1; |
|
| 18 | - | ||
| 19 | - | /// What an artifact is for. |
|
| 20 | - | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
|
| 21 | - | pub enum Kind { |
|
| 22 | - | Container, |
|
| 23 | - | RunnerImage, |
|
| 24 | - | Package, |
|
| 25 | - | Archive, |
|
| 26 | - | Report, |
|
| 27 | - | } |
|
| 28 | - | ||
| 29 | - | impl Kind { |
|
| 30 | - | pub const ALL: [Kind; 5] = [ |
|
| 31 | - | Kind::Container, |
|
| 32 | - | Kind::RunnerImage, |
|
| 33 | - | Kind::Package, |
|
| 34 | - | Kind::Archive, |
|
| 35 | - | Kind::Report, |
|
| 36 | - | ]; |
|
| 37 | - | ||
| 38 | - | pub fn as_str(self) -> &'static str { |
|
| 39 | - | match self { |
|
| 40 | - | Kind::Container => "container", |
|
| 41 | - | Kind::RunnerImage => "runner-image", |
|
| 42 | - | Kind::Package => "package", |
|
| 43 | - | Kind::Archive => "archive", |
|
| 44 | - | Kind::Report => "report", |
|
| 45 | - | } |
|
| 46 | - | } |
|
| 47 | - | ||
| 48 | - | pub fn parse(s: &str) -> R<Kind> { |
|
| 49 | - | Kind::ALL.into_iter().find(|k| k.as_str() == s).map_or_else( |
|
| 50 | - | || { |
|
| 51 | - | schema(format!( |
|
| 52 | - | "{s:?} is not a kind of artifact: {}", |
|
| 53 | - | Kind::ALL.map(|k| k.as_str()).join(", ") |
|
| 54 | - | )) |
|
| 55 | - | }, |
|
| 56 | - | Ok, |
|
| 57 | - | ) |
|
| 58 | - | } |
|
| 59 | - | } |
|
| 60 | - | ||
| 61 | - | /// A file's mode in a tree: a regular file, an executable one, or a |
|
| 62 | - | /// symbolic link (whose blob is its target). |
|
| 63 | - | pub const MODE_FILE: u32 = 0o100644; |
|
| 64 | - | pub const MODE_EXEC: u32 = 0o100755; |
|
| 65 | - | pub const MODE_LINK: u32 = 0o120000; |
|
| 66 | - | ||
| 67 | - | /// A file of an artifact's tree. |
|
| 68 | - | #[derive(Clone, Debug, PartialEq, Eq)] |
|
| 69 | - | pub struct Entry { |
|
| 70 | - | /// `/`-separated, relative, never `.` or `..` parts. |
|
| 71 | - | pub path: String, |
|
| 72 | - | pub mode: u32, |
|
| 73 | - | pub blob: ObjectRef, |
|
| 74 | - | pub size: u64, |
|
| 75 | - | } |
|
| 76 | - | ||
| 77 | - | /// An artifact's files, in path order: paths, modes, blobs and sizes. |
|
| 78 | - | #[derive(Clone, Debug, Default, PartialEq, Eq)] |
|
| 79 | - | pub struct DirTree { |
|
| 80 | - | pub entries: Vec<Entry>, |
|
| 81 | - | } |
|
| 82 | - | ||
| 83 | - | fn path_ok(p: &str) -> bool { |
|
| 84 | - | !p.is_empty() |
|
| 85 | - | && !p.starts_with('/') |
|
| 86 | - | && p.split('/').all(|s| !s.is_empty() && s != "." && s != "..") |
|
| 87 | - | } |
|
| 88 | - | ||
| 89 | - | fn obj(r: &ObjectRef) -> Value { |
|
| 90 | - | Value::Bytes(r.0.to_vec()) |
|
| 91 | - | } |
|
| 92 | - | ||
| 93 | - | fn get_obj(v: &Value, what: &str) -> R<ObjectRef> { |
|
| 94 | - | match v.as_bytes() { |
|
| 95 | - | Some(b) if b.len() == 32 => { |
|
| 96 | - | let mut a = [0u8; 32]; |
|
| 97 | - | a.copy_from_slice(b); |
|
| 98 | - | Ok(ObjectRef(a)) |
|
| 99 | - | } |
|
| 100 | - | _ => schema(format!("{what} is not an object reference")), |
|
| 101 | - | } |
|
| 102 | - | } |
|
| 103 | - | ||
| 104 | - | fn get_text(v: &Value, what: &str) -> R<String> { |
|
| 105 | - | v.as_text() |
|
| 106 | - | .map(str::to_string) |
|
| 107 | - | .map_or_else(|| schema(format!("{what} is not text")), Ok) |
|
| 108 | - | } |
|
| 109 | - | ||
| 110 | - | fn get_uint(v: &Value, what: &str) -> R<u64> { |
|
| 111 | - | v.as_uint() |
|
| 112 | - | .map_or_else(|| schema(format!("{what} is not a number")), Ok) |
|
| 113 | - | } |
|
| 114 | - | ||
| 115 | - | impl DirTree { |
|
| 116 | - | pub fn encode(&self) -> Vec<u8> { |
|
| 117 | - | let entries = self |
|
| 118 | - | .entries |
|
| 119 | - | .iter() |
|
| 120 | - | .map(|e| { |
|
| 121 | - | Value::Array(vec![ |
|
| 122 | - | Value::Text(e.path.clone()), |
|
| 123 | - | Value::Uint(e.mode as u64), |
|
| 124 | - | obj(&e.blob), |
|
| 125 | - | Value::Uint(e.size), |
|
| 126 | - | ]) |
|
| 127 | - | }) |
|
| 128 | - | .collect(); |
|
| 129 | - | cbor::encode(&Value::map([ |
|
| 130 | - | (0, Value::Uint(VERSION)), |
|
| 131 | - | (1, Value::Array(entries)), |
|
| 132 | - | ])) |
|
| 133 | - | } |
|
| 134 | - | ||
| 135 | - | /// Read and check a tree: a known version, clean paths, each once, in |
|
| 136 | - | /// order, with a known mode. |
|
| 137 | - | pub fn decode(bytes: &[u8]) -> R<DirTree> { |
|
| 138 | - | let v = cbor::decode(bytes)?; |
|
| 139 | - | let m = v.as_map().map_or_else(|| schema("a tree is a map"), Ok)?; |
|
| 140 | - | if m.get(&0).and_then(Value::as_uint) != Some(VERSION) { |
|
| 141 | - | return schema(format!( |
|
| 142 | - | "tree version {:?} is not known; this reads {VERSION}", |
|
| 143 | - | m.get(&0) |
|
| 144 | - | )); |
|
| 145 | - | } |
|
| 146 | - | let mut entries = Vec::new(); |
|
| 147 | - | for item in m.get(&1).and_then(Value::as_array).unwrap_or_default() { |
|
| 148 | - | let [p, mode, blob, size] = item.as_array().unwrap_or_default() else { |
|
| 149 | - | return schema("a tree entry is [path, mode, blob, size]"); |
|
| 150 | - | }; |
|
| 151 | - | let path = get_text(p, "a path")?; |
|
| 152 | - | let mode = get_uint(mode, "a mode")? as u32; |
|
| 153 | - | if !path_ok(&path) { |
|
| 154 | - | return schema(format!("{path:?} is not a clean relative path")); |
|
| 155 | - | } |
|
| 156 | - | if ![MODE_FILE, MODE_EXEC, MODE_LINK].contains(&mode) { |
|
| 157 | - | return schema(format!( |
|
| 158 | - | "{path}: mode {mode:o} is not a file, an executable or a link" |
|
| 159 | - | )); |
|
| 160 | - | } |
|
| 161 | - | if entries.last().is_some_and(|l: &Entry| l.path >= path) { |
|
| 162 | - | return schema(format!( |
|
| 163 | - | "{path}: entries are not in path order, or one is there twice" |
|
| 164 | - | )); |
|
| 165 | - | } |
|
| 166 | - | entries.push(Entry { |
|
| 167 | - | path, |
|
| 168 | - | mode, |
|
| 169 | - | blob: get_obj(blob, "a blob")?, |
|
| 170 | - | size: get_uint(size, "a size")?, |
|
| 171 | - | }); |
|
| 172 | - | } |
|
| 173 | - | Ok(DirTree { entries }) |
|
| 174 | - | } |
|
| 175 | - | } |
|
| 176 | - | ||
| 177 | - | /// An artifact (docs/cylinder.md §4.1). |
|
| 178 | - | #[derive(Clone, Debug, PartialEq, Eq)] |
|
| 179 | - | pub struct Artifact { |
|
| 180 | - | pub kind: Kind, |
|
| 181 | - | /// `x86_64`, `riscv64`, `aarch64`. |
|
| 182 | - | pub arch: Option<String>, |
|
| 183 | - | /// `linux`, `darwin`, `none`. |
|
| 184 | - | pub os: Option<String>, |
|
| 185 | - | /// The [`DirTree`]'s blob. |
|
| 186 | - | pub tree: ObjectRef, |
|
| 187 | - | /// The default command, for a container or an image. |
|
| 188 | - | pub entrypoint: Option<Vec<String>>, |
|
| 189 | - | pub env: BTreeMap<String, String>, |
|
| 190 | - | pub labels: BTreeMap<String, String>, |
|
| 191 | - | /// The files' bytes together. |
|
| 192 | - | pub total_size: u64, |
|
| 193 | - | /// The receipt of the Flow job that built it, when one did. |
|
| 194 | - | pub receipt: Option<ObjectRef>, |
|
| 195 | - | } |
|
| 196 | - | ||
| 197 | - | fn pairs(m: &BTreeMap<String, String>) -> Value { |
|
| 198 | - | if m.is_empty() { |
|
| 199 | - | return Value::Null; |
|
| 200 | - | } |
|
| 201 | - | Value::Array( |
|
| 202 | - | m.iter() |
|
| 203 | - | .map(|(k, v)| Value::Array(vec![Value::Text(k.clone()), Value::Text(v.clone())])) |
|
| 204 | - | .collect(), |
|
| 205 | - | ) |
|
| 206 | - | } |
|
| 207 | - | ||
| 208 | - | fn get_pairs(v: Option<&Value>, what: &str) -> R<BTreeMap<String, String>> { |
|
| 209 | - | let mut out = BTreeMap::new(); |
|
| 210 | - | let Some(v) = v.filter(|v| !v.is_null()) else { |
|
| 211 | - | return Ok(out); |
|
| 212 | - | }; |
|
| 213 | - | for p in v |
|
| 214 | - | .as_array() |
|
| 215 | - | .map_or_else(|| schema(format!("{what} is a list of pairs")), Ok)? |
|
| 216 | - | { |
|
| 217 | - | let [k, val] = p.as_array().unwrap_or_default() else { |
|
| 218 | - | return schema(format!("{what}: a pair is [key, value]")); |
|
| 219 | - | }; |
|
| 220 | - | let k = get_text(k, what)?; |
|
| 221 | - | if out.insert(k.clone(), get_text(val, what)?).is_some() { |
|
| 222 | - | return schema(format!("{what}: {k} is there twice")); |
|
| 223 | - | } |
|
| 224 | - | } |
|
| 225 | - | Ok(out) |
|
| 226 | - | } |
|
| 227 | - | ||
| 228 | - | fn opt_text(v: &Option<String>) -> Value { |
|
| 229 | - | v.as_ref().map_or(Value::Null, |s| Value::Text(s.clone())) |
|
| 230 | - | } |
|
| 231 | - | ||
| 232 | - | impl Artifact { |
|
| 233 | - | /// Its canonical CBOR, keys as in docs/cylinder.md §4.1. |
|
| 234 | - | pub fn encode(&self) -> Vec<u8> { |
|
| 235 | - | let entry = self.entrypoint.as_ref().map_or(Value::Null, |a| { |
|
| 236 | - | Value::Array(a.iter().cloned().map(Value::Text).collect()) |
|
| 237 | - | }); |
|
| 238 | - | cbor::encode(&Value::map([ |
|
| 239 | - | (0, Value::Uint(VERSION)), |
|
| 240 | - | (1, Value::Text(self.kind.as_str().into())), |
|
| 241 | - | (2, opt_text(&self.arch)), |
|
| 242 | - | (3, opt_text(&self.os)), |
|
| 243 | - | (4, obj(&self.tree)), |
|
| 244 | - | (5, entry), |
|
| 245 | - | (6, pairs(&self.env)), |
|
| 246 | - | (7, pairs(&self.labels)), |
|
| 247 | - | (8, Value::Uint(self.total_size)), |
|
| 248 | - | (9, self.receipt.as_ref().map_or(Value::Null, obj)), |
|
| 249 | - | ])) |
|
| 250 | - | } |
|
| 251 | - | ||
| 252 | - | pub fn decode(bytes: &[u8]) -> R<Artifact> { |
|
| 253 | - | let v = cbor::decode(bytes)?; |
|
| 254 | - | let m = v |
|
| 255 | - | .as_map() |
|
| 256 | - | .map_or_else(|| schema("an artifact is a map"), Ok)?; |
|
| 257 | - | if m.get(&0).and_then(Value::as_uint) != Some(VERSION) { |
|
| 258 | - | return schema(format!( |
|
| 259 | - | "artifact version {:?} is not known; this reads {VERSION}", |
|
| 260 | - | m.get(&0) |
|
| 261 | - | )); |
|
| 262 | - | } |
|
| 263 | - | if let Some(k) = m.keys().find(|k| **k > 9) { |
|
| 264 | - | return schema(format!("key {k} is not part of an artifact")); |
|
| 265 | - | } |
|
| 266 | - | let text = |k: u64, what: &str| -> R<Option<String>> { |
|
| 267 | - | match m.get(&k) { |
|
| 268 | - | None | Some(Value::Null) => Ok(None), |
|
| 269 | - | Some(v) => get_text(v, what).map(Some), |
|
| 270 | - | } |
|
| 271 | - | }; |
|
| 272 | - | let entrypoint = match m.get(&5) { |
|
| 273 | - | None | Some(Value::Null) => None, |
|
| 274 | - | Some(v) => Some( |
|
| 275 | - | v.as_array() |
|
| 276 | - | .unwrap_or_default() |
|
| 277 | - | .iter() |
|
| 278 | - | .map(|a| get_text(a, "the entrypoint")) |
|
| 279 | - | .collect::<R<_>>()?, |
|
| 280 | - | ), |
|
| 281 | - | }; |
|
| 282 | - | let receipt = match m.get(&9) { |
|
| 283 | - | None | Some(Value::Null) => None, |
|
| 284 | - | Some(v) => Some(get_obj(v, "the receipt")?), |
|
| 285 | - | }; |
|
| 286 | - | Ok(Artifact { |
|
| 287 | - | kind: Kind::parse(&text(1, "the kind")?.unwrap_or_default())?, |
|
| 288 | - | arch: text(2, "the architecture")?, |
|
| 289 | - | os: text(3, "the system")?, |
|
| 290 | - | tree: get_obj(m.get(&4).unwrap_or(&Value::Null), "the tree")?, |
|
| 291 | - | entrypoint, |
|
| 292 | - | env: get_pairs(m.get(&6), "env")?, |
|
| 293 | - | labels: get_pairs(m.get(&7), "labels")?, |
|
| 294 | - | total_size: get_uint(m.get(&8).unwrap_or(&Value::Null), "the size")?, |
|
| 295 | - | receipt, |
|
| 296 | - | }) |
|
| 297 | - | } |
|
| 298 | - | ||
| 299 | - | /// Its name: its object's hash, as every Oxygen object is named. |
|
| 300 | - | pub fn name(&self) -> ObjectRef { |
|
| 301 | - | hash_object(ObjectType::Artifact, &self.encode()) |
|
| 302 | - | } |
|
| 303 | - | } |
modified crates/oxy-core/src/hash.rs +1 −6
| … | 67 unchanged lines |
||
| 68 | 68 | Certificate, |
|
| 69 | 69 | /// An author's grant to a certified subject (§14.7). |
|
| 70 | 70 | Grant, |
|
| 71 | - | /// A tree of files as one immutable thing: an image, a package, an |
|
| 72 | - | /// archive (Cylinder, docs/cylinder.md §4.1). |
|
| 73 | - | Artifact, |
|
| 74 | 71 | } |
|
| 75 | 72 | ||
| 76 | 73 | impl ObjectType { |
|
| 77 | - | pub const ALL: [ObjectType; 13] = [ |
|
| 74 | + | pub const ALL: [ObjectType; 12] = [ |
|
| 78 | 75 | ObjectType::Chunk, |
|
| 79 | 76 | ObjectType::Blob, |
|
| 80 | 77 | ObjectType::Change, |
|
| … | 6 unchanged lines |
||
| 87 | 84 | ObjectType::Receipt, |
|
| 88 | 85 | ObjectType::Certificate, |
|
| 89 | 86 | ObjectType::Grant, |
|
| 90 | - | ObjectType::Artifact, |
|
| 91 | 87 | ]; |
|
| 92 | 88 | ||
| 93 | 89 | pub fn name(self) -> &'static str { |
|
| … | 10 unchanged lines |
||
| 104 | 100 | ObjectType::Receipt => "receipt", |
|
| 105 | 101 | ObjectType::Certificate => "certificate", |
|
| 106 | 102 | ObjectType::Grant => "grant", |
|
| 107 | - | ObjectType::Artifact => "artifact", |
|
| 108 | 103 | } |
|
| 109 | 104 | } |
|
| 110 | 105 | ||
| … | 59 unchanged lines |
modified crates/oxy-core/src/lib.rs +0 −2
| … | 6 unchanged lines |
||
| 7 | 7 | ||
| 8 | 8 | pub mod alloc_stats; |
|
| 9 | 9 | pub mod approval; |
|
| 10 | - | pub mod artifact; |
|
| 11 | 10 | pub mod attest; |
|
| 12 | 11 | pub mod attributes; |
|
| 13 | 12 | pub mod cbor; |
|
| … | 11 unchanged lines |
||
| 25 | 24 | pub mod ids; |
|
| 26 | 25 | pub mod lanes; |
|
| 27 | 26 | pub mod lines; |
|
| 28 | - | pub mod mcp; |
|
| 29 | 27 | pub mod objects; |
|
| 30 | 28 | pub mod oplog; |
|
| 31 | 29 | pub mod policy; |
|
| … | 13 unchanged lines |
removed crates/oxy-core/src/mcp.rs +0 −353
| 1 | - | //! A Model Context Protocol server over stdio (oxygen#159): JSON-RPC 2.0, |
|
| 2 | - | //! one message per line, as MCP's stdio transport has it. This is only the |
|
| 3 | - | //! protocol: `initialize`, `ping`, `tools/list` and `tools/call`, with the |
|
| 4 | - | //! tools themselves supplied by the caller (`oxy mcp`, and `oh mcp` in the |
|
| 5 | - | //! hub, which reaches this module through its pinned oxygen). |
|
| 6 | - | //! |
|
| 7 | - | //! Nothing is written to stdout but protocol messages: a tool's own |
|
| 8 | - | //! output goes into its result. |
|
| 9 | - | ||
| 10 | - | use serde_json::{json, Value}; |
|
| 11 | - | use std::io::{BufRead, Write}; |
|
| 12 | - | ||
| 13 | - | /// The protocol versions this server speaks, newest first. A client asking |
|
| 14 | - | /// for one of them gets it back; any other gets the newest. |
|
| 15 | - | pub const PROTOCOL_VERSIONS: &[&str] = &["2025-06-18", "2025-03-26", "2024-11-05"]; |
|
| 16 | - | ||
| 17 | - | /// One tool as `tools/list` describes it. |
|
| 18 | - | #[derive(Clone, Debug)] |
|
| 19 | - | pub struct Tool { |
|
| 20 | - | pub name: String, |
|
| 21 | - | pub description: String, |
|
| 22 | - | /// A JSON Schema object for the arguments. |
|
| 23 | - | pub input_schema: Value, |
|
| 24 | - | /// Reads only: no change to the repository, the remote or the hub. |
|
| 25 | - | pub read_only: bool, |
|
| 26 | - | /// May lose work or history (undo, abandon, deletes). |
|
| 27 | - | pub destructive: bool, |
|
| 28 | - | } |
|
| 29 | - | ||
| 30 | - | impl Tool { |
|
| 31 | - | fn describe(&self) -> Value { |
|
| 32 | - | json!({ |
|
| 33 | - | "name": self.name, |
|
| 34 | - | "description": self.description, |
|
| 35 | - | "inputSchema": self.input_schema, |
|
| 36 | - | "annotations": { |
|
| 37 | - | "readOnlyHint": self.read_only, |
|
| 38 | - | "destructiveHint": self.destructive, |
|
| 39 | - | }, |
|
| 40 | - | }) |
|
| 41 | - | } |
|
| 42 | - | } |
|
| 43 | - | ||
| 44 | - | /// What a tool call produced: text for the model to read, the same as JSON |
|
| 45 | - | /// when there is some, and whether it failed. A failed tool is a result, not |
|
| 46 | - | /// a protocol error, so the model sees why. |
|
| 47 | - | #[derive(Clone, Debug, Default, PartialEq)] |
|
| 48 | - | pub struct ToolOutput { |
|
| 49 | - | pub text: String, |
|
| 50 | - | pub structured: Option<Value>, |
|
| 51 | - | pub is_error: bool, |
|
| 52 | - | } |
|
| 53 | - | ||
| 54 | - | impl ToolOutput { |
|
| 55 | - | pub fn ok(text: impl Into<String>) -> ToolOutput { |
|
| 56 | - | ToolOutput { |
|
| 57 | - | text: text.into(), |
|
| 58 | - | structured: None, |
|
| 59 | - | is_error: false, |
|
| 60 | - | } |
|
| 61 | - | } |
|
| 62 | - | ||
| 63 | - | pub fn error(text: impl Into<String>) -> ToolOutput { |
|
| 64 | - | ToolOutput { |
|
| 65 | - | text: text.into(), |
|
| 66 | - | structured: None, |
|
| 67 | - | is_error: true, |
|
| 68 | - | } |
|
| 69 | - | } |
|
| 70 | - | ||
| 71 | - | fn to_json(&self) -> Value { |
|
| 72 | - | let mut out = json!({ |
|
| 73 | - | "content": [{ "type": "text", "text": self.text }], |
|
| 74 | - | "isError": self.is_error, |
|
| 75 | - | }); |
|
| 76 | - | // Structured content must be an object; an array is wrapped. |
|
| 77 | - | if let Some(s) = &self.structured { |
|
| 78 | - | let obj = if s.is_object() { |
|
| 79 | - | s.clone() |
|
| 80 | - | } else { |
|
| 81 | - | json!({ "result": s }) |
|
| 82 | - | }; |
|
| 83 | - | out["structuredContent"] = obj; |
|
| 84 | - | } |
|
| 85 | - | out |
|
| 86 | - | } |
|
| 87 | - | } |
|
| 88 | - | ||
| 89 | - | /// The tools a server offers. |
|
| 90 | - | pub trait Tools { |
|
| 91 | - | fn list(&self) -> Vec<Tool>; |
|
| 92 | - | /// Run a tool. `None` when no tool has that name. |
|
| 93 | - | fn call(&self, name: &str, args: &Value) -> Option<ToolOutput>; |
|
| 94 | - | } |
|
| 95 | - | ||
| 96 | - | /// Who the server is, for `initialize`. |
|
| 97 | - | #[derive(Clone, Debug)] |
|
| 98 | - | pub struct ServerInfo { |
|
| 99 | - | pub name: String, |
|
| 100 | - | pub version: String, |
|
| 101 | - | /// Shown to the model: what the server is for and how to use it safely. |
|
| 102 | - | pub instructions: String, |
|
| 103 | - | } |
|
| 104 | - | ||
| 105 | - | const PARSE_ERROR: i64 = -32700; |
|
| 106 | - | const INVALID_REQUEST: i64 = -32600; |
|
| 107 | - | const METHOD_NOT_FOUND: i64 = -32601; |
|
| 108 | - | const INVALID_PARAMS: i64 = -32602; |
|
| 109 | - | ||
| 110 | - | fn error(id: Value, code: i64, message: &str) -> Value { |
|
| 111 | - | json!({ "jsonrpc": "2.0", "id": id, "error": { "code": code, "message": message } }) |
|
| 112 | - | } |
|
| 113 | - | ||
| 114 | - | fn result(id: Value, result: Value) -> Value { |
|
| 115 | - | json!({ "jsonrpc": "2.0", "id": id, "result": result }) |
|
| 116 | - | } |
|
| 117 | - | ||
| 118 | - | /// Answer one message; `None` for a notification (no reply is due). |
|
| 119 | - | pub fn handle(info: &ServerInfo, tools: &dyn Tools, message: &Value) -> Option<Value> { |
|
| 120 | - | let Some(obj) = message.as_object() else { |
|
| 121 | - | return Some(error( |
|
| 122 | - | Value::Null, |
|
| 123 | - | INVALID_REQUEST, |
|
| 124 | - | "a message is a JSON object", |
|
| 125 | - | )); |
|
| 126 | - | }; |
|
| 127 | - | let method = obj.get("method").and_then(Value::as_str); |
|
| 128 | - | let id = obj.get("id").cloned(); |
|
| 129 | - | let Some(method) = method else { |
|
| 130 | - | // A response to something we never sent, or nonsense: a request |
|
| 131 | - | // without a method gets an error, anything else is ignored. |
|
| 132 | - | return id.map(|id| error(id, INVALID_REQUEST, "a request needs a method")); |
|
| 133 | - | }; |
|
| 134 | - | // Notifications (initialized, cancelled, …) carry no id and get no reply. |
|
| 135 | - | let id = id?; |
|
| 136 | - | let params = obj.get("params").cloned().unwrap_or(Value::Null); |
|
| 137 | - | Some(match method { |
|
| 138 | - | "initialize" => { |
|
| 139 | - | let asked = params.get("protocolVersion").and_then(Value::as_str); |
|
| 140 | - | let version = asked |
|
| 141 | - | .filter(|v| PROTOCOL_VERSIONS.contains(v)) |
|
| 142 | - | .unwrap_or(PROTOCOL_VERSIONS[0]); |
|
| 143 | - | result( |
|
| 144 | - | id, |
|
| 145 | - | json!({ |
|
| 146 | - | "protocolVersion": version, |
|
| 147 | - | "capabilities": { "tools": { "listChanged": false } }, |
|
| 148 | - | "serverInfo": { "name": info.name, "version": info.version }, |
|
| 149 | - | "instructions": info.instructions, |
|
| 150 | - | }), |
|
| 151 | - | ) |
|
| 152 | - | } |
|
| 153 | - | "ping" => result(id, json!({})), |
|
| 154 | - | "tools/list" => result( |
|
| 155 | - | id, |
|
| 156 | - | json!({ "tools": tools.list().iter().map(Tool::describe).collect::<Vec<_>>() }), |
|
| 157 | - | ), |
|
| 158 | - | "tools/call" => { |
|
| 159 | - | let Some(name) = params.get("name").and_then(Value::as_str) else { |
|
| 160 | - | return Some(error( |
|
| 161 | - | id, |
|
| 162 | - | INVALID_PARAMS, |
|
| 163 | - | "tools/call needs the tool's name", |
|
| 164 | - | )); |
|
| 165 | - | }; |
|
| 166 | - | let args = params |
|
| 167 | - | .get("arguments") |
|
| 168 | - | .cloned() |
|
| 169 | - | .unwrap_or_else(|| json!({})); |
|
| 170 | - | if !args.is_object() { |
|
| 171 | - | return Some(error( |
|
| 172 | - | id, |
|
| 173 | - | INVALID_PARAMS, |
|
| 174 | - | "a tool's arguments are a JSON object", |
|
| 175 | - | )); |
|
| 176 | - | } |
|
| 177 | - | match tools.call(name, &args) { |
|
| 178 | - | Some(out) => result(id, out.to_json()), |
|
| 179 | - | None => error(id, INVALID_PARAMS, &format!("no tool named {name}")), |
|
| 180 | - | } |
|
| 181 | - | } |
|
| 182 | - | other => error(id, METHOD_NOT_FOUND, &format!("{other} is not supported")), |
|
| 183 | - | }) |
|
| 184 | - | } |
|
| 185 | - | ||
| 186 | - | /// Serve until the input ends: read a message per line, write a reply per |
|
| 187 | - | /// request. A line that is not JSON gets a parse error; blank lines are |
|
| 188 | - | /// skipped. |
|
| 189 | - | pub fn serve( |
|
| 190 | - | info: &ServerInfo, |
|
| 191 | - | tools: &dyn Tools, |
|
| 192 | - | input: impl BufRead, |
|
| 193 | - | mut output: impl Write, |
|
| 194 | - | ) -> std::io::Result<()> { |
|
| 195 | - | for line in input.lines() { |
|
| 196 | - | let line = line?; |
|
| 197 | - | if line.trim().is_empty() { |
|
| 198 | - | continue; |
|
| 199 | - | } |
|
| 200 | - | let reply = match serde_json::from_str::<Value>(&line) { |
|
| 201 | - | Ok(Value::Array(batch)) => { |
|
| 202 | - | let replies: Vec<Value> = batch |
|
| 203 | - | .iter() |
|
| 204 | - | .filter_map(|m| handle(info, tools, m)) |
|
| 205 | - | .collect(); |
|
| 206 | - | (!replies.is_empty()).then_some(Value::Array(replies)) |
|
| 207 | - | } |
|
| 208 | - | Ok(message) => handle(info, tools, &message), |
|
| 209 | - | Err(e) => Some(error(Value::Null, PARSE_ERROR, &format!("not JSON: {e}"))), |
|
| 210 | - | }; |
|
| 211 | - | if let Some(reply) = reply { |
|
| 212 | - | writeln!(output, "{reply}")?; |
|
| 213 | - | output.flush()?; |
|
| 214 | - | } |
|
| 215 | - | } |
|
| 216 | - | Ok(()) |
|
| 217 | - | } |
|
| 218 | - | ||
| 219 | - | /// A string argument, if given and a string. |
|
| 220 | - | pub fn arg_str<'a>(args: &'a Value, key: &str) -> Option<&'a str> { |
|
| 221 | - | args.get(key).and_then(Value::as_str) |
|
| 222 | - | } |
|
| 223 | - | ||
| 224 | - | /// A list of strings, if given; a single string counts as a list of one. |
|
| 225 | - | pub fn arg_strings(args: &Value, key: &str) -> Result<Vec<String>, String> { |
|
| 226 | - | match args.get(key) { |
|
| 227 | - | None | Some(Value::Null) => Ok(vec![]), |
|
| 228 | - | Some(Value::String(s)) => Ok(vec![s.clone()]), |
|
| 229 | - | Some(Value::Array(a)) => a |
|
| 230 | - | .iter() |
|
| 231 | - | .map(|v| { |
|
| 232 | - | v.as_str() |
|
| 233 | - | .map(str::to_string) |
|
| 234 | - | .ok_or_else(|| format!("{key} must be a list of strings")) |
|
| 235 | - | }) |
|
| 236 | - | .collect(), |
|
| 237 | - | Some(_) => Err(format!("{key} must be a list of strings")), |
|
| 238 | - | } |
|
| 239 | - | } |
|
| 240 | - | ||
| 241 | - | #[cfg(test)] |
|
| 242 | - | mod tests { |
|
| 243 | - | use super::*; |
|
| 244 | - | ||
| 245 | - | struct Echo; |
|
| 246 | - | ||
| 247 | - | impl Tools for Echo { |
|
| 248 | - | fn list(&self) -> Vec<Tool> { |
|
| 249 | - | vec![Tool { |
|
| 250 | - | name: "echo".into(), |
|
| 251 | - | description: "says it back".into(), |
|
| 252 | - | input_schema: json!({"type": "object"}), |
|
| 253 | - | read_only: true, |
|
| 254 | - | destructive: false, |
|
| 255 | - | }] |
|
| 256 | - | } |
|
| 257 | - | fn call(&self, name: &str, args: &Value) -> Option<ToolOutput> { |
|
| 258 | - | (name == "echo").then(|| ToolOutput { |
|
| 259 | - | text: args.to_string(), |
|
| 260 | - | structured: Some(json!([1, 2])), |
|
| 261 | - | is_error: false, |
|
| 262 | - | }) |
|
| 263 | - | } |
|
| 264 | - | } |
|
| 265 | - | ||
| 266 | - | fn info() -> ServerInfo { |
|
| 267 | - | ServerInfo { |
|
| 268 | - | name: "t".into(), |
|
| 269 | - | version: "1".into(), |
|
| 270 | - | instructions: "be careful".into(), |
|
| 271 | - | } |
|
| 272 | - | } |
|
| 273 | - | ||
| 274 | - | fn talk(lines: &str) -> Vec<Value> { |
|
| 275 | - | let mut out = Vec::new(); |
|
| 276 | - | serve(&info(), &Echo, lines.as_bytes(), &mut out).unwrap(); |
|
| 277 | - | String::from_utf8(out) |
|
| 278 | - | .unwrap() |
|
| 279 | - | .lines() |
|
| 280 | - | .map(|l| serde_json::from_str(l).unwrap()) |
|
| 281 | - | .collect() |
|
| 282 | - | } |
|
| 283 | - | ||
| 284 | - | #[test] |
|
| 285 | - | fn a_session_initializes_lists_and_calls() { |
|
| 286 | - | let r = talk(concat!( |
|
| 287 | - | r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"c","version":"0"}}}"#, |
|
| 288 | - | "\n", |
|
| 289 | - | r#"{"jsonrpc":"2.0","method":"notifications/initialized"}"#, |
|
| 290 | - | "\n\n", |
|
| 291 | - | r#"{"jsonrpc":"2.0","id":2,"method":"tools/list"}"#, |
|
| 292 | - | "\n", |
|
| 293 | - | r#"{"jsonrpc":"2.0","id":"three","method":"tools/call","params":{"name":"echo","arguments":{"a":1}}}"#, |
|
| 294 | - | "\n", |
|
| 295 | - | )); |
|
| 296 | - | assert_eq!(r.len(), 3, "the notification gets no reply: {r:?}"); |
|
| 297 | - | assert_eq!( |
|
| 298 | - | r[0]["result"]["protocolVersion"], "2025-03-26", |
|
| 299 | - | "a version we speak is kept" |
|
| 300 | - | ); |
|
| 301 | - | assert_eq!(r[0]["result"]["instructions"], "be careful"); |
|
| 302 | - | assert_eq!(r[1]["result"]["tools"][0]["name"], "echo"); |
|
| 303 | - | assert_eq!( |
|
| 304 | - | r[1]["result"]["tools"][0]["annotations"]["readOnlyHint"], |
|
| 305 | - | true |
|
| 306 | - | ); |
|
| 307 | - | assert_eq!(r[2]["id"], "three"); |
|
| 308 | - | assert_eq!(r[2]["result"]["content"][0]["text"], r#"{"a":1}"#); |
|
| 309 | - | assert_eq!( |
|
| 310 | - | r[2]["result"]["structuredContent"], |
|
| 311 | - | json!({"result": [1, 2]}), |
|
| 312 | - | "an array is wrapped in an object" |
|
| 313 | - | ); |
|
| 314 | - | assert_eq!(r[2]["result"]["isError"], false); |
|
| 315 | - | } |
|
| 316 | - | ||
| 317 | - | #[test] |
|
| 318 | - | fn errors_are_protocol_errors_and_unknown_versions_get_the_newest() { |
|
| 319 | - | let r = talk(concat!( |
|
| 320 | - | "not json\n", |
|
| 321 | - | r#"{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"1999-01-01"}}"#, |
|
| 322 | - | "\n", |
|
| 323 | - | r#"{"jsonrpc":"2.0","id":2,"method":"resources/list"}"#, |
|
| 324 | - | "\n", |
|
| 325 | - | r#"{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"nope"}}"#, |
|
| 326 | - | "\n", |
|
| 327 | - | r#"{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"echo","arguments":[1]}}"#, |
|
| 328 | - | "\n", |
|
| 329 | - | r#"[{"jsonrpc":"2.0","id":5,"method":"ping"},{"jsonrpc":"2.0","method":"notifications/cancelled"}]"#, |
|
| 330 | - | "\n", |
|
| 331 | - | )); |
|
| 332 | - | assert_eq!(r[0]["error"]["code"], PARSE_ERROR); |
|
| 333 | - | assert_eq!(r[1]["result"]["protocolVersion"], PROTOCOL_VERSIONS[0]); |
|
| 334 | - | assert_eq!(r[2]["error"]["code"], METHOD_NOT_FOUND); |
|
| 335 | - | assert_eq!(r[3]["error"]["code"], INVALID_PARAMS); |
|
| 336 | - | assert_eq!(r[4]["error"]["code"], INVALID_PARAMS); |
|
| 337 | - | assert_eq!( |
|
| 338 | - | r[5], |
|
| 339 | - | json!([{"jsonrpc": "2.0", "id": 5, "result": {}}]), |
|
| 340 | - | "a batch is answered as a batch" |
|
| 341 | - | ); |
|
| 342 | - | } |
|
| 343 | - | ||
| 344 | - | #[test] |
|
| 345 | - | fn string_arguments_and_lists() { |
|
| 346 | - | let a = json!({"one": "x", "many": ["a", "b"], "bad": [1]}); |
|
| 347 | - | assert_eq!(arg_str(&a, "one"), Some("x")); |
|
| 348 | - | assert_eq!(arg_strings(&a, "one").unwrap(), vec!["x"]); |
|
| 349 | - | assert_eq!(arg_strings(&a, "many").unwrap(), vec!["a", "b"]); |
|
| 350 | - | assert_eq!(arg_strings(&a, "missing").unwrap(), Vec::<String>::new()); |
|
| 351 | - | assert!(arg_strings(&a, "bad").is_err()); |
|
| 352 | - | } |
|
| 353 | - | } |
modified crates/oxy-core/src/protocol.rs +5 −26
| … | 261 unchanged lines |
||
| 262 | 262 | } |
|
| 263 | 263 | } |
|
| 264 | 264 | ||
| 265 | - | // Bundles a local remote served on this thread, for tests that count |
|
| 266 | - | // round trips (oxygen#158). |
|
| 267 | - | #[cfg(test)] |
|
| 268 | - | thread_local! { |
|
| 269 | - | pub(crate) static LOCAL_FETCHES: std::cell::Cell<usize> = const { std::cell::Cell::new(0) }; |
|
| 270 | - | } |
|
| 271 | - | ||
| 272 | 265 | impl Remote for LocalRemote { |
|
| 273 | 266 | fn repo_id(&self) -> Result<[u8; 16]> { |
|
| 274 | 267 | self.repo.id() |
|
| … | 5 unchanged lines |
||
| 280 | 273 | self.repo.negotiate(have, want) |
|
| 281 | 274 | } |
|
| 282 | 275 | fn fetch(&self, changes: &[ChangeHash], max_blob: Option<u64>) -> Result<Bundle> { |
|
| 283 | - | #[cfg(test)] |
|
| 284 | - | LOCAL_FETCHES.with(|n| n.set(n.get() + 1)); |
|
| 285 | 276 | self.repo.bundle_raw_for(changes, max_blob) |
|
| 286 | 277 | } |
|
| 287 | 278 | fn objects(&self, refs: &[ObjectRef]) -> Result<Vec<(ObjectType, Vec<u8>)>> { |
|
| … | 49 unchanged lines |
||
| 337 | 328 | /// a temporary directory. |
|
| 338 | 329 | pub cache_dir: Option<PathBuf>, |
|
| 339 | 330 | /// Other tokens for the same hub, tried in turn when `token` is |
|
| 340 | - | /// refused (401, 403 or 404): the credential store's sign-in when |
|
| 341 | - | /// `token` is the remote's own (oxygen#155), or those of enclosing |
|
| 342 | - | /// checkouts when it came from the credential store (oxygen#112). |
|
| 331 | + | /// refused (401, 403 or 404): those of enclosing checkouts, when |
|
| 332 | + | /// `token` came from the credential store rather than from this |
|
| 333 | + | /// remote's own configuration (oxygen#112). |
|
| 343 | 334 | pub fallback_tokens: Vec<String>, |
|
| 344 | - | /// `token` is the remote's own: fall back only when the hub says it is |
|
| 345 | - | /// not a token at all (HTTP 401: expired or unknown), never when it is |
|
| 346 | - | /// one that may not do this (403, 404), so a narrowly scoped token is |
|
| 347 | - | /// not quietly swapped for a wider sign-in (oxygen#155). |
|
| 348 | - | pub fallback_on_401_only: bool, |
|
| 349 | 335 | } |
|
| 350 | 336 | ||
| 351 | 337 | /// Opens a store for a URL it understands, or passes (`None`). Stores that |
|
| … | 65 unchanged lines |
||
| 417 | 403 | /// The token in use, and those still to try when it is refused. |
|
| 418 | 404 | token: Mutex<Option<String>>, |
|
| 419 | 405 | fallbacks: Mutex<Vec<String>>, |
|
| 420 | - | fallback_on_401_only: bool, |
|
| 421 | 406 | repo_id: Option<[u8; 16]>, |
|
| 422 | 407 | agent: ureq::Agent, |
|
| 423 | 408 | } |
|
| … | 42 unchanged lines |
||
| 466 | 451 | base: base.trim_end_matches('/').to_string(), |
|
| 467 | 452 | token: Mutex::new(options.token.clone()), |
|
| 468 | 453 | fallbacks: Mutex::new(options.fallback_tokens.iter().rev().cloned().collect()), |
|
| 469 | - | fallback_on_401_only: options.fallback_on_401_only, |
|
| 470 | 454 | repo_id: options.repo_id, |
|
| 471 | 455 | agent, |
|
| 472 | 456 | }) |
|
| … | 5 unchanged lines |
||
| 478 | 462 | loop { |
|
| 479 | 463 | let token = self.token.lock().unwrap_or_else(|p| p.into_inner()).clone(); |
|
| 480 | 464 | match self.call_once(post, endpoint, body, token.as_deref()) { |
|
| 481 | - | Err(RepoError::Msg(m)) |
|
| 482 | - | if token.is_some() |
|
| 483 | - | && refused(&m) |
|
| 484 | - | && (!self.fallback_on_401_only || m.contains(": HTTP 401")) => |
|
| 485 | - | { |
|
| 465 | + | Err(RepoError::Msg(m)) if token.is_some() && refused(&m) => { |
|
| 486 | 466 | let next = self |
|
| 487 | 467 | .fallbacks |
|
| 488 | 468 | .lock() |
|
| … | 3 unchanged lines |
||
| 492 | 472 | return Err(RepoError::Msg(m)); |
|
| 493 | 473 | }; |
|
| 494 | 474 | crate::credentials::warn_once(&format!( |
|
| 495 | - | "{}: the token in use was refused; trying another this computer has for the hub \ |
|
| 496 | - | (a stale remote.NAME.token goes with `oxy config --unset remote.NAME.token`)", |
|
| 475 | + | "{}: the stored token was refused; using the one an enclosing checkout has for this hub", |
|
| 497 | 476 | self.base |
|
| 498 | 477 | )); |
|
| 499 | 478 | *self.token.lock().unwrap_or_else(|p| p.into_inner()) = Some(next); |
|
| … | 1341 unchanged lines |
modified crates/oxy-core/src/repo/bookmarks.rs +1 −1
| … | 497 unchanged lines |
||
| 498 | 498 | .get(p) |
|
| 499 | 499 | .and_then(|m| m.bookmark.clone()); |
|
| 500 | 500 | super::subrepos::read_pin(&self.root.join(p), hint.as_deref()) |
|
| 501 | - | .is_ok_and(|have| have.same_state(&want)) |
|
| 501 | + | .is_ok_and(|have| have == want) |
|
| 502 | 502 | }; |
|
| 503 | 503 | touched.retain(|p| !at_target_pin(p)); |
|
| 504 | 504 | let same = |p: &String| { |
|
| … | 216 unchanged lines |
modified crates/oxy-core/src/repo/checkout.rs +1 −37
| … | 525 unchanged lines |
||
| 526 | 526 | if i == 0 && *comp == OXY_DIR { |
|
| 527 | 527 | return fail(format!("refusing to write inside {OXY_DIR}: {rel:?}")); |
|
| 528 | 528 | } |
|
| 529 | - | // A `.git` path could plant hooks a side-by-side Git would run; |
|
| 530 | - | // Git refuses them at any depth and in any case, and so does oxy. |
|
| 531 | - | if comp.eq_ignore_ascii_case(".git") { |
|
| 532 | - | return fail(format!("refusing to write a .git path: {rel:?}")); |
|
| 533 | - | } |
|
| 534 | 529 | if i + 1 < comps.len() { |
|
| 535 | 530 | full.push(comp); |
|
| 536 | 531 | if let Ok(m) = fs::symlink_metadata(&full) { |
|
| … | 64 unchanged lines |
||
| 601 | 596 | } |
|
| 602 | 597 | ||
| 603 | 598 | /// Refuse a path that could escape the workspace (spec §7.7): an empty, |
|
| 604 | - | /// `.` or `..` component, a backslash, a first component `.oxy`, or a |
|
| 605 | - | /// `.git` component anywhere (it could plant Git hooks). |
|
| 599 | + | /// `.` or `..` component, a backslash, or a first component `.oxy`. |
|
| 606 | 600 | fn check_path_name(rel: &str) -> Result<()> { |
|
| 607 | 601 | for (i, comp) in rel.split('/').enumerate() { |
|
| 608 | 602 | if comp.is_empty() || comp == "." || comp == ".." || comp.contains('\\') { |
|
| … | 2 unchanged lines |
||
| 611 | 605 | if i == 0 && comp == OXY_DIR { |
|
| 612 | 606 | return fail(format!("refusing to write inside {OXY_DIR}: {rel:?}")); |
|
| 613 | 607 | } |
|
| 614 | - | if comp.eq_ignore_ascii_case(".git") { |
|
| 615 | - | return fail(format!("refusing to write a .git path: {rel:?}")); |
|
| 616 | - | } |
|
| 617 | 608 | } |
|
| 618 | 609 | Ok(()) |
|
| 619 | 610 | } |
|
| … | 36 unchanged lines |
||
| 656 | 647 | } |
|
| 657 | 648 | fs::write(full, bytes)?; |
|
| 658 | 649 | set_executable(full, exec) |
|
| 659 | - | } |
|
| 660 | - | ||
| 661 | - | #[cfg(test)] |
|
| 662 | - | mod path_name_tests { |
|
| 663 | - | use super::check_path_name; |
|
| 664 | - | ||
| 665 | - | #[test] |
|
| 666 | - | fn git_paths_are_refused_at_any_depth_and_case() { |
|
| 667 | - | for bad in [ |
|
| 668 | - | ".git/hooks/post-checkout", |
|
| 669 | - | "sub/.git/config", |
|
| 670 | - | ".GIT/hooks/x", |
|
| 671 | - | "a/.Git", |
|
| 672 | - | ".oxy/x", |
|
| 673 | - | "../x", |
|
| 674 | - | ] { |
|
| 675 | - | assert!(check_path_name(bad).is_err(), "{bad}"); |
|
| 676 | - | } |
|
| 677 | - | for good in [ |
|
| 678 | - | "src/main.rs", |
|
| 679 | - | ".gitignore", |
|
| 680 | - | ".github/workflows/ci.yml", |
|
| 681 | - | "a/.gitmodules", |
|
| 682 | - | ] { |
|
| 683 | - | assert!(check_path_name(good).is_ok(), "{good}"); |
|
| 684 | - | } |
|
| 685 | - | } |
|
| 686 | 650 | } |
modified crates/oxy-core/src/repo/config.rs +0 −6
| … | 45 unchanged lines |
||
| 46 | 46 | /// `git.claim`: a Git import authors the commits whose Git author email |
|
| 47 | 47 | /// is this repository's identity's with its key (oxygen#97). |
|
| 48 | 48 | pub git_claim: bool, |
|
| 49 | - | /// `git.colocate`: keep a `.git` beside `.oxy` with the current |
|
| 50 | - | /// bookmark exported after every operation, so editors' Git features |
|
| 51 | - | /// work on an Oxygen checkout (one way: oxy to Git). |
|
| 52 | - | pub git_colocate: bool, |
|
| 53 | 49 | /// `core.op-retention`: days for which operations keep their states reachable (spec §12.1, §21). |
|
| 54 | 50 | pub op_retention_days: u64, |
|
| 55 | 51 | /// `core.gc-grace`: days an unreachable object survives, protecting concurrent writers (spec §21). |
|
| … | 56 unchanged lines |
||
| 112 | 108 | remote_cas: BTreeMap::new(), |
|
| 113 | 109 | default_remote: None, |
|
| 114 | 110 | git_claim: false, |
|
| 115 | - | git_colocate: false, |
|
| 116 | 111 | op_retention_days: 90, |
|
| 117 | 112 | gc_grace_days: 14, |
|
| 118 | 113 | max_new_file: 100 << 20, |
|
| … | 102 unchanged lines |
||
| 221 | 216 | } |
|
| 222 | 217 | "hooks.semantic-deps" => self.semantic_deps = matches!(value, "true" | "1" | "yes"), |
|
| 223 | 218 | "git.claim" => self.git_claim = matches!(value, "true" | "1" | "yes"), |
|
| 224 | - | "git.colocate" => self.git_colocate = matches!(value, "true" | "1" | "yes"), |
|
| 225 | 219 | "filter.paths" => { |
|
| 226 | 220 | self.sparse_paths = value |
|
| 227 | 221 | .split(',') |
|
| … | 163 unchanged lines |
modified crates/oxy-core/src/repo/fsck.rs +0 −1
| … | 102 unchanged lines |
||
| 103 | 103 | ObjectType::Receipt => crate::receipt::Receipt::decode(body).map(|_| ()), |
|
| 104 | 104 | ObjectType::Certificate => crate::cert::Certificate::decode(body).map(|_| ()), |
|
| 105 | 105 | ObjectType::Grant => crate::cert::Grant::decode(body).map(|_| ()), |
|
| 106 | - | ObjectType::Artifact => crate::artifact::Artifact::decode(body).map(|_| ()), |
|
| 107 | 106 | ObjectType::State => crate::objects::StateObject::decode(body).map(|_| ()), |
|
| 108 | 107 | }; |
|
| 109 | 108 | r.map_err(|e| e.to_string()) |
|
| … | 408 unchanged lines |
modified crates/oxy-core/src/repo/git.rs +8 −358
| … | 1740 unchanged lines |
||
| 1741 | 1741 | } |
|
| 1742 | 1742 | ||
| 1743 | 1743 | fn git_author(&self, c: &Change) -> String { |
|
| 1744 | - | self.git_author_key(&c.author) |
|
| 1744 | + | match self.store.get_identity(&c.author) { |
|
| 1745 | + | Ok(id) if !id.name.is_empty() => format!( |
|
| 1746 | + | "{} <{}>", |
|
| 1747 | + | id.name.replace(['<', '>', '\n'], " "), |
|
| 1748 | + | id.email.replace(['<', '>', '\n', ' '], "") |
|
| 1749 | + | ), |
|
| 1750 | + | _ => "oxy <oxy@localhost>".to_string(), |
|
| 1751 | + | } |
|
| 1745 | 1752 | } |
|
| 1746 | 1753 | ||
| 1747 | 1754 | #[allow(clippy::too_many_arguments)] |
|
| … | 421 unchanged lines |
||
| 2169 | 2176 | h.len(), |
|
| 2170 | 2177 | w.len() |
|
| 2171 | 2178 | ) |
|
| 2172 | - | } |
|
| 2173 | - | ||
| 2174 | - | /// What `git_export_graph` wrote. |
|
| 2175 | - | #[derive(Debug, Clone, Default, PartialEq, Eq)] |
|
| 2176 | - | pub struct GitGraphReport { |
|
| 2177 | - | /// Changes written as commits this time (the rest were exported before). |
|
| 2178 | - | pub commits: usize, |
|
| 2179 | - | /// Branches and tags pointed at their commits. |
|
| 2180 | - | pub branches: usize, |
|
| 2181 | - | pub tags: usize, |
|
| 2182 | - | /// Bookmarks or tags whose names Git does not take as refs. |
|
| 2183 | - | pub skipped_refs: Vec<String>, |
|
| 2184 | - | /// Subrepo nodes with Oxygen pins, which Git cannot represent. |
|
| 2185 | - | pub skipped_subrepos: usize, |
|
| 2186 | - | } |
|
| 2187 | - | ||
| 2188 | - | /// A bookmark or tag name Git takes as a ref without escaping. |
|
| 2189 | - | fn git_ref_ok(name: &str) -> bool { |
|
| 2190 | - | !name.is_empty() |
|
| 2191 | - | && !name.starts_with(['-', '/', '.']) |
|
| 2192 | - | && !name.ends_with(['/', '.']) |
|
| 2193 | - | && !name.contains("..") |
|
| 2194 | - | && !name.contains("//") |
|
| 2195 | - | && !name.ends_with(".lock") |
|
| 2196 | - | && name |
|
| 2197 | - | .bytes() |
|
| 2198 | - | .all(|b| b.is_ascii_alphanumeric() || b"-_./+".contains(&b)) |
|
| 2199 | - | } |
|
| 2200 | - | ||
| 2201 | - | impl Repo { |
|
| 2202 | - | /// Export every bookmark and tag to the bare Git repository at |
|
| 2203 | - | /// `git_dir` from the change graph (spec §23, oxygenhub D1), for a hub |
|
| 2204 | - | /// to serve to Git clients. Unlike `git_export`, which follows one |
|
| 2205 | - | /// checkout's operation log, this depends only on the changes, so the |
|
| 2206 | - | /// same changes give the same Git commits wherever it runs: |
|
| 2207 | - | /// |
|
| 2208 | - | /// - each change is a commit whose tree is the state of the change and |
|
| 2209 | - | /// everything it depends on, whose parents are its dependencies' |
|
| 2210 | - | /// commits, with the change's author, time and message and its |
|
| 2211 | - | /// `Change-Id:` and `Oxy-Hash:` trailers (a change that depends on |
|
| 2212 | - | /// nothing is a root, so Git sees Oxygen's dependencies, not the order |
|
| 2213 | - | /// changes were made in); |
|
| 2214 | - | /// - a bookmark with one head is a branch at that head's commit; with |
|
| 2215 | - | /// several, a merge of their commits whose tree is the bookmark's |
|
| 2216 | - | /// state, at the newest head's time; |
|
| 2217 | - | /// - a tag points at its heads' commit, or such a merge. |
|
| 2218 | - | /// |
|
| 2219 | - | /// Commits already exported are remembered (marks), so a later run |
|
| 2220 | - | /// writes only new changes. Branches for bookmarks that are gone are |
|
| 2221 | - | /// deleted. |
|
| 2222 | - | pub fn git_export_graph(&self, git_dir: &Path) -> Result<GitGraphReport> { |
|
| 2223 | - | if !git_dir.join("HEAD").exists() { |
|
| 2224 | - | fs::create_dir_all(git_dir)?; |
|
| 2225 | - | git(git_dir, &["init", "--bare", "-q"])?; |
|
| 2226 | - | } |
|
| 2227 | - | let marks_dir = self.git_marks_dir(git_dir)?; |
|
| 2228 | - | let git_marks = marks_dir.join("git-marks"); |
|
| 2229 | - | let graph_marks = marks_dir.join("graph-marks"); |
|
| 2230 | - | let mut marks = Self::read_oxy_marks(&graph_marks)?; |
|
| 2231 | - | let mut next = marks.values().copied().max().unwrap_or(0) + 1; |
|
| 2232 | - | let mut report = GitGraphReport::default(); |
|
| 2233 | - | let mut stream: Vec<u8> = Vec::new(); |
|
| 2234 | - | ||
| 2235 | - | let mut refs: Vec<(String, Vec<ChangeHash>)> = Vec::new(); |
|
| 2236 | - | for b in self.bookmarks()? { |
|
| 2237 | - | if git_ref_ok(&b.name) { |
|
| 2238 | - | refs.push((format!("refs/heads/{}", b.name), b.heads)); |
|
| 2239 | - | } else { |
|
| 2240 | - | report.skipped_refs.push(b.name); |
|
| 2241 | - | } |
|
| 2242 | - | } |
|
| 2243 | - | let tags = self.tags()?; |
|
| 2244 | - | for t in &tags { |
|
| 2245 | - | if git_ref_ok(&t.name) { |
|
| 2246 | - | refs.push((format!("refs/tags/{}", t.name), t.heads.clone())); |
|
| 2247 | - | } else { |
|
| 2248 | - | report.skipped_refs.push(t.name.clone()); |
|
| 2249 | - | } |
|
| 2250 | - | } |
|
| 2251 | - | ||
| 2252 | - | // Every change the refs reach, dependencies before dependents: a |
|
| 2253 | - | // depth-first walk in hash order, so the order is the same everywhere. |
|
| 2254 | - | let mut order: Vec<ChangeHash> = Vec::new(); |
|
| 2255 | - | let mut seen: HashSet<ChangeHash> = HashSet::new(); |
|
| 2256 | - | let mut metas: HashMap<ChangeHash, crate::state::ChangeMeta> = HashMap::new(); |
|
| 2257 | - | let mut roots: Vec<ChangeHash> = refs.iter().flat_map(|(_, h)| h.iter().copied()).collect(); |
|
| 2258 | - | roots.sort(); |
|
| 2259 | - | roots.dedup(); |
|
| 2260 | - | for root in roots { |
|
| 2261 | - | if !seen.insert(root) { |
|
| 2262 | - | continue; |
|
| 2263 | - | } |
|
| 2264 | - | let mut stack: Vec<(ChangeHash, bool)> = vec![(root, false)]; |
|
| 2265 | - | while let Some((h, done)) = stack.pop() { |
|
| 2266 | - | if done { |
|
| 2267 | - | order.push(h); |
|
| 2268 | - | continue; |
|
| 2269 | - | } |
|
| 2270 | - | stack.push((h, true)); |
|
| 2271 | - | let meta = self.store.get_change_meta(&h)?; |
|
| 2272 | - | let mut deps = meta.deps.clone(); |
|
| 2273 | - | deps.sort(); |
|
| 2274 | - | for d in deps.into_iter().rev() { |
|
| 2275 | - | if seen.insert(d) { |
|
| 2276 | - | stack.push((d, false)); |
|
| 2277 | - | } |
|
| 2278 | - | } |
|
| 2279 | - | metas.insert(h, meta); |
|
| 2280 | - | } |
|
| 2281 | - | } |
|
| 2282 | - | ||
| 2283 | - | for h in &order { |
|
| 2284 | - | if marks.contains_key(h) { |
|
| 2285 | - | continue; |
|
| 2286 | - | } |
|
| 2287 | - | let meta = &metas[h]; |
|
| 2288 | - | let snapshot = self.load_state(&[*h])?.materialize(); |
|
| 2289 | - | let mut message = meta.message.clone(); |
|
| 2290 | - | if !message.ends_with('\n') { |
|
| 2291 | - | message.push('\n'); |
|
| 2292 | - | } |
|
| 2293 | - | message.push_str(&format!( |
|
| 2294 | - | "\nChange-Id: {}\nOxy-Hash: {}\n", |
|
| 2295 | - | meta.change_id.to_hex(), |
|
| 2296 | - | h.to_hex() |
|
| 2297 | - | )); |
|
| 2298 | - | if snapshot.is_conflicted() { |
|
| 2299 | - | message.push_str("Oxy-Conflicted: true\n"); |
|
| 2300 | - | } |
|
| 2301 | - | let mut deps = meta.deps.clone(); |
|
| 2302 | - | deps.sort(); |
|
| 2303 | - | let parents: Vec<String> = deps |
|
| 2304 | - | .iter() |
|
| 2305 | - | .filter_map(|d| marks.get(d)) |
|
| 2306 | - | .map(|m| format!(":{m}")) |
|
| 2307 | - | .collect(); |
|
| 2308 | - | let mark = next; |
|
| 2309 | - | next += 1; |
|
| 2310 | - | if parents.is_empty() { |
|
| 2311 | - | // Without `from`, fast-import would make the scratch ref's |
|
| 2312 | - | // tip its parent; a change that depends on nothing is a root. |
|
| 2313 | - | stream.extend_from_slice(b"reset refs/oxy/export\n\n"); |
|
| 2314 | - | } |
|
| 2315 | - | self.write_commit( |
|
| 2316 | - | &mut stream, |
|
| 2317 | - | "refs/oxy/export", |
|
| 2318 | - | mark, |
|
| 2319 | - | &self.git_author_key(&meta.author), |
|
| 2320 | - | meta.hlc.wall_ms / 1000, |
|
| 2321 | - | &message, |
|
| 2322 | - | &parents, |
|
| 2323 | - | &snapshot, |
|
| 2324 | - | )?; |
|
| 2325 | - | marks.insert(*h, mark); |
|
| 2326 | - | report.commits += 1; |
|
| 2327 | - | } |
|
| 2328 | - | ||
| 2329 | - | let mut wanted: HashSet<String> = HashSet::new(); |
|
| 2330 | - | for (name, heads) in &refs { |
|
| 2331 | - | let mut heads = heads.clone(); |
|
| 2332 | - | heads.sort(); |
|
| 2333 | - | heads.dedup(); |
|
| 2334 | - | let target = match heads.as_slice() { |
|
| 2335 | - | [] => continue, |
|
| 2336 | - | [one] => format!(":{}", marks[one]), |
|
| 2337 | - | many => { |
|
| 2338 | - | // A merge of the heads, named by them so it is made once. |
|
| 2339 | - | let key = hash_object( |
|
| 2340 | - | ObjectType::Chunk, |
|
| 2341 | - | many.iter() |
|
| 2342 | - | .map(|h| h.to_hex()) |
|
| 2343 | - | .collect::<Vec<_>>() |
|
| 2344 | - | .join(" ") |
|
| 2345 | - | .as_bytes(), |
|
| 2346 | - | ); |
|
| 2347 | - | if let Some(m) = marks.get(&key) { |
|
| 2348 | - | format!(":{m}") |
|
| 2349 | - | } else { |
|
| 2350 | - | let snapshot = self.load_state(many)?.materialize(); |
|
| 2351 | - | let newest = many.iter().map(|h| metas[h].hlc.wall_ms).max().unwrap_or(0); |
|
| 2352 | - | let mut message = format!( |
|
| 2353 | - | "Merge of {} heads\n\nOxy-Heads: {}\n", |
|
| 2354 | - | many.len(), |
|
| 2355 | - | many.iter() |
|
| 2356 | - | .map(|h| h.to_hex()) |
|
| 2357 | - | .collect::<Vec<_>>() |
|
| 2358 | - | .join(" ") |
|
| 2359 | - | ); |
|
| 2360 | - | if snapshot.is_conflicted() { |
|
| 2361 | - | message.push_str("Oxy-Conflicted: true\n"); |
|
| 2362 | - | } |
|
| 2363 | - | let parents: Vec<String> = |
|
| 2364 | - | many.iter().map(|h| format!(":{}", marks[h])).collect(); |
|
| 2365 | - | let mark = next; |
|
| 2366 | - | next += 1; |
|
| 2367 | - | self.write_commit( |
|
| 2368 | - | &mut stream, |
|
| 2369 | - | "refs/oxy/export", |
|
| 2370 | - | mark, |
|
| 2371 | - | "oxy <oxy@localhost>", |
|
| 2372 | - | newest / 1000, |
|
| 2373 | - | &message, |
|
| 2374 | - | &parents, |
|
| 2375 | - | &snapshot, |
|
| 2376 | - | )?; |
|
| 2377 | - | marks.insert(key, mark); |
|
| 2378 | - | format!(":{mark}") |
|
| 2379 | - | } |
|
| 2380 | - | } |
|
| 2381 | - | }; |
|
| 2382 | - | stream.extend_from_slice(format!("reset {name}\nfrom {target}\n\n").as_bytes()); |
|
| 2383 | - | wanted.insert(name.clone()); |
|
| 2384 | - | if name.starts_with("refs/tags/") { |
|
| 2385 | - | report.tags += 1; |
|
| 2386 | - | } else { |
|
| 2387 | - | report.branches += 1; |
|
| 2388 | - | } |
|
| 2389 | - | } |
|
| 2390 | - | stream.extend_from_slice(b"done\n"); |
|
| 2391 | - | run_fast_import(git_dir, &stream, &git_marks)?; |
|
| 2392 | - | let text: String = marks |
|
| 2393 | - | .iter() |
|
| 2394 | - | .map(|(h, m)| format!("{} {m}\n", h.to_hex())) |
|
| 2395 | - | .collect(); |
|
| 2396 | - | write_atomic(&graph_marks, text.as_bytes())?; |
|
| 2397 | - | let _ = git(git_dir, &["update-ref", "-d", "refs/oxy/export"]); |
|
| 2398 | - | // Branches and tags of bookmarks and tags that are gone. |
|
| 2399 | - | let listed = git( |
|
| 2400 | - | git_dir, |
|
| 2401 | - | &[ |
|
| 2402 | - | "for-each-ref", |
|
| 2403 | - | "--format=%(refname)", |
|
| 2404 | - | "refs/heads", |
|
| 2405 | - | "refs/tags", |
|
| 2406 | - | ], |
|
| 2407 | - | )?; |
|
| 2408 | - | for r in listed |
|
| 2409 | - | .lines() |
|
| 2410 | - | .map(str::trim) |
|
| 2411 | - | .filter(|r| !r.is_empty() && !wanted.contains(*r)) |
|
| 2412 | - | { |
|
| 2413 | - | git(git_dir, &["update-ref", "-d", r])?; |
|
| 2414 | - | } |
|
| 2415 | - | // HEAD names the main bookmark when there is one, so a clone checks it out. |
|
| 2416 | - | let main = ["main", "master", "trunk", "develop"] |
|
| 2417 | - | .into_iter() |
|
| 2418 | - | .find(|b| wanted.contains(&format!("refs/heads/{b}"))); |
|
| 2419 | - | if let Some(b) = main { |
|
| 2420 | - | git( |
|
| 2421 | - | git_dir, |
|
| 2422 | - | &["symbolic-ref", "HEAD", &format!("refs/heads/{b}")], |
|
| 2423 | - | )?; |
|
| 2424 | - | } |
|
| 2425 | - | report.skipped_subrepos = self.git_export_skipped.replace(0); |
|
| 2426 | - | Ok(report) |
|
| 2427 | - | } |
|
| 2428 | - | ||
| 2429 | - | /// `Name <email>` for a Git commit, from the author's identity. |
|
| 2430 | - | fn git_author_key(&self, key: &KeyId) -> String { |
|
| 2431 | - | match self.store.get_identity(key) { |
|
| 2432 | - | Ok(id) if !id.name.is_empty() => format!( |
|
| 2433 | - | "{} <{}>", |
|
| 2434 | - | id.name.replace(['<', '>', '\n'], " "), |
|
| 2435 | - | id.email.replace(['<', '>', '\n', ' '], "") |
|
| 2436 | - | ), |
|
| 2437 | - | _ => "oxy <oxy@localhost>".to_string(), |
|
| 2438 | - | } |
|
| 2439 | - | } |
|
| 2440 | - | } |
|
| 2441 | - | ||
| 2442 | - | /// Feed a fast-import stream to `git fast-import` in `git_dir`, keeping its |
|
| 2443 | - | /// marks in `git_marks` so a later run can refer to commits it wrote. |
|
| 2444 | - | fn run_fast_import(git_dir: &Path, stream: &[u8], git_marks: &Path) -> Result<()> { |
|
| 2445 | - | let mut cmd = Command::new("git"); |
|
| 2446 | - | // `--force`: a ref may move to an unrelated commit (a bookmark rewritten). |
|
| 2447 | - | cmd.arg("-C") |
|
| 2448 | - | .arg(git_dir) |
|
| 2449 | - | .args(["fast-import", "--quiet", "--done", "--force"]) |
|
| 2450 | - | .arg(format!("--export-marks={}", git_marks.display())); |
|
| 2451 | - | if git_marks.exists() { |
|
| 2452 | - | cmd.arg(format!("--import-marks={}", git_marks.display())); |
|
| 2453 | - | } |
|
| 2454 | - | let mut child = cmd |
|
| 2455 | - | .stdin(Stdio::piped()) |
|
| 2456 | - | .stdout(Stdio::null()) |
|
| 2457 | - | .stderr(Stdio::piped()) |
|
| 2458 | - | .spawn() |
|
| 2459 | - | .map_err(|e| RepoError::Msg(format!("running git fast-import: {e}")))?; |
|
| 2460 | - | child.stdin.take().unwrap().write_all(stream)?; |
|
| 2461 | - | let out = child.wait_with_output()?; |
|
| 2462 | - | if !out.status.success() { |
|
| 2463 | - | return fail(format!( |
|
| 2464 | - | "git fast-import failed: {}", |
|
| 2465 | - | String::from_utf8_lossy(&out.stderr).trim() |
|
| 2466 | - | )); |
|
| 2467 | - | } |
|
| 2468 | - | Ok(()) |
|
| 2469 | - | } |
|
| 2470 | - | ||
| 2471 | - | impl Repo { |
|
| 2472 | - | /// Bring the side-by-side Git repository up to date (`git.colocate`): |
|
| 2473 | - | /// a `.git` beside `.oxy`, made with `git init` when missing and told to |
|
| 2474 | - | /// leave `.oxy/` alone, holding the current bookmark as exported by |
|
| 2475 | - | /// `git_export_as` (one commit per state the bookmark passed through), |
|
| 2476 | - | /// with HEAD on that branch and Git's index at its tree, so `git status` |
|
| 2477 | - | /// shows only the working copy's uncommitted work. Files on disk are |
|
| 2478 | - | /// never touched. Does nothing when the bookmark has not moved since the |
|
| 2479 | - | /// last time; `Ok(true)` when it exported. |
|
| 2480 | - | pub fn git_colocate_sync(&self) -> Result<bool> { |
|
| 2481 | - | if self.bare { |
|
| 2482 | - | return fail("a bare repository has no working copy for a .git beside it"); |
|
| 2483 | - | } |
|
| 2484 | - | let git_dir = self.root.join(".git"); |
|
| 2485 | - | if git_dir.is_file() { |
|
| 2486 | - | return fail(".git is a file (a Git worktree or submodule link); remove it to keep a side-by-side Git repository here"); |
|
| 2487 | - | } |
|
| 2488 | - | if !git_dir.join("HEAD").exists() { |
|
| 2489 | - | git(&self.root, &["init", "-q"])?; |
|
| 2490 | - | } |
|
| 2491 | - | let exclude = git_dir.join("info").join("exclude"); |
|
| 2492 | - | let have = fs::read_to_string(&exclude).unwrap_or_default(); |
|
| 2493 | - | if !have.lines().any(|l| l.trim() == "/.oxy/") { |
|
| 2494 | - | fs::create_dir_all(exclude.parent().expect("info/"))?; |
|
| 2495 | - | let sep = if have.is_empty() || have.ends_with('\n') { |
|
| 2496 | - | "" |
|
| 2497 | - | } else { |
|
| 2498 | - | "\n" |
|
| 2499 | - | }; |
|
| 2500 | - | fs::write( |
|
| 2501 | - | &exclude, |
|
| 2502 | - | format!("{have}{sep}# Oxygen's own repository (oxy git colocate)\n/.oxy/\n"), |
|
| 2503 | - | )?; |
|
| 2504 | - | } |
|
| 2505 | - | let bookmark = self.config.bookmark.clone(); |
|
| 2506 | - | let state = self |
|
| 2507 | - | .view()? |
|
| 2508 | - | .bookmarks |
|
| 2509 | - | .get(&bookmark) |
|
| 2510 | - | .map(|s| s.to_hex()) |
|
| 2511 | - | .unwrap_or_default(); |
|
| 2512 | - | let stamp_file = self.oxy.join("git").join("colocate-stamp"); |
|
| 2513 | - | let stamp = format!("{bookmark} {state}"); |
|
| 2514 | - | if fs::read_to_string(&stamp_file).is_ok_and(|s| s.trim() == stamp) { |
|
| 2515 | - | return Ok(false); |
|
| 2516 | - | } |
|
| 2517 | - | if !state.is_empty() { |
|
| 2518 | - | self.git_export_as(&git_dir, &bookmark)?; |
|
| 2519 | - | git( |
|
| 2520 | - | &self.root, |
|
| 2521 | - | &["symbolic-ref", "HEAD", &format!("refs/heads/{bookmark}")], |
|
| 2522 | - | )?; |
|
| 2523 | - | git(&self.root, &["read-tree", "HEAD"])?; |
|
| 2524 | - | } |
|
| 2525 | - | fs::create_dir_all(stamp_file.parent().expect("git/"))?; |
|
| 2526 | - | fs::write(&stamp_file, stamp)?; |
|
| 2527 | - | Ok(!state.is_empty()) |
|
| 2528 | - | } |
|
| 2529 | 2179 | } |
modified crates/oxy-core/src/repo/identity.rs +0 −100
| … | 17 unchanged lines |
||
| 18 | 18 | Invalid(String), |
|
| 19 | 19 | } |
|
| 20 | 20 | ||
| 21 | - | /// Make a user identity with no repository (oxygen#144), so a first |
|
| 22 | - | /// identity comes before any repository: its secret and a copy of it go to |
|
| 23 | - | /// this home's keys, and the user file names it as the author, as `oxy |
|
| 24 | - | /// identity create` does inside one. A repository reads it from the keys |
|
| 25 | - | /// when it first signs with it. `name` and `email` default to the user |
|
| 26 | - | /// file's author, then to `$USER` and `OXY_AUTHOR_*`. |
|
| 27 | - | pub fn create_user_identity( |
|
| 28 | - | name: Option<&str>, |
|
| 29 | - | email: Option<&str>, |
|
| 30 | - | expires: Option<u64>, |
|
| 31 | - | ) -> Result<(KeyId, Identity)> { |
|
| 32 | - | let user = default_user_config(); |
|
| 33 | - | let defaults = Config::load(Some(&user), Path::new(""))?; |
|
| 34 | - | let name = name.map(str::to_string).unwrap_or(defaults.author_name); |
|
| 35 | - | let email = email.map(str::to_string).unwrap_or(defaults.author_email); |
|
| 36 | - | let sk = SecretKey::generate(); |
|
| 37 | - | let mut id = sk.identity(&name, &email, Hlc::now().wall_ms); |
|
| 38 | - | id.expires = expires; |
|
| 39 | - | let key = id.hash(); |
|
| 40 | - | let keys = default_keys_dir(); |
|
| 41 | - | fs::create_dir_all(&keys)?; |
|
| 42 | - | crate::durable::write_atomic_private( |
|
| 43 | - | &keys.join(format!("{}.secret", key.to_hex())), |
|
| 44 | - | &sk.encode(&key), |
|
| 45 | - | )?; |
|
| 46 | - | write_atomic( |
|
| 47 | - | &keys.join(format!("{}.identity", key.to_hex())), |
|
| 48 | - | &id.encode(), |
|
| 49 | - | )?; |
|
| 50 | - | Config::set_user(&user, "author.name", &id.name)?; |
|
| 51 | - | Config::set_user(&user, "author.email", &id.email)?; |
|
| 52 | - | Config::set_user(&user, "author.key", &key.to_hex())?; |
|
| 53 | - | Ok((key, id)) |
|
| 54 | - | } |
|
| 55 | - | ||
| 56 | 21 | /// The outcome of replacing the configured identity (spec §14.2). |
|
| 57 | 22 | #[derive(Clone, Debug)] |
|
| 58 | 23 | pub struct Rotation { |
|
| … | 112 unchanged lines |
||
| 171 | 136 | }; |
|
| 172 | 137 | if new.previous != Some(old) { |
|
| 173 | 138 | return fail("the successor identity must name the current key as previous"); |
|
| 174 | - | } |
|
| 175 | - | // A key that already has a successor is not the identity's newest: |
|
| 176 | - | // building another from it forks the identity into two branches |
|
| 177 | - | // (oxygen#163), as a checkout whose stale `author.key` pin outlived |
|
| 178 | - | // a rotation made elsewhere once did. |
|
| 179 | - | if let Some(newer) = self.successors(&old)?.into_iter().next() { |
|
| 180 | - | let newest = self.newest(&newer)?; |
|
| 181 | - | let fix = if self.config.is_repo_set("author.key") { |
|
| 182 | - | format!( |
|
| 183 | - | "This repository's config pins author.key to the older key: `oxy config author.key {}` here \ |
|
| 184 | - | (or `oxy config --unset author.key` to follow the user config), then run it again.", |
|
| 185 | - | newest.to_hex() |
|
| 186 | - | ) |
|
| 187 | - | } else { |
|
| 188 | - | format!( |
|
| 189 | - | "The user config names the older key: `oxy config --user author.key {}`, then run it again.", |
|
| 190 | - | newest.to_hex() |
|
| 191 | - | ) |
|
| 192 | - | }; |
|
| 193 | - | return fail(format!( |
|
| 194 | - | "`{command}` would start from key {}, which is not your identity's newest ({} succeeds it, and {} is the newest). \ |
|
| 195 | - | Another successor would fork the identity into two branches.\n{fix}", |
|
| 196 | - | old.short(12), |
|
| 197 | - | newer.short(12), |
|
| 198 | - | newest.short(12), |
|
| 199 | - | )); |
|
| 200 | 139 | } |
|
| 201 | 140 | let new_key = self.install_key(&new, &sk)?; |
|
| 202 | 141 | let attest = Attest { |
|
| … | 19 unchanged lines |
||
| 222 | 161 | identity: new, |
|
| 223 | 162 | policy, |
|
| 224 | 163 | }) |
|
| 225 | - | } |
|
| 226 | - | ||
| 227 | - | /// Keys in this home whose identity names `key` as `previous`: the |
|
| 228 | - | /// successors already made from it. More than one means a fork. |
|
| 229 | - | pub fn successors(&self, key: &KeyId) -> Result<Vec<KeyId>> { |
|
| 230 | - | let mut found = Vec::new(); |
|
| 231 | - | let entries = match fs::read_dir(&self.keys_dir) { |
|
| 232 | - | Ok(e) => e, |
|
| 233 | - | Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(found), |
|
| 234 | - | Err(e) => return Err(e.into()), |
|
| 235 | - | }; |
|
| 236 | - | for entry in entries { |
|
| 237 | - | let path = entry?.path(); |
|
| 238 | - | if path.extension().and_then(|e| e.to_str()) != Some("identity") { |
|
| 239 | - | continue; |
|
| 240 | - | } |
|
| 241 | - | let Ok(bytes) = fs::read(&path) else { continue }; |
|
| 242 | - | let Ok(id) = Identity::decode(&bytes) else { |
|
| 243 | - | continue; |
|
| 244 | - | }; |
|
| 245 | - | if id.previous == Some(*key) { |
|
| 246 | - | found.push(id.hash()); |
|
| 247 | - | } |
|
| 248 | - | } |
|
| 249 | - | found.sort(); |
|
| 250 | - | Ok(found) |
|
| 251 | - | } |
|
| 252 | - | ||
| 253 | - | /// The newest key of the line through `key` in this home: its |
|
| 254 | - | /// successors followed to the end (the first, where there is a fork). |
|
| 255 | - | pub fn newest(&self, key: &KeyId) -> Result<KeyId> { |
|
| 256 | - | let mut cur = *key; |
|
| 257 | - | for _ in 0..256 { |
|
| 258 | - | match self.successors(&cur)?.into_iter().next() { |
|
| 259 | - | Some(next) => cur = next, |
|
| 260 | - | None => break, |
|
| 261 | - | } |
|
| 262 | - | } |
|
| 263 | - | Ok(cur) |
|
| 264 | 164 | } |
|
| 265 | 165 | ||
| 266 | 166 | /// Rotate to a fresh key pair; the new identity names the old one as |
|
| … | 613 unchanged lines |
modified crates/oxy-core/src/repo/mod.rs +10 −37
| … | 142 unchanged lines |
||
| 143 | 143 | pub use git::{GitExportReport, GitImportReport, GitVerifyReport}; |
|
| 144 | 144 | pub use hooks::{json_array, json_str, HookOutcome}; |
|
| 145 | 145 | pub use hosted::FileEdit; |
|
| 146 | - | pub use identity::{create_user_identity, Rotation, SignatureStatus}; |
|
| 146 | + | pub use identity::{Rotation, SignatureStatus}; |
|
| 147 | 147 | pub use inspect::{BisectStep, BlameLine, Description}; |
|
| 148 | 148 | pub use keyless::home_key; |
|
| 149 | 149 | pub use ops::{RestoreReport, RevertReport, Undone, ViewChange}; |
|
| … | 549 unchanged lines |
||
| 699 | 699 | ||
| 700 | 700 | pub fn root(&self) -> &Path { |
|
| 701 | 701 | &self.root |
|
| 702 | - | } |
|
| 703 | - | /// The repository's `.oxy` directory (shared by its workspaces), for |
|
| 704 | - | /// what other crates keep beside the store (Cylinder's artifacts). |
|
| 705 | - | pub fn oxy_dir(&self) -> &Path { |
|
| 706 | - | &self.oxy |
|
| 707 | 702 | } |
|
| 708 | 703 | pub fn store(&self) -> &Store { |
|
| 709 | 704 | &self.store |
|
| … | 1517 unchanged lines |
||
| 2227 | 2222 | // already tracked as subrepo nodes, they contribute their pin; |
|
| 2228 | 2223 | // unregistered ones are left alone. |
|
| 2229 | 2224 | let modules = self.modules_on_disk(); |
|
| 2230 | - | // A subrepo at the state its recorded pin names is unmodified, |
|
| 2231 | - | // whatever bookmark it sits on (#147): the recorded pin stands. |
|
| 2232 | - | let subrepo_entry = |rel: &str, pin: crate::subrepo::Pin| -> FsEntry { |
|
| 2233 | - | if let Some((NodeKind::Subrepo, Some(b))) = tracked.get(rel) { |
|
| 2234 | - | let recorded = self |
|
| 2235 | - | .read_blob(b) |
|
| 2236 | - | .ok() |
|
| 2237 | - | .and_then(|x| crate::subrepo::Pin::decode(&x).ok()); |
|
| 2238 | - | if recorded.is_some_and(|r| r.same_state(&pin)) { |
|
| 2239 | - | return FsEntry { |
|
| 2240 | - | blob: Some(*b), |
|
| 2241 | - | ..FsEntry::new(NodeKind::Subrepo, false, vec![]) |
|
| 2242 | - | }; |
|
| 2243 | - | } |
|
| 2244 | - | } |
|
| 2245 | - | FsEntry::new(NodeKind::Subrepo, false, pin.encode()) |
|
| 2246 | - | }; |
|
| 2247 | - | // A removal's marker is spent once the removal is recorded (no |
|
| 2248 | - | // subrepo node is tracked there) or the path is registered again: |
|
| 2249 | - | // dropped before it is read, or the change registering it again |
|
| 2250 | - | // would leave it out (oxygen#152). |
|
| 2251 | - | let mut removed = self.removed_subrepos(); |
|
| 2252 | - | removed.retain(|rel| { |
|
| 2253 | - | let spent = tracked.get(rel).map(|(k, _)| *k) != Some(NodeKind::Subrepo) |
|
| 2254 | - | || modules.entries.contains_key(rel); |
|
| 2255 | - | if spent { |
|
| 2225 | + | let removed = self.removed_subrepos(); |
|
| 2226 | + | for rel in &removed { |
|
| 2227 | + | if tracked.get(rel).map(|(k, _)| *k) != Some(NodeKind::Subrepo) { |
|
| 2256 | 2228 | self.clear_removed_subrepo(rel); |
|
| 2257 | 2229 | } |
|
| 2258 | - | !spent |
|
| 2259 | - | }); |
|
| 2230 | + | } |
|
| 2260 | 2231 | let mut untracked_nested = Vec::new(); |
|
| 2261 | 2232 | for dir in nested { |
|
| 2262 | 2233 | let rel = self.rel_path(&dir); |
|
| … | 7 unchanged lines |
||
| 2270 | 2241 | continue; |
|
| 2271 | 2242 | } |
|
| 2272 | 2243 | let pin = subrepos::read_pin(&dir, registered.and_then(|m| m.bookmark.as_deref()))?; |
|
| 2273 | - | let entry = subrepo_entry(&rel, pin); |
|
| 2274 | - | out.insert(rel, entry); |
|
| 2244 | + | out.insert(rel, FsEntry::new(NodeKind::Subrepo, false, pin.encode())); |
|
| 2275 | 2245 | } |
|
| 2276 | 2246 | untracked_nested.sort(); |
|
| 2277 | 2247 | *self.untracked_nested.borrow_mut() = untracked_nested; |
|
| … | 14 unchanged lines |
||
| 2292 | 2262 | &path, |
|
| 2293 | 2263 | modules.entries.get(rel).and_then(|m| m.bookmark.as_deref()), |
|
| 2294 | 2264 | )?; |
|
| 2295 | - | out.insert(rel.clone(), subrepo_entry(rel, pin)); |
|
| 2265 | + | out.insert( |
|
| 2266 | + | rel.clone(), |
|
| 2267 | + | FsEntry::new(NodeKind::Subrepo, false, pin.encode()), |
|
| 2268 | + | ); |
|
| 2296 | 2269 | } else if let Some(b) = blob { |
|
| 2297 | 2270 | // Not cloned (or emptied): the pin stays as recorded, as a |
|
| 2298 | 2271 | // Git gitlink does when its directory is absent. |
|
| … | 650 unchanged lines |
modified crates/oxy-core/src/repo/subrepos.rs +10 −1
| … | 181 unchanged lines |
||
| 182 | 182 | } |
|
| 183 | 183 | } |
|
| 184 | 184 | let actual = read_pin(&dir, module.as_ref().and_then(|m| m.bookmark.as_deref()))?; |
|
| 185 | - | let same = pin.same_state(&actual); |
|
| 185 | + | let same = match (pin, &actual) { |
|
| 186 | + | (Pin::Oxy { heads: a, .. }, Pin::Oxy { heads: b, .. }) => { |
|
| 187 | + | let (mut a, mut b) = (a.clone(), b.clone()); |
|
| 188 | + | a.sort(); |
|
| 189 | + | b.sort(); |
|
| 190 | + | a == b |
|
| 191 | + | } |
|
| 192 | + | (Pin::Git { sha: a, .. }, Pin::Git { sha: b, .. }) => a == b, |
|
| 193 | + | _ => false, |
|
| 194 | + | }; |
|
| 186 | 195 | if same { |
|
| 187 | 196 | return Ok(if cloned { |
|
| 188 | 197 | SubrepoSync::Updated |
|
| … | 242 unchanged lines |
modified crates/oxy-core/src/repo/sync.rs +24 −121
| … | 1474 unchanged lines |
||
| 1475 | 1475 | if options.token.is_some() && options.ca.is_some() { |
|
| 1476 | 1476 | return; |
|
| 1477 | 1477 | } |
|
| 1478 | - | let own = options.token.is_some(); |
|
| 1479 | - | let env = std::env::var("OXY_TOKEN").is_ok_and(|t| !t.is_empty()); |
|
| 1480 | - | let explicit = own || env; |
|
| 1478 | + | let explicit = |
|
| 1479 | + | options.token.is_some() || std::env::var("OXY_TOKEN").is_ok_and(|t| !t.is_empty()); |
|
| 1481 | 1480 | let stored = self.credentials().options_for(url); |
|
| 1482 | - | // A checkout's own token refused as expired or unknown (401) falls |
|
| 1483 | - | // back to this computer's sign-in for the hub, never to another |
|
| 1484 | - | // checkout's, and never when it is refused for permission (#155). |
|
| 1485 | - | if own && !env { |
|
| 1486 | - | if let Some(t) = stored |
|
| 1487 | - | .token |
|
| 1488 | - | .clone() |
|
| 1489 | - | .filter(|t| options.token.as_ref() != Some(t)) |
|
| 1490 | - | { |
|
| 1491 | - | options.fallback_tokens.push(t); |
|
| 1492 | - | options.fallback_on_401_only = true; |
|
| 1493 | - | } |
|
| 1494 | - | } |
|
| 1495 | 1481 | options.token = options.token.take().or(stored.token); |
|
| 1496 | 1482 | options.ca = options.ca.take().or(stored.ca); |
|
| 1497 | 1483 | let enclosing = self.enclosing_credentials(url); |
|
| … | 12 unchanged lines |
||
| 1510 | 1496 | } |
|
| 1511 | 1497 | } |
|
| 1512 | 1498 | ||
| 1513 | - | /// What to do when `remote`'s own token was refused (`message` says |
|
| 1514 | - | /// HTTP 401) and so was this computer's sign-in for its hub, which it |
|
| 1515 | - | /// falls back to (oxygen#155). |
|
| 1516 | - | pub fn stale_token_note(&self, remote: &str, message: &str) -> Option<String> { |
|
| 1517 | - | if !message.contains("HTTP 401") { |
|
| 1518 | - | return None; |
|
| 1519 | - | } |
|
| 1520 | - | let own = self.config.remote_tokens.get(remote)?; |
|
| 1521 | - | let url = self.config.remotes.get(remote)?; |
|
| 1522 | - | let stored = self.credentials().options_for(url).token?; |
|
| 1523 | - | (stored != *own).then(|| { |
|
| 1524 | - | format!( |
|
| 1525 | - | "the hub refused both this checkout's own token for {remote} (remote.{remote}.token) and your sign-in: \ |
|
| 1526 | - | `oxy auth login HUB`, then `oxy config --unset remote.{remote}.token` so the sign-in is used" |
|
| 1527 | - | ) |
|
| 1528 | - | }) |
|
| 1529 | - | } |
|
| 1530 | - | ||
| 1531 | 1499 | /// The tokens and CAs of remotes on `url`'s hub in enclosing |
|
| 1532 | 1500 | /// checkouts, nearest first. |
|
| 1533 | 1501 | fn enclosing_credentials(&self, url: &str) -> Vec<(Option<String>, Option<PathBuf>)> { |
|
| … | 200 unchanged lines |
||
| 1734 | 1702 | pub fn fetch(&self, remote_name: &str) -> Result<FetchReport> { |
|
| 1735 | 1703 | let remote = self.open_named_remote(remote_name)?; |
|
| 1736 | 1704 | self.check_remote_id(remote.as_ref(), remote_name, false)?; |
|
| 1737 | - | let resp = { |
|
| 1738 | - | let _t = crate::timing::phase("fetch: refs"); |
|
| 1739 | - | remote.refs()? |
|
| 1740 | - | }; |
|
| 1705 | + | let resp = remote.refs()?; |
|
| 1741 | 1706 | // The host's transparency log (spec §14.8): a fork fails here. |
|
| 1742 | - | let log_phase = crate::timing::phase("fetch: transparency log"); |
|
| 1743 | 1707 | let log = self.check_log( |
|
| 1744 | 1708 | &self.remote_url(remote_name)?, |
|
| 1745 | 1709 | self.config.remote_cas.get(remote_name).map(Path::new), |
|
| 1746 | 1710 | &resp, |
|
| 1747 | 1711 | )?; |
|
| 1748 | - | drop(log_phase); |
|
| 1749 | 1712 | let mut log_notes = log.notes.clone(); |
|
| 1750 | 1713 | // Trust policy (spec §14.5). Adopt the remote's policy when it is newer |
|
| 1751 | 1714 | // and signed by roots we trust, or on first contact. A remote that |
|
| … | 47 unchanged lines |
||
| 1799 | 1762 | let mut report = Vec::new(); |
|
| 1800 | 1763 | let mut skipped = Vec::new(); |
|
| 1801 | 1764 | let max_blob = self.config.max_blob; |
|
| 1802 | - | // One negotiation and one bundle for every bookmark's heads at |
|
| 1803 | - | // once (oxygen#158): a bookmark at a time cost a round trip each and |
|
| 1804 | - | // sent again the changes bookmarks share, as `have` did not grow |
|
| 1805 | - | // between them (160 bookmarks: 160 bundles, 49k changes encoded for |
|
| 1806 | - | // a few hundred). Heads already here, with every attestation's |
|
| 1807 | - | // signer known, need no round trip at all. |
|
| 1808 | - | let mut wanted: Vec<ChangeHash> = resp |
|
| 1809 | - | .refs |
|
| 1810 | - | .iter() |
|
| 1811 | - | .flat_map(|r| r.heads.iter().copied()) |
|
| 1812 | - | .filter(|h| !self.store.has(h)) |
|
| 1813 | - | .collect(); |
|
| 1814 | - | wanted.sort(); |
|
| 1815 | - | wanted.dedup(); |
|
| 1816 | - | // A bundle also carries the identities and certificates of the keys |
|
| 1817 | - | // that signed the remote's attestations (spec §16.2): with no change |
|
| 1818 | - | // wanted, ask anyway when one of those signers is unknown here. |
|
| 1819 | - | let unknown_signer = resp |
|
| 1820 | - | .refs |
|
| 1821 | - | .iter() |
|
| 1822 | - | .filter_map(|r| r.attestation.as_ref()) |
|
| 1823 | - | .chain(resp.tags.iter().filter_map(|t| t.attestation.as_ref())) |
|
| 1824 | - | .flat_map(|a| a.sigs.iter().map(|s| s.key)) |
|
| 1825 | - | .any(|k| { |
|
| 1826 | - | self.store.get_identity(&k).is_err() |
|
| 1827 | - | && !matches!(self.store.certificate_of(&k), Ok(Some(_))) |
|
| 1828 | - | }); |
|
| 1829 | - | let shallow = self.is_shallow(); |
|
| 1830 | - | let imported: Vec<ChangeHash> = if wanted.is_empty() && !unknown_signer { |
|
| 1831 | - | Vec::new() |
|
| 1832 | - | } else { |
|
| 1765 | + | for r in resp.refs { |
|
| 1833 | 1766 | let needed = { |
|
| 1834 | 1767 | let _t = crate::timing::phase("fetch: negotiate"); |
|
| 1835 | - | remote.negotiate(&have, &wanted)? |
|
| 1768 | + | remote.negotiate(&have, &r.heads)? |
|
| 1836 | 1769 | }; |
|
| 1837 | 1770 | let bundle = { |
|
| 1838 | 1771 | let _t = crate::timing::phase("fetch: bundle"); |
|
| 1839 | 1772 | remote.fetch(&needed, max_blob)? |
|
| 1840 | 1773 | }; |
|
| 1841 | - | // Changes are not individually re-verified here: each bookmark's |
|
| 1774 | + | // Changes are not individually re-verified here: the bookmark's |
|
| 1842 | 1775 | // attestation (checked below) binds its whole state, and the |
|
| 1843 | 1776 | // receiver of the push verified the added changes at that time. |
|
| 1844 | 1777 | // A shallow repository takes changes whose dependencies it never |
|
| 1845 | 1778 | // held (below what it cloned), as its clone did (#137). |
|
| 1846 | - | let _t = crate::timing::phase("fetch: import"); |
|
| 1779 | + | let shallow = self.is_shallow(); |
|
| 1780 | + | let imported = { |
|
| 1781 | + | let _t = crate::timing::phase("fetch: import"); |
|
| 1782 | + | if shallow { |
|
| 1783 | + | self.import_bundle_shallow(&bundle, false)? |
|
| 1784 | + | } else { |
|
| 1785 | + | self.import_bundle(&bundle, false)? |
|
| 1786 | + | } |
|
| 1787 | + | }; |
|
| 1847 | 1788 | if shallow { |
|
| 1848 | - | self.import_bundle_shallow(&bundle, false)? |
|
| 1849 | - | } else { |
|
| 1850 | - | self.import_bundle(&bundle, false)? |
|
| 1789 | + | self.refresh_boundary(&imported)?; |
|
| 1851 | 1790 | } |
|
| 1852 | - | }; |
|
| 1853 | - | if shallow { |
|
| 1854 | - | self.refresh_boundary(&imported)?; |
|
| 1855 | - | } |
|
| 1856 | - | if max_blob.is_some() { |
|
| 1857 | - | self.register_missing_blobs(&imported, remote_name)?; |
|
| 1858 | - | } |
|
| 1859 | - | let boundary = if shallow { |
|
| 1860 | - | self.boundary() |
|
| 1861 | - | } else { |
|
| 1862 | - | BTreeSet::new() |
|
| 1863 | - | }; |
|
| 1864 | - | // Each bookmark's new changes: those just imported that its heads |
|
| 1865 | - | // reach, for the report. |
|
| 1866 | - | let mut new_deps: HashMap<ChangeHash, Vec<ChangeHash>> = HashMap::new(); |
|
| 1867 | - | for h in &imported { |
|
| 1868 | - | if let Ok(m) = self.store.get_change_meta(h) { |
|
| 1869 | - | new_deps.insert(*h, m.deps); |
|
| 1791 | + | if max_blob.is_some() { |
|
| 1792 | + | self.register_missing_blobs(&imported, remote_name)?; |
|
| 1870 | 1793 | } |
|
| 1871 | - | } |
|
| 1872 | - | let new_in = |heads: &[ChangeHash]| -> usize { |
|
| 1873 | - | let mut seen: HashSet<ChangeHash> = HashSet::new(); |
|
| 1874 | - | let mut stack: Vec<ChangeHash> = heads |
|
| 1875 | - | .iter() |
|
| 1876 | - | .filter(|h| new_deps.contains_key(*h)) |
|
| 1877 | - | .copied() |
|
| 1878 | - | .collect(); |
|
| 1879 | - | while let Some(h) = stack.pop() { |
|
| 1880 | - | if seen.insert(h) { |
|
| 1881 | - | stack.extend( |
|
| 1882 | - | new_deps[&h] |
|
| 1883 | - | .iter() |
|
| 1884 | - | .filter(|d| new_deps.contains_key(*d) && !seen.contains(*d)), |
|
| 1885 | - | ); |
|
| 1886 | - | } |
|
| 1887 | - | } |
|
| 1888 | - | seen.len() |
|
| 1889 | - | }; |
|
| 1890 | - | let checks = crate::timing::phase("fetch: check each bookmark"); |
|
| 1891 | - | for r in resp.refs { |
|
| 1794 | + | let boundary = if shallow { |
|
| 1795 | + | self.boundary() |
|
| 1796 | + | } else { |
|
| 1797 | + | BTreeSet::new() |
|
| 1798 | + | }; |
|
| 1892 | 1799 | for h in &r.heads { |
|
| 1893 | 1800 | if !self.store.has(h) && !boundary.contains(h) { |
|
| 1894 | 1801 | return fail(format!("remote did not send head {}", h.short(12))); |
|
| … | 74 unchanged lines |
||
| 1969 | 1876 | .entry(remote_name.to_string()) |
|
| 1970 | 1877 | .or_default() |
|
| 1971 | 1878 | .insert(r.name.clone(), state); |
|
| 1972 | - | let n = new_in(&r.heads); |
|
| 1973 | - | report.push((r.name, r.heads, n)); |
|
| 1879 | + | report.push((r.name, r.heads, imported.len())); |
|
| 1974 | 1880 | } |
|
| 1975 | - | drop(checks); |
|
| 1976 | - | let tags_phase = crate::timing::phase("fetch: tags"); |
|
| 1977 | 1881 | let mut new_tags = 0; |
|
| 1978 | 1882 | for t in &resp.tags { |
|
| 1979 | 1883 | if view.tags.contains_key(&t.name) { |
|
| … | 34 unchanged lines |
||
| 2014 | 1918 | // The remote withdrew a tag this repository has: so does this one, |
|
| 2015 | 1919 | // once the withdrawal is checked as a push's would be; one that is |
|
| 2016 | 1920 | // not is left as it is, said so (oxygenhub#301). |
|
| 2017 | - | drop(tags_phase); |
|
| 2018 | 1921 | let mut withdrawn_tags = Vec::new(); |
|
| 2019 | 1922 | for t in &resp.withdrawn { |
|
| 2020 | 1923 | if !view.tags.contains_key(&t.name) { |
|
| … | 1151 unchanged lines |
modified crates/oxy-core/src/repo/tests.rs +0 −361
| … | 5371 unchanged lines |
||
| 5372 | 5372 | !clone.snapshot("status").unwrap().changed, |
|
| 5373 | 5373 | "an unregistered nested repository is ignored" |
|
| 5374 | 5374 | ); |
|
| 5375 | - | ||
| 5376 | - | // Registered again, it is pinned again; removed and committed, then |
|
| 5377 | - | // registered again with no snapshot between, the change that adds it |
|
| 5378 | - | // back pins it too: the removal's marker is spent (oxygen#152). |
|
| 5379 | - | let modules = format!("[libs/lib]\nurl = {lib_url}\n"); |
|
| 5380 | - | let pinned = |c: ChangeHash| { |
|
| 5381 | - | clone |
|
| 5382 | - | .load_state(&[c]) |
|
| 5383 | - | .unwrap() |
|
| 5384 | - | .materialize() |
|
| 5385 | - | .files |
|
| 5386 | - | .get("libs/lib") |
|
| 5387 | - | .map(|n| n.kind) |
|
| 5388 | - | }; |
|
| 5389 | - | write(&clone_dir, ".oxymodules", modules.as_bytes()); |
|
| 5390 | - | let c = clone.commit("lib again", &[]).unwrap(); |
|
| 5391 | - | assert_eq!(pinned(c), Some(NodeKind::Subrepo)); |
|
| 5392 | - | clone.submodule_remove("libs/lib").unwrap(); |
|
| 5393 | - | let c = clone.commit("drop lib again", &[]).unwrap(); |
|
| 5394 | - | assert_eq!(pinned(c), None); |
|
| 5395 | - | write(&clone_dir, ".oxymodules", modules.as_bytes()); |
|
| 5396 | - | let c = clone.commit("lib back", &[]).unwrap(); |
|
| 5397 | - | assert_eq!( |
|
| 5398 | - | pinned(c), |
|
| 5399 | - | Some(NodeKind::Subrepo), |
|
| 5400 | - | "pinned in the change that registers it" |
|
| 5401 | - | ); |
|
| 5402 | - | assert!(!clone.snapshot("status").unwrap().changed); |
|
| 5403 | 5375 | } |
|
| 5404 | 5376 | ||
| 5405 | 5377 | #[test] |
|
| … | 5603 unchanged lines |
||
| 11009 | 10981 | assert!(format!("{:?}", e.unwrap_err()).contains("does not exist")); |
|
| 11010 | 10982 | } |
|
| 11011 | 10983 | ||
| 11012 | - | /// oxygen#147: a subrepo at its pinned state is unmodified whatever |
|
| 11013 | - | /// bookmark it sits on, so the parent's status is clean and a bookmark |
|
| 11014 | - | /// switch goes ahead; a new state in it is still a change. |
|
| 11015 | - | #[test] |
|
| 11016 | - | fn a_subrepo_at_its_pinned_state_on_another_bookmark_is_unmodified() { |
|
| 11017 | - | hermetic(); |
|
| 11018 | - | let dir = tempfile::tempdir().unwrap(); |
|
| 11019 | - | let root = dir.path(); |
|
| 11020 | - | let _lib_origin = Repo::init(&root.join("lib-origin")).unwrap(); |
|
| 11021 | - | let lib_url = root.join("lib-origin").to_string_lossy().to_string(); |
|
| 11022 | - | let lib = Repo::clone(&lib_url, &root.join("lib")) |
|
| 11023 | - | .unwrap() |
|
| 11024 | - | .with_home(root.join("home")); |
|
| 11025 | - | write(&root.join("lib"), "lib.txt", b"v1\n"); |
|
| 11026 | - | lib.commit("lib v1", &[]).unwrap(); |
|
| 11027 | - | assert!(lib.push("origin", false).unwrap()[0].ok); |
|
| 11028 | - | let _app_origin = Repo::init(&root.join("app-origin")).unwrap(); |
|
| 11029 | - | let app_dir = root.join("app"); |
|
| 11030 | - | let mut app = Repo::clone(&root.join("app-origin").to_string_lossy(), &app_dir) |
|
| 11031 | - | .unwrap() |
|
| 11032 | - | .with_home(root.join("home")); |
|
| 11033 | - | write(&app_dir, "main.txt", b"app\n"); |
|
| 11034 | - | app.submodule_add(&lib_url, "libs/lib", None).unwrap(); |
|
| 11035 | - | let a1 = app.commit("app with lib", &[]).unwrap(); |
|
| 11036 | - | ||
| 11037 | - | // The nested repository moves to another bookmark at the same heads. |
|
| 11038 | - | let mut nested = Repo::open(&app_dir.join("libs/lib")) |
|
| 11039 | - | .unwrap() |
|
| 11040 | - | .with_home(root.join("home")); |
|
| 11041 | - | let heads = nested.bookmark_heads().unwrap(); |
|
| 11042 | - | nested.bookmark_create("feature", Some(&heads)).unwrap(); |
|
| 11043 | - | nested.bookmark_switch("feature", false).unwrap(); |
|
| 11044 | - | let snap = app.snapshot("status").unwrap(); |
|
| 11045 | - | assert!( |
|
| 11046 | - | !snap.changed, |
|
| 11047 | - | "only the bookmark differs: {:?}", |
|
| 11048 | - | snap.statuses |
|
| 11049 | - | ); |
|
| 11050 | - | app.bookmark_create("other", Some(&[a1])).unwrap(); |
|
| 11051 | - | app.bookmark_switch("other", false).unwrap(); |
|
| 11052 | - | ||
| 11053 | - | // A new state in it is a change, as before. |
|
| 11054 | - | let nested = Repo::open(&app_dir.join("libs/lib")) |
|
| 11055 | - | .unwrap() |
|
| 11056 | - | .with_home(root.join("home")); |
|
| 11057 | - | write(&app_dir.join("libs/lib"), "lib.txt", b"v2\n"); |
|
| 11058 | - | nested.commit("lib v2", &[]).unwrap(); |
|
| 11059 | - | let snap = app.snapshot("status").unwrap(); |
|
| 11060 | - | assert_eq!( |
|
| 11061 | - | snap.statuses |
|
| 11062 | - | .iter() |
|
| 11063 | - | .map(|s| (s.path.as_str(), s.status)) |
|
| 11064 | - | .collect::<Vec<_>>(), |
|
| 11065 | - | vec![("libs/lib", ChangeStatus::Modified)] |
|
| 11066 | - | ); |
|
| 11067 | - | } |
|
| 11068 | - | ||
| 11069 | 10984 | /// oxygenhub#249: a handle reads the operation head once and keeps it, |
|
| 11070 | 10985 | /// so one command or request never mixes two heads; another handle's |
|
| 11071 | 10986 | /// operation shows only after `refresh`. Its own operations move it, and |
|
| … | 200 unchanged lines |
||
| 11272 | 11187 | Some(pin), |
|
| 11273 | 11188 | "a repository's pin wins" |
|
| 11274 | 11189 | ); |
|
| 11275 | - | } |
|
| 11276 | - | ||
| 11277 | - | #[test] |
|
| 11278 | - | fn git_export_graph_is_deterministic_and_merges_heads() { |
|
| 11279 | - | hermetic(); |
|
| 11280 | - | if std::process::Command::new("git") |
|
| 11281 | - | .arg("--version") |
|
| 11282 | - | .output() |
|
| 11283 | - | .is_err() |
|
| 11284 | - | { |
|
| 11285 | - | eprintln!("git not installed; skipping"); |
|
| 11286 | - | return; |
|
| 11287 | - | } |
|
| 11288 | - | let dir = tempfile::tempdir().unwrap(); |
|
| 11289 | - | let root = dir.path(); |
|
| 11290 | - | let mut repo = Repo::init(&root.join("r")) |
|
| 11291 | - | .unwrap() |
|
| 11292 | - | .with_home(root.join("home")); |
|
| 11293 | - | repo.create_identity("Ada Lovelace", "[email protected]", IdentityScope::User) |
|
| 11294 | - | .unwrap(); |
|
| 11295 | - | let r = root.join("r"); |
|
| 11296 | - | write(&r, "README.md", b"hello\n"); |
|
| 11297 | - | let h1 = repo.commit("first", &[]).unwrap(); |
|
| 11298 | - | write(&r, "README.md", b"hello\nworld\n"); |
|
| 11299 | - | write(&r, "src/main.rs", b"fn main() {}\n"); |
|
| 11300 | - | let h2 = repo.commit("second", &[]).unwrap(); |
|
| 11301 | - | repo.tag_create("v1", &[h2], "the first release").unwrap(); |
|
| 11302 | - | // An independent change: main gets two heads. |
|
| 11303 | - | repo.checkout(&[h1], false, "checkout").unwrap(); |
|
| 11304 | - | write(&r, "other.txt", b"o\n"); |
|
| 11305 | - | let h3 = repo.commit("third", &[]).unwrap(); |
|
| 11306 | - | repo.bookmark_create("gone", Some(&[h1])).unwrap(); |
|
| 11307 | - | ||
| 11308 | - | let git = |git_dir: &Path, args: &[&str]| -> String { |
|
| 11309 | - | let out = std::process::Command::new("git") |
|
| 11310 | - | .arg("-C") |
|
| 11311 | - | .arg(git_dir) |
|
| 11312 | - | .args(args) |
|
| 11313 | - | .output() |
|
| 11314 | - | .unwrap(); |
|
| 11315 | - | assert!( |
|
| 11316 | - | out.status.success(), |
|
| 11317 | - | "git {args:?}: {}", |
|
| 11318 | - | String::from_utf8_lossy(&out.stderr) |
|
| 11319 | - | ); |
|
| 11320 | - | String::from_utf8_lossy(&out.stdout).trim().to_string() |
|
| 11321 | - | }; |
|
| 11322 | - | let a = root.join("a.git"); |
|
| 11323 | - | let rep = repo.git_export_graph(&a).unwrap(); |
|
| 11324 | - | assert_eq!((rep.commits, rep.tags), (3, 1), "{rep:?}"); |
|
| 11325 | - | assert_eq!(rep.branches, 2, "main and gone: {rep:?}"); |
|
| 11326 | - | ||
| 11327 | - | // Each change is a commit whose parents are exactly its dependencies' |
|
| 11328 | - | // commits (Oxygen's dependencies, not the order changes were made in). |
|
| 11329 | - | let by_hash = |hash: ChangeHash| { |
|
| 11330 | - | git( |
|
| 11331 | - | &a, |
|
| 11332 | - | &[ |
|
| 11333 | - | "log", |
|
| 11334 | - | "--all", |
|
| 11335 | - | "--format=%H", |
|
| 11336 | - | &format!("--grep=Oxy-Hash: {}", hash.to_hex()), |
|
| 11337 | - | ], |
|
| 11338 | - | ) |
|
| 11339 | - | }; |
|
| 11340 | - | let (c1, c2, c3) = (by_hash(h1), by_hash(h2), by_hash(h3)); |
|
| 11341 | - | for (h, c) in [(h1, &c1), (h2, &c2), (h3, &c3)] { |
|
| 11342 | - | let mut want: Vec<String> = repo |
|
| 11343 | - | .store() |
|
| 11344 | - | .get_change_meta(&h) |
|
| 11345 | - | .unwrap() |
|
| 11346 | - | .deps |
|
| 11347 | - | .iter() |
|
| 11348 | - | .map(|d| by_hash(*d)) |
|
| 11349 | - | .collect(); |
|
| 11350 | - | want.sort(); |
|
| 11351 | - | let mut have: Vec<String> = git(&a, &["rev-list", "--parents", "-1", c]) |
|
| 11352 | - | .split(' ') |
|
| 11353 | - | .skip(1) |
|
| 11354 | - | .map(String::from) |
|
| 11355 | - | .collect(); |
|
| 11356 | - | have.sort(); |
|
| 11357 | - | assert_eq!(have, want, "{h:?}'s commit's parents"); |
|
| 11358 | - | } |
|
| 11359 | - | assert!( |
|
| 11360 | - | !repo.store().get_change_meta(&h2).unwrap().deps.is_empty(), |
|
| 11361 | - | "second edits first's README" |
|
| 11362 | - | ); |
|
| 11363 | - | assert_eq!( |
|
| 11364 | - | git(&a, &["show", &format!("{c2}:src/main.rs")]), |
|
| 11365 | - | "fn main() {}" |
|
| 11366 | - | ); |
|
| 11367 | - | assert!( |
|
| 11368 | - | git(&a, &["ls-tree", "--name-only", &c3]) |
|
| 11369 | - | .lines() |
|
| 11370 | - | .all(|l| l != "src"), |
|
| 11371 | - | "a change's tree is its own closure, not the bookmark's" |
|
| 11372 | - | ); |
|
| 11373 | - | assert_eq!( |
|
| 11374 | - | git(&a, &["log", "-1", "--format=%an <%ae>", &c1]), |
|
| 11375 | - | "Ada Lovelace <[email protected]>" |
|
| 11376 | - | ); |
|
| 11377 | - | ||
| 11378 | - | // main has two heads: a merge of both, whose tree is the union. |
|
| 11379 | - | let main = git(&a, &["rev-parse", "main"]); |
|
| 11380 | - | let mut parents: Vec<String> = git(&a, &["rev-list", "--parents", "-1", "main"]) |
|
| 11381 | - | .split(' ') |
|
| 11382 | - | .skip(1) |
|
| 11383 | - | .map(String::from) |
|
| 11384 | - | .collect(); |
|
| 11385 | - | parents.sort(); |
|
| 11386 | - | let mut want = vec![c2.clone(), c3.clone()]; |
|
| 11387 | - | want.sort(); |
|
| 11388 | - | assert_eq!(parents, want, "the merge's parents are the heads"); |
|
| 11389 | - | assert_eq!( |
|
| 11390 | - | git(&a, &["ls-tree", "--name-only", "main"]), |
|
| 11391 | - | "README.md\nother.txt\nsrc" |
|
| 11392 | - | ); |
|
| 11393 | - | assert!(git(&a, &["log", "-1", "--format=%B", "main"]).contains("Merge of 2 heads")); |
|
| 11394 | - | assert_eq!( |
|
| 11395 | - | git(&a, &["rev-parse", "v1^{commit}"]), |
|
| 11396 | - | c2, |
|
| 11397 | - | "the tag is its head's commit" |
|
| 11398 | - | ); |
|
| 11399 | - | assert_eq!(git(&a, &["symbolic-ref", "HEAD"]), "refs/heads/main"); |
|
| 11400 | - | ||
| 11401 | - | // Again: nothing new. A bookmark deleted takes its branch with it. |
|
| 11402 | - | repo.bookmark_delete("gone").unwrap(); |
|
| 11403 | - | let rep = repo.git_export_graph(&a).unwrap(); |
|
| 11404 | - | assert_eq!(rep.commits, 0, "{rep:?}"); |
|
| 11405 | - | assert!( |
|
| 11406 | - | git(&a, &["for-each-ref", "--format=%(refname)", "refs/heads"]) |
|
| 11407 | - | .lines() |
|
| 11408 | - | .all(|r| r != "refs/heads/gone") |
|
| 11409 | - | ); |
|
| 11410 | - | assert_eq!( |
|
| 11411 | - | git(&a, &["rev-parse", "main"]), |
|
| 11412 | - | main, |
|
| 11413 | - | "the merge is made once" |
|
| 11414 | - | ); |
|
| 11415 | - | ||
| 11416 | - | // The same changes elsewhere give the same commits. |
|
| 11417 | - | let other = Repo::clone(r.to_str().unwrap(), &root.join("clone")) |
|
| 11418 | - | .unwrap() |
|
| 11419 | - | .with_home(root.join("home")); |
|
| 11420 | - | let b = root.join("b.git"); |
|
| 11421 | - | other.git_export_graph(&b).unwrap(); |
|
| 11422 | - | assert_eq!( |
|
| 11423 | - | git(&b, &["rev-parse", "main"]), |
|
| 11424 | - | main, |
|
| 11425 | - | "deterministic across repositories" |
|
| 11426 | - | ); |
|
| 11427 | - | assert_eq!(git(&b, &["rev-parse", "v1^{commit}"]), c2); |
|
| 11428 | - | } |
|
| 11429 | - | ||
| 11430 | - | #[test] |
|
| 11431 | - | fn a_fetch_of_many_bookmarks_takes_shared_changes_once() { |
|
| 11432 | - | // oxygen#158: every bookmark's heads are fetched in one exchange, so |
|
| 11433 | - | // changes bookmarks share are not sent again for each; each bookmark |
|
| 11434 | - | // still says how many of its changes were new, and a fetch with |
|
| 11435 | - | // nothing new imports nothing. |
|
| 11436 | - | hermetic(); |
|
| 11437 | - | let dir = tempfile::tempdir().unwrap(); |
|
| 11438 | - | let root = dir.path(); |
|
| 11439 | - | drop(Repo::init(&root.join("origin")).unwrap()); |
|
| 11440 | - | let url = root.join("origin").to_string_lossy().to_string(); |
|
| 11441 | - | let mut a = Repo::clone(&url, &root.join("a")) |
|
| 11442 | - | .unwrap() |
|
| 11443 | - | .with_home(root.join("home-a")); |
|
| 11444 | - | let w = root.join("a"); |
|
| 11445 | - | write(&w, "f.txt", b"one\n"); |
|
| 11446 | - | a.commit("one", &[]).unwrap(); |
|
| 11447 | - | write(&w, "f.txt", b"one\ntwo\n"); |
|
| 11448 | - | a.commit("two", &[]).unwrap(); |
|
| 11449 | - | a.push("origin", false).unwrap(); |
|
| 11450 | - | // Five bookmarks on main's history, each one change of its own. |
|
| 11451 | - | for i in 0..5 { |
|
| 11452 | - | a.bookmark_create(&format!("feat{i}"), None).unwrap(); |
|
| 11453 | - | a.bookmark_switch(&format!("feat{i}"), false).unwrap(); |
|
| 11454 | - | write(&w, &format!("feat{i}.txt"), format!("{i}\n").as_bytes()); |
|
| 11455 | - | a.commit(&format!("feat {i}"), &[]).unwrap(); |
|
| 11456 | - | a.push("origin", false).unwrap(); |
|
| 11457 | - | a.bookmark_switch("main", false).unwrap(); |
|
| 11458 | - | } |
|
| 11459 | - | ||
| 11460 | - | let b = Repo::clone(&url, &root.join("b")) |
|
| 11461 | - | .unwrap() |
|
| 11462 | - | .with_home(root.join("home-b")); |
|
| 11463 | - | let report = b.fetch("origin").unwrap(); |
|
| 11464 | - | assert_eq!(report.refs.len(), 6, "every bookmark: {:?}", report.refs); |
|
| 11465 | - | assert!( |
|
| 11466 | - | report.refs.iter().all(|(_, _, n)| *n == 0), |
|
| 11467 | - | "the clone brought them all: {:?}", |
|
| 11468 | - | report.refs |
|
| 11469 | - | ); |
|
| 11470 | - | ||
| 11471 | - | // One new change on one bookmark: counted there, nowhere else. |
|
| 11472 | - | a.bookmark_switch("feat3", false).unwrap(); |
|
| 11473 | - | write(&w, "feat3.txt", b"3\nmore\n"); |
|
| 11474 | - | a.commit("feat 3 again", &[]).unwrap(); |
|
| 11475 | - | a.push("origin", false).unwrap(); |
|
| 11476 | - | let fetches = || crate::protocol::LOCAL_FETCHES.with(|n| n.get()); |
|
| 11477 | - | let at = fetches(); |
|
| 11478 | - | let report = b.fetch("origin").unwrap(); |
|
| 11479 | - | assert_eq!(fetches() - at, 1, "one bundle for all six bookmarks"); |
|
| 11480 | - | let counts: Vec<(String, usize)> = report |
|
| 11481 | - | .refs |
|
| 11482 | - | .iter() |
|
| 11483 | - | .map(|(n, _, c)| (n.clone(), *c)) |
|
| 11484 | - | .collect(); |
|
| 11485 | - | assert!(counts.contains(&("feat3".to_string(), 1)), "{counts:?}"); |
|
| 11486 | - | assert_eq!( |
|
| 11487 | - | counts.iter().filter(|(_, c)| *c > 0).count(), |
|
| 11488 | - | 1, |
|
| 11489 | - | "only feat3 had anything new: {counts:?}" |
|
| 11490 | - | ); |
|
| 11491 | - | ||
| 11492 | - | // Nothing new: no bundle at all, every bookmark still listed. |
|
| 11493 | - | let at = fetches(); |
|
| 11494 | - | let report = b.fetch("origin").unwrap(); |
|
| 11495 | - | assert_eq!(fetches() - at, 0, "nothing to fetch, no round trip"); |
|
| 11496 | - | assert_eq!(report.refs.len(), 6); |
|
| 11497 | - | assert!( |
|
| 11498 | - | report.refs.iter().all(|(_, _, n)| *n == 0), |
|
| 11499 | - | "{:?}", |
|
| 11500 | - | report.refs |
|
| 11501 | - | ); |
|
| 11502 | - | } |
|
| 11503 | - | ||
| 11504 | - | #[test] |
|
| 11505 | - | fn a_stale_pinned_key_cannot_fork_the_identity() { |
|
| 11506 | - | // oxygen#163: a checkout pinned author.key to a key that a rotation made |
|
| 11507 | - | // elsewhere had already succeeded; delegating there built a second |
|
| 11508 | - | // successor of it, splitting the identity in two. |
|
| 11509 | - | hermetic(); |
|
| 11510 | - | let dir = tempfile::tempdir().unwrap(); |
|
| 11511 | - | let root = dir.path(); |
|
| 11512 | - | let home = root.join("home"); |
|
| 11513 | - | let mut a = Repo::init(&root.join("a")).unwrap().with_home(&home); |
|
| 11514 | - | let (first, _) = a |
|
| 11515 | - | .create_identity("Ada", "[email protected]", IdentityScope::User) |
|
| 11516 | - | .unwrap(); |
|
| 11517 | - | let r = a.rotate_identity().unwrap(); |
|
| 11518 | - | assert_eq!((r.old, a.config.author_key), (first, Some(r.new))); |
|
| 11519 | - | assert_eq!(a.successors(&first).unwrap(), vec![r.new]); |
|
| 11520 | - | assert_eq!(a.newest(&first).unwrap(), r.new); |
|
| 11521 | - | ||
| 11522 | - | // Another checkout still pins the first key. |
|
| 11523 | - | let mut b = Repo::init(&root.join("b")).unwrap().with_home(&home); |
|
| 11524 | - | b.config.set("author.key", &first.to_hex()).unwrap(); |
|
| 11525 | - | b.save_config().unwrap(); |
|
| 11526 | - | let mut b = Repo::open(&root.join("b")).unwrap().with_home(&home); |
|
| 11527 | - | assert_eq!(b.config.author_key, Some(first)); |
|
| 11528 | - | for e in [ |
|
| 11529 | - | b.rotate_identity().unwrap_err().to_string(), |
|
| 11530 | - | b.renew_identity(None).unwrap_err().to_string(), |
|
| 11531 | - | ] { |
|
| 11532 | - | assert!(e.contains("fork") && e.contains(&r.new.short(12)), "{e}"); |
|
| 11533 | - | assert!( |
|
| 11534 | - | e.contains(&format!("oxy config author.key {}", r.new.to_hex())), |
|
| 11535 | - | "{e}" |
|
| 11536 | - | ); |
|
| 11537 | - | } |
|
| 11538 | - | assert_eq!( |
|
| 11539 | - | b.successors(&first).unwrap(), |
|
| 11540 | - | vec![r.new], |
|
| 11541 | - | "nothing was made" |
|
| 11542 | - | ); |
|
| 11543 | - | ||
| 11544 | - | // Pointed at the newest key, it rotates as usual. |
|
| 11545 | - | b.config.set("author.key", &r.new.to_hex()).unwrap(); |
|
| 11546 | - | b.save_config().unwrap(); |
|
| 11547 | - | let mut b = Repo::open(&root.join("b")).unwrap().with_home(&home); |
|
| 11548 | - | let r2 = b.rotate_identity().unwrap(); |
|
| 11549 | - | assert_eq!(r2.old, r.new); |
|
| 11550 | - | assert_eq!(b.newest(&first).unwrap(), r2.new); |
|
| 11551 | 11190 | } |
modified crates/oxy-core/src/repo/walk.rs +1 −3
| … | 184 unchanged lines |
||
| 185 | 185 | let mut mine = Listing::default(); |
|
| 186 | 186 | mine.dirs.push((rel.clone(), mtime)); |
|
| 187 | 187 | for (e, name) in entries.into_iter().zip(names) { |
|
| 188 | - | // `.git` is never content: a side-by-side Git repository |
|
| 189 | - | // (`git.colocate`), or Git's own beside an import. |
|
| 190 | - | if name == OXY_DIR || name.eq_ignore_ascii_case(".git") { |
|
| 188 | + | if name == OXY_DIR { |
|
| 191 | 189 | continue; |
|
| 192 | 190 | } |
|
| 193 | 191 | let Ok(ft) = e.file_type() else { continue }; |
|
| … | 136 unchanged lines |
modified crates/oxy-core/src/subrepo.rs +0 −30
| … | 25 unchanged lines |
||
| 26 | 26 | } |
|
| 27 | 27 | ||
| 28 | 28 | impl Pin { |
|
| 29 | - | /// Whether two pins name the same state: the same repository at the |
|
| 30 | - | /// same heads, in any order, or the same Git commit. The bookmark or |
|
| 31 | - | /// branch each names does not count (#147): a subrepo at its pinned |
|
| 32 | - | /// state is at it whatever bookmark it sits on. |
|
| 33 | - | pub fn same_state(&self, other: &Pin) -> bool { |
|
| 34 | - | match (self, other) { |
|
| 35 | - | ( |
|
| 36 | - | Pin::Oxy { |
|
| 37 | - | repo: r1, |
|
| 38 | - | heads: h1, |
|
| 39 | - | .. |
|
| 40 | - | }, |
|
| 41 | - | Pin::Oxy { |
|
| 42 | - | repo: r2, |
|
| 43 | - | heads: h2, |
|
| 44 | - | .. |
|
| 45 | - | }, |
|
| 46 | - | ) => { |
|
| 47 | - | let (mut a, mut b) = (h1.clone(), h2.clone()); |
|
| 48 | - | a.sort(); |
|
| 49 | - | a.dedup(); |
|
| 50 | - | b.sort(); |
|
| 51 | - | b.dedup(); |
|
| 52 | - | r1 == r2 && a == b |
|
| 53 | - | } |
|
| 54 | - | (Pin::Git { sha: a, .. }, Pin::Git { sha: b, .. }) => a == b, |
|
| 55 | - | _ => false, |
|
| 56 | - | } |
|
| 57 | - | } |
|
| 58 | - | ||
| 59 | 29 | pub fn encode(&self) -> Vec<u8> { |
|
| 60 | 30 | let v = match self { |
|
| 61 | 31 | Pin::Oxy { |
|
| … | 278 unchanged lines |
modified crates/oxy-server/tests/http.rs +1 −27
| … | 757 unchanged lines |
||
| 758 | 758 | vec!["good".to_string()], |
|
| 759 | 759 | "the parent's, to fall back on" |
|
| 760 | 760 | ); |
|
| 761 | - | assert!(!options.fallback_on_401_only); |
|
| 762 | 761 | write(&nested, "c.txt", b"child\n"); |
|
| 763 | 762 | child.commit("child work", &[]).unwrap(); |
|
| 764 | 763 | let pushed = child.push("origin", false).unwrap(); |
|
| … | 7 unchanged lines |
||
| 772 | 771 | 1 |
|
| 773 | 772 | ); |
|
| 774 | 773 | ||
| 775 | - | // Its own token, if refused, falls back to this computer's sign-in, |
|
| 776 | - | // never to the parent's (#155): stale too here, so the push fails and |
|
| 777 | - | // says what to do. |
|
| 774 | + | // Its own token, if wrong, stays wrong: what a checkout sets is its choice. |
|
| 778 | 775 | child.config.set("remote.origin.token", "wrong").unwrap(); |
|
| 779 | 776 | child.save_config().unwrap(); |
|
| 780 | - | let options = child.options_for_url(&format!("{base}/child")); |
|
| 781 | - | assert_eq!( |
|
| 782 | - | options.fallback_tokens, |
|
| 783 | - | vec!["stale".to_string()], |
|
| 784 | - | "the sign-in only" |
|
| 785 | - | ); |
|
| 786 | - | assert!( |
|
| 787 | - | options.fallback_on_401_only, |
|
| 788 | - | "and only for a token the hub does not know: one refused for permission is not swapped" |
|
| 789 | - | ); |
|
| 790 | 777 | write(&nested, "d.txt", b"more\n"); |
|
| 791 | 778 | child.commit("more", &[]).unwrap(); |
|
| 792 | 779 | let err = child.push("origin", false).err().unwrap().to_string(); |
|
| 793 | 780 | assert!(err.contains("401"), "{err}"); |
|
| 794 | - | let note = child.stale_token_note("origin", &err).expect("a note"); |
|
| 795 | - | assert!( |
|
| 796 | - | note.contains("oxy auth login") && note.contains("oxy config --unset remote.origin.token"), |
|
| 797 | - | "{note}" |
|
| 798 | - | ); |
|
| 799 | - | assert!(child.stale_token_note("origin", "HTTP 500").is_none()); |
|
| 800 | - | // With a good sign-in, an expired checkout token no longer blocks. |
|
| 801 | - | oxy_core::credentials::Credentials::at(&home) |
|
| 802 | - | .save(&base, "good", Some("andy"), None) |
|
| 803 | - | .unwrap(); |
|
| 804 | - | let child = Repo::open(&nested).unwrap().with_home(&home); |
|
| 805 | - | let pushed = child.push("origin", false).unwrap(); |
|
| 806 | - | assert!(pushed[0].ok, "{}", pushed[0].reason); |
|
| 807 | 781 | } |
|
| 808 | 782 | ||
| 809 | 783 | /// A host refuses a push by what it adds (`Backend::vet_push`): the client |
|
| … | 450 unchanged lines |
modified docs/cylinder.md +0 −11
| … | 395 unchanged lines |
||
| 396 | 396 | - **C1. The service boundary and artifact model.** Implement the |
|
| 397 | 397 | `Artifact` CBOR object type and FastCDC chunk engine in `cylinder`; |
|
| 398 | 398 | unify runner images with artifacts. |
|
| 399 | - | *Started 2026-10-28 (oxygen#108):* `crates/cylinder` has the |
|
| 400 | - | `Artifact` and `DirTree` encodings of §4.1 (canonical CBOR; a name is |
|
| 401 | - | the BLAKE3 of the encoding; `env` and `labels` as sorted pairs, since |
|
| 402 | - | the profile's maps take integer keys), packing a directory into the |
|
| 403 | - | repository's own blobs and chunks, verifying and unpacking, and the |
|
| 404 | - | roots garbage collection keeps; `oxy artifact pack | list | show | |
|
| 405 | - | unpack | verify`. The artifact is an object type of its own |
|
| 406 | - | (`artifact`, in oxy-core's `artifact` module, checked by `oxy fsck`), |
|
| 407 | - | named by its object hash like every object; its tree is a blob, and |
|
| 408 | - | `.oxy/artifacts/NAME` records the artifacts a repository keeps. Next: |
|
| 409 | - | runner images as artifacts, then moving them between repositories (C2). |
|
| 410 | 399 | - **C2. Channels, provenance and consensus.** Flow publishes artifacts; |
|
| 411 | 400 | signed channel move attestations; multi-party `reproduced(N)` consensus; |
|
| 412 | 401 | revset predicates. |
|
| … | 44 unchanged lines |
removed docs/mcp.md +0 −78
| 1 | - | # oxy mcp: Oxygen for AI agents |
|
| 2 | - | ||
| 3 | - | `oxy mcp` serves one repository to an AI agent over the |
|
| 4 | - | [Model Context Protocol](https://modelcontextprotocol.io) (MCP), on stdio |
|
| 5 | - | (oxygen#159). The agent calls typed tools (`status`, `log`, `commit`, …) |
|
| 6 | - | and gets JSON back, instead of running `oxy` in a shell and reading its |
|
| 7 | - | output. |
|
| 8 | - | ||
| 9 | - | ## Who changes are signed as |
|
| 10 | - | ||
| 11 | - | The server signs as whatever identity its environment configures, exactly |
|
| 12 | - | as `oxy` would: it runs each tool as this same `oxy` binary, in the |
|
| 13 | - | repository, with the server's environment. Start it from an agent home and |
|
| 14 | - | every change the agent makes is sealed **via the agent**, with no |
|
| 15 | - | `OXY_HOME` to remember on each command: |
|
| 16 | - | ||
| 17 | - | ```sh |
|
| 18 | - | OXY_HOME=~/.oxy-agents/claude oxy mcp ~/development/myproject |
|
| 19 | - | ``` |
|
| 20 | - | ||
| 21 | - | The server says who it signs as in its `initialize` reply (the first line |
|
| 22 | - | of `oxy identity show`), and the `identity` tool shows the rest. Without an |
|
| 23 | - | identity, reading works and committing is refused with oxy's own message. |
|
| 24 | - | ||
| 25 | - | ## Tools |
|
| 26 | - | ||
| 27 | - | Each tool returns the command's `--json` output as structured content (an |
|
| 28 | - | array comes wrapped as `{"result": […]}`) and as text. A failed command is a |
|
| 29 | - | tool result with `isError: true` and oxy's error, so the agent sees why. |
|
| 30 | - | ||
| 31 | - | | Tool | Runs | Arguments | |
|
| 32 | - | |---|---|---| |
|
| 33 | - | | `status` | `oxy status --json` | | |
|
| 34 | - | | `diff` | `oxy diff [CHANGE] --json` | `change` | |
|
| 35 | - | | `log` | `oxy log --json` | `revset`, `path`, `limit` (default 20, at most 1000) | |
|
| 36 | - | | `show` | `oxy show CHANGE --json` | `change` (default `@`), `stat` | |
|
| 37 | - | | `cat` | `oxy cat PATH [-r CHANGE]` | `path`, `change` | |
|
| 38 | - | | `blame` | `oxy blame PATH --json` | `path` | |
|
| 39 | - | | `bookmarks` | `oxy bookmark list --json` | `all` | |
|
| 40 | - | | `tags` | `oxy tag list --json` | | |
|
| 41 | - | | `conflicts` | `oxy resolve --json` (report only) | | |
|
| 42 | - | | `op_log` | `oxy op log --json` | `limit` | |
|
| 43 | - | | `identity` | `oxy identity show` | | |
|
| 44 | - | | `commit` | `oxy commit -m MESSAGE PATHS…` | `message`, and `paths` or `all: true` | |
|
| 45 | - | | `amend` | `oxy amend [-m] PATHS…` | `paths` or `all: true`, `message` | |
|
| 46 | - | | `describe` | `oxy describe [CHANGE] -m MESSAGE` | `message`, `change` | |
|
| 47 | - | | `fetch`, `pull` | `oxy fetch\|pull [REMOTE] --json` | `remote` | |
|
| 48 | - | | `push` | `oxy push [REMOTE] --json` | `remote`, `bookmark`, `force` | |
|
| 49 | - | | `tlog_verify` | `oxy tlog verify --json` | | |
|
| 50 | - | | `undo` | `oxy undo` | only with `--allow-destructive` | |
|
| 51 | - | ||
| 52 | - | ## Safety |
|
| 53 | - | ||
| 54 | - | - **Commits are deliberate.** `commit` and `amend` take the paths to |
|
| 55 | - | include, or `all: true`; never neither. |
|
| 56 | - | - **Nothing destructive by default.** `undo` is not offered, and `push` |
|
| 57 | - | refuses `force`, unless the server is started with `--allow-destructive`. |
|
| 58 | - | Tag withdrawal, bookmark deletion and history rewriting are not tools at |
|
| 59 | - | all. Each tool carries MCP's `readOnlyHint` and `destructiveHint`. |
|
| 60 | - | - **Values are never flags.** Arguments are passed as `--flag=value` and |
|
| 61 | - | after `--`, so a path or message starting with `-` stays a value. |
|
| 62 | - | - **Your policy still applies.** Pushes go through the remote's checks and |
|
| 63 | - | the repository's trust policy like any other; an agent's delegation |
|
| 64 | - | scope limits what its seals may do. |
|
| 65 | - | - **Output is bounded.** A tool's text stops at 256 KiB, saying to narrow |
|
| 66 | - | the request. |
|
| 67 | - | ||
| 68 | - | ## Adding it to an agent |
|
| 69 | - | ||
| 70 | - | Claude Code, for one project (run in the project's root): |
|
| 71 | - | ||
| 72 | - | ```sh |
|
| 73 | - | claude mcp add oxy -- env OXY_HOME=$HOME/.oxy-agents/claude oxy mcp |
|
| 74 | - | ``` |
|
| 75 | - | ||
| 76 | - | Any MCP client that starts stdio servers takes the same command: `oxy mcp |
|
| 77 | - | [DIR] [--allow-destructive]`, with `OXY_HOME` set for an agent's identity. |
|
| 78 | - | `DIR` defaults to the current directory and must be a repository's root. |
modified docs/spec.md +0 −5
| … | 1012 unchanged lines |
||
| 1013 | 1013 | - **Fetch and push against a Git remote.** `oxy git fetch URL` keeps a bare mirror under `.oxy/git/` for the remote, fetches the branch into it, and imports the commits the bookmark does not have yet, seeding the import with the commits already known: an imported commit maps to its change, and a commit this repository exported maps to the bookmark state it was made from (so a Git commit on top of exported work is based on everything that work contained, including changes Git never saw). The bookmark moves to the union of its heads and the new changes, like a pull; the working copy follows when it was clean. A fetched state whose previous state was itself a Git tree is remembered as equal to the fetched tip. `oxy git push URL` refuses until the remote's tip is known, exports the bookmark's later states as commits chained onto that tip, and pushes the branch, so the push is always a fast-forward. |
|
| 1014 | 1014 | - **Submodules.** A Git gitlink entry (mode `160000`) imports as a `subrepo` node with a Git pin (§7.8) and the matching `.gitmodules` entry becomes a `.oxymodules` entry with `branch` set to the submodule's configured branch when there is one. Export writes a Git pin back as a gitlink, keeps a tracked `.gitmodules` as is, and otherwise derives `.gitmodules` from `.oxymodules`; an Oxygen pin has no Git form and is omitted from the exported tree, which the export report counts. |
|
| 1015 | 1015 | - **Merges of opaque files.** When the union of a merge commit's parents holds several live blobs for a file or submodule, the merge's change replaces each of them with the commit's blob and is a resolution: Git's merge is the authority, unlike a working copy, where a candidate on disk is not yet a decision. |
|
| 1016 | - | - **A side-by-side `.git`.** `oxy git colocate` (config `git.colocate`) keeps a `.git` beside `.oxy` so editors' and other tools' Git features work on an Oxygen checkout: made with `git init` when missing, `/.oxy/` added to its `info/exclude`, the current bookmark exported into it (as `oxy git export` does) after every oxy command that leaves the bookmark somewhere new, HEAD on that branch and the index at its tree, so `git status` shows exactly the working copy's uncommitted work. It is one way: commits made with Git are not read back. oxy never takes a `.git` directory as content, and checkout refuses to write a path with a `.git` component at any depth or case (as Git does), so a change cannot plant hooks there. `oxy git colocate --off` stops the updates and leaves `.git` in place. |
|
| 1017 | - | - **Export by change graph.** For a server serving Git clients (a hub's Git view), `git_export_graph` exports every bookmark and tag from the changes alone, so the same changes give the same commits wherever it runs: each change is a commit whose tree is the state of the change and its dependency closure and whose parents are its dependencies' commits (a change that depends on nothing is a root), with the change's author, time, message and `Change-Id:`/`Oxy-Hash:` trailers; a bookmark with one head is a branch at its commit, with several a merge of their commits (the bookmark's state, at the newest head's time, `Oxy-Heads:`); tags likewise. Marks make it incremental; branches of deleted bookmarks are removed. |
|
| 1018 | 1016 | - **Round trip.** Import followed by export MUST reproduce every tree hash. Export followed by import MUST reproduce every ChangeId. `oxy git verify GIT_DIR` checks an import commit by commit: for each commit, the state formed by the changes imported for it and all its ancestors must materialize to exactly that commit's tree (content, executable bits, symlink targets, submodule pins; `.oxymodules` is allowed beside submodules). `--last N` rebuilds only the last N commits, following the others, to look again at where an import went wrong. |
|
| 1019 | 1017 | ||
| 1020 | 1018 | ## 24. Command-line interface |
|
| … | 26 unchanged lines |
||
| 1047 | 1045 | oxy doctor [--offline] [--json] check identity, config and remotes (§21.2) |
|
| 1048 | 1046 | oxy completions SHELL shell completion script oxy man [--dir DIR] man pages |
|
| 1049 | 1047 | oxy hunks oxy discard PATH.. | --hunks N,M |
|
| 1050 | - | oxy mcp [DIR] [--allow-destructive] serve the repository to an AI agent (MCP, stdio) |
|
| 1051 | 1048 | ``` |
|
| 1052 | 1049 | ||
| 1053 | 1050 | **Machine interface.** `status`, `log` (with `--path`), `show`, `diff`, `hunks`, `blame`, `resolve`, `op log`, `bookmark list`, `remote list`, `fetch`, `pull`, `push`, `submodule status`, `bisect status`, `verify`, `policy show`, `root` and `version` take `--json` and then print exactly one JSON document on stdout, with ids as hex strings and times in milliseconds since the epoch; errors go to stderr with a non-zero status. `commit --hunks N,M` and `discard --hunks N,M` take hunk numbers as `hunks` prints them. Editors and other tools MUST use these rather than reading `.oxy/`. |
|
| 1054 | - | ||
| 1055 | - | **Agents.** `oxy mcp` serves the repository to an AI agent over the Model Context Protocol on stdio (docs/mcp.md): each tool runs one of the commands above with `--json`, in the repository and with the server's environment, so it signs as the identity `OXY_HOME` configures (an agent home seals every change via the agent). `commit` and `amend` take explicit paths or `all: true`; `undo` and a forced push are offered only with `--allow-destructive`. |
|
| 1056 | 1051 | ||
| 1057 | 1052 | Change arguments accept a ChangeId prefix, a ChangeHash prefix (with `#`), a bookmark or tag name, and `@` for the working-copy change. Ambiguous prefixes are an error. |
|
| 1058 | 1053 | ||
| … | 141 unchanged lines |
removed packaging/haikuports/README.md +0 −40
| 1 | - | # oxy and oh on HaikuDepot |
|
| 2 | - | ||
| 3 | - | [haikuports](https://github.com/haikuports/haikuports) recipes for oxy |
|
| 4 | - | (`dev-vcs/oxy`) and OxygenHub's `oh` (`dev-vcs/oh`) are written by |
|
| 5 | - | `make-recipe.py` from a release's source tarball (oxygen#156, #157). |
|
| 6 | - | ||
| 7 | - | Each release's dist job attaches `NAME-VERSION-src.tar.gz`: the source as |
|
| 8 | - | released, reproducible (sorted, fixed times and owners, gzip without a |
|
| 9 | - | timestamp). oh's holds the oxygenhub tree with its subrepos inside, so it |
|
| 10 | - | builds alone. The recipe fetches it from the release's stable address, |
|
| 11 | - | `https://oxygenhub.io/andymccall/REPO/releases/download/vVERSION/NAME-VERSION-src.tar.gz`, |
|
| 12 | - | and every crates.io crate in its `Cargo.lock` as a source of its own with its |
|
| 13 | - | checksum, building offline as haikuports' other Rust recipes (ripgrep) do. |
|
| 14 | - | ||
| 15 | - | For a release (oxy shown; oh is the same with `oh` and `oxygenhub`): |
|
| 16 | - | ||
| 17 | - | ```sh |
|
| 18 | - | curl -LO https://oxygenhub.io/andymccall/oxygen/releases/download/vX.Y.Z/oxy-X.Y.Z-src.tar.gz |
|
| 19 | - | python3 packaging/haikuports/make-recipe.py oxy oxy-X.Y.Z-src.tar.gz X.Y.Z > oxy-X.Y.Z.recipe |
|
| 20 | - | ``` |
|
| 21 | - | ||
| 22 | - | Test it on Haiku R1/beta6 with haikuports checked out and `haikuporter` |
|
| 23 | - | installed: copy the recipe to `haikuports/dev-vcs/oxy/` and run |
|
| 24 | - | `haikuporter --no-source-packages -j1 -y oxy`. Submit it as a pull request |
|
| 25 | - | to haikuports (`oxy: new recipe`, then `oxy: bump to X.Y.Z`). |
|
| 26 | - | ||
| 27 | - | Haiku needs the system's zstd (`ZSTD_SYS_USE_PKG_CONFIG=1`: the bundled |
|
| 28 | - | zstd's hidden symbols break the link), which the recipe sets. oh's tests |
|
| 29 | - | pull in the hub, whose pipeline parser needs a newer Rust than HaikuPorts' |
|
| 30 | - | 1.94, so its recipe tests `hub-api` only. |
|
| 31 | - | ||
| 32 | - | ## Icons |
|
| 33 | - | ||
| 34 | - | HaikuDepot takes a package's icon from HaikuDepotServer, not from the |
|
| 35 | - | recipe. `icons/` holds them, written by `make-icons.py icons/` (the PNGs |
|
| 36 | - | rendered from the SVGs): Oxygen (`oxy`) is the mark on a pale tile, |
|
| 37 | - | OxygenHub (`oh`) the mark on the hub's dark tile, as the VS Code |
|
| 38 | - | extensions' icons are. Once the packages are listed on |
|
| 39 | - | depot.haiku-os.org, upload `NAME.hvif` with `NAME-16.png`, `-32` and `-64` |
|
| 40 | - | as each package's icon. |
removed packaging/haikuports/dev-vcs/oh/oh-0.9.16.recipe +0 −1472
| 1 | - | SUMMARY="The command line of OxygenHub, the forge for Oxygen repositories" |
|
| 2 | - | DESCRIPTION="oh talks to an OxygenHub (such as https://oxygenhub.io): issues, proposals \ |
|
| 3 | - | and their reviews, releases, Flow runs, their logs and reports, and checks, \ |
|
| 4 | - | from the terminal. It works alongside oxy, the Oxygen version control \ |
|
| 5 | - | client." |
|
| 6 | - | HOMEPAGE="https://oxygenhub.io/andymccall/oxygenhub" |
|
| 7 | - | COPYRIGHT="2026 Andy McCall" |
|
| 8 | - | LICENSE="MIT |
|
| 9 | - | Apache v2" |
|
| 10 | - | REVISION="1" |
|
| 11 | - | SOURCE_URI="$HOMEPAGE/releases/download/v$portVersion/oh-$portVersion-src.tar.gz" |
|
| 12 | - | CHECKSUM_SHA256="55770a8668647a44e57ed085315dc11bd97028d2a5c1a1640cd85af87b461200" |
|
| 13 | - | SOURCE_DIR="oxygenhub-$portVersion" |
|
| 14 | - | SOURCE_URI_2="https://static.crates.io/crates/adler2/adler2-2.0.1.crate" |
|
| 15 | - | CHECKSUM_SHA256_2="320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" |
|
| 16 | - | SOURCE_FILENAME_2="adler2-2.0.1.tar.gz" |
|
| 17 | - | SOURCE_URI_3="https://static.crates.io/crates/aho-corasick/aho-corasick-1.1.5.crate" |
|
| 18 | - | CHECKSUM_SHA256_3="c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" |
|
| 19 | - | SOURCE_FILENAME_3="aho-corasick-1.1.5.tar.gz" |
|
| 20 | - | SOURCE_URI_4="https://static.crates.io/crates/allocator-api2/allocator-api2-0.2.21.crate" |
|
| 21 | - | CHECKSUM_SHA256_4="683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" |
|
| 22 | - | SOURCE_FILENAME_4="allocator-api2-0.2.21.tar.gz" |
|
| 23 | - | SOURCE_URI_5="https://static.crates.io/crates/ammonia/ammonia-4.2.0.crate" |
|
| 24 | - | CHECKSUM_SHA256_5="3f7ed3ac4252be4d3e36fb589ed5659356842587b21a31596a9dc89d3b2f5e2a" |
|
| 25 | - | SOURCE_FILENAME_5="ammonia-4.2.0.tar.gz" |
|
| 26 | - | SOURCE_URI_6="https://static.crates.io/crates/android_system_properties/android_system_properties-0.1.6.crate" |
|
| 27 | - | CHECKSUM_SHA256_6="ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" |
|
| 28 | - | SOURCE_FILENAME_6="android_system_properties-0.1.6.tar.gz" |
|
| 29 | - | SOURCE_URI_7="https://static.crates.io/crates/anstream/anstream-1.0.0.crate" |
|
| 30 | - | CHECKSUM_SHA256_7="824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" |
|
| 31 | - | SOURCE_FILENAME_7="anstream-1.0.0.tar.gz" |
|
| 32 | - | SOURCE_URI_8="https://static.crates.io/crates/anstyle/anstyle-1.0.14.crate" |
|
| 33 | - | CHECKSUM_SHA256_8="940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" |
|
| 34 | - | SOURCE_FILENAME_8="anstyle-1.0.14.tar.gz" |
|
| 35 | - | SOURCE_URI_9="https://static.crates.io/crates/anstyle-parse/anstyle-parse-1.0.0.crate" |
|
| 36 | - | CHECKSUM_SHA256_9="52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" |
|
| 37 | - | SOURCE_FILENAME_9="anstyle-parse-1.0.0.tar.gz" |
|
| 38 | - | SOURCE_URI_10="https://static.crates.io/crates/anstyle-query/anstyle-query-1.1.5.crate" |
|
| 39 | - | CHECKSUM_SHA256_10="40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" |
|
| 40 | - | SOURCE_FILENAME_10="anstyle-query-1.1.5.tar.gz" |
|
| 41 | - | SOURCE_URI_11="https://static.crates.io/crates/anstyle-wincon/anstyle-wincon-3.0.11.crate" |
|
| 42 | - | CHECKSUM_SHA256_11="291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" |
|
| 43 | - | SOURCE_FILENAME_11="anstyle-wincon-3.0.11.tar.gz" |
|
| 44 | - | SOURCE_URI_12="https://static.crates.io/crates/anyhow/anyhow-1.0.104.crate" |
|
| 45 | - | CHECKSUM_SHA256_12="330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" |
|
| 46 | - | SOURCE_FILENAME_12="anyhow-1.0.104.tar.gz" |
|
| 47 | - | SOURCE_URI_13="https://static.crates.io/crates/arbitrary/arbitrary-1.4.2.crate" |
|
| 48 | - | CHECKSUM_SHA256_13="c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1" |
|
| 49 | - | SOURCE_FILENAME_13="arbitrary-1.4.2.tar.gz" |
|
| 50 | - | SOURCE_URI_14="https://static.crates.io/crates/arc-swap/arc-swap-1.9.2.crate" |
|
| 51 | - | CHECKSUM_SHA256_14="c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" |
|
| 52 | - | SOURCE_FILENAME_14="arc-swap-1.9.2.tar.gz" |
|
| 53 | - | SOURCE_URI_15="https://static.crates.io/crates/argon2/argon2-0.5.3.crate" |
|
| 54 | - | CHECKSUM_SHA256_15="3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" |
|
| 55 | - | SOURCE_FILENAME_15="argon2-0.5.3.tar.gz" |
|
| 56 | - | SOURCE_URI_16="https://static.crates.io/crates/arrayvec/arrayvec-0.7.8.crate" |
|
| 57 | - | CHECKSUM_SHA256_16="d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" |
|
| 58 | - | SOURCE_FILENAME_16="arrayvec-0.7.8.tar.gz" |
|
| 59 | - | SOURCE_URI_17="https://static.crates.io/crates/askama/askama-0.14.0.crate" |
|
| 60 | - | CHECKSUM_SHA256_17="f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4" |
|
| 61 | - | SOURCE_FILENAME_17="askama-0.14.0.tar.gz" |
|
| 62 | - | SOURCE_URI_18="https://static.crates.io/crates/askama_derive/askama_derive-0.14.0.crate" |
|
| 63 | - | CHECKSUM_SHA256_18="129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f" |
|
| 64 | - | SOURCE_FILENAME_18="askama_derive-0.14.0.tar.gz" |
|
| 65 | - | SOURCE_URI_19="https://static.crates.io/crates/askama_parser/askama_parser-0.14.0.crate" |
|
| 66 | - | CHECKSUM_SHA256_19="d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358" |
|
| 67 | - | SOURCE_FILENAME_19="askama_parser-0.14.0.tar.gz" |
|
| 68 | - | SOURCE_URI_20="https://static.crates.io/crates/asn1-rs/asn1-rs-0.7.2.crate" |
|
| 69 | - | CHECKSUM_SHA256_20="b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" |
|
| 70 | - | SOURCE_FILENAME_20="asn1-rs-0.7.2.tar.gz" |
|
| 71 | - | SOURCE_URI_21="https://static.crates.io/crates/asn1-rs-derive/asn1-rs-derive-0.6.0.crate" |
|
| 72 | - | CHECKSUM_SHA256_21="3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" |
|
| 73 | - | SOURCE_FILENAME_21="asn1-rs-derive-0.6.0.tar.gz" |
|
| 74 | - | SOURCE_URI_22="https://static.crates.io/crates/asn1-rs-impl/asn1-rs-impl-0.2.0.crate" |
|
| 75 | - | CHECKSUM_SHA256_22="7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" |
|
| 76 | - | SOURCE_FILENAME_22="asn1-rs-impl-0.2.0.tar.gz" |
|
| 77 | - | SOURCE_URI_23="https://static.crates.io/crates/async-compression/async-compression-0.4.48.crate" |
|
| 78 | - | CHECKSUM_SHA256_23="fb61aea1a7def73ee7c350a184f0e70b32c182344e2e75bf70c9b621b83417fd" |
|
| 79 | - | SOURCE_FILENAME_23="async-compression-0.4.48.tar.gz" |
|
| 80 | - | SOURCE_URI_24="https://static.crates.io/crates/async-trait/async-trait-0.1.92.crate" |
|
| 81 | - | CHECKSUM_SHA256_24="82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" |
|
| 82 | - | SOURCE_FILENAME_24="async-trait-0.1.92.tar.gz" |
|
| 83 | - | SOURCE_URI_25="https://static.crates.io/crates/atoi/atoi-2.0.0.crate" |
|
| 84 | - | CHECKSUM_SHA256_25="f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528" |
|
| 85 | - | SOURCE_FILENAME_25="atoi-2.0.0.tar.gz" |
|
| 86 | - | SOURCE_URI_26="https://static.crates.io/crates/atomic-waker/atomic-waker-1.1.2.crate" |
|
| 87 | - | CHECKSUM_SHA256_26="1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" |
|
| 88 | - | SOURCE_FILENAME_26="atomic-waker-1.1.2.tar.gz" |
|
| 89 | - | SOURCE_URI_27="https://static.crates.io/crates/autocfg/autocfg-1.5.1.crate" |
|
| 90 | - | CHECKSUM_SHA256_27="f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" |
|
| 91 | - | SOURCE_FILENAME_27="autocfg-1.5.1.tar.gz" |
|
| 92 | - | SOURCE_URI_28="https://static.crates.io/crates/axum/axum-0.8.9.crate" |
|
| 93 | - | CHECKSUM_SHA256_28="31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" |
|
| 94 | - | SOURCE_FILENAME_28="axum-0.8.9.tar.gz" |
|
| 95 | - | SOURCE_URI_29="https://static.crates.io/crates/axum-core/axum-core-0.5.6.crate" |
|
| 96 | - | CHECKSUM_SHA256_29="08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" |
|
| 97 | - | SOURCE_FILENAME_29="axum-core-0.5.6.tar.gz" |
|
| 98 | - | SOURCE_URI_30="https://static.crates.io/crates/axum-extra/axum-extra-0.10.3.crate" |
|
| 99 | - | CHECKSUM_SHA256_30="9963ff19f40c6102c76756ef0a46004c0d58957d87259fc9208ff8441c12ab96" |
|
| 100 | - | SOURCE_FILENAME_30="axum-extra-0.10.3.tar.gz" |
|
| 101 | - | SOURCE_URI_31="https://static.crates.io/crates/axum-macros/axum-macros-0.5.1.crate" |
|
| 102 | - | CHECKSUM_SHA256_31="7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" |
|
| 103 | - | SOURCE_FILENAME_31="axum-macros-0.5.1.tar.gz" |
|
| 104 | - | SOURCE_URI_32="https://static.crates.io/crates/axum-server/axum-server-0.8.0.crate" |
|
| 105 | - | CHECKSUM_SHA256_32="b1df331683d982a0b9492b38127151e6453639cd34926eb9c07d4cd8c6d22bfc" |
|
| 106 | - | SOURCE_FILENAME_32="axum-server-0.8.0.tar.gz" |
|
| 107 | - | SOURCE_URI_33="https://static.crates.io/crates/base32/base32-0.5.1.crate" |
|
| 108 | - | CHECKSUM_SHA256_33="022dfe9eb35f19ebbcb51e0b40a5ab759f46ad60cadf7297e0bd085afb50e076" |
|
| 109 | - | SOURCE_FILENAME_33="base32-0.5.1.tar.gz" |
|
| 110 | - | SOURCE_URI_34="https://static.crates.io/crates/base64/base64-0.22.1.crate" |
|
| 111 | - | CHECKSUM_SHA256_34="72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" |
|
| 112 | - | SOURCE_FILENAME_34="base64-0.22.1.tar.gz" |
|
| 113 | - | SOURCE_URI_35="https://static.crates.io/crates/base64/base64-0.23.1.crate" |
|
| 114 | - | CHECKSUM_SHA256_35="ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" |
|
| 115 | - | SOURCE_FILENAME_35="base64-0.23.1.tar.gz" |
|
| 116 | - | SOURCE_URI_36="https://static.crates.io/crates/base64ct/base64ct-1.8.3.crate" |
|
| 117 | - | CHECKSUM_SHA256_36="2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" |
|
| 118 | - | SOURCE_FILENAME_36="base64ct-1.8.3.tar.gz" |
|
| 119 | - | SOURCE_URI_37="https://static.crates.io/crates/basic-toml/basic-toml-0.1.10.crate" |
|
| 120 | - | CHECKSUM_SHA256_37="ba62675e8242a4c4e806d12f11d136e626e6c8361d6b829310732241652a178a" |
|
| 121 | - | SOURCE_FILENAME_37="basic-toml-0.1.10.tar.gz" |
|
| 122 | - | SOURCE_URI_38="https://static.crates.io/crates/bincode/bincode-1.3.3.crate" |
|
| 123 | - | CHECKSUM_SHA256_38="b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" |
|
| 124 | - | SOURCE_FILENAME_38="bincode-1.3.3.tar.gz" |
|
| 125 | - | SOURCE_URI_39="https://static.crates.io/crates/bit-set/bit-set-0.8.0.crate" |
|
| 126 | - | CHECKSUM_SHA256_39="08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" |
|
| 127 | - | SOURCE_FILENAME_39="bit-set-0.8.0.tar.gz" |
|
| 128 | - | SOURCE_URI_40="https://static.crates.io/crates/bit-vec/bit-vec-0.8.0.crate" |
|
| 129 | - | CHECKSUM_SHA256_40="5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" |
|
| 130 | - | SOURCE_FILENAME_40="bit-vec-0.8.0.tar.gz" |
|
| 131 | - | SOURCE_URI_41="https://static.crates.io/crates/bit-vec/bit-vec-0.9.1.crate" |
|
| 132 | - | CHECKSUM_SHA256_41="b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" |
|
| 133 | - | SOURCE_FILENAME_41="bit-vec-0.9.1.tar.gz" |
|
| 134 | - | SOURCE_URI_42="https://static.crates.io/crates/bitflags/bitflags-2.13.2.crate" |
|
| 135 | - | CHECKSUM_SHA256_42="3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" |
|
| 136 | - | SOURCE_FILENAME_42="bitflags-2.13.2.tar.gz" |
|
| 137 | - | SOURCE_URI_43="https://static.crates.io/crates/blake2/blake2-0.10.6.crate" |
|
| 138 | - | CHECKSUM_SHA256_43="46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" |
|
| 139 | - | SOURCE_FILENAME_43="blake2-0.10.6.tar.gz" |
|
| 140 | - | SOURCE_URI_44="https://static.crates.io/crates/blake3/blake3-1.8.7.crate" |
|
| 141 | - | CHECKSUM_SHA256_44="6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" |
|
| 142 | - | SOURCE_FILENAME_44="blake3-1.8.7.tar.gz" |
|
| 143 | - | SOURCE_URI_45="https://static.crates.io/crates/block-buffer/block-buffer-0.10.4.crate" |
|
| 144 | - | CHECKSUM_SHA256_45="3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" |
|
| 145 | - | SOURCE_FILENAME_45="block-buffer-0.10.4.tar.gz" |
|
| 146 | - | SOURCE_URI_46="https://static.crates.io/crates/block-buffer/block-buffer-0.12.1.crate" |
|
| 147 | - | CHECKSUM_SHA256_46="d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" |
|
| 148 | - | SOURCE_FILENAME_46="block-buffer-0.12.1.tar.gz" |
|
| 149 | - | SOURCE_URI_47="https://static.crates.io/crates/bstr/bstr-1.13.1.crate" |
|
| 150 | - | CHECKSUM_SHA256_47="6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" |
|
| 151 | - | SOURCE_FILENAME_47="bstr-1.13.1.tar.gz" |
|
| 152 | - | SOURCE_URI_48="https://static.crates.io/crates/bumpalo/bumpalo-3.20.3.crate" |
|
| 153 | - | CHECKSUM_SHA256_48="72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" |
|
| 154 | - | SOURCE_FILENAME_48="bumpalo-3.20.3.tar.gz" |
|
| 155 | - | SOURCE_URI_49="https://static.crates.io/crates/bytemuck/bytemuck-1.25.2.crate" |
|
| 156 | - | CHECKSUM_SHA256_49="95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" |
|
| 157 | - | SOURCE_FILENAME_49="bytemuck-1.25.2.tar.gz" |
|
| 158 | - | SOURCE_URI_50="https://static.crates.io/crates/byteorder/byteorder-1.5.0.crate" |
|
| 159 | - | CHECKSUM_SHA256_50="1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" |
|
| 160 | - | SOURCE_FILENAME_50="byteorder-1.5.0.tar.gz" |
|
| 161 | - | SOURCE_URI_51="https://static.crates.io/crates/byteorder-lite/byteorder-lite-0.1.0.crate" |
|
| 162 | - | CHECKSUM_SHA256_51="8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" |
|
| 163 | - | SOURCE_FILENAME_51="byteorder-lite-0.1.0.tar.gz" |
|
| 164 | - | SOURCE_URI_52="https://static.crates.io/crates/bytes/bytes-1.12.1.crate" |
|
| 165 | - | CHECKSUM_SHA256_52="fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" |
|
| 166 | - | SOURCE_FILENAME_52="bytes-1.12.1.tar.gz" |
|
| 167 | - | SOURCE_URI_53="https://static.crates.io/crates/cc/cc-1.5.1.crate" |
|
| 168 | - | CHECKSUM_SHA256_53="f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040" |
|
| 169 | - | SOURCE_FILENAME_53="cc-1.5.1.tar.gz" |
|
| 170 | - | SOURCE_URI_54="https://static.crates.io/crates/cfg-if/cfg-if-1.0.5.crate" |
|
| 171 | - | CHECKSUM_SHA256_54="4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" |
|
| 172 | - | SOURCE_FILENAME_54="cfg-if-1.0.5.tar.gz" |
|
| 173 | - | SOURCE_URI_55="https://static.crates.io/crates/cfg_aliases/cfg_aliases-0.2.2.crate" |
|
| 174 | - | CHECKSUM_SHA256_55="f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" |
|
| 175 | - | SOURCE_FILENAME_55="cfg_aliases-0.2.2.tar.gz" |
|
| 176 | - | SOURCE_URI_56="https://static.crates.io/crates/chacha20/chacha20-0.10.2.crate" |
|
| 177 | - | CHECKSUM_SHA256_56="65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" |
|
| 178 | - | SOURCE_FILENAME_56="chacha20-0.10.2.tar.gz" |
|
| 179 | - | SOURCE_URI_57="https://static.crates.io/crates/chrono/chrono-0.4.45.crate" |
|
| 180 | - | CHECKSUM_SHA256_57="1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" |
|
| 181 | - | SOURCE_FILENAME_57="chrono-0.4.45.tar.gz" |
|
| 182 | - | SOURCE_URI_58="https://static.crates.io/crates/clap/clap-4.6.7.crate" |
|
| 183 | - | CHECKSUM_SHA256_58="aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" |
|
| 184 | - | SOURCE_FILENAME_58="clap-4.6.7.tar.gz" |
|
| 185 | - | SOURCE_URI_59="https://static.crates.io/crates/clap_builder/clap_builder-4.6.7.crate" |
|
| 186 | - | CHECKSUM_SHA256_59="ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" |
|
| 187 | - | SOURCE_FILENAME_59="clap_builder-4.6.7.tar.gz" |
|
| 188 | - | SOURCE_URI_60="https://static.crates.io/crates/clap_derive/clap_derive-4.6.7.crate" |
|
| 189 | - | CHECKSUM_SHA256_60="f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" |
|
| 190 | - | SOURCE_FILENAME_60="clap_derive-4.6.7.tar.gz" |
|
| 191 | - | SOURCE_URI_61="https://static.crates.io/crates/clap_lex/clap_lex-1.1.1.crate" |
|
| 192 | - | CHECKSUM_SHA256_61="1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" |
|
| 193 | - | SOURCE_FILENAME_61="clap_lex-1.1.1.tar.gz" |
|
| 194 | - | SOURCE_URI_62="https://static.crates.io/crates/cmov/cmov-0.5.4.crate" |
|
| 195 | - | CHECKSUM_SHA256_62="0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" |
|
| 196 | - | SOURCE_FILENAME_62="cmov-0.5.4.tar.gz" |
|
| 197 | - | SOURCE_URI_63="https://static.crates.io/crates/colorchoice/colorchoice-1.0.5.crate" |
|
| 198 | - | CHECKSUM_SHA256_63="1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" |
|
| 199 | - | SOURCE_FILENAME_63="colorchoice-1.0.5.tar.gz" |
|
| 200 | - | SOURCE_URI_64="https://static.crates.io/crates/compression-codecs/compression-codecs-0.4.43.crate" |
|
| 201 | - | CHECKSUM_SHA256_64="bef16c47ba2797aa6a909cc37d39911f3a6743811fe7408ac0b0cc0276b656e9" |
|
| 202 | - | SOURCE_FILENAME_64="compression-codecs-0.4.43.tar.gz" |
|
| 203 | - | SOURCE_URI_65="https://static.crates.io/crates/compression-core/compression-core-0.4.33.crate" |
|
| 204 | - | CHECKSUM_SHA256_65="6e8ccc4ea9f6acc32d102c0f6d471d11d913ad15f20c04de743374861fa1d414" |
|
| 205 | - | SOURCE_FILENAME_65="compression-core-0.4.33.tar.gz" |
|
| 206 | - | SOURCE_URI_66="https://static.crates.io/crates/const-oid/const-oid-0.10.2.crate" |
|
| 207 | - | CHECKSUM_SHA256_66="a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" |
|
| 208 | - | SOURCE_FILENAME_66="const-oid-0.10.2.tar.gz" |
|
| 209 | - | SOURCE_URI_67="https://static.crates.io/crates/const-oid/const-oid-0.9.6.crate" |
|
| 210 | - | CHECKSUM_SHA256_67="c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" |
|
| 211 | - | SOURCE_FILENAME_67="const-oid-0.9.6.tar.gz" |
|
| 212 | - | SOURCE_URI_68="https://static.crates.io/crates/constant_time_eq/constant_time_eq-0.4.2.crate" |
|
| 213 | - | CHECKSUM_SHA256_68="3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" |
|
| 214 | - | SOURCE_FILENAME_68="constant_time_eq-0.4.2.tar.gz" |
|
| 215 | - | SOURCE_URI_69="https://static.crates.io/crates/cookie/cookie-0.18.2.crate" |
|
| 216 | - | CHECKSUM_SHA256_69="1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" |
|
| 217 | - | SOURCE_FILENAME_69="cookie-0.18.2.tar.gz" |
|
| 218 | - | SOURCE_URI_70="https://static.crates.io/crates/core_detect/core_detect-1.0.0.crate" |
|
| 219 | - | CHECKSUM_SHA256_70="7f8f80099a98041a3d1622845c271458a2d73e688351bf3cb999266764b81d48" |
|
| 220 | - | SOURCE_FILENAME_70="core_detect-1.0.0.tar.gz" |
|
| 221 | - | SOURCE_URI_71="https://static.crates.io/crates/cpufeatures/cpufeatures-0.2.17.crate" |
|
| 222 | - | CHECKSUM_SHA256_71="59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" |
|
| 223 | - | SOURCE_FILENAME_71="cpufeatures-0.2.17.tar.gz" |
|
| 224 | - | SOURCE_URI_72="https://static.crates.io/crates/cpufeatures/cpufeatures-0.3.1.crate" |
|
| 225 | - | CHECKSUM_SHA256_72="5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" |
|
| 226 | - | SOURCE_FILENAME_72="cpufeatures-0.3.1.tar.gz" |
|
| 227 | - | SOURCE_URI_73="https://static.crates.io/crates/crc/crc-3.4.0.crate" |
|
| 228 | - | CHECKSUM_SHA256_73="5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" |
|
| 229 | - | SOURCE_FILENAME_73="crc-3.4.0.tar.gz" |
|
| 230 | - | SOURCE_URI_74="https://static.crates.io/crates/crc-catalog/crc-catalog-2.5.0.crate" |
|
| 231 | - | CHECKSUM_SHA256_74="217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" |
|
| 232 | - | SOURCE_FILENAME_74="crc-catalog-2.5.0.tar.gz" |
|
| 233 | - | SOURCE_URI_75="https://static.crates.io/crates/crc32fast/crc32fast-1.5.2.crate" |
|
| 234 | - | CHECKSUM_SHA256_75="01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" |
|
| 235 | - | SOURCE_FILENAME_75="crc32fast-1.5.2.tar.gz" |
|
| 236 | - | SOURCE_URI_76="https://static.crates.io/crates/crossbeam-deque/crossbeam-deque-0.8.8.crate" |
|
| 237 | - | CHECKSUM_SHA256_76="622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" |
|
| 238 | - | SOURCE_FILENAME_76="crossbeam-deque-0.8.8.tar.gz" |
|
| 239 | - | SOURCE_URI_77="https://static.crates.io/crates/crossbeam-epoch/crossbeam-epoch-0.9.21.crate" |
|
| 240 | - | CHECKSUM_SHA256_77="dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" |
|
| 241 | - | SOURCE_FILENAME_77="crossbeam-epoch-0.9.21.tar.gz" |
|
| 242 | - | SOURCE_URI_78="https://static.crates.io/crates/crossbeam-queue/crossbeam-queue-0.3.14.crate" |
|
| 243 | - | CHECKSUM_SHA256_78="03e8bd762f7479489c70ed6c768ddca99d7296857de437a68dcb2a94365b3fae" |
|
| 244 | - | SOURCE_FILENAME_78="crossbeam-queue-0.3.14.tar.gz" |
|
| 245 | - | SOURCE_URI_79="https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.23.crate" |
|
| 246 | - | CHECKSUM_SHA256_79="a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" |
|
| 247 | - | SOURCE_FILENAME_79="crossbeam-utils-0.8.23.tar.gz" |
|
| 248 | - | SOURCE_URI_80="https://static.crates.io/crates/crypto-common/crypto-common-0.1.7.crate" |
|
| 249 | - | CHECKSUM_SHA256_80="78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" |
|
| 250 | - | SOURCE_FILENAME_80="crypto-common-0.1.7.tar.gz" |
|
| 251 | - | SOURCE_URI_81="https://static.crates.io/crates/crypto-common/crypto-common-0.2.2.crate" |
|
| 252 | - | CHECKSUM_SHA256_81="ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" |
|
| 253 | - | SOURCE_FILENAME_81="crypto-common-0.2.2.tar.gz" |
|
| 254 | - | SOURCE_URI_82="https://static.crates.io/crates/cssparser/cssparser-0.38.0.crate" |
|
| 255 | - | CHECKSUM_SHA256_82="11119743ad110e8c1bdccd930d7f5c30c99e5fc76a7b63ec9807e84eef0c5f59" |
|
| 256 | - | SOURCE_FILENAME_82="cssparser-0.38.0.tar.gz" |
|
| 257 | - | SOURCE_URI_83="https://static.crates.io/crates/ctutils/ctutils-0.4.2.crate" |
|
| 258 | - | CHECKSUM_SHA256_83="7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" |
|
| 259 | - | SOURCE_FILENAME_83="ctutils-0.4.2.tar.gz" |
|
| 260 | - | SOURCE_URI_84="https://static.crates.io/crates/curve25519-dalek/curve25519-dalek-5.0.0.crate" |
|
| 261 | - | CHECKSUM_SHA256_84="b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" |
|
| 262 | - | SOURCE_FILENAME_84="curve25519-dalek-5.0.0.tar.gz" |
|
| 263 | - | SOURCE_URI_85="https://static.crates.io/crates/curve25519-dalek-derive/curve25519-dalek-derive-0.1.1.crate" |
|
| 264 | - | CHECKSUM_SHA256_85="f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" |
|
| 265 | - | SOURCE_FILENAME_85="curve25519-dalek-derive-0.1.1.tar.gz" |
|
| 266 | - | SOURCE_URI_86="https://static.crates.io/crates/data-encoding/data-encoding-2.11.1.crate" |
|
| 267 | - | CHECKSUM_SHA256_86="4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" |
|
| 268 | - | SOURCE_FILENAME_86="data-encoding-2.11.1.tar.gz" |
|
| 269 | - | SOURCE_URI_87="https://static.crates.io/crates/der/der-0.7.10.crate" |
|
| 270 | - | CHECKSUM_SHA256_87="e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" |
|
| 271 | - | SOURCE_FILENAME_87="der-0.7.10.tar.gz" |
|
| 272 | - | SOURCE_URI_88="https://static.crates.io/crates/der/der-0.8.2.crate" |
|
| 273 | - | CHECKSUM_SHA256_88="a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a" |
|
| 274 | - | SOURCE_FILENAME_88="der-0.8.2.tar.gz" |
|
| 275 | - | SOURCE_URI_89="https://static.crates.io/crates/der-parser/der-parser-10.0.0.crate" |
|
| 276 | - | CHECKSUM_SHA256_89="07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" |
|
| 277 | - | SOURCE_FILENAME_89="der-parser-10.0.0.tar.gz" |
|
| 278 | - | SOURCE_URI_90="https://static.crates.io/crates/deranged/deranged-0.5.8.crate" |
|
| 279 | - | CHECKSUM_SHA256_90="7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" |
|
| 280 | - | SOURCE_FILENAME_90="deranged-0.5.8.tar.gz" |
|
| 281 | - | SOURCE_URI_91="https://static.crates.io/crates/derive_arbitrary/derive_arbitrary-1.4.2.crate" |
|
| 282 | - | CHECKSUM_SHA256_91="1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" |
|
| 283 | - | SOURCE_FILENAME_91="derive_arbitrary-1.4.2.tar.gz" |
|
| 284 | - | SOURCE_URI_92="https://static.crates.io/crates/digest/digest-0.10.7.crate" |
|
| 285 | - | CHECKSUM_SHA256_92="9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" |
|
| 286 | - | SOURCE_FILENAME_92="digest-0.10.7.tar.gz" |
|
| 287 | - | SOURCE_URI_93="https://static.crates.io/crates/digest/digest-0.11.3.crate" |
|
| 288 | - | CHECKSUM_SHA256_93="f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" |
|
| 289 | - | SOURCE_FILENAME_93="digest-0.11.3.tar.gz" |
|
| 290 | - | SOURCE_URI_94="https://static.crates.io/crates/displaydoc/displaydoc-0.2.7.crate" |
|
| 291 | - | CHECKSUM_SHA256_94="c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" |
|
| 292 | - | SOURCE_FILENAME_94="displaydoc-0.2.7.tar.gz" |
|
| 293 | - | SOURCE_URI_95="https://static.crates.io/crates/dotenvy/dotenvy-0.15.7.crate" |
|
| 294 | - | CHECKSUM_SHA256_95="1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" |
|
| 295 | - | SOURCE_FILENAME_95="dotenvy-0.15.7.tar.gz" |
|
| 296 | - | SOURCE_URI_96="https://static.crates.io/crates/dtoa/dtoa-1.0.11.crate" |
|
| 297 | - | CHECKSUM_SHA256_96="4c3cf4824e2d5f025c7b531afcb2325364084a16806f6d47fbc1f5fbd9960590" |
|
| 298 | - | SOURCE_FILENAME_96="dtoa-1.0.11.tar.gz" |
|
| 299 | - | SOURCE_URI_97="https://static.crates.io/crates/dtoa-short/dtoa-short-0.3.5.crate" |
|
| 300 | - | CHECKSUM_SHA256_97="cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" |
|
| 301 | - | SOURCE_FILENAME_97="dtoa-short-0.3.5.tar.gz" |
|
| 302 | - | SOURCE_URI_98="https://static.crates.io/crates/dyn-clone/dyn-clone-1.0.20.crate" |
|
| 303 | - | CHECKSUM_SHA256_98="d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" |
|
| 304 | - | SOURCE_FILENAME_98="dyn-clone-1.0.20.tar.gz" |
|
| 305 | - | SOURCE_URI_99="https://static.crates.io/crates/ed25519/ed25519-3.0.0.crate" |
|
| 306 | - | CHECKSUM_SHA256_99="29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" |
|
| 307 | - | SOURCE_FILENAME_99="ed25519-3.0.0.tar.gz" |
|
| 308 | - | SOURCE_URI_100="https://static.crates.io/crates/ed25519-dalek/ed25519-dalek-3.0.0.crate" |
|
| 309 | - | CHECKSUM_SHA256_100="6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" |
|
| 310 | - | SOURCE_FILENAME_100="ed25519-dalek-3.0.0.tar.gz" |
|
| 311 | - | SOURCE_URI_101="https://static.crates.io/crates/either/either-1.18.0.crate" |
|
| 312 | - | CHECKSUM_SHA256_101="252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" |
|
| 313 | - | SOURCE_FILENAME_101="either-1.18.0.tar.gz" |
|
| 314 | - | SOURCE_URI_102="https://static.crates.io/crates/email-encoding/email-encoding-0.4.2.crate" |
|
| 315 | - | CHECKSUM_SHA256_102="420b9da095f052ea597503e39073b5b3c522f7db933fbac202d91d24492693fd" |
|
| 316 | - | SOURCE_FILENAME_102="email-encoding-0.4.2.tar.gz" |
|
| 317 | - | SOURCE_URI_103="https://static.crates.io/crates/email_address/email_address-0.2.9.crate" |
|
| 318 | - | CHECKSUM_SHA256_103="e079f19b08ca6239f47f8ba8509c11cf3ea30095831f7fed61441475edd8c449" |
|
| 319 | - | SOURCE_FILENAME_103="email_address-0.2.9.tar.gz" |
|
| 320 | - | SOURCE_URI_104="https://static.crates.io/crates/encoding_rs/encoding_rs-0.8.41.crate" |
|
| 321 | - | CHECKSUM_SHA256_104="7b5ef0006ac9ab233c38522f5ae99cae3625151de8f706cacee1cba4b8e2832a" |
|
| 322 | - | SOURCE_FILENAME_104="encoding_rs-0.8.41.tar.gz" |
|
| 323 | - | SOURCE_URI_105="https://static.crates.io/crates/equivalent/equivalent-1.0.2.crate" |
|
| 324 | - | CHECKSUM_SHA256_105="877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" |
|
| 325 | - | SOURCE_FILENAME_105="equivalent-1.0.2.tar.gz" |
|
| 326 | - | SOURCE_URI_106="https://static.crates.io/crates/errno/errno-0.3.14.crate" |
|
| 327 | - | CHECKSUM_SHA256_106="39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" |
|
| 328 | - | SOURCE_FILENAME_106="errno-0.3.14.tar.gz" |
|
| 329 | - | SOURCE_URI_107="https://static.crates.io/crates/etcetera/etcetera-0.8.0.crate" |
|
| 330 | - | CHECKSUM_SHA256_107="136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943" |
|
| 331 | - | SOURCE_FILENAME_107="etcetera-0.8.0.tar.gz" |
|
| 332 | - | SOURCE_URI_108="https://static.crates.io/crates/event-listener/event-listener-5.4.2.crate" |
|
| 333 | - | CHECKSUM_SHA256_108="5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2" |
|
| 334 | - | SOURCE_FILENAME_108="event-listener-5.4.2.tar.gz" |
|
| 335 | - | SOURCE_URI_109="https://static.crates.io/crates/fancy-regex/fancy-regex-0.16.2.crate" |
|
| 336 | - | CHECKSUM_SHA256_109="998b056554fbe42e03ae0e152895cd1a7e1002aec800fdc6635d20270260c46f" |
|
| 337 | - | SOURCE_FILENAME_109="fancy-regex-0.16.2.tar.gz" |
|
| 338 | - | SOURCE_URI_110="https://static.crates.io/crates/fastrand/fastrand-2.5.0.crate" |
|
| 339 | - | CHECKSUM_SHA256_110="da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" |
|
| 340 | - | SOURCE_FILENAME_110="fastrand-2.5.0.tar.gz" |
|
| 341 | - | SOURCE_URI_111="https://static.crates.io/crates/fdeflate/fdeflate-0.3.7.crate" |
|
| 342 | - | CHECKSUM_SHA256_111="1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" |
|
| 343 | - | SOURCE_FILENAME_111="fdeflate-0.3.7.tar.gz" |
|
| 344 | - | SOURCE_URI_112="https://static.crates.io/crates/fiat-crypto/fiat-crypto-0.3.0.crate" |
|
| 345 | - | CHECKSUM_SHA256_112="64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" |
|
| 346 | - | SOURCE_FILENAME_112="fiat-crypto-0.3.0.tar.gz" |
|
| 347 | - | SOURCE_URI_113="https://static.crates.io/crates/filetime/filetime-0.2.29.crate" |
|
| 348 | - | CHECKSUM_SHA256_113="5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" |
|
| 349 | - | SOURCE_FILENAME_113="filetime-0.2.29.tar.gz" |
|
| 350 | - | SOURCE_URI_114="https://static.crates.io/crates/find-msvc-tools/find-msvc-tools-0.1.14.crate" |
|
| 351 | - | CHECKSUM_SHA256_114="aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" |
|
| 352 | - | SOURCE_FILENAME_114="find-msvc-tools-0.1.14.tar.gz" |
|
| 353 | - | SOURCE_URI_115="https://static.crates.io/crates/flate2/flate2-1.1.10.crate" |
|
| 354 | - | CHECKSUM_SHA256_115="6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" |
|
| 355 | - | SOURCE_FILENAME_115="flate2-1.1.10.tar.gz" |
|
| 356 | - | SOURCE_URI_116="https://static.crates.io/crates/flume/flume-0.11.1.crate" |
|
| 357 | - | CHECKSUM_SHA256_116="da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095" |
|
| 358 | - | SOURCE_FILENAME_116="flume-0.11.1.tar.gz" |
|
| 359 | - | SOURCE_URI_117="https://static.crates.io/crates/fnv/fnv-1.0.7.crate" |
|
| 360 | - | CHECKSUM_SHA256_117="3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" |
|
| 361 | - | SOURCE_FILENAME_117="fnv-1.0.7.tar.gz" |
|
| 362 | - | SOURCE_URI_118="https://static.crates.io/crates/foldhash/foldhash-0.1.5.crate" |
|
| 363 | - | CHECKSUM_SHA256_118="d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" |
|
| 364 | - | SOURCE_FILENAME_118="foldhash-0.1.5.tar.gz" |
|
| 365 | - | SOURCE_URI_119="https://static.crates.io/crates/form_urlencoded/form_urlencoded-1.2.2.crate" |
|
| 366 | - | CHECKSUM_SHA256_119="cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" |
|
| 367 | - | SOURCE_FILENAME_119="form_urlencoded-1.2.2.tar.gz" |
|
| 368 | - | SOURCE_URI_120="https://static.crates.io/crates/fs-err/fs-err-3.3.1.crate" |
|
| 369 | - | CHECKSUM_SHA256_120="b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" |
|
| 370 | - | SOURCE_FILENAME_120="fs-err-3.3.1.tar.gz" |
|
| 371 | - | SOURCE_URI_121="https://static.crates.io/crates/futures/futures-0.3.34.crate" |
|
| 372 | - | CHECKSUM_SHA256_121="9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" |
|
| 373 | - | SOURCE_FILENAME_121="futures-0.3.34.tar.gz" |
|
| 374 | - | SOURCE_URI_122="https://static.crates.io/crates/futures-channel/futures-channel-0.3.34.crate" |
|
| 375 | - | CHECKSUM_SHA256_122="b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" |
|
| 376 | - | SOURCE_FILENAME_122="futures-channel-0.3.34.tar.gz" |
|
| 377 | - | SOURCE_URI_123="https://static.crates.io/crates/futures-core/futures-core-0.3.34.crate" |
|
| 378 | - | CHECKSUM_SHA256_123="92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" |
|
| 379 | - | SOURCE_FILENAME_123="futures-core-0.3.34.tar.gz" |
|
| 380 | - | SOURCE_URI_124="https://static.crates.io/crates/futures-executor/futures-executor-0.3.34.crate" |
|
| 381 | - | CHECKSUM_SHA256_124="031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" |
|
| 382 | - | SOURCE_FILENAME_124="futures-executor-0.3.34.tar.gz" |
|
| 383 | - | SOURCE_URI_125="https://static.crates.io/crates/futures-intrusive/futures-intrusive-0.5.0.crate" |
|
| 384 | - | CHECKSUM_SHA256_125="1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" |
|
| 385 | - | SOURCE_FILENAME_125="futures-intrusive-0.5.0.tar.gz" |
|
| 386 | - | SOURCE_URI_126="https://static.crates.io/crates/futures-io/futures-io-0.3.34.crate" |
|
| 387 | - | CHECKSUM_SHA256_126="53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" |
|
| 388 | - | SOURCE_FILENAME_126="futures-io-0.3.34.tar.gz" |
|
| 389 | - | SOURCE_URI_127="https://static.crates.io/crates/futures-macro/futures-macro-0.3.34.crate" |
|
| 390 | - | CHECKSUM_SHA256_127="9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" |
|
| 391 | - | SOURCE_FILENAME_127="futures-macro-0.3.34.tar.gz" |
|
| 392 | - | SOURCE_URI_128="https://static.crates.io/crates/futures-sink/futures-sink-0.3.34.crate" |
|
| 393 | - | CHECKSUM_SHA256_128="1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" |
|
| 394 | - | SOURCE_FILENAME_128="futures-sink-0.3.34.tar.gz" |
|
| 395 | - | SOURCE_URI_129="https://static.crates.io/crates/futures-task/futures-task-0.3.34.crate" |
|
| 396 | - | CHECKSUM_SHA256_129="cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" |
|
| 397 | - | SOURCE_FILENAME_129="futures-task-0.3.34.tar.gz" |
|
| 398 | - | SOURCE_URI_130="https://static.crates.io/crates/futures-util/futures-util-0.3.34.crate" |
|
| 399 | - | CHECKSUM_SHA256_130="0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" |
|
| 400 | - | SOURCE_FILENAME_130="futures-util-0.3.34.tar.gz" |
|
| 401 | - | SOURCE_URI_131="https://static.crates.io/crates/generic-array/generic-array-0.14.7.crate" |
|
| 402 | - | CHECKSUM_SHA256_131="85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" |
|
| 403 | - | SOURCE_FILENAME_131="generic-array-0.14.7.tar.gz" |
|
| 404 | - | SOURCE_URI_132="https://static.crates.io/crates/getrandom/getrandom-0.2.17.crate" |
|
| 405 | - | CHECKSUM_SHA256_132="ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" |
|
| 406 | - | SOURCE_FILENAME_132="getrandom-0.2.17.tar.gz" |
|
| 407 | - | SOURCE_URI_133="https://static.crates.io/crates/getrandom/getrandom-0.4.3.crate" |
|
| 408 | - | CHECKSUM_SHA256_133="300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" |
|
| 409 | - | SOURCE_FILENAME_133="getrandom-0.4.3.tar.gz" |
|
| 410 | - | SOURCE_URI_134="https://static.crates.io/crates/globset/globset-0.4.20.crate" |
|
| 411 | - | CHECKSUM_SHA256_134="07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" |
|
| 412 | - | SOURCE_FILENAME_134="globset-0.4.20.tar.gz" |
|
| 413 | - | SOURCE_URI_135="https://static.crates.io/crates/h2/h2-0.4.19.crate" |
|
| 414 | - | CHECKSUM_SHA256_135="ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" |
|
| 415 | - | SOURCE_FILENAME_135="h2-0.4.19.tar.gz" |
|
| 416 | - | SOURCE_URI_136="https://static.crates.io/crates/hashbrown/hashbrown-0.15.5.crate" |
|
| 417 | - | CHECKSUM_SHA256_136="9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" |
|
| 418 | - | SOURCE_FILENAME_136="hashbrown-0.15.5.tar.gz" |
|
| 419 | - | SOURCE_URI_137="https://static.crates.io/crates/hashbrown/hashbrown-0.17.1.crate" |
|
| 420 | - | CHECKSUM_SHA256_137="ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" |
|
| 421 | - | SOURCE_FILENAME_137="hashbrown-0.17.1.tar.gz" |
|
| 422 | - | SOURCE_URI_138="https://static.crates.io/crates/hashlink/hashlink-0.10.0.crate" |
|
| 423 | - | CHECKSUM_SHA256_138="7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1" |
|
| 424 | - | SOURCE_FILENAME_138="hashlink-0.10.0.tar.gz" |
|
| 425 | - | SOURCE_URI_139="https://static.crates.io/crates/heck/heck-0.5.0.crate" |
|
| 426 | - | CHECKSUM_SHA256_139="2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" |
|
| 427 | - | SOURCE_FILENAME_139="heck-0.5.0.tar.gz" |
|
| 428 | - | SOURCE_URI_140="https://static.crates.io/crates/hex/hex-0.4.3.crate" |
|
| 429 | - | CHECKSUM_SHA256_140="7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" |
|
| 430 | - | SOURCE_FILENAME_140="hex-0.4.3.tar.gz" |
|
| 431 | - | SOURCE_URI_141="https://static.crates.io/crates/hkdf/hkdf-0.12.4.crate" |
|
| 432 | - | CHECKSUM_SHA256_141="7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" |
|
| 433 | - | SOURCE_FILENAME_141="hkdf-0.12.4.tar.gz" |
|
| 434 | - | SOURCE_URI_142="https://static.crates.io/crates/hmac/hmac-0.12.1.crate" |
|
| 435 | - | CHECKSUM_SHA256_142="6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" |
|
| 436 | - | SOURCE_FILENAME_142="hmac-0.12.1.tar.gz" |
|
| 437 | - | SOURCE_URI_143="https://static.crates.io/crates/home/home-0.5.12.crate" |
|
| 438 | - | CHECKSUM_SHA256_143="cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" |
|
| 439 | - | SOURCE_FILENAME_143="home-0.5.12.tar.gz" |
|
| 440 | - | SOURCE_URI_144="https://static.crates.io/crates/html5ever/html5ever-0.40.1.crate" |
|
| 441 | - | CHECKSUM_SHA256_144="456a1a377e608e555d22ddab27ac0114bc7a7b4199078108e34c2aeae6c9b130" |
|
| 442 | - | SOURCE_FILENAME_144="html5ever-0.40.1.tar.gz" |
|
| 443 | - | SOURCE_URI_145="https://static.crates.io/crates/http/http-1.5.0.crate" |
|
| 444 | - | CHECKSUM_SHA256_145="918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" |
|
| 445 | - | SOURCE_FILENAME_145="http-1.5.0.tar.gz" |
|
| 446 | - | SOURCE_URI_146="https://static.crates.io/crates/http-body/http-body-1.1.0.crate" |
|
| 447 | - | CHECKSUM_SHA256_146="ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" |
|
| 448 | - | SOURCE_FILENAME_146="http-body-1.1.0.tar.gz" |
|
| 449 | - | SOURCE_URI_147="https://static.crates.io/crates/http-body-util/http-body-util-0.1.5.crate" |
|
| 450 | - | CHECKSUM_SHA256_147="23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" |
|
| 451 | - | SOURCE_FILENAME_147="http-body-util-0.1.5.tar.gz" |
|
| 452 | - | SOURCE_URI_148="https://static.crates.io/crates/httparse/httparse-1.10.1.crate" |
|
| 453 | - | CHECKSUM_SHA256_148="6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" |
|
| 454 | - | SOURCE_FILENAME_148="httparse-1.10.1.tar.gz" |
|
| 455 | - | SOURCE_URI_149="https://static.crates.io/crates/httpdate/httpdate-1.0.3.crate" |
|
| 456 | - | CHECKSUM_SHA256_149="df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" |
|
| 457 | - | SOURCE_FILENAME_149="httpdate-1.0.3.tar.gz" |
|
| 458 | - | SOURCE_URI_150="https://static.crates.io/crates/humantime/humantime-2.4.0.crate" |
|
| 459 | - | CHECKSUM_SHA256_150="15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" |
|
| 460 | - | SOURCE_FILENAME_150="humantime-2.4.0.tar.gz" |
|
| 461 | - | SOURCE_URI_151="https://static.crates.io/crates/hybrid-array/hybrid-array-0.4.15.crate" |
|
| 462 | - | CHECKSUM_SHA256_151="27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" |
|
| 463 | - | SOURCE_FILENAME_151="hybrid-array-0.4.15.tar.gz" |
|
| 464 | - | SOURCE_URI_152="https://static.crates.io/crates/hyper/hyper-1.11.1.crate" |
|
| 465 | - | CHECKSUM_SHA256_152="27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" |
|
| 466 | - | SOURCE_FILENAME_152="hyper-1.11.1.tar.gz" |
|
| 467 | - | SOURCE_URI_153="https://static.crates.io/crates/hyper-rustls/hyper-rustls-0.27.10.crate" |
|
| 468 | - | CHECKSUM_SHA256_153="dfa8e654703247911e29c23fbeaa261834bd9bb74efba2f9acddc37bfb127f53" |
|
| 469 | - | SOURCE_FILENAME_153="hyper-rustls-0.27.10.tar.gz" |
|
| 470 | - | SOURCE_URI_154="https://static.crates.io/crates/hyper-util/hyper-util-0.1.21.crate" |
|
| 471 | - | CHECKSUM_SHA256_154="ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" |
|
| 472 | - | SOURCE_FILENAME_154="hyper-util-0.1.21.tar.gz" |
|
| 473 | - | SOURCE_URI_155="https://static.crates.io/crates/iana-time-zone-haiku/iana-time-zone-haiku-0.1.2.crate" |
|
| 474 | - | CHECKSUM_SHA256_155="f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" |
|
| 475 | - | SOURCE_FILENAME_155="iana-time-zone-haiku-0.1.2.tar.gz" |
|
| 476 | - | SOURCE_URI_156="https://static.crates.io/crates/icu_collections/icu_collections-2.3.0.crate" |
|
| 477 | - | CHECKSUM_SHA256_156="fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" |
|
| 478 | - | SOURCE_FILENAME_156="icu_collections-2.3.0.tar.gz" |
|
| 479 | - | SOURCE_URI_157="https://static.crates.io/crates/icu_locale_core/icu_locale_core-2.3.0.crate" |
|
| 480 | - | CHECKSUM_SHA256_157="d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" |
|
| 481 | - | SOURCE_FILENAME_157="icu_locale_core-2.3.0.tar.gz" |
|
| 482 | - | SOURCE_URI_158="https://static.crates.io/crates/icu_normalizer/icu_normalizer-2.3.0.crate" |
|
| 483 | - | CHECKSUM_SHA256_158="12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" |
|
| 484 | - | SOURCE_FILENAME_158="icu_normalizer-2.3.0.tar.gz" |
|
| 485 | - | SOURCE_URI_159="https://static.crates.io/crates/icu_normalizer_data/icu_normalizer_data-2.3.0.crate" |
|
| 486 | - | CHECKSUM_SHA256_159="1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" |
|
| 487 | - | SOURCE_FILENAME_159="icu_normalizer_data-2.3.0.tar.gz" |
|
| 488 | - | SOURCE_URI_160="https://static.crates.io/crates/icu_properties/icu_properties-2.3.0.crate" |
|
| 489 | - | CHECKSUM_SHA256_160="7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" |
|
| 490 | - | SOURCE_FILENAME_160="icu_properties-2.3.0.tar.gz" |
|
| 491 | - | SOURCE_URI_161="https://static.crates.io/crates/icu_properties_data/icu_properties_data-2.3.0.crate" |
|
| 492 | - | CHECKSUM_SHA256_161="e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" |
|
| 493 | - | SOURCE_FILENAME_161="icu_properties_data-2.3.0.tar.gz" |
|
| 494 | - | SOURCE_URI_162="https://static.crates.io/crates/icu_provider/icu_provider-2.3.1.crate" |
|
| 495 | - | CHECKSUM_SHA256_162="d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" |
|
| 496 | - | SOURCE_FILENAME_162="icu_provider-2.3.1.tar.gz" |
|
| 497 | - | SOURCE_URI_163="https://static.crates.io/crates/idna/idna-1.1.0.crate" |
|
| 498 | - | CHECKSUM_SHA256_163="3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" |
|
| 499 | - | SOURCE_FILENAME_163="idna-1.1.0.tar.gz" |
|
| 500 | - | SOURCE_URI_164="https://static.crates.io/crates/idna_adapter/idna_adapter-1.2.2.crate" |
|
| 501 | - | CHECKSUM_SHA256_164="cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" |
|
| 502 | - | SOURCE_FILENAME_164="idna_adapter-1.2.2.tar.gz" |
|
| 503 | - | SOURCE_URI_165="https://static.crates.io/crates/ignore/ignore-0.4.33.crate" |
|
| 504 | - | CHECKSUM_SHA256_165="00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" |
|
| 505 | - | SOURCE_FILENAME_165="ignore-0.4.33.tar.gz" |
|
| 506 | - | SOURCE_URI_166="https://static.crates.io/crates/image/image-0.25.10.crate" |
|
| 507 | - | CHECKSUM_SHA256_166="85ab80394333c02fe689eaf900ab500fbd0c2213da414687ebf995a65d5a6104" |
|
| 508 | - | SOURCE_FILENAME_166="image-0.25.10.tar.gz" |
|
| 509 | - | SOURCE_URI_167="https://static.crates.io/crates/image-webp/image-webp-0.2.4.crate" |
|
| 510 | - | CHECKSUM_SHA256_167="525e9ff3e1a4be2fbea1fdf0e98686a6d98b4d8f937e1bf7402245af1909e8c3" |
|
| 511 | - | SOURCE_FILENAME_167="image-webp-0.2.4.tar.gz" |
|
| 512 | - | SOURCE_URI_168="https://static.crates.io/crates/indexmap/indexmap-2.14.2.crate" |
|
| 513 | - | CHECKSUM_SHA256_168="cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" |
|
| 514 | - | SOURCE_FILENAME_168="indexmap-2.14.2.tar.gz" |
|
| 515 | - | SOURCE_URI_169="https://static.crates.io/crates/ipnet/ipnet-2.12.2.crate" |
|
| 516 | - | CHECKSUM_SHA256_169="791930b43c0d5973160d90a8f3894509f2b273430f5c5c73b668636d0287c5c0" |
|
| 517 | - | SOURCE_FILENAME_169="ipnet-2.12.2.tar.gz" |
|
| 518 | - | SOURCE_URI_170="https://static.crates.io/crates/is_terminal_polyfill/is_terminal_polyfill-1.70.2.crate" |
|
| 519 | - | CHECKSUM_SHA256_170="a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" |
|
| 520 | - | SOURCE_FILENAME_170="is_terminal_polyfill-1.70.2.tar.gz" |
|
| 521 | - | SOURCE_URI_171="https://static.crates.io/crates/itertools/itertools-0.15.0.crate" |
|
| 522 | - | CHECKSUM_SHA256_171="8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" |
|
| 523 | - | SOURCE_FILENAME_171="itertools-0.15.0.tar.gz" |
|
| 524 | - | SOURCE_URI_172="https://static.crates.io/crates/itoa/itoa-1.0.18.crate" |
|
| 525 | - | CHECKSUM_SHA256_172="8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" |
|
| 526 | - | SOURCE_FILENAME_172="itoa-1.0.18.tar.gz" |
|
| 527 | - | SOURCE_URI_173="https://static.crates.io/crates/jobserver/jobserver-0.1.35.crate" |
|
| 528 | - | CHECKSUM_SHA256_173="1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" |
|
| 529 | - | SOURCE_FILENAME_173="jobserver-0.1.35.tar.gz" |
|
| 530 | - | SOURCE_URI_174="https://static.crates.io/crates/js-sys/js-sys-0.3.106.crate" |
|
| 531 | - | CHECKSUM_SHA256_174="7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" |
|
| 532 | - | SOURCE_FILENAME_174="js-sys-0.3.106.tar.gz" |
|
| 533 | - | SOURCE_URI_175="https://static.crates.io/crates/kdl/kdl-6.7.1.crate" |
|
| 534 | - | CHECKSUM_SHA256_175="082ddf81b2acd76fe04412655d17befedfff1837db772f8e74c38050d25ed670" |
|
| 535 | - | SOURCE_FILENAME_175="kdl-6.7.1.tar.gz" |
|
| 536 | - | SOURCE_URI_176="https://static.crates.io/crates/keccak/keccak-0.2.2.crate" |
|
| 537 | - | CHECKSUM_SHA256_176="d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" |
|
| 538 | - | SOURCE_FILENAME_176="keccak-0.2.2.tar.gz" |
|
| 539 | - | SOURCE_URI_177="https://static.crates.io/crates/lazy_static/lazy_static-1.5.0.crate" |
|
| 540 | - | CHECKSUM_SHA256_177="bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" |
|
| 541 | - | SOURCE_FILENAME_177="lazy_static-1.5.0.tar.gz" |
|
| 542 | - | SOURCE_URI_178="https://static.crates.io/crates/lettre/lettre-0.11.23.crate" |
|
| 543 | - | CHECKSUM_SHA256_178="f2c646bd5cc763b1087b15493e29a64be6147ba8f19342004fa52048ee596eae" |
|
| 544 | - | SOURCE_FILENAME_178="lettre-0.11.23.tar.gz" |
|
| 545 | - | SOURCE_URI_179="https://static.crates.io/crates/libc/libc-0.2.189.crate" |
|
| 546 | - | CHECKSUM_SHA256_179="3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" |
|
| 547 | - | SOURCE_FILENAME_179="libc-0.2.189.tar.gz" |
|
| 548 | - | SOURCE_URI_180="https://static.crates.io/crates/libm/libm-0.2.16.crate" |
|
| 549 | - | CHECKSUM_SHA256_180="b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" |
|
| 550 | - | SOURCE_FILENAME_180="libm-0.2.16.tar.gz" |
|
| 551 | - | SOURCE_URI_181="https://static.crates.io/crates/libredox/libredox-0.1.25.crate" |
|
| 552 | - | CHECKSUM_SHA256_181="61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" |
|
| 553 | - | SOURCE_FILENAME_181="libredox-0.1.25.tar.gz" |
|
| 554 | - | SOURCE_URI_182="https://static.crates.io/crates/libsqlite3-sys/libsqlite3-sys-0.30.1.crate" |
|
| 555 | - | CHECKSUM_SHA256_182="2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" |
|
| 556 | - | SOURCE_FILENAME_182="libsqlite3-sys-0.30.1.tar.gz" |
|
| 557 | - | SOURCE_URI_183="https://static.crates.io/crates/linked-hash-map/linked-hash-map-0.5.6.crate" |
|
| 558 | - | CHECKSUM_SHA256_183="0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" |
|
| 559 | - | SOURCE_FILENAME_183="linked-hash-map-0.5.6.tar.gz" |
|
| 560 | - | SOURCE_URI_184="https://static.crates.io/crates/linux-raw-sys/linux-raw-sys-0.12.1.crate" |
|
| 561 | - | CHECKSUM_SHA256_184="32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" |
|
| 562 | - | SOURCE_FILENAME_184="linux-raw-sys-0.12.1.tar.gz" |
|
| 563 | - | SOURCE_URI_185="https://static.crates.io/crates/litemap/litemap-0.8.3.crate" |
|
| 564 | - | CHECKSUM_SHA256_185="47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" |
|
| 565 | - | SOURCE_FILENAME_185="litemap-0.8.3.tar.gz" |
|
| 566 | - | SOURCE_URI_186="https://static.crates.io/crates/lock_api/lock_api-0.4.14.crate" |
|
| 567 | - | CHECKSUM_SHA256_186="224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" |
|
| 568 | - | SOURCE_FILENAME_186="lock_api-0.4.14.tar.gz" |
|
| 569 | - | SOURCE_URI_187="https://static.crates.io/crates/log/log-0.4.34.crate" |
|
| 570 | - | CHECKSUM_SHA256_187="f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" |
|
| 571 | - | SOURCE_FILENAME_187="log-0.4.34.tar.gz" |
|
| 572 | - | SOURCE_URI_188="https://static.crates.io/crates/lru-slab/lru-slab-0.1.3.crate" |
|
| 573 | - | CHECKSUM_SHA256_188="4050469837a6ff301cd14c1f8f24f88549e6d548f24f64e2148eb0f72cebc51f" |
|
| 574 | - | SOURCE_FILENAME_188="lru-slab-0.1.3.tar.gz" |
|
| 575 | - | SOURCE_URI_189="https://static.crates.io/crates/lzma-rs/lzma-rs-0.3.0.crate" |
|
| 576 | - | CHECKSUM_SHA256_189="297e814c836ae64db86b36cf2a557ba54368d03f6afcd7d947c266692f71115e" |
|
| 577 | - | SOURCE_FILENAME_189="lzma-rs-0.3.0.tar.gz" |
|
| 578 | - | SOURCE_URI_190="https://static.crates.io/crates/maplit/maplit-1.0.2.crate" |
|
| 579 | - | CHECKSUM_SHA256_190="3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" |
|
| 580 | - | SOURCE_FILENAME_190="maplit-1.0.2.tar.gz" |
|
| 581 | - | SOURCE_URI_191="https://static.crates.io/crates/markup5ever/markup5ever-0.40.0.crate" |
|
| 582 | - | CHECKSUM_SHA256_191="0ab3dc68ac4a0f5719e560136778c1ee716e296030d75dbd4484e37e39e3a842" |
|
| 583 | - | SOURCE_FILENAME_191="markup5ever-0.40.0.tar.gz" |
|
| 584 | - | SOURCE_URI_192="https://static.crates.io/crates/matchers/matchers-0.2.0.crate" |
|
| 585 | - | CHECKSUM_SHA256_192="d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" |
|
| 586 | - | SOURCE_FILENAME_192="matchers-0.2.0.tar.gz" |
|
| 587 | - | SOURCE_URI_193="https://static.crates.io/crates/matchit/matchit-0.8.4.crate" |
|
| 588 | - | CHECKSUM_SHA256_193="47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" |
|
| 589 | - | SOURCE_FILENAME_193="matchit-0.8.4.tar.gz" |
|
| 590 | - | SOURCE_URI_194="https://static.crates.io/crates/md-5/md-5-0.10.6.crate" |
|
| 591 | - | CHECKSUM_SHA256_194="d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" |
|
| 592 | - | SOURCE_FILENAME_194="md-5-0.10.6.tar.gz" |
|
| 593 | - | SOURCE_URI_195="https://static.crates.io/crates/md-5/md-5-0.11.0.crate" |
|
| 594 | - | CHECKSUM_SHA256_195="69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" |
|
| 595 | - | SOURCE_FILENAME_195="md-5-0.11.0.tar.gz" |
|
| 596 | - | SOURCE_URI_196="https://static.crates.io/crates/memchr/memchr-2.8.3.crate" |
|
| 597 | - | CHECKSUM_SHA256_196="cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" |
|
| 598 | - | SOURCE_FILENAME_196="memchr-2.8.3.tar.gz" |
|
| 599 | - | SOURCE_URI_197="https://static.crates.io/crates/miette/miette-7.6.0.crate" |
|
| 600 | - | CHECKSUM_SHA256_197="5f98efec8807c63c752b5bd61f862c165c115b0a35685bdcfd9238c7aeb592b7" |
|
| 601 | - | SOURCE_FILENAME_197="miette-7.6.0.tar.gz" |
|
| 602 | - | SOURCE_URI_198="https://static.crates.io/crates/miette-derive/miette-derive-7.6.0.crate" |
|
| 603 | - | CHECKSUM_SHA256_198="db5b29714e950dbb20d5e6f74f9dcec4edbcc1067bb7f8ed198c097b8c1a818b" |
|
| 604 | - | SOURCE_FILENAME_198="miette-derive-7.6.0.tar.gz" |
|
| 605 | - | SOURCE_URI_199="https://static.crates.io/crates/mime/mime-0.3.17.crate" |
|
| 606 | - | CHECKSUM_SHA256_199="6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" |
|
| 607 | - | SOURCE_FILENAME_199="mime-0.3.17.tar.gz" |
|
| 608 | - | SOURCE_URI_200="https://static.crates.io/crates/minimal-lexical/minimal-lexical-0.2.1.crate" |
|
| 609 | - | CHECKSUM_SHA256_200="68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" |
|
| 610 | - | SOURCE_FILENAME_200="minimal-lexical-0.2.1.tar.gz" |
|
| 611 | - | SOURCE_URI_201="https://static.crates.io/crates/miniz_oxide/miniz_oxide-0.8.9.crate" |
|
| 612 | - | CHECKSUM_SHA256_201="1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" |
|
| 613 | - | SOURCE_FILENAME_201="miniz_oxide-0.8.9.tar.gz" |
|
| 614 | - | SOURCE_URI_202="https://static.crates.io/crates/miniz_oxide/miniz_oxide-0.9.1.crate" |
|
| 615 | - | CHECKSUM_SHA256_202="b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" |
|
| 616 | - | SOURCE_FILENAME_202="miniz_oxide-0.9.1.tar.gz" |
|
| 617 | - | SOURCE_URI_203="https://static.crates.io/crates/mio/mio-1.2.3.crate" |
|
| 618 | - | CHECKSUM_SHA256_203="4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" |
|
| 619 | - | SOURCE_FILENAME_203="mio-1.2.3.tar.gz" |
|
| 620 | - | SOURCE_URI_204="https://static.crates.io/crates/ml-dsa/ml-dsa-0.1.1.crate" |
|
| 621 | - | CHECKSUM_SHA256_204="add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d" |
|
| 622 | - | SOURCE_FILENAME_204="ml-dsa-0.1.1.tar.gz" |
|
| 623 | - | SOURCE_URI_205="https://static.crates.io/crates/module-lattice/module-lattice-0.2.3.crate" |
|
| 624 | - | CHECKSUM_SHA256_205="0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" |
|
| 625 | - | SOURCE_FILENAME_205="module-lattice-0.2.3.tar.gz" |
|
| 626 | - | SOURCE_URI_206="https://static.crates.io/crates/moxcms/moxcms-0.8.1.crate" |
|
| 627 | - | CHECKSUM_SHA256_206="bb85c154ba489f01b25c0d36ae69a87e4a1c73a72631fc6c0eb6dde34a73e44b" |
|
| 628 | - | SOURCE_FILENAME_206="moxcms-0.8.1.tar.gz" |
|
| 629 | - | SOURCE_URI_207="https://static.crates.io/crates/multer/multer-3.1.0.crate" |
|
| 630 | - | CHECKSUM_SHA256_207="83e87776546dc87511aa5ee218730c92b666d7264ab6ed41f9d215af9cd5224b" |
|
| 631 | - | SOURCE_FILENAME_207="multer-3.1.0.tar.gz" |
|
| 632 | - | SOURCE_URI_208="https://static.crates.io/crates/multiversion/multiversion-0.9.0.crate" |
|
| 633 | - | CHECKSUM_SHA256_208="b4ca4bea16ffc3f443cf7d866912118196bfef4c6a1556ca00f9f9b00bb43f7c" |
|
| 634 | - | SOURCE_FILENAME_208="multiversion-0.9.0.tar.gz" |
|
| 635 | - | SOURCE_URI_209="https://static.crates.io/crates/multiversion-macros/multiversion-macros-0.9.0.crate" |
|
| 636 | - | CHECKSUM_SHA256_209="0d416831a7317ef4b08bee00b69cbbb9c8763da7959a7026244d6266869f9c83" |
|
| 637 | - | SOURCE_FILENAME_209="multiversion-macros-0.9.0.tar.gz" |
|
| 638 | - | SOURCE_URI_210="https://static.crates.io/crates/multiversion_no_op/multiversion_no_op-1.0.0.crate" |
|
| 639 | - | CHECKSUM_SHA256_210="743fb55ba31b18fb1ecef6bdc9aa2743314978ac084044301a7eee33fb99a20d" |
|
| 640 | - | SOURCE_FILENAME_210="multiversion_no_op-1.0.0.tar.gz" |
|
| 641 | - | SOURCE_URI_211="https://static.crates.io/crates/new_debug_unreachable/new_debug_unreachable-1.0.6.crate" |
|
| 642 | - | CHECKSUM_SHA256_211="650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" |
|
| 643 | - | SOURCE_FILENAME_211="new_debug_unreachable-1.0.6.tar.gz" |
|
| 644 | - | SOURCE_URI_212="https://static.crates.io/crates/nom/nom-7.1.3.crate" |
|
| 645 | - | CHECKSUM_SHA256_212="d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" |
|
| 646 | - | SOURCE_FILENAME_212="nom-7.1.3.tar.gz" |
|
| 647 | - | SOURCE_URI_213="https://static.crates.io/crates/nom/nom-8.0.0.crate" |
|
| 648 | - | CHECKSUM_SHA256_213="df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405" |
|
| 649 | - | SOURCE_FILENAME_213="nom-8.0.0.tar.gz" |
|
| 650 | - | SOURCE_URI_214="https://static.crates.io/crates/nu-ansi-term/nu-ansi-term-0.50.3.crate" |
|
| 651 | - | CHECKSUM_SHA256_214="7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" |
|
| 652 | - | SOURCE_FILENAME_214="nu-ansi-term-0.50.3.tar.gz" |
|
| 653 | - | SOURCE_URI_215="https://static.crates.io/crates/num-bigint/num-bigint-0.4.8.crate" |
|
| 654 | - | CHECKSUM_SHA256_215="c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" |
|
| 655 | - | SOURCE_FILENAME_215="num-bigint-0.4.8.tar.gz" |
|
| 656 | - | SOURCE_URI_216="https://static.crates.io/crates/num-bigint-dig/num-bigint-dig-0.8.6.crate" |
|
| 657 | - | CHECKSUM_SHA256_216="e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" |
|
| 658 | - | SOURCE_FILENAME_216="num-bigint-dig-0.8.6.tar.gz" |
|
| 659 | - | SOURCE_URI_217="https://static.crates.io/crates/num-conv/num-conv-0.2.2.crate" |
|
| 660 | - | CHECKSUM_SHA256_217="521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" |
|
| 661 | - | SOURCE_FILENAME_217="num-conv-0.2.2.tar.gz" |
|
| 662 | - | SOURCE_URI_218="https://static.crates.io/crates/num-integer/num-integer-0.1.47.crate" |
|
| 663 | - | CHECKSUM_SHA256_218="7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" |
|
| 664 | - | SOURCE_FILENAME_218="num-integer-0.1.47.tar.gz" |
|
| 665 | - | SOURCE_URI_219="https://static.crates.io/crates/num-iter/num-iter-0.1.46.crate" |
|
| 666 | - | CHECKSUM_SHA256_219="c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" |
|
| 667 | - | SOURCE_FILENAME_219="num-iter-0.1.46.tar.gz" |
|
| 668 | - | SOURCE_URI_220="https://static.crates.io/crates/num-traits/num-traits-0.2.19.crate" |
|
| 669 | - | CHECKSUM_SHA256_220="071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" |
|
| 670 | - | SOURCE_FILENAME_220="num-traits-0.2.19.tar.gz" |
|
| 671 | - | SOURCE_URI_221="https://static.crates.io/crates/object_store/object_store-0.14.2.crate" |
|
| 672 | - | CHECKSUM_SHA256_221="f1796bc93603f78c5760a69f2d58badc9618d22adade0a95385bb2adbae4eb94" |
|
| 673 | - | SOURCE_FILENAME_221="object_store-0.14.2.tar.gz" |
|
| 674 | - | SOURCE_URI_222="https://static.crates.io/crates/oid-registry/oid-registry-0.8.1.crate" |
|
| 675 | - | CHECKSUM_SHA256_222="12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" |
|
| 676 | - | SOURCE_FILENAME_222="oid-registry-0.8.1.tar.gz" |
|
| 677 | - | SOURCE_URI_223="https://static.crates.io/crates/once_cell/once_cell-1.21.4.crate" |
|
| 678 | - | CHECKSUM_SHA256_223="9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" |
|
| 679 | - | SOURCE_FILENAME_223="once_cell-1.21.4.tar.gz" |
|
| 680 | - | SOURCE_URI_224="https://static.crates.io/crates/once_cell_polyfill/once_cell_polyfill-1.70.2.crate" |
|
| 681 | - | CHECKSUM_SHA256_224="384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" |
|
| 682 | - | SOURCE_FILENAME_224="once_cell_polyfill-1.70.2.tar.gz" |
|
| 683 | - | SOURCE_URI_225="https://static.crates.io/crates/parking/parking-2.2.1.crate" |
|
| 684 | - | CHECKSUM_SHA256_225="f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" |
|
| 685 | - | SOURCE_FILENAME_225="parking-2.2.1.tar.gz" |
|
| 686 | - | SOURCE_URI_226="https://static.crates.io/crates/parking_lot/parking_lot-0.12.5.crate" |
|
| 687 | - | CHECKSUM_SHA256_226="93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" |
|
| 688 | - | SOURCE_FILENAME_226="parking_lot-0.12.5.tar.gz" |
|
| 689 | - | SOURCE_URI_227="https://static.crates.io/crates/parking_lot_core/parking_lot_core-0.9.12.crate" |
|
| 690 | - | CHECKSUM_SHA256_227="2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" |
|
| 691 | - | SOURCE_FILENAME_227="parking_lot_core-0.9.12.tar.gz" |
|
| 692 | - | SOURCE_URI_228="https://static.crates.io/crates/password-hash/password-hash-0.5.0.crate" |
|
| 693 | - | CHECKSUM_SHA256_228="346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" |
|
| 694 | - | SOURCE_FILENAME_228="password-hash-0.5.0.tar.gz" |
|
| 695 | - | SOURCE_URI_229="https://static.crates.io/crates/pem/pem-4.0.0.crate" |
|
| 696 | - | CHECKSUM_SHA256_229="d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" |
|
| 697 | - | SOURCE_FILENAME_229="pem-4.0.0.tar.gz" |
|
| 698 | - | SOURCE_URI_230="https://static.crates.io/crates/pem-rfc7468/pem-rfc7468-0.7.0.crate" |
|
| 699 | - | CHECKSUM_SHA256_230="88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" |
|
| 700 | - | SOURCE_FILENAME_230="pem-rfc7468-0.7.0.tar.gz" |
|
| 701 | - | SOURCE_URI_231="https://static.crates.io/crates/percent-encoding/percent-encoding-2.3.2.crate" |
|
| 702 | - | CHECKSUM_SHA256_231="9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" |
|
| 703 | - | SOURCE_FILENAME_231="percent-encoding-2.3.2.tar.gz" |
|
| 704 | - | SOURCE_URI_232="https://static.crates.io/crates/phf/phf-0.14.0.crate" |
|
| 705 | - | CHECKSUM_SHA256_232="010378780309880b08997fae13be7834dba947d36393bd372f2b1556deb2a2f6" |
|
| 706 | - | SOURCE_FILENAME_232="phf-0.14.0.tar.gz" |
|
| 707 | - | SOURCE_URI_233="https://static.crates.io/crates/phf_codegen/phf_codegen-0.14.0.crate" |
|
| 708 | - | CHECKSUM_SHA256_233="41b585a510fb76fdebead6897982ef2a03a21d8e6cbcca904999742a4afc6ffe" |
|
| 709 | - | SOURCE_FILENAME_233="phf_codegen-0.14.0.tar.gz" |
|
| 710 | - | SOURCE_URI_234="https://static.crates.io/crates/phf_generator/phf_generator-0.14.0.crate" |
|
| 711 | - | CHECKSUM_SHA256_234="aeb62e0959d5a1bebc965f4d15d9e2b7cea002b6b0f5ba8cde6cc26738467100" |
|
| 712 | - | SOURCE_FILENAME_234="phf_generator-0.14.0.tar.gz" |
|
| 713 | - | SOURCE_URI_235="https://static.crates.io/crates/phf_shared/phf_shared-0.14.0.crate" |
|
| 714 | - | CHECKSUM_SHA256_235="c6fd9027e2d9319be6349febd1db4e8d02aa544921200c9b777720ac34a3aa89" |
|
| 715 | - | SOURCE_FILENAME_235="phf_shared-0.14.0.tar.gz" |
|
| 716 | - | SOURCE_URI_236="https://static.crates.io/crates/pin-project-lite/pin-project-lite-0.2.17.crate" |
|
| 717 | - | CHECKSUM_SHA256_236="a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" |
|
| 718 | - | SOURCE_FILENAME_236="pin-project-lite-0.2.17.tar.gz" |
|
| 719 | - | SOURCE_URI_237="https://static.crates.io/crates/pkcs1/pkcs1-0.7.5.crate" |
|
| 720 | - | CHECKSUM_SHA256_237="c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" |
|
| 721 | - | SOURCE_FILENAME_237="pkcs1-0.7.5.tar.gz" |
|
| 722 | - | SOURCE_URI_238="https://static.crates.io/crates/pkcs8/pkcs8-0.10.2.crate" |
|
| 723 | - | CHECKSUM_SHA256_238="f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" |
|
| 724 | - | SOURCE_FILENAME_238="pkcs8-0.10.2.tar.gz" |
|
| 725 | - | SOURCE_URI_239="https://static.crates.io/crates/pkcs8/pkcs8-0.11.0.crate" |
|
| 726 | - | CHECKSUM_SHA256_239="451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" |
|
| 727 | - | SOURCE_FILENAME_239="pkcs8-0.11.0.tar.gz" |
|
| 728 | - | SOURCE_URI_240="https://static.crates.io/crates/pkg-config/pkg-config-0.3.34.crate" |
|
| 729 | - | CHECKSUM_SHA256_240="f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" |
|
| 730 | - | SOURCE_FILENAME_240="pkg-config-0.3.34.tar.gz" |
|
| 731 | - | SOURCE_URI_241="https://static.crates.io/crates/plain/plain-0.2.3.crate" |
|
| 732 | - | CHECKSUM_SHA256_241="b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" |
|
| 733 | - | SOURCE_FILENAME_241="plain-0.2.3.tar.gz" |
|
| 734 | - | SOURCE_URI_242="https://static.crates.io/crates/plist/plist-1.10.1.crate" |
|
| 735 | - | CHECKSUM_SHA256_242="2896bade328c13f7042a297ea5ac5b0951f6cf989dea5f32c2fd98da398195cb" |
|
| 736 | - | SOURCE_FILENAME_242="plist-1.10.1.tar.gz" |
|
| 737 | - | SOURCE_URI_243="https://static.crates.io/crates/png/png-0.18.1.crate" |
|
| 738 | - | CHECKSUM_SHA256_243="60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" |
|
| 739 | - | SOURCE_FILENAME_243="png-0.18.1.tar.gz" |
|
| 740 | - | SOURCE_URI_244="https://static.crates.io/crates/potential_utf/potential_utf-0.1.6.crate" |
|
| 741 | - | CHECKSUM_SHA256_244="d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" |
|
| 742 | - | SOURCE_FILENAME_244="potential_utf-0.1.6.tar.gz" |
|
| 743 | - | SOURCE_URI_245="https://static.crates.io/crates/powerfmt/powerfmt-0.2.0.crate" |
|
| 744 | - | CHECKSUM_SHA256_245="439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" |
|
| 745 | - | SOURCE_FILENAME_245="powerfmt-0.2.0.tar.gz" |
|
| 746 | - | SOURCE_URI_246="https://static.crates.io/crates/ppv-lite86/ppv-lite86-0.2.21.crate" |
|
| 747 | - | CHECKSUM_SHA256_246="85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" |
|
| 748 | - | SOURCE_FILENAME_246="ppv-lite86-0.2.21.tar.gz" |
|
| 749 | - | SOURCE_URI_247="https://static.crates.io/crates/precomputed-hash/precomputed-hash-0.1.1.crate" |
|
| 750 | - | CHECKSUM_SHA256_247="925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" |
|
| 751 | - | SOURCE_FILENAME_247="precomputed-hash-0.1.1.tar.gz" |
|
| 752 | - | SOURCE_URI_248="https://static.crates.io/crates/proc-macro2/proc-macro2-1.0.107.crate" |
|
| 753 | - | CHECKSUM_SHA256_248="985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" |
|
| 754 | - | SOURCE_FILENAME_248="proc-macro2-1.0.107.tar.gz" |
|
| 755 | - | SOURCE_URI_249="https://static.crates.io/crates/pulldown-cmark/pulldown-cmark-0.13.4.crate" |
|
| 756 | - | CHECKSUM_SHA256_249="e9f068eba8e7071c5f9511831b44f32c740d5adf574e990f946ddb53db2f314e" |
|
| 757 | - | SOURCE_FILENAME_249="pulldown-cmark-0.13.4.tar.gz" |
|
| 758 | - | SOURCE_URI_250="https://static.crates.io/crates/pulldown-cmark-escape/pulldown-cmark-escape-0.11.0.crate" |
|
| 759 | - | CHECKSUM_SHA256_250="007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" |
|
| 760 | - | SOURCE_FILENAME_250="pulldown-cmark-escape-0.11.0.tar.gz" |
|
| 761 | - | SOURCE_URI_251="https://static.crates.io/crates/pxfm/pxfm-0.1.30.crate" |
|
| 762 | - | CHECKSUM_SHA256_251="d55d956fa96f5ec02be2e13af0e20391a5aa83d6a074e3ad368959d0fab299ea" |
|
| 763 | - | SOURCE_FILENAME_251="pxfm-0.1.30.tar.gz" |
|
| 764 | - | SOURCE_URI_252="https://static.crates.io/crates/qrcode/qrcode-0.14.1.crate" |
|
| 765 | - | CHECKSUM_SHA256_252="d68782463e408eb1e668cf6152704bd856c78c5b6417adaee3203d8f4c1fc9ec" |
|
| 766 | - | SOURCE_FILENAME_252="qrcode-0.14.1.tar.gz" |
|
| 767 | - | SOURCE_URI_253="https://static.crates.io/crates/quick-error/quick-error-2.0.1.crate" |
|
| 768 | - | CHECKSUM_SHA256_253="a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" |
|
| 769 | - | SOURCE_FILENAME_253="quick-error-2.0.1.tar.gz" |
|
| 770 | - | SOURCE_URI_254="https://static.crates.io/crates/quick-xml/quick-xml-0.41.0.crate" |
|
| 771 | - | CHECKSUM_SHA256_254="e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" |
|
| 772 | - | SOURCE_FILENAME_254="quick-xml-0.41.0.tar.gz" |
|
| 773 | - | SOURCE_URI_255="https://static.crates.io/crates/quick-xml/quick-xml-0.42.0.crate" |
|
| 774 | - | CHECKSUM_SHA256_255="41b1177fdf999d2321d3fb46ff47159d9c1fb9ad66a4879f8c50a0b504615e9b" |
|
| 775 | - | SOURCE_FILENAME_255="quick-xml-0.42.0.tar.gz" |
|
| 776 | - | SOURCE_URI_256="https://static.crates.io/crates/quinn/quinn-0.11.12.crate" |
|
| 777 | - | CHECKSUM_SHA256_256="4051e23e9185c255a7e33ef59cdbca87a22d359052eecd22fc6b901fb37d9d11" |
|
| 778 | - | SOURCE_FILENAME_256="quinn-0.11.12.tar.gz" |
|
| 779 | - | SOURCE_URI_257="https://static.crates.io/crates/quinn-proto/quinn-proto-0.11.18.crate" |
|
| 780 | - | CHECKSUM_SHA256_257="a9746dbde176634f4f2f1faf2404e30a31b2bc1e9cafb5329c95d8177a18c9fc" |
|
| 781 | - | SOURCE_FILENAME_257="quinn-proto-0.11.18.tar.gz" |
|
| 782 | - | SOURCE_URI_258="https://static.crates.io/crates/quinn-udp/quinn-udp-0.5.15.crate" |
|
| 783 | - | CHECKSUM_SHA256_258="35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" |
|
| 784 | - | SOURCE_FILENAME_258="quinn-udp-0.5.15.tar.gz" |
|
| 785 | - | SOURCE_URI_259="https://static.crates.io/crates/quote/quote-1.0.47.crate" |
|
| 786 | - | CHECKSUM_SHA256_259="1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" |
|
| 787 | - | SOURCE_FILENAME_259="quote-1.0.47.tar.gz" |
|
| 788 | - | SOURCE_URI_260="https://static.crates.io/crates/quoted_printable/quoted_printable-0.5.2.crate" |
|
| 789 | - | CHECKSUM_SHA256_260="478e0585659a122aa407eb7e3c0e1fa51b1d8a870038bd29f0cf4a8551eea972" |
|
| 790 | - | SOURCE_FILENAME_260="quoted_printable-0.5.2.tar.gz" |
|
| 791 | - | SOURCE_URI_261="https://static.crates.io/crates/r-efi/r-efi-6.0.0.crate" |
|
| 792 | - | CHECKSUM_SHA256_261="f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" |
|
| 793 | - | SOURCE_FILENAME_261="r-efi-6.0.0.tar.gz" |
|
| 794 | - | SOURCE_URI_262="https://static.crates.io/crates/rand/rand-0.10.3.crate" |
|
| 795 | - | CHECKSUM_SHA256_262="65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" |
|
| 796 | - | SOURCE_FILENAME_262="rand-0.10.3.tar.gz" |
|
| 797 | - | SOURCE_URI_263="https://static.crates.io/crates/rand/rand-0.8.8.crate" |
|
| 798 | - | CHECKSUM_SHA256_263="e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" |
|
| 799 | - | SOURCE_FILENAME_263="rand-0.8.8.tar.gz" |
|
| 800 | - | SOURCE_URI_264="https://static.crates.io/crates/rand_chacha/rand_chacha-0.3.1.crate" |
|
| 801 | - | CHECKSUM_SHA256_264="e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" |
|
| 802 | - | SOURCE_FILENAME_264="rand_chacha-0.3.1.tar.gz" |
|
| 803 | - | SOURCE_URI_265="https://static.crates.io/crates/rand_core/rand_core-0.10.1.crate" |
|
| 804 | - | CHECKSUM_SHA256_265="63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" |
|
| 805 | - | SOURCE_FILENAME_265="rand_core-0.10.1.tar.gz" |
|
| 806 | - | SOURCE_URI_266="https://static.crates.io/crates/rand_core/rand_core-0.6.4.crate" |
|
| 807 | - | CHECKSUM_SHA256_266="ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" |
|
| 808 | - | SOURCE_FILENAME_266="rand_core-0.6.4.tar.gz" |
|
| 809 | - | SOURCE_URI_267="https://static.crates.io/crates/rand_pcg/rand_pcg-0.10.2.crate" |
|
| 810 | - | CHECKSUM_SHA256_267="caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" |
|
| 811 | - | SOURCE_FILENAME_267="rand_pcg-0.10.2.tar.gz" |
|
| 812 | - | SOURCE_URI_268="https://static.crates.io/crates/rayon/rayon-1.12.0.crate" |
|
| 813 | - | CHECKSUM_SHA256_268="fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" |
|
| 814 | - | SOURCE_FILENAME_268="rayon-1.12.0.tar.gz" |
|
| 815 | - | SOURCE_URI_269="https://static.crates.io/crates/rayon-core/rayon-core-1.13.0.crate" |
|
| 816 | - | CHECKSUM_SHA256_269="22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" |
|
| 817 | - | SOURCE_FILENAME_269="rayon-core-1.13.0.tar.gz" |
|
| 818 | - | SOURCE_URI_270="https://static.crates.io/crates/rcgen/rcgen-0.14.10.crate" |
|
| 819 | - | CHECKSUM_SHA256_270="8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" |
|
| 820 | - | SOURCE_FILENAME_270="rcgen-0.14.10.tar.gz" |
|
| 821 | - | SOURCE_URI_271="https://static.crates.io/crates/redox_syscall/redox_syscall-0.5.18.crate" |
|
| 822 | - | CHECKSUM_SHA256_271="ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" |
|
| 823 | - | SOURCE_FILENAME_271="redox_syscall-0.5.18.tar.gz" |
|
| 824 | - | SOURCE_URI_272="https://static.crates.io/crates/redox_syscall/redox_syscall-0.9.4.crate" |
|
| 825 | - | CHECKSUM_SHA256_272="737970939a87c6fa31e7acad13307bccbb017a073b695b6089a2c484f929e20e" |
|
| 826 | - | SOURCE_FILENAME_272="redox_syscall-0.9.4.tar.gz" |
|
| 827 | - | SOURCE_URI_273="https://static.crates.io/crates/ref-cast/ref-cast-1.0.27.crate" |
|
| 828 | - | CHECKSUM_SHA256_273="7e440fb4e4b4147295338efb76001ab9e4efc0e5839df2c47fc5ac2381d365c3" |
|
| 829 | - | SOURCE_FILENAME_273="ref-cast-1.0.27.tar.gz" |
|
| 830 | - | SOURCE_URI_274="https://static.crates.io/crates/ref-cast-impl/ref-cast-impl-1.0.27.crate" |
|
| 831 | - | CHECKSUM_SHA256_274="92ecd8964f8453721699a1ed72037b0db49ce2f5a5138486ee89bed6f67cdf3a" |
|
| 832 | - | SOURCE_FILENAME_274="ref-cast-impl-1.0.27.tar.gz" |
|
| 833 | - | SOURCE_URI_275="https://static.crates.io/crates/regex/regex-1.13.1.crate" |
|
| 834 | - | CHECKSUM_SHA256_275="f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" |
|
| 835 | - | SOURCE_FILENAME_275="regex-1.13.1.tar.gz" |
|
| 836 | - | SOURCE_URI_276="https://static.crates.io/crates/regex-automata/regex-automata-0.4.18.crate" |
|
| 837 | - | CHECKSUM_SHA256_276="ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" |
|
| 838 | - | SOURCE_FILENAME_276="regex-automata-0.4.18.tar.gz" |
|
| 839 | - | SOURCE_URI_277="https://static.crates.io/crates/regex-syntax/regex-syntax-0.8.11.crate" |
|
| 840 | - | CHECKSUM_SHA256_277="d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" |
|
| 841 | - | SOURCE_FILENAME_277="regex-syntax-0.8.11.tar.gz" |
|
| 842 | - | SOURCE_URI_278="https://static.crates.io/crates/reqwest/reqwest-0.12.28.crate" |
|
| 843 | - | CHECKSUM_SHA256_278="eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" |
|
| 844 | - | SOURCE_FILENAME_278="reqwest-0.12.28.tar.gz" |
|
| 845 | - | SOURCE_URI_279="https://static.crates.io/crates/ring/ring-0.17.14.crate" |
|
| 846 | - | CHECKSUM_SHA256_279="a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" |
|
| 847 | - | SOURCE_FILENAME_279="ring-0.17.14.tar.gz" |
|
| 848 | - | SOURCE_URI_280="https://static.crates.io/crates/rsa/rsa-0.9.10.crate" |
|
| 849 | - | CHECKSUM_SHA256_280="b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" |
|
| 850 | - | SOURCE_FILENAME_280="rsa-0.9.10.tar.gz" |
|
| 851 | - | SOURCE_URI_281="https://static.crates.io/crates/rustc-hash/rustc-hash-2.1.3.crate" |
|
| 852 | - | CHECKSUM_SHA256_281="6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" |
|
| 853 | - | SOURCE_FILENAME_281="rustc-hash-2.1.3.tar.gz" |
|
| 854 | - | SOURCE_URI_282="https://static.crates.io/crates/rustc_version/rustc_version-0.4.1.crate" |
|
| 855 | - | CHECKSUM_SHA256_282="cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" |
|
| 856 | - | SOURCE_FILENAME_282="rustc_version-0.4.1.tar.gz" |
|
| 857 | - | SOURCE_URI_283="https://static.crates.io/crates/rusticata-macros/rusticata-macros-4.1.0.crate" |
|
| 858 | - | CHECKSUM_SHA256_283="faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" |
|
| 859 | - | SOURCE_FILENAME_283="rusticata-macros-4.1.0.tar.gz" |
|
| 860 | - | SOURCE_URI_284="https://static.crates.io/crates/rustix/rustix-1.1.5.crate" |
|
| 861 | - | CHECKSUM_SHA256_284="891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" |
|
| 862 | - | SOURCE_FILENAME_284="rustix-1.1.5.tar.gz" |
|
| 863 | - | SOURCE_URI_285="https://static.crates.io/crates/rustls/rustls-0.23.45.crate" |
|
| 864 | - | CHECKSUM_SHA256_285="0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" |
|
| 865 | - | SOURCE_FILENAME_285="rustls-0.23.45.tar.gz" |
|
| 866 | - | SOURCE_URI_286="https://static.crates.io/crates/rustls-pemfile/rustls-pemfile-2.2.0.crate" |
|
| 867 | - | CHECKSUM_SHA256_286="dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" |
|
| 868 | - | SOURCE_FILENAME_286="rustls-pemfile-2.2.0.tar.gz" |
|
| 869 | - | SOURCE_URI_287="https://static.crates.io/crates/rustls-pki-types/rustls-pki-types-1.15.1.crate" |
|
| 870 | - | CHECKSUM_SHA256_287="2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" |
|
| 871 | - | SOURCE_FILENAME_287="rustls-pki-types-1.15.1.tar.gz" |
|
| 872 | - | SOURCE_URI_288="https://static.crates.io/crates/rustls-webpki/rustls-webpki-0.103.15.crate" |
|
| 873 | - | CHECKSUM_SHA256_288="f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" |
|
| 874 | - | SOURCE_FILENAME_288="rustls-webpki-0.103.15.tar.gz" |
|
| 875 | - | SOURCE_URI_289="https://static.crates.io/crates/rustversion/rustversion-1.0.23.crate" |
|
| 876 | - | CHECKSUM_SHA256_289="cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" |
|
| 877 | - | SOURCE_FILENAME_289="rustversion-1.0.23.tar.gz" |
|
| 878 | - | SOURCE_URI_290="https://static.crates.io/crates/ryu/ryu-1.0.23.crate" |
|
| 879 | - | CHECKSUM_SHA256_290="9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" |
|
| 880 | - | SOURCE_FILENAME_290="ryu-1.0.23.tar.gz" |
|
| 881 | - | SOURCE_URI_291="https://static.crates.io/crates/same-file/same-file-1.0.6.crate" |
|
| 882 | - | CHECKSUM_SHA256_291="93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" |
|
| 883 | - | SOURCE_FILENAME_291="same-file-1.0.6.tar.gz" |
|
| 884 | - | SOURCE_URI_292="https://static.crates.io/crates/schemars/schemars-1.2.2.crate" |
|
| 885 | - | CHECKSUM_SHA256_292="687274d293b6cdc6e73e0fee520bf2049650090d7164f87672d212a3c530cf4a" |
|
| 886 | - | SOURCE_FILENAME_292="schemars-1.2.2.tar.gz" |
|
| 887 | - | SOURCE_URI_293="https://static.crates.io/crates/schemars_derive/schemars_derive-1.2.2.crate" |
|
| 888 | - | CHECKSUM_SHA256_293="d98c67716b46af2f0b8cf752abc930f6f9aecfbf671ecfb531db8a31dbe4e2ba" |
|
| 889 | - | SOURCE_FILENAME_293="schemars_derive-1.2.2.tar.gz" |
|
| 890 | - | SOURCE_URI_294="https://static.crates.io/crates/scopeguard/scopeguard-1.2.0.crate" |
|
| 891 | - | CHECKSUM_SHA256_294="94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" |
|
| 892 | - | SOURCE_FILENAME_294="scopeguard-1.2.0.tar.gz" |
|
| 893 | - | SOURCE_URI_295="https://static.crates.io/crates/semver/semver-1.0.28.crate" |
|
| 894 | - | CHECKSUM_SHA256_295="8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" |
|
| 895 | - | SOURCE_FILENAME_295="semver-1.0.28.tar.gz" |
|
| 896 | - | SOURCE_URI_296="https://static.crates.io/crates/serde/serde-1.0.229.crate" |
|
| 897 | - | CHECKSUM_SHA256_296="4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" |
|
| 898 | - | SOURCE_FILENAME_296="serde-1.0.229.tar.gz" |
|
| 899 | - | SOURCE_URI_297="https://static.crates.io/crates/serde_core/serde_core-1.0.229.crate" |
|
| 900 | - | CHECKSUM_SHA256_297="67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" |
|
| 901 | - | SOURCE_FILENAME_297="serde_core-1.0.229.tar.gz" |
|
| 902 | - | SOURCE_URI_298="https://static.crates.io/crates/serde_derive/serde_derive-1.0.229.crate" |
|
| 903 | - | CHECKSUM_SHA256_298="e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" |
|
| 904 | - | SOURCE_FILENAME_298="serde_derive-1.0.229.tar.gz" |
|
| 905 | - | SOURCE_URI_299="https://static.crates.io/crates/serde_derive_internals/serde_derive_internals-0.30.0.crate" |
|
| 906 | - | CHECKSUM_SHA256_299="f852137cce035d6a4df67ccce505ff6b3e9fd3a10e3e52b24dc71e650bb1a9bd" |
|
| 907 | - | SOURCE_FILENAME_299="serde_derive_internals-0.30.0.tar.gz" |
|
| 908 | - | SOURCE_URI_300="https://static.crates.io/crates/serde_html_form/serde_html_form-0.2.8.crate" |
|
| 909 | - | CHECKSUM_SHA256_300="b2f2d7ff8a2140333718bb329f5c40fc5f0865b84c426183ce14c97d2ab8154f" |
|
| 910 | - | SOURCE_FILENAME_300="serde_html_form-0.2.8.tar.gz" |
|
| 911 | - | SOURCE_URI_301="https://static.crates.io/crates/serde_json/serde_json-1.0.151.crate" |
|
| 912 | - | CHECKSUM_SHA256_301="c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" |
|
| 913 | - | SOURCE_FILENAME_301="serde_json-1.0.151.tar.gz" |
|
| 914 | - | SOURCE_URI_302="https://static.crates.io/crates/serde_path_to_error/serde_path_to_error-0.1.20.crate" |
|
| 915 | - | CHECKSUM_SHA256_302="10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" |
|
| 916 | - | SOURCE_FILENAME_302="serde_path_to_error-0.1.20.tar.gz" |
|
| 917 | - | SOURCE_URI_303="https://static.crates.io/crates/serde_spanned/serde_spanned-0.6.9.crate" |
|
| 918 | - | CHECKSUM_SHA256_303="bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" |
|
| 919 | - | SOURCE_FILENAME_303="serde_spanned-0.6.9.tar.gz" |
|
| 920 | - | SOURCE_URI_304="https://static.crates.io/crates/serde_urlencoded/serde_urlencoded-0.7.1.crate" |
|
| 921 | - | CHECKSUM_SHA256_304="d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" |
|
| 922 | - | SOURCE_FILENAME_304="serde_urlencoded-0.7.1.tar.gz" |
|
| 923 | - | SOURCE_URI_305="https://static.crates.io/crates/sha1/sha1-0.10.7.crate" |
|
| 924 | - | CHECKSUM_SHA256_305="a978451301f4db1d02937a4ab3ccce137717b81826e79b7d49ffe3244a13c3b8" |
|
| 925 | - | SOURCE_FILENAME_305="sha1-0.10.7.tar.gz" |
|
| 926 | - | SOURCE_URI_306="https://static.crates.io/crates/sha2/sha2-0.10.9.crate" |
|
| 927 | - | CHECKSUM_SHA256_306="a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" |
|
| 928 | - | SOURCE_FILENAME_306="sha2-0.10.9.tar.gz" |
|
| 929 | - | SOURCE_URI_307="https://static.crates.io/crates/sha2/sha2-0.11.0.crate" |
|
| 930 | - | CHECKSUM_SHA256_307="446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" |
|
| 931 | - | SOURCE_FILENAME_307="sha2-0.11.0.tar.gz" |
|
| 932 | - | SOURCE_URI_308="https://static.crates.io/crates/shake/shake-0.1.0.crate" |
|
| 933 | - | CHECKSUM_SHA256_308="09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a" |
|
| 934 | - | SOURCE_FILENAME_308="shake-0.1.0.tar.gz" |
|
| 935 | - | SOURCE_URI_309="https://static.crates.io/crates/sharded-slab/sharded-slab-0.1.7.crate" |
|
| 936 | - | CHECKSUM_SHA256_309="f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" |
|
| 937 | - | SOURCE_FILENAME_309="sharded-slab-0.1.7.tar.gz" |
|
| 938 | - | SOURCE_URI_310="https://static.crates.io/crates/shlex/shlex-2.0.1.crate" |
|
| 939 | - | CHECKSUM_SHA256_310="f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" |
|
| 940 | - | SOURCE_FILENAME_310="shlex-2.0.1.tar.gz" |
|
| 941 | - | SOURCE_URI_311="https://static.crates.io/crates/signal-hook-registry/signal-hook-registry-1.4.8.crate" |
|
| 942 | - | CHECKSUM_SHA256_311="c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" |
|
| 943 | - | SOURCE_FILENAME_311="signal-hook-registry-1.4.8.tar.gz" |
|
| 944 | - | SOURCE_URI_312="https://static.crates.io/crates/signature/signature-2.2.0.crate" |
|
| 945 | - | CHECKSUM_SHA256_312="77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" |
|
| 946 | - | SOURCE_FILENAME_312="signature-2.2.0.tar.gz" |
|
| 947 | - | SOURCE_URI_313="https://static.crates.io/crates/signature/signature-3.0.0.crate" |
|
| 948 | - | CHECKSUM_SHA256_313="28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" |
|
| 949 | - | SOURCE_FILENAME_313="signature-3.0.0.tar.gz" |
|
| 950 | - | SOURCE_URI_314="https://static.crates.io/crates/simd-adler32/simd-adler32-0.3.10.crate" |
|
| 951 | - | CHECKSUM_SHA256_314="3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" |
|
| 952 | - | SOURCE_FILENAME_314="simd-adler32-0.3.10.tar.gz" |
|
| 953 | - | SOURCE_URI_315="https://static.crates.io/crates/simdutf8/simdutf8-0.1.5.crate" |
|
| 954 | - | CHECKSUM_SHA256_315="e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" |
|
| 955 | - | SOURCE_FILENAME_315="simdutf8-0.1.5.tar.gz" |
|
| 956 | - | SOURCE_URI_316="https://static.crates.io/crates/similar/similar-2.7.0.crate" |
|
| 957 | - | CHECKSUM_SHA256_316="bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" |
|
| 958 | - | SOURCE_FILENAME_316="similar-2.7.0.tar.gz" |
|
| 959 | - | SOURCE_URI_317="https://static.crates.io/crates/siphasher/siphasher-1.0.4.crate" |
|
| 960 | - | CHECKSUM_SHA256_317="33f4fe9184a62d842c9ef383018f3306d8ba224fd9d836f56d7288308847c256" |
|
| 961 | - | SOURCE_FILENAME_317="siphasher-1.0.4.tar.gz" |
|
| 962 | - | SOURCE_URI_318="https://static.crates.io/crates/slab/slab-0.4.12.crate" |
|
| 963 | - | CHECKSUM_SHA256_318="0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" |
|
| 964 | - | SOURCE_FILENAME_318="slab-0.4.12.tar.gz" |
|
| 965 | - | SOURCE_URI_319="https://static.crates.io/crates/smallvec/smallvec-1.16.2.crate" |
|
| 966 | - | CHECKSUM_SHA256_319="f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" |
|
| 967 | - | SOURCE_FILENAME_319="smallvec-1.16.2.tar.gz" |
|
| 968 | - | SOURCE_URI_320="https://static.crates.io/crates/socket2/socket2-0.6.5.crate" |
|
| 969 | - | CHECKSUM_SHA256_320="c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" |
|
| 970 | - | SOURCE_FILENAME_320="socket2-0.6.5.tar.gz" |
|
| 971 | - | SOURCE_URI_321="https://static.crates.io/crates/spin/spin-0.10.1.crate" |
|
| 972 | - | CHECKSUM_SHA256_321="023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" |
|
| 973 | - | SOURCE_FILENAME_321="spin-0.10.1.tar.gz" |
|
| 974 | - | SOURCE_URI_322="https://static.crates.io/crates/spin/spin-0.9.9.crate" |
|
| 975 | - | CHECKSUM_SHA256_322="3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e" |
|
| 976 | - | SOURCE_FILENAME_322="spin-0.9.9.tar.gz" |
|
| 977 | - | SOURCE_URI_323="https://static.crates.io/crates/spki/spki-0.7.3.crate" |
|
| 978 | - | CHECKSUM_SHA256_323="d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" |
|
| 979 | - | SOURCE_FILENAME_323="spki-0.7.3.tar.gz" |
|
| 980 | - | SOURCE_URI_324="https://static.crates.io/crates/spki/spki-0.8.0.crate" |
|
| 981 | - | CHECKSUM_SHA256_324="1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" |
|
| 982 | - | SOURCE_FILENAME_324="spki-0.8.0.tar.gz" |
|
| 983 | - | SOURCE_URI_325="https://static.crates.io/crates/sponge-cursor/sponge-cursor-0.1.0.crate" |
|
| 984 | - | CHECKSUM_SHA256_325="3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620" |
|
| 985 | - | SOURCE_FILENAME_325="sponge-cursor-0.1.0.tar.gz" |
|
| 986 | - | SOURCE_URI_326="https://static.crates.io/crates/sqlx/sqlx-0.8.6.crate" |
|
| 987 | - | CHECKSUM_SHA256_326="1fefb893899429669dcdd979aff487bd78f4064e5e7907e4269081e0ef7d97dc" |
|
| 988 | - | SOURCE_FILENAME_326="sqlx-0.8.6.tar.gz" |
|
| 989 | - | SOURCE_URI_327="https://static.crates.io/crates/sqlx-core/sqlx-core-0.8.6.crate" |
|
| 990 | - | CHECKSUM_SHA256_327="ee6798b1838b6a0f69c007c133b8df5866302197e404e8b6ee8ed3e3a5e68dc6" |
|
| 991 | - | SOURCE_FILENAME_327="sqlx-core-0.8.6.tar.gz" |
|
| 992 | - | SOURCE_URI_328="https://static.crates.io/crates/sqlx-macros/sqlx-macros-0.8.6.crate" |
|
| 993 | - | CHECKSUM_SHA256_328="a2d452988ccaacfbf5e0bdbc348fb91d7c8af5bee192173ac3636b5fb6e6715d" |
|
| 994 | - | SOURCE_FILENAME_328="sqlx-macros-0.8.6.tar.gz" |
|
| 995 | - | SOURCE_URI_329="https://static.crates.io/crates/sqlx-macros-core/sqlx-macros-core-0.8.6.crate" |
|
| 996 | - | CHECKSUM_SHA256_329="19a9c1841124ac5a61741f96e1d9e2ec77424bf323962dd894bdb93f37d5219b" |
|
| 997 | - | SOURCE_FILENAME_329="sqlx-macros-core-0.8.6.tar.gz" |
|
| 998 | - | SOURCE_URI_330="https://static.crates.io/crates/sqlx-mysql/sqlx-mysql-0.8.6.crate" |
|
| 999 | - | CHECKSUM_SHA256_330="aa003f0038df784eb8fecbbac13affe3da23b45194bd57dba231c8f48199c526" |
|
| 1000 | - | SOURCE_FILENAME_330="sqlx-mysql-0.8.6.tar.gz" |
|
| 1001 | - | SOURCE_URI_331="https://static.crates.io/crates/sqlx-postgres/sqlx-postgres-0.8.6.crate" |
|
| 1002 | - | CHECKSUM_SHA256_331="db58fcd5a53cf07c184b154801ff91347e4c30d17a3562a635ff028ad5deda46" |
|
| 1003 | - | SOURCE_FILENAME_331="sqlx-postgres-0.8.6.tar.gz" |
|
| 1004 | - | SOURCE_URI_332="https://static.crates.io/crates/sqlx-sqlite/sqlx-sqlite-0.8.6.crate" |
|
| 1005 | - | CHECKSUM_SHA256_332="c2d12fe70b2c1b4401038055f90f151b78208de1f9f89a7dbfd41587a10c3eea" |
|
| 1006 | - | SOURCE_FILENAME_332="sqlx-sqlite-0.8.6.tar.gz" |
|
| 1007 | - | SOURCE_URI_333="https://static.crates.io/crates/stable_deref_trait/stable_deref_trait-1.2.1.crate" |
|
| 1008 | - | CHECKSUM_SHA256_333="6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" |
|
| 1009 | - | SOURCE_FILENAME_333="stable_deref_trait-1.2.1.tar.gz" |
|
| 1010 | - | SOURCE_URI_334="https://static.crates.io/crates/streaming-iterator/streaming-iterator-0.1.9.crate" |
|
| 1011 | - | CHECKSUM_SHA256_334="2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" |
|
| 1012 | - | SOURCE_FILENAME_334="streaming-iterator-0.1.9.tar.gz" |
|
| 1013 | - | SOURCE_URI_335="https://static.crates.io/crates/string_cache/string_cache-0.11.0.crate" |
|
| 1014 | - | CHECKSUM_SHA256_335="ffa8a5dbe8b3f0bbe29d4c3225daafaeead63afdc1b65fc4c01a1384166038e6" |
|
| 1015 | - | SOURCE_FILENAME_335="string_cache-0.11.0.tar.gz" |
|
| 1016 | - | SOURCE_URI_336="https://static.crates.io/crates/string_cache_codegen/string_cache_codegen-0.11.2.crate" |
|
| 1017 | - | CHECKSUM_SHA256_336="928dcdf75e47626b3617a976ec205d9f057584c371c1f23b782129268d0e6edc" |
|
| 1018 | - | SOURCE_FILENAME_336="string_cache_codegen-0.11.2.tar.gz" |
|
| 1019 | - | SOURCE_URI_337="https://static.crates.io/crates/stringprep/stringprep-0.1.5.crate" |
|
| 1020 | - | CHECKSUM_SHA256_337="7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1" |
|
| 1021 | - | SOURCE_FILENAME_337="stringprep-0.1.5.tar.gz" |
|
| 1022 | - | SOURCE_URI_338="https://static.crates.io/crates/strsim/strsim-0.11.1.crate" |
|
| 1023 | - | CHECKSUM_SHA256_338="7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" |
|
| 1024 | - | SOURCE_FILENAME_338="strsim-0.11.1.tar.gz" |
|
| 1025 | - | SOURCE_URI_339="https://static.crates.io/crates/subtle/subtle-2.6.1.crate" |
|
| 1026 | - | CHECKSUM_SHA256_339="13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" |
|
| 1027 | - | SOURCE_FILENAME_339="subtle-2.6.1.tar.gz" |
|
| 1028 | - | SOURCE_URI_340="https://static.crates.io/crates/syn/syn-2.0.119.crate" |
|
| 1029 | - | CHECKSUM_SHA256_340="872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" |
|
| 1030 | - | SOURCE_FILENAME_340="syn-2.0.119.tar.gz" |
|
| 1031 | - | SOURCE_URI_341="https://static.crates.io/crates/syn/syn-3.0.6.crate" |
|
| 1032 | - | CHECKSUM_SHA256_341="8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" |
|
| 1033 | - | SOURCE_FILENAME_341="syn-3.0.6.tar.gz" |
|
| 1034 | - | SOURCE_URI_342="https://static.crates.io/crates/sync_wrapper/sync_wrapper-1.0.2.crate" |
|
| 1035 | - | CHECKSUM_SHA256_342="0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" |
|
| 1036 | - | SOURCE_FILENAME_342="sync_wrapper-1.0.2.tar.gz" |
|
| 1037 | - | SOURCE_URI_343="https://static.crates.io/crates/synstructure/synstructure-0.13.2.crate" |
|
| 1038 | - | CHECKSUM_SHA256_343="728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" |
|
| 1039 | - | SOURCE_FILENAME_343="synstructure-0.13.2.tar.gz" |
|
| 1040 | - | SOURCE_URI_344="https://static.crates.io/crates/synstructure/synstructure-0.14.0.crate" |
|
| 1041 | - | CHECKSUM_SHA256_344="901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" |
|
| 1042 | - | SOURCE_FILENAME_344="synstructure-0.14.0.tar.gz" |
|
| 1043 | - | SOURCE_URI_345="https://static.crates.io/crates/syntect/syntect-5.3.0.crate" |
|
| 1044 | - | CHECKSUM_SHA256_345="656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" |
|
| 1045 | - | SOURCE_FILENAME_345="syntect-5.3.0.tar.gz" |
|
| 1046 | - | SOURCE_URI_346="https://static.crates.io/crates/tar/tar-0.4.46.crate" |
|
| 1047 | - | CHECKSUM_SHA256_346="3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" |
|
| 1048 | - | SOURCE_FILENAME_346="tar-0.4.46.tar.gz" |
|
| 1049 | - | SOURCE_URI_347="https://static.crates.io/crates/tempfile/tempfile-3.27.0.crate" |
|
| 1050 | - | CHECKSUM_SHA256_347="32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" |
|
| 1051 | - | SOURCE_FILENAME_347="tempfile-3.27.0.tar.gz" |
|
| 1052 | - | SOURCE_URI_348="https://static.crates.io/crates/tendril/tendril-0.5.1.crate" |
|
| 1053 | - | CHECKSUM_SHA256_348="5fed54709c5b3a53d09bb1c113ea4f5ceafd1e772ddcb0030a82e1d56c087b08" |
|
| 1054 | - | SOURCE_FILENAME_348="tendril-0.5.1.tar.gz" |
|
| 1055 | - | SOURCE_URI_349="https://static.crates.io/crates/thiserror/thiserror-1.0.69.crate" |
|
| 1056 | - | CHECKSUM_SHA256_349="b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" |
|
| 1057 | - | SOURCE_FILENAME_349="thiserror-1.0.69.tar.gz" |
|
| 1058 | - | SOURCE_URI_350="https://static.crates.io/crates/thiserror/thiserror-2.0.21.crate" |
|
| 1059 | - | CHECKSUM_SHA256_350="09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" |
|
| 1060 | - | SOURCE_FILENAME_350="thiserror-2.0.21.tar.gz" |
|
| 1061 | - | SOURCE_URI_351="https://static.crates.io/crates/thiserror-impl/thiserror-impl-1.0.69.crate" |
|
| 1062 | - | CHECKSUM_SHA256_351="4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" |
|
| 1063 | - | SOURCE_FILENAME_351="thiserror-impl-1.0.69.tar.gz" |
|
| 1064 | - | SOURCE_URI_352="https://static.crates.io/crates/thiserror-impl/thiserror-impl-2.0.21.crate" |
|
| 1065 | - | CHECKSUM_SHA256_352="fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" |
|
| 1066 | - | SOURCE_FILENAME_352="thiserror-impl-2.0.21.tar.gz" |
|
| 1067 | - | SOURCE_URI_353="https://static.crates.io/crates/thread_local/thread_local-1.1.10.crate" |
|
| 1068 | - | CHECKSUM_SHA256_353="1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" |
|
| 1069 | - | SOURCE_FILENAME_353="thread_local-1.1.10.tar.gz" |
|
| 1070 | - | SOURCE_URI_354="https://static.crates.io/crates/time/time-0.3.55.crate" |
|
| 1071 | - | CHECKSUM_SHA256_354="cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" |
|
| 1072 | - | SOURCE_FILENAME_354="time-0.3.55.tar.gz" |
|
| 1073 | - | SOURCE_URI_355="https://static.crates.io/crates/time-core/time-core-0.1.9.crate" |
|
| 1074 | - | CHECKSUM_SHA256_355="9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" |
|
| 1075 | - | SOURCE_FILENAME_355="time-core-0.1.9.tar.gz" |
|
| 1076 | - | SOURCE_URI_356="https://static.crates.io/crates/time-macros/time-macros-0.2.32.crate" |
|
| 1077 | - | CHECKSUM_SHA256_356="7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" |
|
| 1078 | - | SOURCE_FILENAME_356="time-macros-0.2.32.tar.gz" |
|
| 1079 | - | SOURCE_URI_357="https://static.crates.io/crates/tinystr/tinystr-0.8.4.crate" |
|
| 1080 | - | CHECKSUM_SHA256_357="b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" |
|
| 1081 | - | SOURCE_FILENAME_357="tinystr-0.8.4.tar.gz" |
|
| 1082 | - | SOURCE_URI_358="https://static.crates.io/crates/tinyvec/tinyvec-1.13.3.crate" |
|
| 1083 | - | CHECKSUM_SHA256_358="fd3ca314f692efd6c868f8408f53fe444634a845f96c028b97d35f6a1f79f0ee" |
|
| 1084 | - | SOURCE_FILENAME_358="tinyvec-1.13.3.tar.gz" |
|
| 1085 | - | SOURCE_URI_359="https://static.crates.io/crates/tokio/tokio-1.53.1.crate" |
|
| 1086 | - | CHECKSUM_SHA256_359="202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" |
|
| 1087 | - | SOURCE_FILENAME_359="tokio-1.53.1.tar.gz" |
|
| 1088 | - | SOURCE_URI_360="https://static.crates.io/crates/tokio-macros/tokio-macros-2.7.2.crate" |
|
| 1089 | - | CHECKSUM_SHA256_360="78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" |
|
| 1090 | - | SOURCE_FILENAME_360="tokio-macros-2.7.2.tar.gz" |
|
| 1091 | - | SOURCE_URI_361="https://static.crates.io/crates/tokio-rustls/tokio-rustls-0.26.5.crate" |
|
| 1092 | - | CHECKSUM_SHA256_361="b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" |
|
| 1093 | - | SOURCE_FILENAME_361="tokio-rustls-0.26.5.tar.gz" |
|
| 1094 | - | SOURCE_URI_362="https://static.crates.io/crates/tokio-stream/tokio-stream-0.1.19.crate" |
|
| 1095 | - | CHECKSUM_SHA256_362="a3d06f0b082ba57c26b79407372e57cf2a1e28124f78e9479fe80322cf53420b" |
|
| 1096 | - | SOURCE_FILENAME_362="tokio-stream-0.1.19.tar.gz" |
|
| 1097 | - | SOURCE_URI_363="https://static.crates.io/crates/tokio-util/tokio-util-0.7.19.crate" |
|
| 1098 | - | CHECKSUM_SHA256_363="494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" |
|
| 1099 | - | SOURCE_FILENAME_363="tokio-util-0.7.19.tar.gz" |
|
| 1100 | - | SOURCE_URI_364="https://static.crates.io/crates/toml/toml-0.8.23.crate" |
|
| 1101 | - | CHECKSUM_SHA256_364="dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" |
|
| 1102 | - | SOURCE_FILENAME_364="toml-0.8.23.tar.gz" |
|
| 1103 | - | SOURCE_URI_365="https://static.crates.io/crates/toml_datetime/toml_datetime-0.6.11.crate" |
|
| 1104 | - | CHECKSUM_SHA256_365="22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" |
|
| 1105 | - | SOURCE_FILENAME_365="toml_datetime-0.6.11.tar.gz" |
|
| 1106 | - | SOURCE_URI_366="https://static.crates.io/crates/toml_edit/toml_edit-0.22.27.crate" |
|
| 1107 | - | CHECKSUM_SHA256_366="41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" |
|
| 1108 | - | SOURCE_FILENAME_366="toml_edit-0.22.27.tar.gz" |
|
| 1109 | - | SOURCE_URI_367="https://static.crates.io/crates/toml_write/toml_write-0.1.2.crate" |
|
| 1110 | - | CHECKSUM_SHA256_367="5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" |
|
| 1111 | - | SOURCE_FILENAME_367="toml_write-0.1.2.tar.gz" |
|
| 1112 | - | SOURCE_URI_368="https://static.crates.io/crates/tower/tower-0.5.3.crate" |
|
| 1113 | - | CHECKSUM_SHA256_368="ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" |
|
| 1114 | - | SOURCE_FILENAME_368="tower-0.5.3.tar.gz" |
|
| 1115 | - | SOURCE_URI_369="https://static.crates.io/crates/tower-http/tower-http-0.6.11.crate" |
|
| 1116 | - | CHECKSUM_SHA256_369="4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" |
|
| 1117 | - | SOURCE_FILENAME_369="tower-http-0.6.11.tar.gz" |
|
| 1118 | - | SOURCE_URI_370="https://static.crates.io/crates/tower-layer/tower-layer-0.3.3.crate" |
|
| 1119 | - | CHECKSUM_SHA256_370="121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" |
|
| 1120 | - | SOURCE_FILENAME_370="tower-layer-0.3.3.tar.gz" |
|
| 1121 | - | SOURCE_URI_371="https://static.crates.io/crates/tower-service/tower-service-0.3.3.crate" |
|
| 1122 | - | CHECKSUM_SHA256_371="8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" |
|
| 1123 | - | SOURCE_FILENAME_371="tower-service-0.3.3.tar.gz" |
|
| 1124 | - | SOURCE_URI_372="https://static.crates.io/crates/tracing/tracing-0.1.44.crate" |
|
| 1125 | - | CHECKSUM_SHA256_372="63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" |
|
| 1126 | - | SOURCE_FILENAME_372="tracing-0.1.44.tar.gz" |
|
| 1127 | - | SOURCE_URI_373="https://static.crates.io/crates/tracing-attributes/tracing-attributes-0.1.31.crate" |
|
| 1128 | - | CHECKSUM_SHA256_373="7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" |
|
| 1129 | - | SOURCE_FILENAME_373="tracing-attributes-0.1.31.tar.gz" |
|
| 1130 | - | SOURCE_URI_374="https://static.crates.io/crates/tracing-core/tracing-core-0.1.36.crate" |
|
| 1131 | - | CHECKSUM_SHA256_374="db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" |
|
| 1132 | - | SOURCE_FILENAME_374="tracing-core-0.1.36.tar.gz" |
|
| 1133 | - | SOURCE_URI_375="https://static.crates.io/crates/tracing-log/tracing-log-0.2.0.crate" |
|
| 1134 | - | CHECKSUM_SHA256_375="ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" |
|
| 1135 | - | SOURCE_FILENAME_375="tracing-log-0.2.0.tar.gz" |
|
| 1136 | - | SOURCE_URI_376="https://static.crates.io/crates/tracing-subscriber/tracing-subscriber-0.3.23.crate" |
|
| 1137 | - | CHECKSUM_SHA256_376="cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" |
|
| 1138 | - | SOURCE_FILENAME_376="tracing-subscriber-0.3.23.tar.gz" |
|
| 1139 | - | SOURCE_URI_377="https://static.crates.io/crates/tree-sitter/tree-sitter-0.27.0.crate" |
|
| 1140 | - | CHECKSUM_SHA256_377="2038684e0058edba0d17302619f62eabce4a8e11c6ac59506996a8d79848851d" |
|
| 1141 | - | SOURCE_FILENAME_377="tree-sitter-0.27.0.tar.gz" |
|
| 1142 | - | SOURCE_URI_378="https://static.crates.io/crates/tree-sitter-bash/tree-sitter-bash-0.25.1.crate" |
|
| 1143 | - | CHECKSUM_SHA256_378="9e5ec769279cc91b561d3df0d8a5deb26b0ad40d183127f409494d6d8fc53062" |
|
| 1144 | - | SOURCE_FILENAME_378="tree-sitter-bash-0.25.1.tar.gz" |
|
| 1145 | - | SOURCE_URI_379="https://static.crates.io/crates/tree-sitter-language/tree-sitter-language-0.1.8.crate" |
|
| 1146 | - | CHECKSUM_SHA256_379="ca0d1bf6fdd806e43ae5198f82f527056d359def39e54e67a0f478ac09dac081" |
|
| 1147 | - | SOURCE_FILENAME_379="tree-sitter-language-0.1.8.tar.gz" |
|
| 1148 | - | SOURCE_URI_380="https://static.crates.io/crates/tree-sitter-python/tree-sitter-python-0.25.0.crate" |
|
| 1149 | - | CHECKSUM_SHA256_380="6bf85fd39652e740bf60f46f4cda9492c3a9ad75880575bf14960f775cb74a1c" |
|
| 1150 | - | SOURCE_FILENAME_380="tree-sitter-python-0.25.0.tar.gz" |
|
| 1151 | - | SOURCE_URI_381="https://static.crates.io/crates/tree-sitter-rust/tree-sitter-rust-0.24.2.crate" |
|
| 1152 | - | CHECKSUM_SHA256_381="439e577dbe07423ec2582ac62c7531120dbfccfa6e5f92406f93dd271a120e45" |
|
| 1153 | - | SOURCE_FILENAME_381="tree-sitter-rust-0.24.2.tar.gz" |
|
| 1154 | - | SOURCE_URI_382="https://static.crates.io/crates/tree-sitter-typescript/tree-sitter-typescript-0.23.2.crate" |
|
| 1155 | - | CHECKSUM_SHA256_382="6c5f76ed8d947a75cc446d5fccd8b602ebf0cde64ccf2ffa434d873d7a575eff" |
|
| 1156 | - | SOURCE_FILENAME_382="tree-sitter-typescript-0.23.2.tar.gz" |
|
| 1157 | - | SOURCE_URI_383="https://static.crates.io/crates/try-lock/try-lock-0.2.5.crate" |
|
| 1158 | - | CHECKSUM_SHA256_383="e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" |
|
| 1159 | - | SOURCE_FILENAME_383="try-lock-0.2.5.tar.gz" |
|
| 1160 | - | SOURCE_URI_384="https://static.crates.io/crates/typenum/typenum-1.20.1.crate" |
|
| 1161 | - | CHECKSUM_SHA256_384="b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" |
|
| 1162 | - | SOURCE_FILENAME_384="typenum-1.20.1.tar.gz" |
|
| 1163 | - | SOURCE_URI_385="https://static.crates.io/crates/unicase/unicase-2.9.0.crate" |
|
| 1164 | - | CHECKSUM_SHA256_385="dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" |
|
| 1165 | - | SOURCE_FILENAME_385="unicase-2.9.0.tar.gz" |
|
| 1166 | - | SOURCE_URI_386="https://static.crates.io/crates/unicode-bidi/unicode-bidi-0.3.18.crate" |
|
| 1167 | - | CHECKSUM_SHA256_386="5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" |
|
| 1168 | - | SOURCE_FILENAME_386="unicode-bidi-0.3.18.tar.gz" |
|
| 1169 | - | SOURCE_URI_387="https://static.crates.io/crates/unicode-ident/unicode-ident-1.0.26.crate" |
|
| 1170 | - | CHECKSUM_SHA256_387="d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" |
|
| 1171 | - | SOURCE_FILENAME_387="unicode-ident-1.0.26.tar.gz" |
|
| 1172 | - | SOURCE_URI_388="https://static.crates.io/crates/unicode-normalization/unicode-normalization-0.1.25.crate" |
|
| 1173 | - | CHECKSUM_SHA256_388="5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8" |
|
| 1174 | - | SOURCE_FILENAME_388="unicode-normalization-0.1.25.tar.gz" |
|
| 1175 | - | SOURCE_URI_389="https://static.crates.io/crates/unicode-properties/unicode-properties-0.1.4.crate" |
|
| 1176 | - | CHECKSUM_SHA256_389="7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d" |
|
| 1177 | - | SOURCE_FILENAME_389="unicode-properties-0.1.4.tar.gz" |
|
| 1178 | - | SOURCE_URI_390="https://static.crates.io/crates/unicode-width/unicode-width-0.1.14.crate" |
|
| 1179 | - | CHECKSUM_SHA256_390="7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" |
|
| 1180 | - | SOURCE_FILENAME_390="unicode-width-0.1.14.tar.gz" |
|
| 1181 | - | SOURCE_URI_391="https://static.crates.io/crates/untrusted/untrusted-0.9.0.crate" |
|
| 1182 | - | CHECKSUM_SHA256_391="8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" |
|
| 1183 | - | SOURCE_FILENAME_391="untrusted-0.9.0.tar.gz" |
|
| 1184 | - | SOURCE_URI_392="https://static.crates.io/crates/ureq/ureq-2.12.1.crate" |
|
| 1185 | - | CHECKSUM_SHA256_392="02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" |
|
| 1186 | - | SOURCE_FILENAME_392="ureq-2.12.1.tar.gz" |
|
| 1187 | - | SOURCE_URI_393="https://static.crates.io/crates/url/url-2.5.8.crate" |
|
| 1188 | - | CHECKSUM_SHA256_393="ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" |
|
| 1189 | - | SOURCE_FILENAME_393="url-2.5.8.tar.gz" |
|
| 1190 | - | SOURCE_URI_394="https://static.crates.io/crates/utf8_iter/utf8_iter-1.0.4.crate" |
|
| 1191 | - | CHECKSUM_SHA256_394="b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" |
|
| 1192 | - | SOURCE_FILENAME_394="utf8_iter-1.0.4.tar.gz" |
|
| 1193 | - | SOURCE_URI_395="https://static.crates.io/crates/utf8parse/utf8parse-0.2.2.crate" |
|
| 1194 | - | CHECKSUM_SHA256_395="06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" |
|
| 1195 | - | SOURCE_FILENAME_395="utf8parse-0.2.2.tar.gz" |
|
| 1196 | - | SOURCE_URI_396="https://static.crates.io/crates/valuable/valuable-0.1.1.crate" |
|
| 1197 | - | CHECKSUM_SHA256_396="ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" |
|
| 1198 | - | SOURCE_FILENAME_396="valuable-0.1.1.tar.gz" |
|
| 1199 | - | SOURCE_URI_397="https://static.crates.io/crates/vcpkg/vcpkg-0.2.15.crate" |
|
| 1200 | - | CHECKSUM_SHA256_397="accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" |
|
| 1201 | - | SOURCE_FILENAME_397="vcpkg-0.2.15.tar.gz" |
|
| 1202 | - | SOURCE_URI_398="https://static.crates.io/crates/version_check/version_check-0.9.5.crate" |
|
| 1203 | - | CHECKSUM_SHA256_398="0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" |
|
| 1204 | - | SOURCE_FILENAME_398="version_check-0.9.5.tar.gz" |
|
| 1205 | - | SOURCE_URI_399="https://static.crates.io/crates/walkdir/walkdir-2.5.0.crate" |
|
| 1206 | - | CHECKSUM_SHA256_399="29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" |
|
| 1207 | - | SOURCE_FILENAME_399="walkdir-2.5.0.tar.gz" |
|
| 1208 | - | SOURCE_URI_400="https://static.crates.io/crates/want/want-0.3.1.crate" |
|
| 1209 | - | CHECKSUM_SHA256_400="bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" |
|
| 1210 | - | SOURCE_FILENAME_400="want-0.3.1.tar.gz" |
|
| 1211 | - | SOURCE_URI_401="https://static.crates.io/crates/wasi/wasi-0.11.1+wasi-snapshot-preview1.crate" |
|
| 1212 | - | CHECKSUM_SHA256_401="ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" |
|
| 1213 | - | SOURCE_FILENAME_401="wasi-0.11.1+wasi-snapshot-preview1.tar.gz" |
|
| 1214 | - | SOURCE_URI_402="https://static.crates.io/crates/wasite/wasite-0.1.0.crate" |
|
| 1215 | - | CHECKSUM_SHA256_402="b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" |
|
| 1216 | - | SOURCE_FILENAME_402="wasite-0.1.0.tar.gz" |
|
| 1217 | - | SOURCE_URI_403="https://static.crates.io/crates/wasm-bindgen/wasm-bindgen-0.2.129.crate" |
|
| 1218 | - | CHECKSUM_SHA256_403="9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" |
|
| 1219 | - | SOURCE_FILENAME_403="wasm-bindgen-0.2.129.tar.gz" |
|
| 1220 | - | SOURCE_URI_404="https://static.crates.io/crates/wasm-bindgen-futures/wasm-bindgen-futures-0.4.79.crate" |
|
| 1221 | - | CHECKSUM_SHA256_404="3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e" |
|
| 1222 | - | SOURCE_FILENAME_404="wasm-bindgen-futures-0.4.79.tar.gz" |
|
| 1223 | - | SOURCE_URI_405="https://static.crates.io/crates/wasm-bindgen-macro/wasm-bindgen-macro-0.2.129.crate" |
|
| 1224 | - | CHECKSUM_SHA256_405="2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" |
|
| 1225 | - | SOURCE_FILENAME_405="wasm-bindgen-macro-0.2.129.tar.gz" |
|
| 1226 | - | SOURCE_URI_406="https://static.crates.io/crates/wasm-bindgen-macro-support/wasm-bindgen-macro-support-0.2.129.crate" |
|
| 1227 | - | CHECKSUM_SHA256_406="6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" |
|
| 1228 | - | SOURCE_FILENAME_406="wasm-bindgen-macro-support-0.2.129.tar.gz" |
|
| 1229 | - | SOURCE_URI_407="https://static.crates.io/crates/wasm-bindgen-shared/wasm-bindgen-shared-0.2.129.crate" |
|
| 1230 | - | CHECKSUM_SHA256_407="23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" |
|
| 1231 | - | SOURCE_FILENAME_407="wasm-bindgen-shared-0.2.129.tar.gz" |
|
| 1232 | - | SOURCE_URI_408="https://static.crates.io/crates/web-sys/web-sys-0.3.106.crate" |
|
| 1233 | - | CHECKSUM_SHA256_408="88261b9deccee56594c11a3460c462c41f58d148598fe70ad77070126a68aba4" |
|
| 1234 | - | SOURCE_FILENAME_408="web-sys-0.3.106.tar.gz" |
|
| 1235 | - | SOURCE_URI_409="https://static.crates.io/crates/web-time/web-time-1.1.0.crate" |
|
| 1236 | - | CHECKSUM_SHA256_409="5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" |
|
| 1237 | - | SOURCE_FILENAME_409="web-time-1.1.0.tar.gz" |
|
| 1238 | - | SOURCE_URI_410="https://static.crates.io/crates/web_atoms/web_atoms-0.3.0.crate" |
|
| 1239 | - | CHECKSUM_SHA256_410="7572660c8890448ba236b7376f27e389c6a7e1c70195622faced601f855c0ada" |
|
| 1240 | - | SOURCE_FILENAME_410="web_atoms-0.3.0.tar.gz" |
|
| 1241 | - | SOURCE_URI_411="https://static.crates.io/crates/webpki-roots/webpki-roots-0.26.11.crate" |
|
| 1242 | - | CHECKSUM_SHA256_411="521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" |
|
| 1243 | - | SOURCE_FILENAME_411="webpki-roots-0.26.11.tar.gz" |
|
| 1244 | - | SOURCE_URI_412="https://static.crates.io/crates/webpki-roots/webpki-roots-1.0.9.crate" |
|
| 1245 | - | CHECKSUM_SHA256_412="7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" |
|
| 1246 | - | SOURCE_FILENAME_412="webpki-roots-1.0.9.tar.gz" |
|
| 1247 | - | SOURCE_URI_413="https://static.crates.io/crates/whoami/whoami-1.6.1.crate" |
|
| 1248 | - | CHECKSUM_SHA256_413="5d4a4db5077702ca3015d3d02d74974948aba2ad9e12ab7df718ee64ccd7e97d" |
|
| 1249 | - | SOURCE_FILENAME_413="whoami-1.6.1.tar.gz" |
|
| 1250 | - | SOURCE_URI_414="https://static.crates.io/crates/winapi-util/winapi-util-0.1.11.crate" |
|
| 1251 | - | CHECKSUM_SHA256_414="c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" |
|
| 1252 | - | SOURCE_FILENAME_414="winapi-util-0.1.11.tar.gz" |
|
| 1253 | - | SOURCE_URI_415="https://static.crates.io/crates/windows-core/windows-core-0.62.2.crate" |
|
| 1254 | - | CHECKSUM_SHA256_415="b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" |
|
| 1255 | - | SOURCE_FILENAME_415="windows-core-0.62.2.tar.gz" |
|
| 1256 | - | SOURCE_URI_416="https://static.crates.io/crates/windows-implement/windows-implement-0.60.2.crate" |
|
| 1257 | - | CHECKSUM_SHA256_416="053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" |
|
| 1258 | - | SOURCE_FILENAME_416="windows-implement-0.60.2.tar.gz" |
|
| 1259 | - | SOURCE_URI_417="https://static.crates.io/crates/windows-interface/windows-interface-0.59.3.crate" |
|
| 1260 | - | CHECKSUM_SHA256_417="3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" |
|
| 1261 | - | SOURCE_FILENAME_417="windows-interface-0.59.3.tar.gz" |
|
| 1262 | - | SOURCE_URI_418="https://static.crates.io/crates/windows-link/windows-link-0.2.1.crate" |
|
| 1263 | - | CHECKSUM_SHA256_418="f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" |
|
| 1264 | - | SOURCE_FILENAME_418="windows-link-0.2.1.tar.gz" |
|
| 1265 | - | SOURCE_URI_419="https://static.crates.io/crates/windows-result/windows-result-0.4.1.crate" |
|
| 1266 | - | CHECKSUM_SHA256_419="7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" |
|
| 1267 | - | SOURCE_FILENAME_419="windows-result-0.4.1.tar.gz" |
|
| 1268 | - | SOURCE_URI_420="https://static.crates.io/crates/windows-strings/windows-strings-0.5.1.crate" |
|
| 1269 | - | CHECKSUM_SHA256_420="7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" |
|
| 1270 | - | SOURCE_FILENAME_420="windows-strings-0.5.1.tar.gz" |
|
| 1271 | - | SOURCE_URI_421="https://static.crates.io/crates/windows-sys/windows-sys-0.48.0.crate" |
|
| 1272 | - | CHECKSUM_SHA256_421="677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" |
|
| 1273 | - | SOURCE_FILENAME_421="windows-sys-0.48.0.tar.gz" |
|
| 1274 | - | SOURCE_URI_422="https://static.crates.io/crates/windows-sys/windows-sys-0.52.0.crate" |
|
| 1275 | - | CHECKSUM_SHA256_422="282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" |
|
| 1276 | - | SOURCE_FILENAME_422="windows-sys-0.52.0.tar.gz" |
|
| 1277 | - | SOURCE_URI_423="https://static.crates.io/crates/windows-sys/windows-sys-0.61.2.crate" |
|
| 1278 | - | CHECKSUM_SHA256_423="ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" |
|
| 1279 | - | SOURCE_FILENAME_423="windows-sys-0.61.2.tar.gz" |
|
| 1280 | - | SOURCE_URI_424="https://static.crates.io/crates/windows-targets/windows-targets-0.48.5.crate" |
|
| 1281 | - | CHECKSUM_SHA256_424="9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" |
|
| 1282 | - | SOURCE_FILENAME_424="windows-targets-0.48.5.tar.gz" |
|
| 1283 | - | SOURCE_URI_425="https://static.crates.io/crates/windows-targets/windows-targets-0.52.6.crate" |
|
| 1284 | - | CHECKSUM_SHA256_425="9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" |
|
| 1285 | - | SOURCE_FILENAME_425="windows-targets-0.52.6.tar.gz" |
|
| 1286 | - | SOURCE_URI_426="https://static.crates.io/crates/windows_aarch64_gnullvm/windows_aarch64_gnullvm-0.48.5.crate" |
|
| 1287 | - | CHECKSUM_SHA256_426="2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" |
|
| 1288 | - | SOURCE_FILENAME_426="windows_aarch64_gnullvm-0.48.5.tar.gz" |
|
| 1289 | - | SOURCE_URI_427="https://static.crates.io/crates/windows_aarch64_gnullvm/windows_aarch64_gnullvm-0.52.6.crate" |
|
| 1290 | - | CHECKSUM_SHA256_427="32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" |
|
| 1291 | - | SOURCE_FILENAME_427="windows_aarch64_gnullvm-0.52.6.tar.gz" |
|
| 1292 | - | SOURCE_URI_428="https://static.crates.io/crates/windows_aarch64_msvc/windows_aarch64_msvc-0.48.5.crate" |
|
| 1293 | - | CHECKSUM_SHA256_428="dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" |
|
| 1294 | - | SOURCE_FILENAME_428="windows_aarch64_msvc-0.48.5.tar.gz" |
|
| 1295 | - | SOURCE_URI_429="https://static.crates.io/crates/windows_aarch64_msvc/windows_aarch64_msvc-0.52.6.crate" |
|
| 1296 | - | CHECKSUM_SHA256_429="09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" |
|
| 1297 | - | SOURCE_FILENAME_429="windows_aarch64_msvc-0.52.6.tar.gz" |
|
| 1298 | - | SOURCE_URI_430="https://static.crates.io/crates/windows_i686_gnu/windows_i686_gnu-0.48.5.crate" |
|
| 1299 | - | CHECKSUM_SHA256_430="a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" |
|
| 1300 | - | SOURCE_FILENAME_430="windows_i686_gnu-0.48.5.tar.gz" |
|
| 1301 | - | SOURCE_URI_431="https://static.crates.io/crates/windows_i686_gnu/windows_i686_gnu-0.52.6.crate" |
|
| 1302 | - | CHECKSUM_SHA256_431="8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" |
|
| 1303 | - | SOURCE_FILENAME_431="windows_i686_gnu-0.52.6.tar.gz" |
|
| 1304 | - | SOURCE_URI_432="https://static.crates.io/crates/windows_i686_gnullvm/windows_i686_gnullvm-0.52.6.crate" |
|
| 1305 | - | CHECKSUM_SHA256_432="0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" |
|
| 1306 | - | SOURCE_FILENAME_432="windows_i686_gnullvm-0.52.6.tar.gz" |
|
| 1307 | - | SOURCE_URI_433="https://static.crates.io/crates/windows_i686_msvc/windows_i686_msvc-0.48.5.crate" |
|
| 1308 | - | CHECKSUM_SHA256_433="8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" |
|
| 1309 | - | SOURCE_FILENAME_433="windows_i686_msvc-0.48.5.tar.gz" |
|
| 1310 | - | SOURCE_URI_434="https://static.crates.io/crates/windows_i686_msvc/windows_i686_msvc-0.52.6.crate" |
|
| 1311 | - | CHECKSUM_SHA256_434="240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" |
|
| 1312 | - | SOURCE_FILENAME_434="windows_i686_msvc-0.52.6.tar.gz" |
|
| 1313 | - | SOURCE_URI_435="https://static.crates.io/crates/windows_x86_64_gnu/windows_x86_64_gnu-0.48.5.crate" |
|
| 1314 | - | CHECKSUM_SHA256_435="53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" |
|
| 1315 | - | SOURCE_FILENAME_435="windows_x86_64_gnu-0.48.5.tar.gz" |
|
| 1316 | - | SOURCE_URI_436="https://static.crates.io/crates/windows_x86_64_gnu/windows_x86_64_gnu-0.52.6.crate" |
|
| 1317 | - | CHECKSUM_SHA256_436="147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" |
|
| 1318 | - | SOURCE_FILENAME_436="windows_x86_64_gnu-0.52.6.tar.gz" |
|
| 1319 | - | SOURCE_URI_437="https://static.crates.io/crates/windows_x86_64_gnullvm/windows_x86_64_gnullvm-0.48.5.crate" |
|
| 1320 | - | CHECKSUM_SHA256_437="0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" |
|
| 1321 | - | SOURCE_FILENAME_437="windows_x86_64_gnullvm-0.48.5.tar.gz" |
|
| 1322 | - | SOURCE_URI_438="https://static.crates.io/crates/windows_x86_64_gnullvm/windows_x86_64_gnullvm-0.52.6.crate" |
|
| 1323 | - | CHECKSUM_SHA256_438="24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" |
|
| 1324 | - | SOURCE_FILENAME_438="windows_x86_64_gnullvm-0.52.6.tar.gz" |
|
| 1325 | - | SOURCE_URI_439="https://static.crates.io/crates/windows_x86_64_msvc/windows_x86_64_msvc-0.48.5.crate" |
|
| 1326 | - | CHECKSUM_SHA256_439="ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" |
|
| 1327 | - | SOURCE_FILENAME_439="windows_x86_64_msvc-0.48.5.tar.gz" |
|
| 1328 | - | SOURCE_URI_440="https://static.crates.io/crates/windows_x86_64_msvc/windows_x86_64_msvc-0.52.6.crate" |
|
| 1329 | - | CHECKSUM_SHA256_440="589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" |
|
| 1330 | - | SOURCE_FILENAME_440="windows_x86_64_msvc-0.52.6.tar.gz" |
|
| 1331 | - | SOURCE_URI_441="https://static.crates.io/crates/winnow/winnow-0.7.15.crate" |
|
| 1332 | - | CHECKSUM_SHA256_441="df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" |
|
| 1333 | - | SOURCE_FILENAME_441="winnow-0.7.15.tar.gz" |
|
| 1334 | - | SOURCE_URI_442="https://static.crates.io/crates/writeable/writeable-0.6.4.crate" |
|
| 1335 | - | CHECKSUM_SHA256_442="3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" |
|
| 1336 | - | SOURCE_FILENAME_442="writeable-0.6.4.tar.gz" |
|
| 1337 | - | SOURCE_URI_443="https://static.crates.io/crates/x509-parser/x509-parser-0.18.1.crate" |
|
| 1338 | - | CHECKSUM_SHA256_443="d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" |
|
| 1339 | - | SOURCE_FILENAME_443="x509-parser-0.18.1.tar.gz" |
|
| 1340 | - | SOURCE_URI_444="https://static.crates.io/crates/xattr/xattr-1.6.1.crate" |
|
| 1341 | - | CHECKSUM_SHA256_444="32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" |
|
| 1342 | - | SOURCE_FILENAME_444="xattr-1.6.1.tar.gz" |
|
| 1343 | - | SOURCE_URI_445="https://static.crates.io/crates/yaml-rust/yaml-rust-0.4.5.crate" |
|
| 1344 | - | CHECKSUM_SHA256_445="56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" |
|
| 1345 | - | SOURCE_FILENAME_445="yaml-rust-0.4.5.tar.gz" |
|
| 1346 | - | SOURCE_URI_446="https://static.crates.io/crates/yasna/yasna-0.6.0.crate" |
|
| 1347 | - | CHECKSUM_SHA256_446="b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" |
|
| 1348 | - | SOURCE_FILENAME_446="yasna-0.6.0.tar.gz" |
|
| 1349 | - | SOURCE_URI_447="https://static.crates.io/crates/yoke/yoke-0.8.3.crate" |
|
| 1350 | - | CHECKSUM_SHA256_447="709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" |
|
| 1351 | - | SOURCE_FILENAME_447="yoke-0.8.3.tar.gz" |
|
| 1352 | - | SOURCE_URI_448="https://static.crates.io/crates/yoke-derive/yoke-derive-0.8.3.crate" |
|
| 1353 | - | CHECKSUM_SHA256_448="33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" |
|
| 1354 | - | SOURCE_FILENAME_448="yoke-derive-0.8.3.tar.gz" |
|
| 1355 | - | SOURCE_URI_449="https://static.crates.io/crates/zerocopy/zerocopy-0.8.59.crate" |
|
| 1356 | - | CHECKSUM_SHA256_449="6df92bf3d9227be3d53173901ddbffac2babc27ae50f397776ffd6dc33f800cb" |
|
| 1357 | - | SOURCE_FILENAME_449="zerocopy-0.8.59.tar.gz" |
|
| 1358 | - | SOURCE_URI_450="https://static.crates.io/crates/zerocopy-derive/zerocopy-derive-0.8.59.crate" |
|
| 1359 | - | CHECKSUM_SHA256_450="ac4f328cf2f05d084e496c3e9c3f33ed0a183656a16e1fcec4d464d8373aec82" |
|
| 1360 | - | SOURCE_FILENAME_450="zerocopy-derive-0.8.59.tar.gz" |
|
| 1361 | - | SOURCE_URI_451="https://static.crates.io/crates/zerofrom/zerofrom-0.1.8.crate" |
|
| 1362 | - | CHECKSUM_SHA256_451="0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" |
|
| 1363 | - | SOURCE_FILENAME_451="zerofrom-0.1.8.tar.gz" |
|
| 1364 | - | SOURCE_URI_452="https://static.crates.io/crates/zerofrom-derive/zerofrom-derive-0.1.8.crate" |
|
| 1365 | - | CHECKSUM_SHA256_452="f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" |
|
| 1366 | - | SOURCE_FILENAME_452="zerofrom-derive-0.1.8.tar.gz" |
|
| 1367 | - | SOURCE_URI_453="https://static.crates.io/crates/zeroize/zeroize-1.9.0.crate" |
|
| 1368 | - | CHECKSUM_SHA256_453="e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" |
|
| 1369 | - | SOURCE_FILENAME_453="zeroize-1.9.0.tar.gz" |
|
| 1370 | - | SOURCE_URI_454="https://static.crates.io/crates/zerotrie/zerotrie-0.2.5.crate" |
|
| 1371 | - | CHECKSUM_SHA256_454="4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" |
|
| 1372 | - | SOURCE_FILENAME_454="zerotrie-0.2.5.tar.gz" |
|
| 1373 | - | SOURCE_URI_455="https://static.crates.io/crates/zerovec/zerovec-0.11.8.crate" |
|
| 1374 | - | CHECKSUM_SHA256_455="bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" |
|
| 1375 | - | SOURCE_FILENAME_455="zerovec-0.11.8.tar.gz" |
|
| 1376 | - | SOURCE_URI_456="https://static.crates.io/crates/zerovec-derive/zerovec-derive-0.11.6.crate" |
|
| 1377 | - | CHECKSUM_SHA256_456="34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" |
|
| 1378 | - | SOURCE_FILENAME_456="zerovec-derive-0.11.6.tar.gz" |
|
| 1379 | - | SOURCE_URI_457="https://static.crates.io/crates/zip/zip-2.4.2.crate" |
|
| 1380 | - | CHECKSUM_SHA256_457="fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" |
|
| 1381 | - | SOURCE_FILENAME_457="zip-2.4.2.tar.gz" |
|
| 1382 | - | SOURCE_URI_458="https://static.crates.io/crates/zlib-rs/zlib-rs-0.6.8.crate" |
|
| 1383 | - | CHECKSUM_SHA256_458="b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" |
|
| 1384 | - | SOURCE_FILENAME_458="zlib-rs-0.6.8.tar.gz" |
|
| 1385 | - | SOURCE_URI_459="https://static.crates.io/crates/zmij/zmij-1.0.23.crate" |
|
| 1386 | - | CHECKSUM_SHA256_459="29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" |
|
| 1387 | - | SOURCE_FILENAME_459="zmij-1.0.23.tar.gz" |
|
| 1388 | - | SOURCE_URI_460="https://static.crates.io/crates/zopfli/zopfli-0.8.3.crate" |
|
| 1389 | - | CHECKSUM_SHA256_460="f05cd8797d63865425ff89b5c4a48804f35ba0ce8d125800027ad6017d2b5249" |
|
| 1390 | - | SOURCE_FILENAME_460="zopfli-0.8.3.tar.gz" |
|
| 1391 | - | SOURCE_URI_461="https://static.crates.io/crates/zstd/zstd-0.13.3.crate" |
|
| 1392 | - | CHECKSUM_SHA256_461="e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" |
|
| 1393 | - | SOURCE_FILENAME_461="zstd-0.13.3.tar.gz" |
|
| 1394 | - | SOURCE_URI_462="https://static.crates.io/crates/zstd-safe/zstd-safe-7.3.0.crate" |
|
| 1395 | - | CHECKSUM_SHA256_462="64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" |
|
| 1396 | - | SOURCE_FILENAME_462="zstd-safe-7.3.0.tar.gz" |
|
| 1397 | - | SOURCE_URI_463="https://static.crates.io/crates/zstd-sys/zstd-sys-2.1.0+zstd.1.5.7.crate" |
|
| 1398 | - | CHECKSUM_SHA256_463="0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" |
|
| 1399 | - | SOURCE_FILENAME_463="zstd-sys-2.1.0+zstd.1.5.7.tar.gz" |
|
| 1400 | - | SOURCE_URI_464="https://static.crates.io/crates/zune-core/zune-core-0.5.3.crate" |
|
| 1401 | - | CHECKSUM_SHA256_464="d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" |
|
| 1402 | - | SOURCE_FILENAME_464="zune-core-0.5.3.tar.gz" |
|
| 1403 | - | SOURCE_URI_465="https://static.crates.io/crates/zune-jpeg/zune-jpeg-0.5.15.crate" |
|
| 1404 | - | CHECKSUM_SHA256_465="27bc9d5b815bc103f142aa054f561d9187d191692ec7c2d1e2b4737f8dbd7296" |
|
| 1405 | - | SOURCE_FILENAME_465="zune-jpeg-0.5.15.tar.gz" |
|
| 1406 | - | ||
| 1407 | - | ARCHITECTURES="!all x86_64" |
|
| 1408 | - | ||
| 1409 | - | PROVIDES=" |
|
| 1410 | - | oh$secondaryArchSuffix = $portVersion |
|
| 1411 | - | cmd:oh |
|
| 1412 | - | " |
|
| 1413 | - | REQUIRES=" |
|
| 1414 | - | haiku$secondaryArchSuffix |
|
| 1415 | - | lib:libzstd$secondaryArchSuffix |
|
| 1416 | - | " |
|
| 1417 | - | ||
| 1418 | - | BUILD_REQUIRES=" |
|
| 1419 | - | haiku${secondaryArchSuffix}_devel |
|
| 1420 | - | devel:libzstd$secondaryArchSuffix |
|
| 1421 | - | " |
|
| 1422 | - | BUILD_PREREQUIRES=" |
|
| 1423 | - | cmd:gcc$secondaryArchSuffix |
|
| 1424 | - | cmd:pkg_config$secondaryArchSuffix |
|
| 1425 | - | cmd:rustc$secondaryArchSuffix |
|
| 1426 | - | " |
|
| 1427 | - | ||
| 1428 | - | BUILD() |
|
| 1429 | - | { |
|
| 1430 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 1431 | - | vendor=$CARGO_HOME/haiku |
|
| 1432 | - | mkdir -p "$vendor" |
|
| 1433 | - | for i in $(seq 2 465); do |
|
| 1434 | - | eval "srcDir=\$sourceDir$i" |
|
| 1435 | - | eval "sha256sum=\$CHECKSUM_SHA256_$i" |
|
| 1436 | - | set -- "$srcDir"/* |
|
| 1437 | - | ln -sf "$1" "$vendor" |
|
| 1438 | - | cat <<-EOF >"$vendor/${1##*/}/.cargo-checksum.json" |
|
| 1439 | - | { |
|
| 1440 | - | "package": "$sha256sum", |
|
| 1441 | - | "files": {} |
|
| 1442 | - | } |
|
| 1443 | - | EOF |
|
| 1444 | - | done |
|
| 1445 | - | ||
| 1446 | - | cat <<-EOF >"$CARGO_HOME"/config.toml |
|
| 1447 | - | [source.haiku] |
|
| 1448 | - | directory = "$vendor" |
|
| 1449 | - | ||
| 1450 | - | [source.crates-io] |
|
| 1451 | - | replace-with = "haiku" |
|
| 1452 | - | EOF |
|
| 1453 | - | ||
| 1454 | - | # The bundled zstd's hidden symbols break the link on Haiku: use the system's. |
|
| 1455 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 1456 | - | export OXY_BUILD=v$portVersion |
|
| 1457 | - | cargo build --release --frozen -p oh |
|
| 1458 | - | } |
|
| 1459 | - | ||
| 1460 | - | INSTALL() |
|
| 1461 | - | { |
|
| 1462 | - | install -v -m 755 -d "$prefix"/bin "$docDir" |
|
| 1463 | - | install -v -m 755 ./target/release/oh "$prefix"/bin |
|
| 1464 | - | install -v -m 644 README.md LICENSE docs/oh.md "$docDir" |
|
| 1465 | - | } |
|
| 1466 | - | ||
| 1467 | - | TEST() |
|
| 1468 | - | { |
|
| 1469 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 1470 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 1471 | - | cargo test --release --frozen -p hub-api |
|
| 1472 | - | } |
removed packaging/haikuports/dev-vcs/oxy/oxy-0.9.0.recipe +0 −990
| 1 | - | SUMMARY="A version control system of signed, commuting changes, with Git interop" |
|
| 2 | - | DESCRIPTION="oxy is the command line of Oxygen, a version control system built on \ |
|
| 3 | - | patch theory: changes commute, conflicts are recorded rather than blocking, \ |
|
| 4 | - | every change can be signed, and a trust policy says who may move what. It \ |
|
| 5 | - | imports and exports Git history, clones from OxygenHub and other Oxygen \ |
|
| 6 | - | hosts, and keeps repositories on disk or in S3, GCS or Azure buckets." |
|
| 7 | - | HOMEPAGE="https://oxygenhub.io/andymccall/oxygen" |
|
| 8 | - | COPYRIGHT="2026 Andy McCall" |
|
| 9 | - | LICENSE="MIT |
|
| 10 | - | Apache v2" |
|
| 11 | - | REVISION="1" |
|
| 12 | - | SOURCE_URI="$HOMEPAGE/releases/download/v$portVersion/oxy-$portVersion-src.tar.gz" |
|
| 13 | - | CHECKSUM_SHA256="b284392c53677177429b7db7f47b0b3585c766a910654a24ab47a6a75555bb8a" |
|
| 14 | - | SOURCE_DIR="oxygen-$portVersion" |
|
| 15 | - | SOURCE_URI_2="https://static.crates.io/crates/adler2/adler2-2.0.1.crate" |
|
| 16 | - | CHECKSUM_SHA256_2="320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" |
|
| 17 | - | SOURCE_FILENAME_2="adler2-2.0.1.tar.gz" |
|
| 18 | - | SOURCE_URI_3="https://static.crates.io/crates/aho-corasick/aho-corasick-1.1.5.crate" |
|
| 19 | - | CHECKSUM_SHA256_3="c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" |
|
| 20 | - | SOURCE_FILENAME_3="aho-corasick-1.1.5.tar.gz" |
|
| 21 | - | SOURCE_URI_4="https://static.crates.io/crates/android_system_properties/android_system_properties-0.1.6.crate" |
|
| 22 | - | CHECKSUM_SHA256_4="ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" |
|
| 23 | - | SOURCE_FILENAME_4="android_system_properties-0.1.6.tar.gz" |
|
| 24 | - | SOURCE_URI_5="https://static.crates.io/crates/anstream/anstream-1.0.0.crate" |
|
| 25 | - | CHECKSUM_SHA256_5="824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" |
|
| 26 | - | SOURCE_FILENAME_5="anstream-1.0.0.tar.gz" |
|
| 27 | - | SOURCE_URI_6="https://static.crates.io/crates/anstyle/anstyle-1.0.14.crate" |
|
| 28 | - | CHECKSUM_SHA256_6="940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" |
|
| 29 | - | SOURCE_FILENAME_6="anstyle-1.0.14.tar.gz" |
|
| 30 | - | SOURCE_URI_7="https://static.crates.io/crates/anstyle-parse/anstyle-parse-1.0.0.crate" |
|
| 31 | - | CHECKSUM_SHA256_7="52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" |
|
| 32 | - | SOURCE_FILENAME_7="anstyle-parse-1.0.0.tar.gz" |
|
| 33 | - | SOURCE_URI_8="https://static.crates.io/crates/anstyle-query/anstyle-query-1.1.5.crate" |
|
| 34 | - | CHECKSUM_SHA256_8="40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" |
|
| 35 | - | SOURCE_FILENAME_8="anstyle-query-1.1.5.tar.gz" |
|
| 36 | - | SOURCE_URI_9="https://static.crates.io/crates/anstyle-wincon/anstyle-wincon-3.0.11.crate" |
|
| 37 | - | CHECKSUM_SHA256_9="291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" |
|
| 38 | - | SOURCE_FILENAME_9="anstyle-wincon-3.0.11.tar.gz" |
|
| 39 | - | SOURCE_URI_10="https://static.crates.io/crates/anyhow/anyhow-1.0.104.crate" |
|
| 40 | - | CHECKSUM_SHA256_10="330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" |
|
| 41 | - | SOURCE_FILENAME_10="anyhow-1.0.104.tar.gz" |
|
| 42 | - | SOURCE_URI_11="https://static.crates.io/crates/arc-swap/arc-swap-1.9.2.crate" |
|
| 43 | - | CHECKSUM_SHA256_11="c049c0be4daef0b145cb3555416b3b8ef5b7888a38aea1a3a155801fe7b0810b" |
|
| 44 | - | SOURCE_FILENAME_11="arc-swap-1.9.2.tar.gz" |
|
| 45 | - | SOURCE_URI_12="https://static.crates.io/crates/arrayvec/arrayvec-0.7.8.crate" |
|
| 46 | - | CHECKSUM_SHA256_12="d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" |
|
| 47 | - | SOURCE_FILENAME_12="arrayvec-0.7.8.tar.gz" |
|
| 48 | - | SOURCE_URI_13="https://static.crates.io/crates/asn1-rs/asn1-rs-0.7.2.crate" |
|
| 49 | - | CHECKSUM_SHA256_13="b7f43a50ac4fdca5df8e885c21b835997f0a1cdee65494a6847694a98652d9d8" |
|
| 50 | - | SOURCE_FILENAME_13="asn1-rs-0.7.2.tar.gz" |
|
| 51 | - | SOURCE_URI_14="https://static.crates.io/crates/asn1-rs-derive/asn1-rs-derive-0.6.0.crate" |
|
| 52 | - | CHECKSUM_SHA256_14="3109e49b1e4909e9db6515a30c633684d68cdeaa252f215214cb4fa1a5bfee2c" |
|
| 53 | - | SOURCE_FILENAME_14="asn1-rs-derive-0.6.0.tar.gz" |
|
| 54 | - | SOURCE_URI_15="https://static.crates.io/crates/asn1-rs-impl/asn1-rs-impl-0.2.0.crate" |
|
| 55 | - | CHECKSUM_SHA256_15="7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" |
|
| 56 | - | SOURCE_FILENAME_15="asn1-rs-impl-0.2.0.tar.gz" |
|
| 57 | - | SOURCE_URI_16="https://static.crates.io/crates/async-trait/async-trait-0.1.92.crate" |
|
| 58 | - | CHECKSUM_SHA256_16="82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" |
|
| 59 | - | SOURCE_FILENAME_16="async-trait-0.1.92.tar.gz" |
|
| 60 | - | SOURCE_URI_17="https://static.crates.io/crates/atomic-waker/atomic-waker-1.1.2.crate" |
|
| 61 | - | CHECKSUM_SHA256_17="1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" |
|
| 62 | - | SOURCE_FILENAME_17="atomic-waker-1.1.2.tar.gz" |
|
| 63 | - | SOURCE_URI_18="https://static.crates.io/crates/autocfg/autocfg-1.5.1.crate" |
|
| 64 | - | CHECKSUM_SHA256_18="f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" |
|
| 65 | - | SOURCE_FILENAME_18="autocfg-1.5.1.tar.gz" |
|
| 66 | - | SOURCE_URI_19="https://static.crates.io/crates/axum/axum-0.8.9.crate" |
|
| 67 | - | CHECKSUM_SHA256_19="31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" |
|
| 68 | - | SOURCE_FILENAME_19="axum-0.8.9.tar.gz" |
|
| 69 | - | SOURCE_URI_20="https://static.crates.io/crates/axum-core/axum-core-0.5.6.crate" |
|
| 70 | - | CHECKSUM_SHA256_20="08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" |
|
| 71 | - | SOURCE_FILENAME_20="axum-core-0.5.6.tar.gz" |
|
| 72 | - | SOURCE_URI_21="https://static.crates.io/crates/axum-server/axum-server-0.8.0.crate" |
|
| 73 | - | CHECKSUM_SHA256_21="b1df331683d982a0b9492b38127151e6453639cd34926eb9c07d4cd8c6d22bfc" |
|
| 74 | - | SOURCE_FILENAME_21="axum-server-0.8.0.tar.gz" |
|
| 75 | - | SOURCE_URI_22="https://static.crates.io/crates/base64/base64-0.22.1.crate" |
|
| 76 | - | CHECKSUM_SHA256_22="72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" |
|
| 77 | - | SOURCE_FILENAME_22="base64-0.22.1.tar.gz" |
|
| 78 | - | SOURCE_URI_23="https://static.crates.io/crates/base64/base64-0.23.1.crate" |
|
| 79 | - | CHECKSUM_SHA256_23="ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" |
|
| 80 | - | SOURCE_FILENAME_23="base64-0.23.1.tar.gz" |
|
| 81 | - | SOURCE_URI_24="https://static.crates.io/crates/base64ct/base64ct-1.8.3.crate" |
|
| 82 | - | CHECKSUM_SHA256_24="2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" |
|
| 83 | - | SOURCE_FILENAME_24="base64ct-1.8.3.tar.gz" |
|
| 84 | - | SOURCE_URI_25="https://static.crates.io/crates/bit-set/bit-set-0.8.0.crate" |
|
| 85 | - | CHECKSUM_SHA256_25="08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" |
|
| 86 | - | SOURCE_FILENAME_25="bit-set-0.8.0.tar.gz" |
|
| 87 | - | SOURCE_URI_26="https://static.crates.io/crates/bit-vec/bit-vec-0.8.0.crate" |
|
| 88 | - | CHECKSUM_SHA256_26="5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" |
|
| 89 | - | SOURCE_FILENAME_26="bit-vec-0.8.0.tar.gz" |
|
| 90 | - | SOURCE_URI_27="https://static.crates.io/crates/bit-vec/bit-vec-0.9.1.crate" |
|
| 91 | - | CHECKSUM_SHA256_27="b71798fca2c1fe1086445a7258a4bc81e6e49dcd24c8d0dd9a1e57395b603f51" |
|
| 92 | - | SOURCE_FILENAME_27="bit-vec-0.9.1.tar.gz" |
|
| 93 | - | SOURCE_URI_28="https://static.crates.io/crates/bitflags/bitflags-2.13.2.crate" |
|
| 94 | - | CHECKSUM_SHA256_28="3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06" |
|
| 95 | - | SOURCE_FILENAME_28="bitflags-2.13.2.tar.gz" |
|
| 96 | - | SOURCE_URI_29="https://static.crates.io/crates/blake3/blake3-1.8.7.crate" |
|
| 97 | - | CHECKSUM_SHA256_29="6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" |
|
| 98 | - | SOURCE_FILENAME_29="blake3-1.8.7.tar.gz" |
|
| 99 | - | SOURCE_URI_30="https://static.crates.io/crates/block-buffer/block-buffer-0.12.1.crate" |
|
| 100 | - | CHECKSUM_SHA256_30="d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" |
|
| 101 | - | SOURCE_FILENAME_30="block-buffer-0.12.1.tar.gz" |
|
| 102 | - | SOURCE_URI_31="https://static.crates.io/crates/bstr/bstr-1.13.1.crate" |
|
| 103 | - | CHECKSUM_SHA256_31="6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" |
|
| 104 | - | SOURCE_FILENAME_31="bstr-1.13.1.tar.gz" |
|
| 105 | - | SOURCE_URI_32="https://static.crates.io/crates/bumpalo/bumpalo-3.20.3.crate" |
|
| 106 | - | CHECKSUM_SHA256_32="72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" |
|
| 107 | - | SOURCE_FILENAME_32="bumpalo-3.20.3.tar.gz" |
|
| 108 | - | SOURCE_URI_33="https://static.crates.io/crates/bytes/bytes-1.12.1.crate" |
|
| 109 | - | CHECKSUM_SHA256_33="fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" |
|
| 110 | - | SOURCE_FILENAME_33="bytes-1.12.1.tar.gz" |
|
| 111 | - | SOURCE_URI_34="https://static.crates.io/crates/cc/cc-1.5.1.crate" |
|
| 112 | - | CHECKSUM_SHA256_34="f360145194ee8e21db5ee7f3fcd4fe52210864c75c985dae33218202c8bbe040" |
|
| 113 | - | SOURCE_FILENAME_34="cc-1.5.1.tar.gz" |
|
| 114 | - | SOURCE_URI_35="https://static.crates.io/crates/cfg-if/cfg-if-1.0.5.crate" |
|
| 115 | - | CHECKSUM_SHA256_35="4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600" |
|
| 116 | - | SOURCE_FILENAME_35="cfg-if-1.0.5.tar.gz" |
|
| 117 | - | SOURCE_URI_36="https://static.crates.io/crates/chacha20/chacha20-0.10.2.crate" |
|
| 118 | - | CHECKSUM_SHA256_36="65c35e4b699c7e15ccbe7ee35c005e4fc0a278d22238a2857e6ce2dadeda1b06" |
|
| 119 | - | SOURCE_FILENAME_36="chacha20-0.10.2.tar.gz" |
|
| 120 | - | SOURCE_URI_37="https://static.crates.io/crates/chrono/chrono-0.4.45.crate" |
|
| 121 | - | CHECKSUM_SHA256_37="1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" |
|
| 122 | - | SOURCE_FILENAME_37="chrono-0.4.45.tar.gz" |
|
| 123 | - | SOURCE_URI_38="https://static.crates.io/crates/clap/clap-4.6.7.crate" |
|
| 124 | - | CHECKSUM_SHA256_38="aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" |
|
| 125 | - | SOURCE_FILENAME_38="clap-4.6.7.tar.gz" |
|
| 126 | - | SOURCE_URI_39="https://static.crates.io/crates/clap_builder/clap_builder-4.6.7.crate" |
|
| 127 | - | CHECKSUM_SHA256_39="ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" |
|
| 128 | - | SOURCE_FILENAME_39="clap_builder-4.6.7.tar.gz" |
|
| 129 | - | SOURCE_URI_40="https://static.crates.io/crates/clap_complete/clap_complete-4.6.11.crate" |
|
| 130 | - | CHECKSUM_SHA256_40="037e2a1a92236d0aff7e845093f64661d6df4c02c9fcc61a60e9e1d736fa392f" |
|
| 131 | - | SOURCE_FILENAME_40="clap_complete-4.6.11.tar.gz" |
|
| 132 | - | SOURCE_URI_41="https://static.crates.io/crates/clap_derive/clap_derive-4.6.7.crate" |
|
| 133 | - | CHECKSUM_SHA256_41="f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" |
|
| 134 | - | SOURCE_FILENAME_41="clap_derive-4.6.7.tar.gz" |
|
| 135 | - | SOURCE_URI_42="https://static.crates.io/crates/clap_lex/clap_lex-1.1.1.crate" |
|
| 136 | - | CHECKSUM_SHA256_42="1c133bc6a41be0d194c306b5506d15e6feeea7b1d6604bd3f8310dfb2ca96486" |
|
| 137 | - | SOURCE_FILENAME_42="clap_lex-1.1.1.tar.gz" |
|
| 138 | - | SOURCE_URI_43="https://static.crates.io/crates/clap_mangen/clap_mangen-0.3.3.crate" |
|
| 139 | - | CHECKSUM_SHA256_43="211d617eaa4b735c96c9e0228fcbdb5120ef623f2b8cb67ffb84c3e02dbc28a4" |
|
| 140 | - | SOURCE_FILENAME_43="clap_mangen-0.3.3.tar.gz" |
|
| 141 | - | SOURCE_URI_44="https://static.crates.io/crates/cmov/cmov-0.5.4.crate" |
|
| 142 | - | CHECKSUM_SHA256_44="0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" |
|
| 143 | - | SOURCE_FILENAME_44="cmov-0.5.4.tar.gz" |
|
| 144 | - | SOURCE_URI_45="https://static.crates.io/crates/colorchoice/colorchoice-1.0.5.crate" |
|
| 145 | - | CHECKSUM_SHA256_45="1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" |
|
| 146 | - | SOURCE_FILENAME_45="colorchoice-1.0.5.tar.gz" |
|
| 147 | - | SOURCE_URI_46="https://static.crates.io/crates/console/console-0.15.11.crate" |
|
| 148 | - | CHECKSUM_SHA256_46="054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" |
|
| 149 | - | SOURCE_FILENAME_46="console-0.15.11.tar.gz" |
|
| 150 | - | SOURCE_URI_47="https://static.crates.io/crates/const-oid/const-oid-0.10.2.crate" |
|
| 151 | - | CHECKSUM_SHA256_47="a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" |
|
| 152 | - | SOURCE_FILENAME_47="const-oid-0.10.2.tar.gz" |
|
| 153 | - | SOURCE_URI_48="https://static.crates.io/crates/constant_time_eq/constant_time_eq-0.4.2.crate" |
|
| 154 | - | CHECKSUM_SHA256_48="3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" |
|
| 155 | - | SOURCE_FILENAME_48="constant_time_eq-0.4.2.tar.gz" |
|
| 156 | - | SOURCE_URI_49="https://static.crates.io/crates/cpufeatures/cpufeatures-0.3.1.crate" |
|
| 157 | - | CHECKSUM_SHA256_49="5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" |
|
| 158 | - | SOURCE_FILENAME_49="cpufeatures-0.3.1.tar.gz" |
|
| 159 | - | SOURCE_URI_50="https://static.crates.io/crates/crc32fast/crc32fast-1.5.2.crate" |
|
| 160 | - | CHECKSUM_SHA256_50="01a7799fd6b852db0e61728dde9a204c423b44d689dbd432522543614b490e78" |
|
| 161 | - | SOURCE_FILENAME_50="crc32fast-1.5.2.tar.gz" |
|
| 162 | - | SOURCE_URI_51="https://static.crates.io/crates/crossbeam-deque/crossbeam-deque-0.8.8.crate" |
|
| 163 | - | CHECKSUM_SHA256_51="622f3fc73690be383c7214310406f28a90e6edeadc3cea882f9d71e495b9711a" |
|
| 164 | - | SOURCE_FILENAME_51="crossbeam-deque-0.8.8.tar.gz" |
|
| 165 | - | SOURCE_URI_52="https://static.crates.io/crates/crossbeam-epoch/crossbeam-epoch-0.9.21.crate" |
|
| 166 | - | CHECKSUM_SHA256_52="dc74980687109a3b14c72fd458107bf0baa1da1a1a805e178d15501ba9b86d9d" |
|
| 167 | - | SOURCE_FILENAME_52="crossbeam-epoch-0.9.21.tar.gz" |
|
| 168 | - | SOURCE_URI_53="https://static.crates.io/crates/crossbeam-utils/crossbeam-utils-0.8.23.crate" |
|
| 169 | - | CHECKSUM_SHA256_53="a31eee39dddec8330830986fcd7625edb5a24ec90ea038215273bbc3adb08ac6" |
|
| 170 | - | SOURCE_FILENAME_53="crossbeam-utils-0.8.23.tar.gz" |
|
| 171 | - | SOURCE_URI_54="https://static.crates.io/crates/crypto-common/crypto-common-0.1.7.crate" |
|
| 172 | - | CHECKSUM_SHA256_54="78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" |
|
| 173 | - | SOURCE_FILENAME_54="crypto-common-0.1.7.tar.gz" |
|
| 174 | - | SOURCE_URI_55="https://static.crates.io/crates/crypto-common/crypto-common-0.2.2.crate" |
|
| 175 | - | CHECKSUM_SHA256_55="ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" |
|
| 176 | - | SOURCE_FILENAME_55="crypto-common-0.2.2.tar.gz" |
|
| 177 | - | SOURCE_URI_56="https://static.crates.io/crates/ctutils/ctutils-0.4.2.crate" |
|
| 178 | - | CHECKSUM_SHA256_56="7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" |
|
| 179 | - | SOURCE_FILENAME_56="ctutils-0.4.2.tar.gz" |
|
| 180 | - | SOURCE_URI_57="https://static.crates.io/crates/curve25519-dalek/curve25519-dalek-5.0.0.crate" |
|
| 181 | - | CHECKSUM_SHA256_57="b5eed333089e2e1c1ac8c6c0398e5e2497b4c9926ca6d0365ed1e099afa5bc23" |
|
| 182 | - | SOURCE_FILENAME_57="curve25519-dalek-5.0.0.tar.gz" |
|
| 183 | - | SOURCE_URI_58="https://static.crates.io/crates/curve25519-dalek-derive/curve25519-dalek-derive-0.1.1.crate" |
|
| 184 | - | CHECKSUM_SHA256_58="f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" |
|
| 185 | - | SOURCE_FILENAME_58="curve25519-dalek-derive-0.1.1.tar.gz" |
|
| 186 | - | SOURCE_URI_59="https://static.crates.io/crates/data-encoding/data-encoding-2.11.1.crate" |
|
| 187 | - | CHECKSUM_SHA256_59="4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06" |
|
| 188 | - | SOURCE_FILENAME_59="data-encoding-2.11.1.tar.gz" |
|
| 189 | - | SOURCE_URI_60="https://static.crates.io/crates/der/der-0.8.2.crate" |
|
| 190 | - | CHECKSUM_SHA256_60="a878c850e9e421b20262e9b41f9c860e4785fa07541c266b62ff9d1ef998a80a" |
|
| 191 | - | SOURCE_FILENAME_60="der-0.8.2.tar.gz" |
|
| 192 | - | SOURCE_URI_61="https://static.crates.io/crates/der-parser/der-parser-10.0.0.crate" |
|
| 193 | - | CHECKSUM_SHA256_61="07da5016415d5a3c4dd39b11ed26f915f52fc4e0dc197d87908bc916e51bc1a6" |
|
| 194 | - | SOURCE_FILENAME_61="der-parser-10.0.0.tar.gz" |
|
| 195 | - | SOURCE_URI_62="https://static.crates.io/crates/deranged/deranged-0.5.8.crate" |
|
| 196 | - | CHECKSUM_SHA256_62="7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" |
|
| 197 | - | SOURCE_FILENAME_62="deranged-0.5.8.tar.gz" |
|
| 198 | - | SOURCE_URI_63="https://static.crates.io/crates/digest/digest-0.10.7.crate" |
|
| 199 | - | CHECKSUM_SHA256_63="9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" |
|
| 200 | - | SOURCE_FILENAME_63="digest-0.10.7.tar.gz" |
|
| 201 | - | SOURCE_URI_64="https://static.crates.io/crates/digest/digest-0.11.3.crate" |
|
| 202 | - | CHECKSUM_SHA256_64="f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" |
|
| 203 | - | SOURCE_FILENAME_64="digest-0.11.3.tar.gz" |
|
| 204 | - | SOURCE_URI_65="https://static.crates.io/crates/displaydoc/displaydoc-0.2.7.crate" |
|
| 205 | - | CHECKSUM_SHA256_65="c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" |
|
| 206 | - | SOURCE_FILENAME_65="displaydoc-0.2.7.tar.gz" |
|
| 207 | - | SOURCE_URI_66="https://static.crates.io/crates/ed25519/ed25519-3.0.0.crate" |
|
| 208 | - | CHECKSUM_SHA256_66="29fcf32e6c73d1079f83ab4d782de2d81620346a5f38c6237a86a22f8368980a" |
|
| 209 | - | SOURCE_FILENAME_66="ed25519-3.0.0.tar.gz" |
|
| 210 | - | SOURCE_URI_67="https://static.crates.io/crates/ed25519-dalek/ed25519-dalek-3.0.0.crate" |
|
| 211 | - | CHECKSUM_SHA256_67="6ebaa1a2bf1290ab3bfe5a7b771d050ebffab2711c19a81691c683a5144a25de" |
|
| 212 | - | SOURCE_FILENAME_67="ed25519-dalek-3.0.0.tar.gz" |
|
| 213 | - | SOURCE_URI_68="https://static.crates.io/crates/either/either-1.18.0.crate" |
|
| 214 | - | CHECKSUM_SHA256_68="252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" |
|
| 215 | - | SOURCE_FILENAME_68="either-1.18.0.tar.gz" |
|
| 216 | - | SOURCE_URI_69="https://static.crates.io/crates/encode_unicode/encode_unicode-1.0.0.crate" |
|
| 217 | - | CHECKSUM_SHA256_69="34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" |
|
| 218 | - | SOURCE_FILENAME_69="encode_unicode-1.0.0.tar.gz" |
|
| 219 | - | SOURCE_URI_70="https://static.crates.io/crates/equivalent/equivalent-1.0.2.crate" |
|
| 220 | - | CHECKSUM_SHA256_70="877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" |
|
| 221 | - | SOURCE_FILENAME_70="equivalent-1.0.2.tar.gz" |
|
| 222 | - | SOURCE_URI_71="https://static.crates.io/crates/errno/errno-0.3.14.crate" |
|
| 223 | - | CHECKSUM_SHA256_71="39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" |
|
| 224 | - | SOURCE_FILENAME_71="errno-0.3.14.tar.gz" |
|
| 225 | - | SOURCE_URI_72="https://static.crates.io/crates/fastrand/fastrand-2.5.0.crate" |
|
| 226 | - | CHECKSUM_SHA256_72="da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" |
|
| 227 | - | SOURCE_FILENAME_72="fastrand-2.5.0.tar.gz" |
|
| 228 | - | SOURCE_URI_73="https://static.crates.io/crates/fiat-crypto/fiat-crypto-0.3.0.crate" |
|
| 229 | - | CHECKSUM_SHA256_73="64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" |
|
| 230 | - | SOURCE_FILENAME_73="fiat-crypto-0.3.0.tar.gz" |
|
| 231 | - | SOURCE_URI_74="https://static.crates.io/crates/find-msvc-tools/find-msvc-tools-0.1.14.crate" |
|
| 232 | - | CHECKSUM_SHA256_74="aedcfb3409746eddb02b9e19ebda1c3394f759a152e48ee875a0844d1b955484" |
|
| 233 | - | SOURCE_FILENAME_74="find-msvc-tools-0.1.14.tar.gz" |
|
| 234 | - | SOURCE_URI_75="https://static.crates.io/crates/flate2/flate2-1.1.10.crate" |
|
| 235 | - | CHECKSUM_SHA256_75="6e634e2e0ebac1ee034020da1ca582e17ffe4e0f5e985823721e168928136dcb" |
|
| 236 | - | SOURCE_FILENAME_75="flate2-1.1.10.tar.gz" |
|
| 237 | - | SOURCE_URI_76="https://static.crates.io/crates/fnv/fnv-1.0.7.crate" |
|
| 238 | - | CHECKSUM_SHA256_76="3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" |
|
| 239 | - | SOURCE_FILENAME_76="fnv-1.0.7.tar.gz" |
|
| 240 | - | SOURCE_URI_77="https://static.crates.io/crates/form_urlencoded/form_urlencoded-1.2.2.crate" |
|
| 241 | - | CHECKSUM_SHA256_77="cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" |
|
| 242 | - | SOURCE_FILENAME_77="form_urlencoded-1.2.2.tar.gz" |
|
| 243 | - | SOURCE_URI_78="https://static.crates.io/crates/fs-err/fs-err-3.3.1.crate" |
|
| 244 | - | CHECKSUM_SHA256_78="b91aa448ca50d7e79433bdf3ee8d99215430d2ec02ade5aefab2a073a1822e8a" |
|
| 245 | - | SOURCE_FILENAME_78="fs-err-3.3.1.tar.gz" |
|
| 246 | - | SOURCE_URI_79="https://static.crates.io/crates/futures/futures-0.3.34.crate" |
|
| 247 | - | CHECKSUM_SHA256_79="9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" |
|
| 248 | - | SOURCE_FILENAME_79="futures-0.3.34.tar.gz" |
|
| 249 | - | SOURCE_URI_80="https://static.crates.io/crates/futures-channel/futures-channel-0.3.34.crate" |
|
| 250 | - | CHECKSUM_SHA256_80="b1f9e3d69d39e4862ffed03ed071a76f9a13ba1d9109d355b0f0aa6b15e393c4" |
|
| 251 | - | SOURCE_FILENAME_80="futures-channel-0.3.34.tar.gz" |
|
| 252 | - | SOURCE_URI_81="https://static.crates.io/crates/futures-core/futures-core-0.3.34.crate" |
|
| 253 | - | CHECKSUM_SHA256_81="92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" |
|
| 254 | - | SOURCE_FILENAME_81="futures-core-0.3.34.tar.gz" |
|
| 255 | - | SOURCE_URI_82="https://static.crates.io/crates/futures-executor/futures-executor-0.3.34.crate" |
|
| 256 | - | CHECKSUM_SHA256_82="031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" |
|
| 257 | - | SOURCE_FILENAME_82="futures-executor-0.3.34.tar.gz" |
|
| 258 | - | SOURCE_URI_83="https://static.crates.io/crates/futures-io/futures-io-0.3.34.crate" |
|
| 259 | - | CHECKSUM_SHA256_83="53c0fa8157de1303bfffdaa1cc2a673bfffb60102f76b0ef4441659124373fed" |
|
| 260 | - | SOURCE_FILENAME_83="futures-io-0.3.34.tar.gz" |
|
| 261 | - | SOURCE_URI_84="https://static.crates.io/crates/futures-macro/futures-macro-0.3.34.crate" |
|
| 262 | - | CHECKSUM_SHA256_84="9fb9654ba8355388abeb8dcb4fc62f511300867002afc858860463bdd9fe0c44" |
|
| 263 | - | SOURCE_FILENAME_84="futures-macro-0.3.34.tar.gz" |
|
| 264 | - | SOURCE_URI_85="https://static.crates.io/crates/futures-sink/futures-sink-0.3.34.crate" |
|
| 265 | - | CHECKSUM_SHA256_85="1944426bf7d03f1d14f708785e4b33efd750b36d48a157b836b3efc15ede8e1d" |
|
| 266 | - | SOURCE_FILENAME_85="futures-sink-0.3.34.tar.gz" |
|
| 267 | - | SOURCE_URI_86="https://static.crates.io/crates/futures-task/futures-task-0.3.34.crate" |
|
| 268 | - | CHECKSUM_SHA256_86="cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" |
|
| 269 | - | SOURCE_FILENAME_86="futures-task-0.3.34.tar.gz" |
|
| 270 | - | SOURCE_URI_87="https://static.crates.io/crates/futures-util/futures-util-0.3.34.crate" |
|
| 271 | - | CHECKSUM_SHA256_87="0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" |
|
| 272 | - | SOURCE_FILENAME_87="futures-util-0.3.34.tar.gz" |
|
| 273 | - | SOURCE_URI_88="https://static.crates.io/crates/generic-array/generic-array-0.14.7.crate" |
|
| 274 | - | CHECKSUM_SHA256_88="85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" |
|
| 275 | - | SOURCE_FILENAME_88="generic-array-0.14.7.tar.gz" |
|
| 276 | - | SOURCE_URI_89="https://static.crates.io/crates/getrandom/getrandom-0.2.17.crate" |
|
| 277 | - | CHECKSUM_SHA256_89="ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" |
|
| 278 | - | SOURCE_FILENAME_89="getrandom-0.2.17.tar.gz" |
|
| 279 | - | SOURCE_URI_90="https://static.crates.io/crates/getrandom/getrandom-0.3.4.crate" |
|
| 280 | - | CHECKSUM_SHA256_90="899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" |
|
| 281 | - | SOURCE_FILENAME_90="getrandom-0.3.4.tar.gz" |
|
| 282 | - | SOURCE_URI_91="https://static.crates.io/crates/getrandom/getrandom-0.4.3.crate" |
|
| 283 | - | CHECKSUM_SHA256_91="300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" |
|
| 284 | - | SOURCE_FILENAME_91="getrandom-0.4.3.tar.gz" |
|
| 285 | - | SOURCE_URI_92="https://static.crates.io/crates/globset/globset-0.4.20.crate" |
|
| 286 | - | CHECKSUM_SHA256_92="07c34a9410465b45bd9787443bc7370f37735bad04b0f0cd57ff1a3186c98988" |
|
| 287 | - | SOURCE_FILENAME_92="globset-0.4.20.tar.gz" |
|
| 288 | - | SOURCE_URI_93="https://static.crates.io/crates/h2/h2-0.4.19.crate" |
|
| 289 | - | CHECKSUM_SHA256_93="ef8e5e5a340588f4452631496976cf8636d4a7ecf600239fdc27615d2530bc16" |
|
| 290 | - | SOURCE_FILENAME_93="h2-0.4.19.tar.gz" |
|
| 291 | - | SOURCE_URI_94="https://static.crates.io/crates/hashbrown/hashbrown-0.17.1.crate" |
|
| 292 | - | CHECKSUM_SHA256_94="ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" |
|
| 293 | - | SOURCE_FILENAME_94="hashbrown-0.17.1.tar.gz" |
|
| 294 | - | SOURCE_URI_95="https://static.crates.io/crates/heck/heck-0.5.0.crate" |
|
| 295 | - | CHECKSUM_SHA256_95="2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" |
|
| 296 | - | SOURCE_FILENAME_95="heck-0.5.0.tar.gz" |
|
| 297 | - | SOURCE_URI_96="https://static.crates.io/crates/hex/hex-0.4.3.crate" |
|
| 298 | - | CHECKSUM_SHA256_96="7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" |
|
| 299 | - | SOURCE_FILENAME_96="hex-0.4.3.tar.gz" |
|
| 300 | - | SOURCE_URI_97="https://static.crates.io/crates/http/http-1.5.0.crate" |
|
| 301 | - | CHECKSUM_SHA256_97="918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" |
|
| 302 | - | SOURCE_FILENAME_97="http-1.5.0.tar.gz" |
|
| 303 | - | SOURCE_URI_98="https://static.crates.io/crates/http-body/http-body-1.1.0.crate" |
|
| 304 | - | CHECKSUM_SHA256_98="ca2a8f2913ee65f60facd6a5905613afaa448497a0230cc41ce022d93290bc2c" |
|
| 305 | - | SOURCE_FILENAME_98="http-body-1.1.0.tar.gz" |
|
| 306 | - | SOURCE_URI_99="https://static.crates.io/crates/http-body-util/http-body-util-0.1.5.crate" |
|
| 307 | - | CHECKSUM_SHA256_99="23169fe34a5fbcdd3f3862e78fb9b6fccd5f02a6dc6f732547005d45631ce71c" |
|
| 308 | - | SOURCE_FILENAME_99="http-body-util-0.1.5.tar.gz" |
|
| 309 | - | SOURCE_URI_100="https://static.crates.io/crates/httparse/httparse-1.10.1.crate" |
|
| 310 | - | CHECKSUM_SHA256_100="6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" |
|
| 311 | - | SOURCE_FILENAME_100="httparse-1.10.1.tar.gz" |
|
| 312 | - | SOURCE_URI_101="https://static.crates.io/crates/httpdate/httpdate-1.0.3.crate" |
|
| 313 | - | CHECKSUM_SHA256_101="df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" |
|
| 314 | - | SOURCE_FILENAME_101="httpdate-1.0.3.tar.gz" |
|
| 315 | - | SOURCE_URI_102="https://static.crates.io/crates/humantime/humantime-2.4.0.crate" |
|
| 316 | - | CHECKSUM_SHA256_102="15cdd26707701c53297e2fa6afb323d55fbc1d0810c3aec078ae3ef0424c3c15" |
|
| 317 | - | SOURCE_FILENAME_102="humantime-2.4.0.tar.gz" |
|
| 318 | - | SOURCE_URI_103="https://static.crates.io/crates/hybrid-array/hybrid-array-0.4.15.crate" |
|
| 319 | - | CHECKSUM_SHA256_103="27f864f10dfb56725ce5ce5472bc52252c8f93a4ab86327122cebf62c5f59a17" |
|
| 320 | - | SOURCE_FILENAME_103="hybrid-array-0.4.15.tar.gz" |
|
| 321 | - | SOURCE_URI_104="https://static.crates.io/crates/hyper/hyper-1.11.1.crate" |
|
| 322 | - | CHECKSUM_SHA256_104="27b501faa50e7a26c3d3560ca625132f4078a17771f4810baf70475ae48cbe43" |
|
| 323 | - | SOURCE_FILENAME_104="hyper-1.11.1.tar.gz" |
|
| 324 | - | SOURCE_URI_105="https://static.crates.io/crates/hyper-util/hyper-util-0.1.21.crate" |
|
| 325 | - | CHECKSUM_SHA256_105="ddc03d96684f9226b8a787cdb71488417b53ab5ea8fdb1dac946cb9431cc8bff" |
|
| 326 | - | SOURCE_FILENAME_105="hyper-util-0.1.21.tar.gz" |
|
| 327 | - | SOURCE_URI_106="https://static.crates.io/crates/iana-time-zone-haiku/iana-time-zone-haiku-0.1.2.crate" |
|
| 328 | - | CHECKSUM_SHA256_106="f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" |
|
| 329 | - | SOURCE_FILENAME_106="iana-time-zone-haiku-0.1.2.tar.gz" |
|
| 330 | - | SOURCE_URI_107="https://static.crates.io/crates/icu_collections/icu_collections-2.3.0.crate" |
|
| 331 | - | CHECKSUM_SHA256_107="fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" |
|
| 332 | - | SOURCE_FILENAME_107="icu_collections-2.3.0.tar.gz" |
|
| 333 | - | SOURCE_URI_108="https://static.crates.io/crates/icu_locale_core/icu_locale_core-2.3.0.crate" |
|
| 334 | - | CHECKSUM_SHA256_108="d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" |
|
| 335 | - | SOURCE_FILENAME_108="icu_locale_core-2.3.0.tar.gz" |
|
| 336 | - | SOURCE_URI_109="https://static.crates.io/crates/icu_normalizer/icu_normalizer-2.3.0.crate" |
|
| 337 | - | CHECKSUM_SHA256_109="12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" |
|
| 338 | - | SOURCE_FILENAME_109="icu_normalizer-2.3.0.tar.gz" |
|
| 339 | - | SOURCE_URI_110="https://static.crates.io/crates/icu_normalizer_data/icu_normalizer_data-2.3.0.crate" |
|
| 340 | - | CHECKSUM_SHA256_110="1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" |
|
| 341 | - | SOURCE_FILENAME_110="icu_normalizer_data-2.3.0.tar.gz" |
|
| 342 | - | SOURCE_URI_111="https://static.crates.io/crates/icu_properties/icu_properties-2.3.0.crate" |
|
| 343 | - | CHECKSUM_SHA256_111="7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" |
|
| 344 | - | SOURCE_FILENAME_111="icu_properties-2.3.0.tar.gz" |
|
| 345 | - | SOURCE_URI_112="https://static.crates.io/crates/icu_properties_data/icu_properties_data-2.3.0.crate" |
|
| 346 | - | CHECKSUM_SHA256_112="e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" |
|
| 347 | - | SOURCE_FILENAME_112="icu_properties_data-2.3.0.tar.gz" |
|
| 348 | - | SOURCE_URI_113="https://static.crates.io/crates/icu_provider/icu_provider-2.3.1.crate" |
|
| 349 | - | CHECKSUM_SHA256_113="d27bbb9d3abbefac45d55f647c9de1d44aafcd1186eb91879afef17c396c3e73" |
|
| 350 | - | SOURCE_FILENAME_113="icu_provider-2.3.1.tar.gz" |
|
| 351 | - | SOURCE_URI_114="https://static.crates.io/crates/idna/idna-1.1.0.crate" |
|
| 352 | - | CHECKSUM_SHA256_114="3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" |
|
| 353 | - | SOURCE_FILENAME_114="idna-1.1.0.tar.gz" |
|
| 354 | - | SOURCE_URI_115="https://static.crates.io/crates/idna_adapter/idna_adapter-1.2.2.crate" |
|
| 355 | - | CHECKSUM_SHA256_115="cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" |
|
| 356 | - | SOURCE_FILENAME_115="idna_adapter-1.2.2.tar.gz" |
|
| 357 | - | SOURCE_URI_116="https://static.crates.io/crates/ignore/ignore-0.4.33.crate" |
|
| 358 | - | CHECKSUM_SHA256_116="00b69833ed729dc5aa7d19541d96d6cf8e9137194207a04916d658e43168402f" |
|
| 359 | - | SOURCE_FILENAME_116="ignore-0.4.33.tar.gz" |
|
| 360 | - | SOURCE_URI_117="https://static.crates.io/crates/indexmap/indexmap-2.14.2.crate" |
|
| 361 | - | CHECKSUM_SHA256_117="cc4e190f5d26ca7051642629da2c52fc03bde85a03197c99408dcd291734c855" |
|
| 362 | - | SOURCE_FILENAME_117="indexmap-2.14.2.tar.gz" |
|
| 363 | - | SOURCE_URI_118="https://static.crates.io/crates/indicatif/indicatif-0.17.11.crate" |
|
| 364 | - | CHECKSUM_SHA256_118="183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" |
|
| 365 | - | SOURCE_FILENAME_118="indicatif-0.17.11.tar.gz" |
|
| 366 | - | SOURCE_URI_119="https://static.crates.io/crates/is_terminal_polyfill/is_terminal_polyfill-1.70.2.crate" |
|
| 367 | - | CHECKSUM_SHA256_119="a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" |
|
| 368 | - | SOURCE_FILENAME_119="is_terminal_polyfill-1.70.2.tar.gz" |
|
| 369 | - | SOURCE_URI_120="https://static.crates.io/crates/itertools/itertools-0.15.0.crate" |
|
| 370 | - | CHECKSUM_SHA256_120="8b4baf93f58d4425749ca49a51c50ebab072c5df6994d08fed93541c331481dc" |
|
| 371 | - | SOURCE_FILENAME_120="itertools-0.15.0.tar.gz" |
|
| 372 | - | SOURCE_URI_121="https://static.crates.io/crates/itoa/itoa-1.0.18.crate" |
|
| 373 | - | CHECKSUM_SHA256_121="8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" |
|
| 374 | - | SOURCE_FILENAME_121="itoa-1.0.18.tar.gz" |
|
| 375 | - | SOURCE_URI_122="https://static.crates.io/crates/jobserver/jobserver-0.1.35.crate" |
|
| 376 | - | CHECKSUM_SHA256_122="1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" |
|
| 377 | - | SOURCE_FILENAME_122="jobserver-0.1.35.tar.gz" |
|
| 378 | - | SOURCE_URI_123="https://static.crates.io/crates/js-sys/js-sys-0.3.106.crate" |
|
| 379 | - | CHECKSUM_SHA256_123="7883d941dae510fb2d978fc3fe018c71c9e2892fd38854de3e8b92c2e5ad9cc5" |
|
| 380 | - | SOURCE_FILENAME_123="js-sys-0.3.106.tar.gz" |
|
| 381 | - | SOURCE_URI_124="https://static.crates.io/crates/keccak/keccak-0.2.2.crate" |
|
| 382 | - | CHECKSUM_SHA256_124="d8f198d1db720e4940b5a493201d199d9f24f568f8f746bd13706243a2f71598" |
|
| 383 | - | SOURCE_FILENAME_124="keccak-0.2.2.tar.gz" |
|
| 384 | - | SOURCE_URI_125="https://static.crates.io/crates/lazy_static/lazy_static-1.5.0.crate" |
|
| 385 | - | CHECKSUM_SHA256_125="bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" |
|
| 386 | - | SOURCE_FILENAME_125="lazy_static-1.5.0.tar.gz" |
|
| 387 | - | SOURCE_URI_126="https://static.crates.io/crates/libc/libc-0.2.189.crate" |
|
| 388 | - | CHECKSUM_SHA256_126="3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" |
|
| 389 | - | SOURCE_FILENAME_126="libc-0.2.189.tar.gz" |
|
| 390 | - | SOURCE_URI_127="https://static.crates.io/crates/libmimalloc-sys/libmimalloc-sys-0.1.49.crate" |
|
| 391 | - | CHECKSUM_SHA256_127="6a45a52f43e1c16f667ccfe4dd8c85b7f7c204fd5e3bf46c5b0db9a5c3c0b8e9" |
|
| 392 | - | SOURCE_FILENAME_127="libmimalloc-sys-0.1.49.tar.gz" |
|
| 393 | - | SOURCE_URI_128="https://static.crates.io/crates/linux-raw-sys/linux-raw-sys-0.12.1.crate" |
|
| 394 | - | CHECKSUM_SHA256_128="32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" |
|
| 395 | - | SOURCE_FILENAME_128="linux-raw-sys-0.12.1.tar.gz" |
|
| 396 | - | SOURCE_URI_129="https://static.crates.io/crates/litemap/litemap-0.8.3.crate" |
|
| 397 | - | CHECKSUM_SHA256_129="47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" |
|
| 398 | - | SOURCE_FILENAME_129="litemap-0.8.3.tar.gz" |
|
| 399 | - | SOURCE_URI_130="https://static.crates.io/crates/lock_api/lock_api-0.4.14.crate" |
|
| 400 | - | CHECKSUM_SHA256_130="224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" |
|
| 401 | - | SOURCE_FILENAME_130="lock_api-0.4.14.tar.gz" |
|
| 402 | - | SOURCE_URI_131="https://static.crates.io/crates/log/log-0.4.34.crate" |
|
| 403 | - | CHECKSUM_SHA256_131="f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" |
|
| 404 | - | SOURCE_FILENAME_131="log-0.4.34.tar.gz" |
|
| 405 | - | SOURCE_URI_132="https://static.crates.io/crates/matchit/matchit-0.8.4.crate" |
|
| 406 | - | CHECKSUM_SHA256_132="47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" |
|
| 407 | - | SOURCE_FILENAME_132="matchit-0.8.4.tar.gz" |
|
| 408 | - | SOURCE_URI_133="https://static.crates.io/crates/md-5/md-5-0.11.0.crate" |
|
| 409 | - | CHECKSUM_SHA256_133="69b6441f590336821bb897fb28fc622898ccceb1d6cea3fde5ea86b090c4de98" |
|
| 410 | - | SOURCE_FILENAME_133="md-5-0.11.0.tar.gz" |
|
| 411 | - | SOURCE_URI_134="https://static.crates.io/crates/memchr/memchr-2.8.3.crate" |
|
| 412 | - | CHECKSUM_SHA256_134="cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" |
|
| 413 | - | SOURCE_FILENAME_134="memchr-2.8.3.tar.gz" |
|
| 414 | - | SOURCE_URI_135="https://static.crates.io/crates/mimalloc/mimalloc-0.1.52.crate" |
|
| 415 | - | CHECKSUM_SHA256_135="2d4139bb28d14ad1facf21d5eb8825051b326e172d216b39f6d31df53cc97862" |
|
| 416 | - | SOURCE_FILENAME_135="mimalloc-0.1.52.tar.gz" |
|
| 417 | - | SOURCE_URI_136="https://static.crates.io/crates/mime/mime-0.3.17.crate" |
|
| 418 | - | CHECKSUM_SHA256_136="6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" |
|
| 419 | - | SOURCE_FILENAME_136="mime-0.3.17.tar.gz" |
|
| 420 | - | SOURCE_URI_137="https://static.crates.io/crates/minimal-lexical/minimal-lexical-0.2.1.crate" |
|
| 421 | - | CHECKSUM_SHA256_137="68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" |
|
| 422 | - | SOURCE_FILENAME_137="minimal-lexical-0.2.1.tar.gz" |
|
| 423 | - | SOURCE_URI_138="https://static.crates.io/crates/miniz_oxide/miniz_oxide-0.9.1.crate" |
|
| 424 | - | CHECKSUM_SHA256_138="b63fbc4a50860e98e7b2aa7804ded1db5cbc3aff9193adaff57a6931bf7c4b4c" |
|
| 425 | - | SOURCE_FILENAME_138="miniz_oxide-0.9.1.tar.gz" |
|
| 426 | - | SOURCE_URI_139="https://static.crates.io/crates/mio/mio-1.2.3.crate" |
|
| 427 | - | CHECKSUM_SHA256_139="4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" |
|
| 428 | - | SOURCE_FILENAME_139="mio-1.2.3.tar.gz" |
|
| 429 | - | SOURCE_URI_140="https://static.crates.io/crates/ml-dsa/ml-dsa-0.1.1.crate" |
|
| 430 | - | CHECKSUM_SHA256_140="add6b9d92e496f16f4526d68ff29da1483aba4b119baeab8bed3b9e3544a6f3d" |
|
| 431 | - | SOURCE_FILENAME_140="ml-dsa-0.1.1.tar.gz" |
|
| 432 | - | SOURCE_URI_141="https://static.crates.io/crates/module-lattice/module-lattice-0.2.3.crate" |
|
| 433 | - | CHECKSUM_SHA256_141="0c61b87c9683ab7cb1c6871d261ad5479b6b10ceb52c4352aaca3b5d35a8febe" |
|
| 434 | - | SOURCE_FILENAME_141="module-lattice-0.2.3.tar.gz" |
|
| 435 | - | SOURCE_URI_142="https://static.crates.io/crates/nom/nom-7.1.3.crate" |
|
| 436 | - | CHECKSUM_SHA256_142="d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" |
|
| 437 | - | SOURCE_FILENAME_142="nom-7.1.3.tar.gz" |
|
| 438 | - | SOURCE_URI_143="https://static.crates.io/crates/num-bigint/num-bigint-0.4.8.crate" |
|
| 439 | - | CHECKSUM_SHA256_143="c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" |
|
| 440 | - | SOURCE_FILENAME_143="num-bigint-0.4.8.tar.gz" |
|
| 441 | - | SOURCE_URI_144="https://static.crates.io/crates/num-conv/num-conv-0.2.2.crate" |
|
| 442 | - | CHECKSUM_SHA256_144="521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" |
|
| 443 | - | SOURCE_FILENAME_144="num-conv-0.2.2.tar.gz" |
|
| 444 | - | SOURCE_URI_145="https://static.crates.io/crates/num-integer/num-integer-0.1.47.crate" |
|
| 445 | - | CHECKSUM_SHA256_145="7ce2d95d4b3734dc35aa2f45e1aa22cd416814592a4f9d9205e11affd5b8e10b" |
|
| 446 | - | SOURCE_FILENAME_145="num-integer-0.1.47.tar.gz" |
|
| 447 | - | SOURCE_URI_146="https://static.crates.io/crates/num-traits/num-traits-0.2.19.crate" |
|
| 448 | - | CHECKSUM_SHA256_146="071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" |
|
| 449 | - | SOURCE_FILENAME_146="num-traits-0.2.19.tar.gz" |
|
| 450 | - | SOURCE_URI_147="https://static.crates.io/crates/number_prefix/number_prefix-0.4.0.crate" |
|
| 451 | - | CHECKSUM_SHA256_147="830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" |
|
| 452 | - | SOURCE_FILENAME_147="number_prefix-0.4.0.tar.gz" |
|
| 453 | - | SOURCE_URI_148="https://static.crates.io/crates/object_store/object_store-0.14.2.crate" |
|
| 454 | - | CHECKSUM_SHA256_148="f1796bc93603f78c5760a69f2d58badc9618d22adade0a95385bb2adbae4eb94" |
|
| 455 | - | SOURCE_FILENAME_148="object_store-0.14.2.tar.gz" |
|
| 456 | - | SOURCE_URI_149="https://static.crates.io/crates/oid-registry/oid-registry-0.8.1.crate" |
|
| 457 | - | CHECKSUM_SHA256_149="12f40cff3dde1b6087cc5d5f5d4d65712f34016a03ed60e9c08dcc392736b5b7" |
|
| 458 | - | SOURCE_FILENAME_149="oid-registry-0.8.1.tar.gz" |
|
| 459 | - | SOURCE_URI_150="https://static.crates.io/crates/once_cell/once_cell-1.21.4.crate" |
|
| 460 | - | CHECKSUM_SHA256_150="9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" |
|
| 461 | - | SOURCE_FILENAME_150="once_cell-1.21.4.tar.gz" |
|
| 462 | - | SOURCE_URI_151="https://static.crates.io/crates/once_cell_polyfill/once_cell_polyfill-1.70.2.crate" |
|
| 463 | - | CHECKSUM_SHA256_151="384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" |
|
| 464 | - | SOURCE_FILENAME_151="once_cell_polyfill-1.70.2.tar.gz" |
|
| 465 | - | SOURCE_URI_152="https://static.crates.io/crates/parking_lot/parking_lot-0.12.5.crate" |
|
| 466 | - | CHECKSUM_SHA256_152="93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" |
|
| 467 | - | SOURCE_FILENAME_152="parking_lot-0.12.5.tar.gz" |
|
| 468 | - | SOURCE_URI_153="https://static.crates.io/crates/parking_lot_core/parking_lot_core-0.9.12.crate" |
|
| 469 | - | CHECKSUM_SHA256_153="2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" |
|
| 470 | - | SOURCE_FILENAME_153="parking_lot_core-0.9.12.tar.gz" |
|
| 471 | - | SOURCE_URI_154="https://static.crates.io/crates/pem/pem-4.0.0.crate" |
|
| 472 | - | CHECKSUM_SHA256_154="d354a98a3d1251555de99e8fdd8afda05573c31b82f59063a7b0a29b5527f120" |
|
| 473 | - | SOURCE_FILENAME_154="pem-4.0.0.tar.gz" |
|
| 474 | - | SOURCE_URI_155="https://static.crates.io/crates/percent-encoding/percent-encoding-2.3.2.crate" |
|
| 475 | - | CHECKSUM_SHA256_155="9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" |
|
| 476 | - | SOURCE_FILENAME_155="percent-encoding-2.3.2.tar.gz" |
|
| 477 | - | SOURCE_URI_156="https://static.crates.io/crates/pin-project-lite/pin-project-lite-0.2.17.crate" |
|
| 478 | - | CHECKSUM_SHA256_156="a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" |
|
| 479 | - | SOURCE_FILENAME_156="pin-project-lite-0.2.17.tar.gz" |
|
| 480 | - | SOURCE_URI_157="https://static.crates.io/crates/pkcs8/pkcs8-0.11.0.crate" |
|
| 481 | - | CHECKSUM_SHA256_157="451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" |
|
| 482 | - | SOURCE_FILENAME_157="pkcs8-0.11.0.tar.gz" |
|
| 483 | - | SOURCE_URI_158="https://static.crates.io/crates/pkg-config/pkg-config-0.3.34.crate" |
|
| 484 | - | CHECKSUM_SHA256_158="f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" |
|
| 485 | - | SOURCE_FILENAME_158="pkg-config-0.3.34.tar.gz" |
|
| 486 | - | SOURCE_URI_159="https://static.crates.io/crates/portable-atomic/portable-atomic-1.15.0.crate" |
|
| 487 | - | CHECKSUM_SHA256_159="05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" |
|
| 488 | - | SOURCE_FILENAME_159="portable-atomic-1.15.0.tar.gz" |
|
| 489 | - | SOURCE_URI_160="https://static.crates.io/crates/potential_utf/potential_utf-0.1.6.crate" |
|
| 490 | - | CHECKSUM_SHA256_160="d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" |
|
| 491 | - | SOURCE_FILENAME_160="potential_utf-0.1.6.tar.gz" |
|
| 492 | - | SOURCE_URI_161="https://static.crates.io/crates/powerfmt/powerfmt-0.2.0.crate" |
|
| 493 | - | CHECKSUM_SHA256_161="439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" |
|
| 494 | - | SOURCE_FILENAME_161="powerfmt-0.2.0.tar.gz" |
|
| 495 | - | SOURCE_URI_162="https://static.crates.io/crates/ppv-lite86/ppv-lite86-0.2.21.crate" |
|
| 496 | - | CHECKSUM_SHA256_162="85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" |
|
| 497 | - | SOURCE_FILENAME_162="ppv-lite86-0.2.21.tar.gz" |
|
| 498 | - | SOURCE_URI_163="https://static.crates.io/crates/proc-macro2/proc-macro2-1.0.107.crate" |
|
| 499 | - | CHECKSUM_SHA256_163="985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" |
|
| 500 | - | SOURCE_FILENAME_163="proc-macro2-1.0.107.tar.gz" |
|
| 501 | - | SOURCE_URI_164="https://static.crates.io/crates/proptest/proptest-1.11.0.crate" |
|
| 502 | - | CHECKSUM_SHA256_164="4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" |
|
| 503 | - | SOURCE_FILENAME_164="proptest-1.11.0.tar.gz" |
|
| 504 | - | SOURCE_URI_165="https://static.crates.io/crates/quick-error/quick-error-1.2.3.crate" |
|
| 505 | - | CHECKSUM_SHA256_165="a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" |
|
| 506 | - | SOURCE_FILENAME_165="quick-error-1.2.3.tar.gz" |
|
| 507 | - | SOURCE_URI_166="https://static.crates.io/crates/quick-xml/quick-xml-0.41.0.crate" |
|
| 508 | - | CHECKSUM_SHA256_166="e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" |
|
| 509 | - | SOURCE_FILENAME_166="quick-xml-0.41.0.tar.gz" |
|
| 510 | - | SOURCE_URI_167="https://static.crates.io/crates/quote/quote-1.0.47.crate" |
|
| 511 | - | CHECKSUM_SHA256_167="1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" |
|
| 512 | - | SOURCE_FILENAME_167="quote-1.0.47.tar.gz" |
|
| 513 | - | SOURCE_URI_168="https://static.crates.io/crates/r-efi/r-efi-5.3.0.crate" |
|
| 514 | - | CHECKSUM_SHA256_168="69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" |
|
| 515 | - | SOURCE_FILENAME_168="r-efi-5.3.0.tar.gz" |
|
| 516 | - | SOURCE_URI_169="https://static.crates.io/crates/r-efi/r-efi-6.0.0.crate" |
|
| 517 | - | CHECKSUM_SHA256_169="f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" |
|
| 518 | - | SOURCE_FILENAME_169="r-efi-6.0.0.tar.gz" |
|
| 519 | - | SOURCE_URI_170="https://static.crates.io/crates/rand/rand-0.10.3.crate" |
|
| 520 | - | CHECKSUM_SHA256_170="65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" |
|
| 521 | - | SOURCE_FILENAME_170="rand-0.10.3.tar.gz" |
|
| 522 | - | SOURCE_URI_171="https://static.crates.io/crates/rand/rand-0.8.8.crate" |
|
| 523 | - | CHECKSUM_SHA256_171="e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" |
|
| 524 | - | SOURCE_FILENAME_171="rand-0.8.8.tar.gz" |
|
| 525 | - | SOURCE_URI_172="https://static.crates.io/crates/rand/rand-0.9.5.crate" |
|
| 526 | - | CHECKSUM_SHA256_172="b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" |
|
| 527 | - | SOURCE_FILENAME_172="rand-0.9.5.tar.gz" |
|
| 528 | - | SOURCE_URI_173="https://static.crates.io/crates/rand_chacha/rand_chacha-0.3.1.crate" |
|
| 529 | - | CHECKSUM_SHA256_173="e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" |
|
| 530 | - | SOURCE_FILENAME_173="rand_chacha-0.3.1.tar.gz" |
|
| 531 | - | SOURCE_URI_174="https://static.crates.io/crates/rand_chacha/rand_chacha-0.9.0.crate" |
|
| 532 | - | CHECKSUM_SHA256_174="d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" |
|
| 533 | - | SOURCE_FILENAME_174="rand_chacha-0.9.0.tar.gz" |
|
| 534 | - | SOURCE_URI_175="https://static.crates.io/crates/rand_core/rand_core-0.10.1.crate" |
|
| 535 | - | CHECKSUM_SHA256_175="63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" |
|
| 536 | - | SOURCE_FILENAME_175="rand_core-0.10.1.tar.gz" |
|
| 537 | - | SOURCE_URI_176="https://static.crates.io/crates/rand_core/rand_core-0.6.4.crate" |
|
| 538 | - | CHECKSUM_SHA256_176="ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" |
|
| 539 | - | SOURCE_FILENAME_176="rand_core-0.6.4.tar.gz" |
|
| 540 | - | SOURCE_URI_177="https://static.crates.io/crates/rand_core/rand_core-0.9.5.crate" |
|
| 541 | - | CHECKSUM_SHA256_177="76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" |
|
| 542 | - | SOURCE_FILENAME_177="rand_core-0.9.5.tar.gz" |
|
| 543 | - | SOURCE_URI_178="https://static.crates.io/crates/rand_xorshift/rand_xorshift-0.4.0.crate" |
|
| 544 | - | CHECKSUM_SHA256_178="513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" |
|
| 545 | - | SOURCE_FILENAME_178="rand_xorshift-0.4.0.tar.gz" |
|
| 546 | - | SOURCE_URI_179="https://static.crates.io/crates/rayon/rayon-1.12.0.crate" |
|
| 547 | - | CHECKSUM_SHA256_179="fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" |
|
| 548 | - | SOURCE_FILENAME_179="rayon-1.12.0.tar.gz" |
|
| 549 | - | SOURCE_URI_180="https://static.crates.io/crates/rayon-core/rayon-core-1.13.0.crate" |
|
| 550 | - | CHECKSUM_SHA256_180="22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" |
|
| 551 | - | SOURCE_FILENAME_180="rayon-core-1.13.0.tar.gz" |
|
| 552 | - | SOURCE_URI_181="https://static.crates.io/crates/rcgen/rcgen-0.14.10.crate" |
|
| 553 | - | CHECKSUM_SHA256_181="8774e05a7d0de114588e6a28fe7e71694b82614ed569d86d8b389dfbc98b8ad8" |
|
| 554 | - | SOURCE_FILENAME_181="rcgen-0.14.10.tar.gz" |
|
| 555 | - | SOURCE_URI_182="https://static.crates.io/crates/redox_syscall/redox_syscall-0.5.18.crate" |
|
| 556 | - | CHECKSUM_SHA256_182="ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" |
|
| 557 | - | SOURCE_FILENAME_182="redox_syscall-0.5.18.tar.gz" |
|
| 558 | - | SOURCE_URI_183="https://static.crates.io/crates/regex-automata/regex-automata-0.4.18.crate" |
|
| 559 | - | CHECKSUM_SHA256_183="ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" |
|
| 560 | - | SOURCE_FILENAME_183="regex-automata-0.4.18.tar.gz" |
|
| 561 | - | SOURCE_URI_184="https://static.crates.io/crates/regex-syntax/regex-syntax-0.8.11.crate" |
|
| 562 | - | CHECKSUM_SHA256_184="d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" |
|
| 563 | - | SOURCE_FILENAME_184="regex-syntax-0.8.11.tar.gz" |
|
| 564 | - | SOURCE_URI_185="https://static.crates.io/crates/ring/ring-0.17.14.crate" |
|
| 565 | - | CHECKSUM_SHA256_185="a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" |
|
| 566 | - | SOURCE_FILENAME_185="ring-0.17.14.tar.gz" |
|
| 567 | - | SOURCE_URI_186="https://static.crates.io/crates/roff/roff-1.1.1.crate" |
|
| 568 | - | CHECKSUM_SHA256_186="323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189" |
|
| 569 | - | SOURCE_FILENAME_186="roff-1.1.1.tar.gz" |
|
| 570 | - | SOURCE_URI_187="https://static.crates.io/crates/rustc_version/rustc_version-0.4.1.crate" |
|
| 571 | - | CHECKSUM_SHA256_187="cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" |
|
| 572 | - | SOURCE_FILENAME_187="rustc_version-0.4.1.tar.gz" |
|
| 573 | - | SOURCE_URI_188="https://static.crates.io/crates/rusticata-macros/rusticata-macros-4.1.0.crate" |
|
| 574 | - | CHECKSUM_SHA256_188="faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" |
|
| 575 | - | SOURCE_FILENAME_188="rusticata-macros-4.1.0.tar.gz" |
|
| 576 | - | SOURCE_URI_189="https://static.crates.io/crates/rustix/rustix-1.1.5.crate" |
|
| 577 | - | CHECKSUM_SHA256_189="891efababe418670775f199f0d233d84843c227a0949a883ce15b37c78d6629d" |
|
| 578 | - | SOURCE_FILENAME_189="rustix-1.1.5.tar.gz" |
|
| 579 | - | SOURCE_URI_190="https://static.crates.io/crates/rustls/rustls-0.23.45.crate" |
|
| 580 | - | CHECKSUM_SHA256_190="0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" |
|
| 581 | - | SOURCE_FILENAME_190="rustls-0.23.45.tar.gz" |
|
| 582 | - | SOURCE_URI_191="https://static.crates.io/crates/rustls-pemfile/rustls-pemfile-2.2.0.crate" |
|
| 583 | - | CHECKSUM_SHA256_191="dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" |
|
| 584 | - | SOURCE_FILENAME_191="rustls-pemfile-2.2.0.tar.gz" |
|
| 585 | - | SOURCE_URI_192="https://static.crates.io/crates/rustls-pki-types/rustls-pki-types-1.15.1.crate" |
|
| 586 | - | CHECKSUM_SHA256_192="2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" |
|
| 587 | - | SOURCE_FILENAME_192="rustls-pki-types-1.15.1.tar.gz" |
|
| 588 | - | SOURCE_URI_193="https://static.crates.io/crates/rustls-webpki/rustls-webpki-0.103.15.crate" |
|
| 589 | - | CHECKSUM_SHA256_193="f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" |
|
| 590 | - | SOURCE_FILENAME_193="rustls-webpki-0.103.15.tar.gz" |
|
| 591 | - | SOURCE_URI_194="https://static.crates.io/crates/rustversion/rustversion-1.0.23.crate" |
|
| 592 | - | CHECKSUM_SHA256_194="cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" |
|
| 593 | - | SOURCE_FILENAME_194="rustversion-1.0.23.tar.gz" |
|
| 594 | - | SOURCE_URI_195="https://static.crates.io/crates/rusty-fork/rusty-fork-0.3.1.crate" |
|
| 595 | - | CHECKSUM_SHA256_195="cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" |
|
| 596 | - | SOURCE_FILENAME_195="rusty-fork-0.3.1.tar.gz" |
|
| 597 | - | SOURCE_URI_196="https://static.crates.io/crates/ryu/ryu-1.0.23.crate" |
|
| 598 | - | CHECKSUM_SHA256_196="9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" |
|
| 599 | - | SOURCE_FILENAME_196="ryu-1.0.23.tar.gz" |
|
| 600 | - | SOURCE_URI_197="https://static.crates.io/crates/same-file/same-file-1.0.6.crate" |
|
| 601 | - | CHECKSUM_SHA256_197="93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" |
|
| 602 | - | SOURCE_FILENAME_197="same-file-1.0.6.tar.gz" |
|
| 603 | - | SOURCE_URI_198="https://static.crates.io/crates/scopeguard/scopeguard-1.2.0.crate" |
|
| 604 | - | CHECKSUM_SHA256_198="94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" |
|
| 605 | - | SOURCE_FILENAME_198="scopeguard-1.2.0.tar.gz" |
|
| 606 | - | SOURCE_URI_199="https://static.crates.io/crates/semver/semver-1.0.28.crate" |
|
| 607 | - | CHECKSUM_SHA256_199="8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" |
|
| 608 | - | SOURCE_FILENAME_199="semver-1.0.28.tar.gz" |
|
| 609 | - | SOURCE_URI_200="https://static.crates.io/crates/serde/serde-1.0.229.crate" |
|
| 610 | - | CHECKSUM_SHA256_200="4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" |
|
| 611 | - | SOURCE_FILENAME_200="serde-1.0.229.tar.gz" |
|
| 612 | - | SOURCE_URI_201="https://static.crates.io/crates/serde_core/serde_core-1.0.229.crate" |
|
| 613 | - | CHECKSUM_SHA256_201="67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" |
|
| 614 | - | SOURCE_FILENAME_201="serde_core-1.0.229.tar.gz" |
|
| 615 | - | SOURCE_URI_202="https://static.crates.io/crates/serde_derive/serde_derive-1.0.229.crate" |
|
| 616 | - | CHECKSUM_SHA256_202="e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" |
|
| 617 | - | SOURCE_FILENAME_202="serde_derive-1.0.229.tar.gz" |
|
| 618 | - | SOURCE_URI_203="https://static.crates.io/crates/serde_json/serde_json-1.0.151.crate" |
|
| 619 | - | CHECKSUM_SHA256_203="c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" |
|
| 620 | - | SOURCE_FILENAME_203="serde_json-1.0.151.tar.gz" |
|
| 621 | - | SOURCE_URI_204="https://static.crates.io/crates/serde_path_to_error/serde_path_to_error-0.1.20.crate" |
|
| 622 | - | CHECKSUM_SHA256_204="10a9ff822e371bb5403e391ecd83e182e0e77ba7f6fe0160b795797109d1b457" |
|
| 623 | - | SOURCE_FILENAME_204="serde_path_to_error-0.1.20.tar.gz" |
|
| 624 | - | SOURCE_URI_205="https://static.crates.io/crates/serde_urlencoded/serde_urlencoded-0.7.1.crate" |
|
| 625 | - | CHECKSUM_SHA256_205="d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" |
|
| 626 | - | SOURCE_FILENAME_205="serde_urlencoded-0.7.1.tar.gz" |
|
| 627 | - | SOURCE_URI_206="https://static.crates.io/crates/sha2/sha2-0.11.0.crate" |
|
| 628 | - | CHECKSUM_SHA256_206="446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" |
|
| 629 | - | SOURCE_FILENAME_206="sha2-0.11.0.tar.gz" |
|
| 630 | - | SOURCE_URI_207="https://static.crates.io/crates/shake/shake-0.1.0.crate" |
|
| 631 | - | CHECKSUM_SHA256_207="09057cb2149ad4cbd2da1e26b351f9a4c354219421229c69c3063e6f61947c4a" |
|
| 632 | - | SOURCE_FILENAME_207="shake-0.1.0.tar.gz" |
|
| 633 | - | SOURCE_URI_208="https://static.crates.io/crates/shlex/shlex-2.0.1.crate" |
|
| 634 | - | CHECKSUM_SHA256_208="f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" |
|
| 635 | - | SOURCE_FILENAME_208="shlex-2.0.1.tar.gz" |
|
| 636 | - | SOURCE_URI_209="https://static.crates.io/crates/signature/signature-3.0.0.crate" |
|
| 637 | - | CHECKSUM_SHA256_209="28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" |
|
| 638 | - | SOURCE_FILENAME_209="signature-3.0.0.tar.gz" |
|
| 639 | - | SOURCE_URI_210="https://static.crates.io/crates/simd-adler32/simd-adler32-0.3.10.crate" |
|
| 640 | - | CHECKSUM_SHA256_210="3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" |
|
| 641 | - | SOURCE_FILENAME_210="simd-adler32-0.3.10.tar.gz" |
|
| 642 | - | SOURCE_URI_211="https://static.crates.io/crates/similar/similar-2.7.0.crate" |
|
| 643 | - | CHECKSUM_SHA256_211="bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" |
|
| 644 | - | SOURCE_FILENAME_211="similar-2.7.0.tar.gz" |
|
| 645 | - | SOURCE_URI_212="https://static.crates.io/crates/slab/slab-0.4.12.crate" |
|
| 646 | - | CHECKSUM_SHA256_212="0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" |
|
| 647 | - | SOURCE_FILENAME_212="slab-0.4.12.tar.gz" |
|
| 648 | - | SOURCE_URI_213="https://static.crates.io/crates/smallvec/smallvec-1.16.2.crate" |
|
| 649 | - | CHECKSUM_SHA256_213="f9395f0f0eee849a9b707b2f06bb92a6a422090e2123bb2ef8e87a0e61892a8e" |
|
| 650 | - | SOURCE_FILENAME_213="smallvec-1.16.2.tar.gz" |
|
| 651 | - | SOURCE_URI_214="https://static.crates.io/crates/socket2/socket2-0.6.5.crate" |
|
| 652 | - | CHECKSUM_SHA256_214="c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" |
|
| 653 | - | SOURCE_FILENAME_214="socket2-0.6.5.tar.gz" |
|
| 654 | - | SOURCE_URI_215="https://static.crates.io/crates/spin/spin-0.10.1.crate" |
|
| 655 | - | CHECKSUM_SHA256_215="023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" |
|
| 656 | - | SOURCE_FILENAME_215="spin-0.10.1.tar.gz" |
|
| 657 | - | SOURCE_URI_216="https://static.crates.io/crates/spki/spki-0.8.0.crate" |
|
| 658 | - | CHECKSUM_SHA256_216="1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" |
|
| 659 | - | SOURCE_FILENAME_216="spki-0.8.0.tar.gz" |
|
| 660 | - | SOURCE_URI_217="https://static.crates.io/crates/sponge-cursor/sponge-cursor-0.1.0.crate" |
|
| 661 | - | CHECKSUM_SHA256_217="3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620" |
|
| 662 | - | SOURCE_FILENAME_217="sponge-cursor-0.1.0.tar.gz" |
|
| 663 | - | SOURCE_URI_218="https://static.crates.io/crates/stable_deref_trait/stable_deref_trait-1.2.1.crate" |
|
| 664 | - | CHECKSUM_SHA256_218="6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" |
|
| 665 | - | SOURCE_FILENAME_218="stable_deref_trait-1.2.1.tar.gz" |
|
| 666 | - | SOURCE_URI_219="https://static.crates.io/crates/strsim/strsim-0.11.1.crate" |
|
| 667 | - | CHECKSUM_SHA256_219="7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" |
|
| 668 | - | SOURCE_FILENAME_219="strsim-0.11.1.tar.gz" |
|
| 669 | - | SOURCE_URI_220="https://static.crates.io/crates/subtle/subtle-2.6.1.crate" |
|
| 670 | - | CHECKSUM_SHA256_220="13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" |
|
| 671 | - | SOURCE_FILENAME_220="subtle-2.6.1.tar.gz" |
|
| 672 | - | SOURCE_URI_221="https://static.crates.io/crates/syn/syn-2.0.119.crate" |
|
| 673 | - | CHECKSUM_SHA256_221="872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" |
|
| 674 | - | SOURCE_FILENAME_221="syn-2.0.119.tar.gz" |
|
| 675 | - | SOURCE_URI_222="https://static.crates.io/crates/syn/syn-3.0.6.crate" |
|
| 676 | - | CHECKSUM_SHA256_222="8593e8e72159ed2257d083c7a454a85cbf854f37a0966d8d483aff8c8a3ebcee" |
|
| 677 | - | SOURCE_FILENAME_222="syn-3.0.6.tar.gz" |
|
| 678 | - | SOURCE_URI_223="https://static.crates.io/crates/sync_wrapper/sync_wrapper-1.0.2.crate" |
|
| 679 | - | CHECKSUM_SHA256_223="0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" |
|
| 680 | - | SOURCE_FILENAME_223="sync_wrapper-1.0.2.tar.gz" |
|
| 681 | - | SOURCE_URI_224="https://static.crates.io/crates/synstructure/synstructure-0.13.2.crate" |
|
| 682 | - | CHECKSUM_SHA256_224="728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" |
|
| 683 | - | SOURCE_FILENAME_224="synstructure-0.13.2.tar.gz" |
|
| 684 | - | SOURCE_URI_225="https://static.crates.io/crates/synstructure/synstructure-0.14.0.crate" |
|
| 685 | - | CHECKSUM_SHA256_225="901704edd0dfe137f1987838ee4f259e4e063c31371bdb423f7ae38ec6f77f02" |
|
| 686 | - | SOURCE_FILENAME_225="synstructure-0.14.0.tar.gz" |
|
| 687 | - | SOURCE_URI_226="https://static.crates.io/crates/tempfile/tempfile-3.27.0.crate" |
|
| 688 | - | CHECKSUM_SHA256_226="32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" |
|
| 689 | - | SOURCE_FILENAME_226="tempfile-3.27.0.tar.gz" |
|
| 690 | - | SOURCE_URI_227="https://static.crates.io/crates/thiserror/thiserror-1.0.69.crate" |
|
| 691 | - | CHECKSUM_SHA256_227="b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" |
|
| 692 | - | SOURCE_FILENAME_227="thiserror-1.0.69.tar.gz" |
|
| 693 | - | SOURCE_URI_228="https://static.crates.io/crates/thiserror/thiserror-2.0.21.crate" |
|
| 694 | - | CHECKSUM_SHA256_228="09e52cb86a36cede5cb101bf8908837b3e4c6e5e59fe7fd85c23fb56200d189e" |
|
| 695 | - | SOURCE_FILENAME_228="thiserror-2.0.21.tar.gz" |
|
| 696 | - | SOURCE_URI_229="https://static.crates.io/crates/thiserror-impl/thiserror-impl-1.0.69.crate" |
|
| 697 | - | CHECKSUM_SHA256_229="4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" |
|
| 698 | - | SOURCE_FILENAME_229="thiserror-impl-1.0.69.tar.gz" |
|
| 699 | - | SOURCE_URI_230="https://static.crates.io/crates/thiserror-impl/thiserror-impl-2.0.21.crate" |
|
| 700 | - | CHECKSUM_SHA256_230="fe5197923287db20a58125f0bc85c062f7f2c892de97b18c356f9efb14b28524" |
|
| 701 | - | SOURCE_FILENAME_230="thiserror-impl-2.0.21.tar.gz" |
|
| 702 | - | SOURCE_URI_231="https://static.crates.io/crates/time/time-0.3.55.crate" |
|
| 703 | - | CHECKSUM_SHA256_231="cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" |
|
| 704 | - | SOURCE_FILENAME_231="time-0.3.55.tar.gz" |
|
| 705 | - | SOURCE_URI_232="https://static.crates.io/crates/time-core/time-core-0.1.9.crate" |
|
| 706 | - | CHECKSUM_SHA256_232="9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" |
|
| 707 | - | SOURCE_FILENAME_232="time-core-0.1.9.tar.gz" |
|
| 708 | - | SOURCE_URI_233="https://static.crates.io/crates/time-macros/time-macros-0.2.32.crate" |
|
| 709 | - | CHECKSUM_SHA256_233="7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" |
|
| 710 | - | SOURCE_FILENAME_233="time-macros-0.2.32.tar.gz" |
|
| 711 | - | SOURCE_URI_234="https://static.crates.io/crates/tinystr/tinystr-0.8.4.crate" |
|
| 712 | - | CHECKSUM_SHA256_234="b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" |
|
| 713 | - | SOURCE_FILENAME_234="tinystr-0.8.4.tar.gz" |
|
| 714 | - | SOURCE_URI_235="https://static.crates.io/crates/tokio/tokio-1.53.1.crate" |
|
| 715 | - | CHECKSUM_SHA256_235="202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" |
|
| 716 | - | SOURCE_FILENAME_235="tokio-1.53.1.tar.gz" |
|
| 717 | - | SOURCE_URI_236="https://static.crates.io/crates/tokio-macros/tokio-macros-2.7.2.crate" |
|
| 718 | - | CHECKSUM_SHA256_236="78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" |
|
| 719 | - | SOURCE_FILENAME_236="tokio-macros-2.7.2.tar.gz" |
|
| 720 | - | SOURCE_URI_237="https://static.crates.io/crates/tokio-rustls/tokio-rustls-0.26.5.crate" |
|
| 721 | - | CHECKSUM_SHA256_237="b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" |
|
| 722 | - | SOURCE_FILENAME_237="tokio-rustls-0.26.5.tar.gz" |
|
| 723 | - | SOURCE_URI_238="https://static.crates.io/crates/tokio-util/tokio-util-0.7.19.crate" |
|
| 724 | - | CHECKSUM_SHA256_238="494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" |
|
| 725 | - | SOURCE_FILENAME_238="tokio-util-0.7.19.tar.gz" |
|
| 726 | - | SOURCE_URI_239="https://static.crates.io/crates/tower/tower-0.5.3.crate" |
|
| 727 | - | CHECKSUM_SHA256_239="ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" |
|
| 728 | - | SOURCE_FILENAME_239="tower-0.5.3.tar.gz" |
|
| 729 | - | SOURCE_URI_240="https://static.crates.io/crates/tower-layer/tower-layer-0.3.3.crate" |
|
| 730 | - | CHECKSUM_SHA256_240="121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" |
|
| 731 | - | SOURCE_FILENAME_240="tower-layer-0.3.3.tar.gz" |
|
| 732 | - | SOURCE_URI_241="https://static.crates.io/crates/tower-service/tower-service-0.3.3.crate" |
|
| 733 | - | CHECKSUM_SHA256_241="8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" |
|
| 734 | - | SOURCE_FILENAME_241="tower-service-0.3.3.tar.gz" |
|
| 735 | - | SOURCE_URI_242="https://static.crates.io/crates/tracing/tracing-0.1.44.crate" |
|
| 736 | - | CHECKSUM_SHA256_242="63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" |
|
| 737 | - | SOURCE_FILENAME_242="tracing-0.1.44.tar.gz" |
|
| 738 | - | SOURCE_URI_243="https://static.crates.io/crates/tracing-attributes/tracing-attributes-0.1.31.crate" |
|
| 739 | - | CHECKSUM_SHA256_243="7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" |
|
| 740 | - | SOURCE_FILENAME_243="tracing-attributes-0.1.31.tar.gz" |
|
| 741 | - | SOURCE_URI_244="https://static.crates.io/crates/tracing-core/tracing-core-0.1.36.crate" |
|
| 742 | - | CHECKSUM_SHA256_244="db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" |
|
| 743 | - | SOURCE_FILENAME_244="tracing-core-0.1.36.tar.gz" |
|
| 744 | - | SOURCE_URI_245="https://static.crates.io/crates/typenum/typenum-1.20.1.crate" |
|
| 745 | - | CHECKSUM_SHA256_245="b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" |
|
| 746 | - | SOURCE_FILENAME_245="typenum-1.20.1.tar.gz" |
|
| 747 | - | SOURCE_URI_246="https://static.crates.io/crates/unarray/unarray-0.1.4.crate" |
|
| 748 | - | CHECKSUM_SHA256_246="eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" |
|
| 749 | - | SOURCE_FILENAME_246="unarray-0.1.4.tar.gz" |
|
| 750 | - | SOURCE_URI_247="https://static.crates.io/crates/unicode-ident/unicode-ident-1.0.26.crate" |
|
| 751 | - | CHECKSUM_SHA256_247="d245f478577f809a851594d02313b640fb437e0bb33866753cff937863096954" |
|
| 752 | - | SOURCE_FILENAME_247="unicode-ident-1.0.26.tar.gz" |
|
| 753 | - | SOURCE_URI_248="https://static.crates.io/crates/unicode-width/unicode-width-0.2.2.crate" |
|
| 754 | - | CHECKSUM_SHA256_248="b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" |
|
| 755 | - | SOURCE_FILENAME_248="unicode-width-0.2.2.tar.gz" |
|
| 756 | - | SOURCE_URI_249="https://static.crates.io/crates/untrusted/untrusted-0.9.0.crate" |
|
| 757 | - | CHECKSUM_SHA256_249="8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" |
|
| 758 | - | SOURCE_FILENAME_249="untrusted-0.9.0.tar.gz" |
|
| 759 | - | SOURCE_URI_250="https://static.crates.io/crates/ureq/ureq-2.12.1.crate" |
|
| 760 | - | CHECKSUM_SHA256_250="02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" |
|
| 761 | - | SOURCE_FILENAME_250="ureq-2.12.1.tar.gz" |
|
| 762 | - | SOURCE_URI_251="https://static.crates.io/crates/url/url-2.5.8.crate" |
|
| 763 | - | CHECKSUM_SHA256_251="ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" |
|
| 764 | - | SOURCE_FILENAME_251="url-2.5.8.tar.gz" |
|
| 765 | - | SOURCE_URI_252="https://static.crates.io/crates/utf8_iter/utf8_iter-1.0.4.crate" |
|
| 766 | - | CHECKSUM_SHA256_252="b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" |
|
| 767 | - | SOURCE_FILENAME_252="utf8_iter-1.0.4.tar.gz" |
|
| 768 | - | SOURCE_URI_253="https://static.crates.io/crates/utf8parse/utf8parse-0.2.2.crate" |
|
| 769 | - | CHECKSUM_SHA256_253="06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" |
|
| 770 | - | SOURCE_FILENAME_253="utf8parse-0.2.2.tar.gz" |
|
| 771 | - | SOURCE_URI_254="https://static.crates.io/crates/version_check/version_check-0.9.5.crate" |
|
| 772 | - | CHECKSUM_SHA256_254="0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" |
|
| 773 | - | SOURCE_FILENAME_254="version_check-0.9.5.tar.gz" |
|
| 774 | - | SOURCE_URI_255="https://static.crates.io/crates/wait-timeout/wait-timeout-0.2.1.crate" |
|
| 775 | - | CHECKSUM_SHA256_255="09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" |
|
| 776 | - | SOURCE_FILENAME_255="wait-timeout-0.2.1.tar.gz" |
|
| 777 | - | SOURCE_URI_256="https://static.crates.io/crates/walkdir/walkdir-2.5.0.crate" |
|
| 778 | - | CHECKSUM_SHA256_256="29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" |
|
| 779 | - | SOURCE_FILENAME_256="walkdir-2.5.0.tar.gz" |
|
| 780 | - | SOURCE_URI_257="https://static.crates.io/crates/wasi/wasi-0.11.1+wasi-snapshot-preview1.crate" |
|
| 781 | - | CHECKSUM_SHA256_257="ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" |
|
| 782 | - | SOURCE_FILENAME_257="wasi-0.11.1+wasi-snapshot-preview1.tar.gz" |
|
| 783 | - | SOURCE_URI_258="https://static.crates.io/crates/wasip2/wasip2-1.0.4+wasi-0.2.12.crate" |
|
| 784 | - | CHECKSUM_SHA256_258="b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" |
|
| 785 | - | SOURCE_FILENAME_258="wasip2-1.0.4+wasi-0.2.12.tar.gz" |
|
| 786 | - | SOURCE_URI_259="https://static.crates.io/crates/wasm-bindgen/wasm-bindgen-0.2.129.crate" |
|
| 787 | - | CHECKSUM_SHA256_259="9bb54f33acc68fd454578d9820b0bde1a1a3d17aa17bb7b6595806d02886d409" |
|
| 788 | - | SOURCE_FILENAME_259="wasm-bindgen-0.2.129.tar.gz" |
|
| 789 | - | SOURCE_URI_260="https://static.crates.io/crates/wasm-bindgen-futures/wasm-bindgen-futures-0.4.79.crate" |
|
| 790 | - | CHECKSUM_SHA256_260="3cbab34de2d982e9b48e18d216d04c4a6f641066ff19ffb699980f591ee3610e" |
|
| 791 | - | SOURCE_FILENAME_260="wasm-bindgen-futures-0.4.79.tar.gz" |
|
| 792 | - | SOURCE_URI_261="https://static.crates.io/crates/wasm-bindgen-macro/wasm-bindgen-macro-0.2.129.crate" |
|
| 793 | - | CHECKSUM_SHA256_261="2e29d0c35b16e224a7eeb5cd2d25e3e1968fbd65604117b44d3b789d00ee8535" |
|
| 794 | - | SOURCE_FILENAME_261="wasm-bindgen-macro-0.2.129.tar.gz" |
|
| 795 | - | SOURCE_URI_262="https://static.crates.io/crates/wasm-bindgen-macro-support/wasm-bindgen-macro-support-0.2.129.crate" |
|
| 796 | - | CHECKSUM_SHA256_262="6f501a8bc3719dba86ef8ae4728879c08001bea749eb1333ac5b91e040e2a6b7" |
|
| 797 | - | SOURCE_FILENAME_262="wasm-bindgen-macro-support-0.2.129.tar.gz" |
|
| 798 | - | SOURCE_URI_263="https://static.crates.io/crates/wasm-bindgen-shared/wasm-bindgen-shared-0.2.129.crate" |
|
| 799 | - | CHECKSUM_SHA256_263="23f0c9c52aa7cd7d77769a4cfe2a9adb1b331f489a41d912ce14513d5ab995c6" |
|
| 800 | - | SOURCE_FILENAME_263="wasm-bindgen-shared-0.2.129.tar.gz" |
|
| 801 | - | SOURCE_URI_264="https://static.crates.io/crates/web-time/web-time-1.1.0.crate" |
|
| 802 | - | CHECKSUM_SHA256_264="5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" |
|
| 803 | - | SOURCE_FILENAME_264="web-time-1.1.0.tar.gz" |
|
| 804 | - | SOURCE_URI_265="https://static.crates.io/crates/webpki-roots/webpki-roots-0.26.11.crate" |
|
| 805 | - | CHECKSUM_SHA256_265="521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" |
|
| 806 | - | SOURCE_FILENAME_265="webpki-roots-0.26.11.tar.gz" |
|
| 807 | - | SOURCE_URI_266="https://static.crates.io/crates/webpki-roots/webpki-roots-1.0.9.crate" |
|
| 808 | - | CHECKSUM_SHA256_266="7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" |
|
| 809 | - | SOURCE_FILENAME_266="webpki-roots-1.0.9.tar.gz" |
|
| 810 | - | SOURCE_URI_267="https://static.crates.io/crates/winapi-util/winapi-util-0.1.11.crate" |
|
| 811 | - | CHECKSUM_SHA256_267="c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" |
|
| 812 | - | SOURCE_FILENAME_267="winapi-util-0.1.11.tar.gz" |
|
| 813 | - | SOURCE_URI_268="https://static.crates.io/crates/windows-core/windows-core-0.62.2.crate" |
|
| 814 | - | CHECKSUM_SHA256_268="b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" |
|
| 815 | - | SOURCE_FILENAME_268="windows-core-0.62.2.tar.gz" |
|
| 816 | - | SOURCE_URI_269="https://static.crates.io/crates/windows-implement/windows-implement-0.60.2.crate" |
|
| 817 | - | CHECKSUM_SHA256_269="053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" |
|
| 818 | - | SOURCE_FILENAME_269="windows-implement-0.60.2.tar.gz" |
|
| 819 | - | SOURCE_URI_270="https://static.crates.io/crates/windows-interface/windows-interface-0.59.3.crate" |
|
| 820 | - | CHECKSUM_SHA256_270="3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" |
|
| 821 | - | SOURCE_FILENAME_270="windows-interface-0.59.3.tar.gz" |
|
| 822 | - | SOURCE_URI_271="https://static.crates.io/crates/windows-link/windows-link-0.2.1.crate" |
|
| 823 | - | CHECKSUM_SHA256_271="f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" |
|
| 824 | - | SOURCE_FILENAME_271="windows-link-0.2.1.tar.gz" |
|
| 825 | - | SOURCE_URI_272="https://static.crates.io/crates/windows-result/windows-result-0.4.1.crate" |
|
| 826 | - | CHECKSUM_SHA256_272="7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" |
|
| 827 | - | SOURCE_FILENAME_272="windows-result-0.4.1.tar.gz" |
|
| 828 | - | SOURCE_URI_273="https://static.crates.io/crates/windows-strings/windows-strings-0.5.1.crate" |
|
| 829 | - | CHECKSUM_SHA256_273="7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" |
|
| 830 | - | SOURCE_FILENAME_273="windows-strings-0.5.1.tar.gz" |
|
| 831 | - | SOURCE_URI_274="https://static.crates.io/crates/windows-sys/windows-sys-0.52.0.crate" |
|
| 832 | - | CHECKSUM_SHA256_274="282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" |
|
| 833 | - | SOURCE_FILENAME_274="windows-sys-0.52.0.tar.gz" |
|
| 834 | - | SOURCE_URI_275="https://static.crates.io/crates/windows-sys/windows-sys-0.59.0.crate" |
|
| 835 | - | CHECKSUM_SHA256_275="1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" |
|
| 836 | - | SOURCE_FILENAME_275="windows-sys-0.59.0.tar.gz" |
|
| 837 | - | SOURCE_URI_276="https://static.crates.io/crates/windows-sys/windows-sys-0.61.2.crate" |
|
| 838 | - | CHECKSUM_SHA256_276="ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" |
|
| 839 | - | SOURCE_FILENAME_276="windows-sys-0.61.2.tar.gz" |
|
| 840 | - | SOURCE_URI_277="https://static.crates.io/crates/windows-targets/windows-targets-0.52.6.crate" |
|
| 841 | - | CHECKSUM_SHA256_277="9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" |
|
| 842 | - | SOURCE_FILENAME_277="windows-targets-0.52.6.tar.gz" |
|
| 843 | - | SOURCE_URI_278="https://static.crates.io/crates/windows_aarch64_gnullvm/windows_aarch64_gnullvm-0.52.6.crate" |
|
| 844 | - | CHECKSUM_SHA256_278="32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" |
|
| 845 | - | SOURCE_FILENAME_278="windows_aarch64_gnullvm-0.52.6.tar.gz" |
|
| 846 | - | SOURCE_URI_279="https://static.crates.io/crates/windows_aarch64_msvc/windows_aarch64_msvc-0.52.6.crate" |
|
| 847 | - | CHECKSUM_SHA256_279="09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" |
|
| 848 | - | SOURCE_FILENAME_279="windows_aarch64_msvc-0.52.6.tar.gz" |
|
| 849 | - | SOURCE_URI_280="https://static.crates.io/crates/windows_i686_gnu/windows_i686_gnu-0.52.6.crate" |
|
| 850 | - | CHECKSUM_SHA256_280="8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" |
|
| 851 | - | SOURCE_FILENAME_280="windows_i686_gnu-0.52.6.tar.gz" |
|
| 852 | - | SOURCE_URI_281="https://static.crates.io/crates/windows_i686_gnullvm/windows_i686_gnullvm-0.52.6.crate" |
|
| 853 | - | CHECKSUM_SHA256_281="0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" |
|
| 854 | - | SOURCE_FILENAME_281="windows_i686_gnullvm-0.52.6.tar.gz" |
|
| 855 | - | SOURCE_URI_282="https://static.crates.io/crates/windows_i686_msvc/windows_i686_msvc-0.52.6.crate" |
|
| 856 | - | CHECKSUM_SHA256_282="240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" |
|
| 857 | - | SOURCE_FILENAME_282="windows_i686_msvc-0.52.6.tar.gz" |
|
| 858 | - | SOURCE_URI_283="https://static.crates.io/crates/windows_x86_64_gnu/windows_x86_64_gnu-0.52.6.crate" |
|
| 859 | - | CHECKSUM_SHA256_283="147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" |
|
| 860 | - | SOURCE_FILENAME_283="windows_x86_64_gnu-0.52.6.tar.gz" |
|
| 861 | - | SOURCE_URI_284="https://static.crates.io/crates/windows_x86_64_gnullvm/windows_x86_64_gnullvm-0.52.6.crate" |
|
| 862 | - | CHECKSUM_SHA256_284="24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" |
|
| 863 | - | SOURCE_FILENAME_284="windows_x86_64_gnullvm-0.52.6.tar.gz" |
|
| 864 | - | SOURCE_URI_285="https://static.crates.io/crates/windows_x86_64_msvc/windows_x86_64_msvc-0.52.6.crate" |
|
| 865 | - | CHECKSUM_SHA256_285="589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" |
|
| 866 | - | SOURCE_FILENAME_285="windows_x86_64_msvc-0.52.6.tar.gz" |
|
| 867 | - | SOURCE_URI_286="https://static.crates.io/crates/wit-bindgen/wit-bindgen-0.57.1.crate" |
|
| 868 | - | CHECKSUM_SHA256_286="1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" |
|
| 869 | - | SOURCE_FILENAME_286="wit-bindgen-0.57.1.tar.gz" |
|
| 870 | - | SOURCE_URI_287="https://static.crates.io/crates/writeable/writeable-0.6.4.crate" |
|
| 871 | - | CHECKSUM_SHA256_287="3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" |
|
| 872 | - | SOURCE_FILENAME_287="writeable-0.6.4.tar.gz" |
|
| 873 | - | SOURCE_URI_288="https://static.crates.io/crates/x509-parser/x509-parser-0.18.1.crate" |
|
| 874 | - | CHECKSUM_SHA256_288="d43b0f71ce057da06bc0851b23ee24f3f86190b07203dd8f567d0b706a185202" |
|
| 875 | - | SOURCE_FILENAME_288="x509-parser-0.18.1.tar.gz" |
|
| 876 | - | SOURCE_URI_289="https://static.crates.io/crates/yasna/yasna-0.6.0.crate" |
|
| 877 | - | CHECKSUM_SHA256_289="b5f6765e852b9b4dc8e2a76843e4d64d1cea8e79bcde0b6901aea8e7c7f08282" |
|
| 878 | - | SOURCE_FILENAME_289="yasna-0.6.0.tar.gz" |
|
| 879 | - | SOURCE_URI_290="https://static.crates.io/crates/yoke/yoke-0.8.3.crate" |
|
| 880 | - | CHECKSUM_SHA256_290="709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" |
|
| 881 | - | SOURCE_FILENAME_290="yoke-0.8.3.tar.gz" |
|
| 882 | - | SOURCE_URI_291="https://static.crates.io/crates/yoke-derive/yoke-derive-0.8.3.crate" |
|
| 883 | - | CHECKSUM_SHA256_291="33811428bee40dbceb6d545e95754741d17a6aef9a4849f0fd62e2ba4f412a78" |
|
| 884 | - | SOURCE_FILENAME_291="yoke-derive-0.8.3.tar.gz" |
|
| 885 | - | SOURCE_URI_292="https://static.crates.io/crates/zerocopy/zerocopy-0.8.59.crate" |
|
| 886 | - | CHECKSUM_SHA256_292="6df92bf3d9227be3d53173901ddbffac2babc27ae50f397776ffd6dc33f800cb" |
|
| 887 | - | SOURCE_FILENAME_292="zerocopy-0.8.59.tar.gz" |
|
| 888 | - | SOURCE_URI_293="https://static.crates.io/crates/zerocopy-derive/zerocopy-derive-0.8.59.crate" |
|
| 889 | - | CHECKSUM_SHA256_293="ac4f328cf2f05d084e496c3e9c3f33ed0a183656a16e1fcec4d464d8373aec82" |
|
| 890 | - | SOURCE_FILENAME_293="zerocopy-derive-0.8.59.tar.gz" |
|
| 891 | - | SOURCE_URI_294="https://static.crates.io/crates/zerofrom/zerofrom-0.1.8.crate" |
|
| 892 | - | CHECKSUM_SHA256_294="0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" |
|
| 893 | - | SOURCE_FILENAME_294="zerofrom-0.1.8.tar.gz" |
|
| 894 | - | SOURCE_URI_295="https://static.crates.io/crates/zerofrom-derive/zerofrom-derive-0.1.8.crate" |
|
| 895 | - | CHECKSUM_SHA256_295="f75b4683f6c7f45248d4d64056a24298c6281e0993356d7d1b4a1a962ef10d4a" |
|
| 896 | - | SOURCE_FILENAME_295="zerofrom-derive-0.1.8.tar.gz" |
|
| 897 | - | SOURCE_URI_296="https://static.crates.io/crates/zeroize/zeroize-1.9.0.crate" |
|
| 898 | - | CHECKSUM_SHA256_296="e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" |
|
| 899 | - | SOURCE_FILENAME_296="zeroize-1.9.0.tar.gz" |
|
| 900 | - | SOURCE_URI_297="https://static.crates.io/crates/zerotrie/zerotrie-0.2.5.crate" |
|
| 901 | - | CHECKSUM_SHA256_297="4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" |
|
| 902 | - | SOURCE_FILENAME_297="zerotrie-0.2.5.tar.gz" |
|
| 903 | - | SOURCE_URI_298="https://static.crates.io/crates/zerovec/zerovec-0.11.8.crate" |
|
| 904 | - | CHECKSUM_SHA256_298="bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" |
|
| 905 | - | SOURCE_FILENAME_298="zerovec-0.11.8.tar.gz" |
|
| 906 | - | SOURCE_URI_299="https://static.crates.io/crates/zerovec-derive/zerovec-derive-0.11.6.crate" |
|
| 907 | - | CHECKSUM_SHA256_299="34df6fc39dbd26ddc9c10e6a2984476e13acce22e64e4487636ef494369225da" |
|
| 908 | - | SOURCE_FILENAME_299="zerovec-derive-0.11.6.tar.gz" |
|
| 909 | - | SOURCE_URI_300="https://static.crates.io/crates/zlib-rs/zlib-rs-0.6.8.crate" |
|
| 910 | - | CHECKSUM_SHA256_300="b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" |
|
| 911 | - | SOURCE_FILENAME_300="zlib-rs-0.6.8.tar.gz" |
|
| 912 | - | SOURCE_URI_301="https://static.crates.io/crates/zmij/zmij-1.0.23.crate" |
|
| 913 | - | CHECKSUM_SHA256_301="29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" |
|
| 914 | - | SOURCE_FILENAME_301="zmij-1.0.23.tar.gz" |
|
| 915 | - | SOURCE_URI_302="https://static.crates.io/crates/zstd/zstd-0.13.3.crate" |
|
| 916 | - | CHECKSUM_SHA256_302="e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" |
|
| 917 | - | SOURCE_FILENAME_302="zstd-0.13.3.tar.gz" |
|
| 918 | - | SOURCE_URI_303="https://static.crates.io/crates/zstd-safe/zstd-safe-7.3.0.crate" |
|
| 919 | - | CHECKSUM_SHA256_303="64d80649ab6db9d9f6f9c80a40becd948eda4714a0a5ac8c4d157a32231c7882" |
|
| 920 | - | SOURCE_FILENAME_303="zstd-safe-7.3.0.tar.gz" |
|
| 921 | - | SOURCE_URI_304="https://static.crates.io/crates/zstd-sys/zstd-sys-2.1.0+zstd.1.5.7.crate" |
|
| 922 | - | CHECKSUM_SHA256_304="0ef0a8027ec3ee71300ab3bcbcd0393f434aa72b91ca6d635a39941deae8eea0" |
|
| 923 | - | SOURCE_FILENAME_304="zstd-sys-2.1.0+zstd.1.5.7.tar.gz" |
|
| 924 | - | ||
| 925 | - | ARCHITECTURES="!all x86_64" |
|
| 926 | - | ||
| 927 | - | PROVIDES=" |
|
| 928 | - | oxy$secondaryArchSuffix = $portVersion |
|
| 929 | - | cmd:oxy |
|
| 930 | - | " |
|
| 931 | - | REQUIRES=" |
|
| 932 | - | haiku$secondaryArchSuffix |
|
| 933 | - | lib:libzstd$secondaryArchSuffix |
|
| 934 | - | " |
|
| 935 | - | ||
| 936 | - | BUILD_REQUIRES=" |
|
| 937 | - | haiku${secondaryArchSuffix}_devel |
|
| 938 | - | devel:libzstd$secondaryArchSuffix |
|
| 939 | - | " |
|
| 940 | - | BUILD_PREREQUIRES=" |
|
| 941 | - | cmd:gcc$secondaryArchSuffix |
|
| 942 | - | cmd:pkg_config$secondaryArchSuffix |
|
| 943 | - | cmd:rustc$secondaryArchSuffix |
|
| 944 | - | " |
|
| 945 | - | ||
| 946 | - | BUILD() |
|
| 947 | - | { |
|
| 948 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 949 | - | vendor=$CARGO_HOME/haiku |
|
| 950 | - | mkdir -p "$vendor" |
|
| 951 | - | for i in $(seq 2 304); do |
|
| 952 | - | eval "srcDir=\$sourceDir$i" |
|
| 953 | - | eval "sha256sum=\$CHECKSUM_SHA256_$i" |
|
| 954 | - | set -- "$srcDir"/* |
|
| 955 | - | ln -sf "$1" "$vendor" |
|
| 956 | - | cat <<-EOF >"$vendor/${1##*/}/.cargo-checksum.json" |
|
| 957 | - | { |
|
| 958 | - | "package": "$sha256sum", |
|
| 959 | - | "files": {} |
|
| 960 | - | } |
|
| 961 | - | EOF |
|
| 962 | - | done |
|
| 963 | - | ||
| 964 | - | cat <<-EOF >"$CARGO_HOME"/config.toml |
|
| 965 | - | [source.haiku] |
|
| 966 | - | directory = "$vendor" |
|
| 967 | - | ||
| 968 | - | [source.crates-io] |
|
| 969 | - | replace-with = "haiku" |
|
| 970 | - | EOF |
|
| 971 | - | ||
| 972 | - | # The bundled zstd's hidden symbols break the link on Haiku: use the system's. |
|
| 973 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 974 | - | export OXY_BUILD=v$portVersion |
|
| 975 | - | cargo build --release --frozen -p oxy |
|
| 976 | - | } |
|
| 977 | - | ||
| 978 | - | INSTALL() |
|
| 979 | - | { |
|
| 980 | - | install -v -m 755 -d "$prefix"/bin "$docDir" |
|
| 981 | - | install -v -m 755 ./target/release/oxy "$prefix"/bin |
|
| 982 | - | install -v -m 644 README.md LICENSE* "$docDir" |
|
| 983 | - | } |
|
| 984 | - | ||
| 985 | - | TEST() |
|
| 986 | - | { |
|
| 987 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 988 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 989 | - | cargo test --release --frozen -p oxy-core |
|
| 990 | - | } |
removed packaging/haikuports/icons/oh-16.png +0 −0
No line changes.
removed packaging/haikuports/icons/oh-32.png +0 −0
No line changes.
removed packaging/haikuports/icons/oh-64.png +0 −0
No line changes.
removed packaging/haikuports/icons/oh.hvif +0 −0
No line changes.
removed packaging/haikuports/icons/oh.svg +0 −17
| 1 | - | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64"> |
|
| 2 | - | <defs> |
|
| 3 | - | <linearGradient id="g" gradientUnits="userSpaceOnUse" x1="-22" y1="-11" x2="22" y2="11"> |
|
| 4 | - | <stop offset="0%" stop-color="#00F0FF"/> |
|
| 5 | - | <stop offset="100%" stop-color="#0072FF"/> |
|
| 6 | - | </linearGradient> |
|
| 7 | - | </defs> |
|
| 8 | - | <rect width="64" height="64" rx="14" fill="#070c18"/> |
|
| 9 | - | <g transform="translate(32 32)"> |
|
| 10 | - | <path d="M -11 -6 L 11 -6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 11 | - | <path d="M -11 6 L 11 6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 12 | - | <circle cx="-11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 13 | - | <circle cx="-11" cy="0" r="3.5" fill="#00F0FF"/> |
|
| 14 | - | <circle cx="11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 15 | - | <circle cx="11" cy="0" r="3.5" fill="#FFFFFF"/> |
|
| 16 | - | </g> |
|
| 17 | - | </svg> |
removed packaging/haikuports/icons/oxy-16.png +0 −0
No line changes.
removed packaging/haikuports/icons/oxy-32.png +0 −0
No line changes.
removed packaging/haikuports/icons/oxy-64.png +0 −0
No line changes.
removed packaging/haikuports/icons/oxy.hvif +0 −0
No line changes.
removed packaging/haikuports/icons/oxy.svg +0 −17
| 1 | - | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64"> |
|
| 2 | - | <defs> |
|
| 3 | - | <linearGradient id="g" gradientUnits="userSpaceOnUse" x1="-22" y1="-11" x2="22" y2="11"> |
|
| 4 | - | <stop offset="0%" stop-color="#00F0FF"/> |
|
| 5 | - | <stop offset="100%" stop-color="#0072FF"/> |
|
| 6 | - | </linearGradient> |
|
| 7 | - | </defs> |
|
| 8 | - | <rect width="64" height="64" rx="14" fill="#C9DCF5"/><rect x="1.5" y="1.5" width="61" height="61" rx="12.5" fill="#F2F7FF"/> |
|
| 9 | - | <g transform="translate(32 32)"> |
|
| 10 | - | <path d="M -11 -6 L 11 -6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 11 | - | <path d="M -11 6 L 11 6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 12 | - | <circle cx="-11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 13 | - | <circle cx="-11" cy="0" r="3.5" fill="#00F0FF"/> |
|
| 14 | - | <circle cx="11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 15 | - | <circle cx="11" cy="0" r="3.5" fill="#0072FF"/> |
|
| 16 | - | </g> |
|
| 17 | - | </svg> |
removed packaging/haikuports/make-icons.py +0 −163
| 1 | - | #!/usr/bin/env python3 |
|
| 2 | - | """HaikuDepot icons for oxy and oh (oxygen#157): the Oxygen mark as Haiku's |
|
| 3 | - | vector icon format (HVIF), and as SVG to render the 16, 32 and 64 px PNGs. |
|
| 4 | - | ||
| 5 | - | A family of two (Andy, 2026-10-29): Oxygen (oxy, the Oxygen VCS extension) |
|
| 6 | - | is the mark on a pale rounded tile with a blue right dot; OxygenHub (oh, the |
|
| 7 | - | OxygenHub extension) is the mark on the hub's dark tile with a white one, as |
|
| 8 | - | oxygenhub/assets/icons/oxygenhub.svg. Each keeps its edge on light and dark |
|
| 9 | - | backgrounds alike. |
|
| 10 | - | ||
| 11 | - | make-icons.py OUTDIR writes oxy.hvif, oh.hvif, oxy.svg, oh.svg |
|
| 12 | - | ||
| 13 | - | HVIF as Haiku's FlatIconImporter reads it: "ncif", then styles, paths and |
|
| 14 | - | shapes, each a count byte and its items; coordinates in a 64-unit canvas. |
|
| 15 | - | """ |
|
| 16 | - | import math |
|
| 17 | - | import struct |
|
| 18 | - | import sys |
|
| 19 | - | ||
| 20 | - | CYAN, BLUE, WHITE, TILE = (0x00, 0xF0, 0xFF), (0x00, 0x72, 0xFF), (0xFF, 0xFF, 0xFF), (0x07, 0x0C, 0x18) |
|
| 21 | - | LIGHT, EDGE = (0xF2, 0xF7, 0xFF), (0xC9, 0xDC, 0xF5) |
|
| 22 | - | K = 0.5522847498 # a circle's quarter as one cubic Bézier |
|
| 23 | - | ||
| 24 | - | ||
| 25 | - | def coord(v): |
|
| 26 | - | if v == int(v) and -32 <= v <= 95: |
|
| 27 | - | return bytes([int(v) + 32]) |
|
| 28 | - | n = int(round((v + 128.0) * 102.0)) |
|
| 29 | - | return bytes([(n >> 8) | 0x80, n & 0xFF]) |
|
| 30 | - | ||
| 31 | - | ||
| 32 | - | def float24(v): |
|
| 33 | - | if v == 0: |
|
| 34 | - | return b"\0\0\0" |
|
| 35 | - | bits = struct.unpack(">I", struct.pack(">f", v))[0] |
|
| 36 | - | sign, exp, man = bits >> 31, ((bits >> 23) & 0xFF) - 127, bits & 0x7FFFFF |
|
| 37 | - | if not -32 <= exp < 32: |
|
| 38 | - | raise ValueError(f"{v} does not fit a float24") |
|
| 39 | - | n = (sign << 23) | ((exp + 32) << 17) | (man >> 6) |
|
| 40 | - | return n.to_bytes(3, "big") |
|
| 41 | - | ||
| 42 | - | ||
| 43 | - | def solid(rgb): |
|
| 44 | - | return bytes([3, *rgb]) # STYLE_TYPE_SOLID_COLOR_NO_ALPHA |
|
| 45 | - | ||
| 46 | - | ||
| 47 | - | def linear(p1, p2, stops): |
|
| 48 | - | """A linear gradient from p1 to p2: gradient space runs x from -64 to 64.""" |
|
| 49 | - | dx, dy = (p2[0] - p1[0]) / 128.0, (p2[1] - p1[1]) / 128.0 |
|
| 50 | - | mx, my = (p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2 |
|
| 51 | - | out = bytes([2, 0, (1 << 1) | (1 << 2), len(stops)]) # gradient, linear, transform | no alpha |
|
| 52 | - | for v in (dx, dy, -dy, dx, mx, my): |
|
| 53 | - | out += float24(v) |
|
| 54 | - | for off, rgb in stops: |
|
| 55 | - | out += bytes([off, *rgb]) |
|
| 56 | - | return out |
|
| 57 | - | ||
| 58 | - | ||
| 59 | - | def line(a, b): |
|
| 60 | - | return bytes([1 << 3, 2]) + coord(a[0]) + coord(a[1]) + coord(b[0]) + coord(b[1]) # no curves, open |
|
| 61 | - | ||
| 62 | - | ||
| 63 | - | def curve_path(points, closed=True): |
|
| 64 | - | """points: (x, y, in_x, in_y, out_x, out_y).""" |
|
| 65 | - | out = bytes([(1 << 1) if closed else 0, len(points)]) |
|
| 66 | - | for p in points: |
|
| 67 | - | for v in p: |
|
| 68 | - | out += coord(v) |
|
| 69 | - | return out |
|
| 70 | - | ||
| 71 | - | ||
| 72 | - | def circle(cx, cy, r): |
|
| 73 | - | k = r * K |
|
| 74 | - | pts = [(cx, cy - r, cx - k, cy - r, cx + k, cy - r), (cx + r, cy, cx + r, cy - k, cx + r, cy + k), |
|
| 75 | - | (cx, cy + r, cx + k, cy + r, cx - k, cy + r), (cx - r, cy, cx - r, cy + k, cx - r, cy - k)] |
|
| 76 | - | return curve_path(pts) |
|
| 77 | - | ||
| 78 | - | ||
| 79 | - | def rounded(x, y, w, h, r): |
|
| 80 | - | k = r * (1 - K) |
|
| 81 | - | x2, y2 = x + w, y + h |
|
| 82 | - | pts = [ |
|
| 83 | - | (x + r, y, x + k, y, x + r, y), (x2 - r, y, x2 - r, y, x2 - k, y), |
|
| 84 | - | (x2, y + r, x2, y + k, x2, y + r), (x2, y2 - r, x2, y2 - r, x2, y2 - k), |
|
| 85 | - | (x2 - r, y2, x2 - k, y2, x2 - r, y2), (x + r, y2, x + r, y2, x + k, y2), |
|
| 86 | - | (x, y2 - r, x, y2 - k, x, y2 - r), (x, y + r, x, y + r, x, y + k), |
|
| 87 | - | ] |
|
| 88 | - | return curve_path(pts) |
|
| 89 | - | ||
| 90 | - | ||
| 91 | - | def shape(style, paths, stroke=None, cap=0): |
|
| 92 | - | out = bytes([10, style, len(paths), *paths]) |
|
| 93 | - | if stroke is None: |
|
| 94 | - | return out + bytes([0]) |
|
| 95 | - | # has transformers: one stroke (width + 128, cap << 4 | round join, miter limit) |
|
| 96 | - | return out + bytes([1 << 4, 1, 23, int(round(stroke)) + 128, (cap << 4) | 2, 4]) |
|
| 97 | - | ||
| 98 | - | ||
| 99 | - | def mark(scale, ox, oy): |
|
| 100 | - | """The mark's geometry, scaled about its centre and moved to (ox, oy).""" |
|
| 101 | - | p = lambda x, y: (ox + x * scale, oy + y * scale) |
|
| 102 | - | return { |
|
| 103 | - | "top": (p(-11, -6), p(11, -6)), "bottom": (p(-11, 6), p(11, 6)), |
|
| 104 | - | "left": (p(-11, 0), 10 * scale), "right": (p(11, 0), 10 * scale), |
|
| 105 | - | "dot": 3.5 * scale, "stroke": 3 * scale, "grad": (p(-22, -11), p(22, 11)), |
|
| 106 | - | } |
|
| 107 | - | ||
| 108 | - | ||
| 109 | - | def hvif(dark): |
|
| 110 | - | m = mark(1.0, 32, 32) |
|
| 111 | - | styles = [linear(*m["grad"], [(0, CYAN), (255, BLUE)]), solid(CYAN), solid(WHITE if dark else BLUE)] |
|
| 112 | - | paths = [line(*m["top"]), line(*m["bottom"]), circle(*m["left"][0], m["left"][1]), |
|
| 113 | - | circle(*m["right"][0], m["right"][1]), circle(*m["left"][0], m["dot"]), circle(*m["right"][0], m["dot"])] |
|
| 114 | - | if dark: |
|
| 115 | - | styles.append(solid(TILE)) |
|
| 116 | - | paths.append(rounded(0, 0, 64, 64, 14)) |
|
| 117 | - | tile = [shape(3, [6])] |
|
| 118 | - | else: |
|
| 119 | - | # A pale tile with a thin edge: the edge's colour, then the tile inset by it. |
|
| 120 | - | styles += [solid(EDGE), solid(LIGHT)] |
|
| 121 | - | paths += [rounded(0, 0, 64, 64, 14), rounded(1.5, 1.5, 61, 61, 12.5)] |
|
| 122 | - | tile = [shape(3, [6]), shape(4, [7])] |
|
| 123 | - | shapes = tile + [ |
|
| 124 | - | shape(0, [0], m["stroke"], cap=2), shape(0, [1], m["stroke"], cap=2), |
|
| 125 | - | shape(0, [2], m["stroke"]), shape(0, [3], m["stroke"]), |
|
| 126 | - | shape(1, [4]), shape(2, [5]), |
|
| 127 | - | ] |
|
| 128 | - | out = b"ncif" |
|
| 129 | - | for section in (styles, paths, shapes): |
|
| 130 | - | out += bytes([len(section)]) + b"".join(section) |
|
| 131 | - | return out |
|
| 132 | - | ||
| 133 | - | ||
| 134 | - | def svg(dark): |
|
| 135 | - | if dark: |
|
| 136 | - | bg, dot = '<rect width="64" height="64" rx="14" fill="#070c18"/>', "#FFFFFF" |
|
| 137 | - | else: |
|
| 138 | - | bg = '<rect width="64" height="64" rx="14" fill="#C9DCF5"/><rect x="1.5" y="1.5" width="61" height="61" rx="12.5" fill="#F2F7FF"/>' |
|
| 139 | - | dot = "#0072FF" |
|
| 140 | - | return f'''<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64"> |
|
| 141 | - | <defs> |
|
| 142 | - | <linearGradient id="g" gradientUnits="userSpaceOnUse" x1="-22" y1="-11" x2="22" y2="11"> |
|
| 143 | - | <stop offset="0%" stop-color="#00F0FF"/> |
|
| 144 | - | <stop offset="100%" stop-color="#0072FF"/> |
|
| 145 | - | </linearGradient> |
|
| 146 | - | </defs> |
|
| 147 | - | {bg} |
|
| 148 | - | <g transform="translate(32 32)"> |
|
| 149 | - | <path d="M -11 -6 L 11 -6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 150 | - | <path d="M -11 6 L 11 6" stroke="url(#g)" stroke-width="3" stroke-linecap="round"/> |
|
| 151 | - | <circle cx="-11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 152 | - | <circle cx="-11" cy="0" r="3.5" fill="#00F0FF"/> |
|
| 153 | - | <circle cx="11" cy="0" r="10" fill="none" stroke="url(#g)" stroke-width="3"/> |
|
| 154 | - | <circle cx="11" cy="0" r="3.5" fill="{dot}"/> |
|
| 155 | - | </g> |
|
| 156 | - | </svg> |
|
| 157 | - | ''' |
|
| 158 | - | ||
| 159 | - | ||
| 160 | - | out = sys.argv[1] |
|
| 161 | - | for name, dark in (("oxy", False), ("oh", True)): |
|
| 162 | - | open(f"{out}/{name}.hvif", "wb").write(hvif(dark)) |
|
| 163 | - | open(f"{out}/{name}.svg", "w").write(svg(dark)) |
removed packaging/haikuports/make-recipe.py +0 −140
| 1 | - | #!/usr/bin/env python3 |
|
| 2 | - | """Write a haikuports recipe for oxy or oh (oxygen#156, #157) from a release's |
|
| 3 | - | source tarball, NAME-VERSION-src.tar.gz, as the release job attaches it: the |
|
| 4 | - | tarball itself from the release's stable download address, and every |
|
| 5 | - | crates.io crate in its Cargo.lock as a source of its own with its checksum, |
|
| 6 | - | vendored offline in BUILD() as haikuports' Rust recipes (ripgrep) do. |
|
| 7 | - | ||
| 8 | - | make-recipe.py oxy|oh SRC_TARBALL VERSION > NAME-VERSION.recipe |
|
| 9 | - | """ |
|
| 10 | - | import hashlib |
|
| 11 | - | import sys |
|
| 12 | - | import tarfile |
|
| 13 | - | import tomllib |
|
| 14 | - | ||
| 15 | - | PORTS = { |
|
| 16 | - | "oxy": { |
|
| 17 | - | "repo": "oxygen", |
|
| 18 | - | "package": "oxy", |
|
| 19 | - | "summary": "A version control system of signed, commuting changes, with Git interop", |
|
| 20 | - | "description": [ |
|
| 21 | - | "oxy is the command line of Oxygen, a version control system built on", |
|
| 22 | - | "patch theory: changes commute, conflicts are recorded rather than blocking,", |
|
| 23 | - | "every change can be signed, and a trust policy says who may move what. It", |
|
| 24 | - | "imports and exports Git history, clones from OxygenHub and other Oxygen", |
|
| 25 | - | "hosts, and keeps repositories on disk or in S3, GCS or Azure buckets.", |
|
| 26 | - | ], |
|
| 27 | - | "docs": "README.md LICENSE*", |
|
| 28 | - | "test": "oxy-core", |
|
| 29 | - | }, |
|
| 30 | - | "oh": { |
|
| 31 | - | "repo": "oxygenhub", |
|
| 32 | - | "package": "oh", |
|
| 33 | - | "summary": "The command line of OxygenHub, the forge for Oxygen repositories", |
|
| 34 | - | "description": [ |
|
| 35 | - | "oh talks to an OxygenHub (such as https://oxygenhub.io): issues, proposals", |
|
| 36 | - | "and their reviews, releases, Flow runs, their logs and reports, and checks,", |
|
| 37 | - | "from the terminal. It works alongside oxy, the Oxygen version control", |
|
| 38 | - | "client.", |
|
| 39 | - | ], |
|
| 40 | - | "docs": "README.md LICENSE docs/oh.md", |
|
| 41 | - | "test": "hub-api", |
|
| 42 | - | }, |
|
| 43 | - | } |
|
| 44 | - | ||
| 45 | - | name, tarball, version = sys.argv[1], sys.argv[2], sys.argv[3] |
|
| 46 | - | port = PORTS[name] |
|
| 47 | - | prefix = f"{port['repo']}-{version}" |
|
| 48 | - | with tarfile.open(tarball) as t: |
|
| 49 | - | lock = tomllib.load(t.extractfile(f"{prefix}/Cargo.lock")) |
|
| 50 | - | crates = sorted( |
|
| 51 | - | (p["name"], p["version"], p["checksum"]) |
|
| 52 | - | for p in lock["package"] |
|
| 53 | - | if p.get("source", "").startswith("registry+") |
|
| 54 | - | ) |
|
| 55 | - | sha = hashlib.sha256(open(tarball, "rb").read()).hexdigest() |
|
| 56 | - | ||
| 57 | - | out = [] |
|
| 58 | - | w = out.append |
|
| 59 | - | w(f'SUMMARY="{port["summary"]}"') |
|
| 60 | - | w('DESCRIPTION="' + " \\\n".join(port["description"]) + '"') |
|
| 61 | - | w(f'HOMEPAGE="https://oxygenhub.io/andymccall/{port["repo"]}"') |
|
| 62 | - | w('COPYRIGHT="2026 Andy McCall"') |
|
| 63 | - | w('LICENSE="MIT\n\tApache v2"') |
|
| 64 | - | w('REVISION="1"') |
|
| 65 | - | w(f'SOURCE_URI="$HOMEPAGE/releases/download/v$portVersion/{name}-$portVersion-src.tar.gz"') |
|
| 66 | - | w(f'CHECKSUM_SHA256="{sha}"') |
|
| 67 | - | w(f'SOURCE_DIR="{port["repo"]}-$portVersion"') |
|
| 68 | - | for i, (crate, ver, ck) in enumerate(crates, start=2): |
|
| 69 | - | w(f'SOURCE_URI_{i}="https://static.crates.io/crates/{crate}/{crate}-{ver}.crate"') |
|
| 70 | - | w(f'CHECKSUM_SHA256_{i}="{ck}"') |
|
| 71 | - | w(f'SOURCE_FILENAME_{i}="{crate}-{ver}.tar.gz"') |
|
| 72 | - | last = len(crates) + 1 |
|
| 73 | - | w(f''' |
|
| 74 | - | ARCHITECTURES="!all x86_64" |
|
| 75 | - | ||
| 76 | - | PROVIDES=" |
|
| 77 | - | {name}$secondaryArchSuffix = $portVersion |
|
| 78 | - | cmd:{name} |
|
| 79 | - | " |
|
| 80 | - | REQUIRES=" |
|
| 81 | - | haiku$secondaryArchSuffix |
|
| 82 | - | lib:libzstd$secondaryArchSuffix |
|
| 83 | - | " |
|
| 84 | - | ||
| 85 | - | BUILD_REQUIRES=" |
|
| 86 | - | haiku${{secondaryArchSuffix}}_devel |
|
| 87 | - | devel:libzstd$secondaryArchSuffix |
|
| 88 | - | " |
|
| 89 | - | BUILD_PREREQUIRES=" |
|
| 90 | - | cmd:gcc$secondaryArchSuffix |
|
| 91 | - | cmd:pkg_config$secondaryArchSuffix |
|
| 92 | - | cmd:rustc$secondaryArchSuffix |
|
| 93 | - | " |
|
| 94 | - | ||
| 95 | - | BUILD() |
|
| 96 | - | {{ |
|
| 97 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 98 | - | vendor=$CARGO_HOME/haiku |
|
| 99 | - | mkdir -p "$vendor" |
|
| 100 | - | for i in $(seq 2 {last}); do |
|
| 101 | - | eval "srcDir=\\$sourceDir$i" |
|
| 102 | - | eval "sha256sum=\\$CHECKSUM_SHA256_$i" |
|
| 103 | - | set -- "$srcDir"/* |
|
| 104 | - | ln -sf "$1" "$vendor" |
|
| 105 | - | cat <<-EOF >"$vendor/${{1##*/}}/.cargo-checksum.json" |
|
| 106 | - | {{ |
|
| 107 | - | "package": "$sha256sum", |
|
| 108 | - | "files": {{}} |
|
| 109 | - | }} |
|
| 110 | - | EOF |
|
| 111 | - | done |
|
| 112 | - | ||
| 113 | - | cat <<-EOF >"$CARGO_HOME"/config.toml |
|
| 114 | - | [source.haiku] |
|
| 115 | - | directory = "$vendor" |
|
| 116 | - | ||
| 117 | - | [source.crates-io] |
|
| 118 | - | replace-with = "haiku" |
|
| 119 | - | EOF |
|
| 120 | - | ||
| 121 | - | # The bundled zstd's hidden symbols break the link on Haiku: use the system's. |
|
| 122 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 123 | - | export OXY_BUILD=v$portVersion |
|
| 124 | - | cargo build --release --frozen -p {port["package"]} |
|
| 125 | - | }} |
|
| 126 | - | ||
| 127 | - | INSTALL() |
|
| 128 | - | {{ |
|
| 129 | - | install -v -m 755 -d "$prefix"/bin "$docDir" |
|
| 130 | - | install -v -m 755 ./target/release/{name} "$prefix"/bin |
|
| 131 | - | install -v -m 644 {port["docs"]} "$docDir" |
|
| 132 | - | }} |
|
| 133 | - | ||
| 134 | - | TEST() |
|
| 135 | - | {{ |
|
| 136 | - | export CARGO_HOME=$sourceDir/../cargo |
|
| 137 | - | export ZSTD_SYS_USE_PKG_CONFIG=1 |
|
| 138 | - | cargo test --release --frozen -p {port["test"]} |
|
| 139 | - | }}''') |
|
| 140 | - | print("\n".join(out)) |
modified scripts/dist.sh +0 −11
| … | 136 unchanged lines |
||
| 137 | 137 | fi |
|
| 138 | 138 | done |
|
| 139 | 139 | ||
| 140 | - | # The source as released (oxygen#157): the oxygen tree, |
|
| 141 | - | # under oxygen-VERSION/, for packagers (haikuports) to fetch from the |
|
| 142 | - | # release at a fixed checksum. Reproducible: sorted, fixed times and |
|
| 143 | - | # owners, gzip without a timestamp. |
|
| 144 | - | if [ -z "${ONLY:-}" ] || [[ src == $ONLY ]]; then |
|
| 145 | - | echo "== src" |
|
| 146 | - | tar --sort=name --mtime='1970-01-01 00:00:00Z' --owner=0 --group=0 --numeric-owner \ |
|
| 147 | - | --mode='u+rwX,go+rX,go-w' --exclude=./target --exclude=./lost+found --exclude=.oxy \ |
|
| 148 | - | --transform "s|^\.|oxygen-$VERSION|" -cf - . | gzip -9n >"$OUT/$BIN-$VERSION-src.tar.gz" |
|
| 149 | - | fi |
|
| 150 | - | ||
| 151 | 140 | rm -rf "$OUT/stage" |
|
| 152 | 141 | (cd "$OUT" && shopt -s nullglob && sha256sum -- *.tar.gz *.zip *.deb >SHA256SUMS) |
|
| 153 | 142 | # DIST_FLAT=DIR: the same files again under names without the version, for |
|
| … | 12 unchanged lines |
removed src/cli/artifact.rs +0 −180
| 1 | - | //! `oxy artifact`: Cylinder's artifacts (docs/cylinder.md §4.1, step C1): |
|
| 2 | - | //! a directory packed into a tree of the repository's own chunks, named by |
|
| 3 | - | //! the BLAKE3 of its canonical encoding. |
|
| 4 | - | ||
| 5 | - | use super::json; |
|
| 6 | - | use super::open; |
|
| 7 | - | use super::ui; |
|
| 8 | - | use anyhow::Result; |
|
| 9 | - | use cylinder::{Kind, Spec}; |
|
| 10 | - | use std::path::Path; |
|
| 11 | - | ||
| 12 | - | /// `KEY=VALUE` pairs, refused when one has no `=`. |
|
| 13 | - | fn pairs(list: &[String], what: &str) -> Result<std::collections::BTreeMap<String, String>> { |
|
| 14 | - | list.iter() |
|
| 15 | - | .map(|p| { |
|
| 16 | - | p.split_once('=') |
|
| 17 | - | .map(|(k, v)| (k.to_string(), v.to_string())) |
|
| 18 | - | .ok_or_else(|| anyhow::anyhow!("{what} {p:?}: write it KEY=VALUE")) |
|
| 19 | - | }) |
|
| 20 | - | .collect() |
|
| 21 | - | } |
|
| 22 | - | ||
| 23 | - | fn summary(k: &cylinder::Kept) -> String { |
|
| 24 | - | let a = &k.artifact; |
|
| 25 | - | let mut parts = vec![a.kind.as_str().to_string()]; |
|
| 26 | - | parts.extend(a.os.clone()); |
|
| 27 | - | parts.extend(a.arch.clone()); |
|
| 28 | - | format!( |
|
| 29 | - | "{} {} {}", |
|
| 30 | - | ui::hash(&k.name[..12]), |
|
| 31 | - | parts.join(" "), |
|
| 32 | - | ui::dim(format!("{} bytes", a.total_size)) |
|
| 33 | - | ) |
|
| 34 | - | } |
|
| 35 | - | ||
| 36 | - | fn as_json(k: &cylinder::Kept, files: usize) -> String { |
|
| 37 | - | let a = &k.artifact; |
|
| 38 | - | let text = |v: &Option<String>| v.as_deref().map(json::s).unwrap_or_else(|| "null".into()); |
|
| 39 | - | let map = |m: &std::collections::BTreeMap<String, String>| { |
|
| 40 | - | let inner: Vec<String> = m |
|
| 41 | - | .iter() |
|
| 42 | - | .map(|(k, v)| format!("{}:{}", json::s(k), json::s(v))) |
|
| 43 | - | .collect(); |
|
| 44 | - | format!("{{{}}}", inner.join(",")) |
|
| 45 | - | }; |
|
| 46 | - | json::obj([ |
|
| 47 | - | ("name", json::s(&k.name)), |
|
| 48 | - | ("kind", json::s(a.kind.as_str())), |
|
| 49 | - | ("arch", text(&a.arch)), |
|
| 50 | - | ("os", text(&a.os)), |
|
| 51 | - | ("tree", json::s(&a.tree.to_hex())), |
|
| 52 | - | ("files", json::n(files as u64)), |
|
| 53 | - | ("total_size", json::n(a.total_size)), |
|
| 54 | - | ("env", map(&a.env)), |
|
| 55 | - | ("labels", map(&a.labels)), |
|
| 56 | - | ]) |
|
| 57 | - | } |
|
| 58 | - | ||
| 59 | - | #[allow(clippy::too_many_arguments)] |
|
| 60 | - | pub fn pack( |
|
| 61 | - | dir: &Path, |
|
| 62 | - | kind: &str, |
|
| 63 | - | arch: Option<String>, |
|
| 64 | - | os: Option<String>, |
|
| 65 | - | entrypoint: Vec<String>, |
|
| 66 | - | env: &[String], |
|
| 67 | - | labels: &[String], |
|
| 68 | - | as_json_out: bool, |
|
| 69 | - | ) -> Result<i32> { |
|
| 70 | - | let repo = open()?; |
|
| 71 | - | let mut spec = Spec::new(Kind::parse(kind)?); |
|
| 72 | - | spec.arch = arch; |
|
| 73 | - | spec.os = os; |
|
| 74 | - | spec.entrypoint = (!entrypoint.is_empty()).then_some(entrypoint); |
|
| 75 | - | spec.env = pairs(env, "env")?; |
|
| 76 | - | spec.labels = pairs(labels, "label")?; |
|
| 77 | - | let sp = ui::spinner("Packing…"); |
|
| 78 | - | let k = cylinder::pack(&repo, dir, &spec)?; |
|
| 79 | - | sp.clear(); |
|
| 80 | - | let files = cylinder::tree(&repo, &k.artifact)?.entries.len(); |
|
| 81 | - | if as_json_out { |
|
| 82 | - | println!("{}", as_json(&k, files)); |
|
| 83 | - | } else { |
|
| 84 | - | println!( |
|
| 85 | - | "{} {} as {}", |
|
| 86 | - | ui::done("Packed"), |
|
| 87 | - | ui::path(dir.display()), |
|
| 88 | - | summary(&k) |
|
| 89 | - | ); |
|
| 90 | - | println!("{}", ui::kv("name", &k.name)); |
|
| 91 | - | println!("{}", ui::kv("files", files.to_string())); |
|
| 92 | - | } |
|
| 93 | - | Ok(0) |
|
| 94 | - | } |
|
| 95 | - | ||
| 96 | - | pub fn list(as_json_out: bool) -> Result<i32> { |
|
| 97 | - | let repo = open()?; |
|
| 98 | - | let names = cylinder::list(&repo)?; |
|
| 99 | - | let kept: Vec<cylinder::Kept> = names |
|
| 100 | - | .iter() |
|
| 101 | - | .map(|n| cylinder::open(&repo, n)) |
|
| 102 | - | .collect::<std::result::Result<_, _>>()?; |
|
| 103 | - | if as_json_out { |
|
| 104 | - | let items: Vec<String> = kept |
|
| 105 | - | .iter() |
|
| 106 | - | .map(|k| { |
|
| 107 | - | let files = cylinder::tree(&repo, &k.artifact) |
|
| 108 | - | .map(|t| t.entries.len()) |
|
| 109 | - | .unwrap_or(0); |
|
| 110 | - | as_json(k, files) |
|
| 111 | - | }) |
|
| 112 | - | .collect(); |
|
| 113 | - | println!("[{}]", items.join(",")); |
|
| 114 | - | return Ok(0); |
|
| 115 | - | } |
|
| 116 | - | if kept.is_empty() { |
|
| 117 | - | println!("No artifacts yet: oxy artifact pack DIR --kind archive"); |
|
| 118 | - | } |
|
| 119 | - | for k in &kept { |
|
| 120 | - | println!("{}", summary(k)); |
|
| 121 | - | } |
|
| 122 | - | Ok(0) |
|
| 123 | - | } |
|
| 124 | - | ||
| 125 | - | pub fn show(name: &str, as_json_out: bool) -> Result<i32> { |
|
| 126 | - | let repo = open()?; |
|
| 127 | - | let k = cylinder::open(&repo, name)?; |
|
| 128 | - | let t = cylinder::tree(&repo, &k.artifact)?; |
|
| 129 | - | if as_json_out { |
|
| 130 | - | println!("{}", as_json(&k, t.entries.len())); |
|
| 131 | - | return Ok(0); |
|
| 132 | - | } |
|
| 133 | - | println!("{}", summary(&k)); |
|
| 134 | - | println!("{}", ui::kv("name", &k.name)); |
|
| 135 | - | if let Some(e) = &k.artifact.entrypoint { |
|
| 136 | - | println!("{}", ui::kv("entrypoint", e.join(" "))); |
|
| 137 | - | } |
|
| 138 | - | for (key, v) in &k.artifact.labels { |
|
| 139 | - | println!("{}", ui::kv("label", format!("{key}={v}"))); |
|
| 140 | - | } |
|
| 141 | - | for (key, v) in &k.artifact.env { |
|
| 142 | - | println!("{}", ui::kv("env", format!("{key}={v}"))); |
|
| 143 | - | } |
|
| 144 | - | for e in &t.entries { |
|
| 145 | - | let mode = match e.mode { |
|
| 146 | - | cylinder::MODE_EXEC => "x", |
|
| 147 | - | cylinder::MODE_LINK => "l", |
|
| 148 | - | _ => " ", |
|
| 149 | - | }; |
|
| 150 | - | println!(" {mode} {:>10} {}", e.size, e.path); |
|
| 151 | - | } |
|
| 152 | - | Ok(0) |
|
| 153 | - | } |
|
| 154 | - | ||
| 155 | - | pub fn unpack(name: &str, dest: &Path) -> Result<i32> { |
|
| 156 | - | let repo = open()?; |
|
| 157 | - | let k = cylinder::open(&repo, name)?; |
|
| 158 | - | let n = cylinder::unpack(&repo, &k, dest)?; |
|
| 159 | - | println!( |
|
| 160 | - | "{} {} files of {} into {}", |
|
| 161 | - | ui::done("Unpacked"), |
|
| 162 | - | n, |
|
| 163 | - | ui::hash(&k.name[..12]), |
|
| 164 | - | ui::path(dest.display()) |
|
| 165 | - | ); |
|
| 166 | - | Ok(0) |
|
| 167 | - | } |
|
| 168 | - | ||
| 169 | - | pub fn verify(name: &str) -> Result<i32> { |
|
| 170 | - | let repo = open()?; |
|
| 171 | - | let k = cylinder::open(&repo, name)?; |
|
| 172 | - | let n = cylinder::verify(&repo, &k)?; |
|
| 173 | - | println!( |
|
| 174 | - | "{} {}: its name, tree and {} files check out", |
|
| 175 | - | ui::done("Verified"), |
|
| 176 | - | ui::hash(&k.name[..12]), |
|
| 177 | - | n |
|
| 178 | - | ); |
|
| 179 | - | Ok(0) |
|
| 180 | - | } |
modified src/cli/format.rs +3 −25
| … | 41 unchanged lines |
||
| 42 | 42 | ||
| 43 | 43 | /// One line describing how a change is authenticated. |
|
| 44 | 44 | pub fn signature_line(repo: &Repo, h: &ChangeHash) -> Result<String> { |
|
| 45 | - | let status = repo.authenticate_change(h)?; |
|
| 46 | - | let awaiting = repo |
|
| 47 | - | .store() |
|
| 48 | - | .get_change(h) |
|
| 49 | - | .is_ok_and(|c| awaits_seal(repo, &status, &c.author)); |
|
| 50 | - | Ok(match status { |
|
| 51 | - | SignatureStatus::Unsigned if awaiting => { |
|
| 52 | - | "awaiting seal (the next push seals it under the agent's grant)".to_string() |
|
| 53 | - | } |
|
| 45 | + | Ok(match repo.authenticate_change(h)? { |
|
| 54 | 46 | SignatureStatus::Unsigned => "unsigned".to_string(), |
|
| 55 | 47 | SignatureStatus::Valid { |
|
| 56 | 48 | key, |
|
| … | 79 unchanged lines |
||
| 136 | 128 | } |
|
| 137 | 129 | _ => None, |
|
| 138 | 130 | } |
|
| 139 | - | } |
|
| 140 | - | ||
| 141 | - | /// Whether an unsigned change is one the next push will seal: this |
|
| 142 | - | /// checkout signs keyless (an agent under a grant) and the change is its |
|
| 143 | - | /// configured author's (oxygen#165). Read cold, "unsigned" looks like an |
|
| 144 | - | /// error; it is not one until the push. |
|
| 145 | - | pub fn awaits_seal(repo: &Repo, status: &SignatureStatus, author: &oxy_core::hash::KeyId) -> bool { |
|
| 146 | - | matches!(status, SignatureStatus::Unsigned) |
|
| 147 | - | && repo.config.signer_keyless |
|
| 148 | - | && repo.config.author_key == Some(*author) |
|
| 149 | 131 | } |
|
| 150 | 132 | ||
| 151 | 133 | /// A compact, styled authentication marker for log lines, from a status |
|
| 152 | - | /// already in hand (the caller also reads who signed, see [`via`]); |
|
| 153 | - | /// `awaiting` from [`awaits_seal`]. |
|
| 154 | - | pub fn signature_mark_of(status: &SignatureStatus, awaiting: bool) -> String { |
|
| 134 | + | /// already in hand (the caller also reads who signed, see [`via`]). |
|
| 135 | + | pub fn signature_mark_of(status: &SignatureStatus) -> String { |
|
| 155 | 136 | match status { |
|
| 156 | - | SignatureStatus::Unsigned if awaiting => { |
|
| 157 | - | ui::dim(format!("{} awaiting seal", ui::glyph("◌", "o"))) |
|
| 158 | - | } |
|
| 159 | 137 | SignatureStatus::Unsigned => ui::dim(format!("{} unsigned", ui::glyph("·", "-"))), |
|
| 160 | 138 | SignatureStatus::Valid { |
|
| 161 | 139 | sealed, |
|
| … | 64 unchanged lines |
modified src/cli/identity.rs +2 −85
| … | 131 unchanged lines |
||
| 132 | 132 | ui::author(&r.identity.name), |
|
| 133 | 133 | r.identity.email |
|
| 134 | 134 | ); |
|
| 135 | - | // Which key it started from, and where that came from (oxygen#163). |
|
| 136 | - | let from = if repo.config.is_repo_set("author.key") { |
|
| 137 | - | "this repository's author.key" |
|
| 138 | - | } else { |
|
| 139 | - | "the user config's author.key" |
|
| 140 | - | }; |
|
| 141 | - | println!( |
|
| 142 | - | "{}", |
|
| 143 | - | ui::kv( |
|
| 144 | - | "old key", |
|
| 145 | - | format!( |
|
| 146 | - | "{} {}", |
|
| 147 | - | ui::dim(r.old.to_hex()), |
|
| 148 | - | ui::dim(format!("(from {from})")) |
|
| 149 | - | ) |
|
| 150 | - | ) |
|
| 151 | - | ); |
|
| 135 | + | println!("{}", ui::kv("old key", ui::dim(r.old.to_hex()))); |
|
| 152 | 136 | println!("{}", ui::kv("new key", r.new.to_hex())); |
|
| 153 | 137 | print_delegates(repo, &r.identity.delegates); |
|
| 154 | 138 | if let Some(e) = r.identity.expires { |
|
| … | 16 unchanged lines |
||
| 171 | 155 | local: bool, |
|
| 172 | 156 | expires: Option<u64>, |
|
| 173 | 157 | ) -> Result<i32> { |
|
| 174 | - | // A first identity comes before any repository (oxygen#144): only |
|
| 175 | - | // --local needs one; inside one, it is kept there too. |
|
| 176 | - | let mut repo = match open() { |
|
| 177 | - | Ok(r) => r, |
|
| 178 | - | Err(e) if local => return Err(e), |
|
| 179 | - | Err(_) => { |
|
| 180 | - | let (key, id) = repo::create_user_identity( |
|
| 181 | - | name.as_deref(), |
|
| 182 | - | email.as_deref(), |
|
| 183 | - | expires.and_then(expiry_from_days), |
|
| 184 | - | )?; |
|
| 185 | - | println!( |
|
| 186 | - | "{} identity {} <{}>", |
|
| 187 | - | ui::done("Created"), |
|
| 188 | - | ui::author(&id.name), |
|
| 189 | - | id.email |
|
| 190 | - | ); |
|
| 191 | - | println!("{}", ui::kv("key", key)); |
|
| 192 | - | println!( |
|
| 193 | - | "{}", |
|
| 194 | - | ui::kv("secret", ui::path(repo::default_keys_dir().display())) |
|
| 195 | - | ); |
|
| 196 | - | println!( |
|
| 197 | - | "{}", |
|
| 198 | - | ui::kv( |
|
| 199 | - | "scope", |
|
| 200 | - | format!( |
|
| 201 | - | "default author in {}", |
|
| 202 | - | ui::path(repo::default_user_config().display()) |
|
| 203 | - | ) |
|
| 204 | - | ) |
|
| 205 | - | ); |
|
| 206 | - | println!(" {} {}", ui::note(), ui::dim("changes in every repository carry this author; run oxy config --user core.sign change to sign each commit")); |
|
| 207 | - | return Ok(0); |
|
| 208 | - | } |
|
| 209 | - | }; |
|
| 158 | + | let mut repo = open()?; |
|
| 210 | 159 | let name = name.unwrap_or_else(|| repo.config.author_name.clone()); |
|
| 211 | 160 | let email = email.unwrap_or_else(|| repo.config.author_email.clone()); |
|
| 212 | 161 | let scope = if local { |
|
| … | 120 unchanged lines |
||
| 333 | 282 | )) |
|
| 334 | 283 | ); |
|
| 335 | 284 | } |
|
| 336 | - | } |
|
| 337 | - | // A key with a successor is stale, and a key with two is a fork: both |
|
| 338 | - | // are how an identity splits without anyone noticing (oxygen#163). |
|
| 339 | - | let next = repo.successors(&key)?; |
|
| 340 | - | if let Some(n) = next.first() { |
|
| 341 | - | println!( |
|
| 342 | - | " {} {}", |
|
| 343 | - | ui::caution(), |
|
| 344 | - | ui::warn(format!( |
|
| 345 | - | "this key is not your identity's newest: {} succeeds it, {} is the newest. Rotating or delegating from it would fork the identity; point author.key at the newest", |
|
| 346 | - | n.short(12), |
|
| 347 | - | repo.newest(n)?.short(12) |
|
| 348 | - | )) |
|
| 349 | - | ); |
|
| 350 | - | } |
|
| 351 | - | let mut cur = Some(key); |
|
| 352 | - | for _ in 0..256 { |
|
| 353 | - | let Some(k) = cur else { break }; |
|
| 354 | - | let after = repo.successors(&k)?; |
|
| 355 | - | if after.len() > 1 { |
|
| 356 | - | println!( |
|
| 357 | - | " {} {}", |
|
| 358 | - | ui::caution(), |
|
| 359 | - | ui::err(format!( |
|
| 360 | - | "the identity forks at {}: {} each succeed it. Keep one branch: revoke the others' keys (oxy identity revoke KEY) and point every home's author.key at the one you keep", |
|
| 361 | - | k.short(12), |
|
| 362 | - | after.iter().map(|a| a.short(12)).collect::<Vec<_>>().join(" and ") |
|
| 363 | - | )) |
|
| 364 | - | ); |
|
| 365 | - | break; |
|
| 366 | - | } |
|
| 367 | - | cur = repo.identity(&k).ok().and_then(|i| i.previous); |
|
| 368 | 285 | } |
|
| 369 | 286 | print_delegates(&repo, &id.delegates); |
|
| 370 | 287 | if repo.is_revoked(&key)? { |
|
| … | 715 unchanged lines |
removed src/cli/mcp.rs +0 −543
| 1 | - | //! `oxy mcp` (oxygen#159): a Model Context Protocol server over stdio for |
|
| 2 | - | //! the repository it starts in, so an agent works through typed tools |
|
| 3 | - | //! instead of parsing a shell's output. |
|
| 4 | - | //! |
|
| 5 | - | //! Each tool runs this same oxy binary with the command's `--json`, in the |
|
| 6 | - | //! repository, with the server's environment: so a tool returns exactly |
|
| 7 | - | //! what the command does, and signs as whatever `OXY_HOME` configures. In |
|
| 8 | - | //! an agent home every change is sealed via the agent, with no environment |
|
| 9 | - | //! variable to forget per call. Tools that can lose work (undo, a forced |
|
| 10 | - | //! push) are offered only with `--allow-destructive`. |
|
| 11 | - | ||
| 12 | - | use anyhow::{bail, Result}; |
|
| 13 | - | use oxy_core::mcp::{self, arg_str, arg_strings, ServerInfo, Tool, ToolOutput, Tools}; |
|
| 14 | - | use serde_json::{json, Value}; |
|
| 15 | - | use std::path::{Path, PathBuf}; |
|
| 16 | - | use std::process::{Command, Stdio}; |
|
| 17 | - | ||
| 18 | - | /// A tool's text is cut here; its structured result is then left out. |
|
| 19 | - | const MAX_TEXT: usize = 256 * 1024; |
|
| 20 | - | ||
| 21 | - | type Build = fn(&Value, bool) -> Result<Vec<String>, String>; |
|
| 22 | - | ||
| 23 | - | struct Spec { |
|
| 24 | - | name: &'static str, |
|
| 25 | - | description: &'static str, |
|
| 26 | - | schema: fn() -> Value, |
|
| 27 | - | build: Build, |
|
| 28 | - | json: bool, |
|
| 29 | - | read_only: bool, |
|
| 30 | - | destructive: bool, |
|
| 31 | - | } |
|
| 32 | - | ||
| 33 | - | fn obj(props: Value, required: &[&str]) -> Value { |
|
| 34 | - | json!({ "type": "object", "properties": props, "required": required, "additionalProperties": false }) |
|
| 35 | - | } |
|
| 36 | - | ||
| 37 | - | fn none() -> Value { |
|
| 38 | - | obj(json!({}), &[]) |
|
| 39 | - | } |
|
| 40 | - | ||
| 41 | - | /// An option's value as `--flag=value`, so a value starting with `-` is |
|
| 42 | - | /// never read as another flag. |
|
| 43 | - | fn opt(flag: &str, value: &str) -> String { |
|
| 44 | - | format!("{flag}={value}") |
|
| 45 | - | } |
|
| 46 | - | ||
| 47 | - | /// Positional values after `--`, for the same reason. |
|
| 48 | - | fn positional(out: &mut Vec<String>, values: Vec<String>) { |
|
| 49 | - | if !values.is_empty() { |
|
| 50 | - | out.push("--".into()); |
|
| 51 | - | out.extend(values); |
|
| 52 | - | } |
|
| 53 | - | } |
|
| 54 | - | ||
| 55 | - | fn required<'a>(args: &'a Value, key: &str) -> Result<&'a str, String> { |
|
| 56 | - | arg_str(args, key) |
|
| 57 | - | .filter(|s| !s.trim().is_empty()) |
|
| 58 | - | .ok_or_else(|| format!("{key} is required")) |
|
| 59 | - | } |
|
| 60 | - | ||
| 61 | - | /// Paths to act on, or every path when `all` is true; never neither, so a |
|
| 62 | - | /// commit or amend is always a deliberate choice of what goes in. |
|
| 63 | - | fn paths_or_all(args: &Value) -> Result<Vec<String>, String> { |
|
| 64 | - | let paths = arg_strings(args, "paths")?; |
|
| 65 | - | let all = args.get("all").and_then(Value::as_bool).unwrap_or(false); |
|
| 66 | - | match (paths.is_empty(), all) { |
|
| 67 | - | (false, false) => Ok(paths), |
|
| 68 | - | (true, true) => Ok(vec![]), |
|
| 69 | - | (false, true) => Err("give paths or all: true, not both".into()), |
|
| 70 | - | (true, false) => { |
|
| 71 | - | Err("give the paths to include, or all: true for every changed path".into()) |
|
| 72 | - | } |
|
| 73 | - | } |
|
| 74 | - | } |
|
| 75 | - | ||
| 76 | - | fn limit(args: &Value, default: u64) -> String { |
|
| 77 | - | args.get("limit") |
|
| 78 | - | .and_then(Value::as_u64) |
|
| 79 | - | .unwrap_or(default) |
|
| 80 | - | .clamp(1, 1000) |
|
| 81 | - | .to_string() |
|
| 82 | - | } |
|
| 83 | - | ||
| 84 | - | fn specs() -> Vec<Spec> { |
|
| 85 | - | vec![ |
|
| 86 | - | Spec { |
|
| 87 | - | name: "status", |
|
| 88 | - | description: "The working copy: the bookmark, changed paths, and every conflict with its kind and the changes behind it.", |
|
| 89 | - | schema: none, |
|
| 90 | - | build: |_, _| Ok(vec!["status".into(), "--json".into()]), |
|
| 91 | - | json: true, |
|
| 92 | - | read_only: true, |
|
| 93 | - | destructive: false, |
|
| 94 | - | }, |
|
| 95 | - | Spec { |
|
| 96 | - | name: "diff", |
|
| 97 | - | description: "Uncommitted edits in the working copy, or one change's edits when `change` is given (a ChangeId or #hash prefix).", |
|
| 98 | - | schema: || obj(json!({ "change": { "type": "string" } }), &[]), |
|
| 99 | - | build: |a, _| { |
|
| 100 | - | let mut v = vec!["diff".into(), "--json".into()]; |
|
| 101 | - | positional(&mut v, arg_str(a, "change").map(|c| vec![c.to_string()]).unwrap_or_default()); |
|
| 102 | - | Ok(v) |
|
| 103 | - | }, |
|
| 104 | - | json: true, |
|
| 105 | - | read_only: true, |
|
| 106 | - | destructive: false, |
|
| 107 | - | }, |
|
| 108 | - | Spec { |
|
| 109 | - | name: "log", |
|
| 110 | - | description: "Changes, newest first: a revset (`main`, `@`, …) or the current bookmark, optionally only those touching `path`; `limit` defaults to 20.", |
|
| 111 | - | schema: || obj(json!({ "revset": { "type": "string" }, "path": { "type": "string" }, "limit": { "type": "integer", "minimum": 1 } }), &[]), |
|
| 112 | - | build: |a, _| { |
|
| 113 | - | let mut v = vec!["log".into(), "--json".into(), opt("--limit", &limit(a, 20))]; |
|
| 114 | - | if let Some(r) = arg_str(a, "revset") { |
|
| 115 | - | v.push(opt("--revset", r)); |
|
| 116 | - | } |
|
| 117 | - | if let Some(p) = arg_str(a, "path") { |
|
| 118 | - | v.push(opt("--path", p)); |
|
| 119 | - | } |
|
| 120 | - | Ok(v) |
|
| 121 | - | }, |
|
| 122 | - | json: true, |
|
| 123 | - | read_only: true, |
|
| 124 | - | destructive: false, |
|
| 125 | - | }, |
|
| 126 | - | Spec { |
|
| 127 | - | name: "show", |
|
| 128 | - | description: "One change: its message, author, signatures and edits (`stat: true` for files and line counts only). `change` defaults to @, the working copy.", |
|
| 129 | - | schema: || obj(json!({ "change": { "type": "string" }, "stat": { "type": "boolean" } }), &[]), |
|
| 130 | - | build: |a, _| { |
|
| 131 | - | let mut v = vec!["show".into(), "--json".into()]; |
|
| 132 | - | if a.get("stat").and_then(Value::as_bool).unwrap_or(false) { |
|
| 133 | - | v.push("--stat".into()); |
|
| 134 | - | } |
|
| 135 | - | positional(&mut v, vec![arg_str(a, "change").unwrap_or("@").to_string()]); |
|
| 136 | - | Ok(v) |
|
| 137 | - | }, |
|
| 138 | - | json: true, |
|
| 139 | - | read_only: true, |
|
| 140 | - | destructive: false, |
|
| 141 | - | }, |
|
| 142 | - | Spec { |
|
| 143 | - | name: "cat", |
|
| 144 | - | description: "A file's content as a bookmark, tag or change has it (`change`), or as committed on the working copy's base.", |
|
| 145 | - | schema: || obj(json!({ "path": { "type": "string" }, "change": { "type": "string" } }), &["path"]), |
|
| 146 | - | build: |a, _| { |
|
| 147 | - | let mut v = vec!["cat".into()]; |
|
| 148 | - | if let Some(c) = arg_str(a, "change") { |
|
| 149 | - | v.push(opt("--change", c)); |
|
| 150 | - | } |
|
| 151 | - | positional(&mut v, vec![required(a, "path")?.to_string()]); |
|
| 152 | - | Ok(v) |
|
| 153 | - | }, |
|
| 154 | - | json: false, |
|
| 155 | - | read_only: true, |
|
| 156 | - | destructive: false, |
|
| 157 | - | }, |
|
| 158 | - | Spec { |
|
| 159 | - | name: "blame", |
|
| 160 | - | description: "Which change wrote each line of a file, with its line atoms.", |
|
| 161 | - | schema: || obj(json!({ "path": { "type": "string" } }), &["path"]), |
|
| 162 | - | build: |a, _| { |
|
| 163 | - | let mut v = vec!["blame".into(), "--json".into()]; |
|
| 164 | - | positional(&mut v, vec![required(a, "path")?.to_string()]); |
|
| 165 | - | Ok(v) |
|
| 166 | - | }, |
|
| 167 | - | json: true, |
|
| 168 | - | read_only: true, |
|
| 169 | - | destructive: false, |
|
| 170 | - | }, |
|
| 171 | - | Spec { |
|
| 172 | - | name: "bookmarks", |
|
| 173 | - | description: "Bookmarks with their heads and how far each is ahead of or behind its remote; `all: true` adds remotes' bookmarks.", |
|
| 174 | - | schema: || obj(json!({ "all": { "type": "boolean" } }), &[]), |
|
| 175 | - | build: |a, _| { |
|
| 176 | - | let mut v = vec!["bookmark".into(), "list".into(), "--json".into()]; |
|
| 177 | - | if a.get("all").and_then(Value::as_bool).unwrap_or(false) { |
|
| 178 | - | v.push("--all".into()); |
|
| 179 | - | } |
|
| 180 | - | Ok(v) |
|
| 181 | - | }, |
|
| 182 | - | json: true, |
|
| 183 | - | read_only: true, |
|
| 184 | - | destructive: false, |
|
| 185 | - | }, |
|
| 186 | - | Spec { |
|
| 187 | - | name: "tags", |
|
| 188 | - | description: "Tags with their states, messages and signers.", |
|
| 189 | - | schema: none, |
|
| 190 | - | build: |_, _| Ok(vec!["tag".into(), "list".into(), "--json".into()]), |
|
| 191 | - | json: true, |
|
| 192 | - | read_only: true, |
|
| 193 | - | destructive: false, |
|
| 194 | - | }, |
|
| 195 | - | Spec { |
|
| 196 | - | name: "conflicts", |
|
| 197 | - | description: "Which conflicts of the working copy's base the current files resolve, and which remain.", |
|
| 198 | - | schema: none, |
|
| 199 | - | build: |_, _| Ok(vec!["resolve".into(), "--json".into()]), |
|
| 200 | - | json: true, |
|
| 201 | - | read_only: true, |
|
| 202 | - | destructive: false, |
|
| 203 | - | }, |
|
| 204 | - | Spec { |
|
| 205 | - | name: "op_log", |
|
| 206 | - | description: "The operation log, newest first (what undo would take back); `limit` defaults to 20.", |
|
| 207 | - | schema: || obj(json!({ "limit": { "type": "integer", "minimum": 1 } }), &[]), |
|
| 208 | - | build: |a, _| Ok(vec!["op".into(), "log".into(), "--json".into(), opt("--limit", &limit(a, 20))]), |
|
| 209 | - | json: true, |
|
| 210 | - | read_only: true, |
|
| 211 | - | destructive: false, |
|
| 212 | - | }, |
|
| 213 | - | Spec { |
|
| 214 | - | name: "identity", |
|
| 215 | - | description: "Who changes are signed as here: the author, the key, delegates and the signer (an agent home signs keyless, via the agent).", |
|
| 216 | - | schema: none, |
|
| 217 | - | build: |_, _| Ok(vec!["identity".into(), "show".into()]), |
|
| 218 | - | json: false, |
|
| 219 | - | read_only: true, |
|
| 220 | - | destructive: false, |
|
| 221 | - | }, |
|
| 222 | - | Spec { |
|
| 223 | - | name: "commit", |
|
| 224 | - | description: "Record a change with a message: only `paths`, or every changed path with `all: true`. Signed as this server's identity.", |
|
| 225 | - | schema: || obj(json!({ "message": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } }, "all": { "type": "boolean" } }), &["message"]), |
|
| 226 | - | build: |a, _| { |
|
| 227 | - | let mut v = vec!["commit".into(), opt("--message", required(a, "message")?)]; |
|
| 228 | - | positional(&mut v, paths_or_all(a)?); |
|
| 229 | - | Ok(v) |
|
| 230 | - | }, |
|
| 231 | - | json: false, |
|
| 232 | - | read_only: false, |
|
| 233 | - | destructive: false, |
|
| 234 | - | }, |
|
| 235 | - | Spec { |
|
| 236 | - | name: "amend", |
|
| 237 | - | description: "Fold edits into the change the working copy sits on: only `paths`, or all with `all: true`; `message` replaces its message too.", |
|
| 238 | - | schema: || obj(json!({ "message": { "type": "string" }, "paths": { "type": "array", "items": { "type": "string" } }, "all": { "type": "boolean" } }), &[]), |
|
| 239 | - | build: |a, _| { |
|
| 240 | - | let mut v = vec!["amend".into()]; |
|
| 241 | - | if let Some(m) = arg_str(a, "message") { |
|
| 242 | - | v.push(opt("--message", m)); |
|
| 243 | - | } |
|
| 244 | - | positional(&mut v, paths_or_all(a)?); |
|
| 245 | - | Ok(v) |
|
| 246 | - | }, |
|
| 247 | - | json: false, |
|
| 248 | - | read_only: false, |
|
| 249 | - | destructive: false, |
|
| 250 | - | }, |
|
| 251 | - | Spec { |
|
| 252 | - | name: "describe", |
|
| 253 | - | description: "Change a head's message (`change` defaults to the one the working copy sits on).", |
|
| 254 | - | schema: || obj(json!({ "message": { "type": "string" }, "change": { "type": "string" } }), &["message"]), |
|
| 255 | - | build: |a, _| { |
|
| 256 | - | let mut v = vec!["describe".into(), "--json".into(), opt("--message", required(a, "message")?)]; |
|
| 257 | - | positional(&mut v, arg_str(a, "change").map(|c| vec![c.to_string()]).unwrap_or_default()); |
|
| 258 | - | Ok(v) |
|
| 259 | - | }, |
|
| 260 | - | json: true, |
|
| 261 | - | read_only: false, |
|
| 262 | - | destructive: false, |
|
| 263 | - | }, |
|
| 264 | - | Spec { |
|
| 265 | - | name: "fetch", |
|
| 266 | - | description: "Fetch from a remote (default origin) without moving local bookmarks.", |
|
| 267 | - | schema: || obj(json!({ "remote": { "type": "string" } }), &[]), |
|
| 268 | - | build: |a, _| remote_cmd("fetch", a), |
|
| 269 | - | json: true, |
|
| 270 | - | read_only: false, |
|
| 271 | - | destructive: false, |
|
| 272 | - | }, |
|
| 273 | - | Spec { |
|
| 274 | - | name: "pull", |
|
| 275 | - | description: "Fetch from a remote (default origin) and bring the current bookmark and working copy up to date.", |
|
| 276 | - | schema: || obj(json!({ "remote": { "type": "string" } }), &[]), |
|
| 277 | - | build: |a, _| remote_cmd("pull", a), |
|
| 278 | - | json: true, |
|
| 279 | - | read_only: false, |
|
| 280 | - | destructive: false, |
|
| 281 | - | }, |
|
| 282 | - | Spec { |
|
| 283 | - | name: "push", |
|
| 284 | - | description: "Push the current bookmark (or `bookmark`) to a remote (default origin). Changes are sealed at push as this server's identity. `force` (drop heads the remote has) needs the server started with --allow-destructive.", |
|
| 285 | - | schema: || obj(json!({ "remote": { "type": "string" }, "bookmark": { "type": "string" }, "force": { "type": "boolean" } }), &[]), |
|
| 286 | - | build: |a, destructive| { |
|
| 287 | - | let mut v = vec!["push".to_string(), "--json".into()]; |
|
| 288 | - | if let Some(b) = arg_str(a, "bookmark") { |
|
| 289 | - | v.push(opt("--bookmark", b)); |
|
| 290 | - | } |
|
| 291 | - | if a.get("force").and_then(Value::as_bool).unwrap_or(false) { |
|
| 292 | - | if !destructive { |
|
| 293 | - | return Err("a forced push can drop the remote's heads; start oxy mcp with --allow-destructive to allow it".into()); |
|
| 294 | - | } |
|
| 295 | - | v.push("--force".into()); |
|
| 296 | - | } |
|
| 297 | - | positional(&mut v, arg_str(a, "remote").map(|r| vec![r.to_string()]).unwrap_or_default()); |
|
| 298 | - | Ok(v) |
|
| 299 | - | }, |
|
| 300 | - | json: true, |
|
| 301 | - | read_only: false, |
|
| 302 | - | destructive: false, |
|
| 303 | - | }, |
|
| 304 | - | Spec { |
|
| 305 | - | name: "tlog_verify", |
|
| 306 | - | description: "Check the hub's transparency log: that it shows everyone the same history, with this repository's entries and each witness's cosignature.", |
|
| 307 | - | schema: none, |
|
| 308 | - | build: |_, _| Ok(vec!["tlog".into(), "verify".into(), "--json".into()]), |
|
| 309 | - | json: true, |
|
| 310 | - | read_only: true, |
|
| 311 | - | destructive: false, |
|
| 312 | - | }, |
|
| 313 | - | Spec { |
|
| 314 | - | name: "undo", |
|
| 315 | - | description: "Take back the last operation (see op_log). Offered only when the server was started with --allow-destructive.", |
|
| 316 | - | schema: none, |
|
| 317 | - | build: |_, _| Ok(vec!["undo".into()]), |
|
| 318 | - | json: false, |
|
| 319 | - | read_only: false, |
|
| 320 | - | destructive: true, |
|
| 321 | - | }, |
|
| 322 | - | ] |
|
| 323 | - | } |
|
| 324 | - | ||
| 325 | - | fn remote_cmd(command: &str, a: &Value) -> Result<Vec<String>, String> { |
|
| 326 | - | let mut v = vec![command.to_string(), "--json".into()]; |
|
| 327 | - | positional( |
|
| 328 | - | &mut v, |
|
| 329 | - | arg_str(a, "remote") |
|
| 330 | - | .map(|r| vec![r.to_string()]) |
|
| 331 | - | .unwrap_or_default(), |
|
| 332 | - | ); |
|
| 333 | - | Ok(v) |
|
| 334 | - | } |
|
| 335 | - | ||
| 336 | - | struct OxyTools { |
|
| 337 | - | exe: PathBuf, |
|
| 338 | - | dir: PathBuf, |
|
| 339 | - | allow_destructive: bool, |
|
| 340 | - | } |
|
| 341 | - | ||
| 342 | - | impl OxyTools { |
|
| 343 | - | fn offered(&self) -> impl Iterator<Item = Spec> + '_ { |
|
| 344 | - | specs() |
|
| 345 | - | .into_iter() |
|
| 346 | - | .filter(|s| self.allow_destructive || !s.destructive) |
|
| 347 | - | } |
|
| 348 | - | ||
| 349 | - | fn run(&self, spec: &Spec, argv: Vec<String>) -> ToolOutput { |
|
| 350 | - | let out = Command::new(&self.exe) |
|
| 351 | - | .arg("--plain") |
|
| 352 | - | .args(&argv) |
|
| 353 | - | .current_dir(&self.dir) |
|
| 354 | - | .stdin(Stdio::null()) |
|
| 355 | - | .output(); |
|
| 356 | - | let out = match out { |
|
| 357 | - | Ok(o) => o, |
|
| 358 | - | Err(e) => return ToolOutput::error(format!("could not run oxy: {e}")), |
|
| 359 | - | }; |
|
| 360 | - | let stdout = String::from_utf8_lossy(&out.stdout).into_owned(); |
|
| 361 | - | let stderr = String::from_utf8_lossy(&out.stderr).into_owned(); |
|
| 362 | - | if !out.status.success() { |
|
| 363 | - | let why = if stderr.trim().is_empty() { |
|
| 364 | - | stdout |
|
| 365 | - | } else { |
|
| 366 | - | stderr |
|
| 367 | - | }; |
|
| 368 | - | return ToolOutput::error(format!("oxy {} failed: {}", argv.join(" "), why.trim())); |
|
| 369 | - | } |
|
| 370 | - | let mut result = ToolOutput::ok(stdout.clone()); |
|
| 371 | - | if spec.json { |
|
| 372 | - | result.structured = serde_json::from_str(&stdout).ok(); |
|
| 373 | - | } else if !stderr.trim().is_empty() && stdout.trim().is_empty() { |
|
| 374 | - | // Commands that report on stderr (commit's summary) still say what they did. |
|
| 375 | - | result.text = stderr; |
|
| 376 | - | } |
|
| 377 | - | if result.text.len() > MAX_TEXT { |
|
| 378 | - | let mut cut = MAX_TEXT; |
|
| 379 | - | while !result.text.is_char_boundary(cut) { |
|
| 380 | - | cut -= 1; |
|
| 381 | - | } |
|
| 382 | - | result.text.truncate(cut); |
|
| 383 | - | result.text.push_str( |
|
| 384 | - | "\n… (cut at 256 KiB: narrow the request, e.g. a smaller limit or one path)", |
|
| 385 | - | ); |
|
| 386 | - | result.structured = None; |
|
| 387 | - | } |
|
| 388 | - | result |
|
| 389 | - | } |
|
| 390 | - | } |
|
| 391 | - | ||
| 392 | - | impl Tools for OxyTools { |
|
| 393 | - | fn list(&self) -> Vec<Tool> { |
|
| 394 | - | self.offered() |
|
| 395 | - | .map(|s| Tool { |
|
| 396 | - | name: s.name.into(), |
|
| 397 | - | description: s.description.into(), |
|
| 398 | - | input_schema: (s.schema)(), |
|
| 399 | - | read_only: s.read_only, |
|
| 400 | - | destructive: s.destructive, |
|
| 401 | - | }) |
|
| 402 | - | .collect() |
|
| 403 | - | } |
|
| 404 | - | ||
| 405 | - | fn call(&self, name: &str, args: &Value) -> Option<ToolOutput> { |
|
| 406 | - | let spec = self.offered().find(|s| s.name == name)?; |
|
| 407 | - | Some(match (spec.build)(args, self.allow_destructive) { |
|
| 408 | - | Ok(argv) => self.run(&spec, argv), |
|
| 409 | - | Err(why) => ToolOutput::error(why), |
|
| 410 | - | }) |
|
| 411 | - | } |
|
| 412 | - | } |
|
| 413 | - | ||
| 414 | - | /// The first line of `oxy identity show`, said in `initialize` so the client |
|
| 415 | - | /// knows who its changes will be signed as. |
|
| 416 | - | fn signer_line(exe: &Path, dir: &Path) -> String { |
|
| 417 | - | let out = Command::new(exe) |
|
| 418 | - | .args(["--plain", "identity", "show"]) |
|
| 419 | - | .current_dir(dir) |
|
| 420 | - | .stdin(Stdio::null()) |
|
| 421 | - | .output(); |
|
| 422 | - | match out { |
|
| 423 | - | Ok(o) if o.status.success() => { |
|
| 424 | - | let text = String::from_utf8_lossy(&o.stdout); |
|
| 425 | - | let who = text.lines().next().unwrap_or("").trim_start_matches(['#', '▍', ' ']).trim().to_string(); |
|
| 426 | - | let signing = text.lines().find(|l| l.trim_start().starts_with("signing")).map(|l| l.trim().to_string()); |
|
| 427 | - | match signing { |
|
| 428 | - | Some(s) => format!("{who}; {s}"), |
|
| 429 | - | None => who, |
|
| 430 | - | } |
|
| 431 | - | } |
|
| 432 | - | _ => "no identity is configured: commits will be refused until one is (oxy identity create, or an agent home with OXY_HOME)".into(), |
|
| 433 | - | } |
|
| 434 | - | } |
|
| 435 | - | ||
| 436 | - | pub fn serve(dir: Option<PathBuf>, allow_destructive: bool) -> Result<i32> { |
|
| 437 | - | let dir = match dir { |
|
| 438 | - | Some(d) => d, |
|
| 439 | - | None => std::env::current_dir()?, |
|
| 440 | - | }; |
|
| 441 | - | if !dir.join(oxy_core::repo::OXY_DIR).is_dir() { |
|
| 442 | - | bail!("{} is not the root of an Oxygen repository (no {}): start oxy mcp in a checkout's root, or name it", dir.display(), oxy_core::repo::OXY_DIR); |
|
| 443 | - | } |
|
| 444 | - | let exe = std::env::current_exe()?; |
|
| 445 | - | let signer = signer_line(&exe, &dir); |
|
| 446 | - | let info = ServerInfo { |
|
| 447 | - | name: "oxy".into(), |
|
| 448 | - | version: env!("CARGO_PKG_VERSION").into(), |
|
| 449 | - | instructions: format!( |
|
| 450 | - | "Oxygen version control for the repository at {}. Changes are signed as: {signer}. Prefer these tools to running oxy in a shell. \ |
|
| 451 | - | commit and amend take explicit paths (or all: true). {}", |
|
| 452 | - | dir.display(), |
|
| 453 | - | if allow_destructive { "Destructive tools (undo, forced push) are enabled: use them only when asked." } else { "Destructive tools (undo, forced push) are off." } |
|
| 454 | - | ), |
|
| 455 | - | }; |
|
| 456 | - | let tools = OxyTools { |
|
| 457 | - | exe, |
|
| 458 | - | dir, |
|
| 459 | - | allow_destructive, |
|
| 460 | - | }; |
|
| 461 | - | let stdin = std::io::stdin(); |
|
| 462 | - | mcp::serve(&info, &tools, stdin.lock(), std::io::stdout().lock())?; |
|
| 463 | - | Ok(0) |
|
| 464 | - | } |
|
| 465 | - | ||
| 466 | - | #[cfg(test)] |
|
| 467 | - | mod tests { |
|
| 468 | - | use super::*; |
|
| 469 | - | ||
| 470 | - | fn build(name: &str, args: Value, destructive: bool) -> Result<Vec<String>, String> { |
|
| 471 | - | let spec = specs().into_iter().find(|s| s.name == name).unwrap(); |
|
| 472 | - | (spec.build)(&args, destructive) |
|
| 473 | - | } |
|
| 474 | - | ||
| 475 | - | #[test] |
|
| 476 | - | fn values_never_read_as_flags() { |
|
| 477 | - | assert_eq!( |
|
| 478 | - | build( |
|
| 479 | - | "commit", |
|
| 480 | - | json!({"message": "-m oops", "paths": ["-rf"]}), |
|
| 481 | - | false |
|
| 482 | - | ) |
|
| 483 | - | .unwrap(), |
|
| 484 | - | ["commit", "--message=-m oops", "--", "-rf"] |
|
| 485 | - | ); |
|
| 486 | - | assert_eq!( |
|
| 487 | - | build("cat", json!({"path": "--help", "change": "main"}), false).unwrap(), |
|
| 488 | - | ["cat", "--change=main", "--", "--help"] |
|
| 489 | - | ); |
|
| 490 | - | assert_eq!( |
|
| 491 | - | build("log", json!({"limit": 5000}), false).unwrap(), |
|
| 492 | - | ["log", "--json", "--limit=1000"], |
|
| 493 | - | "limit is capped" |
|
| 494 | - | ); |
|
| 495 | - | } |
|
| 496 | - | ||
| 497 | - | #[test] |
|
| 498 | - | fn commits_name_what_goes_in() { |
|
| 499 | - | assert!(build("commit", json!({"message": "x"}), false) |
|
| 500 | - | .unwrap_err() |
|
| 501 | - | .contains("all: true")); |
|
| 502 | - | assert!(build( |
|
| 503 | - | "commit", |
|
| 504 | - | json!({"message": "x", "paths": ["a"], "all": true}), |
|
| 505 | - | false |
|
| 506 | - | ) |
|
| 507 | - | .is_err()); |
|
| 508 | - | assert_eq!( |
|
| 509 | - | build("commit", json!({"message": "x", "all": true}), false).unwrap(), |
|
| 510 | - | ["commit", "--message=x"] |
|
| 511 | - | ); |
|
| 512 | - | assert!(build("commit", json!({"message": " ", "all": true}), false) |
|
| 513 | - | .unwrap_err() |
|
| 514 | - | .contains("message")); |
|
| 515 | - | } |
|
| 516 | - | ||
| 517 | - | #[test] |
|
| 518 | - | fn destructive_tools_need_the_flag() { |
|
| 519 | - | let off = OxyTools { |
|
| 520 | - | exe: "oxy".into(), |
|
| 521 | - | dir: ".".into(), |
|
| 522 | - | allow_destructive: false, |
|
| 523 | - | }; |
|
| 524 | - | let on = OxyTools { |
|
| 525 | - | exe: "oxy".into(), |
|
| 526 | - | dir: ".".into(), |
|
| 527 | - | allow_destructive: true, |
|
| 528 | - | }; |
|
| 529 | - | assert!(!off.list().iter().any(|t| t.name == "undo")); |
|
| 530 | - | assert!( |
|
| 531 | - | off.call("undo", &json!({})).is_none(), |
|
| 532 | - | "an unoffered tool is unknown" |
|
| 533 | - | ); |
|
| 534 | - | assert!(on.list().iter().any(|t| t.name == "undo" && t.destructive)); |
|
| 535 | - | assert!(build("push", json!({"force": true}), false) |
|
| 536 | - | .unwrap_err() |
|
| 537 | - | .contains("--allow-destructive")); |
|
| 538 | - | assert_eq!( |
|
| 539 | - | build("push", json!({"force": true, "remote": "earth"}), true).unwrap(), |
|
| 540 | - | ["push", "--json", "--force", "--", "earth"] |
|
| 541 | - | ); |
|
| 542 | - | } |
|
| 543 | - | } |
modified src/cli/mod.rs +2 −134
| 1 | 1 | //! Command-line definitions and dispatch. |
|
| 2 | 2 | ||
| 3 | 3 | mod approve; |
|
| 4 | - | mod artifact; |
|
| 5 | 4 | mod auth; |
|
| 6 | 5 | mod format; |
|
| 7 | 6 | mod identity; |
|
| 8 | 7 | mod json; |
|
| 9 | - | mod mcp; |
|
| 10 | 8 | mod proposal; |
|
| 11 | 9 | mod receipt; |
|
| 12 | 10 | mod sync; |
|
| … | 196 unchanged lines |
||
| 209 | 207 | #[arg(long)] |
|
| 210 | 208 | json: bool, |
|
| 211 | 209 | }, |
|
| 212 | - | /// Serve this repository to an AI agent over the Model Context Protocol (stdio), signing as this checkout's identity |
|
| 213 | - | Mcp { |
|
| 214 | - | /// The repository's root (default: the current directory) |
|
| 215 | - | dir: Option<PathBuf>, |
|
| 216 | - | /// Also offer tools that can lose work: undo, and a forced push |
|
| 217 | - | #[arg(long)] |
|
| 218 | - | allow_destructive: bool, |
|
| 219 | - | }, |
|
| 220 | 210 | /// Print the version of oxy, its repository format, and protocol |
|
| 221 | 211 | Version { |
|
| 222 | 212 | /// Machine-readable output: one JSON document on stdout |
|
| … | 197 unchanged lines |
||
| 420 | 410 | Tlog { |
|
| 421 | 411 | #[command(subcommand)] |
|
| 422 | 412 | cmd: TlogCmd, |
|
| 423 | - | }, |
|
| 424 | - | /// Artifacts: a directory packed into a tree of this repository's chunks (Cylinder, docs/cylinder.md) |
|
| 425 | - | Artifact { |
|
| 426 | - | #[command(subcommand)] |
|
| 427 | - | cmd: ArtifactCmd, |
|
| 428 | 413 | }, |
|
| 429 | 414 | /// Execution receipts: signed records of what a runner ran on a state |
|
| 430 | 415 | Receipt { |
|
| … | 114 unchanged lines |
||
| 545 | 530 | #[command(subcommand)] |
|
| 546 | 531 | cmd: PolicyCmd, |
|
| 547 | 532 | }, |
|
| 548 | - | /// Set a configuration key (author.*, core.sign, core.op-retention, core.gc-grace, core.checkpoint-interval, filter.max-blob, filter.paths, storage.cache, workspace.bookmark, remote.<name>.url|token|ca, git.claim, git.colocate, auth.helper with --user) |
|
| 533 | + | /// Set a configuration key (author.*, core.sign, core.op-retention, core.gc-grace, core.checkpoint-interval, filter.max-blob, filter.paths, storage.cache, workspace.bookmark, remote.<name>.url|token|ca, auth.helper with --user) |
|
| 549 | 534 | Config { |
|
| 550 | 535 | /// The key, such as author.name or remote.origin.token |
|
| 551 | 536 | key: String, |
|
| … | 280 unchanged lines |
||
| 832 | 817 | Remove { |
|
| 833 | 818 | /// The subrepo to unregister |
|
| 834 | 819 | path: String, |
|
| 835 | - | /// Delete its directory too (#164); refused while it has uncommitted edits |
|
| 836 | - | #[arg(long)] |
|
| 837 | - | delete: bool, |
|
| 838 | - | /// With --delete: delete it even with uncommitted edits |
|
| 839 | - | #[arg(long, requires = "delete")] |
|
| 840 | - | force: bool, |
|
| 841 | - | }, |
|
| 842 | - | } |
|
| 843 | - | ||
| 844 | - | #[derive(Subcommand)] |
|
| 845 | - | enum ArtifactCmd { |
|
| 846 | - | /// Pack DIR into an artifact: each file a blob of this repository's store, so files and chunks it holds cost nothing |
|
| 847 | - | Pack { |
|
| 848 | - | /// The directory whose files make the artifact |
|
| 849 | - | dir: std::path::PathBuf, |
|
| 850 | - | /// container, runner-image, package, archive or report |
|
| 851 | - | #[arg(long, default_value = "archive")] |
|
| 852 | - | kind: String, |
|
| 853 | - | /// x86_64, riscv64, aarch64… |
|
| 854 | - | #[arg(long)] |
|
| 855 | - | arch: Option<String>, |
|
| 856 | - | /// linux, darwin, none… |
|
| 857 | - | #[arg(long)] |
|
| 858 | - | os: Option<String>, |
|
| 859 | - | /// The default command, one word per flag |
|
| 860 | - | #[arg(long = "entrypoint", value_name = "WORD")] |
|
| 861 | - | entrypoint: Vec<String>, |
|
| 862 | - | /// KEY=VALUE for the environment (repeatable) |
|
| 863 | - | #[arg(long = "env", value_name = "KEY=VALUE")] |
|
| 864 | - | env: Vec<String>, |
|
| 865 | - | /// KEY=VALUE metadata (repeatable) |
|
| 866 | - | #[arg(long = "label", value_name = "KEY=VALUE")] |
|
| 867 | - | labels: Vec<String>, |
|
| 868 | - | /// Machine-readable output: one JSON document on stdout |
|
| 869 | - | #[arg(long)] |
|
| 870 | - | json: bool, |
|
| 871 | - | }, |
|
| 872 | - | /// The artifacts kept here |
|
| 873 | - | List { |
|
| 874 | - | /// Machine-readable output: one JSON document on stdout |
|
| 875 | - | #[arg(long)] |
|
| 876 | - | json: bool, |
|
| 877 | - | }, |
|
| 878 | - | /// One artifact and its files |
|
| 879 | - | Show { |
|
| 880 | - | /// Its name, or a unique prefix of at least six characters |
|
| 881 | - | name: String, |
|
| 882 | - | /// Machine-readable output: one JSON document on stdout |
|
| 883 | - | #[arg(long)] |
|
| 884 | - | json: bool, |
|
| 885 | - | }, |
|
| 886 | - | /// Write an artifact's files into DEST (missing or empty) |
|
| 887 | - | Unpack { |
|
| 888 | - | /// Its name, or a unique prefix of at least six characters |
|
| 889 | - | name: String, |
|
| 890 | - | /// Where to write its files |
|
| 891 | - | dest: std::path::PathBuf, |
|
| 892 | 820 | }, |
|
| 893 | - | /// Check an artifact's name, tree and every file against the store |
|
| 894 | - | Verify { |
|
| 895 | - | /// Its name, or a unique prefix of at least six characters |
|
| 896 | - | name: String, |
|
| 897 | - | }, |
|
| 898 | 821 | } |
|
| 899 | 822 | ||
| 900 | 823 | #[derive(Subcommand)] |
|
| … | 222 unchanged lines |
||
| 1123 | 1046 | ||
| 1124 | 1047 | #[derive(Subcommand)] |
|
| 1125 | 1048 | enum GitCmd { |
|
| 1126 | - | /// Keep a .git beside .oxy, up to date after every oxy command, so editors' Git features work here (one way: oxy to Git) |
|
| 1127 | - | Colocate { |
|
| 1128 | - | /// Stop updating it (the .git is left as it is) |
|
| 1129 | - | #[arg(long)] |
|
| 1130 | - | off: bool, |
|
| 1131 | - | }, |
|
| 1132 | 1049 | /// Export the current bookmark to a Git repository (created bare if absent) |
|
| 1133 | 1050 | Export { |
|
| 1134 | 1051 | /// Git repository to write to (created bare if absent) |
|
| … | 139 unchanged lines |
||
| 1274 | 1191 | #[arg(long)] |
|
| 1275 | 1192 | out: Option<PathBuf>, |
|
| 1276 | 1193 | }, |
|
| 1277 | - | } |
|
| 1278 | - | ||
| 1279 | - | /// After a command, bring the side-by-side `.git` up to date when this |
|
| 1280 | - | /// checkout keeps one (`git.colocate`). It never fails the command: a |
|
| 1281 | - | /// problem is a warning, and the next command tries again. |
|
| 1282 | - | pub fn after_command() { |
|
| 1283 | - | if AT_OP.get().and_then(|o| o.as_deref()).is_some() { |
|
| 1284 | - | return; |
|
| 1285 | - | } |
|
| 1286 | - | let Ok(dir) = std::env::current_dir() else { |
|
| 1287 | - | return; |
|
| 1288 | - | }; |
|
| 1289 | - | let Ok(repo) = Repo::open(&dir) else { return }; |
|
| 1290 | - | if !repo.config.git_colocate || repo.is_bare() { |
|
| 1291 | - | return; |
|
| 1292 | - | } |
|
| 1293 | - | if let Err(e) = repo.git_colocate_sync() { |
|
| 1294 | - | eprintln!( |
|
| 1295 | - | "{} the .git beside this checkout was not updated: {e}", |
|
| 1296 | - | ui::warn("!") |
|
| 1297 | - | ); |
|
| 1298 | - | } |
|
| 1299 | 1194 | } |
|
| 1300 | 1195 | ||
| 1301 | 1196 | /// Open the repository containing the current directory. |
|
| … | 74 unchanged lines |
||
| 1376 | 1271 | } |
|
| 1377 | 1272 | Cmd::Cat { path, change } => workspace::cat(&path, change.as_deref()), |
|
| 1378 | 1273 | Cmd::Root { json } => workspace::root(json), |
|
| 1379 | - | Cmd::Mcp { |
|
| 1380 | - | dir, |
|
| 1381 | - | allow_destructive, |
|
| 1382 | - | } => mcp::serve(dir, allow_destructive), |
|
| 1383 | 1274 | Cmd::Version { json } => workspace::version(json), |
|
| 1384 | 1275 | Cmd::Discard { paths, hunks } => workspace::discard(&paths, &hunks), |
|
| 1385 | 1276 | Cmd::Hunks { json } => workspace::hunks(json), |
|
| … | 147 unchanged lines |
||
| 1533 | 1424 | } => sync::submodule_add(&url, &path, bookmark.as_deref()), |
|
| 1534 | 1425 | SubmoduleCmd::Update { init, paths } => sync::submodule_update(init, &paths), |
|
| 1535 | 1426 | SubmoduleCmd::Status { json } => sync::submodule_status(json), |
|
| 1536 | - | SubmoduleCmd::Remove { |
|
| 1537 | - | path, |
|
| 1538 | - | delete, |
|
| 1539 | - | force, |
|
| 1540 | - | } => sync::submodule_remove(&path, delete, force), |
|
| 1427 | + | SubmoduleCmd::Remove { path } => sync::submodule_remove(&path), |
|
| 1541 | 1428 | }, |
|
| 1542 | 1429 | Cmd::Witness { |
|
| 1543 | 1430 | cmd: |
|
| … | 13 unchanged lines |
||
| 1557 | 1444 | all, |
|
| 1558 | 1445 | json, |
|
| 1559 | 1446 | } => tlog::verify(hub.as_deref(), key.as_deref(), all, json), |
|
| 1560 | - | }, |
|
| 1561 | - | Cmd::Artifact { cmd } => match cmd { |
|
| 1562 | - | ArtifactCmd::Pack { |
|
| 1563 | - | dir, |
|
| 1564 | - | kind, |
|
| 1565 | - | arch, |
|
| 1566 | - | os, |
|
| 1567 | - | entrypoint, |
|
| 1568 | - | env, |
|
| 1569 | - | labels, |
|
| 1570 | - | json, |
|
| 1571 | - | } => artifact::pack(&dir, &kind, arch, os, entrypoint, &env, &labels, json), |
|
| 1572 | - | ArtifactCmd::List { json } => artifact::list(json), |
|
| 1573 | - | ArtifactCmd::Show { name, json } => artifact::show(&name, json), |
|
| 1574 | - | ArtifactCmd::Unpack { name, dest } => artifact::unpack(&name, &dest), |
|
| 1575 | - | ArtifactCmd::Verify { name } => artifact::verify(&name), |
|
| 1576 | 1447 | }, |
|
| 1577 | 1448 | Cmd::Receipt { cmd } => match cmd { |
|
| 1578 | 1449 | ReceiptCmd::List { rev, json } => receipt::list(rev.as_deref(), json), |
|
| … | 86 unchanged lines |
||
| 1665 | 1536 | DelegateCmd::List => identity::delegate_list(), |
|
| 1666 | 1537 | }, |
|
| 1667 | 1538 | }, |
|
| 1668 | - | Cmd::Git { |
|
| 1669 | - | cmd: GitCmd::Colocate { off }, |
|
| 1670 | - | } => sync::git_colocate(off), |
|
| 1671 | 1539 | Cmd::Git { |
|
| 1672 | 1540 | cmd: GitCmd::Export { git_dir, branch }, |
|
| 1673 | 1541 | } => sync::git_export(&git_dir, branch.as_deref()), |
|
| … | 121 unchanged lines |
modified src/cli/sync.rs +7 −110
| … | 371 unchanged lines |
||
| 372 | 372 | let repo = open()?; |
|
| 373 | 373 | let remote = remote_name(&repo, remote); |
|
| 374 | 374 | let sp = ui::spinner(&format!("Fetching from {remote}…")); |
|
| 375 | - | let report = noted(&repo, &remote, repo.fetch(&remote))?; |
|
| 375 | + | let report = repo.fetch(&remote)?; |
|
| 376 | 376 | sp.clear(); |
|
| 377 | 377 | if as_json { |
|
| 378 | 378 | println!( |
|
| … | 160 unchanged lines |
||
| 539 | 539 | let repo = open()?; |
|
| 540 | 540 | let remote = remote_name(&repo, remote); |
|
| 541 | 541 | let sp = ui::spinner(&format!("Pulling from {remote}…")); |
|
| 542 | - | let r = noted(&repo, &remote, repo.pull(&remote))?; |
|
| 542 | + | let r = repo.pull(&remote)?; |
|
| 543 | 543 | if as_json { |
|
| 544 | 544 | sp.clear(); |
|
| 545 | 545 | let conflicted = repo |
|
| … | 143 unchanged lines |
||
| 689 | 689 | let sp = ui::spinner(&format!("Pushing to {remote}…")); |
|
| 690 | 690 | let bookmark_name = bookmark.map_or_else(|| repo.config.bookmark.clone(), String::from); |
|
| 691 | 691 | // A long push goes in parts: the spinner says which. |
|
| 692 | - | let results = noted( |
|
| 693 | - | &repo, |
|
| 694 | - | &remote, |
|
| 695 | - | repo.push_bookmark_with(&remote, &bookmark_name, force, &mut |m| { |
|
| 696 | - | sp.set(&format!("Pushing to {remote}… {m}")) |
|
| 697 | - | }), |
|
| 698 | - | )?; |
|
| 692 | + | let results = repo.push_bookmark_with(&remote, &bookmark_name, force, &mut |m| { |
|
| 693 | + | sp.set(&format!("Pushing to {remote}… {m}")) |
|
| 694 | + | })?; |
|
| 699 | 695 | sp.clear(); |
|
| 700 | 696 | if as_json { |
|
| 701 | 697 | // The state each accepted bookmark now holds on the remote (its local |
|
| … | 78 unchanged lines |
||
| 780 | 776 | Ok(0) |
|
| 781 | 777 | } |
|
| 782 | 778 | ||
| 783 | - | /// `oxy git colocate [--off]`: keep a `.git` beside `.oxy` (spec §23). |
|
| 784 | - | pub fn git_colocate(off: bool) -> Result<i32> { |
|
| 785 | - | let mut repo = open()?; |
|
| 786 | - | if repo.is_bare() { |
|
| 787 | - | anyhow::bail!("a bare repository has no working copy for a .git beside it"); |
|
| 788 | - | } |
|
| 789 | - | repo.config |
|
| 790 | - | .set("git.colocate", if off { "false" } else { "true" })?; |
|
| 791 | - | repo.save_config()?; |
|
| 792 | - | if off { |
|
| 793 | - | println!( |
|
| 794 | - | "{} the .git beside this checkout is no longer updated {}", |
|
| 795 | - | ui::done("Stopped:"), |
|
| 796 | - | ui::dim("(it is left as it is: delete .git yourself if you want it gone)") |
|
| 797 | - | ); |
|
| 798 | - | return Ok(0); |
|
| 799 | - | } |
|
| 800 | - | let sp = ui::spinner("Exporting to .git…"); |
|
| 801 | - | repo.git_colocate_sync()?; |
|
| 802 | - | sp.clear(); |
|
| 803 | - | println!( |
|
| 804 | - | "{} .git beside .oxy holds {} {}", |
|
| 805 | - | ui::done("Colocated:"), |
|
| 806 | - | ui::bookmark(&repo.config.bookmark), |
|
| 807 | - | ui::dim("(updated after every oxy command; Git's own commits are not read back: commit with oxy)") |
|
| 808 | - | ); |
|
| 809 | - | Ok(0) |
|
| 810 | - | } |
|
| 811 | - | ||
| 812 | 779 | pub fn git_export(git_dir: &std::path::Path, branch: Option<&str>) -> Result<i32> { |
|
| 813 | 780 | let repo = open()?; |
|
| 814 | 781 | let sp = ui::spinner("Exporting to Git…"); |
|
| … | 421 unchanged lines |
||
| 1236 | 1203 | Ok(0) |
|
| 1237 | 1204 | } |
|
| 1238 | 1205 | ||
| 1239 | - | pub fn submodule_remove(path: &str, delete: bool, force: bool) -> Result<i32> { |
|
| 1206 | + | pub fn submodule_remove(path: &str) -> Result<i32> { |
|
| 1240 | 1207 | let repo = open()?; |
|
| 1241 | - | let dir = repo.root().join(path.trim_end_matches('/')); |
|
| 1242 | - | // Look before unregistering, so a refused delete changes nothing. |
|
| 1243 | - | if delete && dir.exists() && !force { |
|
| 1244 | - | if let Ok(sub) = oxy_core::repo::Repo::open(&dir) { |
|
| 1245 | - | let snap = sub.snapshot("oxy submodule remove --delete")?; |
|
| 1246 | - | if !snap.statuses.is_empty() { |
|
| 1247 | - | anyhow::bail!( |
|
| 1248 | - | "{path} has {} with uncommitted edits; commit them in the subrepo (and push them if you want them kept), or pass --force to delete them", |
|
| 1249 | - | plural(snap.statuses.len(), "file") |
|
| 1250 | - | ); |
|
| 1251 | - | } |
|
| 1252 | - | } |
|
| 1253 | - | } |
|
| 1254 | 1208 | repo.submodule_remove(path)?; |
|
| 1255 | - | if !delete { |
|
| 1256 | - | println!( |
|
| 1257 | - | "{} subrepo {} {}", |
|
| 1258 | - | ui::done("Removed"), |
|
| 1259 | - | ui::path(path), |
|
| 1260 | - | ui::dim("(directory left in place; commit to record the removal)") |
|
| 1261 | - | ); |
|
| 1262 | - | println!( |
|
| 1263 | - | " {} {}", |
|
| 1264 | - | ui::note(), |
|
| 1265 | - | ui::dim(format!( |
|
| 1266 | - | "to delete the directory too: oxy submodule remove {path} --delete" |
|
| 1267 | - | )) |
|
| 1268 | - | ); |
|
| 1269 | - | return Ok(0); |
|
| 1270 | - | } |
|
| 1271 | - | if dir.exists() { |
|
| 1272 | - | delete_tree(&dir)?; |
|
| 1273 | - | } |
|
| 1274 | 1209 | println!( |
|
| 1275 | 1210 | "{} subrepo {} {}", |
|
| 1276 | 1211 | ui::done("Removed"), |
|
| 1277 | 1212 | ui::path(path), |
|
| 1278 | - | ui::dim("and its directory (commit to record the removal)") |
|
| 1213 | + | ui::dim("(directory left in place; commit to record the removal)") |
|
| 1279 | 1214 | ); |
|
| 1280 | 1215 | Ok(0) |
|
| 1281 | - | } |
|
| 1282 | - | ||
| 1283 | - | /// Delete a directory tree that holds a repository: its object files are |
|
| 1284 | - | /// read-only, so each is made writable first (#164). |
|
| 1285 | - | fn delete_tree(dir: &std::path::Path) -> Result<()> { |
|
| 1286 | - | fn writable(p: &std::path::Path) -> std::io::Result<()> { |
|
| 1287 | - | let meta = std::fs::symlink_metadata(p)?; |
|
| 1288 | - | if meta.file_type().is_symlink() { |
|
| 1289 | - | return Ok(()); |
|
| 1290 | - | } |
|
| 1291 | - | let mut perms = meta.permissions(); |
|
| 1292 | - | if perms.readonly() { |
|
| 1293 | - | #[allow(clippy::permissions_set_readonly_false)] |
|
| 1294 | - | perms.set_readonly(false); |
|
| 1295 | - | std::fs::set_permissions(p, perms)?; |
|
| 1296 | - | } |
|
| 1297 | - | if meta.is_dir() { |
|
| 1298 | - | for e in std::fs::read_dir(p)? { |
|
| 1299 | - | writable(&e?.path())?; |
|
| 1300 | - | } |
|
| 1301 | - | } |
|
| 1302 | - | Ok(()) |
|
| 1303 | - | } |
|
| 1304 | - | writable(dir).map_err(|e| anyhow::anyhow!("{}: {e}", dir.display()))?; |
|
| 1305 | - | std::fs::remove_dir_all(dir).map_err(|e| anyhow::anyhow!("{}: {e}", dir.display()))?; |
|
| 1306 | - | Ok(()) |
|
| 1307 | 1216 | } |
|
| 1308 | 1217 | ||
| 1309 | 1218 | pub fn deepen(remote: &str, depth: u32) -> Result<i32> { |
|
| … | 18 unchanged lines |
||
| 1328 | 1237 | } |
|
| 1329 | 1238 | )); |
|
| 1330 | 1239 | Ok(0) |
|
| 1331 | - | } |
|
| 1332 | - | ||
| 1333 | - | /// `r`, with a note when the remote's own token was refused while another |
|
| 1334 | - | /// sign-in for its hub would do (oxygen#155). |
|
| 1335 | - | fn noted<T>(repo: &oxy_core::repo::Repo, remote: &str, r: oxy_core::repo::Result<T>) -> Result<T> { |
|
| 1336 | - | r.map_err(|e| { |
|
| 1337 | - | let m = e.to_string(); |
|
| 1338 | - | match repo.stale_token_note(remote, &m) { |
|
| 1339 | - | Some(note) => anyhow::anyhow!("{m}\n note: {note}"), |
|
| 1340 | - | None => e.into(), |
|
| 1341 | - | } |
|
| 1342 | - | }) |
|
| 1343 | 1240 | } |
modified src/cli/workspace.rs +4 −110
| 1 | 1 | //! Commands that act on the local repository and working copy. |
|
| 2 | 2 | ||
| 3 | 3 | use super::format::{ |
|
| 4 | - | author_name, awaits_seal, deps_line, deps_of, plural, short_id, signature_line, |
|
| 5 | - | signature_mark_of, subject_of, via, when, |
|
| 4 | + | author_name, deps_line, deps_of, plural, short_id, signature_line, signature_mark_of, |
|
| 5 | + | subject_of, via, when, |
|
| 6 | 6 | }; |
|
| 7 | 7 | use super::json; |
|
| 8 | 8 | use super::open; |
|
| … | 235 unchanged lines |
||
| 244 | 244 | ); |
|
| 245 | 245 | print_behind(&repo); |
|
| 246 | 246 | print_statuses(&statuses); |
|
| 247 | - | print_pin_moves(&pin_moves(&repo, None)); |
|
| 248 | 247 | print_untracked_nested(&repo, &repo.untracked_nested()); |
|
| 249 | 248 | print_skipped_large(&repo); |
|
| 250 | 249 | return Ok(0); |
|
| … | 25 unchanged lines |
||
| 276 | 275 | ); |
|
| 277 | 276 | print_behind(&repo); |
|
| 278 | 277 | print_statuses(&snap.statuses); |
|
| 279 | - | print_pin_moves(&pin_moves(&repo, None)); |
|
| 280 | 278 | print_untracked_nested(&repo, &snap.untracked_nested); |
|
| 281 | 279 | print_skipped_large(&repo); |
|
| 282 | 280 | if !snap.base_snapshot.is_conflicted() { |
|
| … | 140 unchanged lines |
||
| 423 | 421 | } else { |
|
| 424 | 422 | oxy_core::repo::Selection::Paths(paths.to_vec()) |
|
| 425 | 423 | }; |
|
| 426 | - | // Pins this commit records as moved, said after it (oxygen#162): a pin |
|
| 427 | - | // moved by work inside a subrepo is a pin bump, easy to make unasked. |
|
| 428 | - | let moves = match &selection { |
|
| 429 | - | oxy_core::repo::Selection::All => pin_moves(&repo, None), |
|
| 430 | - | oxy_core::repo::Selection::Paths(p) => pin_moves(&repo, Some(p)), |
|
| 431 | - | oxy_core::repo::Selection::Hunks(_) => Vec::new(), |
|
| 432 | - | }; |
|
| 433 | 424 | let sp = ui::spinner("Committing…"); |
|
| 434 | 425 | let (h, partial) = repo.commit_selection_partial(message, &deps, &selection)?; |
|
| 435 | 426 | // The metadata only: a first commit's change holds the whole tree. |
|
| … | 5 unchanged lines |
||
| 441 | 432 | ui::hash(format!("#{}", h.short(12))), |
|
| 442 | 433 | ui::subject(subject_of(message)) |
|
| 443 | 434 | )); |
|
| 444 | - | for m in &moves { |
|
| 445 | - | let line = match (&m.to, m.dirty) { |
|
| 446 | - | (Some(to), _) => format!( |
|
| 447 | - | "recorded subrepo {}'s pin moving {} {} {}: a pin bump. Meant only your own files? `oxy commit PATHS` leaves pins out", |
|
| 448 | - | m.path, |
|
| 449 | - | m.from, |
|
| 450 | - | ui::glyph("→", "->"), |
|
| 451 | - | to |
|
| 452 | - | ), |
|
| 453 | - | (None, true) => format!( |
|
| 454 | - | "subrepo {} has uncommitted edits of its own: the pin names its last committed state; the edits stay in it", |
|
| 455 | - | m.path |
|
| 456 | - | ), |
|
| 457 | - | (None, false) => continue, |
|
| 458 | - | }; |
|
| 459 | - | println!(" {} {}", ui::caution(), ui::warn(line)); |
|
| 460 | - | } |
|
| 461 | 435 | print_untracked_nested(&repo, &repo.untracked_nested()); |
|
| 462 | 436 | print_skipped_large(&repo); |
|
| 463 | 437 | // Only a commit that took part of the working copy leaves anything. |
|
| … | 12 unchanged lines |
||
| 476 | 450 | } |
|
| 477 | 451 | where_now(&repo); |
|
| 478 | 452 | Ok(0) |
|
| 479 | - | } |
|
| 480 | - | ||
| 481 | - | /// A subrepo whose pin the next commit would move (`to`), or which has |
|
| 482 | - | /// uncommitted edits of its own (oxygen#162). |
|
| 483 | - | struct PinMove { |
|
| 484 | - | path: String, |
|
| 485 | - | from: String, |
|
| 486 | - | to: Option<String>, |
|
| 487 | - | dirty: bool, |
|
| 488 | - | } |
|
| 489 | - | ||
| 490 | - | /// The subrepos (among `paths`, when given) whose checkout is not at the |
|
| 491 | - | /// pin the base records, or holds uncommitted edits. Only a checkout with |
|
| 492 | - | /// subrepos (an `.oxymodules`) pays for the look. |
|
| 493 | - | fn pin_moves(repo: &oxy_core::repo::Repo, paths: Option<&[String]>) -> Vec<PinMove> { |
|
| 494 | - | if !repo.root().join(".oxymodules").exists() { |
|
| 495 | - | return Vec::new(); |
|
| 496 | - | } |
|
| 497 | - | let Ok(subs) = repo.subrepos() else { |
|
| 498 | - | return Vec::new(); |
|
| 499 | - | }; |
|
| 500 | - | let chosen = |p: &str| { |
|
| 501 | - | paths.is_none_or(|ps| { |
|
| 502 | - | ps.iter().any(|x| { |
|
| 503 | - | let x = x.trim_end_matches('/'); |
|
| 504 | - | p == x || p.starts_with(&format!("{x}/")) || x.is_empty() || x == "." |
|
| 505 | - | }) |
|
| 506 | - | }) |
|
| 507 | - | }; |
|
| 508 | - | subs.into_iter() |
|
| 509 | - | .filter(|s| s.committed && chosen(&s.path)) |
|
| 510 | - | .filter_map(|s| { |
|
| 511 | - | let to = s |
|
| 512 | - | .actual |
|
| 513 | - | .as_ref() |
|
| 514 | - | .filter(|a| !a.same_state(&s.pin)) |
|
| 515 | - | .map(|a| a.summary()); |
|
| 516 | - | (to.is_some() || s.dirty).then(|| PinMove { |
|
| 517 | - | from: s.pin.summary(), |
|
| 518 | - | to, |
|
| 519 | - | dirty: s.dirty, |
|
| 520 | - | path: s.path, |
|
| 521 | - | }) |
|
| 522 | - | }) |
|
| 523 | - | .collect() |
|
| 524 | 453 | } |
|
| 525 | 454 | ||
| 526 | - | /// `oxy status`'s word on subrepos: a moved pin is a change the next commit |
|
| 527 | - | /// records; edits inside a subrepo are not. |
|
| 528 | - | fn print_pin_moves(moves: &[PinMove]) { |
|
| 529 | - | if moves.is_empty() { |
|
| 530 | - | return; |
|
| 531 | - | } |
|
| 532 | - | println!("{}", ui::section("Subrepo pins")); |
|
| 533 | - | for m in moves { |
|
| 534 | - | if let Some(to) = &m.to { |
|
| 535 | - | println!( |
|
| 536 | - | " {} {} {} {} {} {}", |
|
| 537 | - | ui::warn(ui::glyph("↕", "<>")), |
|
| 538 | - | ui::path(&m.path), |
|
| 539 | - | ui::dim(&m.from), |
|
| 540 | - | ui::dim(ui::glyph("→", "->")), |
|
| 541 | - | to, |
|
| 542 | - | ui::dim("pin moved: a bare `oxy commit` records it") |
|
| 543 | - | ); |
|
| 544 | - | } |
|
| 545 | - | if m.dirty { |
|
| 546 | - | println!( |
|
| 547 | - | " {} {} {}", |
|
| 548 | - | ui::warn(ui::glyph("✎", "~")), |
|
| 549 | - | ui::path(&m.path), |
|
| 550 | - | ui::dim("uncommitted edits inside it: commit them there; the parent records only its pin") |
|
| 551 | - | ); |
|
| 552 | - | } |
|
| 553 | - | } |
|
| 554 | - | } |
|
| 555 | - | ||
| 556 | 455 | pub fn blame(path: &str, json: bool) -> Result<i32> { |
|
| 557 | 456 | let repo = open()?; |
|
| 558 | 457 | let lines = repo.blame(path)?; |
|
| … | 368 unchanged lines |
||
| 927 | 826 | if let Some(agent) = via(&repo, &status, &c.author) { |
|
| 928 | 827 | head.push(ui::dim(format!("via {}", agent.name))); |
|
| 929 | 828 | } |
|
| 930 | - | head.push(signature_mark_of( |
|
| 931 | - | &status, |
|
| 932 | - | awaits_seal(&repo, &status, &c.author), |
|
| 933 | - | )); |
|
| 829 | + | head.push(signature_mark_of(&status)); |
|
| 934 | 830 | } |
|
| 935 | 831 | println!("{}{}", node_line(row, &bullet), head.join(" ")); |
|
| 936 | 832 | let subject = if e.is_working_copy && c.message.is_empty() { |
|
| … | 1018 unchanged lines |
||
| 1955 | 1851 | repo.config.snapshot_retention_days = 0; |
|
| 1956 | 1852 | } |
|
| 1957 | 1853 | let sp = ui::spinner("Packing and pruning…"); |
|
| 1958 | - | // Cylinder's artifacts are named from outside the history: keep them. |
|
| 1959 | - | let artifacts = cylinder::roots(&repo)?; |
|
| 1960 | - | let r = repo.gc_keeping(now, &artifacts, &mut |phase| sp.set(&format!("{phase}…")))?; |
|
| 1854 | + | let r = repo.gc_with(now, &mut |phase| sp.set(&format!("{phase}…")))?; |
|
| 1961 | 1855 | sp.clear(); |
|
| 1962 | 1856 | if r.packed.objects > 0 { |
|
| 1963 | 1857 | println!( |
|
| … | 1315 unchanged lines |
modified src/main.rs +0 −3
| … | 34 unchanged lines |
||
| 35 | 35 | } |
|
| 36 | 36 | let command = oxy_core::timing::phase("command"); |
|
| 37 | 37 | let result = cli::run(); |
|
| 38 | - | if result.is_ok() { |
|
| 39 | - | cli::after_command(); |
|
| 40 | - | } |
|
| 41 | 38 | drop(command); |
|
| 42 | 39 | oxy_core::timing::memory_summary(); |
|
| 43 | 40 | match result { |
|
| … | 8 unchanged lines |
removed tests/cli_colocate.rs +0 −110
| 1 | - | //! `oxy git colocate` (oxygenhub#355, part two): a `.git` beside `.oxy`, |
|
| 2 | - | //! kept up to date after every oxy command, so Git tools read an Oxygen |
|
| 3 | - | //! checkout; oxy never takes `.git` as content. |
|
| 4 | - | ||
| 5 | - | use std::path::Path; |
|
| 6 | - | use std::process::Command; |
|
| 7 | - | ||
| 8 | - | fn oxy(dir: &Path, home: &Path, args: &[&str]) -> (bool, String) { |
|
| 9 | - | let out = Command::new(env!("CARGO_BIN_EXE_oxy")) |
|
| 10 | - | .arg("--plain") |
|
| 11 | - | .args(args) |
|
| 12 | - | .current_dir(dir) |
|
| 13 | - | .env("OXY_HOME", home) |
|
| 14 | - | .env("NO_COLOR", "1") |
|
| 15 | - | .output() |
|
| 16 | - | .unwrap(); |
|
| 17 | - | ( |
|
| 18 | - | out.status.success(), |
|
| 19 | - | format!( |
|
| 20 | - | "{}{}", |
|
| 21 | - | String::from_utf8_lossy(&out.stdout), |
|
| 22 | - | String::from_utf8_lossy(&out.stderr) |
|
| 23 | - | ), |
|
| 24 | - | ) |
|
| 25 | - | } |
|
| 26 | - | ||
| 27 | - | fn git(dir: &Path, args: &[&str]) -> String { |
|
| 28 | - | let out = Command::new("git") |
|
| 29 | - | .args(args) |
|
| 30 | - | .current_dir(dir) |
|
| 31 | - | .env("GIT_CONFIG_NOSYSTEM", "1") |
|
| 32 | - | .env("HOME", dir) |
|
| 33 | - | .output() |
|
| 34 | - | .unwrap(); |
|
| 35 | - | assert!( |
|
| 36 | - | out.status.success(), |
|
| 37 | - | "git {args:?}: {}", |
|
| 38 | - | String::from_utf8_lossy(&out.stderr) |
|
| 39 | - | ); |
|
| 40 | - | String::from_utf8_lossy(&out.stdout).trim().to_string() |
|
| 41 | - | } |
|
| 42 | - | ||
| 43 | - | #[test] |
|
| 44 | - | fn a_colocated_git_follows_the_bookmark() { |
|
| 45 | - | if Command::new("git").arg("--version").output().is_err() { |
|
| 46 | - | eprintln!("git not installed; skipping"); |
|
| 47 | - | return; |
|
| 48 | - | } |
|
| 49 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 50 | - | let home = tmp.path().join("home"); |
|
| 51 | - | std::fs::create_dir_all(&home).unwrap(); |
|
| 52 | - | let r = tmp.path().join("r"); |
|
| 53 | - | assert!(oxy(tmp.path(), &home, &["init", r.to_str().unwrap()]).0); |
|
| 54 | - | assert!( |
|
| 55 | - | oxy( |
|
| 56 | - | &r, |
|
| 57 | - | &home, |
|
| 58 | - | &[ |
|
| 59 | - | "identity", |
|
| 60 | - | "create", |
|
| 61 | - | "--name", |
|
| 62 | - | "Ada", |
|
| 63 | - | "--email", |
|
| 64 | - | "[email protected]" |
|
| 65 | - | ] |
|
| 66 | - | ) |
|
| 67 | - | .0 |
|
| 68 | - | ); |
|
| 69 | - | std::fs::write(r.join("a.txt"), "one\n").unwrap(); |
|
| 70 | - | assert!(oxy(&r, &home, &["commit", "-m", "first"]).0); |
|
| 71 | - | ||
| 72 | - | let (ok, out) = oxy(&r, &home, &["git", "colocate"]); |
|
| 73 | - | assert!(ok, "{out}"); |
|
| 74 | - | assert!(r.join(".git/HEAD").exists()); |
|
| 75 | - | assert_eq!(git(&r, &["log", "--format=%s"]), "first"); |
|
| 76 | - | assert_eq!(git(&r, &["symbolic-ref", "HEAD"]), "refs/heads/main"); |
|
| 77 | - | assert_eq!( |
|
| 78 | - | git(&r, &["status", "--porcelain"]), |
|
| 79 | - | "", |
|
| 80 | - | "Git sees no difference, and not .oxy either" |
|
| 81 | - | ); |
|
| 82 | - | let (_, status) = oxy(&r, &home, &["status"]); |
|
| 83 | - | assert!( |
|
| 84 | - | !status.contains(".git"), |
|
| 85 | - | "oxy never takes .git as content: {status}" |
|
| 86 | - | ); |
|
| 87 | - | ||
| 88 | - | // An oxy commit shows in Git without asking. |
|
| 89 | - | std::fs::write(r.join("a.txt"), "one\ntwo\n").unwrap(); |
|
| 90 | - | assert_eq!( |
|
| 91 | - | git(&r, &["status", "--porcelain"]), |
|
| 92 | - | "M a.txt", |
|
| 93 | - | "uncommitted work shows as modified" |
|
| 94 | - | ); |
|
| 95 | - | assert!(oxy(&r, &home, &["commit", "-m", "second"]).0); |
|
| 96 | - | assert_eq!(git(&r, &["log", "--format=%s"]), "second\nfirst"); |
|
| 97 | - | assert_eq!(git(&r, &["status", "--porcelain"]), ""); |
|
| 98 | - | assert_eq!(git(&r, &["show", "HEAD:a.txt"]), "one\ntwo"); |
|
| 99 | - | ||
| 100 | - | // Off: no more updates, the .git stays. |
|
| 101 | - | assert!(oxy(&r, &home, &["git", "colocate", "--off"]).0); |
|
| 102 | - | std::fs::write(r.join("b.txt"), "b\n").unwrap(); |
|
| 103 | - | assert!(oxy(&r, &home, &["commit", "-m", "third"]).0); |
|
| 104 | - | assert_eq!( |
|
| 105 | - | git(&r, &["log", "--format=%s"]), |
|
| 106 | - | "second\nfirst", |
|
| 107 | - | "no longer followed" |
|
| 108 | - | ); |
|
| 109 | - | assert!(r.join(".git/HEAD").exists()); |
|
| 110 | - | } |
modified tests/cli_json.rs +0 −118
| … | 261 unchanged lines |
||
| 262 | 262 | ||
| 263 | 263 | /// `oxy commit -F`, `oxy describe` naming and tags as changes (feedback |
|
| 264 | 264 | /// 4 and 6). |
|
| 265 | - | /// Cylinder C1 (oxygen#108): a directory packs into an artifact of this |
|
| 266 | - | /// repository's chunks, lists and shows as JSON, survives gc, and unpacks. |
|
| 267 | - | #[test] |
|
| 268 | - | fn artifacts_pack_show_survive_gc_and_unpack() { |
|
| 269 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 270 | - | let home = tmp.path().join("home"); |
|
| 271 | - | let dir = tmp.path().join("r"); |
|
| 272 | - | std::fs::create_dir_all(&dir).unwrap(); |
|
| 273 | - | assert_eq!(oxy(&dir, &home, &["init"]).0, 0); |
|
| 274 | - | write(tmp.path(), "out/bin/tool", "#!/bin/sh\necho hi\n"); |
|
| 275 | - | write(tmp.path(), "out/README", "a tool\n"); |
|
| 276 | - | let out = tmp.path().join("out"); |
|
| 277 | - | let pack = [ |
|
| 278 | - | "artifact", |
|
| 279 | - | "pack", |
|
| 280 | - | out.to_str().unwrap(), |
|
| 281 | - | "--kind", |
|
| 282 | - | "package", |
|
| 283 | - | "--arch", |
|
| 284 | - | "x86_64", |
|
| 285 | - | "--label", |
|
| 286 | - | "version=0.1.0", |
|
| 287 | - | "--json", |
|
| 288 | - | ]; |
|
| 289 | - | let a = json(&dir, &home, &pack); |
|
| 290 | - | let name = a["name"].as_str().unwrap().to_string(); |
|
| 291 | - | assert_eq!( |
|
| 292 | - | ( |
|
| 293 | - | a["kind"].as_str(), |
|
| 294 | - | a["files"].as_u64(), |
|
| 295 | - | a["labels"]["version"].as_str() |
|
| 296 | - | ), |
|
| 297 | - | (Some("package"), Some(2), Some("0.1.0")) |
|
| 298 | - | ); |
|
| 299 | - | let list = json(&dir, &home, &["artifact", "list", "--json"]); |
|
| 300 | - | assert_eq!(list[0]["name"], name.as_str()); |
|
| 301 | - | let (code, _, err) = oxy( |
|
| 302 | - | &dir, |
|
| 303 | - | &home, |
|
| 304 | - | &[ |
|
| 305 | - | "artifact", |
|
| 306 | - | "pack", |
|
| 307 | - | out.to_str().unwrap(), |
|
| 308 | - | "--kind", |
|
| 309 | - | "tarball", |
|
| 310 | - | ], |
|
| 311 | - | ); |
|
| 312 | - | assert_ne!(code, 0); |
|
| 313 | - | assert!(err.contains("runner-image"), "{err}"); |
|
| 314 | - | assert_eq!(oxy(&dir, &home, &["gc", "--now"]).0, 0); |
|
| 315 | - | let (code, verified, err) = oxy(&dir, &home, &["artifact", "verify", &name[..8]]); |
|
| 316 | - | assert_eq!(code, 0, "{err}"); |
|
| 317 | - | assert!(String::from_utf8_lossy(&verified).contains("2 files check out")); |
|
| 318 | - | let back = tmp.path().join("back"); |
|
| 319 | - | assert_eq!( |
|
| 320 | - | oxy( |
|
| 321 | - | &dir, |
|
| 322 | - | &home, |
|
| 323 | - | &["artifact", "unpack", &name, back.to_str().unwrap()] |
|
| 324 | - | ) |
|
| 325 | - | .0, |
|
| 326 | - | 0 |
|
| 327 | - | ); |
|
| 328 | - | assert_eq!( |
|
| 329 | - | std::fs::read_to_string(back.join("bin/tool")).unwrap(), |
|
| 330 | - | "#!/bin/sh\necho hi\n" |
|
| 331 | - | ); |
|
| 332 | - | } |
|
| 333 | - | ||
| 334 | - | /// oxygen#144: a first identity needs no repository; the next repository |
|
| 335 | - | /// signs as it. |
|
| 336 | - | #[test] |
|
| 337 | - | fn a_first_identity_needs_no_repository() { |
|
| 338 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 339 | - | let home = tmp.path().join("home"); |
|
| 340 | - | let nowhere = tmp.path().join("nowhere"); |
|
| 341 | - | std::fs::create_dir_all(&nowhere).unwrap(); |
|
| 342 | - | let local = ["identity", "create", "--local"]; |
|
| 343 | - | let (code, _, err) = oxy(&nowhere, &home, &local); |
|
| 344 | - | assert_ne!(code, 0, "--local needs a repository"); |
|
| 345 | - | assert!(err.contains("no oxy repository"), "{err}"); |
|
| 346 | - | let ident = [ |
|
| 347 | - | "identity", |
|
| 348 | - | "create", |
|
| 349 | - | "--name", |
|
| 350 | - | "Ada", |
|
| 351 | - | "--email", |
|
| 352 | - | "[email protected]", |
|
| 353 | - | ]; |
|
| 354 | - | let (code, out, err) = oxy(&nowhere, &home, &ident); |
|
| 355 | - | assert_eq!(code, 0, "{err}"); |
|
| 356 | - | let out = String::from_utf8_lossy(&out); |
|
| 357 | - | assert!( |
|
| 358 | - | out.contains("Created identity Ada <[email protected]>"), |
|
| 359 | - | "{out}" |
|
| 360 | - | ); |
|
| 361 | - | let user = oxy_core::repo::read_config_file(&home.join("config.toml")).unwrap(); |
|
| 362 | - | let key = user["author.key"].clone(); |
|
| 363 | - | assert_eq!(user["author.name"], "Ada"); |
|
| 364 | - | assert!(home.join("keys").join(format!("{key}.secret")).exists()); |
|
| 365 | - | assert!(!nowhere.join(".oxy").exists(), "no repository made"); |
|
| 366 | - | ||
| 367 | - | // A repository made afterwards signs its changes with it. |
|
| 368 | - | let dir = tmp.path().join("r"); |
|
| 369 | - | std::fs::create_dir_all(&dir).unwrap(); |
|
| 370 | - | assert_eq!(oxy(&dir, &home, &["init"]).0, 0); |
|
| 371 | - | assert_eq!(oxy(&dir, &home, &["config", "core.sign", "change"]).0, 0); |
|
| 372 | - | write(&dir, "a.txt", "a\n"); |
|
| 373 | - | let (code, _, err) = oxy(&dir, &home, &["commit", "-m", "First"]); |
|
| 374 | - | assert_eq!(code, 0, "{err}"); |
|
| 375 | - | let log = json(&dir, &home, &["log", "--json", "-n", "2"]); |
|
| 376 | - | let first = &log["changes"][1]; |
|
| 377 | - | assert_eq!(first["message"], "First"); |
|
| 378 | - | assert_eq!(first["signature"]["status"], "signed", "{first}"); |
|
| 379 | - | assert_eq!(first["signature"]["key"], key.as_str()); |
|
| 380 | - | assert_eq!(first["signature"]["name"], "Ada"); |
|
| 381 | - | } |
|
| 382 | - | ||
| 383 | 265 | #[test] |
|
| 384 | 266 | fn commit_from_a_file_and_describe_for_builds() { |
|
| 385 | 267 | let tmp = tempfile::tempdir().unwrap(); |
|
| … | 500 unchanged lines |
removed tests/cli_mcp.rs +0 −231
| 1 | - | //! `oxy mcp` (oxygen#159) end to end: an MCP client talks to the server over |
|
| 2 | - | //! stdio, lists its tools, reads the repository, commits by path as the |
|
| 3 | - | //! configured identity, and is refused what it may not do. |
|
| 4 | - | ||
| 5 | - | use serde_json::{json, Value}; |
|
| 6 | - | use std::io::{BufRead, BufReader, Write}; |
|
| 7 | - | use std::path::Path; |
|
| 8 | - | use std::process::{Command, Stdio}; |
|
| 9 | - | ||
| 10 | - | fn oxy(dir: &Path, home: &Path, args: &[&str]) -> i32 { |
|
| 11 | - | Command::new(env!("CARGO_BIN_EXE_oxy")) |
|
| 12 | - | .arg("--plain") |
|
| 13 | - | .args(args) |
|
| 14 | - | .current_dir(dir) |
|
| 15 | - | .env("OXY_HOME", home) |
|
| 16 | - | .env("NO_COLOR", "1") |
|
| 17 | - | .status() |
|
| 18 | - | .unwrap() |
|
| 19 | - | .code() |
|
| 20 | - | .unwrap_or(-1) |
|
| 21 | - | } |
|
| 22 | - | ||
| 23 | - | /// Send each request in turn and collect the replies, one per request (the |
|
| 24 | - | /// notification gets none). |
|
| 25 | - | fn session(dir: &Path, home: &Path, extra: &[&str], requests: &[Value]) -> Vec<Value> { |
|
| 26 | - | let mut child = Command::new(env!("CARGO_BIN_EXE_oxy")) |
|
| 27 | - | .arg("mcp") |
|
| 28 | - | .args(extra) |
|
| 29 | - | .current_dir(dir) |
|
| 30 | - | .env("OXY_HOME", home) |
|
| 31 | - | .env("NO_COLOR", "1") |
|
| 32 | - | .stdin(Stdio::piped()) |
|
| 33 | - | .stdout(Stdio::piped()) |
|
| 34 | - | .stderr(Stdio::null()) |
|
| 35 | - | .spawn() |
|
| 36 | - | .unwrap(); |
|
| 37 | - | let mut stdin = child.stdin.take().unwrap(); |
|
| 38 | - | let mut stdout = BufReader::new(child.stdout.take().unwrap()); |
|
| 39 | - | let mut replies = vec![]; |
|
| 40 | - | for r in requests { |
|
| 41 | - | writeln!(stdin, "{r}").unwrap(); |
|
| 42 | - | stdin.flush().unwrap(); |
|
| 43 | - | if r.get("id").is_some() { |
|
| 44 | - | let mut line = String::new(); |
|
| 45 | - | stdout.read_line(&mut line).unwrap(); |
|
| 46 | - | replies.push( |
|
| 47 | - | serde_json::from_str(&line).unwrap_or_else(|e| panic!("not JSON ({e}): {line}")), |
|
| 48 | - | ); |
|
| 49 | - | } |
|
| 50 | - | } |
|
| 51 | - | drop(stdin); |
|
| 52 | - | assert!( |
|
| 53 | - | child.wait().unwrap().success(), |
|
| 54 | - | "the server ends cleanly when its input does" |
|
| 55 | - | ); |
|
| 56 | - | replies |
|
| 57 | - | } |
|
| 58 | - | ||
| 59 | - | fn call(id: u64, name: &str, args: Value) -> Value { |
|
| 60 | - | json!({"jsonrpc": "2.0", "id": id, "method": "tools/call", "params": {"name": name, "arguments": args}}) |
|
| 61 | - | } |
|
| 62 | - | ||
| 63 | - | #[test] |
|
| 64 | - | fn an_agent_reads_and_commits_through_mcp() { |
|
| 65 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 66 | - | let home = tmp.path().join("home"); |
|
| 67 | - | std::fs::create_dir_all(&home).unwrap(); |
|
| 68 | - | let repo = tmp.path().join("repo"); |
|
| 69 | - | assert_eq!(oxy(tmp.path(), &home, &["init", repo.to_str().unwrap()]), 0); |
|
| 70 | - | assert_eq!( |
|
| 71 | - | oxy( |
|
| 72 | - | &repo, |
|
| 73 | - | &home, |
|
| 74 | - | &[ |
|
| 75 | - | "identity", |
|
| 76 | - | "create", |
|
| 77 | - | "--name", |
|
| 78 | - | "Ada", |
|
| 79 | - | "--email", |
|
| 80 | - | "[email protected]" |
|
| 81 | - | ] |
|
| 82 | - | ), |
|
| 83 | - | 0 |
|
| 84 | - | ); |
|
| 85 | - | assert_eq!( |
|
| 86 | - | oxy(&repo, &home, &["config", "--user", "core.sign", "change"]), |
|
| 87 | - | 0 |
|
| 88 | - | ); |
|
| 89 | - | std::fs::write(repo.join("a.txt"), "one\n").unwrap(); |
|
| 90 | - | std::fs::write(repo.join("b.txt"), "two\n").unwrap(); |
|
| 91 | - | ||
| 92 | - | let r = session( |
|
| 93 | - | &repo, |
|
| 94 | - | &home, |
|
| 95 | - | &[], |
|
| 96 | - | &[ |
|
| 97 | - | json!({"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "test", "version": "0"}}}), |
|
| 98 | - | json!({"jsonrpc": "2.0", "method": "notifications/initialized"}), |
|
| 99 | - | json!({"jsonrpc": "2.0", "id": 2, "method": "tools/list"}), |
|
| 100 | - | call(3, "status", json!({})), |
|
| 101 | - | call(4, "commit", json!({"message": "everything"})), |
|
| 102 | - | call(5, "commit", json!({"message": "Add a", "paths": ["a.txt"]})), |
|
| 103 | - | call(6, "log", json!({"limit": 5})), |
|
| 104 | - | call(7, "status", json!({})), |
|
| 105 | - | call(8, "undo", json!({})), |
|
| 106 | - | call(9, "push", json!({"force": true})), |
|
| 107 | - | call(10, "cat", json!({"path": "a.txt", "change": "@"})), |
|
| 108 | - | ], |
|
| 109 | - | ); |
|
| 110 | - | ||
| 111 | - | let init = &r[0]["result"]; |
|
| 112 | - | assert_eq!(init["serverInfo"]["name"], "oxy"); |
|
| 113 | - | let said = init["instructions"].as_str().unwrap(); |
|
| 114 | - | assert!( |
|
| 115 | - | said.contains("Ada"), |
|
| 116 | - | "initialize says who changes are signed as: {said}" |
|
| 117 | - | ); |
|
| 118 | - | assert!( |
|
| 119 | - | said.contains("Destructive tools (undo, forced push) are off"), |
|
| 120 | - | "{said}" |
|
| 121 | - | ); |
|
| 122 | - | ||
| 123 | - | let names: Vec<&str> = r[1]["result"]["tools"] |
|
| 124 | - | .as_array() |
|
| 125 | - | .unwrap() |
|
| 126 | - | .iter() |
|
| 127 | - | .map(|t| t["name"].as_str().unwrap()) |
|
| 128 | - | .collect(); |
|
| 129 | - | for t in [ |
|
| 130 | - | "status", |
|
| 131 | - | "diff", |
|
| 132 | - | "log", |
|
| 133 | - | "show", |
|
| 134 | - | "cat", |
|
| 135 | - | "blame", |
|
| 136 | - | "bookmarks", |
|
| 137 | - | "commit", |
|
| 138 | - | "amend", |
|
| 139 | - | "push", |
|
| 140 | - | "pull", |
|
| 141 | - | "tlog_verify", |
|
| 142 | - | ] { |
|
| 143 | - | assert!(names.contains(&t), "{t} is offered: {names:?}"); |
|
| 144 | - | } |
|
| 145 | - | assert!(!names.contains(&"undo"), "undo needs --allow-destructive"); |
|
| 146 | - | ||
| 147 | - | let before = &r[2]["result"]; |
|
| 148 | - | assert_eq!(before["isError"], false, "{before}"); |
|
| 149 | - | assert!( |
|
| 150 | - | before["structuredContent"].is_object(), |
|
| 151 | - | "status comes back as JSON: {before}" |
|
| 152 | - | ); |
|
| 153 | - | assert!(before["content"][0]["text"] |
|
| 154 | - | .as_str() |
|
| 155 | - | .unwrap() |
|
| 156 | - | .contains("b.txt")); |
|
| 157 | - | ||
| 158 | - | assert_eq!( |
|
| 159 | - | r[3]["result"]["isError"], true, |
|
| 160 | - | "a commit names its paths or all: {}", |
|
| 161 | - | r[3] |
|
| 162 | - | ); |
|
| 163 | - | assert!(r[3]["result"]["content"][0]["text"] |
|
| 164 | - | .as_str() |
|
| 165 | - | .unwrap() |
|
| 166 | - | .contains("all: true")); |
|
| 167 | - | ||
| 168 | - | assert_eq!(r[4]["result"]["isError"], false, "commit by path: {}", r[4]); |
|
| 169 | - | ||
| 170 | - | let log = r[5]["result"]["content"][0]["text"].as_str().unwrap(); |
|
| 171 | - | assert!(log.contains("Add a"), "{log}"); |
|
| 172 | - | assert!( |
|
| 173 | - | r[5]["result"]["structuredContent"].is_object(), |
|
| 174 | - | "a JSON array comes wrapped: {}", |
|
| 175 | - | r[5] |
|
| 176 | - | ); |
|
| 177 | - | ||
| 178 | - | let after = r[6]["result"]["content"][0]["text"].as_str().unwrap(); |
|
| 179 | - | assert!( |
|
| 180 | - | after.contains("b.txt") && !after.contains("a.txt"), |
|
| 181 | - | "only a.txt went in: {after}" |
|
| 182 | - | ); |
|
| 183 | - | ||
| 184 | - | assert!( |
|
| 185 | - | r[7]["error"]["message"] |
|
| 186 | - | .as_str() |
|
| 187 | - | .unwrap() |
|
| 188 | - | .contains("no tool named undo"), |
|
| 189 | - | "{}", |
|
| 190 | - | r[7] |
|
| 191 | - | ); |
|
| 192 | - | assert_eq!(r[8]["result"]["isError"], true); |
|
| 193 | - | assert!(r[8]["result"]["content"][0]["text"] |
|
| 194 | - | .as_str() |
|
| 195 | - | .unwrap() |
|
| 196 | - | .contains("--allow-destructive")); |
|
| 197 | - | assert_eq!(r[9]["result"]["content"][0]["text"], "one\n"); |
|
| 198 | - | } |
|
| 199 | - | ||
| 200 | - | #[test] |
|
| 201 | - | fn destructive_tools_come_with_the_flag_and_a_bad_directory_is_refused() { |
|
| 202 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 203 | - | let home = tmp.path().join("home"); |
|
| 204 | - | std::fs::create_dir_all(&home).unwrap(); |
|
| 205 | - | let repo = tmp.path().join("repo"); |
|
| 206 | - | assert_eq!(oxy(tmp.path(), &home, &["init", repo.to_str().unwrap()]), 0); |
|
| 207 | - | let r = session( |
|
| 208 | - | &repo, |
|
| 209 | - | &home, |
|
| 210 | - | &["--allow-destructive"], |
|
| 211 | - | &[json!({"jsonrpc": "2.0", "id": 1, "method": "tools/list"})], |
|
| 212 | - | ); |
|
| 213 | - | let undo = r[0]["result"]["tools"] |
|
| 214 | - | .as_array() |
|
| 215 | - | .unwrap() |
|
| 216 | - | .iter() |
|
| 217 | - | .find(|t| t["name"] == "undo") |
|
| 218 | - | .cloned(); |
|
| 219 | - | assert_eq!( |
|
| 220 | - | undo.expect("undo is offered")["annotations"]["destructiveHint"], |
|
| 221 | - | true |
|
| 222 | - | ); |
|
| 223 | - | ||
| 224 | - | let out = Command::new(env!("CARGO_BIN_EXE_oxy")) |
|
| 225 | - | .args(["mcp", tmp.path().to_str().unwrap()]) |
|
| 226 | - | .env("OXY_HOME", &home) |
|
| 227 | - | .output() |
|
| 228 | - | .unwrap(); |
|
| 229 | - | assert!(!out.status.success()); |
|
| 230 | - | assert!(String::from_utf8_lossy(&out.stderr).contains("not the root of an Oxygen repository")); |
|
| 231 | - | } |
removed tests/cli_subrepo.rs +0 −94
| 1 | - | //! oxygen#162: a subrepo pin moved by work inside the subrepo is a change |
|
| 2 | - | //! the parent's next commit records; `oxy status` and `oxy commit` say so, |
|
| 3 | - | //! and say when a subrepo holds uncommitted edits of its own. |
|
| 4 | - | ||
| 5 | - | use std::path::Path; |
|
| 6 | - | use std::process::Command; |
|
| 7 | - | ||
| 8 | - | fn oxy(dir: &Path, home: &Path, args: &[&str]) -> (i32, String) { |
|
| 9 | - | let out = Command::new(env!("CARGO_BIN_EXE_oxy")) |
|
| 10 | - | .arg("--plain") |
|
| 11 | - | .args(args) |
|
| 12 | - | .current_dir(dir) |
|
| 13 | - | .env("OXY_HOME", home) |
|
| 14 | - | .env("NO_COLOR", "1") |
|
| 15 | - | .output() |
|
| 16 | - | .unwrap(); |
|
| 17 | - | let text = format!( |
|
| 18 | - | "{}{}", |
|
| 19 | - | String::from_utf8_lossy(&out.stdout), |
|
| 20 | - | String::from_utf8_lossy(&out.stderr) |
|
| 21 | - | ); |
|
| 22 | - | (out.status.code().unwrap_or(-1), text) |
|
| 23 | - | } |
|
| 24 | - | ||
| 25 | - | fn ok(dir: &Path, home: &Path, args: &[&str]) -> String { |
|
| 26 | - | let (code, out) = oxy(dir, home, args); |
|
| 27 | - | assert_eq!(code, 0, "oxy {args:?}: {out}"); |
|
| 28 | - | out |
|
| 29 | - | } |
|
| 30 | - | ||
| 31 | - | #[test] |
|
| 32 | - | fn moved_pins_and_edits_inside_subrepos_are_named() { |
|
| 33 | - | let tmp = tempfile::tempdir().unwrap(); |
|
| 34 | - | let t = tmp.path(); |
|
| 35 | - | let home = t.join("home"); |
|
| 36 | - | std::fs::create_dir_all(&home).unwrap(); |
|
| 37 | - | ok( |
|
| 38 | - | t, |
|
| 39 | - | &home, |
|
| 40 | - | &[ |
|
| 41 | - | "identity", |
|
| 42 | - | "create", |
|
| 43 | - | "--name", |
|
| 44 | - | "Ada", |
|
| 45 | - | "--email", |
|
| 46 | - | "[email protected]", |
|
| 47 | - | ], |
|
| 48 | - | ); |
|
| 49 | - | // The subrepo's own repository, with one change. |
|
| 50 | - | let lib = t.join("lib"); |
|
| 51 | - | ok(t, &home, &["init", lib.to_str().unwrap()]); |
|
| 52 | - | std::fs::write(lib.join("lib.txt"), "one\n").unwrap(); |
|
| 53 | - | ok(&lib, &home, &["commit", "-m", "lib one"]); |
|
| 54 | - | // The parent pins it. |
|
| 55 | - | let app = t.join("app"); |
|
| 56 | - | ok(t, &home, &["init", app.to_str().unwrap()]); |
|
| 57 | - | std::fs::write(app.join("app.txt"), "app\n").unwrap(); |
|
| 58 | - | ok( |
|
| 59 | - | &app, |
|
| 60 | - | &home, |
|
| 61 | - | &["submodule", "add", lib.to_str().unwrap(), "deps/lib"], |
|
| 62 | - | ); |
|
| 63 | - | ok(&app, &home, &["commit", "-m", "app with lib"]); |
|
| 64 | - | let quiet = ok(&app, &home, &["status"]); |
|
| 65 | - | assert!(!quiet.contains("Subrepo pins"), "{quiet}"); |
|
| 66 | - | ||
| 67 | - | // Edits inside the subrepo, not committed there: named, not a pin move. |
|
| 68 | - | let inner = app.join("deps/lib"); |
|
| 69 | - | std::fs::write(inner.join("lib.txt"), "two\n").unwrap(); |
|
| 70 | - | let st = ok(&app, &home, &["status"]); |
|
| 71 | - | assert!( |
|
| 72 | - | st.contains("Subrepo pins") && st.contains("uncommitted edits inside it"), |
|
| 73 | - | "{st}" |
|
| 74 | - | ); |
|
| 75 | - | assert!(!st.contains("pin moved"), "{st}"); |
|
| 76 | - | ||
| 77 | - | // Committed inside: the pin has moved, and a bare commit says it records it. |
|
| 78 | - | ok(&inner, &home, &["commit", "-m", "lib two"]); |
|
| 79 | - | let st = ok(&app, &home, &["status"]); |
|
| 80 | - | assert!(st.contains("deps/lib") && st.contains("pin moved"), "{st}"); |
|
| 81 | - | std::fs::write(app.join("app.txt"), "app 2\n").unwrap(); |
|
| 82 | - | let by_path = ok(&app, &home, &["commit", "-m", "app only", "app.txt"]); |
|
| 83 | - | assert!( |
|
| 84 | - | !by_path.contains("recorded subrepo"), |
|
| 85 | - | "a commit by path leaves the pin out: {by_path}" |
|
| 86 | - | ); |
|
| 87 | - | let bare = ok(&app, &home, &["commit", "-m", "everything"]); |
|
| 88 | - | assert!( |
|
| 89 | - | bare.contains("recorded subrepo deps/lib's pin moving") && bare.contains("a pin bump"), |
|
| 90 | - | "{bare}" |
|
| 91 | - | ); |
|
| 92 | - | let after = ok(&app, &home, &["status"]); |
|
| 93 | - | assert!(!after.contains("Subrepo pins"), "recorded: {after}"); |
|
| 94 | - | } |