294 lines
9.6 KiB
Python
Executable File
294 lines
9.6 KiB
Python
Executable File
|
|
import string, os, stat, threading, logging, bz2
|
|
import unittest
|
|
|
|
from engineconfig import getConfig
|
|
from judgescript import InternalJudge, ExternalJudge
|
|
|
|
|
|
def _to_text(value, encoding='utf-8', errors='replace'):
|
|
if value is None:
|
|
return ''
|
|
if isinstance(value, bytes):
|
|
return value.decode(encoding, errors)
|
|
if isinstance(value, str):
|
|
return value
|
|
return str(value)
|
|
|
|
|
|
class Problem:
|
|
|
|
def __init__(self, datasource, row):
|
|
self.tests = None
|
|
self.presetcodes = {}
|
|
self.datafiles = None
|
|
|
|
self.datasource = datasource
|
|
self.id = row['id']
|
|
self.timemodified = row['timemodified']
|
|
self.vcode = row['validator_code']
|
|
if not isinstance(self.vcode, str):
|
|
self.vcode = _to_text(self.vcode)
|
|
self.vtype = row['validator_type']
|
|
self.vlang = row['validator_lang']
|
|
self.gcode = row['generator_code']
|
|
if not isinstance(self.gcode, str):
|
|
self.gcode = _to_text(self.gcode)
|
|
|
|
self.gtype = row['generator_type']
|
|
self.standard_code = row['standard_code']
|
|
|
|
if 'input_filename' in row and row['input_filename']:
|
|
self.input_filename = row['input_filename']
|
|
else:
|
|
self.input_filename = None
|
|
if 'output_filename' in row and row['output_filename']:
|
|
self.output_filename = row['output_filename']
|
|
else:
|
|
self.output_filename = None
|
|
|
|
def get_judge_script(self):
|
|
if self.vtype == 'comparetext':
|
|
return InternalJudge()
|
|
elif self.vtype == 'comparetextwithpe':
|
|
return InternalJudge(allowpe = True)
|
|
elif self.vtype == 'comparefile':
|
|
code = open('scripts/compare-file.py').read()
|
|
return ExternalJudge(self.id, 'python-2.5', code)
|
|
elif self.vtype == 'customized':
|
|
return ExternalJudge(self.id, self.vlang, self.vcode)
|
|
|
|
def get_testcases(self):
|
|
if not self.tests:
|
|
self.tests = self.datasource.get_tests(self.id, False)
|
|
for testcase in self.tests:
|
|
testcase.problem = self
|
|
return self.tests
|
|
|
|
def get_input_filename(self):
|
|
return self.input_filename
|
|
|
|
def get_output_filename(self):
|
|
return self.output_filename
|
|
|
|
def get_presetcodes(self, lang):
|
|
if not self.presetcodes or lang not in self.presetcodes:
|
|
codes = self.datasource.get_presetcodes(self.id, lang)
|
|
for code in codes: code.problem = self
|
|
self.presetcodes[lang] = codes
|
|
return self.presetcodes[lang]
|
|
|
|
def get_datafiles(self):
|
|
if not self.datafiles:
|
|
self.datafiles = self.datasource.get_datafiles(self.id)
|
|
return self.datafiles
|
|
|
|
class Submit:
|
|
|
|
def __init__(self, datasource, row):
|
|
self.datasource = datasource
|
|
self.problem = None
|
|
self.id = row['id']
|
|
self.problem_id = row['problem_id']
|
|
self.language = row['language']
|
|
self.code = row['code']
|
|
|
|
def get_problem(self):
|
|
if not self.problem:
|
|
self.problem = self.datasource.get_problem(self.problem_id)
|
|
return self.problem
|
|
|
|
def get_testcases(self):
|
|
return self.get_problem().get_testcases()
|
|
|
|
def get_judge_script(self):
|
|
return self.get_problem().get_judge_script()
|
|
|
|
def get_input_filename(self):
|
|
return self.get_problem().get_input_filename()
|
|
|
|
def get_output_filename(self):
|
|
return self.get_problem().get_output_filename()
|
|
|
|
def get_presetcodes(self):
|
|
return self.get_problem().get_presetcodes(self.language)
|
|
|
|
def set_compilemessage(self, msg):
|
|
return self.datasource.update_submit_compilemessage(self.id, msg)
|
|
|
|
def set_status(self, newstatus):
|
|
return self.datasource.update_submits_status(self.id, newstatus)
|
|
|
|
def get_status(self):
|
|
return self.datasource.get_submit_status(self.id)
|
|
|
|
def get_compilemessage(self):
|
|
return self.datasource.get_submit_compilemessage(self.id)
|
|
|
|
def update_test_results(self, results):
|
|
config = getConfig()
|
|
|
|
newresults = []
|
|
for r in results:
|
|
# stdout
|
|
with open(r[4], 'r') as f:
|
|
r[4] = f.read(config.output_sendback_size_limit)
|
|
# stderr
|
|
with open(r[5], 'r') as f:
|
|
r[5] = f.read(config.output_sendback_size_limit)
|
|
|
|
# strip stdout and stderr send back to datasource
|
|
# preventing post data too big
|
|
if len(r[4]) > config.output_sendback_size_limit:
|
|
r[4] = r[4][0:config.output_sendback_size_limit]
|
|
if len(r[5]) > config.output_sendback_size_limit:
|
|
r[5] = r[5][0:config.output_sendback_size_limit]
|
|
|
|
newresults.append({ 'test_id' : r[0],
|
|
'judge_result' : r[1],
|
|
'exitcode' : r[2],
|
|
'signal' : r[3],
|
|
'stdout' : r[4],
|
|
'stderr' : r[5],
|
|
'timeused' : r[6],
|
|
'memused' : r[7] })
|
|
|
|
return self.datasource.update_submit_test_results(self.id, newresults)
|
|
|
|
class TestCase:
|
|
|
|
write_lock = threading.Lock()
|
|
|
|
def __init__(self, datasource, row):
|
|
config = getConfig()
|
|
logger = logging.getLogger('main')
|
|
self.id = row['id']
|
|
self.problem_id = row['problem_id']
|
|
self.timemodified = row['timemodified']
|
|
#self.input = string.replace(row['input'], '\r\n', '\n')
|
|
#self.output = string.replace(row['output'], '\r\n', '\n')
|
|
self.timelimit = row['timelimit']
|
|
if not self.timelimit:
|
|
self.timelimit = 1
|
|
self.memlimit = row['memlimit']
|
|
if not self.memlimit:
|
|
self.memlimit = config.maxmem
|
|
if 'nproc' in row and row['nproc']:
|
|
self.nproc = int(row['nproc'])
|
|
else:
|
|
self.nproc = 0
|
|
|
|
config = getConfig()
|
|
testdir = os.path.join(config.datadir, 'testcase')
|
|
if not os.path.exists(testdir): os.mkdir(testdir)
|
|
|
|
self.infile = os.path.join(testdir, self.id + '.in')
|
|
self.outfile = os.path.join(testdir, self.id + '.out')
|
|
|
|
TestCase.write_lock.acquire()
|
|
|
|
if os.path.exists(self.infile):
|
|
inmtime = os.stat(self.infile)[stat.ST_MTIME]
|
|
else:
|
|
inmtime = 0
|
|
if os.path.exists(self.outfile):
|
|
outmtime = os.stat(self.outfile)[stat.ST_MTIME]
|
|
else:
|
|
outmtime = 0
|
|
logger.debug("inmtime=%d outmtime=%d timemodified=%d" % (inmtime, outmtime, self.timemodified))
|
|
if inmtime <= self.timemodified or outmtime <= self.timemodified:
|
|
logger.debug('Creating input/output file %s and %s' % (self.infile, self.outfile))
|
|
row = datasource.get_test(self.id)
|
|
input = row['input'].replace('\r\n', '\n')
|
|
output = row['output'].replace('\r\n', '\n')
|
|
|
|
|
|
with open(self.infile, 'w') as f:
|
|
f.write(input)
|
|
if len(input) > 0 and input[-1] != '\n':
|
|
f.write('\n')
|
|
|
|
with open(self.outfile, 'w') as f:
|
|
f.write(output)
|
|
if len(output) > 0 and output[-1] != '\n':
|
|
f.write('\n')
|
|
logger.debug('Finished')
|
|
else:
|
|
logger.debug('Skip input/output file creation')
|
|
|
|
TestCase.write_lock.release()
|
|
|
|
def get_input_file(self):
|
|
return self.infile
|
|
|
|
def get_output_file(self):
|
|
return self.outfile
|
|
|
|
class PresetCode:
|
|
|
|
def __init__(self, datasource, row):
|
|
self.datasource = datasource
|
|
self.problem = None
|
|
|
|
self.id = row['id']
|
|
self.name = row['name']
|
|
self.code = row['code']
|
|
self.isheader = row['isheader']
|
|
|
|
class DataFile:
|
|
|
|
write_lock = threading.Lock()
|
|
|
|
def __init__(self, datasource, row):
|
|
self.datasource = datasource
|
|
self.problem = None
|
|
|
|
# Data passed from datasource
|
|
self.id = row['id']
|
|
self.problem_id = row['problem_id']
|
|
self.filename = row['filename']
|
|
self.type = row['type']
|
|
self.timemodified = row['timemodified']
|
|
|
|
# Save datafile
|
|
config = getConfig()
|
|
logger = logging.getLogger('main')
|
|
testdir = os.path.join(config.datadir, 'testcase')
|
|
if not os.path.exists(testdir): os.mkdir(testdir)
|
|
self.absolute_path = os.path.join(
|
|
testdir, self.problem_id + '.' + self.filename)
|
|
|
|
DataFile.write_lock.acquire()
|
|
|
|
mtime = 0
|
|
if os.path.exists(self.absolute_path):
|
|
mtime = os.stat(self.absolute_path)[stat.ST_MTIME]
|
|
if mtime < self.timemodified:
|
|
data = datasource.get_datafile_data(self.id)
|
|
try:
|
|
data = bz2.decompress(data)
|
|
except OSError:
|
|
logger.exception('Failed to decompress datafile %s', self.id)
|
|
DataFile.write_lock.release()
|
|
raise
|
|
if self.type == 'text':
|
|
if isinstance(data, (bytes, bytearray)):
|
|
text = data.decode('utf-8', errors='replace')
|
|
else:
|
|
text = str(data)
|
|
with open(self.absolute_path, 'w') as f:
|
|
f.write(text.replace('\r\n', '\n'))
|
|
else:
|
|
if isinstance(data, str):
|
|
data = data.encode('utf-8', errors='replace')
|
|
with open(self.absolute_path, 'wb') as f:
|
|
f.write(data)
|
|
|
|
DataFile.write_lock.release()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|
|
|
|
# vim: set expandtab tabstop=4 shiftwidth=4:
|