Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save solution's stderr to a file under rime-out #104

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
23 changes: 13 additions & 10 deletions rime/plugins/judge_system/domjudge.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import shutil
import signal
import subprocess
import tempfile
import threading
import time

Expand Down Expand Up @@ -74,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 @@ -156,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 @@ -206,22 +207,24 @@ 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')
if os.path.exists(feedback_dir_name):
shutil.rmtree(feedback_dir_name)
os.makedirs(feedback_dir_name, exist_ok=True)
# 2nd argument is an "expected output" file, which is not supported
# in rime interactive for now.
# As a placeholder, using a temporary file.
with tempfile.NamedTemporaryFile() as tmpfile:

# Makes sure output file exists.
open(output, 'w').close()

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

Expand Down
29 changes: 17 additions & 12 deletions rime/plugins/plus/flexible_judge.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,17 @@ 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):
# Not sure how solution's stderr should be handled.
return reactive.Run(
args=("'%s'" % ' '.join(args),),
cwd=cwd,
Expand All @@ -72,16 +74,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 +112,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 +131,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 +146,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 +199,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