mirror of
https://github.com/ironfox-oss/IronFox.git
synced 2026-06-11 01:34:46 -04:00
This reverts commit 3dd7cf2d5f, as these changes were not related to the issue
Signed-off-by: celenity <celenity@celenity.dev>
448 lines
14 KiB
Bash
448 lines
14 KiB
Bash
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
|
|
# Set-up our environment
|
|
if [[ -z "${IRONFOX_SET_ENVS+x}" ]]; then
|
|
bash -x $(dirname $0)/env.sh
|
|
fi
|
|
source $(dirname $0)/env.sh
|
|
|
|
readonly RED="\033[0;31m"
|
|
readonly GREEN="\033[0;32m"
|
|
readonly NC="\033[0m"
|
|
|
|
declare -a PATCH_CMD
|
|
readonly PATCH_CMD=(patch -p1 -f --fuzz=3 --no-backup-if-mismatch)
|
|
|
|
declare -a PATCH_FILES
|
|
declare -a AS_PATCH_FILES
|
|
declare -a GLEAN_PATCH_FILES
|
|
declare -a UP_AC_PATCH_FILES
|
|
|
|
readonly PATCH_FILES=($(yq '.patches[].file' "$(dirname "$0")"/patches.yaml))
|
|
readonly AS_PATCH_FILES=($(yq '.patches[].file' "$(dirname "$0")"/a-s-patches.yaml))
|
|
readonly GLEAN_PATCH_FILES=($(yq '.patches[].file' "$(dirname "$0")"/glean-patches.yaml))
|
|
readonly UP_AC_PATCH_FILES=($(yq '.patches[].file' "${IRONFOX_UP_AC}"/patches/patches.yaml))
|
|
|
|
function check_patch() {
|
|
local readonly patch="${IRONFOX_PATCHES}/$1"
|
|
if ! [[ -f "${patch}" ]]; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "'${patch}' does not exist or is not a file"
|
|
return 1
|
|
fi
|
|
|
|
if ! "${PATCH_CMD[@]}" --dry-run <"${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Incompatible patch: '${patch}'"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function up_ac_check_patch() {
|
|
local readonly patch="${IRONFOX_UP_AC}/patches/$1"
|
|
if ! [[ -f "${patch}" ]]; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "'${patch}' does not exist or is not a file"
|
|
return 1
|
|
fi
|
|
|
|
if ! "${PATCH_CMD[@]}" --dry-run <"${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Incompatible patch: '${patch}'"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
function check_patches() {
|
|
for patch in "${PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}"; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function a-s_check_patches() {
|
|
for patch in "${AS_PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}"; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function glean_check_patches() {
|
|
for patch in "${GLEAN_PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}"; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function up_ac_check_patches() {
|
|
for patch in "${UP_AC_PATCH_FILES[@]}"; do
|
|
if ! up_ac_check_patch "${patch}"; then
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function test_patches() {
|
|
for patch in "${PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
else
|
|
printf "${GREEN}✓ %-45s: OK${NC}\n" "$(basename "${patch}")"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function a-s_test_patches() {
|
|
for patch in "${AS_PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
else
|
|
printf "${GREEN}✓ %-45s: OK${NC}\n" "$(basename "${patch}")"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function glean_test_patches() {
|
|
for patch in "${GLEAN_PATCH_FILES[@]}"; do
|
|
if ! check_patch "${patch}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
else
|
|
printf "${GREEN}✓ %-45s: OK${NC}\n" "$(basename "${patch}")"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function up_ac_test_patches() {
|
|
for patch in "${UP_AC_PATCH_FILES[@]}"; do
|
|
if ! up_ac_check_patch "${patch}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
else
|
|
printf "${GREEN}✓ %-45s: OK${NC}\n" "$(basename "${patch}")"
|
|
fi
|
|
done
|
|
}
|
|
|
|
function apply_patch() {
|
|
local readonly name="$1"
|
|
echo "Applying patch: ${name}"
|
|
check_patch "${name}" || return 1
|
|
"${PATCH_CMD[@]}" <"${IRONFOX_PATCHES}/${name}"
|
|
return $?
|
|
}
|
|
|
|
function up_ac_apply_patch() {
|
|
local readonly name="$1"
|
|
echo "Applying patch: ${name}"
|
|
up_ac_check_patch "${name}" || return 1
|
|
"${PATCH_CMD[@]}" <"${IRONFOX_UP_AC}/patches/${name}"
|
|
return $?
|
|
}
|
|
|
|
function apply_patches() {
|
|
for patch in "${PATCH_FILES[@]}"; do
|
|
if ! apply_patch "${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to apply ${patch}"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function a-s_apply_patches() {
|
|
for patch in "${AS_PATCH_FILES[@]}"; do
|
|
if ! apply_patch "${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to apply ${patch}"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function glean_apply_patches() {
|
|
for patch in "${GLEAN_PATCH_FILES[@]}"; do
|
|
if ! apply_patch "${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to apply ${patch}"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function up_ac_apply_patches() {
|
|
for patch in "${UP_AC_PATCH_FILES[@]}"; do
|
|
if ! up_ac_apply_patch "${patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to apply ${patch}"
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
function list_patches() {
|
|
for patch in "${PATCH_FILES[@]}"; do
|
|
echo "${patch}"
|
|
done
|
|
}
|
|
|
|
function a-s_list_patches() {
|
|
for patch in "${AS_PATCH_FILES[@]}"; do
|
|
echo "${patch}"
|
|
done
|
|
}
|
|
|
|
function glean_list_patches() {
|
|
for patch in "${GLEAN_PATCH_FILES[@]}"; do
|
|
echo "${patch}"
|
|
done
|
|
}
|
|
|
|
function up_ac_list_patches() {
|
|
for patch in "${UP_AC_PATCH_FILES[@]}"; do
|
|
echo "${patch}"
|
|
done
|
|
}
|
|
|
|
function slugify() {
|
|
local readonly input="$1"
|
|
echo "${input}" | \
|
|
tr '[:upper:]' '[:lower:]' | \
|
|
"${IRONFOX_SED}" -E 's/[^a-z0-9]+/-/g' | \
|
|
"${IRONFOX_SED}" -E 's/^-+|-+$//g'
|
|
}
|
|
|
|
# Function to rebase a single patch file atomically
|
|
# Usage: rebase_patch <compatible_tag> <target_tag> <patch_file_path>
|
|
function rebase_patch() {
|
|
local readonly compatible_tag="$1"
|
|
local readonly target_tag="$2"
|
|
local readonly patch_file="$3"
|
|
|
|
# Validate inputs
|
|
if [[ -z "${compatible_tag}" || -z "${target_tag}" || -z "${patch_file}" ]]; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Missing required parameters" >&2
|
|
echo "Usage: rebase_patch <compatible_tag> <target_tag> <patch_file_path>" >&2
|
|
return 1
|
|
fi
|
|
|
|
if [[ ! -f "${patch_file}" ]]; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Patch file '${patch_file}' does not exist" >&2
|
|
return 1
|
|
fi
|
|
|
|
# Store original state for rollback
|
|
local readonly original_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)
|
|
|
|
local readonly original_stash_count=$(git stash list | wc -l)
|
|
|
|
local readonly patch_name=$(basename "${patch_file}" .patch)
|
|
|
|
local readonly branch_name="rebase-${patch_name}"
|
|
|
|
function cleanup_and_rollback() {
|
|
echo "Error occurred, rolling back changes..." >&2
|
|
|
|
# Check if we're in the middle of a rebase and abort it
|
|
if git status --porcelain=v1 2>/dev/null | grep -q "^R" ||
|
|
[[ -d "$(git rev-parse --git-dir)/rebase-merge" ]] ||
|
|
[[ -d "$(git rev-parse --git-dir)/rebase-apply" ]]; then
|
|
echo "Aborting rebase in progress..."
|
|
git rebase --abort 2>/dev/null
|
|
fi
|
|
|
|
# Switch back to original branch if it exists
|
|
if [[ -n "${original_branch}" && "${original_branch}" != "HEAD" ]]; then
|
|
git checkout "${original_branch}" 2>/dev/null
|
|
fi
|
|
|
|
# Delete the temporary branch if it was created
|
|
git branch -D "${branch_name}" 2>/dev/null
|
|
|
|
# Restore stashed changes if any were created
|
|
local readonly current_stash_count=$(git stash list | wc -l)
|
|
if [[ "${current_stash_count}" -gt "${original_stash_count}" ]]; then
|
|
git stash pop 2>/dev/null
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
# Ensure clean git directory state
|
|
if ! git diff-index --quiet HEAD --; then
|
|
echo "Stashing uncommitted changes..."
|
|
if ! git stash push -m "Temporary stash for patch rebase"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to stash changes" >&2
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# Check if tags exist
|
|
if ! git rev-parse --verify "${compatible_tag}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Compatible tag '${compatible_tag}' does not exist" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
if ! git rev-parse --verify "${target_tag}" >/dev/null 2>&1; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Target tag '${target_tag}' does not exist" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Checkout the compatible tag
|
|
echo "Checking out compatible tag '${compatible_tag}'..."
|
|
if ! git checkout "${compatible_tag}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to checkout compatible tag '${compatible_tag}'" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Create and switch to new branch
|
|
echo "Creating branch '${branch_name}'..."
|
|
if ! git checkout -b "${branch_name}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to create branch '${branch_name}'" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Apply the patch
|
|
echo "Applying patch '${patch_file}'..."
|
|
if ! git apply "${patch_file}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to apply '${patch_file}'" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Stage all changes
|
|
if ! git add .; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to stage changes" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Commit the changes
|
|
local readonly commit_message="Apply patch $(basename "${patch_file}") - rebased to ${target_tag}"
|
|
echo "Committing changes..."
|
|
if ! git commit -m "${commit_message}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to commit changes" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Rebase to target tag
|
|
echo "Rebasing to target tag '${target_tag}'..."
|
|
if ! git rebase "$target_tag"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to rebase to target tag '${target_tag}'" >&2
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Update the patch file using git format-patch
|
|
echo "Updating patch file..."
|
|
local readonly temp_patch=$(mktemp)
|
|
if ! git format-patch -1 --stdout >"${temp_patch}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patc}h")"
|
|
echo "Failed to generate new patch" >&2
|
|
rm -f "${temp_patch}"
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Atomically replace the original patch file
|
|
if ! mv "${temp_patch}" "${patch_file}"; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Failed to update patch file" >&2
|
|
rm -f "${temp_patch}"
|
|
cleanup_and_rollback
|
|
return 1
|
|
fi
|
|
|
|
# Cleanup: switch back to original branch and delete temporary branch
|
|
if [[ -n "${original_branch}" && "${original_branch}" != "HEAD" ]]; then
|
|
git checkout "${original_branch}"
|
|
else
|
|
git checkout "${target_tag}"
|
|
fi
|
|
|
|
git branch -D "${branch_name}"
|
|
|
|
# Restore stashed changes if any
|
|
local readonly current_stash_count=$(git stash list | wc -l)
|
|
if [[ "${current_stash_count}" -gt "${original_stash_count}" ]]; then
|
|
echo "Restoring stashed changes..."
|
|
git stash pop
|
|
fi
|
|
|
|
printf "${GREEN}✓ %-45s: SUCCESS${NC}\n" "$(basename "${patch}")"
|
|
echo "Rebased patch '${patch_file}' from '${compatible_tag}' to '${target_tag}'"
|
|
return 0
|
|
}
|
|
|
|
# Function to rebase multiple patch files
|
|
# Usage: rebase_patches <compatible_tag> <target_tag> <patch_file1> [patch_file2] [...]
|
|
function rebase_patches() {
|
|
local readonly compatible_tag="$1"
|
|
local readonly target_tag="$2"
|
|
|
|
# Validate inputs
|
|
if [[ -z "${compatible_tag}" || -z "${target_tag}" ]]; then
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
echo "Missing required parameters" >&2
|
|
echo "Usage: rebase_patches <compatible_tag> <target_tag>" >&2
|
|
return 1
|
|
fi
|
|
|
|
local success_count=0
|
|
local failure_count=0
|
|
local failed_patches=()
|
|
|
|
echo "Starting batch rebase of ${#PATCH_FILES[@]} patch files..."
|
|
echo "Compatible tag: ${compatible_tag}"
|
|
echo "Target tag: ${target_tag}"
|
|
echo "----------------------------------------"
|
|
|
|
for patch_file in "${PATCH_FILES[@]}"; do
|
|
echo "Processing: ${patch_file}"
|
|
|
|
if rebase_patch "${compatible_tag}" "${target_tag}" "${patch_file}"; then
|
|
printf "${GREEN}✓ %-45s: SUCCESS${NC}\n" "$(basename "${patch}")"
|
|
((success_count++))
|
|
else
|
|
printf "${RED}✗ %-45s: FAILED${NC}\n" "$(basename "${patch}")"
|
|
failed_patches+=("${patch_file}")
|
|
((failure_count++))
|
|
fi
|
|
echo "----------------------------------------"
|
|
done
|
|
|
|
# Summary
|
|
echo "Batch rebase completed:"
|
|
echo " Successful: ${success_count}"
|
|
echo " Failed: ${failure_count}"
|
|
|
|
if [[ "${failure_count}" -gt 0 ]]; then
|
|
echo "Failed patches:"
|
|
for failed_patch in "${failed_patches[@]}"; do
|
|
echo " - ${failed_patch}"
|
|
done
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|