Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 158 additions & 104 deletions check.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,139 +8,193 @@

# Note: at the moment, there is some useless recompilation, which could be improved.

# --help menu
for arg in $@; do
if [ "$arg" == "--help" ]; then
echo "Usage: check.sh [--double] [<commands>]"
echo ""
echo "Each specified command will be run (until one fails)."
echo "If no commands are specified, all checks are run (no doc; may take several minutes)."
echo ""
echo "Commands:"
echo " fmt format code, fail if bad"
echo " clippy validate clippy lints"
echo " test run unit tests (no Godot)"
echo " itest run integration tests (Godot)"
echo " doc generate docs for 'godot' crate"
echo " dok generate docs and open in browser"
echo ""
echo "Options:"
echo " --double run check with double-precision"
echo ""
echo "Examples:"
echo " check.sh fmt clippy"
echo " check.sh"
echo " check.sh --double clippy"
exit 0
fi
done

firstArg=1
toolchain=""
extraArgs=()

if [[ "$1" == "--double" ]]; then
firstArg=2
extraArgs+=("--features double-precision")
fi
################################################################################
# Constants
################################################################################

# Commands to run (in that order) if none are given on the command line.
DEFAULT_COMMANDS=("fmt" "clippy" "test" "itest")

# Store help text in a variable $HELP_TEXT so we don't need weird indentation later on.
read -r -d '' HELP_TEXT <<EOF
Usage: check.sh [OPTION|COMMAND...]

Each specified command will be run (until one fails).
If no commands are specified, the following commands will be run:
${DEFAULT_COMMANDS[@]}

Commands:
fmt format code, fail if bad
clippy validate clippy lints
test run unit tests (no Godot needed)
itest run integration tests (from within Godot)
doc generate docs for 'godot' crate
dok generate docs and open in browser

Options:
-h, --help print this help text
--double run check with double-precision

Examples:
check.sh fmt clippy
check.sh
check.sh --double clippy
RUSTUP_TOOLCHAIN=nightly check.sh
EOF

# Terminal color codes.
RED='\033[1;31m'
CYAN='\033[1;36m'
END='\033[0m'

args=()
################################################################################
# Helper functions
################################################################################

for arg in "${@:$firstArg}"; do
args+=("$arg")
done
# Drop-in replacement for `echo` that outputs to stderr and adds a newline.
function log() {
echo "$@" >&2
}

