#!/usr/bin/env bash # Default behaviour: # Reverts all patches in patch dir, notes down the ones # which were previously applied. Applies all from the beginning # and reports about previously unapplied patches. If there's # an error, reverts the last one and stops. # # Usage: ./patcher -p -r -v # -p: is where to apply to (a go-ethereum package) # -r: reverts all and exit if this flag is present # -c: reverts all to see what's applied, applies all previously applied back again, # reports unapplied patches in this branch by comparing with "develop" including # uncommitted ones and exits (with 1 if there are any) # -v: verbose error reporting about failed patch # # If -p is not present, default path is as below ($basepath). dir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) patches=("$dir"/geth/*.patch) # Use this branch as a reference for comparing patches # in current branch (-c option). baseBranch="develop" # Base path is vendor/github.com/ethereum/go-ethereum # unless specified. basepath="vendor/github.com/ethereum/go-ethereum" verbose=0 while getopts :prcv opt; do case $opt in p) basepath=$OPTARG ;; r) # Reverts in reverse order and exits. for ((i=${#patches[@]}-1; i>=0; i--)); do git apply "${patches[$i]}" --directory="$basepath" -R > /dev/null 2>&1 done echo "Reverted all." exit ;; c) applied=() unapplied=() # Finds applied patches using reverse order and # notes them down. for ((i=${#patches[@]}-1; i>=0; i--)); do f=${patches[$i]} git apply "$f" --directory="$basepath" -R > /dev/null 2>&1 if [ $? -eq 1 ]; then unapplied+=("$f") else applied+=("$f") fi done # Applies reverted patches back again. for ((i=${#applied[@]}-1; i>=0; i--)); do f=${applied[$i]} git apply "$f" --directory="$basepath" > /dev/null 2>&1 done # Sorts out new patches' paths by comparing with base branch. fromBaseBranch=($(git diff $baseBranch --stat | grep "\\.patch" | while IFS=" " read -r -a line; do path="$(pwd)/${line[0]}" echo "$path" done )) # Also does the same with uncommitted. uncommitted=($(git status -u --porcelain | grep "\\.patch" | while IFS=" " read -r -a line; do length=${#line[@]} path="$(pwd)/${line[$((length - 1))]}" echo "$path" done )) newPatches=( "${fromBaseBranch[@]}" "${uncommitted[@]}" ) # Checks new patches and exits with 1 if there are unapplied. hasUnapplied=0 for newPatch in "${newPatches[@]}"; do for unapp in "${unapplied[@]}"; do if [ "$unapp" == "$newPatch" ]; then echo "Recently added/changed but not applied: $unapp" hasUnapplied=1 break fi done done exit $hasUnapplied ;; v) verbose=1 ;; \?) echo "Invalid flag: -$OPTARG" >&2 exit ;; esac done applied=() echo -en "\\n" echo "Previously applied:" echo "===================" # Reverts every patch in reverse order to see # which was previously applied. for ((i=${#patches[@]}-1; i>=0; i--)); do f=${patches[$i]} git apply "$f" --directory="$basepath" -R > /dev/null 2>&1 if [ $? -eq 0 ]; then applied+=("$f") echo "$f" fi done echo "===================" echo -en "\\n" # Applies every patch from the beginning. for ((i=0; i<${#patches[@]}; i++)); do f=${patches[$i]} # If not applied, report it new. has=0 for patch in "${applied[@]}"; do if [ "$patch" == "$f" ]; then has=1 break fi done if [ $has -eq 0 ]; then echo "Applying new: $f" echo -en "\\n" fi if [ $verbose -eq 1 ]; then git apply "$f" --directory="$basepath" else git apply "$f" --directory="$basepath" > /dev/null 2>&1 fi if [ $? -eq 1 ]; then echo "Failed and reverting: $f" git apply "$f" --directory="$basepath" -R > /dev/null 2>&1 echo -en "\\n" exit fi done echo -en "\\n" echo "Done."