#! /bin/bash
#------------------------------------------------------------------------------
#$Author: saulius $
#$Date: 2026-01-21 15:03:59 +0000 (Wed, 21 Jan 2026) $
#$Revision: 12756 $
#$URL: file:///home/saulius/svn-repositories/paskaitos/VU/software/assignment-evaluation/trunk/scripts/check-assignment $
#------------------------------------------------------------------------------
#*
# Check a student's programming assignment in a provided single
# archive file. Use various check-* subcommands to run various checks.
#**

test -z "${LC_MESSAGES}" && LC_MESSAGES=en_US.UTF-8

TMP_DIR="${TMPDIR}"

set -ue
## set -x

script() { echo "# $*"; cat; }
setvar() { eval $1="'$3'"; }

setvar Id = '$Id: check-assignment 12756 2026-01-21 15:03:59Z saulius $'

setvar FILES = ""

setvar BASENAME = "`basename $0`"

CHECK_SCRIPT_DIRS="$(dirname $0) \
$(dirname $(dirname $0))/libexec/assignment-evaluation \
$(dirname $(dirname $0))/lib/assignment-evaluation"

CHECK_SCRIPT_DIR=""

CHECK_SCRIPT_INFIX=$(basename $0 | sed 's/-assignment$//')

DEBUG=false

#** USAGE:
#**   $0 --options ... file1.tgz files*.tbz2
#**
#** OPTIONS:
#**  --script-name check
#**      Specify the infix of the specific worker script names as 'check';
#**      by default a prefix of the runner script is taken after discarding
#**      the '-assignment' suffix, so that for the 'check-assignment' main
#**      script the infix will be 'check' and the worker scripts will be
#**      called, e.g., 'do-check-line-length'.
#**
#**  --check-script-directory ./check/scripts
#**      Use './check/scripts' as a directory to find check-specific
#**      scripts. By default, $0 uses its parent dir to find the
#**      scripts.
#**
#**  --language en_US.UTF-8
#**      Specify which language to use for outputs (as in LC_MESSAGES).
#**
#**  --debug                  Print out every command before executing (set -x)
#**
#**  --help                   Print short help message (this message) and exit
while [ $# -gt 0 ]
do
    case $1 in
        --script-name|--script-nam|--script-na|--script-n|\
        --script|--scrip|--scri|--scr|--sc|--s)
            CHECK_SCRIPT_INFIX="$2"
            shift
            ;;
        --check-script-directory|--check-script-director|\
        --check-script-directo|--check-script-direct|\
        --check-script-direc|--check-script-dire|--check-script-dir|\
        --check-script-di|--check-script-d|--check-script|--check-scrip|\
        --check-scri|--check-scr|--check-sc|--check-s|--check|--chec|\
        --che|--ch|--c)
            CHECK_SCRIPT_DIR="$2"
            shift
            ;;
        --debug|--debu|--deb|--de|--d)
            DEBUG=true
            ;;
        -l|--language|--languag|--langua|--langu|--lang|--lan|--la|--l)
            LC_MESSAGES=$2
            export LC_MESSAGES
            shift
            ;;
        --help|--hel|--he|--h)
            awk '/#\*/,/#\*\*/ {
                    sub("^ *#[*]?[*]?", ""); \
                    gsub("\\$0","'$(basename $0)'"); \
                    print $0
                }' $0
	    exit
	    ;;      
        -*) echo "`basename $0`: unknown option $1" >&2 ; exit 1 ;;
        *)  FILES="$FILES '$1'" ;;
    esac
    shift
done

if [ $DEBUG = true ]; then set -x; fi

eval set -- "${FILES}"

test -z "${TMP_DIR}" && TMP_DIR="/tmp"
TMP_DIR="${TMP_DIR}/tmp-${BASENAME}-$$"
mkdir "${TMP_DIR}"

# To make the trap portable between bash and dash, we need to trap
# "signal" 0 ("EXIT") and rely on it for the cleanup:
## trap "rm -rf '${TMP_DIR}'" 0 1 2 3 15
trap "chmod -R u+wx '${TMP_DIR}'; rm -rf '${TMP_DIR}'" EXIT
trap "exit 1" HUP INT QUIT TERM

## set -x

if [ -n "${CHECK_SCRIPT_DIR}" ]
then
    if ! [ -d "${CHECK_SCRIPT_DIR}" ]
    then
        echo "$0: ERROR, directory of the checker scripts" \
             "\"${CHECK_SCRIPT_DIR}\" does not exist" >&2
        exit 2
    else
        CHECK_SCRIPT_DIRS="${CHECK_SCRIPT_DIR}"
    fi
fi  

