280 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
		
		
			
		
	
	
			280 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| 
								 | 
							
								# This file provides:
							 | 
						||
| 
								 | 
							
								# - a default control flow
							 | 
						||
| 
								 | 
							
								#   * initializes the environment
							 | 
						||
| 
								 | 
							
								#   * able to mock "git push" in your script and in all sub scripts
							 | 
						||
| 
								 | 
							
								#   * call a function in your script based on the arguments
							 | 
						||
| 
								 | 
							
								# - named argument parsing and automatic generation of the "usage" for your script
							 | 
						||
| 
								 | 
							
								# - intercepting "git push" in your script and all sub scripts
							 | 
						||
| 
								 | 
							
								# - utility functions
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Usage:
							 | 
						||
| 
								 | 
							
								# - define the variable ARGS_DEF (see below) with the arguments for your script
							 | 
						||
| 
								 | 
							
								# - include this file using `source utils.inc` at the end of your script.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Default control flow:
							 | 
						||
| 
								 | 
							
								# 0. Set the current directory to the directory of the script. By this
							 | 
						||
| 
								 | 
							
								#    the script can be called from anywhere.
							 | 
						||
| 
								 | 
							
								# 1. Parse the named arguments
							 | 
						||
| 
								 | 
							
								# 2. If the parameter "git_push_dryrun" is set, all calls to `git push` in this script
							 | 
						||
| 
								 | 
							
								#    or in child scripts will be intercepted so that the `--dry-run` and `--porcelain` is added
							 | 
						||
| 
								 | 
							
								#    to show what the push would do but not actually do it.
							 | 
						||
| 
								 | 
							
								# 3. If the parameter "verbose" is set, the `-x` flag will be set in bash.
							 | 
						||
| 
								 | 
							
								# 4. The function "init" will be called if it exists
							 | 
						||
| 
								 | 
							
								# 5. If the parameter "action" is set, it will call the function with the name of that parameter.
							 | 
						||
| 
								 | 
							
								#    Otherwise the function "run" will be called.
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Named Argument Parsing:
							 | 
						||
| 
								 | 
							
								# - The variable ARGS_DEF defines the valid command arguments
							 | 
						||
| 
								 | 
							
								#   * Required args syntax: --paramName=paramRegex
							 | 
						||
| 
								 | 
							
								#   * Optional args syntax: [--paramName=paramRegex]
							 | 
						||
| 
								 | 
							
								#   * e.g. ARG_DEFS=("--required_param=(.+)" "[--optional_param=(.+)]")
							 | 
						||
| 
								 | 
							
								# - Checks that:
							 | 
						||
| 
								 | 
							
								#   * all arguments match to an entry in ARGS_DEF
							 | 
						||
| 
								 | 
							
								#   * all required arguments are present
							 | 
						||
| 
								 | 
							
								#   * all arguments match their regex
							 | 
						||
| 
								 | 
							
								# - Afterwards, every parameter value will be stored in a variable
							 | 
						||
| 
								 | 
							
								#   with the name of the parameter in upper case (with dash converted to underscore).
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Special arguments that are always available:
							 | 
						||
| 
								 | 
							
								# - "--action=.*": This parameter will be used to execute a function with that name when the
							 | 
						||
| 
								 | 
							
								#   script is started
							 | 
						||
| 
								 | 
							
								# - "--git_push_dryrun=true": This will intercept all calls to `git push` in this script
							 | 
						||
| 
								 | 
							
								#   or in child scripts so that the `--dry-run` and `--porcelain` is added
							 | 
						||
| 
								 | 
							
								#   to show what the push would do but not actually do it.
							 | 
						||
| 
								 | 
							
								# - "--verbose=true": This will set the `-x` flag in bash so that all calls will be logged
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# Utility functions:
							 | 
						||
| 
								 | 
							
								# - readJsonProp
							 | 
						||
| 
								 | 
							
								# - replaceJsonProp
							 | 
						||
| 
								 | 
							
								# - resolveDir
							 | 
						||
| 
								 | 
							
								# - getVar
							 | 
						||
