Misc cleanups, shellcheck warnings.

helmrepo.sh
-----------
  o Use readarray -t to slurp command output.
  o Replace while read -r with for loop iteration over named vars.
  o Replace awk/string parsing with bash builtin string functions
    (added insulation against external shell command failures).
  o Added several functions to shorten all-code-in-main-program.
  o Added functions func_echo() and error() for formatted output.
  o Arguments --debug, --dry-run and --help added.
  o 'helm package' command functions added to support --dry-run use.
  o Detect and error on Chart.yaml files that lack 'version:'.
  o chart_yaml_diff - differentiate no_diff case from error induced.

Change-Id: I54d4f1e71291899540ec0f339ee9e033ca62a443
diff --git a/helmrepo.sh b/helmrepo.sh
index 56808c0..230ae1f 100755
--- a/helmrepo.sh
+++ b/helmrepo.sh
@@ -20,7 +20,9 @@
 
 set -eu -o pipefail
 
-echo "# helmrepo.sh, using helm: $(helm version -c) #"
+##-------------------##
+##---]  GLOBALS  [---##
+##-------------------##
 
 # when not running under Jenkins, use current dir as workspace
 WORKSPACE=${WORKSPACE:-.}
@@ -31,6 +33,162 @@
 
 PUBLISH_URL="${PUBLISH_URL:-charts.opencord.org}"
 
