86 lines
3.0 KiB
Bash
Executable File
86 lines
3.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Checks the layer dependency rule stated in README.md.
|
|
#
|
|
# The workspace is organized into dependency ordered layers:
|
|
#
|
|
# foundation -> physics -> orbit -> rf -> network -> ops -> sim
|
|
#
|
|
# A crate may depend on any crate in a layer to its left, but never on one to
|
|
# its right. This script reads every workspace manifest, works out which
|
|
# layer each dependency belongs to, and fails if any dependency points to the
|
|
# right.
|
|
#
|
|
# `apsis-core` and `apsis-math` are exempt as global prerequisites: they sit
|
|
# in `foundation` and every layer may use them, which the left-only rule
|
|
# already permits, so no special case is needed for them.
|
|
#
|
|
# Usage:
|
|
#
|
|
# scripts/check-layers.sh
|
|
#
|
|
# Exit status is zero when the rule holds and one otherwise.
|
|
|
|
set -euo pipefail
|
|
|
|
# The layer order, left to right. A dependency to a layer with a lower index
|
|
# is allowed; to a higher index is a reverse dependency and fails.
|
|
LAYERS=(foundation physics orbit rf network ops sim)
|
|
|
|
# The root of the workspace, taken from this script's location so that the
|
|
# check works from any working directory.
|
|
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
cd "$root"
|
|
|
|
# Returns the index of a layer name, or an empty string when the name is not
|
|
# a layer. A crate outside these directories is not part of the layer scheme
|
|
# and is skipped rather than reported.
|
|
layer_index() {
|
|
local name="$1"
|
|
local index=0
|
|
for layer in "${LAYERS[@]}"; do
|
|
if [ "$layer" = "$name" ]; then
|
|
echo "$index"
|
|
return 0
|
|
fi
|
|
index=$((index + 1))
|
|
done
|
|
echo ""
|
|
}
|
|
|
|
failures=0
|
|
checked=0
|
|
|
|
for manifest in $(find crates -name Cargo.toml | sort); do
|
|
directory="$(dirname "$manifest")"
|
|
# The layer directory is the second path component, as in
|
|
# `crates/<layer>/<crate>/Cargo.toml`.
|
|
layer="$(echo "$directory" | cut -d/ -f2)"
|
|
source_index="$(layer_index "$layer")"
|
|
[ -z "$source_index" ] && continue
|
|
|
|
# Every `apsis-...` name in the manifest is a dependency or a package
|
|
# name. The package name is the crate itself, which resolves to the same
|
|
# layer and is skipped by the index comparison below.
|
|
for dependency in $(grep -oE 'apsis-[a-z-]+' "$manifest" | sort -u); do
|
|
dependency_directory="$(find crates -maxdepth 2 -type d -name "$dependency" 2>/dev/null | head -1)"
|
|
[ -z "$dependency_directory" ] && continue
|
|
dependency_layer="$(echo "$dependency_directory" | cut -d/ -f2)"
|
|
dependency_index="$(layer_index "$dependency_layer")"
|
|
[ -z "$dependency_index" ] && continue
|
|
|
|
if [ "$dependency_index" -gt "$source_index" ]; then
|
|
echo "reverse dependency: $layer -> $dependency_layer ($(basename "$directory") -> $dependency)" >&2
|
|
failures=$((failures + 1))
|
|
fi
|
|
checked=$((checked + 1))
|
|
done
|
|
done
|
|
|
|
if [ "$failures" -gt 0 ]; then
|
|
echo "layer check failed: $failures reverse dependency(ies)" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "layer check passed: $checked dependency edge(s), none reversed"
|