#!/bin/sh

CONFIG="$(pwd)/mkarchiso.conf" 
CPIOCONFIG="$(pwd)/archiso-mkinitcpio.conf"
DEF_CONFIG_DIR="$(pwd)/default-config"
QUIET="y"
FORCE="n"

command_name=""
work_dir=""
isoname=""

PKGDIR="."

APPNAME=$(basename "${0}")

if [ "$EUID" != "0" ]; then
    echo "This script must be run as root."
    exit 1
fi

usage ()
{
    echo "usage ${APPNAME} [options] command <command options>"
    echo " general options:"
    echo "    -c CONFIG        Use CONFIG file. default: /etc/archlive/mkarchiso.conf"
    echo "    -i CPIO CONFIG   Use CONFIG file for mkinitcpio. default: /etc/archlive/mkinitcpio.conf"
    echo "    -f               Force overwrite of working files / iso"
    echo "    -v               Verbose output. Default: no"
    echo "    -h               This message."
    echo " commands:"
    echo " install <working dir>        : where to build the ISO root"
    echo " squash <working dir>         : generate a squashfs image of the ISO root"
    echo " iso <working dir> <iso name> : build an iso from the working directory"
    echo " all <working dir> <iso name> : perform all of the above, in order"
    exit 1
}

while getopts 'c:i:fvh' arg; do
    case "${arg}" in
        c) CONFIG="${OPTARG}" ;;
        i) CPIOCONFIG="${OPTARG}" ;;
        f) FORCE="y" ;;
        v) QUIET="n" ;;
        h|?) usage ;;
        *) echo "invalid argument '${arg}'"; usage ;;
    esac
done
shift $(($OPTIND - 1))
echo "ARGS: $@"

[ $# -le 1 ] && usage

command_name="${1}"
case "${command_name}" in
    install) work_dir="${2}" ;;
    squash) work_dir="${2}" ;;
    iso) work_dir="${2}"; isoname="${3}" ;;
    all) work_dir="${2}"; isoname="${3}" ;;
    *) echo "invalid command name '${command_name}'"; usage ;;
esac

[ "x${work_dir}" = "x" ] && (echo "please specify a working directory" && usage)

#TODO - do we even need a config file?
if [ -e "${CONFIG}" ]; then
    source "${CONFIG}"
else
    echo "Config '${CONFIG}' does not exist, aborting..."
    exit 1
fi

# {{{ Build
isoroot="${work_dir}/iso"
instroot="${work_dir}/install"

_kversion ()
{
    source ${instroot}/etc/mkinitcpio.d/kernel26.kver
    echo ${ALL_kver}
}

_pacman ()
{
    if ! mkarchroot -f ${instroot} $*; then
        exit 1
    fi
}

install_pkgfile ()
{
    if [ -e "${1}" ]; then
        toinstall=""
        while read pkg; do
            echo $ignorepkgs | grep "\<$pkg\>" >/dev/null 2>&1 && continue
            toinstall="${toinstall} ${pkg}"
        done < ${1}
        _pacman "${toinstall}"
    fi
}