# No args specified: do everything
if [ ${#args[@]} -eq 0 ]; then
args=("fmt" "clippy" "test" "itest")
fi
# Echoes the given command to stderr, then executes it.
function run() {
# https://stackoverflow.com/a/76153233/14637
echo -n '>' >&2
for arg in "$@"; do
printf " %q" "$arg" >&2
done
echo >&2
"$@"
}

# For integration tests
# Finds the Godot binary and stores its path in $godotBin. Logs an error and returns with nonzero
# exit status if not found.
function findGodot() {
# User-defined GODOT4_BIN
if [ -n "$GODOT4_BIN" ]; then
echo "Found GODOT4_BIN env var ($GODOT4_BIN)"
# $godotBin previously detected.
if [[ -v godotBin ]]; then
return

# User-defined GODOT4_BIN.
elif [[ -n "$GODOT4_BIN" ]]; then
log "Using environment variable GODOT4_BIN=$(printf %q "$GODOT4_BIN")"
godotBin="$GODOT4_BIN"

# Executable in path
elif command -v godot4 &>/dev/null; then
echo "Found 'godot4' executable"
# Executable in path.
elif command -v godot4 >/dev/null; then
log "Found 'godot4' executable"
godotBin="godot4"

# Special case for Windows when there is a .bat file
# Special case for Windows when there is a .bat file.
# Also consider that 'cmd /c' would need 'cmd //c' (https://stackoverflow.com/q/21357813)
elif
godot4.bat --version
[[ $? -eq 0 ]]
then
echo "Found 'godot4.bat' script"
elif godot4.bat --version 2>/dev/null; then
log "Found 'godot4.bat' script"
godotBin="godot4.bat"

# This should come last: only use this as a last resort as usually `godot`
# refers to a Godot 3.x installation.
elif command -v godot &>/dev/null; then
# This should come last: only use this as a last resort as `godot` may refer to a
# Godot 3.x installation.
elif command -v godot >/dev/null; then
# Check if `godot` actually is Godot 4.x
if godot --version | grep -qE "^4\\."; then
echo "Found 'godot' executable with version $(godot --version)"
godotVersion="$(command godot --version)"
if [[ "$godotVersion" =~ ^4\. ]]; then
log "Found 'godot' executable with version $godotVersion"
godotBin="godot"
else
echo "Found 'godot' executable, but it has the incompatible version $(godot --version)"
exit 2
log "Found 'godot' executable, but it has incompatible version $godotVersion"
return 1
fi

# Error case
# Error case.
else
echo "Godot executable not found"
exit 2
log "Godot executable not found; try setting GODOT4_BIN to the full path to the executable"
return 1
fi
}

################################################################################
# Commands
################################################################################

# Surrogate namespacing: all commands are prefixed with `cmd_` to avoid confusion with shell
# builtins like `test`.

function cmd_fmt() {
run cargo fmt --all -- --check
}

function cmd_clippy() {
run cargo clippy "${extraCargoArgs[@]}" -- \
-D clippy::suspicious \
-D clippy::style \
-D clippy::complexity \
-D clippy::perf \
-D clippy::dbg_macro \
-D clippy::todo \
-D clippy::unimplemented \
-D warnings
}

function cmd_test() {
run cargo test "${extraCargoArgs[@]}"
}

function cmd_itest() {
findGodot && \
run cargo build -p itest "${extraCargoArgs[@]}" && \
run "$godotBin" --path itest/godot --headless
}

function cmd_doc() {
run cargo doc --lib -p godot --no-deps "${extraCargoArgs[@]}"
}

function cmd_dok() {
run cargo doc --lib -p godot --no-deps "${extraCargoArgs[@]}" --open
}

################################################################################
# Argument parsing
################################################################################

cmds=()
extraArgs="${extraArgs[@]}"
extraCargoArgs=()

for arg in "${args[@]}"; do
for arg in "$@"; do
case "$arg" in
fmt)
cmds+=("cargo $toolchain fmt --all -- --check")
;;
clippy)
cmds+=("cargo $toolchain clippy $extraArgs -- -D clippy::suspicious -D clippy::style -D clippy::complexity -D clippy::perf -D clippy::dbg_macro -D clippy::todo -D clippy::unimplemented -D warnings")
;;
test)
cmds+=("cargo $toolchain test $extraArgs")
;;
itest)
findGodot

cmds+=("cargo $toolchain build -p itest $extraArgs")
cmds+=("$godotBin --path itest/godot --headless")
;;
doc)
cmds+=("cargo $toolchain doc --lib -p godot --no-deps $extraArgs")
;;
dok)
cmds+=("cargo $toolchain doc --lib -p godot --no-deps $extraArgs --open")
;;
*)
echo "Unrecognized command '$arg'"
exit 2
;;
-h | --help | help)
echo "$HELP_TEXT"
exit 0
Comment on lines +163 to +165
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably -h|--help should be enough, no? Just to streamline usage a bit.

Copy link
Contributor Author

@ttencate ttencate May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Plain help without any hyphens is a hidden feature, super simple to add and might save someone a few seconds if they try it as a guess. Documenting it would just clutter help output, since we'd also need to specify that it's mutually exclusive with other non-option commands.

Which reminds me, let me point at --help in the "Unrecognized argument" error message.

;;
--double)
extraCargoArgs+=("--features" "double-precision")
;;
fmt | clippy | test | itest | doc | dok)
cmds+=("$arg")
;;
*)
log "Unrecognized argument '$arg'. Use '$0 --help' to see what's available."
exit 2
;;
esac
done

RED='\033[1;31m'
GREEN='\033[1;36m'
END='\033[0m'
# Default if no commands are explicitly given.
if [[ ${#cmds[@]} -eq 0 ]]; then
cmds=("${DEFAULT_COMMANDS[@]}")
fi

################################################################################
# Execution
################################################################################

for cmd in "${cmds[@]}"; do
echo "> $cmd"
$cmd || {
printf "$RED\n====================="
printf "\ngdext: checks FAILED."
printf "\n=====================\n$END"
"cmd_${cmd}" || {
log -ne "$RED\n====================="
log -ne "\ngdext: checks FAILED."
log -ne "\n=====================\n$END"
exit 1
}
done

printf "$GREEN\n========================="
printf "\ngdext: checks SUCCESSFUL."
printf "\n=========================\n$END"
log -ne "$CYAN\n========================="
log -ne "\ngdext: checks SUCCESSFUL."
log -ne "\n=========================\n$END"