#!/bin/bash
#==================================================================================
#
#          FILE: outset-pkg
#
#         USAGE: outset-pkg --all [<options>] | --file <filename> [<options>]
#
#   DESCRIPTION: Creates a PKG of /usr/local/outset processing directories 
#                Either for one file or package the entire structure 
#
#         NOTES: ---
#        AUTHOR: Bart Reardon
#  ORGANIZATION: Macadmins Open Source
#       CREATED: 2023-03-23
#      REVISION: 1.0.2
#
#       COPYRIGHT: (C) Macadmins Open Source 2023. All rights reserved.
#
#==================================================================================

FILE_TO_PACKAGE=""
FILE_TARGET="login-once"
BUILD_ALL=false
POSTINSTALL_SCRIPT=false
MAKE_EXECUTABLE=false
POSTINSTALL_SCRIPT_FILE=""
BUILD_DIRECTORY="/var/tmp/outset"

PKGTITLE="Outset Custom Content"
PKG_DOMAIN="io.macadmins.Outset"
PKGVERSION="1.0"
PKGID="${PKG_DOMAIN}.custom-content"

OUTSET_ROOT="/usr/local/outset"
PGKROOT="${BUILD_DIRECTORY}/PGKROOT"
SCRIPT_DIR="${PGKROOT}/scripts"
PKGNAME="outset-custom-content"
ONDEMAND_POSTINSTALL=$(cat <<EOF
#!/bin/bash
trigger="/private/tmp/.io.macadmins.outset.ondemand.launchd"
[[ \$3 != "/" ]] && exit 0
/usr/bin/touch "\${trigger}"
exit 0
EOF
)

printUsage() {
    echo "OVERVIEW: ${0##*/} is a utility that packages files for use in outset workflows."
    echo ""
    echo "USAGE: ${0##*/} --all [<options>] | --file <filename> [<options>]"
    echo ""
    echo "OPTIONS:"
    echo "    -a, --all                 Package all scripts from outset processing directories into one package"
    echo "    -f, --file <filename>     Package the selected file"
    echo "    -x, --make-executable     Ensure the selected file executable bit is set (only applies to script files)"
    echo "    -t, --target <directory>  Target processing directory (default 'login-once')"
    echo "    -s, --postinstall-script [<filename>]"
    echo "                              Include a postinstall script. If no argument is given, a standard postinstall"
    echo "                              script to trigger on-demand will be included."
    echo "    -v, --version, <number>   Set package version to the selected number (default is '1.0')"
    echo "    -p, --build-path, <path>  Path to use as the build location (default ${BUILD_DIRECTORY})"
    echo "    -h, --help                Print this message"
    echo ""
}

validateVersion() {
    # Regular expression to match a version number
    regex='^[0-9]+([.][0-9]+)*$'

    # Check if the string matches the regular expression
    if [[ $1 =~ $regex ]]; then
        echo $1
    else
        return 1
    fi
}

validateTarget() {
    targetList=($(ls -d ${OUTSET_ROOT}/login-* ${OUTSET_ROOT}/boot-* ${OUTSET_ROOT}/on-*))
    for target in "${targetList[@]}"; do
        if [[ "${target##*/}" == "$1" ]]; then
            echo "${target##*/}"
            return 0
        fi
    done
    return 1
}

printValidTargets() {
    targetList=($(ls -d ${OUTSET_ROOT}/login-* ${OUTSET_ROOT}/boot-* ${OUTSET_ROOT}/on-*))
    echo "Invalid target name '$1'"
    echo "Valid targets:"
    for target in ${targetList[@]}; do
        echo "  [${target##*/}]"
    done
    exit 1
}

exitWithError() {
    echo "$1"
    exit 1
}

# if no arguments passed, print help and exit
if [[ "$#" -eq 0 ]]; then
    printUsage
    exit 0
fi

