#!/bin/sh
# ebs build system
# build xpt packages from ebs formulae

set -eu
if (set -o pipefail) 2>/dev/null; then
    set -o pipefail
fi


if command -v aria2c > /dev/null 2>&1; then
    download() {
        aria2c -o "$2" "$1"
    }
    DLPROG="aria2c"
elif command -v wget >/dev/null 2>&1; then
    download() {
        wget -O "$2" "$1"
    }
    DLPROG="wget"
elif command -v curl >/dev/null 2>&1; then
    download() {
        curl -L -o "$2" "$1" --progress-bar
    }
    DLPROG="curl"
else
    echo "no url transfer program found, tried"
    echo "aria2c, wget, curl"
    exit 1
fi

if [ "${1:-}" = "" ]; then
    echo "usage: ebs <command> [arguments]"
    exit 1
fi

print_ebs_help() {
    echo "ebs: ebs build system"
    echo "build xpt packages from ebs formulae"
    echo "usage: ebs <command> [arguments]"
    echo "commands"
    echo "  help    show this message"
    echo "  build   build from an ebs formula"
    echo "  buildt  build from an ebs formula and install to the toolchain specified in \$TOOLCHAIN_DIR"
    echo "part of ebt build tools (ebt)"
}

createTreefile() {
    if [ ! -d "$1" ]; then
        echo "directory $1 does not exist" >&2
        return 1
    fi

    dir="$1"
    tmpd=""

    rm -f "$dir/xpt.tree"
    if [ -f "$dir/xpt.manifest" ]; then
        tmpd=$(mktemp)
        mv "$dir/xpt.manifest" "$tmpd"
    fi
    tree=$(cd "$dir" && find . \( -type f -o -type l \) | sed 's|^\./||')
    echo "$tree" > "$dir/xpt.tree"
    if [ -n "$tmpd" ] && [ -f "$tmpd" ]; then
        mv "$tmpd" "$dir/xpt.manifest"
    fi
    echo "successfully created a treefile for $dir"
}

extract_source() {
    archive="$1"
    builddir="$2"

    mkdir -p "$builddir"

    case "$archive" in
        *.tar.gz|*.tgz)
            command -v tar >/dev/null 2>&1 || { echo "! tar not found"; exit 1; }
            tar -xzf "$archive" -C "$builddir"
            ;;
        *.tar.xz)
            command -v tar >/dev/null 2>&1 || { echo "! tar not found"; exit 1; }
            tar -xJf "$archive" -C "$builddir"
            ;;
        *.tar.bz2)
            command -v tar >/dev/null 2>&1 || { echo "! tar not found"; exit 1; }
            tar -xjf "$archive" -C "$builddir"
            ;;
        *.zip)
            command -v unzip >/dev/null 2>&1 || { echo "! unzip not found"; exit 1; }
            unzip "$archive" -d "$builddir"
            ;;
        *)
            echo "! unsupported archive format: $archive"
            exit 1
            ;;
    esac
}

build_formula() {
    initdir="$(pwd)"
    formula_script="${1:-ebs.formulae}"

    case "$formula_script" in
        /*) formula_path="$formula_script" ;;
        *)  formula_path="$initdir/$formula_script" ;;
    esac

    if ! [ -f "$formula_path" ]; then
        echo "! formula $formula_path does not exist"
        exit 1
    fi
    . "$formula_path"
    [ -n "$ebsver" ] || { echo "! ebsver not set in $formula_script"; exit 1; }

    case "$ebsver" in
        1) ;;
        *) echo "! incompatible ebs formula version"; exit 1 ;;
    esac

    echo "* validating formula"

    command -v build >/dev/null 2>&1 || { echo "! build not found in $formula_script"; exit 1; }
    command -v package >/dev/null 2>&1 || { echo "! package not found in $formula_script"; exit 1; }
    [ -n "$pkgname" ] || { echo "! pkgname not set in $formula_script"; exit 1; }
    [ -n "$pkgver" ] || { echo "! pkgver not set in $formula_script"; exit 1; }
    [ -n "$pkgmaintainer" ] || { echo "! pkgmaintainer not set in $formula_script "; exit 1; }
    [ -n "$pkgdesc" ] || { echo "! pkgdesc not set in $formula_script"; exit 1; }

    echo "* formula is valid"

    pkgdir=$(mktemp -d)
    if ! [ -d "$pkgdir" ]; then
        echo "! $pkgdir does not exist"
        exit 1
    fi
    trap 'rm -rf "$pkgdir"' EXIT

    buildroot=$(mktemp -d)
    trap 'rm -rf "$buildroot" "$pkgdir"' EXIT

    if [ -n "${pkgsrc:-}" ]; then
        [ -n "$pkgchecksum" ] || { echo "! pkgchecksum not set in $formula_script"; exit 1; }
        echo "* downloading $pkgsrc"
        srcfile=$(basename "${pkgsrc%%\?*}")
        download "$pkgsrc" "$srcfile" || {
            echo "! $DLPROG failed"
            exit 1
        }
        echo "* verifying source"

        algo="${pkgchecksum%%:*}"
        sum="${pkgchecksum#*:}"
        case "$algo" in
            sha256) cmd=sha256sum ;;
            sha512) cmd=sha512sum ;;
            *) echo "! unknown checksum algorithm: $algo"; exit 1 ;;
        esac

        echo "$sum  $initdir/$srcfile" | $cmd -c - || { echo "! checksum mismatch"; exit 1; }

        echo "* extracting source"
        extract_source "$initdir/$srcfile" "$buildroot"
        trap 'rm -rf "$initdir/$srcfile" "$buildroot" "$pkgdir"' EXIT
    fi

    echo "* building $pkgname@$pkgver"

    cd "$buildroot"
    build || {
        echo "! failed building the package"
        exit 1
    }

    echo "* packaging $pkgname"
    package || { echo "! error packaging the package"; exit 1; }

    createTreefile "$pkgdir"

    echo "* compressing the package"
    output_file=${2:-"$pkgname-$pkgver.xpt"}
    if [ "$output_file" = "ebs.auto" ]; then
        output_file="$pkgname-$pkgver.xpt"
    fi
    cat << EOF > "$pkgdir/xpt.manifest"
// generated by ebs on $(date "+%Y-%m-%d %H:%M:%S")
name=$pkgname
version=$pkgver
arch=$(uname -m)
desc=$pkgdesc
maintainer=$pkgmaintainer
depends=${pkgdeps:-}
EOF

    if [ "${3:-}" = 'install_to_toolchain' ]; then
        echo "* attempting to install to toolchain"
        if ! [ -n "$TOOLCHAIN_DIR" ]; then
            echo "! toolchain dir not found"
            exit 1
        fi
        command -v install_to_toolchain >/dev/null 2>&1 || { echo "! install_to_toolchain not found in $formula_script"; exit 1; }
        install_to_toolchain "$TOOLCHAIN_DIR"
        echo "* installed to toolchain at $TOOLCHAIN_DIR"
    fi
    tar -czf "$initdir/$output_file" -C "$pkgdir" .
    echo "* $initdir/$output_file is ready."
}

case "${1:-}" in
    help|--help|-h|h)
        print_ebs_help
        exit 0
        ;;

    build|--build|-b|b)
        build_formula "${2:-./ebs.formulae}" "${3:-ebs.auto}"
        ;;

    buildt|--build-to-toolchain|-t|t)
        build_formula "${2:-./ebs.formulae}" "${3:-ebs.auto}" "install_to_toolchain"
        ;;

    *)
        echo "ebs: invalid option -- '$1'"
        exit 1
        ;;
esac
