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: