-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathjudge.py
executable file
·172 lines (152 loc) · 5.81 KB
/
judge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# This file is part of the BotWarsServer program.
# Copyright (C) 2013 Rahul Huilgol, Rajat Khanduja
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This file defines functions required to compile and run the code and
# evaluate the output
# Currently supports only the following langauges
# - C
# - C++
# - Python
#
# TODO : Take care of naming when multiple users might be accessing.
import subprocess
import logging
import os, sys, time
PROBLEMS_DIR = "Problems"
class NoSuchProblemException(Exception):
def __init__ (self, value):
self.value = value
def __str__ (self):
return repr(self.value)
class CompilationError (Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
def judge(problemRef, sourceFile):
'''
This function takes as input the reference number of the problem
and the submitted file and calls the compile-run function
appropriately. Eventually, it returns the score earned by the
submitted solution based on the problemRef and the evaluation
function given in the file problems/problemRef.py
'''
# First ensure that the problem reference is a valid one.
importFile = PROBLEMS_DIR + "." + str(problemRef)
try:
prob = __import__(importFile, fromlist = [problemRef])
except Exception as e:
logging.debug(str(e))
raise NoSuchProblemException("Problem " + str(problemRef) + " not defined")
return
# Initial setup
prob.setup(sourceFile, os.path.realpath(PROBLEMS_DIR))
score = 0
allErrors = ""
# For each input, output pair run the test.
# TODO : This step calls the compilation of files over and over. Fix this.
try:
for (inFile,outFile) in prob.testFiles:
inFile = os.path.join(PROBLEMS_DIR, inFile)
outFile = os.path.join(PROBLEMS_DIR, outFile)
(producedOutput, error) = compilerun(sourceFile, inFile, prob.MEM_LIM,
prob.TIME_LIM)
inputData = open(inFile).read()
expectedOutput = open(outFile).read()
if not error:
score += prob.evaluate (inputData, expectedOutput, producedOutput,
sourceFile)
else:
allErrors += error + "\n"
except CompilationError as e:
logging.debug ("CompilationError:" + str(e))
allErrors += str(e)
pass
except Exception as e:
logging.info (str(e))
raise e
return score, allErrors
def init():
'''
Initializations required for judging steps.
'''
compilec = ['/usr/bin/gcc', 'runner.c', '-o', 'runner','-lm']
subprocess.call(compilec)
def compilerun(filename, inputfile, memlimit, timelimit):
TEST_DIR = os.path.dirname(filename)
outFiles = {'c' : filename + ".out",
'cpp': filename + '.out'}
compiler = {'c' : ['/usr/bin/gcc', '-lm', '-w', '-o', outFiles['c']],
'cpp': ['/usr/bin/g++', '-lm', '-w', '-o', outFiles['cpp']]}
interpreter = {'py' : '/usr/bin/python'}
# Convert all parameters to string
filename = str(filename)
inputfile = str(inputfile)
memlimit = str(memlimit)
timelimit = str(timelimit)
logging.debug("%s; %s; %s; %s", filename, inputfile, memlimit, timelimit)
# Find language of the program
dotpos = filename.find(".")
language = filename[dotpos + 1:]
logging.debug("Language of file %s is '%s'", filename, language)
compileerror = False
# Create and open output and error files
t = str(int(time.time()))
errfile = os.path.join(TEST_DIR, os.path.basename(inputfile) + "_err_" + t)
outputfile = os.path.join(TEST_DIR, os.path.basename(inputfile) + "_out_" + t)
ferr = open(errfile,'w')
fout = open(outputfile, 'w') # Ensures that the file is created
fout.close() # Close it as only creation of file is required
logging.debug("Created output file : %s ; Created error file : %s", errfile, outputfile)
error = ""
output = ""
# Check if it is a compiled language
if language in compiler:
compiler[language].append(filename)
subprocess.call(compiler[language], stderr = ferr)
with open(errfile) as error_file:
error = error_file.read()
if not error:
logging.debug("Compiled %s successfully", filename)
run = ['./runner', outFiles[language], '--input=' + inputfile,
'--output=' + outputfile, '--mem=' + memlimit,
'--time=' + timelimit, '--chroot=.']
subprocess.call(run, stderr = ferr)
else:
logging.debug("Error when compiling %s", filename)
compileerror = True
raise CompilationError(error)
elif language in interpreter:
run = ['./runner', interpreter[language], filename, '--input=' + inputfile,
'--output=' + outputfile, '--mem=' + memlimit,
'--time=' + timelimit, '--chroot=.']
subprocess.call(run, stderr = ferr)
with open(errfile, 'r') as error_file:
error = error_file.read()
if error:
compileerror = True
ferr.close()
with open(errfile, 'r') as error_file:
if compileerror == False:
error = error_file.read()
else:
error = 'CERR ' + error_file.read()
# print error
with open(outputfile, 'r') as output_file:
output = output_file.read()
# print output
# TODO : Delete error and output files
return (output, error)