| 
								 | 
							
								# - serVar
							 | 
						||
| 
								 | 
							
								# - isFunction
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# always stop on errors
							 | 
						||
| 
								 | 
							
								set -e
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function usage {
							 | 
						||
| 
								 | 
							
								  echo "Usage: ${0} ${ARG_DEFS[@]}"
							 | 
						||
| 
								 | 
							
								  exit 1
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function parseArgs {
							 | 
						||
| 
								 | 
							
								  local REQUIRED_ARG_NAMES=()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # -- helper functions
							 | 
						||
| 
								 | 
							
								  function varName {
							 | 
						||
| 
								 | 
							
								    # everything to upper case and dash to underscore
							 | 
						||
| 
								 | 
							
								    echo ${1//-/_} | tr '[:lower:]' '[:upper:]'
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function readArgDefs {
							 | 
						||
| 
								 | 
							
								    local ARG_DEF
							 | 
						||
| 
								 | 
							
								    local AD_OPTIONAL
							 | 
						||
| 
								 | 
							
								    local AD_NAME
							 | 
						||
| 
								 | 
							
								    local AD_RE
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # -- helper functions
							 | 
						||
| 
								 | 
							
								    function parseArgDef {
							 | 
						||
| 
								 | 
							
								      local ARG_DEF_REGEX="(\[?)--([^=]+)=(.*)"
							 | 
						||
| 
								 | 
							
								      if [[ ! $1 =~ $ARG_DEF_REGEX ]]; then
							 | 
						||
| 
								 | 
							
								        echo "Internal error: arg def has wrong format: $ARG_DEF"
							 | 
						||
| 
								 | 
							
								        exit 1
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								      AD_OPTIONAL="${BASH_REMATCH[1]}"
							 | 
						||
| 
								 | 
							
								      AD_NAME="${BASH_REMATCH[2]}"
							 | 
						||
| 
								 | 
							
								      AD_RE="${BASH_REMATCH[3]}"
							 | 
						||
| 
								 | 
							
								      if [[ $AD_OPTIONAL ]]; then
							 | 
						||
| 
								 | 
							
								        # Remove last bracket for optional args.
							 | 
						||
| 
								 | 
							
								        # Can't put this into the ARG_DEF_REGEX somehow...
							 | 
						||
| 
								 | 
							
								        AD_RE=${AD_RE%?}
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # -- run
							 | 
						||
| 
								 | 
							
								    for ARG_DEF in "${ARG_DEFS[@]}"
							 | 
						||
| 
								 | 
							
								    do
							 | 
						||
| 
								 | 
							
								      parseArgDef $ARG_DEF
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      local AD_NAME_UPPER=$(varName $AD_NAME)
							 | 
						||
| 
								 | 
							
								      setVar "${AD_NAME_UPPER}_OPTIONAL" "$AD_OPTIONAL"
							 | 
						||
| 
								 | 
							
								      setVar "${AD_NAME_UPPER}_RE" "$AD_RE"
							 | 
						||
| 
								 | 
							
								      if [[ ! $AD_OPTIONAL ]]; then
							 | 
						||
| 
								 | 
							
								        REQUIRED_ARG_NAMES+=($AD_NAME)
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								    done
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function readAndValidateArgs {
							 | 
						||
| 
								 | 
							
								    local ARG_NAME
							 | 
						||
| 
								 | 
							
								    local ARG_VALUE
							 | 
						||
| 
								 | 
							
								    local ARG_NAME_UPPER
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # -- helper functions
							 | 
						||
| 
								 | 
							
								    function parseArg {
							 | 
						||
| 
								 | 
							
								      local ARG_REGEX="--([^=]+)=?(.*)"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if [[ ! $1 =~ $ARG_REGEX ]]; then
							 | 
						||
| 
								 | 
							
								        echo "Can't parse argument $i"
							 | 
						||
| 
								 | 
							
								        usage
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      ARG_NAME="${BASH_REMATCH[1]}"
							 | 
						||
| 
								 | 
							
								      ARG_VALUE="${BASH_REMATCH[2]}"
							 | 
						||
| 
								 | 
							
								      ARG_NAME_UPPER=$(varName $ARG_NAME)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    function validateArg {
							 | 
						||
| 
								 | 
							
								      local AD_RE=$(getVar ${ARG_NAME_UPPER}_RE)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if [[ ! $AD_RE ]]; then
							 | 
						||
| 
								 | 
							
								        echo "Unknown option: $ARG_NAME"
							 | 
						||
| 
								 | 
							
								        usage
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if [[ ! $ARG_VALUE =~ ^${AD_RE}$ ]]; then
							 | 
						||
| 
								 | 
							
								        echo "Wrong format: $ARG_NAME"
							 | 
						||
| 
								 | 
							
								        usage;
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      # validate that the "action" option points to a valid function
							 | 
						||
| 
								 | 
							
								      if [[ $ARG_NAME == "action" ]] && ! isFunction $ARG_VALUE; then
							 | 
						||
| 
								 | 
							
								        echo "No action $ARG_VALUE defined in this script"
							 | 
						||
| 
								 | 
							
								        usage;
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # -- run
							 | 
						||
| 
								 | 
							
								    for i in "$@"
							 | 
						||
| 
								 | 
							
								    do
							 | 
						||
| 
								 | 
							
								      parseArg $i
							 | 
						||
| 
								 | 
							
								      validateArg
							 | 
						||
| 
								 | 
							
								      setVar "${ARG_NAME_UPPER}" "$ARG_VALUE"
							 | 
						||
| 
								 | 
							
								    done
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function checkMissingArgs {
							 | 
						||
| 
								 | 
							
								    local ARG_NAME
							 | 
						||
| 
								 | 
							
								    for ARG_NAME in "${REQUIRED_ARG_NAMES[@]}"
							 | 
						||
| 
								 | 
							
								    do
							 | 
						||
| 
								 | 
							
								      ARG_VALUE=$(getVar $(varName $ARG_NAME))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      if [[ ! $ARG_VALUE ]]; then
							 | 
						||
| 
								 | 
							
								        echo "Missing: $ARG_NAME"
							 | 
						||
| 
								 | 
							
								        usage;
							 | 
						||
| 
								 | 
							
								      fi
							 | 
						||
| 
								 | 
							
								    done
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # -- run
							 | 
						||
| 
								 | 
							
								  readArgDefs
							 | 
						||
| 
								 | 
							
								  readAndValidateArgs "$@"
							 | 
						||
| 
								 | 
							
								  checkMissingArgs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# getVar(varName)
							 | 
						||
| 
								 | 
							
								function getVar {
							 | 
						||
| 
								 | 
							
								  echo ${!1}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# setVar(varName, varValue)
							 | 
						||
| 
								 | 
							
								function setVar {
							 | 
						||
| 
								 | 
							
								  eval "$1=\"$2\""
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# isFunction(name)
							 | 
						||
| 
								 | 
							
								# - to be used in an if, so return 0 if successful and 1 if not!
							 | 
						||
| 
								 | 
							
								function isFunction {
							 | 
						||
| 
								 | 
							
								  if [[ $(type -t $1) == "function" ]]; then
							 | 
						||
| 
								 | 
							
								    return 0
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    return 1
							 | 
						||
| 
								 | 
							
								  fi
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# readJsonProp(jsonFile, property)
							 | 
						||
| 
								 | 
							
								# - restriction: property needs to be on a single line!
							 | 
						||
| 
								 | 
							
								function readJsonProp {
							 | 
						||
| 
								 | 
							
								  echo $(sed -En 's/.*"'$2'"[ ]*:[ ]*"(.*)".*/\1/p' $1)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# replaceJsonProp(jsonFile, propertyRegex, valueRegex, replacePattern)
							 | 
						||
| 
								 | 
							
								# - note: propertyRegex will be automatically placed into a
							 | 
						||
| 
								 | 
							
								#   capturing group! -> all other groups start at index 2!
							 | 
						||
| 
								 | 
							
								function replaceJsonProp {
							 | 
						||
| 
								 | 
							
								  replaceInFile $1 '"('$2')"[ ]*:[ ]*"'$3'"' '"\1": "'$4'"'
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# replaceInFile(file, findPattern, replacePattern)
							 | 
						||
| 
								 | 
							
								function replaceInFile {
							 | 
						||
| 
								 | 
							
								  sed -i .tmp -E "s/$2/$3/" $1
							 | 
						||
| 
								 | 
							
								  rm $1.tmp
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# resolveDir(relativeDir)
							 | 
						||
| 
								 | 
							
								# - resolves a directory relative to the current script
							 | 
						||
| 
								 | 
							
								function resolveDir {
							 | 
						||
| 
								 | 
							
								  echo $(cd $SCRIPT_DIR; cd $1; pwd)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function git_push_dryrun_proxy {
							 | 
						||
| 
								 | 
							
								  echo "## git push dryrun proxy enabled!"
							 | 
						||
| 
								 | 
							
								  export ORIGIN_GIT=$(which git)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function git {
							 | 
						||
| 
								 | 
							
									  local ARGS=("$@")
							 | 
						||
| 
								 | 
							
									  local RC
							 | 
						||
| 
								 | 
							
									  if [[ $1 == "push" ]]; then
							 | 
						||
| 
								 | 
							
									    ARGS+=("--dry-run" "--porcelain")
							 | 
						||
| 
								 | 
							
									    echo "####### START GIT PUSH DRYRUN #######"
							 | 
						||
| 
								 | 
							
								      echo "${ARGS[@]}"
							 | 
						||
| 
								 | 
							
									  fi
							 | 
						||
| 
								 | 
							
									  if [[ $1 == "commit" ]]; then
							 | 
						||
| 
								 | 
							
								      echo "${ARGS[@]}"
							 | 
						||
| 
								 | 
							
									  fi
							 | 
						||
| 
								 | 
							
									  $ORIGIN_GIT "${ARGS[@]}"
							 | 
						||
| 
								 | 
							
									  RC=$?
							 | 
						||
| 
								 | 
							
									  if [[ $1 == "push" ]]; then
							 | 
						||
| 
								 | 
							
									    echo "####### END GIT PUSH DRYRUN #######"
							 | 
						||
| 
								 | 
							
									  fi
							 | 
						||
| 
								 | 
							
									  return $RC
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  export -f git
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function main {
							 | 
						||
| 
								 | 
							
								  # normalize the working dir to the directory of the script
							 | 
						||
| 
								 | 
							
								  cd $(dirname $0);SCRIPT_DIR=$(pwd)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ARG_DEFS+=("[--git-push-dryrun=(true|false)]" "[--verbose=(true|false)]")
							 | 
						||
| 
								 | 
							
								  parseArgs "$@"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # --git_push_dryrun argument
							 | 
						||
| 
								 | 
							
								  if [[ $GIT_PUSH_DRYRUN == "true" ]]; then
							 | 
						||
| 
								 | 
							
								    git_push_dryrun_proxy
							 | 
						||
| 
								 | 
							
								  fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # --verbose argument
							 | 
						||
| 
								 | 
							
								  if [[ $VERBOSE == "true" ]]; then
							 | 
						||
| 
								 | 
							
								    set -x
							 | 
						||
| 
								 | 
							
								  fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if isFunction init; then
							 | 
						||
| 
								 | 
							
								    init "$@"
							 | 
						||
| 
								 | 
							
								  fi
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  # jump to the function denoted by the --action argument,
							 | 
						||
| 
								 | 
							
								  # otherwise call the "run" function
							 | 
						||
| 
								 | 
							
								  if [[ $ACTION ]]; then
							 | 
						||
| 
								 | 
							
								    $ACTION "$@"
							 | 
						||
| 
								 | 
							
								  else
							 | 
						||
| 
								 | 
							
								    run "$@"
							 | 
						||
| 
								 | 
							
								  fi
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								main "$@"
							 |