Created
March 12, 2017 16:34
-
-
Save alexpatel/5d8086af23d4af90f0487aa8cf937ef8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Submit programming assignment submissions to the MOSS plagiarism detection | |
# server. | |
if [ $BASH_VERSINFO -lt 4 ]; | |
then | |
echo "Expected bash 4.0.0 or later, found $BASH_VERSION" | |
exit 1 | |
fi | |
shopt -u dotglob | |
NORM=`tput sgr0` | |
BOLD=`tput bold` | |
SCRIPT=`basename "$0"` | |
HOST=moss.stanford.edu | |
PORT=7690 | |
USERID= | |
ASSN= | |
REPOS= | |
declare -A MOSSOPTS=( [l]=c [m]=10 [d]=0 [x]=0 [n]=250 ) | |
function pushd { command pushd "$@" > /dev/null; } | |
function popd { command popd "$@" > /dev/null; } | |
# Print usage string | |
function USAGE { | |
cat <<EOF | |
Usage: $SCRIPT -a ASSN -u USERID -d REPOS [-s HOST] [-p PORT] [-m REPEAT] | |
[-n MATCHES] [-x EXPERIMENTAL] | |
${BOLD}-a${NORM} -- CS61 assignment number (1- 6) | |
${BOLD}-d${NORM} -- directory containing course submission repositories | |
${BOLD}-u${NORM} -- MOSS user ID | |
${BOLD}-s${NORM} -- MOSS server hostname (default: ${HOST}) | |
${BOLD}-p${NORM} -- MOSS server port (default: ${PORT}) | |
${BOLD}-m${NORM} -- maximum times a passage may appear before being ignored default: ${MOSSOPTS[m]}) | |
${BOLD}-n${NORM} -- number of matching files to show in results (default: ${MOSSOPTS[n]}) | |
${BOLD}-x${NORM} -- use experimental server (default: ${MOSSOPTS[d]}) | |
${BOLD}-h${NORM} -- display this message | |
EOF | |
exit 0 | |
} | |
# Parse command-line options | |
function PARSEOPTS { | |
while getopts :a:d:u:s:p:m:n:x:h OPT; do | |
case $OPT in | |
a) ASSN="pset${OPTARG}" | |
;; | |
d) REPOS="${OPTARG}" | |
;; | |
u) USERID="${OPTARG}" | |
;; | |
s) HOST="${OPTARG}" | |
;; | |
p) PORT=${OPTARG} | |
;; | |
m) MOSSOPTS[m]=${OPTARG} | |
;; | |
n) MOSSOPTS[n]=${OPTARG} | |
;; | |
x) MOSSOPTS[x]=${OPTARG} | |
;; | |
h) USAGE | |
;; | |
\?) echo -e \\n"Unknown option ${BOLD}$OPTARG${NORM}." && USAGE ;; | |
esac | |
done | |
if [ $OPTIND -eq 1 ]; then USAGE; fi | |
if [ -z "${ASSN}" ]; then echo "-${BOLD}a${NORM} is required." && USAGE; fi | |
if [ -z "${USERID}" ]; then echo "-${BOLD}u${NORM} is required." && USAGE; fi | |
if [ -z "${REPOS}" ]; then echo "-${BOLD}d${NORM} is required." && USAGE; fi | |
shift $((OPTIND-1)) | |
} | |
# Test TCP connection to MOSS server | |
function TESTCONN { | |
nc -z -w5 $HOST $PORT > /dev/null | |
if [ $? -ne 0 ]; then echo "Connection failed: $HOST:$PORT" && exit 1; fi | |
} | |
# Open TCP connection to MOSS server | |
function SOCKOPEN { exec 3<>/dev/tcp/$HOST/$PORT; TESTCONN; } | |
# Close TCP connection to MOSS server | |
function SOCKCLOSE { TESTCONN; exec 3<&- && exec 3>&-; } | |
# Read response from MOSS server | |
function READRESP { | |
for lno in $(seq 1 2); do | |
read resp | |
echo $resp | |
if [ $lno -eq 1 ] && [ "$resp" != "yes"]; then | |
echo "Invalid language: ${MOSSOPTS[l]}" && exit 1 | |
else | |
echo "Valid language: ${MOSSOPTS[l]}" | |
fi | |
if [ $lno -eq 2 ]; then echo "URL: $resp" && exit 0; fi | |
done < <(cat <&3) | |
} | |
# Read submissions query metadata to MOSS connection | |
function WRITEMETA { | |
echo -ne "moss $USERID\n" >&3 | |
echo -ne "directory ${MOSSOPTS[d]}\n" >&3 | |
echo -ne "X ${MOSSOPTS[x]}\n" >&3 | |
echo -ne "maxmatches ${MOSSOPTS[m]}\n" >&3 | |
echo -ne "show ${MOSSOPTS[n]}\n" >&3 | |
echo -ne "language ${MOSSOPTS[l]}\n" >&3 | |
} | |
# Write query suffix and submit command to MOSS connection | |
function WRITEQUERY { | |
echo -ne "query 0 $ASSN-$(date +%s)\n" >&3 | |
echo -ne "end" >&3 | |
} | |
# Write contents + metadata of a single file to MOSS connection | |
# Arguments: (file name, Git remote name, file index) | |
function WRITEFILE { | |
file=$1 | |
remote=$2 | |
filendx=$3 | |
echo -e "\tWriting file: $remote/$file" | |
fname="${remote}_${file//[[:space:]]}" | |
echo -ne "file ${filendx} ${MOSSOPTS[l]} $(stat -f "%z" $file) $fname\n" >&3 | |
echo -ne "$(cat $file)\n" >&3 | |
} | |
# Parse student submissions Git repositories and submit all contained .c/.h | |
# files | |
function WRITEREPOS { | |
# external counter to avoid sub-process scope | |
filectr=/tmp/filectr | |
echo 1 > $filectr | |
pushd $REPOS | |
find * -prune -type d | while read repo; do | |
pushd $repo | |
git branch --all -r | tr -d ' ' | grep "master$" |\ | |
while IFS='/' read remote branch; do | |
git reset --hard -q handout/master > /dev/null | |
if [[ $remote =~ "repo" ]]; then | |
git checkout -q $remote/$branch > /dev/null | |
ASSNDIR=$(find . -type d -name "${ASSN}" -print) | |
if [ -z $ASSNDIR ]; then | |
echo "$repo/$remote - could not find Assignment $ASSN" | |
else | |
pushd $ASSNDIR | |
nfiles=$(ls *.{c,h} | wc -l | tr -d ' ') | |
echo "${BOLD}Processing repository: $repo/$remote with $nfiles code files.${NORM}" | |
for file in $(ls *.{c,h}); do | |
filendx=$(cat $filectr) | |
WRITEFILE $file $remote $filendx | |
echo $[$(cat $filectr) + 1] > $filectr | |
done | |
git reset --hard -q handout/master > /dev/null | |
popd | |
fi | |
fi | |
done | |
popd | |
done | |
rm $filectr | |
} | |
# Write all code files for this assignment from handout respository | |
function WRITEBASE { | |
remote=handout | |
pushd $REPOS | |
pushd $(find * -prune -type d | head -n 1) | |
git checkout -q handout/master | |
ASSNDIR=$(find . -type d -name "${ASSN}" -print) | |
pushd $ASSNDIR | |
for file in $(ls *.{c,h}); do | |
WRITEFILE $file $remote 0 | |
done | |
popd | |
popd | |
popd | |
} | |
function MAIN { | |
PARSEOPTS "$@" | |
echo "Opening MOSS socket connection." | |
SOCKOPEN | |
echo "Writing submission metadata." | |
WRITEMETA | |
echo "Writing common submission files." | |
WRITEBASE | |
echo "Writing student submission files." | |
WRITEREPOS | |
echo "Submitting MOSS query." | |
WRITEQUERY | |
READRESP | |
echo "Closing MOSS socket connection." | |
SOCKCLOSE | |
} | |
MAIN "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment