#!/bin/bash -p


fail () {
    set +exu
    local ret="${1}"
    shift
    echo "${@}" >&2
    exit "${ret}"
}


require_program () {
    command -v "${1}" &>/dev/null ||
        fail 127 "Required program '${1}' not found in PATH"
}


set -eu
set -o pipefail
IFS=$'\n\t'

true <<'=cut'
=head3 init_repo

Initialize the git repo, add the quilt files to the exclude list, and
commit all the other files.  Tag the commit 'base'.

=cut

init_repo () {
    git init .
    if $lineendings; then
        git config core.safecrlf false
    fi
    printf "%s\n" '' .pc patches patches-main series series-q ./*.patch tags TAGS >> .git/info/exclude
    git add .
    # set the date so we get the same hash each run
    export GIT_AUTHOR_DATE="1970-01-01 00:00:00"
    export GIT_COMMITTER_DATE="1970-01-01 00:00:00"
    git commit -aqm "Base sources"
    unset GIT_AUTHOR_DATE
    unset GIT_COMMITTER_DATE
    git tag base
    stg init 
}


true <<'=cut'
=head3 fix_line_endings

Convert the line endings of each patch, and each file affected by the
patches, to Unix (LF) format.  The source tree ends up with no patches
applied.

=cut

fix_line_endings () {
    [[ -e patches ]] || return

    find . -name .git -prune -o -type f -print0 | xargs --max-procs=3 -0 dos2unix
}


true <<'=cut'
=head3 qualify_series_file

Add the 'patches/' prefix to all the lines in a series file and save it
as series-q.

=cut

qualify_series_file () {
    [[ -e patches ]] || return
    sed -e '/^[A-Za-z0-9]/s|^|patches/|' series > series-q
}


true <<'=cut'
=head3 apply_all_patches

Apply all patches in the quilt series using stg import.

=cut

apply_all_patches () {
    stg import --series series-q
}


true <<'=cut'
=head3 fix_patches_dir

Turn the C<patches> dir from a symlink (which may be a symlink to C<..>,
creating a loop) to a regular directory containing just the patches.

=cut

fix_patches_dir () {
    # check if we really need to do anything first
    if [[ -L patches ]]; then
        # save all the patch files, since the dir 'patches' links to
        # may have other files in it
        local patches_tempdir
        patches_tempdir="$(mktemp -d)"
        quilt series | while read -r line; do
            patchfile=${line#patches/}
            cp -f "patches/$patchfile" "$patches_tempdir/$patchfile" || :
        done
        rm -f patches
        mv "$patches_tempdir" patches
    fi
}


########
# MAIN #
########


require_program quilt
require_program git
require_program stg


lineendings=false
fixpatchesdir=false
force=false

while getopts :lpf OPT; do
    case $OPT in
        l)
            lineendings=true
            ;;
        p)
            fixpatchesdir=true
            ;;
        f)  force=true
            ;;
        *)
            echo "usage: ${0##*/} [-lpf] [--] [DIRECTORY]"
            echo ""
            echo "-l  Fix line endings in patches"
            echo "-p  Turn patches symlink into directory"
            echo "-f  Don't check for presence of quilt files"
            exit 2
    esac
done
shift $(( OPTIND - 1 ))
OPTIND=1

directory=${1:-$(pwd)}

cd "$directory"
if [[ $(pwd | wc -l) -gt 1 ]]; then
    fail 3 "No embedded newline shenanigans please!"
fi

if ! $force && [[ ! -d patches || ! -f series ]]; then
    fail 4 "No quilt files found"
fi


init_repo

if $fixpatchesdir; then
    fix_patches_dir
fi

if $lineendings; then
    fix_line_endings
fi

qualify_series_file

apply_all_patches

