diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 06dc41896..d0bc301db 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -4,13 +4,11 @@ (Example: [ffbd316](https://github.com/taiki-e/install-action/commit/ffbd316e0fe98cb460dae3a66cd2ef9deb398bb1)) -1\. Add tool name to the table in ["Supported tools" section in `README.md`](https://github.com/taiki-e/install-action#supported-tools). - -2\. Add base manifest to [`tools/codegen/base`](tools/codegen/base) directory. +1\. Add base manifest to [`tools/codegen/base`](tools/codegen/base) directory. See JSON files in `tools/codegen/base` directory for examples of the manifest. -3\. Generate manifest with the following command (replace `` with the tool name). +2\. Generate manifest with the following command (replace `` with the tool name). ```sh ./tools/manifest.sh @@ -23,6 +21,14 @@ See JSON files in `tools/codegen/base` directory for examples of the manifest. > GITHUB_TOKEN=$(gh auth status --show-token 2>&1 | sed -n 's/^.*Token: \(.*\)$/\1/p') ./tools/manifest.sh > ``` +## Refresh TOOLS.md + +To update `TOOLS.md`, run + +```sh +./tools/update-markdown.sh +``` + ## Troubleshooting If one of the CI builds fails due to a bin path or release asset_name, fix the problem in the base diff --git a/README.md b/README.md index f7d7ae6c3..140c53155 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # install-action [![release](https://img.shields.io/github/release/taiki-e/install-action?style=flat-square&logo=github)](https://github.com/taiki-e/install-action/releases/latest) @@ -74,57 +75,7 @@ Or: ## Supported tools - - -| Name | Where binaries will be installed | Where will it be installed from | Supported platform | License | -| ---- | -------------------------------- | ------------------------------- | ------------------ | ------- | -| [**biome**](https://biomejs.dev)| `/usr/local/bin` | [GitHub Releases](https://github.com/biomejs/biome/releases) | Linux, macOS, Windows | [MIT](https://github.com/biomejs/biome/blob/HEAD/LICENSE) | -| [**cargo-audit**](https://github.com/rustsec/rustsec/tree/HEAD/cargo-audit) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustsec/rustsec/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-APACHE) OR [MIT](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-MIT) | -| [**cargo-binstall**][cargo-binstall] | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/cargo-bins/cargo-binstall/releases) | Linux, macOS, Windows | [GPL-3.0](https://github.com/cargo-bins/cargo-binstall/blob/HEAD/crates/bin/LICENSE) | -| [**cargo-careful**](https://github.com/RalfJung/cargo-careful) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/RalfJung/cargo-careful/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/RalfJung/cargo-careful/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/RalfJung/cargo-careful/blob/HEAD/LICENSE-MIT) | -| [**cargo-cyclonedx**](https://github.com/CycloneDX/cyclonedx-rust-cargo) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/CycloneDX/cyclonedx-rust-cargo/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/HEAD/LICENSE) | -| [**cargo-deny**](https://github.com/EmbarkStudios/cargo-deny) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/EmbarkStudios/cargo-deny/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/EmbarkStudios/cargo-deny/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/EmbarkStudios/cargo-deny/blob/HEAD/LICENSE-MIT) | -| [**cargo-dinghy**](https://github.com/sonos/dinghy) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sonos/dinghy/releases) | Linux, macOS | [Apache-2.0](https://github.com/sonos/dinghy/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/sonos/dinghy/blob/HEAD/LICENSE-MIT) | -| [**cargo-export**](https://github.com/bazhenov/cargo-export) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bazhenov/cargo-export/releases) | Linux, macOS, Windows | [MIT](https://github.com/bazhenov/cargo-export/blob/HEAD/LICENSE) | -| [**cargo-hack**](https://github.com/taiki-e/cargo-hack) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-hack/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-hack/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-hack/blob/HEAD/LICENSE-MIT) | -| [**cargo-llvm-cov**](https://github.com/taiki-e/cargo-llvm-cov) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-llvm-cov/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-llvm-cov/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-llvm-cov/blob/HEAD/LICENSE-MIT) | -| [**cargo-machete**](https://github.com/bnjbvr/cargo-machete) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bnjbvr/cargo-machete/releases) | Linux, macOS, Windows | [MIT](https://github.com/bnjbvr/cargo-machete/blob/HEAD/LICENSE.md) | -| [**cargo-make**](https://github.com/sagiegurari/cargo-make) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sagiegurari/cargo-make/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/sagiegurari/cargo-make/blob/HEAD/LICENSE) | -| [**cargo-minimal-versions**](https://github.com/taiki-e/cargo-minimal-versions) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-minimal-versions/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-minimal-versions/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-minimal-versions/blob/HEAD/LICENSE-MIT) | -| [**cargo-no-dev-deps**](https://github.com/taiki-e/cargo-no-dev-deps) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-no-dev-deps/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-no-dev-deps/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-no-dev-deps/blob/HEAD/LICENSE-MIT) | -| [**cargo-rdme**](https://github.com/orium/cargo-rdme) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/orium/cargo-rdme/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/orium/cargo-rdme/blob/HEAD/LICENSE.md) | -| [**cargo-sort**](https://github.com/DevinR528/cargo-sort) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/DevinR528/cargo-sort/releases) | Linux, macOS, Windows | [Apache-2.0 OR MIT](https://github.com/DevinR528/cargo-sort/blob/55ec89082466f6bb246d870a8d56d166a8e1f08b/Cargo.toml#L5) | -| [**cargo-spellcheck**](https://github.com/drahnr/cargo-spellcheck) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/drahnr/cargo-spellcheck/releases) | Linux and Windows | [LGPLv2.1](https://github.com/drahnr/cargo-spellcheck/blob/f60c81ad0134c12faf08715f08d14f66e749f6e7/docs/checkers.md#nlprules) | -| [**cargo-tarpaulin**](https://github.com/xd009642/tarpaulin) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/xd009642/tarpaulin/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/xd009642/tarpaulin/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/xd009642/tarpaulin/blob/HEAD/LICENSE-MIT) | -| [**cargo-udeps**](https://github.com/est31/cargo-udeps) | `$CARGO_HOME/bin` | [GitHub Release](https://github.com/est31/cargo-udeps/releases) | Linux, macOS, Windows | [Apache-2.0 OR MIT](https://github.com/est31/cargo-udeps/blob/HEAD/LICENSE) | -| [**cargo-valgrind**](https://github.com/jfrimmel/cargo-valgrind) | `$CARGO_HOME/bin` | [GitHub Release](https://github.com/jfrimmel/cargo-valgrind/releases) | Linux, macOS, Windows | [MIT](https://github.com/jfrimmel/cargo-valgrind/blob/HEAD/LICENSE-MIT) or [Apache-2.0](https://github.com/jfrimmel/cargo-valgrind/blob/HEAD/LICENSE-APACHE) | -| [**cross**](https://github.com/cross-rs/cross) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/cross-rs/cross/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/cross-rs/cross/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/cross-rs/cross/blob/HEAD/LICENSE-MIT) | -| [**dprint**](https://github.com/dprint/dprint) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/dprint/dprint/releases) | Linux, macOS, Windows | [MIT](https://github.com/dprint/dprint/blob/HEAD/LICENSE) | -| [**espup**](https://github.com/esp-rs/espup) | `$CARGO_HOME/bin` | [GitHub Release](https://github.com/esp-rs/espup/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/esp-rs/espup/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/esp-rs/espup/blob/HEAD/LICENSE-MIT) | -| [**git-cliff**](https://github.com/orhun/git-cliff) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/orhun/git-cliff/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/orhun/git-cliff/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/orhun/git-cliff/blob/HEAD/LICENSE-MIT) | -| [**grcov**](https://github.com/mozilla/grcov) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/mozilla/grcov/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/mozilla/grcov/blob/HEAD/LICENSE-MPL-2.0) | -| [**hyperfine**](https://github.com/sharkdp/hyperfine) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sharkdp/hyperfine/releases) | Linux, macOS, Windows | [MIT](https://github.com/sharkdp/hyperfine/blob/HEAD/LICENSE-MIT) or [Apache-2.0](https://github.com/sharkdp/hyperfine/blob/HEAD/LICENSE-APACHE) | -| [**just**](https://github.com/casey/just) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/casey/just/releases) | Linux, macOS, Windows | [CC0-1.0](https://github.com/casey/just/blob/HEAD/LICENSE) | -| [**mdbook-linkcheck**](https://github.com/Michael-F-Bryan/mdbook-linkcheck) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases) | Linux, macOS, Windows | [MIT](https://github.com/Michael-F-Bryan/mdbook-linkcheck/blob/HEAD/LICENSE) | -| [**mdbook**](https://github.com/rust-lang/mdBook) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rust-lang/mdBook/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/rust-lang/mdBook/blob/HEAD/LICENSE) | -| [**nextest**](https://github.com/nextest-rs/nextest) (alias: `cargo-nextest`) | `$CARGO_HOME/bin` | cargo-binstall | Linux, macOS, Windows | [Apache-2.0](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-MIT) | -| [**osv-scanner**]( https://github.com/google/osv-scanner) | `/usr/local/bin` | [GitHub Releases]( https://github.com/google/osv-scanner/releases) | Linux, macOS, Windows | [Apache-2](https://github.com/google/osv-scanner/blob/HEAD/LICENSE) | -| [**parse-changelog**](https://github.com/taiki-e/parse-changelog) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/parse-changelog/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/parse-changelog/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/parse-changelog/blob/HEAD/LICENSE-MIT) | -| [**protoc**](https://github.com/protocolbuffers/protobuf) | `$HOME/.install-action/bin` | [GitHub Releases](https://github.com/protocolbuffers/protobuf/releases) | Linux, macOS, Windows | [BSD-3-Clause](https://github.com/protocolbuffers/protobuf/blob/HEAD/LICENSE) | -| [**sccache**](https://github.com/mozilla/sccache) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/mozilla/sccache/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/mozilla/sccache/blob/HEAD/LICENSE) | -| [**shellcheck**](https://www.shellcheck.net) | `/usr/local/bin` | [GitHub Releases](https://github.com/koalaman/shellcheck/releases) | Linux, macOS, Windows | [GPL-3.0-or-later](https://github.com/koalaman/shellcheck/blob/HEAD/LICENSE) | -| [**shfmt**](https://github.com/mvdan/sh) | `/usr/local/bin` | [GitHub Releases](https://github.com/mvdan/sh/releases) | Linux, macOS, Windows | [BSD-3-Clause](https://github.com/mvdan/sh/blob/HEAD/LICENSE) | -| [**syft**](https://github.com/anchore/syft) | `/usr/local/bin` | [Github Releases](https://github.com/anchore/syft/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/anchore/syft/blob/HEAD/LICENSE) | -| [**typos**](https://github.com/crate-ci/typos) | `$CARGO_HOME/bin` | [Github Releases](https://github.com/crate-ci/typos/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/crate-ci/typos/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/crate-ci/typos/blob/HEAD/LICENSE-MIT) | -| [**valgrind**](https://valgrind.org) | `/snap/bin` | [snap](https://snapcraft.io/install/valgrind/ubuntu) | Linux | [GPL-2.0-or-later](https://valgrind.org/docs/manual/license.gpl.html) | -| [**wasm-bindgen**](https://github.com/rustwasm/wasm-bindgen) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustwasm/wasm-bindgen/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/rustwasm/wasm-bindgen/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/rustwasm/wasm-bindgen/blob/HEAD/LICENSE-MIT) | -| [**wasm-pack**](https://github.com/rustwasm/wasm-pack) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustwasm/wasm-pack/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/rustwasm/wasm-pack/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/rustwasm/wasm-pack/blob/HEAD/LICENSE-MIT) | -| [**wasmtime**](https://github.com/bytecodealliance/wasmtime) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bytecodealliance/wasmtime/releases) | Linux, macOS, Windows | [Apache-2.0 WITH LLVM-exception](https://github.com/bytecodealliance/wasmtime/blob/HEAD/LICENSE) | -| [**xbuild**](https://github.com/rust-mobile/xbuild) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rust-mobile/xbuild/releases) | Linux, macOS, Windows | Apache-2.0 OR MIT | -| [**zola**](https://github.com/getzola/zola) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/getzola/zola/releases) | Linux, macOS, Windows | [MIT](https://github.com/getzola/zola/blob/HEAD/LICENSE) | +See [TOOLS.md](TOOLS.md) for the list of tools that are installed from manifests managed in this action. If `$CARGO_HOME/bin` is not available, Rust-related binaries will be installed to `$HOME/.cargo/bin`.
If `$HOME/.cargo/bin` is not available, Rust-related binaries will be installed to `/usr/local/bin`.
diff --git a/TOOLS.md b/TOOLS.md new file mode 100644 index 000000000..8846880e8 --- /dev/null +++ b/TOOLS.md @@ -0,0 +1,49 @@ +# Tools + +| Name | Where binaries will be installed | Where will it be installed from | Supported platform | License | +| ---- | -------------------------------- | ------------------------------- | ------------------ | ------- | +| [**biome**](https://biomejs.dev) | `/usr/local/bin` | [GitHub Releases](https://github.com/biomejs/biome/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/biomejs/biome/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/biomejs/biome/blob/main/LICENSE-MIT) | +| [**cargo-audit**](https://github.com/rustsec/rustsec/tree/HEAD/cargo-audit) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustsec/rustsec/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-APACHE) OR [MIT](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-MIT) | +| [**cargo-binstall**](https://github.com/cargo-bins/cargo-binstall) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/cargo-bins/cargo-binstall/releases) | Linux, macOS, Windows | [GPL-3.0](https://github.com/cargo-bins/cargo-binstall/blob/HEAD/crates/bin/LICENSE) | +| [**cargo-careful**](https://github.com/RalfJung/cargo-careful) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/RalfJung/cargo-careful/releases) | Linux, macOS, Windows | [MIT](https://github.com/RalfJung/cargo-careful/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/RalfJung/cargo-careful/blob/master/LICENSE-APACHE) | +| [**cargo-cyclonedx**](https://github.com/CycloneDX/cyclonedx-rust-cargo) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/CycloneDX/cyclonedx-rust-cargo/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/main/LICENSE) | +| [**cargo-deny**](https://github.com/EmbarkStudios/cargo-deny) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/EmbarkStudios/cargo-deny/releases) | Linux, macOS, Windows | [MIT](https://github.com/EmbarkStudios/cargo-deny/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/EmbarkStudios/cargo-deny/blob/main/LICENSE-APACHE) | +| [**cargo-dinghy**](https://github.com/sonos/dinghy) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sonos/dinghy/releases) | Linux, macOS | [MIT](https://github.com/sonos/dinghy/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/sonos/dinghy/blob/main/LICENSE-APACHE) | +| [**cargo-export**](https://github.com/bazhenov/cargo-export) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bazhenov/cargo-export/releases) | Linux, macOS, Windows | [MIT](https://github.com/bazhenov/cargo-export/blob/master/LICENSE) | +| [**cargo-hack**](https://github.com/taiki-e/cargo-hack) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-hack/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-hack/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-hack/blob/main/LICENSE-MIT) | +| [**cargo-llvm-cov**](https://github.com/taiki-e/cargo-llvm-cov) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-llvm-cov/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-llvm-cov/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-llvm-cov/blob/main/LICENSE-MIT) | +| [**cargo-machete**](https://github.com/bnjbvr/cargo-machete) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bnjbvr/cargo-machete/releases) | Linux, macOS, Windows | [MIT](https://github.com/bnjbvr/cargo-machete/blob/main/LICENSE.md) | +| [**cargo-make**](https://github.com/sagiegurari/cargo-make) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sagiegurari/cargo-make/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/sagiegurari/cargo-make/blob/master/LICENSE) | +| [**cargo-minimal-versions**](https://github.com/taiki-e/cargo-minimal-versions) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-minimal-versions/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-minimal-versions/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-minimal-versions/blob/main/LICENSE-MIT) | +| [**cargo-no-dev-deps**](https://github.com/taiki-e/cargo-no-dev-deps) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/cargo-no-dev-deps/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/cargo-no-dev-deps/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-no-dev-deps/blob/main/LICENSE-MIT) | +| [**cargo-rdme**](https://github.com/orium/cargo-rdme) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/orium/cargo-rdme/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/orium/cargo-rdme/blob/main/LICENSE.md) | +| [**cargo-sort**](https://github.com/DevinR528/cargo-sort) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/DevinR528/cargo-sort/releases) | Linux, macOS, Windows | [Apache-2.0 OR MIT](https://github.com/DevinR528/cargo-sort/blob/55ec89082466f6bb246d870a8d56d166a8e1f08b/Cargo.toml#L5) | +| [**cargo-spellcheck**](https://github.com/drahnr/cargo-spellcheck) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/drahnr/cargo-spellcheck/releases) | Linux, Windows | [LGPLv2.1](https://github.com/drahnr/cargo-spellcheck/blob/master/LICENSE-LGPL) | +| [**cargo-tarpaulin**](https://github.com/xd009642/tarpaulin) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/xd009642/tarpaulin/releases) | Linux, macOS, Windows | [MIT](https://github.com/xd009642/tarpaulin/blob/develop/LICENSE-MIT) OR [Apache-2.0](https://github.com/xd009642/tarpaulin/blob/develop/LICENSE-APACHE) | +| [**cargo-udeps**](https://github.com/est31/cargo-udeps) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/est31/cargo-udeps/releases) | Linux, macOS, Windows | [Apache-2.0 OR MIT](https://github.com/est31/cargo-udeps/blob/HEAD/LICENSE) | +| [**cargo-valgrind**](https://github.com/jfrimmel/cargo-valgrind) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/jfrimmel/cargo-valgrind/releases) | Linux, macOS, Windows | [MIT](https://github.com/jfrimmel/cargo-valgrind/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/jfrimmel/cargo-valgrind/blob/master/LICENSE-APACHE) | +| [**cross**](https://github.com/cross-rs/cross) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/cross-rs/cross/releases) | Linux, macOS, Windows | [MIT](https://github.com/cross-rs/cross/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/cross-rs/cross/blob/main/LICENSE-APACHE) | +| [**dprint**](https://github.com/dprint/dprint) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/dprint/dprint/releases) | Linux, macOS, Windows | [MIT](https://github.com/dprint/dprint/blob/main/LICENSE) | +| [**editorconfig-checker**](https://github.com/editorconfig-checker/editorconfig-checker) | `/usr/local/bin` | [GitHub Releases](https://github.com/editorconfig-checker/editorconfig-checker/releases) | Linux, macOS, Windows | [MIT](https://github.com/editorconfig-checker/editorconfig-checker/blob/main/LICENSE) | +| [**espup**](https://github.com/esp-rs/espup) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/esp-rs/espup/releases) | Linux, macOS, Windows | [MIT](https://github.com/esp-rs/espup/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/esp-rs/espup/blob/main/LICENSE-APACHE) | +| [**git-cliff**](https://github.com/orhun/git-cliff) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/orhun/git-cliff/releases) | Linux, macOS, Windows | [MIT](https://github.com/orhun/git-cliff/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/orhun/git-cliff/blob/main/LICENSE-APACHE) | +| [**grcov**](https://github.com/mozilla/grcov) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/mozilla/grcov/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/mozilla/grcov/blob/HEAD/LICENSE-MPL-2.0) | +| [**hyperfine**](https://github.com/sharkdp/hyperfine) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/sharkdp/hyperfine/releases) | Linux, macOS, Windows | [MIT](https://github.com/sharkdp/hyperfine/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/sharkdp/hyperfine/blob/master/LICENSE-APACHE) | +| [**just**](https://github.com/casey/just) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/casey/just/releases) | Linux, macOS, Windows | [CC0-1.0](https://github.com/casey/just/blob/master/LICENSE) | +| [**mdbook**](https://github.com/rust-lang/mdBook) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rust-lang/mdBook/releases) | Linux, macOS, Windows | [MPL-2.0](https://github.com/rust-lang/mdBook/blob/master/LICENSE) | +| [**mdbook-linkcheck**](https://github.com/Michael-F-Bryan/mdbook-linkcheck) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases) | Linux, macOS, Windows | [MIT](https://github.com/Michael-F-Bryan/mdbook-linkcheck/blob/master/LICENSE) | +| [**nextest**](https://nexte.st/) (alias: `cargo-nextest`)| `$CARGO_HOME/bin` | `cargo-binstall` | Linux, macOS, Windows | [Apache-2.0](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-MIT) | +| [**osv-scanner**](https://github.com/google/osv-scanner) | `/usr/local/bin` | [GitHub Releases](https://github.com/google/osv-scanner/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/google/osv-scanner/blob/main/LICENSE) | +| [**parse-changelog**](https://github.com/taiki-e/parse-changelog) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/taiki-e/parse-changelog/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/taiki-e/parse-changelog/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/parse-changelog/blob/main/LICENSE-MIT) | +| [**protoc**](https://github.com/protocolbuffers/protobuf) | `/usr/local/bin` | [GitHub Releases](https://github.com/protocolbuffers/protobuf/releases) | Linux, macOS, Windows | [BSD-3-Clause](https://github.com/protocolbuffers/protobuf/blob/HEAD/LICENSE) | +| [**sccache**](https://github.com/mozilla/sccache) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/mozilla/sccache/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/mozilla/sccache/blob/main/LICENSE) | +| [**shellcheck**](https://www.shellcheck.net) | `/usr/local/bin` | [GitHub Releases](https://github.com/koalaman/shellcheck/releases) | Linux, macOS, Windows | [GPL-3.0](https://github.com/koalaman/shellcheck/blob/master/LICENSE) | +| [**shfmt**](https://github.com/mvdan/sh) | `/usr/local/bin` | [GitHub Releases](https://github.com/mvdan/sh/releases) | Linux, macOS, Windows | [BSD-3-Clause](https://github.com/mvdan/sh/blob/master/LICENSE) | +| [**syft**](https://github.com/anchore/syft) | `/usr/local/bin` | [GitHub Releases](https://github.com/anchore/syft/releases) | Linux, macOS, Windows | [Apache-2.0](https://github.com/anchore/syft/blob/main/LICENSE) | +| [**typos**](https://github.com/crate-ci/typos) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/crate-ci/typos/releases) | Linux, macOS, Windows | [MIT](https://github.com/crate-ci/typos/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/crate-ci/typos/blob/master/LICENSE-APACHE) | +| [**valgrind**](https://valgrind.org/) | `/snap/bin` | [snap](https://snapcraft.io/install/valgrind/ubuntu) | Linux | [GPL-2.0](https://sourceware.org/git/?p=valgrind.git;a=blob;f=COPYING;hb=HEAD) | +| [**wasm-bindgen**](https://github.com/rustwasm/wasm-bindgen) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustwasm/wasm-bindgen/releases) | Linux, macOS, Windows | [MIT](https://github.com/rustwasm/wasm-bindgen/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/rustwasm/wasm-bindgen/blob/main/LICENSE-APACHE) | +| [**wasm-pack**](https://github.com/rustwasm/wasm-pack) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rustwasm/wasm-pack/releases) | Linux, macOS, Windows | [MIT](https://github.com/rustwasm/wasm-pack/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/rustwasm/wasm-pack/blob/master/LICENSE-APACHE) | +| [**wasmtime**](https://github.com/bytecodealliance/wasmtime) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/bytecodealliance/wasmtime/releases) | Linux, macOS, Windows | [Apache-2.0 WITH LLVM-exception](https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE) | +| [**xbuild**](https://github.com/rust-mobile/xbuild) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/rust-mobile/xbuild/releases) | Linux, macOS, Windows | [Apache-2.0 OR MIT](https://github.com/rust-mobile/xbuild/blob/268939a99a50d7927bce3e343e5d2ed32eb8b30e/xbuild/Cargo.toml#L7) | +| [**zola**](https://github.com/getzola/zola) | `$CARGO_HOME/bin` | [GitHub Releases](https://github.com/getzola/zola/releases) | Linux, macOS, Windows | [MIT](https://github.com/getzola/zola/blob/master/LICENSE) | diff --git a/manifests/biome.json b/manifests/biome.json index 3355af4dc..93b4fc5af 100644 --- a/manifests/biome.json +++ b/manifests/biome.json @@ -34,6 +34,7 @@ "bin": "biome.exe" } }, + "license_markdown": "[Apache-2.0](https://github.com/biomejs/biome/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/biomejs/biome/blob/main/LICENSE-MIT)", "latest": { "version": "1.7.3" }, diff --git a/manifests/cargo-audit.json b/manifests/cargo-audit.json index 635d4743b..3a0ec3f17 100644 --- a/manifests/cargo-audit.json +++ b/manifests/cargo-audit.json @@ -18,6 +18,7 @@ "bin": "cargo-audit-aarch64-unknown-linux-gnu-v${version}/cargo-audit" } }, + "license_markdown": "[Apache-2.0](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-APACHE) OR [MIT](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-MIT)", "latest": { "version": "0.20.0" }, diff --git a/manifests/cargo-binstall.json b/manifests/cargo-binstall.json index 35c20e906..cad7fccb2 100644 --- a/manifests/cargo-binstall.json +++ b/manifests/cargo-binstall.json @@ -20,6 +20,7 @@ "url": "https://github.com/cargo-bins/cargo-binstall/releases/download/v${version}/cargo-binstall-aarch64-pc-windows-msvc.zip" } }, + "license_markdown": "[GPL-3.0](https://github.com/cargo-bins/cargo-binstall/blob/HEAD/crates/bin/LICENSE)", "latest": { "version": "1.6.8" }, diff --git a/manifests/cargo-careful.json b/manifests/cargo-careful.json index d2a398450..5a814cea5 100644 --- a/manifests/cargo-careful.json +++ b/manifests/cargo-careful.json @@ -11,6 +11,7 @@ "url": "https://github.com/RalfJung/cargo-careful/releases/download/v${version}/cargo-careful.exe" } }, + "license_markdown": "[MIT](https://github.com/RalfJung/cargo-careful/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/RalfJung/cargo-careful/blob/master/LICENSE-APACHE)", "latest": { "version": "0.4.2" }, diff --git a/manifests/cargo-cyclonedx.json b/manifests/cargo-cyclonedx.json index 41f6da219..12ba6d8a8 100644 --- a/manifests/cargo-cyclonedx.json +++ b/manifests/cargo-cyclonedx.json @@ -11,6 +11,7 @@ "url": "https://github.com/CycloneDX/cyclonedx-rust-cargo/releases/download/cargo-cyclonedx-${version}/cargo-cyclonedx-Win-x86_64.zip" } }, + "license_markdown": "[Apache-2.0](https://github.com/CycloneDX/cyclonedx-rust-cargo/blob/main/LICENSE)", "latest": { "version": "0.5.0" }, diff --git a/manifests/cargo-deny.json b/manifests/cargo-deny.json index d0da83e0b..2a627d062 100644 --- a/manifests/cargo-deny.json +++ b/manifests/cargo-deny.json @@ -22,6 +22,7 @@ "bin": "cargo-deny-${version}-aarch64-apple-darwin/cargo-deny" } }, + "license_markdown": "[MIT](https://github.com/EmbarkStudios/cargo-deny/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/EmbarkStudios/cargo-deny/blob/main/LICENSE-APACHE)", "latest": { "version": "0.14.24" }, diff --git a/manifests/cargo-dinghy.json b/manifests/cargo-dinghy.json index aba53cd7f..cb6b6c8b9 100644 --- a/manifests/cargo-dinghy.json +++ b/manifests/cargo-dinghy.json @@ -10,6 +10,7 @@ "bin": "cargo-dinghy-${version}/cargo-dinghy" } }, + "license_markdown": "[MIT](https://github.com/sonos/dinghy/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/sonos/dinghy/blob/main/LICENSE-APACHE)", "latest": { "version": "0.7.1" }, diff --git a/manifests/cargo-export.json b/manifests/cargo-export.json index 7b2cb3c1d..584b05f0d 100644 --- a/manifests/cargo-export.json +++ b/manifests/cargo-export.json @@ -18,6 +18,7 @@ "bin": "cargo-export-v${version}-aarch64-apple-darwin/bin/cargo-export" } }, + "license_markdown": "[MIT](https://github.com/bazhenov/cargo-export/blob/master/LICENSE)", "latest": { "version": "0.2.5" }, diff --git a/manifests/cargo-hack.json b/manifests/cargo-hack.json index f8278ac41..0ccde21a0 100644 --- a/manifests/cargo-hack.json +++ b/manifests/cargo-hack.json @@ -1,6 +1,7 @@ { "rust_crate": "cargo-hack", "template": null, + "license_markdown": "[Apache-2.0](https://github.com/taiki-e/cargo-hack/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-hack/blob/main/LICENSE-MIT)", "latest": { "version": "0.6.28" }, diff --git a/manifests/cargo-llvm-cov.json b/manifests/cargo-llvm-cov.json index ce79ec9d8..01a920a6d 100644 --- a/manifests/cargo-llvm-cov.json +++ b/manifests/cargo-llvm-cov.json @@ -17,6 +17,7 @@ "url": "https://github.com/taiki-e/cargo-llvm-cov/releases/download/v${version}/cargo-llvm-cov-aarch64-apple-darwin.tar.gz" } }, + "license_markdown": "[Apache-2.0](https://github.com/taiki-e/cargo-llvm-cov/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-llvm-cov/blob/main/LICENSE-MIT)", "latest": { "version": "0.6.9" }, diff --git a/manifests/cargo-machete.json b/manifests/cargo-machete.json index bbb612168..106d8eeb0 100644 --- a/manifests/cargo-machete.json +++ b/manifests/cargo-machete.json @@ -1,6 +1,7 @@ { "rust_crate": "cargo-machete", "template": null, + "license_markdown": "[MIT](https://github.com/bnjbvr/cargo-machete/blob/main/LICENSE.md)", "latest": { "version": "0.6.2" }, diff --git a/manifests/cargo-make.json b/manifests/cargo-make.json index 29c3b538c..6aa3b6d91 100644 --- a/manifests/cargo-make.json +++ b/manifests/cargo-make.json @@ -18,6 +18,7 @@ "bin": "cargo-make-v${version}-aarch64-apple-darwin/cargo-make" } }, + "license_markdown": "[Apache-2.0](https://github.com/sagiegurari/cargo-make/blob/master/LICENSE)", "latest": { "version": "0.37.12" }, diff --git a/manifests/cargo-minimal-versions.json b/manifests/cargo-minimal-versions.json index 9e89d3912..c69afd9f9 100644 --- a/manifests/cargo-minimal-versions.json +++ b/manifests/cargo-minimal-versions.json @@ -20,6 +20,7 @@ "url": "https://github.com/taiki-e/cargo-minimal-versions/releases/download/v${version}/cargo-minimal-versions-aarch64-pc-windows-msvc.tar.gz" } }, + "license_markdown": "[Apache-2.0](https://github.com/taiki-e/cargo-minimal-versions/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-minimal-versions/blob/main/LICENSE-MIT)", "latest": { "version": "0.1.27" }, diff --git a/manifests/cargo-no-dev-deps.json b/manifests/cargo-no-dev-deps.json index 2f3bf0c3e..9ac5f8039 100644 --- a/manifests/cargo-no-dev-deps.json +++ b/manifests/cargo-no-dev-deps.json @@ -20,6 +20,7 @@ "url": "https://github.com/taiki-e/cargo-no-dev-deps/releases/download/v${version}/cargo-no-dev-deps-aarch64-pc-windows-msvc.tar.gz" } }, + "license_markdown": "[Apache-2.0](https://github.com/taiki-e/cargo-no-dev-deps/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/cargo-no-dev-deps/blob/main/LICENSE-MIT)", "latest": { "version": "0.2.12" }, diff --git a/manifests/cargo-rdme.json b/manifests/cargo-rdme.json index 0bbb1c143..b2aaa0203 100644 --- a/manifests/cargo-rdme.json +++ b/manifests/cargo-rdme.json @@ -11,6 +11,7 @@ "url": "https://github.com/orium/cargo-rdme/releases/download/v${version}/cargo-rdme_v${version}_x86_64-pc-windows-gnu.zip" } }, + "license_markdown": "[MPL-2.0](https://github.com/orium/cargo-rdme/blob/main/LICENSE.md)", "latest": { "version": "1.4.2" }, diff --git a/manifests/cargo-sort.json b/manifests/cargo-sort.json index d505ac3ab..cb4acb3ad 100644 --- a/manifests/cargo-sort.json +++ b/manifests/cargo-sort.json @@ -11,6 +11,7 @@ "url": "https://github.com/DevinR528/cargo-sort/releases/download/v${version}/cargo-sort-x86_64-pc-windows-msvc.zip" } }, + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/DevinR528/cargo-sort/blob/55ec89082466f6bb246d870a8d56d166a8e1f08b/Cargo.toml#L5)", "latest": { "version": "1.0.9" }, diff --git a/manifests/cargo-spellcheck.json b/manifests/cargo-spellcheck.json index a38c6c3af..f5e147550 100644 --- a/manifests/cargo-spellcheck.json +++ b/manifests/cargo-spellcheck.json @@ -8,6 +8,7 @@ "url": "https://github.com/drahnr/cargo-spellcheck/releases/download/v${version}/cargo-spellcheck-v${version}-x86_64-pc-windows-gnu.exe" } }, + "license_markdown": "[LGPLv2.1](https://github.com/drahnr/cargo-spellcheck/blob/master/LICENSE-LGPL)", "latest": { "version": "0.14.0" }, diff --git a/manifests/cargo-tarpaulin.json b/manifests/cargo-tarpaulin.json index 4c35a8c0e..b3dd165e3 100644 --- a/manifests/cargo-tarpaulin.json +++ b/manifests/cargo-tarpaulin.json @@ -17,6 +17,7 @@ "url": "https://github.com/xd009642/tarpaulin/releases/download/${version}/cargo-tarpaulin-aarch64-apple-darwin.tar.gz" } }, + "license_markdown": "[MIT](https://github.com/xd009642/tarpaulin/blob/develop/LICENSE-MIT) OR [Apache-2.0](https://github.com/xd009642/tarpaulin/blob/develop/LICENSE-APACHE)", "latest": { "version": "0.30.0" }, diff --git a/manifests/cargo-udeps.json b/manifests/cargo-udeps.json index a47857b44..81b39a196 100644 --- a/manifests/cargo-udeps.json +++ b/manifests/cargo-udeps.json @@ -30,6 +30,7 @@ "bin": "./cargo-udeps-v${version}-aarch64-pc-windows-msvc/cargo-udeps.exe" } }, + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/est31/cargo-udeps/blob/HEAD/LICENSE)", "latest": { "version": "0.1.47" }, diff --git a/manifests/cargo-valgrind.json b/manifests/cargo-valgrind.json index 8b37256e5..3c6b9748b 100644 --- a/manifests/cargo-valgrind.json +++ b/manifests/cargo-valgrind.json @@ -11,6 +11,7 @@ "url": "https://github.com/jfrimmel/cargo-valgrind/releases/download/v${version}/cargo-valgrind-${version}-x86_64-pc-windows-msvc.zip" } }, + "license_markdown": "[MIT](https://github.com/jfrimmel/cargo-valgrind/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/jfrimmel/cargo-valgrind/blob/master/LICENSE-APACHE)", "latest": { "version": "2.1.0" }, diff --git a/manifests/cross.json b/manifests/cross.json index 9709463ce..ec5c416f1 100644 --- a/manifests/cross.json +++ b/manifests/cross.json @@ -1,6 +1,7 @@ { "rust_crate": "cross", "template": null, + "license_markdown": "[MIT](https://github.com/cross-rs/cross/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/cross-rs/cross/blob/main/LICENSE-APACHE)", "latest": { "version": "0.2.5" }, diff --git a/manifests/dprint.json b/manifests/dprint.json index 62399bf75..830939f57 100644 --- a/manifests/dprint.json +++ b/manifests/dprint.json @@ -23,6 +23,7 @@ "url": "https://github.com/dprint/dprint/releases/download/${version}/dprint-aarch64-apple-darwin.zip" } }, + "license_markdown": "[MIT](https://github.com/dprint/dprint/blob/main/LICENSE)", "latest": { "version": "0.46.1" }, diff --git a/manifests/editorconfig-checker.json b/manifests/editorconfig-checker.json index 1e60c1cfc..87559838a 100644 --- a/manifests/editorconfig-checker.json +++ b/manifests/editorconfig-checker.json @@ -26,6 +26,7 @@ "bin": "bin/ec-windows-arm64.exe" } }, + "license_markdown": "[MIT](https://github.com/editorconfig-checker/editorconfig-checker/blob/main/LICENSE)", "latest": { "version": "3.0.1" }, diff --git a/manifests/espup.json b/manifests/espup.json index e01fb0046..9fe7b1b83 100644 --- a/manifests/espup.json +++ b/manifests/espup.json @@ -17,6 +17,7 @@ "url": "https://github.com/esp-rs/espup/releases/download/v${version}/espup-aarch64-apple-darwin.zip" } }, + "license_markdown": "[MIT](https://github.com/esp-rs/espup/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/esp-rs/espup/blob/main/LICENSE-APACHE)", "latest": { "version": "0.11.0" }, diff --git a/manifests/git-cliff.json b/manifests/git-cliff.json index 52bddaa63..326bf4046 100644 --- a/manifests/git-cliff.json +++ b/manifests/git-cliff.json @@ -26,6 +26,7 @@ "bin": "git-cliff-${version}/git-cliff.exe" } }, + "license_markdown": "[MIT](https://github.com/orhun/git-cliff/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/orhun/git-cliff/blob/main/LICENSE-APACHE)", "latest": { "version": "2.2.2" }, diff --git a/manifests/grcov.json b/manifests/grcov.json index 5b2a03f24..3a4653f85 100644 --- a/manifests/grcov.json +++ b/manifests/grcov.json @@ -17,6 +17,7 @@ "url": "https://github.com/mozilla/grcov/releases/download/v${version}/grcov-aarch64-apple-darwin.tar.bz2" } }, + "license_markdown": "[MPL-2.0](https://github.com/mozilla/grcov/blob/HEAD/LICENSE-MPL-2.0)", "latest": { "version": "0.8.19" }, diff --git a/manifests/hyperfine.json b/manifests/hyperfine.json index 20a46f0ef..b8b362878 100644 --- a/manifests/hyperfine.json +++ b/manifests/hyperfine.json @@ -18,6 +18,7 @@ "bin": "hyperfine-v${version}-aarch64-unknown-linux-gnu/hyperfine" } }, + "license_markdown": "[MIT](https://github.com/sharkdp/hyperfine/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/sharkdp/hyperfine/blob/master/LICENSE-APACHE)", "latest": { "version": "1.18.0" }, diff --git a/manifests/just.json b/manifests/just.json index 2976f9ef6..e6cd570e3 100644 --- a/manifests/just.json +++ b/manifests/just.json @@ -17,6 +17,7 @@ "url": "https://github.com/casey/just/releases/download/${version}/just-${version}-aarch64-apple-darwin.tar.gz" } }, + "license_markdown": "[CC0-1.0](https://github.com/casey/just/blob/master/LICENSE)", "latest": { "version": "1.27.0" }, diff --git a/manifests/mdbook-linkcheck.json b/manifests/mdbook-linkcheck.json index 590dec664..e3ca3e132 100644 --- a/manifests/mdbook-linkcheck.json +++ b/manifests/mdbook-linkcheck.json @@ -11,6 +11,7 @@ "url": "https://github.com/Michael-F-Bryan/mdbook-linkcheck/releases/download/v${version}/mdbook-linkcheck.x86_64-pc-windows-msvc.zip" } }, + "license_markdown": "[MIT](https://github.com/Michael-F-Bryan/mdbook-linkcheck/blob/master/LICENSE)", "latest": { "version": "0.7.7" }, diff --git a/manifests/mdbook.json b/manifests/mdbook.json index 865f3c04e..a85af67aa 100644 --- a/manifests/mdbook.json +++ b/manifests/mdbook.json @@ -17,6 +17,7 @@ "url": "https://github.com/rust-lang/mdBook/releases/download/v${version}/mdbook-v${version}-aarch64-unknown-linux-musl.tar.gz" } }, + "license_markdown": "[MPL-2.0](https://github.com/rust-lang/mdBook/blob/master/LICENSE)", "latest": { "version": "0.4.40" }, diff --git a/manifests/osv-scanner.json b/manifests/osv-scanner.json index 4b548d865..35f1fe46c 100644 --- a/manifests/osv-scanner.json +++ b/manifests/osv-scanner.json @@ -20,6 +20,7 @@ "url": "https://github.com/google/osv-scanner/releases/download/v${version}/osv-scanner_${version}_windows_arm64.exe" } }, + "license_markdown": "[Apache-2.0](https://github.com/google/osv-scanner/blob/main/LICENSE)", "latest": { "version": "1.6.2" }, diff --git a/manifests/parse-changelog.json b/manifests/parse-changelog.json index 2e83fd59b..686ed43bc 100644 --- a/manifests/parse-changelog.json +++ b/manifests/parse-changelog.json @@ -1,6 +1,7 @@ { "rust_crate": "parse-changelog", "template": null, + "license_markdown": "[Apache-2.0](https://github.com/taiki-e/parse-changelog/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/taiki-e/parse-changelog/blob/main/LICENSE-MIT)", "latest": { "version": "0.6.8" }, diff --git a/manifests/protoc.json b/manifests/protoc.json index 4f42f2c9c..359496980 100644 --- a/manifests/protoc.json +++ b/manifests/protoc.json @@ -1,6 +1,7 @@ { "rust_crate": null, "template": null, + "license_markdown": "[BSD-3-Clause](https://github.com/protocolbuffers/protobuf/blob/HEAD/LICENSE)", "latest": { "version": "3.27.0" }, @@ -397,7 +398,29 @@ } }, "3.22": { - "version": "3.22.4" + "version": "3.22.5" + }, + "3.22.5": { + "x86_64_linux_gnu": { + "url": "https://github.com/protocolbuffers/protobuf/releases/download/v22.5/protoc-22.5-linux-x86_64.zip", + "checksum": "c11692013bbffb7c257de7f82cd02d323700ebcdb8a4923ed02fea812f70f5e3" + }, + "x86_64_macos": { + "url": "https://github.com/protocolbuffers/protobuf/releases/download/v22.5/protoc-22.5-osx-x86_64.zip", + "checksum": "3edd0c65e2a8efc83f24918db27e1bbc72f3abe7618cb4cfb1842630a830b562" + }, + "x86_64_windows": { + "url": "https://github.com/protocolbuffers/protobuf/releases/download/v22.5/protoc-22.5-win64.zip", + "checksum": "f99d1e9e28f7704b22d4254fab293477ea0d4ef3e5b9aa940a8fccfc99c1ce4c" + }, + "aarch64_linux_gnu": { + "url": "https://github.com/protocolbuffers/protobuf/releases/download/v22.5/protoc-22.5-linux-aarch_64.zip", + "checksum": "1890f845b333fe040ec002a659a4ff7515cd93f8db0066c3885d1fce9f70b208" + }, + "aarch64_macos": { + "url": "https://github.com/protocolbuffers/protobuf/releases/download/v22.5/protoc-22.5-osx-aarch_64.zip", + "checksum": "b7fc6c6099ad10149d90f8b107871537ca030980354b402d8e034055ce082b77" + } }, "3.22.4": { "x86_64_linux_gnu": { diff --git a/manifests/sccache.json b/manifests/sccache.json index e8a8aefae..e1b02275c 100644 --- a/manifests/sccache.json +++ b/manifests/sccache.json @@ -22,6 +22,7 @@ "bin": "sccache-v${version}-aarch64-apple-darwin/sccache" } }, + "license_markdown": "[Apache-2.0](https://github.com/mozilla/sccache/blob/main/LICENSE)", "latest": { "version": "0.8.1" }, diff --git a/manifests/shellcheck.json b/manifests/shellcheck.json index 7e30f4608..6de0755b8 100644 --- a/manifests/shellcheck.json +++ b/manifests/shellcheck.json @@ -18,6 +18,7 @@ "bin": "shellcheck-v${version}/shellcheck" } }, + "license_markdown": "[GPL-3.0](https://github.com/koalaman/shellcheck/blob/master/LICENSE)", "latest": { "version": "0.10.0" }, diff --git a/manifests/shfmt.json b/manifests/shfmt.json index d0d419b59..e43decbaa 100644 --- a/manifests/shfmt.json +++ b/manifests/shfmt.json @@ -17,6 +17,7 @@ "url": "https://github.com/mvdan/sh/releases/download/v${version}/shfmt_v${version}_darwin_arm64" } }, + "license_markdown": "[BSD-3-Clause](https://github.com/mvdan/sh/blob/master/LICENSE)", "latest": { "version": "3.8.0" }, diff --git a/manifests/syft.json b/manifests/syft.json index 03e0c70e5..677084040 100644 --- a/manifests/syft.json +++ b/manifests/syft.json @@ -22,6 +22,7 @@ "bin": "syft" } }, + "license_markdown": "[Apache-2.0](https://github.com/anchore/syft/blob/main/LICENSE)", "latest": { "version": "1.5.0" }, diff --git a/manifests/typos.json b/manifests/typos.json index d0f012b3f..e60d2bd30 100644 --- a/manifests/typos.json +++ b/manifests/typos.json @@ -14,6 +14,7 @@ "url": "https://github.com/crate-ci/typos/releases/download/v${version}/typos-v${version}-aarch64-apple-darwin.tar.gz" } }, + "license_markdown": "[MIT](https://github.com/crate-ci/typos/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/crate-ci/typos/blob/master/LICENSE-APACHE)", "latest": { "version": "1.21.0" }, diff --git a/manifests/wasm-bindgen.json b/manifests/wasm-bindgen.json index 5b5981c9b..4a9cb0e6f 100644 --- a/manifests/wasm-bindgen.json +++ b/manifests/wasm-bindgen.json @@ -42,6 +42,7 @@ ] } }, + "license_markdown": "[MIT](https://github.com/rustwasm/wasm-bindgen/blob/main/LICENSE-MIT) OR [Apache-2.0](https://github.com/rustwasm/wasm-bindgen/blob/main/LICENSE-APACHE)", "latest": { "version": "0.2.92" }, diff --git a/manifests/wasm-pack.json b/manifests/wasm-pack.json index 3d1555c31..3cad521b9 100644 --- a/manifests/wasm-pack.json +++ b/manifests/wasm-pack.json @@ -18,6 +18,7 @@ "bin": "wasm-pack-v${version}-aarch64-unknown-linux-musl/wasm-pack" } }, + "license_markdown": "[MIT](https://github.com/rustwasm/wasm-pack/blob/master/LICENSE-MIT) OR [Apache-2.0](https://github.com/rustwasm/wasm-pack/blob/master/LICENSE-APACHE)", "latest": { "version": "0.12.1" }, diff --git a/manifests/wasmtime.json b/manifests/wasmtime.json index 8865484c3..1791578ca 100644 --- a/manifests/wasmtime.json +++ b/manifests/wasmtime.json @@ -22,6 +22,7 @@ "bin": "wasmtime-v${version}-aarch64-macos/wasmtime" } }, + "license_markdown": "[Apache-2.0 WITH LLVM-exception](https://github.com/bytecodealliance/wasmtime/blob/main/LICENSE)", "latest": { "version": "21.0.1" }, diff --git a/manifests/xbuild.json b/manifests/xbuild.json index 8f27d3323..7796b5825 100644 --- a/manifests/xbuild.json +++ b/manifests/xbuild.json @@ -14,6 +14,7 @@ "bin": "xbuild-windows-x64.exe" } }, + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/rust-mobile/xbuild/blob/268939a99a50d7927bce3e343e5d2ed32eb8b30e/xbuild/Cargo.toml#L7)", "latest": { "version": "0.2.0" }, diff --git a/manifests/zola.json b/manifests/zola.json index 183de2429..859ab271f 100644 --- a/manifests/zola.json +++ b/manifests/zola.json @@ -14,6 +14,7 @@ "url": "https://github.com/getzola/zola/releases/download/v${version}/zola-v${version}-aarch64-apple-darwin.tar.gz" } }, + "license_markdown": "[MIT](https://github.com/getzola/zola/blob/master/LICENSE)", "latest": { "version": "0.18.0" }, diff --git a/tools/codegen/Cargo.toml b/tools/codegen/Cargo.toml index fe973e04e..9888ea94f 100644 --- a/tools/codegen/Cargo.toml +++ b/tools/codegen/Cargo.toml @@ -1,6 +1,7 @@ [package] name = "install-action-internal-codegen" edition = "2021" +default-run = "generate-manifest" [dependencies] anyhow = "1" @@ -12,6 +13,7 @@ serde = "1" serde_derive = "1" serde_json = "1" sha2 = "0.10" +spdx = "0.10" tar = "0.4" toml_edit = { version = "0.22", default-features = false, features = ["parse", "serde"] } # TODO: call curl command instead of using ureq? @@ -19,3 +21,15 @@ ureq = { version = "2", features = ["json"] } [lints] workspace = true + +[[bin]] +bench = false +name = "generate-manifest" +path = "src/main.rs" +test = false + +[[bin]] +bench = false +name = "generate-tools-markdown" +path = "src/tools-markdown.rs" +test = false diff --git a/tools/codegen/base/biome.json b/tools/codegen/base/biome.json index 962c0b564..9b3e9b276 100644 --- a/tools/codegen/base/biome.json +++ b/tools/codegen/base/biome.json @@ -1,5 +1,7 @@ { "repository": "https://github.com/biomejs/biome", + "website": "https://biomejs.dev", + "license_markdown": "[Apache-2.0](https://github.com/biomejs/biome/blob/main/LICENSE-APACHE) OR [MIT](https://github.com/biomejs/biome/blob/main/LICENSE-MIT)", "tag_prefix": "cli/v", "bin": "${package}${exe}", "platform": { diff --git a/tools/codegen/base/cargo-audit.json b/tools/codegen/base/cargo-audit.json index d740aa3a7..03af3ff9a 100644 --- a/tools/codegen/base/cargo-audit.json +++ b/tools/codegen/base/cargo-audit.json @@ -1,5 +1,7 @@ { "repository": "https://github.com/rustsec/rustsec", + "website": "https://github.com/rustsec/rustsec/tree/HEAD/cargo-audit", + "license_markdown": "[Apache-2.0](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-APACHE) OR [MIT](https://github.com/rustsec/rustsec/blob/HEAD/cargo-audit/LICENSE-MIT)", "tag_prefix": "cargo-audit/v", "rust_crate": "${package}", "asset_name": "${package}-${rust_target}-v${version}.tgz", diff --git a/tools/codegen/base/cargo-binstall.json b/tools/codegen/base/cargo-binstall.json index 453a7f08f..0371b652a 100644 --- a/tools/codegen/base/cargo-binstall.json +++ b/tools/codegen/base/cargo-binstall.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/cargo-bins/cargo-binstall", + "license_markdown": "[GPL-3.0](https://github.com/cargo-bins/cargo-binstall/blob/HEAD/crates/bin/LICENSE)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-${rust_target}.zip", diff --git a/tools/codegen/base/cargo-sort.json b/tools/codegen/base/cargo-sort.json index 726f0931e..46eebdab6 100644 --- a/tools/codegen/base/cargo-sort.json +++ b/tools/codegen/base/cargo-sort.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/DevinR528/cargo-sort", + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/DevinR528/cargo-sort/blob/55ec89082466f6bb246d870a8d56d166a8e1f08b/Cargo.toml#L5)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-${rust_target}.tar.gz", diff --git a/tools/codegen/base/cargo-spellcheck.json b/tools/codegen/base/cargo-spellcheck.json index 63ea0e0d1..af542b2e0 100644 --- a/tools/codegen/base/cargo-spellcheck.json +++ b/tools/codegen/base/cargo-spellcheck.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/drahnr/cargo-spellcheck", + "license_markdown": "[LGPLv2.1](https://github.com/drahnr/cargo-spellcheck/blob/master/LICENSE-LGPL)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-v${version}-${rust_target}", diff --git a/tools/codegen/base/cargo-udeps.json b/tools/codegen/base/cargo-udeps.json index 92da9ea16..dc41a9d2e 100644 --- a/tools/codegen/base/cargo-udeps.json +++ b/tools/codegen/base/cargo-udeps.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/est31/cargo-udeps", + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/est31/cargo-udeps/blob/HEAD/LICENSE)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-v${version}-${rust_target}.tar.gz", diff --git a/tools/codegen/base/grcov.json b/tools/codegen/base/grcov.json index b7a8a2a17..6f996fc13 100644 --- a/tools/codegen/base/grcov.json +++ b/tools/codegen/base/grcov.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/mozilla/grcov", + "license_markdown": "[MPL-2.0](https://github.com/mozilla/grcov/blob/HEAD/LICENSE-MPL-2.0)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-${rust_target}.tar.bz2", diff --git a/tools/codegen/base/protoc.json b/tools/codegen/base/protoc.json index 1e37650c3..77250a622 100644 --- a/tools/codegen/base/protoc.json +++ b/tools/codegen/base/protoc.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/protocolbuffers/protobuf", + "license_markdown": "[BSD-3-Clause](https://github.com/protocolbuffers/protobuf/blob/HEAD/LICENSE)", "tag_prefix": "v", "default_major_version": "3", "platform": { diff --git a/tools/codegen/base/shellcheck.json b/tools/codegen/base/shellcheck.json index 2d53da829..01c6a3460 100644 --- a/tools/codegen/base/shellcheck.json +++ b/tools/codegen/base/shellcheck.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/koalaman/shellcheck", + "website": "https://www.shellcheck.net", "tag_prefix": "v", "bin": "${package}-v${version}/${package}${exe}", "platform": { diff --git a/tools/codegen/base/xbuild.json b/tools/codegen/base/xbuild.json index 41525ad9c..a310337eb 100644 --- a/tools/codegen/base/xbuild.json +++ b/tools/codegen/base/xbuild.json @@ -1,5 +1,6 @@ { "repository": "https://github.com/rust-mobile/xbuild", + "license_markdown": "[Apache-2.0 OR MIT](https://github.com/rust-mobile/xbuild/blob/268939a99a50d7927bce3e343e5d2ed32eb8b30e/xbuild/Cargo.toml#L7)", "tag_prefix": "v", "rust_crate": "${package}", "asset_name": "${package}-${rust_target_os}-x64${exe}", diff --git a/tools/codegen/src/lib.rs b/tools/codegen/src/lib.rs new file mode 100644 index 000000000..6ee62c48d --- /dev/null +++ b/tools/codegen/src/lib.rs @@ -0,0 +1,379 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::{ + cmp::{self, Reverse}, + collections::BTreeMap, + env, fmt, + path::{Path, PathBuf}, + slice, + str::FromStr, +}; + +use anyhow::Result; +use serde::{ + de::{self, Deserialize, Deserializer}, + ser::{Serialize, Serializer}, +}; +use serde_derive::{Deserialize, Serialize}; + +#[must_use] +pub fn workspace_root() -> PathBuf { + let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + dir.pop(); // codegen + dir.pop(); // tools + dir +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Version { + pub major: Option, + pub minor: Option, + pub patch: Option, + pub pre: semver::Prerelease, + pub build: semver::BuildMetadata, +} + +impl Version { + #[must_use] + pub fn omitted(major: u64, minor: Option) -> Self { + Self { + major: Some(major), + minor, + patch: None, + pre: semver::Prerelease::default(), + build: semver::BuildMetadata::default(), + } + } + #[must_use] + pub fn latest() -> Self { + Self { + major: None, + minor: None, + patch: None, + pre: semver::Prerelease::default(), + build: semver::BuildMetadata::default(), + } + } + #[must_use] + pub fn to_semver(&self) -> Option { + Some(semver::Version { + major: self.major?, + minor: self.minor?, + patch: self.patch?, + pre: self.pre.clone(), + build: self.build.clone(), + }) + } +} +impl From for Version { + fn from(v: semver::Version) -> Self { + Self { + major: Some(v.major), + minor: Some(v.minor), + patch: Some(v.patch), + pre: v.pre, + build: v.build, + } + } +} +impl PartialOrd for Version { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} +impl Ord for Version { + fn cmp(&self, other: &Self) -> cmp::Ordering { + pub(crate) fn convert(v: &Version) -> semver::Version { + semver::Version { + major: v.major.unwrap_or(u64::MAX), + minor: v.minor.unwrap_or(u64::MAX), + patch: v.patch.unwrap_or(u64::MAX), + pre: v.pre.clone(), + build: v.build.clone(), + } + } + convert(self).cmp(&convert(other)) + } +} +impl fmt::Display for Version { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let Some(major) = self.major else { + f.write_str("latest")?; + return Ok(()); + }; + f.write_str(&major.to_string())?; + let Some(minor) = self.minor else { + return Ok(()); + }; + f.write_str(".")?; + f.write_str(&minor.to_string())?; + let Some(patch) = self.patch else { + return Ok(()); + }; + f.write_str(".")?; + f.write_str(&patch.to_string())?; + if !self.pre.is_empty() { + f.write_str("-")?; + f.write_str(&self.pre)?; + } + if !self.build.is_empty() { + f.write_str("+")?; + f.write_str(&self.build)?; + } + Ok(()) + } +} +impl FromStr for Version { + type Err = semver::Error; + fn from_str(s: &str) -> Result { + if s == "latest" { + return Ok(Self::latest()); + } + match s.parse::() { + Ok(v) => Ok(v.into()), + Err(e) => match s.parse::() { + Ok(v) => Ok(Self { + major: Some(v.major), + minor: v.minor, + patch: v.patch, + pre: semver::Prerelease::default(), + build: semver::BuildMetadata::default(), + }), + Err(_e) => Err(e), + }, + } + } +} +impl Serialize for Version { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + String::serialize(&self.to_string(), serializer) + } +} +impl<'de> Deserialize<'de> for Version { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + String::deserialize(deserializer)?.parse().map_err(de::Error::custom) + } +} + +#[derive(Debug, Clone, Default, Serialize, Deserialize)] +pub struct Manifests { + pub rust_crate: Option, + pub template: Option, + /// Markdown for the licenses. + pub license_markdown: String, + #[serde(flatten)] + pub map: BTreeMap, ManifestRef>, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ManifestRef { + Ref { version: Version }, + Real(Manifest), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Manifest { + #[serde(flatten)] + pub download_info: BTreeMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManifestDownloadInfo { + #[serde(skip_serializing_if = "Option::is_none")] + pub url: Option, + pub checksum: String, + /// Path to binaries in archive. Default to `${tool}${exe}`. + #[serde(skip_serializing_if = "Option::is_none")] + pub bin: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManifestTemplate { + #[serde(flatten)] + pub download_info: BTreeMap, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ManifestTemplateDownloadInfo { + pub url: String, + /// Path to binaries in archive. Default to `${tool}${exe}`. + #[serde(skip_serializing_if = "Option::is_none")] + pub bin: Option, +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BaseManifest { + /// Link to the GitHub repository. + pub repository: String, + /// Alternative link for the project. Automatically detected if possible. + pub website: Option, + /// Markdown syntax for links to licenses. Automatically detected if possible. + pub license_markdown: Option, + /// Prefix of release tag. + pub tag_prefix: String, + /// Crate name, if this is Rust crate. + pub rust_crate: Option, + pub default_major_version: Option, + /// Asset name patterns. + pub asset_name: Option, + /// Path to binaries in archive. Default to `${tool}${exe}`. + pub bin: Option, + pub signing: Option, + #[serde(default)] + pub broken: Vec, + pub platform: BTreeMap, + pub version_range: Option, +} +impl BaseManifest { + /// Validate the manifest. + // The panic is an assert + #[allow(clippy::missing_panics_doc)] + pub fn validate(&self) { + for bin in self.bin.iter().chain(self.platform.values().flat_map(|m| &m.bin)) { + assert!(!bin.as_slice().is_empty()); + for bin in bin.as_slice() { + let file_name = Path::new(bin).file_name().unwrap().to_str().unwrap(); + if !self.repository.ends_with("/xbuild") { + assert!( + !(file_name.contains("${version") || file_name.contains("${rust")), + "{bin}" + ); + } + } + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct Signing { + pub kind: SigningKind, +} + +#[derive(Debug, Deserialize, PartialEq, Eq)] +#[serde(rename_all = "kebab-case")] +#[serde(deny_unknown_fields)] +pub enum SigningKind { + /// algorithm: minisign + /// public key: package.metadata.binstall.signing.pubkey at Cargo.toml + /// + MinisignBinstall, +} + +#[derive(Debug, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BaseManifestPlatformInfo { + /// Asset name patterns. Default to the value at `BaseManifest::asset_name`. + pub asset_name: Option, + /// Path to binaries in archive. Default to the value at `BaseManifest::bin`. + pub bin: Option, +} + +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum StringOrArray { + String(String), + Array(Vec), +} + +impl StringOrArray { + #[must_use] + pub fn as_slice(&self) -> &[String] { + match self { + Self::String(s) => slice::from_ref(s), + Self::Array(v) => v, + } + } + #[must_use] + pub fn map(&self, mut f: impl FnMut(&String) -> String) -> Self { + match self { + Self::String(s) => Self::String(f(s)), + Self::Array(v) => Self::Array(v.iter().map(f).collect()), + } + } +} + +/// GitHub Actions Runner supports Linux (x86_64, aarch64, arm), Windows (x86_64, aarch64), +/// and macOS (x86_64, aarch64). +/// https://github.com/actions/runner/blob/v2.315.0/.github/workflows/build.yml#L21 +/// https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#supported-architectures-and-operating-systems-for-self-hosted-runners +/// +/// Note: +/// - Static-linked binaries compiled for linux-musl will also work on linux-gnu systems and are +/// usually preferred over linux-gnu binaries because they can avoid glibc version issues. +/// (rustc enables statically linking for linux-musl by default, except for mips.) +/// - Binaries compiled for x86_64 macOS will usually also work on aarch64 macOS. +/// - Binaries compiled for x86_64 Windows will usually also work on aarch64 Windows 11+. +/// - Ignore arm for now, as we need to consider the version and whether hard-float is supported. +/// https://github.com/rust-lang/rustup/pull/593 +/// https://github.com/cross-rs/cross/pull/1018 +/// Does it seem only armv7l+ is supported? +/// https://github.com/actions/runner/blob/v2.315.0/src/Misc/externals.sh#L189 +/// https://github.com/actions/runner/issues/688 +#[allow(non_camel_case_types)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] +pub enum HostPlatform { + x86_64_linux_gnu, + x86_64_linux_musl, + x86_64_macos, + x86_64_windows, + aarch64_linux_gnu, + aarch64_linux_musl, + aarch64_macos, + aarch64_windows, +} + +impl HostPlatform { + #[must_use] + pub fn rust_target(self) -> &'static str { + match self { + Self::x86_64_linux_gnu => "x86_64-unknown-linux-gnu", + Self::x86_64_linux_musl => "x86_64-unknown-linux-musl", + Self::x86_64_macos => "x86_64-apple-darwin", + Self::x86_64_windows => "x86_64-pc-windows-msvc", + Self::aarch64_linux_gnu => "aarch64-unknown-linux-gnu", + Self::aarch64_linux_musl => "aarch64-unknown-linux-musl", + Self::aarch64_macos => "aarch64-apple-darwin", + Self::aarch64_windows => "aarch64-pc-windows-msvc", + } + } + #[must_use] + pub fn rust_target_arch(self) -> &'static str { + match self { + Self::aarch64_linux_gnu + | Self::aarch64_linux_musl + | Self::aarch64_macos + | Self::aarch64_windows => "aarch64", + Self::x86_64_linux_gnu + | Self::x86_64_linux_musl + | Self::x86_64_macos + | Self::x86_64_windows => "x86_64", + } + } + #[must_use] + pub fn rust_target_os(self) -> &'static str { + match self { + Self::aarch64_linux_gnu + | Self::aarch64_linux_musl + | Self::x86_64_linux_gnu + | Self::x86_64_linux_musl => "linux", + Self::aarch64_macos | Self::x86_64_macos => "macos", + Self::aarch64_windows | Self::x86_64_windows => "windows", + } + } + #[must_use] + pub fn exe_suffix(self) -> &'static str { + match self { + Self::x86_64_windows | Self::aarch64_windows => ".exe", + _ => "", + } + } +} diff --git a/tools/codegen/src/main.rs b/tools/codegen/src/main.rs index fffe7266e..66d584954 100644 --- a/tools/codegen/src/main.rs +++ b/tools/codegen/src/main.rs @@ -1,26 +1,23 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use std::{ - cmp::{self, Reverse}, + cmp::Reverse, collections::{BTreeMap, BTreeSet}, env, ffi::OsStr, - fmt, io::Read, - path::{Path, PathBuf}, - slice, - str::FromStr, + path::Path, time::Duration, }; use anyhow::{bail, Context as _, Result}; use fs_err as fs; -use serde::{ - de::{self, Deserialize, Deserializer}, - ser::{Serialize, Serializer}, +use install_action_internal_codegen::{ + workspace_root, BaseManifest, HostPlatform, Manifest, ManifestDownloadInfo, ManifestRef, + ManifestTemplate, ManifestTemplateDownloadInfo, Manifests, Signing, SigningKind, Version, }; -use serde_derive::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; +use spdx::expression::{ExprNode, ExpressionReq, Operator}; fn main() -> Result<()> { let args: Vec<_> = env::args().skip(1).collect(); @@ -46,7 +43,12 @@ fn main() -> Result<()> { let repo = base_info .repository .strip_prefix("https://github.com/") - .context("repository must be starts with https://github.com/")?; + .context("repository must start with https://github.com/")?; + + eprintln!("downloading metadata from https://github.com/{repo}"); + + let repo_info: github::RepoMetadata = + download_github(&format!("https://api.github.com/repos/{repo}"))?.into_json()?; eprintln!("downloading releases of https://github.com/{repo} from https://api.github.com/repos/{repo}/releases"); let mut releases: github::Releases = vec![]; @@ -82,6 +84,7 @@ fn main() -> Result<()> { .collect(); let mut crates_io_info = None; + let mut crates_io_version_detail = None; base_info.rust_crate = base_info .rust_crate .as_ref() @@ -89,10 +92,29 @@ fn main() -> Result<()> { .transpose()?; if let Some(crate_name) = &base_info.rust_crate { eprintln!("downloading crate info from https://crates.io/api/v1/crates/{crate_name}"); - crates_io_info = Some( - download(&format!("https://crates.io/api/v1/crates/{crate_name}"))? - .into_json::()?, + let info = download(&format!("https://crates.io/api/v1/crates/{crate_name}"))? + .into_json::()?; + let latest_version = &info.versions[0].num; + crates_io_version_detail = Some( + download(&format!("https://crates.io/api/v1/crates/{crate_name}/{latest_version}"))? + .into_json::()? + .version, ); + + if let Some(crate_repository) = info.crate_.repository.clone() { + // cargo-dinghy is fixed at https://github.com/sonos/dinghy/pull/231, but not yet released + if crate_name != "cargo-dinghy" + && !crate_repository + .to_lowercase() + .starts_with(&base_info.repository.to_lowercase()) + { + panic!("repository {crate_repository} from crates.io differs from base manifest"); + } + } else if crate_name != "zola" { + panic!("crate metadata does not include a repository"); + } + + crates_io_info = Some(info); } let mut manifests: Manifests = Manifests::default(); @@ -130,6 +152,44 @@ fn main() -> Result<()> { Err(e) => eprintln!("failed to load old manifest: {e}"), } } + + // Check website + if let Some(website) = base_info.website { + if website.is_empty() || website == base_info.repository { + panic!("Please do not put the repository in website, or set website to an empty value"); + } + } + + // Populate license_markdown + if let Some(license_markdown) = base_info.license_markdown { + if license_markdown.is_empty() { + panic!("license_markdown can not be an empty value"); + } + manifests.license_markdown = license_markdown; + } else if let Some(detail) = crates_io_version_detail { + if let Some(license) = detail.license { + eprintln!("Trying to using license '{license}' from crates.io ..."); + if let Some(license_markdown) = + get_license_markdown(&license, &repo.to_string(), &repo_info.default_branch) + { + manifests.license_markdown = license_markdown; + } + } + } else if let Some(license) = repo_info.license { + if let Some(license) = license.spdx_id { + eprintln!("Trying to using license '{license}' from github.com ..."); + if let Some(license_markdown) = + get_license_markdown(&license, &repo.to_string(), &repo_info.default_branch) + { + manifests.license_markdown = license_markdown; + } + } + } + + if manifests.license_markdown.is_empty() { + panic!("Unable to determine license_markdown; set manually") + } + let version_req: Option = match args.get(1) { _ if latest_only => { let req = format!("={}", releases.first_key_value().unwrap().0 .0).parse()?; @@ -488,13 +548,6 @@ fn main() -> Result<()> { Ok(()) } -fn workspace_root() -> PathBuf { - let mut dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - dir.pop(); // codegen - dir.pop(); // tools - dir -} - fn replace_vars( s: &str, package: &str, @@ -561,6 +614,35 @@ fn download_github(url: &str) -> Result { Err(last_error.unwrap().into()) } +#[allow(clippy::missing_panics_doc)] +pub fn github_head(url: &str) -> Result<()> { + eprintln!("fetching head of {url} .."); + let mut token = env::var("GITHUB_TOKEN").ok().filter(|v| !v.is_empty()); + let mut retry = 0; + let max_retry = 2; + let mut last_error; + loop { + let mut req = ureq::head(url); + if let Some(token) = &token { + req = req.set("Authorization", token); + } + match req.call() { + Ok(_) => return Ok(()), + Err(e) => last_error = Some(e), + } + if retry == max_retry / 2 && token.is_some() { + token = None; + } + retry += 1; + if retry > max_retry { + break; + } + eprintln!("head of {url} failed; retrying after {}s ({retry}/{max_retry})", retry * 2); + std::thread::sleep(Duration::from_secs(retry * 2)); + } + Err(last_error.unwrap().into()) +} + /// Download without using GITHUB_TOKEN. #[allow(clippy::missing_panics_doc)] pub fn download(url: &str) -> Result { @@ -583,344 +665,128 @@ pub fn download(url: &str) -> Result { Err(last_error.unwrap().into()) } -#[derive(Debug, Clone, PartialEq, Eq)] -struct Version { - major: Option, - minor: Option, - patch: Option, - pre: semver::Prerelease, - build: semver::BuildMetadata, -} - -impl Version { - fn omitted(major: u64, minor: Option) -> Self { - Self { - major: Some(major), - minor, - patch: None, - pre: semver::Prerelease::default(), - build: semver::BuildMetadata::default(), - } - } - fn latest() -> Self { - Self { - major: None, - minor: None, - patch: None, - pre: semver::Prerelease::default(), - build: semver::BuildMetadata::default(), - } - } - fn to_semver(&self) -> Option { - Some(semver::Version { - major: self.major?, - minor: self.minor?, - patch: self.patch?, - pre: self.pre.clone(), - build: self.build.clone(), - }) - } -} -impl From for Version { - fn from(v: semver::Version) -> Self { - Self { - major: Some(v.major), - minor: Some(v.minor), - patch: Some(v.patch), - pre: v.pre, - build: v.build, - } - } -} -impl PartialOrd for Version { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} -impl Ord for Version { - fn cmp(&self, other: &Self) -> cmp::Ordering { - fn convert(v: &Version) -> semver::Version { - semver::Version { - major: v.major.unwrap_or(u64::MAX), - minor: v.minor.unwrap_or(u64::MAX), - patch: v.patch.unwrap_or(u64::MAX), - pre: v.pre.clone(), - build: v.build.clone(), +#[must_use] +fn create_github_raw_link(repository: &String, branch: &String, filename: &String) -> String { + format!("https://raw.githubusercontent.com/{repository}/{branch}/{filename}") +} + +#[must_use] +fn create_github_link(repository: &String, branch: &String, filename: &String) -> String { + format!("https://github.com/{repository}/blob/{branch}/{filename}") +} +#[must_use] +fn get_license_markdown(spdx_expr: &str, repo: &String, default_branch: &String) -> Option { + // TODO: use https://docs.rs/spdx/latest/spdx/expression/struct.Expression.html#method.canonicalize ? + let expr = spdx::Expression::parse_mode(spdx_expr, spdx::ParseMode::LAX).unwrap(); + + let mut op = None; + let mut license_ids: Vec<(&spdx::LicenseId, Option<&spdx::ExceptionId>)> = vec![]; + + for node in expr.iter() { + match node { + ExprNode::Req(ExpressionReq { + req: + spdx::LicenseReq { + license: spdx::LicenseItem::Spdx { id, or_later }, + exception, + .. + }, + .. + }) => { + if *or_later { + panic!("need to handle or_later"); + } + if let Some(exception_id) = exception { + license_ids.push((id, Some(exception_id))); + } else { + license_ids.push((id, None)); + } } - } - convert(self).cmp(&convert(other)) - } -} -impl fmt::Display for Version { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let Some(major) = self.major else { - f.write_str("latest")?; - return Ok(()); - }; - f.write_str(&major.to_string())?; - let Some(minor) = self.minor else { - return Ok(()); - }; - f.write_str(".")?; - f.write_str(&minor.to_string())?; - let Some(patch) = self.patch else { - return Ok(()); - }; - f.write_str(".")?; - f.write_str(&patch.to_string())?; - if !self.pre.is_empty() { - f.write_str("-")?; - f.write_str(&self.pre)?; - } - if !self.build.is_empty() { - f.write_str("+")?; - f.write_str(&self.build)?; - } - Ok(()) - } -} -impl FromStr for Version { - type Err = semver::Error; - fn from_str(s: &str) -> Result { - if s == "latest" { - return Ok(Self::latest()); - } - match s.parse::() { - Ok(v) => Ok(v.into()), - Err(e) => match s.parse::() { - Ok(v) => Ok(Self { - major: Some(v.major), - minor: v.minor, - patch: v.patch, - pre: semver::Prerelease::default(), - build: semver::BuildMetadata::default(), - }), - Err(_e) => Err(e), - }, - } - } -} -impl Serialize for Version { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - String::serialize(&self.to_string(), serializer) - } -} -impl<'de> Deserialize<'de> for Version { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - String::deserialize(deserializer)?.parse().map_err(de::Error::custom) - } -} - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -struct Manifests { - rust_crate: Option, - template: Option, - #[serde(flatten)] - map: BTreeMap, ManifestRef>, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(untagged)] -enum ManifestRef { - Ref { version: Version }, - Real(Manifest), -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct Manifest { - #[serde(flatten)] - download_info: BTreeMap, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct ManifestDownloadInfo { - #[serde(skip_serializing_if = "Option::is_none")] - url: Option, - checksum: String, - /// Path to binaries in archive. Default to `${tool}${exe}`. - #[serde(skip_serializing_if = "Option::is_none")] - bin: Option, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct ManifestTemplate { - #[serde(flatten)] - download_info: BTreeMap, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -struct ManifestTemplateDownloadInfo { - url: String, - /// Path to binaries in archive. Default to `${tool}${exe}`. - #[serde(skip_serializing_if = "Option::is_none")] - bin: Option, -} - -#[derive(Debug, Deserialize)] -#[serde(deny_unknown_fields)] -struct BaseManifest { - /// Link to the GitHub repository. - repository: String, - /// Prefix of release tag. - tag_prefix: String, - /// Crate name, if this is Rust crate. - rust_crate: Option, - default_major_version: Option, - /// Asset name patterns. - asset_name: Option, - /// Path to binaries in archive. Default to `${tool}${exe}`. - bin: Option, - signing: Option, - #[serde(default)] - broken: Vec, - platform: BTreeMap, - version_range: Option, -} -impl BaseManifest { - fn validate(&self) { - for bin in self.bin.iter().chain(self.platform.values().flat_map(|m| &m.bin)) { - assert!(!bin.as_slice().is_empty()); - for bin in bin.as_slice() { - let file_name = Path::new(bin).file_name().unwrap().to_str().unwrap(); - if !self.repository.ends_with("/xbuild") { - assert!( - !(file_name.contains("${version") || file_name.contains("${rust")), - "{bin}" - ); + ExprNode::Op(current_op) => { + if op.is_some() && op != Some(current_op) { + panic!("SPDX too complex"); } + op = Some(current_op); } + ExprNode::Req(_) => {} } } -} - -#[derive(Debug, Deserialize)] -#[serde(deny_unknown_fields)] -struct Signing { - kind: SigningKind, -} - -#[derive(Debug, Deserialize, PartialEq, Eq)] -#[serde(rename_all = "kebab-case")] -#[serde(deny_unknown_fields)] -enum SigningKind { - /// algorithm: minisign - /// public key: package.metadata.binstall.signing.pubkey at Cargo.toml - /// - MinisignBinstall, -} - -#[derive(Debug, Deserialize)] -#[serde(deny_unknown_fields)] -struct BaseManifestPlatformInfo { - /// Asset name patterns. Default to the value at `BaseManifest::asset_name`. - asset_name: Option, - /// Path to binaries in archive. Default to the value at `BaseManifest::bin`. - bin: Option, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -enum StringOrArray { - String(String), - Array(Vec), -} -impl StringOrArray { - fn as_slice(&self) -> &[String] { - match self { - Self::String(s) => slice::from_ref(s), - Self::Array(v) => v, + match license_ids.len() { + 0 => panic!("No licenses"), + 1 => { + let (license_id, exception_id) = license_ids.first().unwrap(); + let license_name = if let Some(exception_id) = exception_id { + format!("{} WITH {}", license_id.name, exception_id.name) + } else { + license_id.name.to_string() + }; + let name = license_id.name.split('-').next().unwrap().to_ascii_uppercase(); + for filename in + ["LICENSE".to_string(), format!("LICENSE-{name}"), "LICENSE.md".to_string()] + { + let url = create_github_raw_link(repo, default_branch, &filename); + if github_head(&url).is_ok() { + let url = create_github_link(repo, default_branch, &filename); + return Some(format!("[{license_name}]({url})")); + } + } } - } - fn map(&self, mut f: impl FnMut(&String) -> String) -> Self { - match self { - Self::String(s) => Self::String(f(s)), - Self::Array(v) => Self::Array(v.iter().map(f).collect()), + len => { + let mut license_markdowns: Vec = vec![]; + for (license_id, exception_id) in &license_ids { + let name = license_id.name.split('-').next().unwrap().to_ascii_uppercase(); + let filename = format!("LICENSE-{name}"); + let url = create_github_raw_link(repo, default_branch, &filename); + let license_name = if let Some(exception_id) = exception_id { + format!("{} WITH {}", license_id.name, exception_id.name) + } else { + license_id.name.to_string() + }; + if github_head(&url).is_ok() { + let url = create_github_link(repo, default_branch, &filename); + license_markdowns.push(format!("[{license_name}]({url})")); + } + } + if license_markdowns.is_empty() { + panic!("Unable to find any license files in the repo for licenses {license_ids:?}"); + } + if license_markdowns.len() != len { + panic!("Unable to find license files in the repo for all licenses {license_ids:?}; found {license_markdowns:?}"); + } + match op { + None => panic!("op expected"), + Some(Operator::Or) => { + return Some(license_markdowns.join(" OR ")); + } + Some(Operator::And) => { + return Some(license_markdowns.join(" AND ")); + } + } } } + None } -/// GitHub Actions Runner supports Linux (x86_64, aarch64, arm), Windows (x86_64, aarch64), -/// and macOS (x86_64, aarch64). -/// https://github.com/actions/runner/blob/v2.315.0/.github/workflows/build.yml#L21 -/// https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners#supported-architectures-and-operating-systems-for-self-hosted-runners -/// -/// Note: -/// - Static-linked binaries compiled for linux-musl will also work on linux-gnu systems and are -/// usually preferred over linux-gnu binaries because they can avoid glibc version issues. -/// (rustc enables statically linking for linux-musl by default, except for mips.) -/// - Binaries compiled for x86_64 macOS will usually also work on aarch64 macOS. -/// - Binaries compiled for x86_64 Windows will usually also work on aarch64 Windows 11+. -/// - Ignore arm for now, as we need to consider the version and whether hard-float is supported. -/// https://github.com/rust-lang/rustup/pull/593 -/// https://github.com/cross-rs/cross/pull/1018 -/// Does it seem only armv7l+ is supported? -/// https://github.com/actions/runner/blob/v2.315.0/src/Misc/externals.sh#L189 -/// https://github.com/actions/runner/issues/688 -#[allow(non_camel_case_types)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)] -enum HostPlatform { - x86_64_linux_gnu, - x86_64_linux_musl, - x86_64_macos, - x86_64_windows, - aarch64_linux_gnu, - aarch64_linux_musl, - aarch64_macos, - aarch64_windows, -} +mod github { + use serde_derive::Deserialize; -impl HostPlatform { - fn rust_target(self) -> &'static str { - match self { - Self::x86_64_linux_gnu => "x86_64-unknown-linux-gnu", - Self::x86_64_linux_musl => "x86_64-unknown-linux-musl", - Self::x86_64_macos => "x86_64-apple-darwin", - Self::x86_64_windows => "x86_64-pc-windows-msvc", - Self::aarch64_linux_gnu => "aarch64-unknown-linux-gnu", - Self::aarch64_linux_musl => "aarch64-unknown-linux-musl", - Self::aarch64_macos => "aarch64-apple-darwin", - Self::aarch64_windows => "aarch64-pc-windows-msvc", - } - } - fn rust_target_arch(self) -> &'static str { - match self { - Self::aarch64_linux_gnu - | Self::aarch64_linux_musl - | Self::aarch64_macos - | Self::aarch64_windows => "aarch64", - Self::x86_64_linux_gnu - | Self::x86_64_linux_musl - | Self::x86_64_macos - | Self::x86_64_windows => "x86_64", - } - } - fn rust_target_os(self) -> &'static str { - match self { - Self::aarch64_linux_gnu - | Self::aarch64_linux_musl - | Self::x86_64_linux_gnu - | Self::x86_64_linux_musl => "linux", - Self::aarch64_macos | Self::x86_64_macos => "macos", - Self::aarch64_windows | Self::x86_64_windows => "windows", - } - } - fn exe_suffix(self) -> &'static str { - match self { - Self::x86_64_windows | Self::aarch64_windows => ".exe", - _ => "", - } + // https://api.github.com/repos/ + #[derive(Debug, Deserialize)] + pub(crate) struct RepoMetadata { + #[serde(default)] + #[allow(dead_code)] + pub(crate) homepage: Option, + #[serde(default)] + pub(crate) license: Option, + pub(crate) default_branch: String, } -} -mod github { - use serde_derive::Deserialize; + #[derive(Debug, Deserialize)] + pub(crate) struct RepoLicense { + #[serde(default)] + pub(crate) spdx_id: Option, + } // https://api.github.com/repos//releases pub(crate) type Releases = Vec; @@ -948,6 +814,8 @@ mod crates_io { #[derive(Debug, Deserialize)] pub(crate) struct Crate { pub(crate) versions: Vec, + #[serde(rename = "crate")] + pub(crate) crate_: CrateMetadata, } #[derive(Debug, Deserialize)] @@ -957,6 +825,24 @@ mod crates_io { pub(crate) num: semver::Version, pub(crate) yanked: bool, } + + #[derive(Debug, Deserialize)] + pub(crate) struct CrateMetadata { + #[allow(dead_code)] + pub(crate) homepage: Option, + pub(crate) repository: Option, + } + + // https://crates.io/api/v1/crates// + #[derive(Debug, Deserialize)] + pub(crate) struct VersionMetadata { + pub(crate) version: VersionMetadataDetail, + } + + #[derive(Debug, Deserialize)] + pub(crate) struct VersionMetadataDetail { + pub(crate) license: Option, + } } mod cargo_manifest { diff --git a/tools/codegen/src/tools-markdown.rs b/tools/codegen/src/tools-markdown.rs new file mode 100644 index 000000000..fd7fe6b39 --- /dev/null +++ b/tools/codegen/src/tools-markdown.rs @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: Apache-2.0 OR MIT + +use std::{env, fmt, io::Write, path::PathBuf}; + +use anyhow::Result; +use fs_err as fs; +use install_action_internal_codegen::{workspace_root, BaseManifest, Manifests}; + +fn main() -> Result<()> { + let args: Vec<_> = env::args().skip(1).collect(); + if !args.is_empty() || args.iter().any(|arg| arg.starts_with('-')) { + println!( + "USAGE: cargo run --manifest-path tools/codegen/Cargo.toml --bin generate-tools-markdown --release" + ); + std::process::exit(1); + } + + let workspace_root = workspace_root(); + + let mut manifest_dir = workspace_root.clone(); + manifest_dir.push("manifests"); + let mut base_info_dir = workspace_root.clone(); + base_info_dir.push("tools"); + base_info_dir.push("codegen"); + base_info_dir.push("base"); + + let mut paths: Vec<_> = + fs::read_dir(manifest_dir.clone()).unwrap().map(|r| r.unwrap()).collect(); + paths.sort_by_key(fs_err::DirEntry::path); + + let mut tools = vec![ + MarkdownEntry { + name: "nextest".to_string(), + alias: "cargo-nextest".to_string().into(), + website: "https://nexte.st/".to_string(), + installed_to: InstalledTo::Cargo, + installed_from: InstalledFrom::Binstall, + platforms: Platforms::all(), + repository: "https://github.com/nextest-rs/nextest".to_string(), + license_markdown: "[Apache-2.0](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-APACHE) OR [MIT](https://github.com/nextest-rs/nextest/blob/HEAD/LICENSE-MIT)".to_string() + }, + MarkdownEntry { + name: "valgrind".to_string(), + alias: None, + website: "https://valgrind.org/".to_string(), + installed_to: InstalledTo::Snap, + installed_from: InstalledFrom::Snap, + platforms: Platforms { + linux: true, + ..Default::default() + }, + repository: "https://sourceware.org/git/valgrind.git".to_string(), + license_markdown: "[GPL-2.0](https://sourceware.org/git/?p=valgrind.git;a=blob;f=COPYING;hb=HEAD)".to_string() + } + ]; + + for path in paths { + let file_name = path.file_name(); + let mut name = PathBuf::from(file_name.clone()); + name.set_extension(""); + let name = name.to_string_lossy().to_string(); + let base_info: BaseManifest = + serde_json::from_slice(&fs::read(base_info_dir.join(file_name.clone()))?)?; + let manifests: Manifests = + serde_json::from_slice(&fs::read(manifest_dir.join(file_name))?)?; + + let website = match base_info.website { + Some(website) => website, + None => base_info.repository.clone(), + }; + + let repository = base_info.repository; + + let installed_to = + if manifests.rust_crate.is_some() { InstalledTo::Cargo } else { InstalledTo::UsrLocal }; + + let installed_from = InstalledFrom::GitHubRelease; + let mut platforms = Platforms::default(); + + for platform in base_info.platform.keys() { + match platform.rust_target_os() { + "linux" => platforms.linux = true, + "macos" => platforms.macos = true, + "windows" => platforms.windows = true, + &_ => todo!(), + } + } + + let license_markdown = manifests.license_markdown; + + let readme_entry = MarkdownEntry { + name, + website, + repository, + installed_to, + installed_from, + platforms, + license_markdown, + alias: None, + }; + tools.push(readme_entry); + } + + tools.sort_by(|x, y| x.name.cmp(&y.name)); + + let mut markdown_file = workspace_root.clone(); + markdown_file.push("TOOLS.md"); + + let file = std::fs::File::create(markdown_file).expect("Unable to create file"); + let mut file = std::io::BufWriter::new(file); + + let header = "# Tools + +| Name | Where binaries will be installed | Where will it be installed from | Supported platform | License | +| ---- | -------------------------------- | ------------------------------- | ------------------ | ------- | +"; + + file.write_all(header.as_bytes()).expect("Unable to write header"); + + for tool in tools { + file.write_all(tool.to_string().as_bytes()).expect("Unable to write entry"); + } + + Ok(()) +} + +#[derive(Debug)] +struct MarkdownEntry { + name: String, + alias: Option, + website: String, + repository: String, + installed_to: InstalledTo, + installed_from: InstalledFrom, + platforms: Platforms, + license_markdown: String, +} + +#[derive(Debug, Eq, PartialEq)] +enum InstalledFrom { + Binstall, + GitHubRelease, + Snap, +} + +#[derive(Debug, Default, Eq, PartialEq)] +struct Platforms { + linux: bool, + macos: bool, + windows: bool, +} +impl Platforms { + fn all() -> Self { + Self { linux: true, macos: true, windows: true } + } +} + +impl fmt::Display for Platforms { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut platform_names: Vec<&str> = vec![]; + if self.linux { + platform_names.push("Linux"); + } + if self.macos { + platform_names.push("macOS"); + } + if self.windows { + platform_names.push("Windows"); + } + let name = platform_names.join(", "); + f.write_str(&name)?; + Ok(()) + } +} + +#[derive(Debug, Eq, PartialEq)] +enum InstalledTo { + Cargo, + Snap, + UsrLocal, +} + +impl fmt::Display for InstalledTo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InstalledTo::Cargo => f.write_str("`$CARGO_HOME/bin`")?, + InstalledTo::Snap => f.write_str("`/snap/bin`")?, + InstalledTo::UsrLocal => f.write_str("`/usr/local/bin`")?, + } + + Ok(()) + } +} + +impl fmt::Display for MarkdownEntry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let name = format!("| [**{}**]({}) ", self.name, self.website); + f.write_str(&name)?; + + if let Some(alias) = self.alias.clone() { + let alias = format!("(alias: `{alias}`)"); + f.write_str(&alias)?; + } + + f.write_str(&format!("| {} ", self.installed_to))?; + + match self.installed_from { + InstalledFrom::GitHubRelease => { + let markdown = format!("| [GitHub Releases]({}/releases) ", self.repository); + f.write_str(&markdown)?; + } + InstalledFrom::Binstall => f.write_str("| `cargo-binstall` ")?, + InstalledFrom::Snap => { + let markdown = + format!("| [snap](https://snapcraft.io/install/{}/ubuntu) ", self.name); + f.write_str(&markdown)?; + } + } + + f.write_str(&format!("| {} ", self.platforms))?; + f.write_str(&format!("| {} |\n", self.license_markdown))?; + Ok(()) + } +} diff --git a/tools/update-markdown.sh b/tools/update-markdown.sh new file mode 100755 index 000000000..1f5392e31 --- /dev/null +++ b/tools/update-markdown.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 OR MIT +set -eEuo pipefail +IFS=$'\n\t' +cd "$(dirname "$0")"/.. + +# Update markdown +# +# USAGE: +# ./tools/update-markdown.sh + +cargo run --manifest-path tools/codegen/Cargo.toml --bin generate-tools-markdown --release