170 lines
7.5 KiB
Bash
170 lines
7.5 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
fail() {
|
|
echo "::error::$*" >&2
|
|
exit 1
|
|
}
|
|
|
|
require_command() {
|
|
command -v "$1" >/dev/null 2>&1 || fail "Required command '$1' was not found on the runner."
|
|
}
|
|
|
|
require_environment() {
|
|
[[ -n "${!1:-}" ]] || fail "Required environment variable '$1' is not set."
|
|
}
|
|
|
|
validate_common_inputs() {
|
|
[[ "$GODOT_VERSION" =~ ^4(\.[0-9]+){1,2}-stable$ ]] || fail "godot-version must be a stable Godot 4 tag such as 4.7.2-stable. Alpha, beta, RC, and dev tags are not supported."
|
|
[[ "$GODOT_HOST_OS" == "macos" ]] || fail "host-os must be 'macos' when this action runs on macOS."
|
|
[[ "$GODOT_DOTNET" == "true" || "$GODOT_DOTNET" == "false" ]] || fail "dotnet must be 'true' or 'false'."
|
|
[[ "$GODOT_EXPORT_MODE" == "release" || "$GODOT_EXPORT_MODE" == "debug" ]] || fail "export-mode must be 'release' or 'debug'."
|
|
[[ -n "$GODOT_EXPORT_PRESET" ]] || fail "export-preset must not be empty."
|
|
[[ -n "$GODOT_EXPORT_FILE_NAME" && "$GODOT_EXPORT_FILE_NAME" != "." && "$GODOT_EXPORT_FILE_NAME" != ".." ]] || fail "export-file-name must be a filename."
|
|
[[ "$GODOT_EXPORT_FILE_NAME" != */* && "$GODOT_EXPORT_FILE_NAME" != *\\* ]] || fail "export-file-name must not contain a path separator."
|
|
}
|
|
|
|
actual_architecture() {
|
|
case "$(uname -m)" in
|
|
x86_64) echo x86_64 ;;
|
|
arm64) echo arm64 ;;
|
|
*) fail "Unsupported macOS runner architecture: $(uname -m)." ;;
|
|
esac
|
|
}
|
|
|
|
release_asset_checksum() {
|
|
local asset="$1"
|
|
local sum_file="$2"
|
|
local expected
|
|
|
|
expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$sum_file")"
|
|
[[ -n "$expected" ]] || fail "Godot $GODOT_VERSION does not publish required $EDITION asset '$asset' for macOS/$GODOT_HOST_ARCH at $BASE_URL. Choose a supported stable release and architecture."
|
|
printf '%s\n' "$expected"
|
|
}
|
|
|
|
download_and_verify() {
|
|
local asset="$1"
|
|
local destination="$2"
|
|
local expected="$3"
|
|
local actual
|
|
|
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/$asset" --output "$destination"
|
|
actual="$(shasum -a 512 "$destination" | awk '{ print $1 }')"
|
|
[[ "$actual" == "$expected" ]] || fail "SHA-512 verification failed for $asset."
|
|
}
|
|
|
|
find_editor() {
|
|
find "$EDITOR_DIR" -type f -path '*.app/Contents/MacOS/*' -name 'Godot*' -print -quit
|
|
}
|
|
|
|
install_export_templates() {
|
|
local staging_directory="$1"
|
|
local staged_templates="$staging_directory/templates"
|
|
local staged_version="$staged_templates/version.txt"
|
|
local actual_template_version
|
|
|
|
[[ -f "$staged_version" ]] || fail "The export-template archive '$TEMPLATES_ASSET' did not contain templates/version.txt."
|
|
actual_template_version="$(tr -d '\r\n' < "$staged_version")"
|
|
[[ "$actual_template_version" == "$TEMPLATE_VERSION" ]] || fail "The export-template archive '$TEMPLATES_ASSET' reports template version '$actual_template_version', expected '$TEMPLATE_VERSION'."
|
|
mkdir -p "$TEMPLATE_DIR"
|
|
cp -R "$staged_templates/." "$TEMPLATE_DIR/"
|
|
rm -rf "$staging_directory"
|
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive '$TEMPLATES_ASSET' could not be installed to '$TEMPLATE_DIR'."
|
|
}
|
|
|
|
install_godot() {
|
|
local sum_file="$CACHE_DIR/SHA512-SUMS.txt"
|
|
local editor_archive="$CACHE_DIR/$EDITOR_ASSET"
|
|
local templates_archive="$CACHE_DIR/$TEMPLATES_ASSET"
|
|
local templates_staging_directory="$CACHE_DIR/templates-staging"
|
|
local editor_checksum
|
|
local templates_checksum
|
|
|
|
rm -rf "$CACHE_DIR"
|
|
mkdir -p "$EDITOR_DIR"
|
|
curl --fail --location --retry 3 --silent --show-error "$BASE_URL/SHA512-SUMS.txt" --output "$sum_file"
|
|
editor_checksum="$(release_asset_checksum "$EDITOR_ASSET" "$sum_file")"
|
|
templates_checksum="$(release_asset_checksum "$TEMPLATES_ASSET" "$sum_file")"
|
|
download_and_verify "$EDITOR_ASSET" "$editor_archive" "$editor_checksum"
|
|
download_and_verify "$TEMPLATES_ASSET" "$templates_archive" "$templates_checksum"
|
|
unzip -q "$editor_archive" -d "$EDITOR_DIR"
|
|
unzip -q "$templates_archive" -d "$templates_staging_directory"
|
|
install_export_templates "$templates_staging_directory"
|
|
EDITOR_EXECUTABLE="$(find_editor)"
|
|
[[ -n "$EDITOR_EXECUTABLE" ]] || fail "The Godot editor archive did not contain a macOS app executable."
|
|
[[ -f "$TEMPLATE_DIR/version.txt" ]] || fail "The export-template archive did not contain version.txt."
|
|
printf 'release=%s\neditor=%s\ntemplates=%s\n' "$GODOT_VERSION" "$EDITOR_ASSET" "$TEMPLATES_ASSET" > "$CACHE_DIR/.complete"
|
|
}
|
|
|
|
require_environment GODOT_VERSION
|
|
require_environment GODOT_HOST_OS
|
|
require_environment GODOT_HOST_ARCH
|
|
require_environment GODOT_DOTNET
|
|
require_environment GODOT_PROJECT_PATH
|
|
require_environment GODOT_EXPORT_PRESET
|
|
require_environment GODOT_EXPORT_MODE
|
|
require_environment GODOT_EXPORT_FILE_NAME
|
|
require_environment GODOT_ACTION_ROOT
|
|
require_environment GITHUB_WORKSPACE
|
|
require_environment GITHUB_OUTPUT
|
|
|
|
require_command curl
|
|
require_command unzip
|
|
require_command shasum
|
|
validate_common_inputs
|
|
|
|
[[ "$(uname -s)" == "Darwin" ]] || fail "The macOS script was selected on a non-macOS runner."
|
|
[[ "$GODOT_HOST_ARCH" == "x86_64" || "$GODOT_HOST_ARCH" == "arm64" ]] || fail "Unsupported macOS host-arch '$GODOT_HOST_ARCH'."
|
|
[[ "$GODOT_HOST_ARCH" == "$(actual_architecture)" ]] || fail "host-arch '$GODOT_HOST_ARCH' does not match this macOS runner ($(actual_architecture))."
|
|
|
|
[[ "$GODOT_PROJECT_PATH" != /* && "$GODOT_PROJECT_PATH" != \\* ]] || fail "project-path must be relative to the checked-out workspace."
|
|
WORKSPACE_DIR="$(cd "$GITHUB_WORKSPACE" && pwd -P)"
|
|
PROJECT_DIR="$(cd "$WORKSPACE_DIR/$GODOT_PROJECT_PATH" 2>/dev/null && pwd -P)" || fail "project-path '$GODOT_PROJECT_PATH' does not exist."
|
|
case "$PROJECT_DIR/" in
|
|
"$WORKSPACE_DIR/"*) ;;
|
|
*) fail "project-path must remain inside the checked-out workspace." ;;
|
|
esac
|
|
[[ -f "$PROJECT_DIR/project.godot" ]] || fail "No project.godot was found in project-path '$GODOT_PROJECT_PATH'."
|
|
[[ -f "$PROJECT_DIR/export_presets.cfg" ]] || fail "No export_presets.cfg was found in project-path '$GODOT_PROJECT_PATH'."
|
|
grep -Fq "name=\"$GODOT_EXPORT_PRESET\"" "$PROJECT_DIR/export_presets.cfg" || fail "Export preset '$GODOT_EXPORT_PRESET' was not found in export_presets.cfg."
|
|
|
|
if [[ "$GODOT_DOTNET" == "true" ]]; then
|
|
EDITION=dotnet
|
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_mono_macos.universal.zip"
|
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_mono_export_templates.tpz"
|
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}.mono"
|
|
else
|
|
EDITION=standard
|
|
EDITOR_ASSET="Godot_v${GODOT_VERSION}_macos.universal.zip"
|
|
TEMPLATES_ASSET="Godot_v${GODOT_VERSION}_export_templates.tpz"
|
|
TEMPLATE_VERSION="${GODOT_VERSION//-/.}"
|
|
fi
|
|
|
|
BASE_URL="https://github.com/godotengine/godot/releases/download/$GODOT_VERSION"
|
|
CACHE_DIR="$GODOT_ACTION_ROOT/cache/$GODOT_VERSION/$EDITION/macos-$GODOT_HOST_ARCH"
|
|
EDITOR_DIR="$CACHE_DIR/editor"
|
|
USER_HOME="$CACHE_DIR/home"
|
|
TEMPLATE_DIR="$USER_HOME/Library/Application Support/Godot/export_templates/$TEMPLATE_VERSION"
|
|
|
|
if [[ -f "$CACHE_DIR/.complete" && -f "$TEMPLATE_DIR/version.txt" ]]; then
|
|
EDITOR_EXECUTABLE="$(find_editor || true)"
|
|
else
|
|
EDITOR_EXECUTABLE=""
|
|
fi
|
|
if [[ -z "$EDITOR_EXECUTABLE" ]]; then
|
|
install_godot
|
|
fi
|
|
|
|
chmod +x "$EDITOR_EXECUTABLE"
|
|
SAFE_PRESET="$(printf '%s' "$GODOT_EXPORT_PRESET" | tr -cs '[:alnum:]_.-' '_')"
|
|
BUILD_DIR="$GODOT_ACTION_ROOT/builds/${SAFE_PRESET:-export}-$GODOT_EXPORT_MODE-$$"
|
|
OUTPUT_FILE="$BUILD_DIR/$GODOT_EXPORT_FILE_NAME"
|
|
mkdir -p "$BUILD_DIR"
|
|
|
|
export HOME="$USER_HOME"
|
|
"$EDITOR_EXECUTABLE" --headless --path "$PROJECT_DIR" "--export-$GODOT_EXPORT_MODE" "$GODOT_EXPORT_PRESET" "$OUTPUT_FILE"
|
|
[[ -e "$OUTPUT_FILE" ]] || fail "Godot completed without creating the expected output '$GODOT_EXPORT_FILE_NAME'."
|
|
|
|
printf 'build-directory=%s\n' "$BUILD_DIR" >> "$GITHUB_OUTPUT"
|