#!/bin/bash
### @accetto (https://github.com/accetto) (https://hub.docker.com/u/accetto/)

# ARG_POSITIONAL_INF([args],[Command arguments will be used as follows:\n \
#   args[0] - The file containing the line to be execute (required) \n \
#   args[1] - The number of the line to be executed (required) \n \
#   args[2] and above will be inserted after 'docker build', if found, or appended otherwise \n \
#])
# ARG_POSITIONAL_DOUBLEDASH([])
# ARG_OPTIONAL_SINGLE([lines],[],[Number of header lines to display],[10])
# ARG_OPTIONAL_BOOLEAN([echo],[],[Just print the command line to be executed])
# ARG_VERSION([echo $0 v20.10.04])
# ARG_HELP([Displays the file head and executes the chosen line, removing the first occurrence of '#' and trimming it from the left first.\nProviding the line number argument skips the interaction and executes the given line directly.])
# ARGBASH_SET_INDENT([  ])
# ARGBASH_GO()
# needed because of Argbash --> m4_ignore([
### START OF CODE GENERATED BY Argbash v2.8.1 one line above ###
# Argbash is a bash code generator used to get arguments parsing right.
# Argbash is FREE SOFTWARE, see https://argbash.io for more info


die()
{
  local _ret="${2:-1}"
  test "${_PRINT_HELP:-no}" = yes && print_help >&2
  echo "$1" >&2
  exit "${_ret}"
}


begins_with_short_option()
{
  local first_option all_short_options='vh'
  first_option="${1:0:1}"
  test "$all_short_options" = "${all_short_options/$first_option/}" && return 1 || return 0
}

# THE DEFAULTS INITIALIZATION - POSITIONALS
_positionals=()
_arg_args=()
# THE DEFAULTS INITIALIZATION - OPTIONALS
_arg_lines="10"
_arg_echo="off"


print_help()
{
  printf '%s\n' "Displays the file head and executes the chosen line, removing the first occurrence of '#' and trimming it from the left first.
Providing the line number argument skips the interaction and executes the given line directly."
  printf 'Usage: %s [--lines <arg>] [--(no-)echo] [-v|--version] [-h|--help] [--] [<args-1>] ... [<args-n>] ...\n' "$0"
  printf '\t%s\n' "<args>: Command arguments will be used as follows:
		 \
#   args[0] - The file containing the line to be execute (required)
		 \
#   args[1] - The number of the line to be executed (required)
		 \
#   args[2] and above will be inserted after 'docker build', if found, or appended otherwise
		 \
#"
  printf '\t%s\n' "--lines: Number of header lines to display (default: '10')"
  printf '\t%s\n' "--echo, --no-echo: Just print the command line to be executed (off by default)"
  printf '\t%s\n' "-v, --version: Prints version"
  printf '\t%s\n' "-h, --help: Prints help"
}


parse_commandline()
{
  _positionals_count=0
  while test $# -gt 0
  do
    _key="$1"
    if test "$_key" = '--'
    then
      shift
      test $# -gt 0 || break
      _positionals+=("$@")
      _positionals_count=$((_positionals_count + $#))
      shift $(($# - 1))
      _last_positional="$1"
      break
    fi
    case "$_key" in
      --lines)
        test $# -lt 2 && die "Missing value for the optional argument '$_key'." 1
        _arg_lines="$2"
        shift
        ;;
      --lines=*)
        _arg_lines="${_key##--lines=}"
        ;;
      --no-echo|--echo)
        _arg_echo="on"
        test "${1:0:5}" = "--no-" && _arg_echo="off"
        ;;
      -v|--version)
        echo $0 v20.10.04
        exit 0
        ;;
      -v*)
        echo $0 v20.10.04
        exit 0
        ;;
      -h|--help)
        print_help
        exit 0
        ;;
      -h*)
        print_help
        exit 0
        ;;
      *)
        _last_positional="$1"
        _positionals+=("$_last_positional")
        _positionals_count=$((_positionals_count + 1))
        ;;
    esac
    shift
  done
}


assign_positional_args()
{
  local _positional_name _shift_for=$1
  _positional_names=""
  _our_args=$((${#_positionals[@]} - 0))
  for ((ii = 0; ii < _our_args; ii++))
  do
    _positional_names="$_positional_names _arg_args[$((ii + 0))]"
  done

  shift "$_shift_for"
  for _positional_name in ${_positional_names}
  do
    test $# -gt 0 || break
    eval "$_positional_name=\${1}" || die "Error during argument parsing, possibly an Argbash bug." 1
    shift
  done
}

parse_commandline "$@"
assign_positional_args 1 "${_positionals[@]}"

# OTHER STUFF GENERATED BY Argbash

### END OF CODE GENERATED BY Argbash (sortof) ### ])
# [ <-- needed because of Argbash

### #########################
### CUSTOM CODE BEGEINGS HERE
### #########################

main() {
  local _cmd=""
  local _file=""
  local _input=""
  local _leftovers=""
  local _key=''
  local -i _line=0
  local -i _size=10

  [[ ${#_arg_args[@]} -lt 2 ]] && die "FAILED: First two arguments are mandatory!"

  _file="${_arg_args[0]}"

  _line=${_arg_args[1]}
  [[ ${_line} -le 0 ]] && _line=0

  [[ ! -f "${_file}" ]] && die "FAILED: File \"${_file}\" not found!"

  [[ ${#_arg_args[@]} -gt 2 ]] && _leftovers="${_arg_args[@]:2}"

  _size=$(wc -l <"${_file}")
  [[ ${_size} -gt ${_arg_lines} ]] && _size=${_arg_lines}

  if [[ ${_line} -le 0 ]]; then
    ### output the header numbering the lines
    head -n ${_size} "${_file}" | cat -n

    ### get the line number
    read -rp $'Which line to execute? ' _input
    _input=$(echo ${_input} | grep -E "^[0-9]+$")
    [[ ${_input} ]] && _line=${_input} || die "INTERRUPTED: Numeric input required!"
    [[ ${_line} -lt 1 || ${_line} -gt ${_size} ]] && die "FAILED: The line number must be from the interval [1..${_size}]!"
  fi

  ### get the command line, remove the first '#' and trim it from the left
  _cmd=$(sed "${_line}q;d" "${_file}")
  _cmd=$(echo "${_cmd}" | sed -r -e 's/^\s*#\s*//g')

  ### add the leftover arguments to the command line
  if [[ -n "${_leftovers}" ]] ; then
    if [[ "${_cmd}" =~ 'docker build' ]] ; then
      ### insert the leftovers after 'docker build'
      _cmd=$(echo "${_cmd}" | sed -r -e "s/docker build/docker build ${_leftovers}/g" )
    else
      ### just append the leftovers
      _cmd="${_cmd} ${_arg_args[@]:2}"
    fi
  fi

  ### display the command to be executed
  echo "${_cmd}"

  if [[ ${_line} -eq 0 && "${_arg_echo}" = "off" ]]; then
    ### ask for user confirmation
    read -rp $'Execute the line above? (y) ' -n1 _key
    echo
    # [[ "${_key,,}" != "y" ]] && die "INTERRUPTED"   ## not working on qnas
    [[ "${_key}" != "y" ]] && die "INTERRUPTED"
  fi

  if [[ "${_arg_echo}" == "off" ]]; then
    eval "${_cmd}"
  fi
}

main $@

# ] <-- needed because of Argbash
