scripts, build, just: POSIX Compliance

Enforce POSIX shell syntax with ShellCheck using `--shell sh`.
This commit is contained in:
Lorenz Leutgeb
2026-10-30 12:45:40 +01:00
parent 9e80d2d4b9
commit c7d71df4ab
26 changed files with 94 additions and 92 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
main() {
+1 -1
View File
@@ -1,2 +1,2 @@
#!/bin/sh
#! /usr/bin/env sh
find build/artifacts -type f -name '*.sha256' -exec cat {} +
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
if [ $# -ne 1 ]; then
+1 -1
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -euo pipefail
if ! version=$(grep -m 1 -oP '^\s*channel\s*=\s*"?\K([\d\.]+)' rust-toolchain.toml)
+1 -1
View File
@@ -1,4 +1,4 @@
#! /bin/sh
#! /usr/bin/env sh
set -e
if [ $# -ne 1 ]; then
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
SSH_LOGIN=${SSH_LOGIN:-release}
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
if ! version="$(git describe --match='releases/*' --candidates=1 2>/dev/null)"; then
echo "fatal: no version tag found by 'git describe'" >&2 ; exit 1
+4 -1
View File
@@ -294,7 +294,10 @@
clippy = rustup.toolchain;
};
};
shellcheck.enable = true;
shellcheck = {
enable = true;
args = ["--shell" "sh" "--exclude" "SC3040"];
};
}
// grep.hooks;
};
+1 -1
View File
@@ -90,7 +90,7 @@ check-spelling: (verify-tool "codespell")
[parallel]
check-scripts: (verify-tool "shellcheck")
@echo "{{CHECK}}Checking shell scripts…{{NORMAL}}"
@find . -type f -name "*.sh" -exec shellcheck {} +
@find . -type f -name "*.sh" -exec shellcheck --shell sh --exclude SC3040 {} +
# Run checks for forbidden keywords
[group('pre-commit')]
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
DIRECTORY="$(rad path)/storage"
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
render_commit_footnotes() {
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
DB="$(rad path)/node/node.db"
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
unset SSH_AUTH_SOCK
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
# Delete all remote branches that don't have a local copy.
remote="rad"
+15 -15
View File
@@ -1,35 +1,35 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -euo pipefail
readonly HOOK="${HOOK:-$(basename "$0")}"
if ! [[ "$HOOK" =~ ^(pre-(commit|push)|post-checkout|commit-msg)$ ]]
then
echo "Unknown hook '${HOOK}'."
exit 1
fi
case "$HOOK" in
pre-commit|pre-push|post-checkout|commit-msg) ;;
*)
echo "Unknown hook '${HOOK}'."
exit 1
;;
esac
readonly SENSITIVE_FILES=("justfile" "build.rs" "rust-toolchain.toml")
readonly BASE_BRANCH="main"
# Check which files were modified compared to the base branch.
mapfile -t CHANGED_FILES < <(comm -12 \
<(git diff --name-only "${BASE_BRANCH}" | sort) \
<(IFS=$'\n'; echo "${SENSITIVE_FILES[*]}" | sort) \
)
# Check which sensitive files were modified compared to the base branch.
CHANGED_FILES=$(git diff --name-only "$BASE_BRANCH" -- \
justfile build.rs rust-toolchain.toml)
if [ ${#CHANGED_FILES[@]} -gt 0 ]
if [ -n "$CHANGED_FILES" ]
then
echo "⚠️ WARNING: Sensitive files have been modified relative to $BASE_BRANCH."
echo "Executing this hook may run arbitrary code from the modified files."
echo ""
git --no-pager diff "$BASE_BRANCH" -- "${SENSITIVE_FILES[@]}"
git --no-pager diff "$BASE_BRANCH" -- justfile build.rs rust-toolchain.toml
# Read from /dev/tty because stdin is not attached to the terminal in Git hooks.
exec < /dev/tty
read -r -p "⚠️ Do you want to continue executing the '${HOOK}' hook? [y/N] " response
printf "⚠️ Do you want to continue executing the '%s' hook? [y/N] " "$HOOK"
read -r response
case "$response" in
[yY][eE][sS]|[yY])
echo "Continuing with '${HOOK}' hook…"
+15 -28
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#! /usr/bin/env sh
#
# Import a GitHub issue into Radicle.
#
@@ -16,25 +16,8 @@ if ! command -v rad > /dev/null; then
echo "Error: rad is not installed" ; exit 1
fi
if ! command -v pcregrep > /dev/null; then
echo "Error: pcregrep is not installed" ; exit 1
fi
if ! command -v sed > /dev/null; then
echo "Error: sed is not installed" ; exit 1
fi
function removeImgTags {
local html
html="$(cat)"
local imgTags
imgTags="$(echo "$html" | pcregrep -M '<img [^>]*>')"
# shellcheck disable=SC2066
for imgTag in "$imgTags"; do
html="$(echo "$html" | sed -z "s@$imgTag@@")"
done
echo "$html"
removeImgTags() {
jq -Rrs 'gsub("<img [^>]*>"; "")'
}
# Check if the correct number of arguments is provided
@@ -53,13 +36,17 @@ url="https://api.github.com/repos/${owner}/${repo}/issues/${issue}"
response="$(curl -s "$url")"
# Extract the title and body from the JSON response
title="$(echo "$response" | jq -r '.title')"
body="$(echo "$response" | jq -r '.body' | removeImgTags)"
labels="$(echo "$response" | jq -r '.labels | .[].name')"
title="$(printf '%s\n' "$response" | jq -r '.title')"
body="$(printf '%s\n' "$response" | jq -r '.body' | removeImgTags)"
labels="$(printf '%s\n' "$response" | jq -r '.labels | .[].name')"
tags=()
for label in $labels; do
tags+=("--label" "$label")
done
set --
while IFS= read -r label; do
if [ -n "$label" ]; then
set -- "$@" --label "$label"
fi
done <<EOF
$labels
EOF
rad issue open --title "$title" "${tags[@]}" --description "$body" --no-announce
rad issue open --title "$title" "$@" --description "$body" --no-announce
+23 -17
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -euo pipefail
# Replace '...' with '…' (U+2026) in markdown, just and Rust files, but ignore:
@@ -6,22 +6,28 @@ set -euo pipefail
# - Git ranges with ref paths, e.g. feature/1...rad/patches/f2de534
# - Standalone '...' lines used as output wildcards in CLI example tests
# - Wildcards for CLI example tests, i.e. [...]
patterns=('*.md' '*.rs' '*justfile')
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' 0
trap 'exit 1' HUP INT TERM
# Get all regular files (exclude symlinks, directories, etc.)
files=()
while IFS= read -r -d '' file; do
if [ -f "$file" ] && [ ! -L "$file" ]; then
files+=("$file")
fi
done < <(git ls-files -z "${patterns[@]}")
# Keep NUL-delimited filenames so spaces and newlines are preserved.
git ls-files -z '*.md' '*.rs' '*justfile' > "$tmp/tracked"
# The child shell expands these variables.
# shellcheck disable=SC2016
xargs -0 sh -c '
for file do
if [ -f "$file" ] && [ ! -L "$file" ]; then
printf "%s\000" "$file"
fi
done
' sh < "$tmp/tracked" > "$tmp/files"
if [ ${#files[@]} -eq 0 ]; then
if [ ! -s "$tmp/files" ]; then
exit 0
fi
# Checksum files before sed so we detect only changes it makes.
before=$(printf '%s\0' "${files[@]}" | xargs -0 md5sum)
xargs -0 md5sum < "$tmp/files" > "$tmp/before"
standalone_wildcard='^[[:space:]]*\.\.\.[[:space:]]*$'
git_hex_range='[0-9a-f]{4,}\.\.\.[0-9a-f]{4,}'
@@ -30,20 +36,20 @@ bracket_wildcard='\[[[:space:]]*\.\.\.[[:space:]]*\]'
# Detect GNU vs BSD sed to apply the correct in-place flag
if sed --version >/dev/null 2>&1; then
sed_cmd=(sed -i -E)
set -- -i -E
else
sed_cmd=(sed -i '' -E)
set -- -i '' -E
fi
printf '%s\0' "${files[@]}" | xargs -0 "${sed_cmd[@]}" \
xargs -0 sed "$@" \
-e "/${standalone_wildcard}/b" \
-e "/${git_hex_range}/b" \
-e "/${git_ref_range}/b" \
-e "/${bracket_wildcard}/b" \
-e "/${bracket_wildcard}/b" < "$tmp/files"
after=$(printf '%s\0' "${files[@]}" | xargs -0 md5sum)
xargs -0 md5sum < "$tmp/files" > "$tmp/after"
changed=$(diff <(echo "$before") <(echo "$after") | grep '^>' | sed 's/^> [a-f0-9]* //' || true)
changed=$(diff "$tmp/before" "$tmp/after" | grep '^>' | sed 's/^> [a-f0-9]* //' || true)
if [ -n "$changed" ]; then
echo "error: Replaced '...' with '…' (U+2026) in the following files:"
+7 -7
View File
@@ -1,11 +1,11 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -e
HOOK_SCRIPT=$1
HOOKS=$2
TEMPLATE="$HOOK_SCRIPT"
OUTDATED=()
OUTDATED=""
MISSING=0
TOTAL=0
@@ -13,9 +13,9 @@ for hook in $HOOKS; do
TOTAL=$((TOTAL + 1))
if [ ! -f ".git/hooks/$hook" ]; then
MISSING=$((MISSING + 1))
OUTDATED+=("$hook")
OUTDATED="$OUTDATED $hook"
elif ! cmp -s "$TEMPLATE" ".git/hooks/$hook"; then
OUTDATED+=("$hook")
OUTDATED="$OUTDATED $hook"
fi
done
@@ -23,12 +23,12 @@ if [ "$MISSING" -eq "$TOTAL" ] && [ "$TOTAL" -gt 0 ]; then
echo ""
echo "${HINT}No git hooks are installed. Run 'just install-hooks' to install them.${NORMAL}"
echo ""
elif [ ${#OUTDATED[@]} -gt 0 ]; then
elif [ -n "$OUTDATED" ]; then
echo ""
echo "${WARN}WARNING: The following git hooks are missing or out of date:${NORMAL}"
echo ""
for hook in "${OUTDATED[@]}"; do
echo -e "\t$hook"
for hook in $OUTDATED; do
printf '\t%s\n' "$hook"
done
echo ""
echo "${HINT}Check them with 'diff $HOOK_SCRIPT .git/hooks/<hook name>' then run 'just install-hooks'${NORMAL}"
+1 -1
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -e
echo "${CHECK}Checking for forbidden words in staged files…${NORMAL}"
+1 -1
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -euo pipefail
FILE=$1
+1 -1
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
if command -v alejandra >/dev/null 2>&1; then
alejandra --check .
+4 -3
View File
@@ -1,11 +1,12 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -e
HOOK_SCRIPT=$1
HOOKS=$2
read -r -p "Overwrite existing hooks '${HOOKS}'? [y/N] " confirm
[[ "$confirm" == "y" ]] || exit 1
printf "Overwrite existing hooks '%s'? [y/N] " "$HOOKS"
read -r confirm
[ "$confirm" = "y" ] || exit 1
for hook in $HOOKS; do
if [ -f ".git/hooks/$hook" ]; then
+1 -1
View File
@@ -1,4 +1,4 @@
#! /usr/bin/env bash
#! /usr/bin/env sh
set -e
TOOL=$1
PKG_NAME=$2
+1 -1
View File
@@ -1,4 +1,4 @@
#!/bin/sh
#! /usr/bin/env sh
set -e
if [ "$#" -lt 1 ]; then
+7 -2
View File
@@ -1,4 +1,4 @@
#!/bin/bash
#! /usr/bin/env sh
set -e
if [ "$#" -lt 2 ]; then
@@ -23,4 +23,9 @@ actual=$(echo "$actual" | sed "s@refs/namespaces/$REMOTE/@@")
# Remove `sigrefs` itself.
actual=$(echo "$actual" | grep -v "refs/rad/sigrefs$")
diff <(echo "$signed") <(echo "$actual") --color=always -y --minimal -W 240
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' 0
trap 'exit 1' HUP INT TERM
printf '%s\n' "$signed" > "$tmp/signed"
printf '%s\n' "$actual" > "$tmp/actual"
diff --color=always -y --minimal -W 240 "$tmp/signed" "$tmp/actual"