for FILE
do
    MUST_REMOVE=false

    # Unpack the student's work for evaluation:
    if [ -d "${FILE}" ]
    then
        DIR="${FILE}"
        case $LC_MESSAGES in
            lt_LT.UTF-8) echo -n Tikrinama direktorija "'$FILE'" ;;
            *) echo -n Checking "'$FILE'" ;;
        esac
        echo ""
        pwd
    else
        case $LC_MESSAGES in
            lt_LT.UTF-8) echo -n Tikrinamas failas "'$FILE'" ;;
            *) echo -n Checking "'$FILE'" ;;
        esac
        echo ' (MD5:' $(md5sum < "${FILE}" | awk '{print $1}')')'

        DIR="${TMP_DIR}/$(basename "$(dirname "${FILE}")")/unpack"
        mkdir -p "${DIR}"
        case "$FILE" in
            *.zip)
                ABS_FILE="$(cd "$(dirname "${FILE}")"; pwd)/$(basename "${FILE}")"
                ( cd "$DIR"; 7z -aoa x "$ABS_FILE" > /dev/null )
                ;;
            *.7z)
                ABS_FILE="$(cd "$(dirname "${FILE}")"; pwd)/$(basename "${FILE}")"
                ( cd "$DIR"; 7z -aoa x "$ABS_FILE" > /dev/null )
                ;;
            *)
                tar -xf "$FILE" -C "${DIR}"
                ;;
        esac
        MUST_REMOVE=true
    fi
    echo ""

    # If the assignment contains both a working copy (copies) and a
    # student's Subversion repository, switch find URL of the
    # repository and switch working copies to it:

    ABS_DIR=$(cd "$DIR"; pwd)
    UUIDS="$(find "${ABS_DIR}" -name uuid | sort | grep /db/ || true)"

    if [ -n "${UUIDS}" ]
    then
        if [ $(echo "${UUIDS}" | wc -l) -gt 1 ]
        then
            echo -e "$0: more than one SVN repository found:\n${UUIDS}" >&2
            echo "$0: taking the one that has matching UUID" >&2
        fi

        find "${DIR}" -name __MACOSX -prune -o -name .svn -prune -print \
            | while read SVN_DIR
        do
            WC_DIR=$(dirname "${SVN_DIR}")
            # Check that the working copy is not an attached
            # 'svn:external'; externals will be ignored:
            WC_BASE=$(basename "${WC_DIR}")
            WC_DDIR=$(dirname "${WC_DIR}")
            set +e
            EXTERNALS=$(svn propget svn:externals "${WC_DDIR}" 2> /dev/null)
            set -e
            ## echo ">>> $0: DEBUG -- '${EXTERNALS}'" >&2
            if ! echo "${EXTERNALS}" | grep -q "${WC_BASE}"
            then
                # The working copy is *not* attached as an external --
                # either it is the top level working copy and the 'svn
                # propget' command failed ( in this case $EXTERNALS is
                # an empty string), or it is inside another working
                # copy, but its directory name is *not* mentioned
                # among the svn:external names. Let's switch it:
                OLD_REPO="$(svn info $WC_DIR | grep ^URL: | sed 's/URL: *//')"
                OLD_PATH="$(svn info $WC_DIR | grep '^Relative URL:' | sed 's/Relative URL: *\^\///')"

                WC_UUID=$(svn info "${WC_DIR}" | awk '/^Repository UUID:/ {print $3}')

                for UUID_FILE in ${UUIDS}
                do
                    REPO_UUID=$(svnlook uuid "$(dirname "$(dirname "${UUID_FILE}")")")
                    if [ "${WC_UUID}" = "${REPO_UUID}" ]
                    then
                        SVN_REPO=$(dirname "$(dirname "${UUID_FILE}")")
                        SVN_REPO_URL=file://"${SVN_REPO}"
                        SVN_PATH_URL="${SVN_REPO_URL}/${OLD_PATH}"

                        svn sw --relocate "${OLD_REPO}" "${SVN_PATH_URL}" "${WC_DIR}"
                        break
                    fi
                done;
            fi
        done
    fi
    
    # Check the student's assignment directory running
    # assignment-specific check scripts:
    for CHECK_SCRIPT_DIR in ${CHECK_SCRIPT_DIRS}
    do
        for CHECK in \
            $CHECK_SCRIPT_DIR/do-${CHECK_SCRIPT_INFIX}--* \
            $CHECK_SCRIPT_DIR/${CHECK_SCRIPT_INFIX}/* \
            ;
        do
            if [ -x $CHECK ]
            then (
                if [ $DEBUG = true ]
                then
                    bash -x $CHECK "$DIR"
                else
                    $CHECK "$DIR"
                fi
            ) fi
        done
    done

    case $LC_MESSAGES in
        lt_LT.UTF-8) echo Failo "'$FILE'" turinys: ;;
        *) echo File "'$FILE'" contents: ;;
    esac

    ( cd "$DIR"; tree; echo "" )

    if [ ${MUST_REMOVE} = true ]
    then
        chmod -R u+wx "${DIR}"
        rm -rf "$DIR"
    fi
done