+## -----------------------------------------------------------------------
+## Intent: Dispay called function with given output
+## -----------------------------------------------------------------------
+function func_echo()
+{
+    echo "** ${FUNCNAME[1]}: $*"
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Display given text and exit with shell error status.
+## -----------------------------------------------------------------------
+function error()
+{
+    echo "** ${BASH_SOURCE[0]}::${FUNCNAME[1]} ERROR: $*"
+    exit 1
+}
+
+## -----------------------------------------------------------------------
+## Intent: Gather a list of Chart.yaml files from the filesystem.
+## -----------------------------------------------------------------------
+function get_chart_yaml()
+{
+    local dir="$1"    ; shift
+    declare -n ref=$1 ; shift
+
+    readarray -t _charts < <(find "$dir" -name Chart.yaml -print | sort)
+    ref=("${_charts[@]}")
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Update helm package dependencies
+## -----------------------------------------------------------------------
+function helm_deps_update()
+{
+    local dest="$1"; shift    # helm --destination
+
+    if [[ -v dry_run ]]; then
+	func_echo "helm package --dependency-update --destination $dest $chartdir"
+    else
+	helm package --dependency-update --destination "$dest" "$chartdir"
+    fi
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Update helm package index
+## -----------------------------------------------------------------------
+function helm_index_publish()
+{
+    local repo_dir="$1"; shift    # helm --destination
+
+    if [[ -v dry_run ]]; then
+	func_echo "helm repo index $repo_dir --url https://${PUBLISH_URL}"
+    else
+	helm repo index "$repo_dir" --url https://"${PUBLISH_URL}"
+    fi
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Update helm package index
+## -----------------------------------------------------------------------
+function helm_index_merge()
+{
+    local old_repo="$1" ; shift
+    local new_repo="$1" ; shift
+
+    declare -a cmd=()
+    cmd+=('helm' 'repo' 'index')
+    cmd+=('--url' "https://${PUBLISH_URL}")
+    cmd+=('--merge' "${old_repo}/index.yaml" "$new_repo")
+
+    if [[ -v dry_run ]]; then
+	func_echo "${cmd[@]}"
+    else
+	"${cmd[@]}"
+    fi
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Given a Chart.yaml file path return test directory where stored
+## -----------------------------------------------------------------------
+function chart_path_to_test_dir()
+{
+    local val="$1"    ; shift
+
+# shellcheck disable=SC2178 
+   declare -n ref=$1 ; shift # indirect var
+
+    val="${val%/Chart.yaml}"  # dirname: prune /Chart.yaml
+    val="${val##*/}"          # basename: test directory
+
+# shellcheck disable=SC2034,SC2178
+    ref="$val"                # Return value to caller
+    return
+}
+
+## -----------------------------------------------------------------------
+## Intent: Given a Chart.yaml file path return test directory where stored
+## -----------------------------------------------------------------------
+function create_helm_repo_new()
+{
+    local repo_dir="$1"; shift # NEW_REPO_DIR
+    local work_dir="$1"; shift # WORKSPACE
+
+    echo "Creating new helm repo: ${repo_dir}"
+
+    declare -a charts=()
+    get_chart_yaml "$work_dir" charts
+
+    local chart
+    for chart in "${charts[@]}";
+    do
+	echo
+	func_echo "Chart.yaml: $chart"
+	
+	chartdir=''
+	chart_path_to_test_dir "$chart" chartdir
+	func_echo " Chart.dir: $chartdir"
+	
+	helm_deps_update "${repo_dir}"
+    done
+    
+    helm_index_publish "${repo_dir}"
+    return
+}
+
+##----------------##
+##---]  MAIN  [---##
+##----------------##
+
+while [ $# -gt 0 ]; do
+    arg="$1"; shift
+
+    case "$arg" in
+	-*debug) declare -g -i debug=1     ;;
+	-*dry*)  declare -g -i dry_run=1   ;;
+	-*help)
+	    cat <<EOH
+Usage: $0
+  --debug       Enable debug mode
+  --dry-run     Simulate helm calls
+EOH
+	    ;;	
+	
+	-*) echo "[SKIP] unknown switch [$arg]" ;;
+	*) echo "[SKIP] unknown argument [$arg]" ;;
+    esac
+done
+
+
+echo "# helmrepo.sh, using helm: $(helm version -c) #"
+
 # create and clean NEW_REPO_DIR
 mkdir -p "${NEW_REPO_DIR}"
 rm -f "${NEW_REPO_DIR}"/*
@@ -38,67 +196,104 @@
 # if OLD_REPO_DIR doesn't exist, generate packages and index in NEW_REPO_DIR
 if [ ! -d "${OLD_REPO_DIR}" ]
 then
-  echo "Creating new helm repo: ${NEW_REPO_DIR}"
-
-  while IFS= read -r -d '' chart
-  do
-    chartdir=$(dirname "${chart#${WORKSPACE}/}")
-    helm package --dependency-update --destination "${NEW_REPO_DIR}" "${chartdir}"
-
-  done < <(find "${WORKSPACE}" -name Chart.yaml -print0)
-
-  helm repo index "${NEW_REPO_DIR}" --url https://"${PUBLISH_URL}"
-  echo "# helmrepo.sh Success! Generated new repo index in ${NEW_REPO_DIR}"
+    create_helm_repo_new "$NEW_REPO_DIR" "$WORKSPACE"
+    echo
+    echo "# helmrepo.sh Success! Generated new repo index in ${NEW_REPO_DIR}"
 
 else
   # OLD_REPO_DIR exists, check for new charts and update only with changes
   echo "Found existing helm repo: ${OLD_REPO_DIR}, attempting update"
 
   # Loop and create chart packages, only if changed
-  while IFS= read -r -d '' chart
+  declare -a charts=()
+  get_chart_yaml "$WORKSPACE" charts
+
+  for chart in "${charts[@]}";
   do
-    chartdir=$(dirname "${chart#${WORKSPACE}/}")
+      echo
+      func_echo "Chart.yaml: $chart"
 
-    # See if chart version changed from previous HEAD commit
-    chart_yaml_diff=$(git diff -p HEAD^ -- "${chartdir}/Chart.yaml")
+      chartdir=''
+      chart_path_to_test_dir "$chart" chartdir
+      func_echo " Chart.dir: $chartdir"
 
-    if [ -n "$chart_yaml_diff" ]
-    then
-      # assumes that helmlint.sh and chart_version_check.sh have been run
-      # pre-merge, which ensures that all charts are valid and have their
-      # version updated in Chart.yaml
-      new_version_string=$(echo "$chart_yaml_diff" | awk '/^\+version:/ { print $2 }')
-      echo "New version of chart ${chartdir}, creating package: ${new_version_string//+version:/}"
-      helm package --dependency-update --destination "${NEW_REPO_DIR}" "${chartdir}"
-    else
-      echo "Chart unchanged, not packaging: '${chartdir}'"
-    fi
+      # See if chart version changed from previous HEAD commit
+      readarray -t chart_yaml_diff < <(git diff -p HEAD^ -- "$chart")
+      
+      if [[ ! -v chart_yaml_diff ]]; then
+	  echo "Chart unchanged, not packaging: '${chartdir}'"
 
-  done < <(find "${WORKSPACE}" -name Chart.yaml -print0)
+      elif [ ${#chart_yaml_diff} -gt 0 ]; then
+	  # assumes that helmlint.sh and chart_version_check.sh have been run
+	  # pre-merge, which ensures that all charts are valid and have their
+	  # version updated in Chart.yaml
 
+	  [[ -v new_version_string ]] && unset new_version_string
+
+	  for line in "${chart_yaml_diff[@]}";
+	  do
+	      [[ -v debug ]] && func_echo "$line"
+
+	      case "$line" in
+		  # "-version: \"1.0.3\""
+		  -version:*)
+		      [[ ! -v debug ]] && func_echo "$line"
+		      ;;
+
+		  # "+version: \"1.0.4\""
+		  +version:*)
+		      [[ ! -v debug ]] && func_echo "$line"
+
+		      readarray -d':' -t _fields <<<"$line" # split on delimiter
+		      val="${_fields[1]}"
+		      val="${val//[[:blank:]]}"
+		      
+		      # error detection: only assign when we have a value.
+		      [ ${#val} -gt 0 ] && new_version_string="$val"
+		      break
+		      ;;
+	      esac
+	  done
+
+	  [[ ! -v new_version_string ]] && error "Failed to detect version: in $chart"
+
+	  echo "New version of chart ${chartdir}, creating package: ${new_version_string}"
+
+	  helm_deps_update "1${NEW_REPO_DIR}"
+
+      else
+	  echo "Chart unchanged, not packaging: '${chartdir}'"
+      fi    
+  done
+
+  ## -----------------------------------------------------------------------
+  ## -----------------------------------------------------------------------
+  readarray -t package_paths < <(find "${NEW_REPO_DIR}" -name '*.tgz' -print)
+  declare -p package_paths
+  
   # Check for collisions between old/new packages
-  while IFS= read -r -d '' package_path
+  #  while IFS= read -r -d '' package_path
+  for package_path in "${package_paths[@]}";
   do
-    package=$(basename "${package_path}")
+      package="${package_path##*/}" # basename
 
