def _load_test_case_info(self): try: with open(os.path.join(self._test_case_dir, "info")) as f: return json.load(f) except IOError: raise JudgeClientError("Test case not found" + self._test_case_dir) except ValueError: raise JudgeClientError("Bad test case config")
def load_judge_info(self, problem_id): try: with open(os.path.join(self.task_path, 'info.json')) as f: return json.load(f) except IOError: raise JudgeClientError("Test case not found: " + problem_id) except ValueError: raise JudgeClientError("Bad test case config")
def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir, spj_version, spj_config, output=False): self._run_config = run_config self._exe_path = exe_path self._max_cpu_time = max_cpu_time self._max_memory = max_memory self._max_real_time = self._max_cpu_time * 3 self._test_case_id = test_case_id self._test_case_dir = os.path.join(TEST_CASE_DIR, test_case_id) self._submission_dir = submission_dir self._pool = Pool(processes=psutil.cpu_count()) self._test_case_info = self._load_test_case_info() self._spj_version = spj_version self._spj_config = spj_config self._output = output if self._spj_version and self._spj_config: self._spj_exe = os.path.join( SPJ_EXE_DIR, self._spj_config["exe_name"].format( spj_version=self._spj_version)) if not os.path.exists(self._spj_exe): raise JudgeClientError("spj exe not found")
def __exit__(self, exc_type, exc_val, exc_tb): if not DEBUG: try: shutil.rmtree(self.path) except Exception as e: logger.exception(e) raise JudgeClientError("failed to clean runtime dir")
def _judge_one(self, test_case_file_id): test_case_info = self._get_test_case_file_info(test_case_file_id) in_file = os.path.join(self._test_case_dir, test_case_info["input_name"]) user_output_file = os.path.join(self._submission_dir, test_case_file_id + ".out") command = self._run_config["command"].format(exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path), max_memory=int(self._max_memory / 1024)).split(" ") env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get("env", []) run_result = _judger.run(max_cpu_time=self._max_cpu_time, max_real_time=self._max_real_time, max_memory=self._max_memory, max_stack=128 * 1024 * 1024, max_output_size=max(test_case_info.get("output_size", 0) * 2, 1024 * 1024 * 16), max_process_number=_judger.UNLIMITED, exe_path=command[0], input_path=in_file, output_path=user_output_file, error_path=user_output_file, args=command[1::], env=env, log_path=JUDGER_RUN_LOG_PATH, seccomp_rule_name=self._run_config["seccomp_rule"], uid=RUN_USER_UID, gid=RUN_GROUP_GID, memory_limit_check_only=self._run_config.get("memory_limit_check_only", 0)) run_result["test_case"] = test_case_file_id # if progress exited normally, then we should check output result run_result["output_md5"] = None run_result["output"] = None if run_result["result"] == _judger.RESULT_SUCCESS: if self._test_case_info.get("spj"): if not self._spj_config or not self._spj_version: raise JudgeClientError("spj_config or spj_version not set") spj_result = self._spj(in_file_path=in_file, user_out_file_path=user_output_file) if spj_result == SPJ_WA: run_result["result"] = _judger.RESULT_WRONG_ANSWER elif spj_result == SPJ_ERROR: run_result["result"] = _judger.RESULT_SYSTEM_ERROR run_result["error"] = _judger.ERROR_SPJ_ERROR else: run_result["output_md5"], is_ac, is_pe = self._compare_output(test_case_file_id) # -1 == Wrong Answer if not is_ac: run_result["result"] = _judger.RESULT_WRONG_ANSWER if not is_ac and is_pe: run_result["result"] = _judger.RESULT_PRESENTATION_ERROR if self._output: try: with open(user_output_file, "r", encoding="utf-8") as f: run_result["output"] = f.read() except Exception: pass return run_result
def __enter__(self): try: os.mkdir(self.path) os.chmod(self.path, 0o777) except Exception as e: logger.exception(e) raise JudgeClientError("failed to create runtime dir") return self.path
def __exit__(self, exc_type, exc_val, exc_tb): if not DEBUG: try: shutil.rmtree(self.work_dir) #remove temp files pass except Exception as e: logger.exception(e) raise JudgeClientError("failed to clean runtime dir")
def __enter__(self): try: os.mkdir(self.path) os.chown(self.path, COMPILER_USER_UID, RUN_GROUP_GID) os.chmod(self.path, 0o711) except Exception as e: logger.exception(e) raise JudgeClientError("failed to create runtime dir") return self.path
def __enter__(self): try: os.mkdir(self.work_dir) if self.init_test_case_dir: os.mkdir(self.test_case_dir) os.chown(self.work_dir, COMPILER_USER_UID, RUN_GROUP_GID) os.chmod(self.work_dir, 0o711) except Exception as e: logger.exception(e) raise JudgeClientError("failed to create runtime dir") return self.work_dir, self.test_case_dir
def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_dir, submission_dir, spj_version, spj_config, io_mode, submission_id, input_str, output=False, output_description=None): self._run_config = run_config self._exe_path = exe_path self._max_cpu_time = max_cpu_time self._max_memory = max_memory self._max_real_time = self._max_cpu_time * 3 self._test_case_dir = test_case_dir self._submission_dir = submission_dir self._submission_id = submission_id self._pool = Pool(processes=psutil.cpu_count()) self._test_case_info = self._load_test_case_info() self._spj_version = spj_version self._spj_config = spj_config self._output = output self._io_mode = io_mode self._input_str = input_str pattern = re.compile(r'<[^>]+>', re.S) self._output_description = pattern.sub('', output_description) if self._spj_version and self._spj_config: self._spj_exe = os.path.join( SPJ_EXE_DIR, self._spj_config["exe_name"].format( spj_version=self._spj_version)) if not os.path.exists(self._spj_exe): raise JudgeClientError("spj exe not found")
def __init__(self, run_config, exe_path, max_cpu_time, max_memory, test_case_id, submission_dir, spj_version, spj_config, output=False): #_run_config是一个json的数据 self._run_config = run_config self._exe_path = exe_path self._max_cpu_time = max_cpu_time self._max_memory = max_memory #最大真实时间限定为最大CPU时间的3倍 self._max_real_time = self._max_cpu_time * 3 self._test_case_id = test_case_id #因为每个测试用例不同的,这个test_case_id也应该有用户传进,然后拼接在一起形成一个新的文件路径 self._test_case_dir = os.path.join(TEST_CASE_DIR, test_case_id) #_submission_dir=submission_dir=/judger/run/submission_id/ self._submission_dir = submission_dir #实例化一个多进程池,里面的进程数根据系统CPU逻辑个数开启 self._pool = Pool(processes=psutil.cpu_count()) #加载测试用例信息 self._test_case_info = self._load_test_case_info() self._spj_version = spj_version self._spj_config = spj_config self._output = output #如果特殊评判版本和配置不为空,则执行特殊评判 #拼接配置特殊评判的执行文件的路径,注意这里是config的,非compile if self._spj_version and self._spj_config: self._spj_exe = os.path.join( SPJ_EXE_DIR, self._spj_config["exe_name"].format( spj_version=self._spj_version)) #到SPJ_EXE_DIR去找,如果特殊评判执行文件不存在,则抛出异常 if not os.path.exists(self._spj_exe): raise JudgeClientError("spj exe not found")
def get_token(): token = os.environ.get("TOKEN") if token: return token else: raise JudgeClientError("env 'token' not found")
def judge(cls, language_config, src, max_cpu_time, max_memory, test_case_id=None, test_case=None, spj_version=None, spj_config=None, spj_compile_config=None, spj_src=None, output=False, io_mode=None, output_description=None, input_str=None): if not io_mode: io_mode = {"io_mode": ProblemIOMode.standard} if not (test_case or test_case_id) or (test_case and test_case_id): raise JudgeClientError("invalid parameter") # init compile_config = language_config.get("compile") run_config = language_config["run"] submission_id = uuid.uuid4().hex is_spj = spj_version and spj_config if is_spj: spj_exe_path = os.path.join( SPJ_EXE_DIR, spj_config["exe_name"].format(spj_version=spj_version)) # spj src has not been compiled if not os.path.isfile(spj_exe_path): logger.warning( "%s does not exists, spj src will be recompiled") cls.compile_spj(spj_version=spj_version, src=spj_src, spj_compile_config=spj_compile_config) init_test_case_dir = bool(test_case) with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id), init_test_case_dir=init_test_case_dir) as dirs: submission_dir, test_case_dir = dirs test_case_dir = test_case_dir or os.path.join( TEST_CASE_DIR, test_case_id) if compile_config: src_path = os.path.join(submission_dir, compile_config["src_name"]) # write source code into file with open(src_path, "w", encoding="utf-8") as f: src = "import sys \nimport codecs \nsys.stdout = codecs.getwriter('utf-8')(sys.stdout.detach()) \n" + src f.write(src) os.chown(src_path, COMPILER_USER_UID, 0) os.chmod(src_path, 0o400) # compile source code, return exe file path exe_path = Compiler().compile(compile_config=compile_config, src_path=src_path, output_dir=submission_dir) try: # Java exe_path is SOME_PATH/Main, but the real path is SOME_PATH/Main.class # We ignore it temporarily os.chown(exe_path, RUN_USER_UID, 0) os.chmod(exe_path, 0o500) except Exception: pass else: exe_path = os.path.join(submission_dir, run_config["exe_name"]) with open(exe_path, "w", encoding="utf-8") as f: f.write(src) if init_test_case_dir: info = { "test_case_number": len(test_case), "spj": is_spj, "test_cases": {} } # write test case for index, item in enumerate(test_case): index += 1 item_info = {} input_name = str(index) + ".in" item_info["input_name"] = input_name input_data = item["input"].encode("utf-8") item_info["input_size"] = len(input_data) with open(os.path.join(test_case_dir, input_name), "wb") as f: f.write(input_data) if not is_spj: output_name = str(index) + ".out" item_info["output_name"] = output_name output_data = item["output"].encode("utf-8") item_info["output_md5"] = hashlib.md5( output_data).hexdigest() item_info["output_size"] = len(output_data) item_info["stripped_output_md5"] = hashlib.md5( output_data.rstrip()).hexdigest() with open(os.path.join(test_case_dir, output_name), "wb") as f: f.write(output_data) info["test_cases"][index] = item_info with open(os.path.join(test_case_dir, "info"), "w") as f: json.dump(info, f) judge_client = JudgeClient(run_config=language_config["run"], exe_path=exe_path, max_cpu_time=max_cpu_time, max_memory=max_memory, test_case_dir=test_case_dir, submission_dir=submission_dir, submission_id=submission_id, spj_version=spj_version, spj_config=spj_config, output=output, io_mode=io_mode, output_description=output_description, input_str=input_str) run_result = judge_client.run() return run_result
def _judge_one(self, test_case_file_id): test_case_info = self._get_test_case_file_info(test_case_file_id) in_file = os.path.join(self._test_case_dir, test_case_info["input_name"]) if self._io_mode["io_mode"] == ProblemIOMode.file: user_output_dir = os.path.join(self._submission_dir, str(test_case_file_id)) os.mkdir(user_output_dir) os.chown(user_output_dir, RUN_USER_UID, RUN_GROUP_GID) os.chmod(user_output_dir, 0o711) os.chdir(user_output_dir) # todo check permission user_output_file = os.path.join(user_output_dir, self._io_mode["output"]) real_user_output_file = os.path.join(user_output_dir, "stdio.txt") shutil.copyfile( in_file, os.path.join(user_output_dir, self._io_mode["input"])) kwargs = { "input_path": in_file, "output_path": real_user_output_file, "error_path": real_user_output_file } else: real_user_output_file = user_output_file = os.path.join( self._submission_dir, test_case_file_id + ".out") kwargs = { "input_path": in_file, "output_path": real_user_output_file, "error_path": real_user_output_file } command = self._run_config["command"].format( exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path), max_memory=int(self._max_memory / 1024)).split(" ") env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get( "env", []) seccomp_rule = self._run_config["seccomp_rule"] if isinstance(seccomp_rule, dict): seccomp_rule = seccomp_rule[self._io_mode["io_mode"]] run_result = _judger.run(max_cpu_time=self._max_cpu_time, max_real_time=self._max_real_time, max_memory=self._max_memory, max_stack=128 * 1024 * 1024, max_output_size=max( test_case_info.get("output_size", 0) * 2, 1024 * 1024 * 16), max_process_number=_judger.UNLIMITED, exe_path=command[0], args=command[1::], env=env, log_path=JUDGER_RUN_LOG_PATH, seccomp_rule_name=seccomp_rule, uid=RUN_USER_UID, gid=RUN_GROUP_GID, memory_limit_check_only=self._run_config.get( "memory_limit_check_only", 0), **kwargs) run_result["test_case"] = test_case_file_id # if progress exited normally, then we should check output result run_result["output_md5"] = None run_result["output"] = None if run_result["result"] == _judger.RESULT_SUCCESS: if not os.path.exists(user_output_file): run_result["result"] = _judger.RESULT_WRONG_ANSWER else: if self._test_case_info.get("spj"): if not self._spj_config or not self._spj_version: raise JudgeClientError( "spj_config or spj_version not set") spj_result = self._spj(in_file_path=in_file, user_out_file_path=user_output_file) if spj_result == SPJ_WA: run_result["result"] = _judger.RESULT_WRONG_ANSWER elif spj_result == SPJ_ERROR: run_result["result"] = _judger.RESULT_SYSTEM_ERROR run_result["error"] = _judger.ERROR_SPJ_ERROR else: run_result["output_md5"], is_ac = self._compare_output( test_case_file_id, user_output_file) # -1 == Wrong Answer if not is_ac: run_result["result"] = _judger.RESULT_WRONG_ANSWER if self._output: try: with open(user_output_file, "rb") as f: run_result["output"] = f.read().decode( "utf-8", errors="backslashreplace") except Exception: pass return run_result
def judge(cls, language_config, src, max_cpu_time, max_memory, test_case_id=None, test_case=None, spj_version=None, spj_config=None, spj_compile_config=None, spj_src=None, output=False, io_mode=None): if not io_mode: io_mode = {"io_mode": ProblemIOMode.standard} if not (test_case or test_case_id) or (test_case and test_case_id): raise JudgeClientError("invalid parameter") # init compile_config = language_config.get("compile") run_config = language_config["run"] submission_id = uuid.uuid4().hex # 是否是特殊题 is_spj = spj_version and spj_config if is_spj: spj_exe_path = os.path.join( SPJ_EXE_DIR, spj_config["exe_name"].format(spj_version=spj_version)) # spj src has not been compiled if not os.path.isfile(spj_exe_path): logger.warning( "%s does not exists, spj src will be recompiled") cls.compile_spj(spj_version=spj_version, src=spj_src, spj_compile_config=spj_compile_config) # 初始化判题目录 init_test_case_dir = bool(test_case) with InitSubmissionEnv(JUDGER_WORKSPACE_BASE, submission_id=str(submission_id), init_test_case_dir=init_test_case_dir) as dirs: submission_dir, test_case_dir = dirs test_case_dir = test_case_dir or os.path.join( TEST_CASE_DIR, test_case_id) #若compile_config 不为空创建获得源码路径 if compile_config: src_path = os.path.join(submission_dir, compile_config["src_name"]) # 将源码写入源码地址 with open(src_path, "w", encoding="utf-8") as f: f.write(src) os.chown(src_path, COMPILER_USER_UID, 0) os.chmod(src_path, 0o400) # compile source code, return exe file path exe_path = Compiler().compile(compile_config=compile_config, src_path=src_path, output_dir=submission_dir) try: # Java exe_path is SOME_PATH/Main, but the real path is SOME_PATH/Main.class # We ignore it temporarily os.chown(exe_path, RUN_USER_UID, 0) os.chmod(exe_path, 0o500) except Exception: pass #若compile_config为空 直接获得EXE路径 else: exe_path = os.path.join(submission_dir, run_config["exe_name"]) with open(exe_path, "w", encoding="utf-8") as f: f.write(src) # 初始化判题目录 # info # |-test_case_numeber int # |-spj bool # |-test_cases # ||-item_info[0] # ||-item_info[1] # ||- ... if init_test_case_dir: info = { "test_case_number": len(test_case), "spj": is_spj, "test_cases": {} } # write test case for index, item in enumerate(test_case): index += 1 item_info = {} # item_info # |-input_name # |-input_size # |-output_name # |-output_md5 # |-output_size # |-stripped_output_md5 input_name = str(index) + ".in" item_info["input_name"] = input_name input_data = item["input"].encode("utf-8") item_info["input_size"] = len(input_data) with open(os.path.join(test_case_dir, input_name), "wb") as f: f.write(input_data) if not is_spj: output_name = str(index) + ".out" item_info["output_name"] = output_name output_data = item["output"].encode("utf-8") item_info["output_md5"] = hashlib.md5( output_data).hexdigest() item_info["output_size"] = len(output_data) # strip() # 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。 # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。 item_info["stripped_output_md5"] = hashlib.md5( output_data.rstrip()).hexdigest() with open(os.path.join(test_case_dir, output_name), "wb") as f: f.write(output_data) info["test_cases"][index] = item_info with open(os.path.join(test_case_dir, "info"), "w") as f: json.dump(info, f) # json.dumps()函数是将一个Python数据类型列表进行json格式的编码 # 开始初始化评测机 judge_client = JudgeClient(run_config=language_config["run"], exe_path=exe_path, max_cpu_time=max_cpu_time, max_memory=max_memory, test_case_dir=test_case_dir, submission_dir=submission_dir, spj_version=spj_version, spj_config=spj_config, output=output, io_mode=io_mode) run_result = judge_client.run() return run_result
def _judge_one(self, test_case_file_id): # 找到测试用例信息 test_case_info = self._get_test_case_file_info(test_case_file_id) # 输入文件路径,input_name:1.in,那么路径就是/test_case/1.in in_file = os.path.join(self._test_case_dir, test_case_info["input_name"]) # 输出文件路径:user_output_file=_submission_dir+test_case_file_id.out=/judger/run/submission_id/test_case_file_id.out user_output_file = os.path.join(self._submission_dir, test_case_file_id + ".out") #先格式化执行文件命令并按照空格分割成块,exe_path对应c和c++,exe_dir和max_memory对应java command = self._run_config["command"].format( exe_path=self._exe_path, exe_dir=os.path.dirname(self._exe_path), max_memory=int(self._max_memory / 1024)).split(" ") #设置运行环境:系统的路径拼接上运行配置的路径 env = ["PATH=" + os.environ.get("PATH", "")] + self._run_config.get( "env", []) run_result = _judger.run( max_cpu_time=self._max_cpu_time, max_real_time=self._max_real_time, max_memory=self._max_memory, max_stack=128 * 1024 * 1024, # 根据配置文件要求,比较选取最大的那个 max_output_size=max( test_case_info.get("output_size", 0) * 2, 1024 * 1024 * 16), max_process_number=_judger.UNLIMITED, #这里执行的是用户的编译好的代码 exe_path=command[0], input_path=in_file, output_path=user_output_file, error_path=user_output_file, #从第1个参数开始,直至最后 args=command[1::], env=env, log_path=JUDGER_RUN_LOG_PATH, #这里需要设置黑名单安全计算规则 seccomp_rule_name=self._run_config["seccomp_rule"], uid=RUN_USER_UID, gid=RUN_GROUP_GID, #由于java比较特殊,所以只设置其运行内存为检查,查出了就报错 memory_limit_check_only=self._run_config.get( "memory_limit_check_only", 0)) #这个是judge.run():返回的数据:例如{'cpu_time': 0, 'signal': 0, 'memory': 4554752, 'exit_code': 0, 'result': 0, 'error': 0, 'real_time': 2} #因为run_result里面的json数据是没有对应的test_cast这么一条数据的,但是可以添加进去,那么运行的结果就有对应的数据了 #因为是for循环进行的调用的,所以可以每次评判完成时候添加这几个数据,例如下面的outp_md5和output因为还没有生成,需要 #进行测试结果比较会后才会返回,所以这里就先将它们赋值为None,等返回对应的之后再进行相应的覆盖即可。 #run_result是一个json的数据,里面的参数就是运行的结果 run_result["test_case"] = test_case_file_id # if progress exited normally, then we should check output result # 如果进程正常退出,那么然后我们就应该检查输出结果 run_result["output_md5"] = None run_result["output"] = None # 如果评测结果通过,仅仅运行没有错误,还要将结果进行比较 if run_result["result"] == _judger.RESULT_SUCCESS: #调用_load_test_case_info加载测试用例信息,当spj为真,就进行spj评判,否者比较结果 if self._test_case_info.get("spj"): #如果特殊测试配值为0或者版本号没设置,抛出相应的异常 if not self._spj_config or not self._spj_version: raise JudgeClientError("spj_config or spj_version not set") #意思就是通过正常的测试之后,如果需要进行特殊评判的话,就进入特殊评判,所以输入文 # 件路径还是从本目录传进去,等到调用_spj()函数之后,在做相应的用户和用户组和权限的更改。 spj_result = self._spj(in_file_path=in_file, user_out_file_path=user_output_file) #特殊评判答案错误-1 if spj_result == SPJ_WA: run_result["result"] = _judger.RESULT_WRONG_ANSWER #返回1(这里不设RESULT_CPU_TIME_LIMIT_EXCEEDED),因为不用,只是然后用户知道是系统错误就行 elif spj_result == SPJ_ERROR: run_result["result"] = _judger.RESULT_SYSTEM_ERROR run_result["error"] = _judger.ERROR_SPJ_ERROR else: #否则就不用进行特殊测试,直接比较结果的md5值,判断评测结果,返回之后覆盖None run_result["output_md5"], is_ac = self._compare_output( test_case_file_id) # -1 为错误答案 # is_ac为假,WA并不便是运算不通过,是得出的结果和测试数据的不同 if not is_ac: run_result["result"] = _judger.RESULT_WRONG_ANSWER #输出文件不为空,就设置运行的结果为文件的内容 if self._output: try: with open(user_output_file, "r", encoding="utf-8") as f: #覆盖之前的None run_result["output"] = f.read() except Exception: pass return run_result