#! /bin/bash

. shell-args
. shell-error
. shell-quote

print_version()
{
    printf '%s version %s\n' "$1" "0.07"
    exit 0
}

show_usage()
{
    cat <<EOF

mkve-cache - install packages, create fake devices, run hooks, tarify

Usage: $PROG [options] [<path-to-workdir>] [packages]

Options:
  --output=PATH             path to target tarball;
  --hook=HOOK               a hook to run in chroot;
  --hsh-workdir=DIR         specify another working directory for hsh;
  --command=COMMAND         a command to run in chroot;
  --copy="FILE1 FILE2"      copy a file from host to chroot;
  --create-fake-devices      create additional fake devices;
  --no-tarify               do not tarify chroot;
  --tarify-only             do not try to create chroot;
  -z, --gzip                gzip output tarball;
  -q, --quiet               try to be more quiet;
  -v, --verbose             try to be more verbose;
  -V, --version             print program version and exit;
  -h, --help                show help text and exit.

EOF
}

show_help()
{
    which man >/dev/null 2>&1 &&
        man mkve-cache ||
        show_usage
    exit 0
}

# set internal variables
__my_output=
__my_comhoo_count=0
__my_gzip=
__my_hashdir="${TMPDIR}/hasher"
__my_create_fake_devices=
__my_no_tarify=
__my_tarify_only=

TEMP=$(getopt -o z${getopt_common_opts} -n ve-cache --long hook:,command:,copy:,output:,hsh-workdir:,gzip,create-fake-devices,no-tarify,tarify-only,${getopt_common_longopts} -- "$@")
eval set -- "${TEMP}"
while true; do
    case "$1" in
        --output)
            __my_output="$2"; shift
            ;;
        --hook)
            __my_comhoo_count=$(( __my_comhoo_count + 1 ))
            eval "__my_hook${__my_comhoo_count}=\"$(quote_shell "$2")\""
            eval "__my_command${__my_comhoo_count}=\"\""
            eval "__my_copy${__my_comhoo_count}=\"\""
            shift
            ;;
        --command)
            __my_comhoo_count=$(( __my_comhoo_count + 1 ))
            eval "__my_command${__my_comhoo_count}=\"$(quote_shell "$2")\""
            eval "__my_hook${__my_comhoo_count}=\"\""
            eval "__my_copy${__my_comhoo_count}=\"\""
            shift
            ;;
        --copy)
            __my_comhoo_count=$(( __my_comhoo_count + 1 ))
            eval "__my_command${__my_comhoo_count}=\"\""
            eval "__my_hook${__my_comhoo_count}=\"\""
            eval "__my_copy${__my_comhoo_count}=\"$(quote_shell "$2")\""
            shift
            ;;
        --hsh-workdir)
            __my_hashdir="$2"; shift
            ;;
        -z|--gzip)
            __my_gzip="--gzip"
            ;;
        --create-fake-devices)
            __my_create_fake_devices="true"
            ;;
        --no-tarify)
            __my_no_tarify="true"
            ;;
        --tarify-only)
            __my_tarify_only="true"
            ;;
        --) shift; break
            ;;
        *)
            parse_common_option "$1"
            ;;
    esac
    shift
done

#
# if --tarify-only specified, then remove all contradictory options
# and cleanup all arguments
#
if [ -n "${__my_tarify_only}" ]; then
    __my_comhoo_count=0
    __my_create_fake_devices=
    __my_no_tarify=
    while [ -n "$1" ]; do shift; done
fi

#
# If output name doesn't specified, set a default one
#
if [ -z "${__my_output}" ]; then
    [ -z "${__my_gzip}" ] &&
    __my_output="${TMPDIR}/output.tar" ||
    __my_output="${TMPDIR}/output.tar.gz"
fi

#
# Install hasher root. This root remains unchanged as far as somebody (or
# something) won't delete it (e.g., reboot, in case of tmpfs).
#
if [ -z "${__my_tarify_only}" ]; then
    message 'installing hasher root'
    [ -d "${__my_hashdir}" ] ||
        mkdir -p "${__my_hashdir}" ||
        fatal "Can't create directory ${__myhashdir}"
    hsh --save-fakeroot --initroot-only --pkg-build-list=, "${__my_hashdir}" ||
    fatal "Can't install hasher root"
