#!/bin/sh

set -e

show_help() {
  cat << EOF

Simple tool to generate Mender Artifact suitable for single-file Update Module

Usage: $0 [options] file [-- [options-for-mender-artifact] ]

    Options: [ -n|artifact-name -t|--device-type -d|--dest-dir --software-name --software-version --software-filesystem -o|--output_path -h|--help ]

        --artifact-name       - Artifact name
        --device-type         - Target device type identification (can be given more than once)
        --dest-dir            - Target destination directory where to deploy the update
        --software-name       - Name of the key to store the software version: rootfs-image.NAME.version,
                                instead of rootfs-image.single-file.version
        --software-version    - Value for the software version, defaults to the name of the artifact
        --software-filesystem - If specified, is used instead of rootfs-image
        --output-path         - Path to output file. Default: file-install-artifact.mender
        --help                - Show help and exit
        file                  - Single file to bundle in the update

Anything after a '--' gets passed directly to the mender-artifact tool.

EOF
}

show_help_and_exit_error() {
  show_help
  exit 1
}

check_dependency() {
  if ! which "$1" > /dev/null; then
    echo "The $1 utility is not found but required to generate Artifacts." 1>&2
    return 1
  fi
}

if ! check_dependency mender-artifact; then
  echo "Please follow the instructions here to install mender-artifact and then try again: https://docs.mender.io/downloads#mender-artifact" 1>&2
  exit 1
fi

device_types=""
artifact_name=""
dest_dir=""
output_path="single-file-artifact.mender"
file=""
passthrough_args=""

while [ -n "$1" ]; do
  case "$1" in
    --device-type | -t)
      if [ -z "$2" ]; then
        show_help_and_exit_error
      fi
      device_types="$device_types $1 $2"
      shift 2
      ;;
    --artifact-name | -n)
      if [ -z "$2" ]; then
        show_help_and_exit_error
      fi
      artifact_name=$2
      shift 2
      ;;
    --dest-dir | -d)
      if [ -z "$2" ]; then
        show_help_and_exit_error
      fi
      dest_dir=$2
      shift 2
      ;;
    --software-name | --software-version | --software-filesystem)
      if [ -z "$2" ]; then
        show_help_and_exit_error
      fi
      passthrough_args="$passthrough_args $1 $2"
      shift 2
      ;;
    --output-path | -o)
      if [ -z "$2" ]; then
        show_help_and_exit_error
      fi
      output_path=$2
      shift 2
      ;;
    -h | --help)
      show_help
      exit 0
      ;;
    --)
      shift
      passthrough_args="$passthrough_args $@"
      break
      ;;
    -*)
      echo "Error: unsupported option $1"
      show_help_and_exit_error
      ;;
    *)
      if [ -n "$file" ]; then
        echo "File already specified. Unrecognized argument \"$1\""
        show_help_and_exit_error
      fi
      file="$1"
      shift
      ;;
  esac
done

if [ -z "${artifact_name}" ]; then
  echo "Artifact name not specified. Aborting."
  show_help_and_exit_error
fi

if [ -z "${device_types}" ]; then
  echo "Device type not specified. Aborting."
  show_help_and_exit_error
fi

if [ -z "${dest_dir}" ]; then
  echo "Destination dir not specified. Aborting."
  show_help_and_exit_error
fi

if [ -z "${file}" ]; then
  echo "File not specified. Aborting."
  show_help_and_exit_error
fi

# Check dest-dir is an absolute path
case $dest_dir in
  /*)
    ;;
  *)
    echo "Destination dir must be an absolute path. Aborting"
    exit 1
  ;;
esac

# Create tarball, accepts single file
filename=""
if [ -e "${file}" ]; then
  if [ -f "${file}" ]; then
    filename=$(basename $file)
  else
    echo "Error: \"${file}\" is not a regular file. Aborting."
    exit 1
  fi
else
  echo "Error: File \"${file}\" does not exist. Aborting."
  exit 1
fi

# Create required files for the Update Module
tmpdir=$(mktemp -d)
dest_dir_file="$tmpdir/dest_dir"
filename_file="$tmpdir/filename"
permissions_file="$tmpdir/permissions"

# Create dest_dir file in plain text
echo "$dest_dir" > $dest_dir_file

# Create single_file file in plain text
echo "$filename" > $filename_file

STAT_HAS_f=1;
stat -f %A "${file}" >/dev/null 2>&1 || STAT_HAS_f=0;

# Create permissions file in plain text
if [ $STAT_HAS_f -eq 1 ]; then
  stat -f %A "${file}" > $permissions_file
else
  stat -c %a "${file}" > $permissions_file
fi

# Check the the passthrough_args and potentially modify them
# to avoid conflicts or to let them override the already args
# provided to mender-artifact
# Runs in a subshell to allow overriding some parameters passed
# to mender-artifact
passthrough_args_modified=" "
echo -n $passthrough_args | xargs -n 2 printf "%s %s\n" | (while read -r flag arg; do
  if [ -n "$flag" ]; then
    case $flag in
      -T | --type)
        echo "Error: Conflicting flag '$flag'. Already specified by the script."
        exit 1
        ;;
      -o | --output-path)
        output_path=$arg
        ;;
      -n | --name)
        artifact_name=$arg
        ;;
      *)
        passthrough_args_modified="$passthrough_args_modified $flag $arg"
        ;;
    esac
  fi
done

mender-artifact write module-image \
  -T single-file \
  $device_types \
  -o "$output_path" \
  -n "$artifact_name" \
  -f "$dest_dir_file" \
  -f "$filename_file" \
  -f "$permissions_file" \
  -f "$file" \
  $passthrough_args_modified


echo "Artifact $output_path generated successfully:"
mender-artifact read $output_path
# End of subshell
)
rm -rf $tmpdir
exit 0
