Skip to content

Commit

Permalink
Save solution's stderr to a file under rime-out
Browse files Browse the repository at this point in the history
  • Loading branch information
tossy310 committed Sep 22, 2024
1 parent eeaecb6 commit 05a2a9d
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 41 deletions.
39 changes: 25 additions & 14 deletions rime/basic/codes.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/python

import contextlib
import optparse
import os
import os.path
Expand Down Expand Up @@ -35,13 +36,14 @@ def Compile(self):

@taskgraph.task_method
def Run(self, args, cwd, input, output, timeout, precise,
redirect_error=False, ok_returncode=0, ng_returncode=None):
redirect_error=False, stderr_file=None,
ok_returncode=0, ng_returncode=None):
"""Run the code and return RunResult."""
try:
result = yield self._ExecForRun(
args=tuple(list(self.run_args) + list(args)), cwd=cwd,
input=input, output=output, timeout=timeout, precise=precise,
redirect_error=redirect_error,
redirect_error=redirect_error, stderr_file=stderr_file,
ok_returncode=ok_returncode, ng_returncode=ng_returncode)
except Exception as e:
result = codes.RunResult('On execution: %s' % e, None)
Expand Down Expand Up @@ -73,18 +75,27 @@ def _ExecForCompile(self, args):

@taskgraph.task_method
def _ExecForRun(self, args, cwd, input, output, timeout, precise,
redirect_error=False, ok_returncode=0, ng_returncode=None):
with open(input, 'r') as infile:
with open(output, 'w') as outfile:
if redirect_error:
errfile = subprocess.STDOUT
else:
errfile = files.OpenNull()
yield (yield self._ExecInternal(
args=args, cwd=cwd,
stdin=infile, stdout=outfile, stderr=errfile,
timeout=timeout, precise=precise,
ok_returncode=ok_returncode, ng_returncode=ng_returncode))
redirect_error=False, stderr_file=None,
ok_returncode=0, ng_returncode=None):
with contextlib.ExitStack() as exitStack:
infile = exitStack.enter_context(open(input, 'r'))
outfile = exitStack.enter_context(open(output, 'w'))

if redirect_error and stderr_file:
# Internal inconsistency, this should not happen.
raise taskgraph.Bailout([False])
elif redirect_error:
errfile = subprocess.STDOUT
elif stderr_file:
errfile = exitStack.enter_context(open(stderr_file, 'w'))
else:
errfile = files.OpenNull()

yield (yield self._ExecInternal(
args=args, cwd=cwd,
stdin=infile, stdout=outfile, stderr=errfile,
timeout=timeout, precise=precise,
ok_returncode=ok_returncode, ng_returncode=ng_returncode))

@taskgraph.task_method
def _ExecInternal(self, args, cwd, stdin, stdout, stderr,
Expand Down
1 change: 1 addition & 0 deletions rime/basic/consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
CACHE_EXT = '.cache'
LOG_EXT = '.log'
VALIDATION_EXT = '.validation'
STDERR_EXT = '.stderr'

RIME_OUT_DIR = 'rime-out'

Expand Down
5 changes: 3 additions & 2 deletions rime/basic/targets/solution.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,12 @@ def Build(self, ui):
yield True

@taskgraph.task_method
def Run(self, args, cwd, input, output, timeout, precise):
def Run(self, args, cwd, input, output, timeout, precise,
stderr_file=None):
"""Run this solution."""
yield (yield self.code.Run(
args=args, cwd=cwd, input=input, output=output,
timeout=timeout, precise=precise))
timeout=timeout, precise=precise, stderr_file=stderr_file))

