#!/bin/sh
# shellcheck disable=2094,2103 source=/dev/null
#
# pkg - package manager for kiss linux.

die() {
    printf '\033[31mERROR>\033[m %s\n' "$@" >&2
    exit 1
}

log() {
    printf '\033[32m=>\033[m %s\n' "$@"
}

clean() {
    rm -rf -- "$mak_dir" "$pkg_dir"

    [ -n "$name" ] &&
        rm "$old_pwd/repo/$name/.checksums" 2>/dev/null
}

pkg_info() {
    [ -z "$1" ]    && die "No package specified."
    cd "./repo/$1" || die "Package '$1' not in repository."
    [ -f version ] || die "Version file not found."
    [ -f sources ] || die "Sources file not found."

    read -r version release < version
    name=$1
    pkg=$name-$version-$release
}

pkg_depends() {
    [ -f depends ] && while read -r dependency; do
        pkg_list "$dependency" || missing="$missing $dependency"
    done < depends

    [ -n "$missing" ] && die "Missing dependencies:$missing"
}

pkg_sources() {
    while read -r src; do
        src_name=${src##*/}

        if [ -f "$src" ] || [ -f "$src_dir/$src_name" ]; then
            log "Found local $src_name."

        elif [ -z "${src##git:*}" ]; then
            git clone "${src##git:}" "$mak_dir"

        elif [ -z "${src##*://*}" ]; then
            log "Downloading '$src'."
            wget -P "$src_dir" "$src" || die "Failed to download $src."

        else
            die "Source file '$src' not found."
        fi
    done < sources
}

pkg_checksum() {
    while read -r src; do
        src_name=${src##*/}

        if [ -z "${src##git:*}" ]; then
            continue

        elif [ -f "$src" ]; then
            src_path=$src

        elif [ -f "$src_dir/$src_name" ]; then
            src_path=$src_dir/$src_name
        fi

        cd "${src_path%/*}"
        sha256sum -- "$src_name" || die "Failed to generate checksums."
        cd - >/dev/null
    done < sources > "${1-checksums}"
}

pkg_verify() {
    pkg_checksum .checksums

    diff .checksums checksums ||
        die "checksum of sources does not match checksum of package" \
            "run '$0 checksum $name' to update checksums"

    log "Checksums verified."
    rm .checksums
}

pkg_extract() {
    while read -r src; do
        src_name=${src##*/}

        if [ -z "${src##git:*}" ]; then
            continue

        elif [ -f "$src" ]; then
            cp -f "$src" "$mak_dir"

        elif [ ! -f "$src_dir/$src_name" ]; then
            die "$src_name not found."

        else
            case $src_dir/$src_name in
                *.tar|*.tar.??|*.tar.???|*.tar.????|*.tgz)
                    tar xf "$src_dir/$src_name" -C "$mak_dir" \
                        --strip-components 1 ||
                        die "Couldn't extract $src_name"
                ;;
            esac
        fi
    done < sources
}

pkg_build() {
    log "Building $pkg."

    cd "$mak_dir"
    set -e
    . "$OLDPWD/build"
    set +e
    cd -

    cp -R "$old_pwd/repo/$name" "$old_pwd/pkg/var/db/puke"
    log "Sucessfully built $pkg."
}

pkg_manifest() {
    cd "$pkg_dir"

    _() { find . -mindepth 1 "$@" | sed 's/^\.//'; }
    _ -not -type d  > "$OLDPWD/manifest"
    _ -type d | sort -r >> "$OLDPWD/manifest"

    cd - >/dev/null
}

pkg_tar() {
    cd "$bin_dir"

    tar pcvf "$pkg.tar.gz" -C "$pkg_dir" . ||
        die "Failed to create package."

    log "Package is at $bin_dir/$pkg.tar.gz."
}

pkg_list() {
    [ "$1" ] && {
        [ -d "$sys_dir/var/db/puke/$1" ] || return 1 && return 0
    }

    for pkg in "$sys_dir/var/db/puke/"*; do
        read -r version release < "$pkg/version"
        log "${pkg##*/} $version-$release"
    done
}

args() {
    [ -n "${1#l*}" ] && {
        mkdir -p sources build pkg/var/db/puke sys bin ||
            die "Couldn't create directories at '$PWD'".

        pkg_info "$2"
    }

    case $1 in
        b*)
            [ -f checksums ] || die "Checksums missing, run '$0 checksum $name'"

            pkg_depends
            pkg_sources
            pkg_verify
            pkg_extract
            pkg_build
            pkg_manifest
            pkg_tar
        ;;

        c*)
            pkg_sources
            pkg_checksum

            log "Generated checksums."
        ;;

        i*)
            tar pxvf "$bin_dir/$pkg.tar.gz" -C "$sys_dir/" ||
                die "Failed to install $pkg"

            log "Installed $pkg"
        ;;

        l*)
            pkg_list "$2"
        ;;

        *)
            log "$0 [build|checksum|install|list|help] [pkg]"
        ;;
    esac
}

main() {
    trap clean EXIT INT
    clean

    old_pwd=$PWD
    src_dir=$PWD/sources
    mak_dir=$PWD/build
    pkg_dir=$PWD/pkg
    sys_dir=$PWD/sys
    bin_dir=$PWD/bin
    db_dir=var/db/puke

    args "$@"
}

main "$@"