| 1 | #!/usr/bin/env bash |
| 2 | set -euo pipefail |
| 3 | |
| 4 | MODE="${1:-}" |
| 5 | |
| 6 | if [[ "$MODE" != "style-clippy" && "$MODE" != "test" ]]; then |
| 7 | echo "Usage: $0 {style-clippy|test}" >&2 |
| 8 | exit 2 |
| 9 | fi |
| 10 | |
| 11 | if ROOT_DIR="$(git rev-parse --show-toplevel 2>/dev/null)"; then |
| 12 | : |
| 13 | else |
| 14 | SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" |
| 15 | ROOT_DIR="$(cd -- "${SCRIPT_DIR}/../.." && pwd -P)" |
| 16 | fi |
| 17 | cd "$ROOT_DIR" |
| 18 | |
| 19 | export CARGO_TERM_COLOR="${CARGO_TERM_COLOR:-always}" |
| 20 | export CARGO_HOME="${CARGO_HOME:-$HOME/.cargo}" |
| 21 | export RUSTUP_HOME="${RUSTUP_HOME:-$HOME/.rustup}" |
| 22 | export PATH="$CARGO_HOME/bin:$PATH" |
| 23 | |
| 24 | CARGO_BINSTALL_VERSION="${CARGO_BINSTALL_VERSION:-1.20.1}" |
| 25 | UV_VERSION="${UV_VERSION:-0.11.28}" |
| 26 | PYO3_PYTHON_VERSION="${PYO3_PYTHON_VERSION:-3.12}" |
| 27 | |
| 28 | CARGO_SORT_VERSION_REQ="${CARGO_SORT_VERSION_REQ:-2}" |
| 29 | CARGO_DENY_VERSION_REQ="${CARGO_DENY_VERSION_REQ:-0.20}" |
| 30 | CARGO_NEXTEST_VERSION_REQ="${CARGO_NEXTEST_VERSION_REQ:-0.9}" |
| 31 | |
| 32 | log_section() { |
| 33 | echo "--- $*" |
| 34 | } |
| 35 | |
| 36 | rust_toolchain() { |
| 37 | awk -F '"' '/channel[[:space:]]*=/ { print $2; exit }' rust-toolchain.toml |
| 38 | } |
| 39 | |
| 40 | install_rust_toolchain() { |
| 41 | log_section "Installing Rust toolchain" |
| 42 | if ! command -v rustup >/dev/null 2>&1; then |
| 43 | curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \ |
| 44 | | sh -s -- -y --profile minimal --default-toolchain none |
| 45 | fi |
| 46 | |
| 47 | local toolchain |
| 48 | toolchain="$(rust_toolchain)" |
| 49 | rustup toolchain install "$toolchain" --profile minimal --component rustfmt,clippy |
| 50 | rustup component add --toolchain "$toolchain" rustfmt clippy |
| 51 | } |
| 52 | |
| 53 | install_cargo_binstall() { |
| 54 | log_section "Installing cargo-binstall ${CARGO_BINSTALL_VERSION}" |
| 55 | curl -L --proto '=https' --tlsv1.2 -sSf \ |
| 56 | "https://raw.githubusercontent.com/cargo-bins/cargo-binstall/v${CARGO_BINSTALL_VERSION}/install-from-binstall-release.sh" \ |
| 57 | | env BINSTALL_VERSION="$CARGO_BINSTALL_VERSION" bash |
| 58 | cargo-binstall -V |
| 59 | } |
| 60 | |
| 61 | install_cargo_sort() { |
| 62 | log_section "Installing cargo-sort ${CARGO_SORT_VERSION_REQ}" |
| 63 | cargo binstall --no-confirm --force "cargo-sort@${CARGO_SORT_VERSION_REQ}" |
| 64 | } |
| 65 | |
| 66 | install_cargo_deny() { |
| 67 | log_section "Installing cargo-deny ${CARGO_DENY_VERSION_REQ}" |
| 68 | cargo binstall --no-confirm --force "cargo-deny@${CARGO_DENY_VERSION_REQ}" |
| 69 | } |
| 70 | |
| 71 | install_cargo_nextest() { |
| 72 | log_section "Installing cargo-nextest ${CARGO_NEXTEST_VERSION_REQ}" |
| 73 | cargo binstall \ |
| 74 | --no-confirm \ |
| 75 | --force \ |
| 76 | --secure \ |
| 77 | "cargo-nextest@${CARGO_NEXTEST_VERSION_REQ}" |
| 78 | } |
| 79 | |
| 80 | install_uv() { |
| 81 | log_section "Installing uv ${UV_VERSION}" |
| 82 | curl -L --proto '=https' --tlsv1.2 -sSf \ |
| 83 | "https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/uv-installer.sh" \ |
| 84 | | env UV_INSTALL_DIR="$CARGO_HOME/bin" sh |
| 85 | uv --version |
| 86 | } |
| 87 | |
| 88 | setup_pyo3_python() { |
| 89 | log_section "Installing Python ${PYO3_PYTHON_VERSION} for PyO3 tests" |
| 90 | uv python install "$PYO3_PYTHON_VERSION" |
| 91 | PYO3_PYTHON="$(uv python find \ |
| 92 | --managed-python \ |
| 93 | --no-project \ |
| 94 | --resolve-links \ |
| 95 | "$PYO3_PYTHON_VERSION")" |
| 96 | export PYO3_PYTHON |
| 97 | |
| 98 | local python_libdir |
| 99 | python_libdir="$("$PYO3_PYTHON" - <<'PY' |
| 100 | import pathlib |
| 101 | import sysconfig |
| 102 | |
| 103 | libdir = pathlib.Path(sysconfig.get_config_var("LIBDIR")) |
| 104 | ldlibrary = sysconfig.get_config_var("LDLIBRARY") |
| 105 | assert sysconfig.get_config_var("Py_ENABLE_SHARED") == 1 |
| 106 | assert ldlibrary |
| 107 | assert (libdir / ldlibrary).exists(), libdir / ldlibrary |
| 108 | print(libdir) |
| 109 | PY |
| 110 | )" |
| 111 | |
| 112 | export LD_LIBRARY_PATH="${python_libdir}:${LD_LIBRARY_PATH:-}" |
| 113 | export LIBRARY_PATH="${python_libdir}:${LIBRARY_PATH:-}" |
| 114 | } |
| 115 | |
| 116 | run_style_clippy() { |
| 117 | install_cargo_binstall |
| 118 | install_cargo_sort |
| 119 | install_cargo_deny |
| 120 | |
| 121 | log_section "Checking Rust formatting" |
| 122 | cargo fmt --manifest-path rust/Cargo.toml --all -- --check |
| 123 | |
| 124 | log_section "Checking Cargo.toml ordering" |
| 125 | cargo sort --workspace --check rust |
| 126 | |
| 127 | log_section "Checking Rust dependency bans" |
| 128 | cargo deny \ |
| 129 | --manifest-path rust/Cargo.toml \ |
| 130 | --config rust/deny.toml \ |
| 131 | check \ |
| 132 | bans |
| 133 | |
| 134 | log_section "Running clippy" |
| 135 | cargo clippy \ |
| 136 | --manifest-path rust/Cargo.toml \ |
| 137 | --workspace \ |
| 138 | --all-targets \ |
| 139 | --all-features \ |
| 140 | --locked \ |
| 141 | -- \ |
| 142 | -D warnings |
| 143 | } |
| 144 | |
| 145 | run_tests() { |
| 146 | install_uv |
| 147 | setup_pyo3_python |
| 148 | install_cargo_binstall |
| 149 | install_cargo_nextest |
| 150 | |
| 151 | log_section "Running cargo nextest" |
| 152 | cargo nextest run \ |
| 153 | --manifest-path rust/Cargo.toml \ |
| 154 | --workspace \ |
| 155 | --all-features \ |
| 156 | --locked \ |
| 157 | --no-fail-fast |
| 158 | } |
| 159 | |
| 160 | install_rust_toolchain |
| 161 | |
| 162 | case "$MODE" in |
| 163 | style-clippy) |
| 164 | run_style_clippy |
| 165 | ;; |
| 166 | test) |
| 167 | run_tests |
| 168 | ;; |
| 169 | esac |