Make gate scripts handle table-form dependencies and fail closed
Implemented-By: Laguna S 2.1 (OpenCode)
This commit is contained in:
Regular → Executable
+64
-33
@@ -1,11 +1,27 @@
|
||||
#!/bin/sh
|
||||
# Fails if a key in [workspace.dependencies] of ROOT/Cargo.toml that is not a
|
||||
# workspace crate has no table row starting `| `name` |` in ROOT/docs/dependencies.md.
|
||||
# Also fails if any dependency line in any ROOT/crates/*/Cargo.toml lacks
|
||||
# `workspace = true`.
|
||||
# Fails if a workspace dependency declared in ROOT/Cargo.toml has no table row in
|
||||
# ROOT/docs/dependencies.md, or if any dependency in a crate manifest lacks
|
||||
# `workspace = true` (on its own line for the plain/dotted form, or as a
|
||||
# `workspace = true` line inside a table-form dependency). A table header such as
|
||||
# `[dependencies.x]` introduces dependency x; the lines that follow it until the
|
||||
# next section header are settings of x, never dependencies themselves.
|
||||
ROOT="${1:-.}"
|
||||
status=0
|
||||
|
||||
# Fail closed.
|
||||
if [ ! -d "$ROOT/crates" ]; then
|
||||
echo "check-dep-docs: $ROOT/crates is not a directory" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$ROOT/Cargo.toml" ]; then
|
||||
echo "check-dep-docs: $ROOT/Cargo.toml is not a file" >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -f "$ROOT/docs/dependencies.md" ]; then
|
||||
echo "check-dep-docs: $ROOT/docs/dependencies.md is not a file" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Workspace crate names: directories under ROOT/crates that contain a Cargo.toml.
|
||||
workspace=""
|
||||
for d in "$ROOT"/crates/*/; do
|
||||
@@ -17,26 +33,31 @@ done
|
||||
root_toml="$ROOT/Cargo.toml"
|
||||
docs="$ROOT/docs/dependencies.md"
|
||||
|
||||
# Extract dependency keys from every [dependencies*]-ish section.
|
||||
# Part 1: non-workspace-crate workspace dependencies in ROOT/Cargo.toml must have a docs row.
|
||||
dep_keys=$(awk '
|
||||
BEGIN { in_deps = 0; depth = 0 }
|
||||
/^\[/ {
|
||||
sec = $0
|
||||
sub(/^\[[ \t]*/, "", sec)
|
||||
sub(/[ \t]*\][ \t]*.*$/, "", sec)
|
||||
in_deps = (sec ~ /dependencies/)
|
||||
BEGIN { in_deps = 0; in_table = 0; depth = 0 }
|
||||
/^[ \t]*\[/ {
|
||||
hdr = $0
|
||||
sub(/^[ \t]*\[/, "", hdr)
|
||||
sub(/[ \t]*\][ \t]*.*$/, "", hdr)
|
||||
if (hdr ~ /dependencies/) {
|
||||
n = split(hdr, parts, ".")
|
||||
if (parts[n] ~ /dependencies$/) { in_deps = 1; in_table = 0 }
|
||||
else { in_deps = 1; in_table = 1; print parts[n] }
|
||||
} else { in_deps = 0; in_table = 0 }
|
||||
depth = 0
|
||||
next
|
||||
}
|
||||
in_table { next }
|
||||
in_deps {
|
||||
if (depth == 0) {
|
||||
t = $0
|
||||
sub(/^[ \t]+/, "", t)
|
||||
if (t ~ /^[A-Za-z0-9][A-Za-z0-9_-]*(\.workspace)?[ \t]*=/) {
|
||||
if (match(t, /[A-Za-z0-9][A-Za-z0-9_-]*/)) {
|
||||
k = substr(t, RSTART, RLENGTH)
|
||||
if (RSTART == 1) print k
|
||||
}
|
||||
if (match(t, /^[A-Za-z0-9][A-Za-z0-9_-]*(\.[A-Za-z0-9_-]+)*[ \t]*=/)) {
|
||||
name = t
|
||||
sub(/[ \t]*=.*/, "", name)
|
||||
sub(/\..*/, "", name)
|
||||
print name
|
||||
}
|
||||
}
|
||||
s = $0
|
||||
@@ -47,43 +68,53 @@ dep_keys=$(awk '
|
||||
s = substr(s, RSTART + 1)
|
||||
}
|
||||
}
|
||||
' "$root_toml" 2>/dev/null)
|
||||
' "$root_toml")
|
||||
|
||||
# Part 1: non-workspace-crate workspace dependencies must have a docs table row.
|
||||
for key in $dep_keys; do
|
||||
hit=0
|
||||
for w in $workspace; do
|
||||
if [ "$key" = "$w" ]; then hit=1; break; fi
|
||||
done
|
||||
if [ "$hit" -eq 0 ]; then
|
||||
if ! awk -v k="$key" 'index($0, "| `" k "` |") == 1 { found = 1; exit } END { exit !found }' "$docs" 2>/dev/null; then
|
||||
if ! awk -v k="$key" 'index($0, "| `" k "` |") == 1 { found = 1; exit } END { exit !found }' "$docs"; then
|
||||
echo "check-dep-docs: $key has no row in $docs" >&2
|
||||
status=1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Part 2: every dependency line in a crate manifest must contain `workspace = true`.
|
||||
# Part 2: every dependency in a crate manifest must have `workspace = true`.
|
||||
for crate in "$ROOT"/crates/*/; do
|
||||
[ -d "$crate" ] || continue
|
||||
crate_name=$(basename "$crate")
|
||||
[ -f "$crate/Cargo.toml" ] || continue
|
||||
bad=$(awk '
|
||||
BEGIN { in_deps = 0; depth = 0 }
|
||||
/^\[/ {
|
||||
sec = $0
|
||||
sub(/^\[[ \t]*/, "", sec)
|
||||
sub(/[ \t]*\][ \t]*.*$/, "", sec)
|
||||
in_deps = (sec ~ /dependencies/)
|
||||
bad=$(awk -v cn="$crate_name" '
|
||||
BEGIN { in_deps = 0; in_table = 0; cur = ""; has_ws = 0; depth = 0 }
|
||||
/^[ \t]*\[/ {
|
||||
if (in_table && !has_ws) printf "check-dep-docs: %s table-form dependency %s has no `workspace = true` line\n", cn, cur
|
||||
in_table = 0
|
||||
hdr = $0
|
||||
sub(/^[ \t]*\[/, "", hdr)
|
||||
sub(/[ \t]*\][ \t]*.*$/, "", hdr)
|
||||
if (hdr ~ /dependencies/) {
|
||||
n = split(hdr, parts, ".")
|
||||
if (parts[n] ~ /dependencies$/) { in_deps = 1 }
|
||||
else { in_deps = 1; in_table = 1; cur = parts[n]; has_ws = 0 }
|
||||
} else { in_deps = 0 }
|
||||
depth = 0
|
||||
next
|
||||
}
|
||||
in_table {
|
||||
if ($0 ~ /workspace[ \t]*=[ \t]*true/) has_ws = 1
|
||||
next
|
||||
}
|
||||
in_deps {
|
||||
if (depth == 0) {
|
||||
t = $0
|
||||
sub(/^[ \t]+/, "", t)
|
||||
if (t ~ /^[A-Za-z0-9][A-Za-z0-9_-]*(\.workspace)?[ \t]*=/) {
|
||||
print $0
|
||||
if (match(t, /^[A-Za-z0-9][A-Za-z0-9_-]*(\.[A-Za-z0-9_-]+)*[ \t]*=/)) {
|
||||
if ($0 !~ /workspace[ \t]*=[ \t]*true/)
|
||||
printf "check-dep-docs: %s declares a dependency without `workspace = true`: %s\n", cn, $0
|
||||
}
|
||||
}
|
||||
s = $0
|
||||
@@ -94,12 +125,12 @@ for crate in "$ROOT"/crates/*/; do
|
||||
s = substr(s, RSTART + 1)
|
||||
}
|
||||
}
|
||||
' "$crate/Cargo.toml" 2>/dev/null | grep -v 'workspace = true')
|
||||
END { if (in_table && !has_ws) printf "check-dep-docs: %s table-form dependency %s has no `workspace = true` line\n", cn, cur }
|
||||
' "$crate/Cargo.toml")
|
||||
if [ -n "$bad" ]; then
|
||||
echo "$bad" | while read -r line; do
|
||||
[ -n "$line" ] && echo "check-dep-docs: $crate_name declares a dependency without workspace = true: $line" >&2
|
||||
done
|
||||
printf '%s\n' "$bad" >&2
|
||||
status=1
|
||||
fi
|
||||
done
|
||||
|
||||
exit $status
|
||||
|
||||
Reference in New Issue
Block a user