if [ "${command_name}" = "install" -o "${command_name}" = "all" ]; then
    if [ -e "${work_dir}" -a "${FORCE}" = "n" ]; then
        echo "Working dir '${work_dir}' already exists, aborting..."
        exit 1
    fi

    mkdir -p "${isoroot}"
    mkdir -p "${instroot}"

    echo "Installing 'base' packages..."
    install_pkgfile "${PKGDIR}/base.packages"

    echo "Installing custom packages..."
    for fil in ${package_files}; do
        #TODO search for file if not absolute...
        echo " Installing packages from file '$fil'"
        install_pkgfile "${fil}"
    done
    for pkg in ${additional_packages}; do
        echo "   Installing package '${pkg}'"
        _pacman "${pkg}"
    done

    echo "Installing kernel '${kernelpkg}'"
    if ! _pacman "${kernelpkg}" ; then
        echo "pacman failed to install '${kernelpkg}', aborting..."
        exit 1
    fi
    kernelver=$(_kversion)
    kernelsuffix=${kernelver##*-}
    echo "Kernel Version ${kernelver} (${kernelsuffix}) installed - installing modules..."
    install_pkgfile "modules.${kernelsuffix}"

    echo "Updating module dependancies"
    [ "${kernelsuffix}" = "ARCH" ] && kernelsuffix=""
    depmod -a -b "${instroot}" -v "${kernelver}" -F "${instroot}/boot/System.map26${kernelsuffix}" >/dev/null
    find "${instroot}/boot" -name *.img -delete #TODO, will this delete our special stuff?

    echo "Applying default configuration for the Arch ISO."
    cp -rfa ${DEF_CONFIG_DIR}/* "${instroot}"

    echo "Copyright (C) 2006, Arch Linux (Judd Vinet)" > "${instroot}/etc/copyright"

    echo "Creating initial device nodes "
    rm -f "${instroot}/dev/console" "${instroot}/dev/null" "${instroot}/dev/zero"
    mknod -m 644 "${instroot}/dev/console" c 5 1
    mknod -m 666 "${instroot}/dev/null" c 1 3
    mknod -m 666 "${instroot}/dev/zero" c 1 5 

    echo "Creating default home directory"
    mkdir -p "${instroot}/home/arch"

    # Cleanup
    echo "Cleaning up ISO root files..."
    find "${instroot}" -name *.pacnew -name *.pacsave -name *.pacorig -delete

    kill_dirs="var/abs var/cache/man var/cache/pacman var/log/* var/mail tmp usr/include initrd"
    for x in ${kill_dirs}; do
        if [ -e "${instroot}/${x}" ]; then
            rm -rf "${instroot}/${x}"
        fi
    done

    find "${instroot}/lib" -name *.a -delete
    find "${instroot}/usr/lib" -name *.a -delete

    # this actually takes up alot of space...
    for d in ${instroot}/var/lib/pacman/*; do
        [ "$(basename ${d})" != "local" ] && rm -rf "${d}"
    done

    if [ -e "${instroot}/boot" ]; then
        rm -rf "${isoroot}/boot"
        mv "${instroot}/boot" "${isoroot}"
    fi
fi

if [ "${command_name}" = "squash" -o "${command_name}" = "all" ]; then
    if [ -e "${isoroot}/archlive.sqfs" ]; then
        echo -n "Removing old squashfs image..."
        rm "${isoroot}/archlive.sqfs"
        echo "done."
    fi

    echo -n "Creating squashfs image. This may take some time..."
    start=$(date +%s)
    mksquashfs "${instroot}" "${isoroot}/archlive.sqfs" -root-owned > /dev/null
    echo "done in $(echo $start $(date +%s) | awk '{ printf "%0.2f",($2-$1)/60 }') minutes."
fi

if [ "${command_name}" = "iso" -o "${command_name}" = "all" ]; then
    [ "x${isoname}" = "x" ] && (echo "please specify an iso name" && usage)
    if [ -e "${isoname}" ]; then
        if [ "${FORCE}" = "y" ]; then
            rm -rf "${isoname}"
        else
            echo "ISO Image '${isoname}' already exists, aborting..."
            exit 1
        fi
    fi
    if [ ! -e "${CPIOCONFIG}" ]; then
        echo "mkinitcpio config '${CPIOCONFIG}' does not exist, aborting..."
        exit 1
    fi

    kernelver=$(_kversion)
    basedir=${instroot}
    [ "${instroot:0:1}" != "/" ] && basedir="$(pwd)/${instroot}"
    if ! mkinitcpio -c "${CPIOCONFIG}" -b "${basedir}" -k "${kernelver}"\
        -g "${isoroot}/boot/archlive.img"; then
        echo "initcpio image creation failed..."
        exit 1
    fi

    cp ${instroot}/usr/lib/grub/i386-pc/* "${isoroot}/boot/grub"

    echo "Creating ISO image..."
    q=""
    #[ "${QUIET}" = "y" ] && q="-q"
    mkisofs ${q} -r -l -b "boot/grub/stage2_eltorito" -uid 0 -gid 0 -no-emul-boot \
        -boot-load-size 4 -boot-info-table -publisher "Arch Linux <archlinux.org>" \
        -input-charset=UTF-8 -p "prepared by $NAME" -A "Arch Linux Live/Rescue CD" \
        -copyright /etc/copyright -o "${isoname}" "${isoroot}"
fi