Something went wrong. Try again.
Data management tools for playing BattleTech
Something went wrong. Try again.
Shell
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138#!/usr/bin/env bash# Hold the crate graph to the shape the rules depend on.## ./scripts/check-boundaries.sh## Two boundaries, both of which erode silently if nothing checks them.## The rules have to run in a browser. Battle value and construction validation# are wanted in two places - in the page while somebody edits a design, and# again on the server that believes the answer - so the crates they are written# against cannot acquire a filesystem, a database or a network. A `use` added# in a hurry is all it takes, and the failure shows up much later as "why can# this not compile to wasm".## The database must not learn to compute. helm-db takes ComputedStats and is# not allowed to know who produced them, so that swapping the Java bridge for a# native implementation is a change in helm-cli and nowhere else.set -euo pipefail
cd "$(dirname "${BASH_SOURCE[0]}")/.."
FAIL=0note() { printf ' %s\n' "$1"; }fail() { printf 'FAIL: %s\n' "$1" >&2; FAIL=1; }
# Crates that must reach wasm, and so must stay clear of these.## serde_json is on the list for the rules crates but not because it cannot run# in a browser - it compiles to wasm perfectly well. It is forbidden there# because the rules are written against MegaMek's own formats with hand-written# parsers, and a JSON dependency appearing in one of them means a rule has# started reading somebody's serialisation instead.## helm-query carries serde derives and is still on this list: it describes# helm's own wire shape, which is the one thing in the graph that is allowed to# know it will be serialised. It has no serde_json, because decoding a document# is the job of whoever is holding one.WASM_CRATES=(helm-core helm-facet helm-query helm-force helm-bv helm-cost)FORBIDDEN=(rusqlite zip serde_json libsqlite3-sys)
# The boundary crate is the exception: decoding what JavaScript hands over is# the whole of its job. It still may not touch a file or a database.BOUNDARY_CRATES=(helm-wasm)BOUNDARY_FORBIDDEN=(rusqlite zip libsqlite3-sys)
# Crates that must not depend on a producer of ComputedStats.CONSUMER_CRATES=(helm-db)PRODUCERS=(helm-bridge helm-bv helm-cost)
echo "checking wasm-bound crates carry no I/O dependency"for crate in "${WASM_CRATES[@]}"; do if ! cargo metadata --format-version 1 --no-deps 2>/dev/null | grep -q "\"$crate\""; then note "$crate: not in the workspace yet, skipped" continue fi tree="$(cargo tree -p "$crate" --edges normal 2>/dev/null || true)" for dep in "${FORBIDDEN[@]}"; do if grep -qE "^[^a-z]*\b$dep v" <<<"$tree"; then fail "$crate depends on $dep, which cannot go in a browser." note "It belongs in a crate that depends on $crate, not in $crate." fi done note "$crate: clean"done
for crate in "${BOUNDARY_CRATES[@]}"; do if ! cargo metadata --format-version 1 --no-deps 2>/dev/null | grep -q "\"$crate\""; then note "$crate: not in the workspace yet, skipped" continue fi tree="$(cargo tree -p "$crate" --edges normal 2>/dev/null || true)" for dep in "${BOUNDARY_FORBIDDEN[@]}"; do if grep -qE "^[^a-z]*\b$dep v" <<<"$tree"; then fail "$crate depends on $dep, which cannot go in a browser." fi done note "$crate: clean"done
echo "checking the database layer cannot compute"for crate in "${CONSUMER_CRATES[@]}"; do tree="$(cargo tree -p "$crate" --edges normal 2>/dev/null || true)" for dep in "${PRODUCERS[@]}"; do if grep -qE "^[^a-z]*\b$dep v" <<<"$tree"; then fail "$crate depends on $dep." note "Computed values reach $crate as helm_core::ComputedStats. Choosing" note "who produces them is helm-cli's job, so that retiring a producer is" note "a change in one crate." fi done note "$crate: clean"done
echo "checking the parsers build without their I/O feature"if cargo check -q -p helm-unitfile --no-default-features 2>/dev/null; then note "helm-unitfile --no-default-features: ok"else fail "helm-unitfile does not build without its 'library' feature." note "Parsing one design must not require the zip reader."fi
echo "checking the wasm target"if rustup target list --installed 2>/dev/null | grep -q wasm32-unknown-unknown; then for crate in "${WASM_CRATES[@]}"; do if cargo check -q -p "$crate" --target wasm32-unknown-unknown 2>/dev/null; then note "$crate: builds for wasm32-unknown-unknown" else fail "$crate does not build for wasm32-unknown-unknown." fi done for crate in "${BOUNDARY_CRATES[@]}"; do if cargo check -q -p "$crate" --target wasm32-unknown-unknown 2>/dev/null; then note "$crate: builds for wasm32-unknown-unknown" else fail "$crate does not build for wasm32-unknown-unknown." fi done if cargo check -q -p helm-unitfile --no-default-features \ --target wasm32-unknown-unknown 2>/dev/null; then note "helm-unitfile (no default features): builds for wasm32-unknown-unknown" else fail "helm-unitfile does not build for wasm32 without its 'library' feature." fielse # Not installed, and installing a target is not this script's decision to # make. The dependency checks above are the ones that catch the mistake # early anyway; this one only confirms it. note "wasm32-unknown-unknown is not installed, so the build check is skipped." note "Enable it with: rustup target add wasm32-unknown-unknown"fi
if [ "$FAIL" -ne 0 ]; then echo echo "crate boundaries are broken; see above." >&2 exit 1fiecho "crate boundaries hold."