#!/bin/bash

#
# Slurp - add everything, slurp into a WIP commit and push
#

warn() {
    echo "$@" >&2
}

die() {
    warn "$@"
    exit 2
}

usage() {
    die "usage: git slurp [--force-slurp] [--force-push] [pathspec]..."
}

allowed_slurp() {
    #
    # Is slurp allowed in this repo?
    #
    test -f "$ok_file"
}

allowed_push() {
    #
    # Is push allowed for the remote branch??
    #
    # If this branch is tracking a remote branch, and the remote
    # branch name is listed in .git-slurp-ok after PUSH, we are
    # allowed to push
    #
    # The remote tracking branch is parsed; example output is here:
    #
    #     $ git branch -vv
    #       main   aaf02f0 [main/master: ahead 25] Some other commit
    #     * master add0a03 [jdsumsion/master] Some commit
    #
    local tbranch=$(
        git branch -vv \
          | grep '^\*' \
          | cut -d \] -f1 \
          | cut -d \[ -f2 \
          | cut -d :  -f1
    )
    test -n "$tbranch" || return 0
    grep -qxF "PUSH $tbranch" "$ok_file" 2>/dev/null
}

git_relative() {
    #
    # Convert pathspec $1 to git-root-based pathspec
    #
    # Also try to clean up path a bit; i.e. remove double slashes
    # or unnecessary trailing dot.
    #
    local path="$1"
    test -n "$GIT_PREFIX" && path="$GIT_PREFIX/$path"
    local full=$(readlink -m "$path")
    test "$full" = "$git_root" && echo . && return
    printf %s "${full#$git_root/}"
}

slurp1() {
    #
    # Slurp pathspec $1
    #
    local rel_pathspec      # relative to git root
    rel_pathspec=$(git_relative "$1")
    git add "$rel_pathspec"                         || die
    git commit -m "WIP slurp, $date: $rel_pathspec" || die
}

go_slurp() {
    #
    # Do the slurp for pathspecs $@
    #
    $force_slurp || allowed_slurp || die "you don't want this."
    local date=$(date -Isec)
    local pathspec
    for pathspec in "$@";
    do
        slurp1 "$pathspec"
    done
}

go_push() {
    #
    # Do the push (if allowed)
    #
    if $force_push || allowed_push;
    then
        git push
    fi
}

main() {
    local git_root
    local ok_file
    local force_slurp=false
    local force_push=false
    while true; do case $1 in
        --force-slurp)  force_slurp=true; shift ;;
        --force-push)   force_push=true;  shift ;;
        --)             shift; break ;;
        -*)             usage ;;
        *)              break ;;
    esac done
    test -n "$1" || set -- .
    git_root="$(git rev-parse --show-toplevel)" || die
    ok_file="$git_root/.git-slurp-ok"
    go_slurp "$@"
    go_push
}

main "$@"