Files
komorebi/tools/test-partition
T

124 lines
4.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# Which packages of the workspace are tested where: see tools/README.md and docs/dev/build-and-test.md.
#
# tools/test-partition check fail when the classification and the workspace disagree
# tools/test-partition packages <class> print `-p a -p b` for cargo
# tools/test-partition expr <class> print a nextest filterset: `package(a) | package(b)`
# tools/test-partition expr recorder-macos
# the filterset of the recorder tests that run on macOS
# tools/test-partition --self-test run `check` against the tree and against deliberately broken copies
#
# The classification is tools/test-partition.json (class -> package names); it is the single source of truth
# for the CI jobs, the justfile and the Nix check sets (nix/windows). It needs only bash, cargo and jq.
#
# Environment (for the self-test): TEST_PARTITION_JSON overrides the classification file, and
# TEST_PARTITION_METADATA is a file with the output of `cargo metadata --format-version 1 --no-deps`.
set -euo pipefail
root=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
json=${TEST_PARTITION_JSON:-$root/tools/test-partition.json}
classes="neutral os_sensitive windows linux macos mixed tool none"
# the crates a `neutral` package must not depend on, directly
platform_crates='["komorebi-windows","komorebi-macos","komorebi-linux"]'
# the tests of the recorder that run on macOS, by their module path: the macOS flavoured sources, which
# the recorder's other tests (the platform-neutral ones) share a binary with
recorder_macos_filter='package(komorebi-recorder) & test(/^(sources::oslog|av|capture::sck|platform|power|system_state)::/)'
die() {
echo "test-partition: $*" >&2
exit 1
}
metadata() {
if [ -n "${TEST_PARTITION_METADATA:-}" ]; then
cat "$TEST_PARTITION_METADATA"
else
(cd "$root" && cargo metadata --format-version 1 --no-deps)
fi
}
valid_class() {
case " $classes " in
*" $1 "*) return 0 ;;
*) return 1 ;;
esac
}
check() {
local meta problems
meta=$(metadata)
problems=$(
jq -r --argjson platform "$platform_crates" --slurpfile part "$json" --arg classes "$classes" '
($part[0]) as $p
| [ .packages[] ] as $pkgs
| ($classes | split(" ")) as $known
| (
# classes the file has that are not part of the contract
($p | keys[] | select(. as $k | $known | index($k) | not)
| "unknown class \(.)"),
# a member in no class, or in two
($pkgs[].name as $n
| [ $known[] as $c | select(($p[$c] // []) | index($n)) | $c ] as $in
| if ($in | length) == 0 then "\($n): in no class"
elif ($in | length) > 1 then "\($n): in two classes (\($in | join(", ")))"
else empty end),
# a name that is no member (stale), or listed twice in one class
($known[] as $c | ($p[$c] // [])[] as $n
| select(($pkgs | map(.name) | index($n)) == null)
| "\($n) (\($c)): not a member of the workspace"),
($known[] as $c | ($p[$c] // []) | group_by(.)[] | select(length > 1)
| "\(.[0]): listed twice in \($c)"),
# a neutral package that is not neutral
($pkgs[] | select(.name as $n | ($p.neutral // []) | index($n))
| .name as $n
| (.dependencies[]
| select(.target != null)
| "\($n): neutral, but depends on \(.name) only for \(.target)"),
(.dependencies[] | select(.name as $d | $platform | index($d))
| "\($n): neutral, but depends on the platform crate \(.name)")
)
)
' <<<"$meta"
)
if [ -n "$problems" ]; then
echo "$problems" >&2
echo "test-partition: tools/test-partition.json does not match the workspace" >&2
return 1
fi
}
members_of() {
jq -r --arg c "$1" '.[$c] // [] | .[]' "$json"
}
cmd=${1:-}
case "$cmd" in
check)
check
;;
packages)
class=${2:-}
valid_class "$class" || die "unknown class '$class' (one of: $classes)"
members_of "$class" | sed 's/^/-p /' | paste -sd' ' -
;;
expr)
class=${2:-}
if [ "$class" = recorder-macos ]; then
echo "$recorder_macos_filter"
exit 0
fi
valid_class "$class" || die "unknown class '$class' (one of: $classes)"
members_of "$class" | sed 's/.*/package(&)/' | paste -sd'|' - | sed 's/|/ | /g'
;;
--self-test)
exec "$root/tools/test-partition.test" "$root/tools/test-partition"
;;
*)
sed -n '2,9p' "$0" | sed 's/^# \{0,1\}//' >&2
exit 2
;;
esac