-    if [ -f "${OLD_REPO_DIR}/${package}" ]
-    then
-      echo "# helmrepo.sh Failure! Package: ${package} with same version already exists in ${OLD_REPO_DIR}"
-      exit 1
-    fi
-  done < <(find "${NEW_REPO_DIR}" -name '*.tgz' -print0)
+      [ -f "${OLD_REPO_DIR}/${package}" ] \
+	  && error "Package: ${package} with same version already exists in ${OLD_REPO_DIR}"
+  done
+  
+  ## -----------------------------------------------------------------------
+  ## -----------------------------------------------------------------------
+  # only update index when new charts are added
+  if [ ${#package_paths[@]} -gt 0 ]; then
 
-  # only update index if new charts are added
-  if ls "${NEW_REPO_DIR}"/*.tgz > /dev/null 2>&1;
-  then
-    # Create updated index.yaml (new version created in NEW_REPO_DIR)
-    helm repo index --url "https://${PUBLISH_URL}" --merge "${OLD_REPO_DIR}/index.yaml" "${NEW_REPO_DIR}"
+      # Create updated index.yaml (new version created in NEW_REPO_DIR)
+      helm_index_merge "${OLD_REPO_DIR}" "${NEW_REPO_DIR}"
 
-    # move over packages and index.yaml
-    mv "${NEW_REPO_DIR}"/*.tgz "${OLD_REPO_DIR}/"
-    mv "${NEW_REPO_DIR}/index.yaml" "${OLD_REPO_DIR}/index.yaml"
+      # move over packages and index.yaml
+      mv "${NEW_REPO_DIR}"/*.tgz "${OLD_REPO_DIR}/"
+      mv "${NEW_REPO_DIR}/index.yaml" "${OLD_REPO_DIR}/index.yaml"
 
-    echo "# helmrepo.sh Success! Updated existing repo index in ${OLD_REPO_DIR}"
+      echo "# helmrepo.sh Success! Updated existing repo index in ${OLD_REPO_DIR}"
 
   else
     echo "# helmrepo.sh Success! No new charts added."