274 lines
7.0 KiB
Bash
Executable File
274 lines
7.0 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$ROOT"
|
|
|
|
MODE="check"
|
|
case "${1:---check}" in
|
|
--check) MODE="check" ;;
|
|
--fix|--write) MODE="fix" ;;
|
|
-h|--help)
|
|
echo "Usage: scripts/format_native.sh [--check|--fix]"
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown argument: $1" >&2
|
|
echo "Usage: scripts/format_native.sh [--check|--fix]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
KTLINT_VERSION="1.5.0"
|
|
KTLINT_SHA256="a16be01dcc480aab2f55f444b620142152f66e31564b3b9376506d624c28a2ad"
|
|
KTLINT_URL="https://github.com/ktlint/ktlint/releases/download/$KTLINT_VERSION/ktlint"
|
|
KTLINT_BIN="$ROOT/.dart_tool/native-format/ktlint-$KTLINT_VERSION"
|
|
KTLINT_TMP=""
|
|
JAVA_BIN_DIR=""
|
|
|
|
cleanup() {
|
|
if [ -n "$KTLINT_TMP" ]; then
|
|
rm -f -- "$KTLINT_TMP"
|
|
fi
|
|
}
|
|
trap cleanup EXIT
|
|
trap 'exit 129' HUP
|
|
trap 'exit 130' INT
|
|
trap 'exit 143' TERM
|
|
has_command() {
|
|
command -v "$1" >/dev/null 2>&1
|
|
}
|
|
|
|
run_clang_format() {
|
|
if has_command xcrun && xcrun --find clang-format >/dev/null 2>&1; then
|
|
xcrun clang-format "$@"
|
|
elif has_command clang-format; then
|
|
clang-format "$@"
|
|
else
|
|
echo "clang-format not found. Install clang-format or Xcode command line tools." >&2
|
|
return 127
|
|
fi
|
|
}
|
|
|
|
run_swift_format() {
|
|
if has_command xcrun && xcrun --find swift-format >/dev/null 2>&1; then
|
|
xcrun swift-format "$@"
|
|
elif has_command swift-format; then
|
|
swift-format "$@"
|
|
elif has_command swift && swift format --help >/dev/null 2>&1; then
|
|
swift format "$@"
|
|
else
|
|
echo "swift-format not found. Install Swift 6+, swift-format, or Xcode 16+." >&2
|
|
return 127
|
|
fi
|
|
}
|
|
|
|
java_diagnostic() {
|
|
echo "A working JDK 17+ is required for Kotlin formatting. Set JAVA_HOME to a JDK 17+ installation or put java on PATH." >&2
|
|
}
|
|
|
|
resolve_java() {
|
|
local candidate output version major
|
|
if [ -n "${JAVA_HOME:-}" ]; then
|
|
candidate="$JAVA_HOME/bin/java"
|
|
else
|
|
candidate="$(command -v java 2>/dev/null || true)"
|
|
fi
|
|
if [ -z "$candidate" ] || [ ! -x "$candidate" ]; then
|
|
java_diagnostic
|
|
return 127
|
|
fi
|
|
if [[ "$candidate" != /* ]]; then
|
|
candidate="$PWD/$candidate"
|
|
fi
|
|
if ! output="$("$candidate" -version 2>&1)"; then
|
|
java_diagnostic
|
|
return 127
|
|
fi
|
|
if [[ "$output" =~ version[[:space:]]+\"([^\"]+)\" ]]; then
|
|
version="${BASH_REMATCH[1]}"
|
|
else
|
|
java_diagnostic
|
|
return 127
|
|
fi
|
|
if [[ "$version" =~ ^1\.([0-9]+)([._-]|$) ]]; then
|
|
major="${BASH_REMATCH[1]}"
|
|
elif [[ "$version" =~ ^([0-9]+)([._-]|$) ]]; then
|
|
major="${BASH_REMATCH[1]}"
|
|
else
|
|
java_diagnostic
|
|
return 127
|
|
fi
|
|
if ((major < 17)); then
|
|
java_diagnostic
|
|
return 127
|
|
fi
|
|
JAVA_BIN_DIR="${candidate%/*}"
|
|
}
|
|
|
|
sha256_file() {
|
|
local output
|
|
if has_command shasum; then
|
|
output="$(shasum -a 256 "$1")" || {
|
|
echo "Failed to calculate the ktlint SHA-256 digest with shasum." >&2
|
|
return 2
|
|
}
|
|
elif has_command sha256sum; then
|
|
output="$(sha256sum "$1")" || {
|
|
echo "Failed to calculate the ktlint SHA-256 digest with sha256sum." >&2
|
|
return 2
|
|
}
|
|
else
|
|
echo "A SHA-256 tool is required to verify ktlint (shasum or sha256sum)." >&2
|
|
return 127
|
|
fi
|
|
printf '%s\n' "${output%%[[:space:]]*}"
|
|
}
|
|
|
|
verify_ktlint() {
|
|
local digest
|
|
digest="$(sha256_file "$1")" || return $?
|
|
[[ "$digest" =~ ^[0-9a-f]{64}$ ]] && [ "$digest" = "$KTLINT_SHA256" ]
|
|
}
|
|
|
|
ensure_ktlint() {
|
|
local status
|
|
if ! has_command shasum && ! has_command sha256sum; then
|
|
echo "A SHA-256 tool is required to verify ktlint (shasum or sha256sum)." >&2
|
|
return 127
|
|
fi
|
|
if [ -f "$KTLINT_BIN" ]; then
|
|
if verify_ktlint "$KTLINT_BIN"; then
|
|
chmod +x "$KTLINT_BIN"
|
|
return 0
|
|
else
|
|
status=$?
|
|
if [ "$status" -ne 1 ]; then
|
|
return "$status"
|
|
fi
|
|
fi
|
|
fi
|
|
if ! has_command curl; then
|
|
echo "curl not found. Install curl to download ktlint." >&2
|
|
return 127
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$KTLINT_BIN")"
|
|
KTLINT_TMP="$(mktemp "$(dirname "$KTLINT_BIN")/.ktlint-$KTLINT_VERSION.XXXXXX")"
|
|
if ! curl -fsSL "$KTLINT_URL" -o "$KTLINT_TMP"; then
|
|
echo "Failed to download ktlint $KTLINT_VERSION." >&2
|
|
return 1
|
|
fi
|
|
if verify_ktlint "$KTLINT_TMP"; then
|
|
:
|
|
else
|
|
status=$?
|
|
if [ "$status" -eq 1 ]; then
|
|
echo "Downloaded ktlint $KTLINT_VERSION failed SHA-256 verification." >&2
|
|
fi
|
|
return "$status"
|
|
fi
|
|
chmod +x "$KTLINT_TMP"
|
|
mv -f "$KTLINT_TMP" "$KTLINT_BIN"
|
|
KTLINT_TMP=""
|
|
}
|
|
|
|
run_ktlint() {
|
|
PATH="$JAVA_BIN_DIR:$PATH" "$KTLINT_BIN" "$@"
|
|
}
|
|
|
|
append_native_files() {
|
|
while IFS= read -r -d '' file; do
|
|
case "$file" in
|
|
android/app/src/main/cpp/include/*) continue ;;
|
|
android/app/src/main/java/io/flutter/plugins/*) continue ;;
|
|
ios/Flutter/*|macos/Flutter/*|tvos/Flutter/*) continue ;;
|
|
linux/flutter/*|windows/flutter/*) continue ;;
|
|
tvos/Runner/Plugins/*) continue ;;
|
|
*/GeneratedPluginRegistrant.*|*/generated_plugin_registrant.*) continue ;;
|
|
esac
|
|
|
|
case "$file" in
|
|
*.kt|*.kts) ktlint_files+=("$file") ;;
|
|
*.swift) swift_files+=("$file") ;;
|
|
*.c|*.cc|*.cpp|*.h|*.hpp|*.m|*.mm) clang_files+=("$file") ;;
|
|
esac
|
|
done < <(git ls-files -z -- "$@")
|
|
}
|
|
|
|
ktlint_files=()
|
|
swift_files=()
|
|
clang_files=()
|
|
|
|
append_native_files \
|
|
'android/**/*.kt' 'android/**/*.kts' \
|
|
'ios/**/*.swift' 'macos/**/*.swift' 'tvos/**/*.swift' 'shared/**/*.swift' \
|
|
'android/**/*.[ch]' 'android/**/*.cc' 'android/**/*.cpp' 'android/**/*.hpp' \
|
|
'ios/**/*.[hm]' 'ios/**/*.mm' \
|
|
'macos/**/*.[hm]' 'macos/**/*.mm' \
|
|
'tvos/**/*.[hm]' 'tvos/**/*.mm' \
|
|
'linux/**/*.[ch]' 'linux/**/*.cc' 'linux/**/*.cpp' 'linux/**/*.hpp' \
|
|
'windows/**/*.[ch]' 'windows/**/*.cc' 'windows/**/*.cpp' 'windows/**/*.hpp' \
|
|
'shared/**/*.[ch]' 'shared/**/*.cc' 'shared/**/*.cpp' 'shared/**/*.hpp'
|
|
|
|
FAILED=0
|
|
|
|
if [ "${#ktlint_files[@]}" -gt 0 ]; then
|
|
resolve_java
|
|
ensure_ktlint
|
|
if [ "$MODE" = "fix" ]; then
|
|
run_ktlint -F "${ktlint_files[@]}"
|
|
else
|
|
run_ktlint "${ktlint_files[@]}" || FAILED=1
|
|
fi
|
|
else
|
|
echo "No Kotlin files found."
|
|
fi
|
|
|
|
if [ "${#swift_files[@]}" -gt 0 ]; then
|
|
if [ "$MODE" = "fix" ]; then
|
|
run_swift_format format --configuration "$ROOT/.swift-format" --in-place "${swift_files[@]}"
|
|
else
|
|
swift_failed=0
|
|
for file in "${swift_files[@]}"; do
|
|
tmp="$(mktemp)"
|
|
run_swift_format format --configuration "$ROOT/.swift-format" "$file" >"$tmp"
|
|
if ! cmp -s "$file" "$tmp"; then
|
|
if [ "$swift_failed" -eq 0 ]; then
|
|
echo "Swift files need formatting:"
|
|
fi
|
|
echo " $file"
|
|
swift_failed=1
|
|
fi
|
|
rm -f "$tmp"
|
|
done
|
|
if [ "$swift_failed" -ne 0 ]; then
|
|
FAILED=1
|
|
fi
|
|
fi
|
|
else
|
|
echo "No Swift files found."
|
|
fi
|
|
|
|
if [ "${#clang_files[@]}" -gt 0 ]; then
|
|
if [ "$MODE" = "fix" ]; then
|
|
run_clang_format -i "${clang_files[@]}"
|
|
else
|
|
run_clang_format --dry-run --Werror "${clang_files[@]}" || FAILED=1
|
|
fi
|
|
else
|
|
echo "No C/C++/Obj-C files found."
|
|
fi
|
|
|
|
if [ "$FAILED" -ne 0 ]; then
|
|
echo "Native formatting issues found. Run: scripts/format_native.sh --fix" >&2
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$MODE" = "check" ]; then
|
|
echo "Native formatting passed."
|
|
else
|
|
echo "Native formatting applied."
|
|
fi
|