]> mj.ucw.cz Git - eval.git/blob - bin/lib
Added ability to submit or check an arbitrary file.
[eval.git] / bin / lib
1 # The Evaluator -- Shell Function Library
2 # (c) 2001--2004 Martin Mares <mj@ucw.cz>
3
4 # General settings
5 shopt -s dotglob
6
7 # Logging functions.
8 # File handles used: fd1=log, fd2=progress
9
10 function log-init
11 {
12         exec >>$TDIR/log
13         HAVE_LOG=1
14 }
15
16 function pstart
17 {
18         echo >&2 -n "$@"
19 }
20
21 function pcont
22 {
23         echo >&2 -n "$@"
24 }
25
26 function pend
27 {
28         echo >&2 "$@"
29 }
30
31 function die
32 {
33         # Report an internal error
34         echo >&2 "$@"
35         [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
36         exit 2
37 }
38
39 function fatal
40 {
41         # Report a fatal error in the program being tested
42         echo >&2 "$@"
43         [ -n "$HAVE_LOG" ] && echo "Fatal error: $@"
44         exit 1
45 }
46
47 # Sandbox subroutines
48
49 function box-init
50 {
51         pstart "Preparing sandbox... "
52         if [ -z "$TEST_USER" -o "$TEST_USER" == $EVAL_USER ] ; then
53                 pcont "running locally (INSECURE), "
54                 TEST_USER=$EVAL_USER
55                 BOXDIR=box
56                 BOXCMD=bin/box
57                 mkdir -p box
58         else
59                 pcont "used account $TEST_USER, "
60                 BOXDIR=$MO_ROOT/eval/$TEST_USER
61                 BOXCMD=bin/box-$TEST_USER
62         fi
63         [ -d $BOXDIR -a -f $BOXCMD ] || die "Sandbox set up incorrectly"
64         BOXCMD="$BOXCMD -c$BOXDIR"
65         echo "Sandbox directory: $BOXDIR"
66         echo "Sandbox command: $BOXCMD"
67         box-clean
68         pend "OK"
69 }
70
71 function box-clean
72 {
73         [ -n "$BOXCMD" ] || die "box-init not called"
74         rm -rf $BOXDIR/*
75 }
76
77 # Initialization of testing directories
78
79 function dir-init
80 {
81         pstart "Initializing... "
82         HDIR=.
83         PDIR=problems/$PROBLEM
84         SDIR=solutions/$CONTESTANT/$PROBLEM
85         TDIR=testing/$CONTESTANT/$PROBLEM
86         TMPDIR=tmp
87         [ -d $PDIR ] || die "Problem $PROBLEM not known"
88         [ -d $SDIR ] || fatal "Solution of $PROBLEM not found"
89         mkdir -p $TDIR $TMPDIR
90         rm -rf $TDIR $TMPDIR
91         mkdir -p $TDIR $TMPDIR
92         cat >$TDIR/log <<EOF
93 Testing solution of $PROBLEM by $CONTESTANT
94 Test started at `date`
95 Contestant's solution directory: $SDIR
96 Problem directory: $PDIR
97 Testing directory: $TDIR
98 EOF
99         pend "OK"
100 }
101
102 # Locating source file in SDIR, pass name in SRCN (without path) and extension in SRCEXT
103
104 function locate-source
105 {
106         pstart "Finding source... "
107         if [ -n "$1" ] ; then
108                 SRCBASE=$(echo $1 | sed 's/\.\([^.]\+\)//')
109                 SRCEXT=$(echo $1 | sed 's/.*\.\([^.]\+\)/\1/')
110                 if [ -n "$SRCEXT" ] ; then
111                         # Full name given, so just check the extension and existence
112                         SRCN=$1
113                         if [ ${SRCN:0:1} == / ] ; then
114                                 SRCN=${SRCN:1}
115                                 SDIR=
116                         fi
117                         [ -f "$SDIR/$SRCN" ] || die "Cannot find source file $SDIR/$SRCN"
118                         SRCEXT_OK=
119                         for a in $EXTENSIONS ; do
120                                 if [ $a == $SRCEXT ] ; then
121                                         pend $SDIR/$SRCN
122                                         echo "Explicitly set source file: $SDIR/$SRCN"
123                                         return 0
124                                 fi
125                         done
126                         die "Unknown extension .$SRCEXT"
127                 fi
128         else
129                 SBASE=$PROBLEM
130         fi
131         for a in $EXTENSIONS ; do
132                 if [ -f $SDIR/$SBASE.$a ] ; then
133                         [ -z "$SRCN" ] || die "Multiple source files found: $SDIR/$PROBLEM.$a and $SDIR/$SRCN. Please fix."
134                         SRCN=$SBASE.$a
135                         SRCEXT=$a
136                 fi
137         done
138         [ -n "$SRCN" ] || fatal "NOT FOUND"
139         pend $SRCN
140         echo "Found source file: $SDIR/$SRCN"
141 }
142
143 # Compilation (compile SDIR/SRCN with PDIR/COMP_EXTRAS to EXE=TDIR/PROBLEM)
144
145 function compile
146 {
147         pstart "Compiling... "
148         # Beware, the original SRCN can be a strange user-supplied name
149         SRC=$PROBLEM.$SRCEXT
150         cp -a $SDIR/$SRCN $TDIR/$SRC
151         if [ -n "$COMP_EXTRAS" ] ; then
152                 echo "Extras: $COMP_EXTRAS"
153                 for a in $COMP_EXTRAS ; do cp $PDIR/$a $TDIR/ ; done
154         fi
155         box-clean
156         for a in $SRC $COMP_EXTRAS ; do cp $TDIR/$a $BOXDIR/ ; done
157         EXE=$PROBLEM
158         CCMD=COMP_$SRCEXT
159         CCMD=`eval echo ${!CCMD}`
160         COMP_SANDBOX_OPTS=`eval echo $COMP_SANDBOX_OPTS`
161         echo "Compiler command: $CCMD"
162         echo "Compiler sandbox options: $COMP_SANDBOX_OPTS"
163         eval $COMP_SANDBOX_INIT
164
165         echo "Compiler input files:"
166         ls -Al $BOXDIR
167         echo "Compiler output:"
168         if ! $BOXCMD $COMP_SANDBOX_OPTS -- $CCMD 2>$TDIR/compile.out ; then
169                 COMPILE_MSG="`cat $TDIR/compile.out`"
170                 pend "FAILED: $COMPILE_MSG"
171                 echo "$COMPILE_MSG"
172                 return 1
173         fi
174         cat $TDIR/compile.out
175         rm $TDIR/compile.out
176         echo "Compiler output files:"
177         ls -Al $BOXDIR
178         if [ ! -f $BOXDIR/$PROBLEM ] ; then
179                 pend "FAILED: Missing executable file"
180                 echo "Missing executable file"
181                 return 1
182         fi
183         EXE=$TDIR/$PROBLEM
184         cp -a $BOXDIR/$PROBLEM $EXE
185         echo "Compiled OK, result copied to $EXE"
186         pend "OK"
187 }
188
189 # Running of test program according to current task type (returns exit code and TEST_MSG)
190
191 function test-run
192 {
193         test-run-$TASK_TYPE
194 }
195
196 function test-result
197 {
198         P=$1
199         M=$2
200         if [ -s $TDIR/$TEST.pts ] ; then
201                 P=`cat $TDIR/$TEST.pts`
202                 rm $TDIR/$TEST.pts
203         fi
204         echo "Verdict: $M"
205         echo "Points: $P"
206         test-verdict $P "$M"
207 }
208
209 function test-prolog
210 {
211         pcont "<init> "
212         box-clean
213         echo "Executable file: $TDIR/$PROBLEM"
214         if [ ! -x $TDIR/$PROBLEM ] ; then
215                 test-result 0 "Compile error."
216         fi
217         cp $TDIR/$PROBLEM $BOXDIR/
218         BOX_EXTRAS=
219         IN_TYPE=${IN_TYPE:-$IO_TYPE}
220         OUT_TYPE=${OUT_TYPE:-$IO_TYPE}
221         case $IN_TYPE in
222                 file)   echo "Input file: $PROBLEM.in (from $PDIR/$TEST.in)"
223                         ln $PDIR/$TEST.in $TDIR/$TEST.in
224                         cp $PDIR/$TEST.in $BOXDIR/$PROBLEM.in
225                         BOX_EXTRAS="$BOX_EXTRAS -i/dev/null"
226                         ;;
227                 stdio)  echo "Input file: <stdin> (from $PDIR/$TEST.in)"
228                         ln $PDIR/$TEST.in $TDIR/$TEST.in
229                         cp $PDIR/$TEST.in $BOXDIR/.stdin
230                         BOX_EXTRAS="$BOX_EXTRAS -i.stdin"
231                         ;;
232                 none)   echo "Input file: <none>"
233                         ;;
234                 *)      die "Unknown IN_TYPE $IN_TYPE"
235                         ;;
236         esac
237         case $OUT_TYPE in
238                 file)   echo "Output file: $PROBLEM.out"
239                         BOX_EXTRAS="$BOX_EXTRAS -o/dev/null"
240                         ;;
241                 stdio)  echo "Output file: <stdout>"
242                         BOX_EXTRAS="$BOX_EXTRAS -o.stdout"
243                         ;;
244                 none)   echo "Output file: <none>"
245                         ;;
246                 *)      die "Unknown OUT_TYPE $OUT_TYPE"
247                         ;;
248         esac
249         echo "Timeout: $TIME_LIMIT s"
250         echo "Memory: $MEM_LIMIT KB"
251         eval $SANDBOX_INIT
252         echo "Sandbox contents before start:"
253         ls -Al $BOXDIR
254 }
255
256 function test-epilog
257 {
258         echo "Sandbox contents after exit:"
259         ls -Al $BOXDIR
260         case ${OUT_TYPE:-$IO_TYPE} in
261                 file)   [ -f $BOXDIR/$PROBLEM.out ] || test-result 0 "No output file."
262                         cp $BOXDIR/$PROBLEM.out $TDIR/$TEST.out
263                         ;;
264                 stdio)  [ -f $BOXDIR/.stdout ] || test-result 0 "No output file."
265                         cp $BOXDIR/.stdout $TDIR/$TEST.out
266                         ;;
267         esac
268 }
269
270 # Running of test program with file input/output
271
272 function test-run-file
273 {
274         test-prolog
275         pcont "<run> "
276         BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
277         echo "Sandbox options: $BOXOPTS"
278         if ! $BOXCMD $BOXOPTS -- ./$PROBLEM 2>$TMPDIR/exec.out ; then
279                 cat $TMPDIR/exec.out
280                 MSG=`tail -1 $TMPDIR/exec.out`
281                 test-result 0 "$MSG"
282         fi
283         cat $TMPDIR/exec.out
284         test-epilog
285 }
286
287 # Running of interactive test programs
288
289 function test-run-interactive
290 {
291         test-prolog
292         pcont "<run> "
293         BOXOPTS="`eval echo $TEST_SANDBOX_OPTS`$BOX_EXTRAS"
294         echo "Sandbox options: $BOXOPTS"
295         ICCMD=`eval echo $IA_CHECK`
296         echo "Interactive checker: $ICCMD"
297         if ! $HDIR/bin/iwrapper $BOXCMD $BOXOPTS -- ./$PROBLEM @@ $ICCMD 2>$TMPDIR/exec.out ; then
298                 cat $TMPDIR/exec.out
299                 MSG="`tail -1 $TMPDIR/exec.out`"
300                 test-result 0 "$MSG"
301         fi
302         cat $TMPDIR/exec.out
303         test-epilog
304 }
305
306 # Syntax checks
307
308 function syntax-check
309 {
310         [ -n "$SYNTAX_CHECK" ] || return 0
311         pcont "<syntax> "
312         SCHECK=`eval echo $SYNTAX_CHECK`
313         echo "Syntax check command: $SCHECK"
314         if ! eval $SCHECK 2>$TMPDIR/exec.out ; then
315                 cat $TMPDIR/exec.out
316                 MSG=`tail -1 $TMPDIR/exec.out`
317                 if [ -z "$MSG" ] ; then MSG="Wrong syntax." ; fi
318                 test-result 0 "$MSG"
319         fi
320         cat $TMPDIR/exec.out
321 }
322
323 # Output checks
324
325 function output-check
326 {
327         [ -n "$OUTPUT_CHECK" ] || return 0
328         pcont "<check> "
329         [ -f $PDIR/$TEST.out ] && ln $PDIR/$TEST.out $TDIR/$TEST.ok
330         OCHECK=`eval echo $OUTPUT_CHECK`
331         echo "Output check command: $OCHECK"
332         if ! eval $OCHECK 2>$TMPDIR/exec.out ; then
333                 cat $TMPDIR/exec.out
334                 MSG=`tail -1 $TMPDIR/exec.out`
335                 if [ -z "$MSG" ] ; then MSG="Wrong answer." ; fi
336                 test-result 0 "$MSG"
337         fi
338         cat $TMPDIR/exec.out
339         MSG=`tail -1 $TMPDIR/exec.out`
340         if [ -z "$MSG" ] ; then MSG="OK" ; fi
341         test-result $POINTS_PER_TEST "$MSG"
342 }
343
344 # Setup of public commands
345
346 function public-setup
347 {
348         HDIR=$MO_ROOT
349         PDIR=$MO_ROOT/problems/$PROBLEM
350         SDIR=.
351         TDIR=~/.test
352         TMPDIR=~/.test
353         [ -d $PDIR ] || die "Unknown problem $PROBLEM"
354
355         pstart "Initializing... "
356         mkdir -p $TDIR
357         rm -rf $TDIR/*
358         BOXDIR=~/.box
359         mkdir -p $BOXDIR
360         rm -rf $BOXDIR/*
361         BOXCMD="$MO_ROOT/bin/box -c$BOXDIR"
362         exec >log
363         pend "OK  (see 'log' for details)"
364 }
365
366 # Locate output of open data problem, test case TEST
367
368 function open-locate
369 {
370         [ -f $PDIR/$TEST.in ] || die "Unknown test $TEST"
371         if [ -n "$1" ] ; then
372                 SRCN=$1
373         else
374                 SRCN=$SDIR/$PROBLEM$TEST.out
375         fi
376         [ -f $SRCN ] || fatal "Output file $SRCN not found"
377 }