# Loop through named arguments
while [[ "$#" -gt 0 ]]; do
    case $1 in
        --file|-f) FILE_TO_PACKAGE="$2"; shift ;;
        --make-executable|-x) MAKE_EXECUTABLE=true ;;
        --target|-t) FILE_TARGET=$(validateTarget "$2") || printValidTargets "$2"; shift ;;
        --version|-v) PKGVERSION=$(validateVersion "$2") || exitWithError "invalid version number $2"; shift ;;
        --postinstall-script|-s) POSTINSTALL_SCRIPT_FILE="$2" && POSTINSTALL_SCRIPT=true
            # if the first character is a hyphen, then no argument was passed
            if [[ -z $POSTINSTALL_SCRIPT_FILE ]] || [[ "${POSTINSTALL_SCRIPT_FILE:0:1}" == "-" ]]; then
                POSTINSTALL_SCRIPT_FILE=""
            else
                shift
            fi
        ;;
        --build-path|-p)
            if [[ -e "$2" ]]; then 
                BUILD_DIRECTORY="${2%/}"
                PGKROOT="${BUILD_DIRECTORY}/PGKROOT"
            else
                exitWithError "path '$2' not found"
            fi
            shift
        ;;
        --help|-h|help) printUsage; exit 0 ;;
        --all|-a) BUILD_ALL=true ;;
        *) echo "Unknown argument: $1"; printUsage; exit 1 ;;
    esac
    shift
done
    
# create PGKROOT structure
mkdir -p "${PGKROOT}${OUTSET_ROOT}"

if $POSTINSTALL_SCRIPT; then
    mkdir -p "${SCRIPT_DIR}"
    if [[ -n $POSTINSTALL_SCRIPT_FILE ]]; then
        if [[ -e "${POSTINSTALL_SCRIPT_FILE}" ]]; then
            cp "${POSTINSTALL_SCRIPT_FILE}" "${SCRIPT_DIR}/postinstall"
        else
            exitWithError "${POSTINSTALL_SCRIPT_FILE} doesn't exist"
        fi
    else
        echo "${ONDEMAND_POSTINSTALL}" > "${SCRIPT_DIR}/postinstall"
    fi
    chmod 755 "${SCRIPT_DIR}/postinstall"
fi

if [[ -n $FILE_TO_PACKAGE ]]; then
    PKGID="${PKG_DOMAIN}.${FILE_TARGET}-${FILE_TO_PACKAGE##*/}"
    PKGNAME="outset-${FILE_TARGET}-${FILE_TO_PACKAGE##*/}_v${PKGVERSION}"
    TARGET_DIR="${PGKROOT}${OUTSET_ROOT}/${FILE_TARGET}/"
    
    mkdir -p "${TARGET_DIR}"
    
    if [[ -e "${FILE_TO_PACKAGE}" ]]; then
        cp "${FILE_TO_PACKAGE}" "${TARGET_DIR}"
        # if the file is not a pkg or dmg, make it executable
        if $MAKE_EXECUTABLE && [[ "${FILE_TO_PACKAGE##*.}" != "pkg" ]] && [[ "${FILE_TO_PACKAGE##*.}" != "dmg" ]]; then
            chmod 755 "${TARGET_DIR}/${FILE_TO_PACKAGE##*/}"
        fi
    else
        exitWithError "${FILE_TO_PACKAGE} doesn't exist"
    fi
elif $BUILD_ALL; then
    PKGNAME="outset-custom-content_v${PKGVERSION}"
    for folder in $(ls -d ${OUTSET_ROOT}/login-* ${OUTSET_ROOT}/boot-* ${OUTSET_ROOT}/on-*); do
        cp -r "${folder}" "${PGKROOT}${OUTSET_ROOT}"
    done
fi

# create package
TMP_PKG="${BUILD_DIRECTORY}/${PKGNAME}.component.pkg"
BUILD_PKG="${BUILD_DIRECTORY}/${PKGNAME}.pkg"

if $POSTINSTALL_SCRIPT; then
    /usr/bin/pkgbuild --root "${PGKROOT}" --scripts "${SCRIPT_DIR}" --identifier ${PKGID} --version ${PKGVERSION} "${TMP_PKG}"
else
    /usr/bin/pkgbuild --root "${PGKROOT}" --identifier ${PKGID} --version ${PKGVERSION} "${TMP_PKG}"
fi
/usr/bin/productbuild --identifier ${PKGID} --package "${TMP_PKG}" "${BUILD_PKG}"

# clean up
rm -r "${PGKROOT}"
rm "${TMP_PKG}"

# done
echo "Package has been created at ${BUILD_PKG}"
