#!/bin/sh
# Usage: resync.sh PUZZLES_PATH
#
# Automatic resync tool. Removes the current source snapshot in src/
# and copies just the source files we need from the puzzles source
# tree. Handles help generation as well. Stages changes in git.
#
# Expects a modified Halibut (https://github.com/built1n/halibut) to
# be installed in $PATH. Also requires host CC and lz4 library to be
# available


if [ $# -ne 1 ]
then
    echo -e "Usage: $0 PUZZLES_PATH\n"
    echo "Automatically resync with upstream."
    echo "PUZZLES_PATH is the path to a puzzles source tree."
    exit
fi

echo "Resyncing to upstream sources $1"
echo "This script assumes you have gcc, lz4, and a custom halibut (https://github.com/built1n/halibut) installed!"

echo "=== POTENTIALLY DANGEROUS OPERATION ==="
echo "Are you sure you want to remove all files in src/ and help/?"
echo -n "If so, type \"yes\" in all caps: "
read ans
if [ "YES" == $ans ]
then
    pushd "$(dirname "$0")" > /dev/null
    ROOT="$PWD"

    echo "[1/6] Removing current src/ directory"
    rm -rf src

    echo "[2/6] Copying new sources"
    mkdir -p src/unfinished
    cp -r "$1"/{*.h,puzzles.but,LICENCE,README,CMakeLists.txt,unfinished} src

    echo "[3/6] Generating SOURCES, SOURCES.games"

    cat <<EOF | tee SOURCES SOURCES.games >/dev/null
/* !!! DO NOT MODIFY THIS FILE !!! */

/*
 *
 * This file is automatically generated by resync.sh. Any manual
 * changes here will be overwritten by future resyncs.
 *
 * If you wish to change anything in this file, instead edit resync.sh
 * to accomplish what you want. You have been warned.
 */

/* !!! DO NOT MODIFY THIS FILE !!! */

EOF

    # Parse out definitions of core, core_obj, and common from the
    # upstream CMakeLists.txt. Extract the .c filenames, except
    # malloc.c and ps.c, and store in SOURCES.core.
    EXCLUDE_CORE_REGEX="malloc|ps"

    cat src/CMakeLists.txt |
        awk '/add_library\(/{p=1} p{printf $0" "} /\)/{if(p) print; p=0}' | # parse out add_library(...)
        grep -E "core|common" |
        grep -Po "[a-z0-9\-]*?\.c" |
        sort -n |
        grep -vE "$EXCLUDE_CORE_REGEX" |
        awk '{print "src/"$0}' |
        uniq > SOURCES.core

    # printing.c is pulled in via platforms/*.cmake. We don't have
    # that, so must add it ourselves.
    echo "src/printing.c" >> SOURCES.core

    # Parse out puzzle definitions to build SOURCES.games, but exclude
    # nullgame, and also #ifdef also memory-intensive games on
    # low-memory targets.
    EXCLUDE_GAMES_ALWAYS="nullgame|separate"

    cat src/CMakeLists.txt |
        awk '/puzzle\(/{p=1} p{print} /\)/{p=0}' | # parse out puzzle(...)
        grep -Eo "\(.*$" | # parse out only the first argument - this is brittle.
        tr -dc "a-z\n" |
        grep -vE "$EXCLUDE_GAMES_ALWAYS" | # exclude nullgame
        awk '{print "src/"$0".c"}' > SOURCES.games

    SRC="$(cat SOURCES.games SOURCES.core | sed 's/src\///' | tr '\n' ' ' | head -c-1)"
    echo "Detected sources:" $SRC
    pushd "$1" > /dev/null
    cp -r $SRC "$ROOT"/src
    popd > /dev/null

    EXCLUDE_GAMES_LOW_MEMORY="loopy|pearl|solo"

    # Linking on win32 (i.e. for sim/app builds) blows up with
    # un-overridden weak symbols, which are used by nullhelp.c to
    # provide fallback help text variables for the unfinished
    # plugins. A possible fix to support those games on win32 would be
    # to compile two versions of rockbox.o with a preprocessor flag to
    # prevent referencing the help variables in unfinished builds.
    #
    # But for now, we just disable the unfinished plugins on win32.
    EXCLUDE_GAMES_WIN32="unfinished"

    cat src/unfinished/CMakeLists.txt |
        awk '/puzzle\(/{p=1} p{print} /\)/{p=0}' |
        grep -Eo "\(.*$" |
        tr -dc "a-z\n" |
        awk '{print "src/unfinished/"$0".c"}' |
        grep -Ev "$EXCLUDE_GAMES_ALWAYS" >> SOURCES.games

    # Edit SOURCES.games in-place to conditionally compile games due
    # to either low-memory (EXCLUDE_GAMES_LOW_MEMORY), or win32
    # incompatibility (EXCLUDE_GAMES_WIN32).
    awk -i inplace '{
    if ($0 ~ /'"$EXCLUDE_GAMES_WIN32"'/) {
       print "#ifndef WIN32"; print $0; print "#endif";
    }
    else if ($0 ~ /'"$EXCLUDE_GAMES_LOW_MEMORY"'/) {
         print "#if PLUGIN_BUFFER_SIZE > 0x14000"; print $0; print "#endif";
    }
    else {
         print
    }
}' SOURCES.games

    cat <<EOF >> SOURCES
/* rockbox frontend sources, from SOURCES.rockbox */
EOF
    cat SOURCES.rockbox | cpp | grep -vE "^#" | sed '/^$/d' >> SOURCES

    cat <<EOF >> SOURCES

/* puzzles core sources, from src/CMakeLists.txt */
EOF

    cat SOURCES.core >> SOURCES
    rm SOURCES.core

    echo "[4/6] Generating help"
    rm -rf help
    ./genhelp.sh

    echo "[5/6] Staging for commit"
    git add src help
    echo "[6/6] Successfully resynced with upstream"

    popd > /dev/null
else
    echo "Did nothing."
fi
