#!/usr/bin/env bash
#
# This script generates a single input file list for SwiftLint containing only changed files
# to improve the speed of incremental builds: https://developer.apple.com/documentation/xcode/improving-the-speed-of-incremental-builds
#
# This script only processes Swift files with staged or unstaged changes to improve performance.

# Get the git root path
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BUILD_FOLDER="$SCRIPT_DIR/../DerivedData/Build/SwiftLint"
CACHE_KEY_PATH="$BUILD_FOLDER/cache_key"
SWIFTLINT_FILELIST_PATH="$BUILD_FOLDER/swiftlint_input.xcfilelist"
SWIFTLINT_STATIC_OUTPUT_PATH="$BUILD_FOLDER/swiftlint_static_output"

# Create a directory where we store the input/output files. This should be a folder that is ignored by git.
mkdir -p "$BUILD_FOLDER"

echo "Generating file list for changed files only (staged + unstaged)"

# Get all changed Swift files (both staged and unstaged, excluding deleted files)
# --diff-filter=d excludes deleted files
# Using git diff for unstaged changes and git diff --cached for staged changes
export LC_ALL=C
GIT_DIFF=$(
	{
		git diff --raw --diff-filter=d -- '*.swift'
		git diff --cached --raw --diff-filter=d -- '*.swift'
	} | sort -u
)

# Read previous cache if it exists
PREV_GIT_RESULT=""
if [[ -f "$CACHE_KEY_PATH" ]]; then
	PREV_GIT_RESULT=$(<"$CACHE_KEY_PATH")
fi

# If there are no changes, we can simplify exist and avoid running swiftlint again
# But only if the output files already exist
if [[ "$PREV_GIT_RESULT" == "$GIT_DIFF" ]] && [[ -f "$SWIFTLINT_FILELIST_PATH" ]] && [[ -f "$SWIFTLINT_STATIC_OUTPUT_PATH" ]]; then
	echo "No changes since last git diff, do nothing"
	exit 0
fi

echo -n "$GIT_DIFF" > "$CACHE_KEY_PATH"

CHANGED_FILES="$(echo "$GIT_DIFF" | awk '{ print $6 }')"

# Handle case where there are no changed files
if [[ -z "$CHANGED_FILES" || "$CHANGED_FILES" =~ ^[[:space:]]*$ ]]; then
	echo "No changed Swift files found"
	echo "" > "$SWIFTLINT_FILELIST_PATH"
	touch "$SWIFTLINT_STATIC_OUTPUT_PATH"
	exit 0
fi

echo "Found $(echo "$CHANGED_FILES" | wc -l | xargs) changed Swift file(s)"

# Add $(SRCROOT)/ prefix to each file path for Xcode
echo "Updating file list..."
SWIFTLINT_FILELIST=$(while IFS= read -r file; do
  echo "\$(SRCROOT)/$file"
done <<< "$CHANGED_FILES")
echo "$SWIFTLINT_FILELIST" > "$SWIFTLINT_FILELIST_PATH"

echo "Creating static output file"
# Create a static empty output file. We need to create these empty output files as stated in the documentation linked above:
# "You must still specify an input and output file to prevent Xcode from running the script every time, even if your script doesn’t actually require those files.
# For a script that requires no input, provide a file that never changes as the input file. For a script with no outputs, create a static output file from your script so Xcode has something to check."
touch "$SWIFTLINT_STATIC_OUTPUT_PATH"
