diff options
| author | Tobias Bosch | 2014-01-06 12:19:51 -0800 | 
|---|---|---|
| committer | Tobias Bosch | 2014-01-06 12:27:54 -0800 | 
| commit | 5dc27959d5c0e45cc0cc6133a9ef676cc15d44bd (patch) | |
| tree | ecc31ec61ff67169774d529d487f819616638a01 /scripts/utils.inc | |
| parent | 4c21355940a98c7236a33d1b5e86d6cd3cf562cb (diff) | |
| download | angular.js-5dc27959d5c0e45cc0cc6133a9ef676cc15d44bd.tar.bz2 | |
chore(build): refactor build scripts in prepare/publish phase
Refactored all scripts so that they are divided into a `prepare`
and a `publish` phase. By this we can build, test, tag, commit
everything first. Only if all of this is ok we start pushing
to Github. By this we keep Github consistent even in error cases.
Extracted include script `/scripts/utils.inc`:
- parse and validate named arguments in the style
  `--name=value`
- proxy git command and deactivate `git push` based on
  command option `--git_push_dry_run=true`
  (will be inherited to child scripts)
- enable/disable bash debug mode by command option
  `--verbose=true`
- dispatch to functions based on command option
  `--action=...`
- helper functions for dealing with json files
Diffstat (limited to 'scripts/utils.inc')
| -rw-r--r-- | scripts/utils.inc | 273 | 
1 files changed, 273 insertions, 0 deletions
| diff --git a/scripts/utils.inc b/scripts/utils.inc new file mode 100644 index 00000000..0465de8f --- /dev/null +++ b/scripts/utils.inc @@ -0,0 +1,273 @@ +# 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 the `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 paramter 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 dispatch to 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 + + +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 an own 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 { +  sed -i .tmp -E 's/"('$2')"[ ]*:[ ]*"'$3'"/"\1": "'$4'"/' $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 var +	  ARGS=("$@") +	  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[@]}" +	  if [[ $1 == "push" ]]; then +	    echo "####### END GIT PUSH DRYRUN #######" +	  fi +  } + +  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]" "[--verbose=true]") +  parseArgs "$@" + +  # --git_push_dryrun argument +  if [[ $GIT_PUSH_DRYRUN ]]; then +    git_push_dryrun_proxy +  fi + +  # stop on errors +  set -e + +  # --verbose argument +  if [[ $VERBOSE ]]; 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 "$@" | 
