#!/bin/bash
#
# @file tarb
#
# Creates a tarball of the current directory.
#
# Examples:
#   $ cd tarb-test
#   $ tarb          # create ../tarb-test.tar.gz
#   $ tarb -j       # create ../tarb-test.tar.bz2
#   $ tarb -d ~     # create ~/tarb-test.tar.gz
#
set -eu
set -o pipefail

tartool=gzip
tarcmd=z
suffix=.tar.gz
outdir=..
compression_level=
parallel=false

print_help() {
  cat << END
Usage: $(basename "$0") [OPTION...]
Options:
  -h, --help    print this help
  -z, --gzip    use gzip (default)
  -j, --bzip2   use bzip2
  -J, --xz      use xz
  -d DIR, --directory DIR
                write the archive to DIR (default: ..)
  -0, ..., -9, -11
                set compression level
  -p, --parallel
                parallel compression (pigz, lbzip2/pbzip2 required)
END
}

while [[ $# -gt 0 ]]; do
  key="$1"

  case $key in
    z|-z|--gzip)
      tartool=gzip
      tarcmd=z
      suffix=.tar.gz
      shift
      ;;
    j|-j|--bzip2)
      tartool=bzip2
      tarcmd=j
      suffix=.tar.bz2
      shift
      ;;
    J|-J|--xz)  # GNU tar 1.22
      tartool=xz
      tarcmd=J
      suffix=.tar.xz
      shift
      ;;
    -0)
      compression_level=0
      shift
      ;;
    -1)
      compression_level=1
      shift
      ;;
    -2)
      compression_level=2
      shift
      ;;
    -3)
      compression_level=3
      shift
      ;;
    -4)
      compression_level=4
      shift
      ;;
    -5)
      compression_level=5
      shift
      ;;
    -6)
      compression_level=6
      shift
      ;;
    -7)
      compression_level=7
      shift
      ;;
    -8)
      compression_level=8
      shift
      ;;
    -9)
      compression_level=9
      shift
      ;;
    -11)
      compression_level=11
      shift
      ;;
    -d|--directory)
      outdir="$2"
      shift
      shift
      ;;
    -p|--parallel)
      parallel=:
      shift
      ;;
    -h|--help)
      print_help
      exit 0
      ;;
    *)
      echo "error: unrecognized option $key" >&2
      print_help
      exit 1
      ;;
  esac
done

dirname=$(basename "$(pwd)")
tarname="$dirname$suffix"
parent_dir=$(cd .. && pwd)

extra_opts=

if $parallel; then
  case $tarcmd in
    z)
      if command -v pigz >/dev/null; then
        tartool=pigz
        tarcmd=
        extra_opts=-Ipigz
      else
        echo "error: option -p is specified, but pgzip is not available" >&2
        exit 1
      fi
      ;;
    j)
      if command -v lbzip2 >/dev/null; then
        tartool=lbzip2
        tarcmd=
        extra_opts=-Ilbzip2
      elif command -v pbzip2 >/dev/null; then
        tartool=pbzip2
        tarcmd=
        extra_opts=-Ipbzip2
      else
        echo "error: option -p is specified, but lbzip2/pbzip2 is not available" >&2
        exit 1
      fi
      ;;
    J)
      ;;
    *)
      echo "error: option -$tarcmd does not support parallel compression" >&2
      exit 1
      ;;
  esac
fi

case $tartool:$compression_level in
  gzip:0|gzip:11|bzip2:0|bzip2:11|lbzip2:0|lbzip2:11|pbzip2:0|pbzip2:11|xz:11)
    echo "error: $tartool doesn't support -$compression_level" >&2
    exit 1
    ;;
  pbzip2:?)
    echo "error: $tartool with -$compression_level not supported yet" >&2
    exit 1
    ;;
  *)
    ;;
esac

(
  cd "$outdir"
  echo "creating $outdir/$tarname..." >&2
  if [[ -n "$compression_level" ]]; then
    # gzip (deprecated) and pigz
    export GZIP=-$compression_level
    # bzip2 and lbzip2
    export BZIP2=-$compression_level
    # xz
    export XZ_OPT=-$compression_level
  fi
  if $parallel; then
    # xz
    export XZ_DEFAULTS=-T0
  fi
  tar -cv${tarcmd}f "$tarname.tmp$$" -C "$parent_dir" $extra_opts "$dirname"
  mv "$tarname.tmp$$" "$tarname"
  echo "created $outdir/$tarname ($(wc -c <"$tarname") bytes)" >&2
)