fi

#
# Install additional packages. These packages will be tar'ed.
#
if [ -n "$1" ]; then
    message 'install packages' "$@"
    hsh-install -- "${__my_hashdir}" "$@" ||
    fatal "Can't install packages"
fi

#
# Create fake device files
#
if [ -n "${__my_create_fake_devices}" ]; then
    message 'create fake device files'

    # install sed, required by hsh-fakedev in chroot, if it doesn't yet
    hsh-run -- "${__my_hashdir}" rpmquery sed ||
    hsh-install -- "${__my_hashdir}" sed ||
    fatal "Can't install sed into chroot"

    hsh-fakedev -r /dev/tty -- "${__my_hashdir}" &&
    hsh-fakedev -- "${__my_hashdir}" /dev/console c 5 1 &&
    hsh-fakedev -r /dev/ptmx -- "${__my_hashdir}" ||
    fatal "Can't create fake device files"
fi

#
# copy files from host to chroot
#
copy_cleanup()
{
    rm -rf "${__my_hashdir}/chroot/.in/$1" ||
    { message "copyfiles: rm failed"; return 1; }
}

copyfiles()
{
    [ -n "$1" -a -n "$2" ] &&
    message "Copy file(s) host:$1 to chroot:$2" ||
    { message "copyfiles: not enough or empty arguments (1=\"$1\"; 2=\"$2\")"; return 1; }

    cp "$1" "${__my_hashdir}/chroot/.in" ||
    { message "copyfiles: cp failed"; copy_cleanup "$1"; return 1; }

    hsh-run --rooter ${__my_hashdir} -- cp "/.in/$(basename "$1")" "$2" ||
    { message "copyfiles: hsh-run failed"; copy_cleanup "$1"; return 1; }

    copy_cleanup "$1" || return 1
}

#
# Run commands and hooks specified by user, and copy files
#
if [ ${__my_comhoo_count} -gt 0 ]; then
    message 'run commands and hooks and copy files'

    __l_c=1
    while [ ${__l_c} -le ${__my_comhoo_count} ]; do
        eval __l_comm="\${__my_command${__l_c}}"
        eval __l_hook="\${__my_hook${__l_c}}"
        eval __l_copy="\${__my_copy${__l_c}}"
        if [ -n "${__l_comm}" ]; then
            message "Running command ${__l_comm}"
            eval hsh-run --root -- "${__my_hashdir}" ${__l_comm} ||
            fatal "running of command ${__l_comm} failed"
        elif [ -n "${__l_hook}" ]; then
            message "Running hook ${__l_hook}"
            eval hsh-run --root --execute "${__l_hook}" -- "${__my_hashdir}" ||
            fatal "running of hook ${__l_hook} failed"
        elif [ -n "${__l_copy}" ]; then
            copyfiles ${__l_copy} ||
            fatal "can't copy files ${__l_copy}"
        fi
        __l_c=$(( __l_c + 1 ))
    done
fi

#
# Tarify the tree
#
if [ -z "${__my_no_tarify}" ]; then
    message 'tarify'

    # install tar in chroot, if it doesn't yet
    hsh-run -- "${__my_hashdir}" rpmquery tar ||
    hsh-install -- "${__my_hashdir}" tar ||
    fatal "Can't install tar into chroot"

    # install gzip in chroot, if it doesn't yet
    if [ -n "${__my_gzip}" ]; then
        hsh-run -- "${__my_hashdir}" rpmquery gzip ||
        hsh-install -- "${__my_hashdir}" gzip ||
        fatal "Can't install gzip into chroot"
    fi

    __l_tarify=$(mktemp "${TMPDIR}/tarify.XXXXXX")
    cat >"${__l_tarify}" <<EOF
#!/bin/sh -e
cd /
tar ${__my_gzip} --create --file=- --numeric-owner --one-file-system --sparse -- *
EOF
    hsh-run --root --execute "${__l_tarify}" -- "${__my_hashdir}" >"${__my_output}" &&
    message "created tarball ${__my_output}" ||
    fatal "Can't tarify filesystem"

    message 'cleanup'
    rm -rf "${__l_tarify}"
fi

# vim:fdm=marker ts=4 sw=4 et