@taskgraph.task_method
def Test(self, ui):
Expand Down
7 changes: 4 additions & 3 deletions rime/basic/targets/testset.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,17 +507,18 @@ def _TestOneCaseNoCache(self, solution, testcase, ui):
Never cache results.
Returns TestCaseResult.
"""
outfile, judgefile = [
outfile, judgefile, stderrfile = [
os.path.join(
solution.out_dir,
os.path.splitext(os.path.basename(testcase.infile))[0] + ext)
for ext in (consts.OUT_EXT, consts.JUDGE_EXT)]
for ext in (consts.OUT_EXT, consts.JUDGE_EXT, consts.STDERR_EXT)]
precise = (ui.options.precise or ui.options.parallelism <= 1)
res = yield solution.Run(
args=(), cwd=solution.out_dir,
input=testcase.infile,
output=outfile,
timeout=testcase.timeout, precise=precise)
timeout=testcase.timeout, precise=precise,
stderr_file=stderrfile)
if res.status == core_codes.RunResult.TLE:
yield test.TestCaseResult(solution, testcase,
test.TestCaseResult.TLE,
Expand Down
24 changes: 14 additions & 10 deletions rime/plugins/judge_system/domjudge.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,10 @@ def Run(self, judge, infile, difffile, outfile, cwd, judgefile):


class DOMJudgeReactiveTask(taskgraph.Task):
def __init__(self, judge_args, solution_args, **kwargs):
def __init__(self, judge_args, solution_args, solution_stderr, **kwargs):
self.judge_args = judge_args
self.solution_args = solution_args
self.solution_stderr = solution_stderr
self.judge_proc = None
self.solution_proc = None
if 'timeout' in kwargs:
Expand Down Expand Up @@ -155,7 +156,8 @@ def _StartProcess(self):
**self.kwargs)
self.solution_proc = subprocess.Popen(
self.solution_args, stdin=self.judge_proc.stdout,
stdout=self.judge_proc.stdin, **self.kwargs)
stdout=self.judge_proc.stdin, stderr=self.solution_stderr,
**self.kwargs)
# Makes writing side responsible to close the pipe.

def pipe_closer(write_proc, read_proc):
Expand Down Expand Up @@ -205,7 +207,8 @@ class DOMJudgeReactiveRunner(flexible_judge.ReactiveRunner):
PREFIX = 'domjudge'

@taskgraph.task_method
def Run(self, reactive, args, cwd, input, output, timeout, precise):
def Run(self, reactive, args, cwd, input, output, timeout, precise,
stderr_file):
feedback_dir_name = os.path.join(
cwd,
os.path.splitext(os.path.basename(input))[0] + '.feedback')
Expand All @@ -216,13 +219,14 @@ def Run(self, reactive, args, cwd, input, output, timeout, precise):
# Makes sure output file exists.
open(output, 'w').close()

judge_args = reactive.run_args + \
(input, output, feedback_dir_name, )
solution_args = args
task = DOMJudgeReactiveTask(
judge_args, solution_args,
cwd=cwd, timeout=timeout, exclusive=precise)
(judge_proc, solution_proc) = yield task
with open(stderr_file, 'w') as solution_stderr:
judge_args = reactive.run_args + \
(input, output, feedback_dir_name, )
solution_args = args
task = DOMJudgeReactiveTask(
judge_args, solution_args, solution_stderr,
cwd=cwd, timeout=timeout, exclusive=precise)
(judge_proc, solution_proc) = yield task

judge_code = judge_proc.returncode
solution_code = solution_proc.returncode
Expand Down
28 changes: 16 additions & 12 deletions rime/plugins/plus/flexible_judge.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,16 @@ def Run(self, judge, infile, difffile, outfile, cwd, judgefile):


class ReactiveRunner(object):
def Run(self, reactive, solution, args, cwd, input, output, timeout,
precise):
def Run(self, reactive, args, cwd, input, output, timeout, precise,
stderr_file):
raise NotImplementedError()


class KUPCReactiveRunner(ReactiveRunner):
PREFIX = 'kupc'

def Run(self, reactive, args, cwd, input, output, timeout, precise):
def Run(self, reactive, args, cwd, input, output, timeout, precise,
stderr_file):
return reactive.Run(
args=("'%s'" % ' '.join(args),),
cwd=cwd,
Expand All @@ -72,16 +73,16 @@ def Run(self, reactive, args, cwd, input, output, timeout, precise):
class TestlibReactiveRunner(ReactiveRunner):
PREFIX = 'testlib'

def Run(self, reactive, solution, args, cwd, input, output, timeout,
precise):
def Run(self, reactive, args, cwd, input, output, timeout, precise,
stderr_file):
raise NotImplementedError()


class NEERCReactiveRunner(ReactiveRunner):
PREFIX = 'neerc'

def Run(self, reactive, solution, args, cwd, input, output, timeout,
precise):
def Run(self, reactive, args, cwd, input, output, timeout, precise,
stderr_file):
raise NotImplementedError()


Expand Down Expand Up @@ -110,11 +111,11 @@ def _TestOneCaseNoCache(self, solution, testcase, ui):
Never cache results.
Returns TestCaseResult.
"""
outfile, judgefile = [
outfile, judgefile, stderrfile = [
os.path.join(
solution.out_dir,
os.path.splitext(os.path.basename(testcase.infile))[0] + ext)
for ext in (consts.OUT_EXT, consts.JUDGE_EXT)]
for ext in (consts.OUT_EXT, consts.JUDGE_EXT, consts.STDERR_EXT)]
precise = (ui.options.precise or ui.options.parallelism <= 1)
# reactive
if self.reactives:
Expand All @@ -129,7 +130,8 @@ def _TestOneCaseNoCache(self, solution, testcase, ui):
args=solution.code.run_args, cwd=solution.out_dir,
input=testcase.infile,
output=outfile,
timeout=testcase.timeout, precise=precise)
timeout=testcase.timeout, precise=precise,
stderr_file=stderrfile)
# Normally, res is codes.RunResult.
# Some reactive variants returns TestCaseResult
if isinstance(res, test.TestCaseResult):
Expand All @@ -143,7 +145,8 @@ def _TestOneCaseNoCache(self, solution, testcase, ui):
args=(), cwd=solution.out_dir,
input=testcase.infile,
output=outfile,
timeout=testcase.timeout, precise=precise)
timeout=testcase.timeout, precise=precise,
stderr_file=stderrfile)
if res.status == core_codes.RunResult.TLE:
yield test.TestCaseResult(solution, testcase,
test.TestCaseResult.TLE,
Expand Down Expand Up @@ -195,7 +198,8 @@ def _RunReferenceSolutionOne(self, reference_solution, testcase, ui):
cwd=reference_solution.out_dir,
input=testcase.infile,
output=testcase.difffile,
timeout=None, precise=False)
timeout=None, precise=False,
stderr_file=os.devnull)
# Some reactive variants returns TestCaseResult
if isinstance(res, test.TestCaseResult):
if res.verdict != test.TestCaseResult.AC:
Expand Down

0 comments on commit 05a2a9d

Please sign in to comment.