JOJ3-config-generator/joj3_config_generator/processers/task.py

313 lines
12 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import shlex
import re
from typing import List, Tuple
from joj3_config_generator.models import result, task
def get_conf_stage(
task_stage: task.Stage, executor_with_config: result.ExecutorWith
) -> result.StageDetail:
conf_stage = result.StageDetail(
name=task_stage.name if task_stage.name is not None else "",
# FIXME to be deterined the way
# group=(
# re.search(r'\[([^\[\]]+)\]', task_stage.name).group(1)
# if (task_stage.name is not None and re.search(r'\[([^\[\]]+)\]', task_stage.name))
# else ""
# ),
group=(
task_stage.group
if (task_stage.group is not None)
else ""
),
executor=result.Executor(
name="sandbox",
with_=executor_with_config,
),
parsers=(
[result.Parser(name=parser, with_={}) for parser in task_stage.parsers]
if task_stage.parsers is not None
else []
),
)
return conf_stage
def get_executorWithConfig(
task_stage: task.Stage, cached: List[str]
) -> Tuple[result.ExecutorWith, List[str]]:
file_import = (
task_stage.files.import_
if hasattr(task_stage, "files")
and hasattr(task_stage.files, "import_")
and (task_stage.files is not None)
and (task_stage.files.import_ is not None)
else []
)
copy_in_files = [file for file in file_import if (file not in cached)]
file_export = (
task_stage.files.export
if hasattr(task_stage, "files")
and hasattr(task_stage.files, "export")
and (task_stage.files is not None)
else []
)
copy_out_files = ["stdout", "stderr"]
executor_with_config = result.ExecutorWith(
default=result.Cmd(
args=(
shlex.split(task_stage.command)
if task_stage.command is not None
else []
),
# FIXME: remove this trick
copy_in={
("./.clang-tidy" if file.endswith("clang-tidy") else file): (
result.CmdFile(src=f"/home/tt/.config/joj/{file}")
if not file.endswith("main.cpp")
else result.CmdFile(
# src=f"/home/tt/.config/joj/homework/h7/e3/ex3-main.cpp"
src=f"/home/tt/.config/joj/homework/h8/e1/ex1-main.cpp"
)
)
for file in copy_in_files
},
stdin=(
result.CmdFile(content="") if "diff" not in task_stage.parsers else None
),
copy_out=copy_out_files,
copy_in_cached={file: file for file in cached},
copy_out_cached=file_export if file_export is not None else [],
cpu_limit=(
task_stage.limit.cpu * 1_000_000_000_000
if task_stage.limit is not None and task_stage.limit.cpu is not None
else 80 * 1_000_000_000_000
),
clock_limit=(
2 * task_stage.limit.cpu * 1_000_000_000_000
if task_stage.limit is not None and task_stage.limit.cpu is not None
else 80 * 1_000_000_000_000
),
memory_limit=(
task_stage.limit.mem * 1_024 * 1_024
if task_stage.limit is not None and task_stage.limit.mem is not None
else 800 * 1_024 * 1_024
),
stderr=result.CmdFile(
name="stderr",
max=(
task_stage.limit.stderr * 1_000_000_000_000
if task_stage.limit is not None
and task_stage.limit.stderr is not None
else 800 * 1_024 * 1_024
),
),
stdout=result.CmdFile(
name="stdout",
max=(
task_stage.limit.stdout * 1_000_000_000_000
if task_stage.limit is not None
and task_stage.limit.stdout is not None
else 800 * 1_024 * 1_024
),
),
),
cases=[], # You can add cases if needed
)
if file_export is not None:
for file in file_export:
if file not in cached:
cached.append(file)
return (executor_with_config, cached)
def fix_keyword(
task_stage: task.Stage, conf_stage: result.StageDetail
) -> result.StageDetail:
keyword_parser = ["clangtidy", "keyword", "cppcheck", "cpplint"]
if task_stage.parsers is not None:
for parser in task_stage.parsers:
if parser in keyword_parser:
keyword_parser_ = next(
p for p in conf_stage.parsers if p.name == parser
)
keyword_weight = []
if getattr(task_stage, parser, None) is not None:
unique_weight = list(set(getattr(task_stage, parser).weight))
for score in unique_weight:
keyword_weight.append({"keywords": [], "score": score})
for idx, score in enumerate(unique_weight):
for idx_, score_ in enumerate(
getattr(task_stage, parser).weight
):
if score == score_:
keyword_weight[idx]["keywords"].append(
getattr(task_stage, parser).keyword[idx_]
)
else:
continue
keyword_parser_.with_.update({"matches": keyword_weight, "fullscore": 0, "minscore": -1000, "files": ["stdout", "stderr"]})
else:
continue
return conf_stage
def fix_result_detail(
task_stage: task.Stage, conf_stage: result.StageDetail
) -> result.StageDetail:
if (task_stage.parsers is not None) and ("result-detail" in task_stage.parsers):
result_detail_parser = next(
p for p in conf_stage.parsers if p.name == "result-detail"
)
if task_stage.result_detail is not None:
show_files = []
if (
task_stage.result_detail.stdout
and task_stage.result_detail.stdout is not None
):
show_files.append("stdout")
if (
task_stage.result_detail.stderr
and task_stage.result_detail.stderr is not None
):
show_files.append("stderr")
result_detail_parser.with_.update(
{
"score": 0,
"comment": "",
"showFiles": show_files,
"showExitStatus": task_stage.result_detail.exitstatus,
"showRuntime": task_stage.result_detail.time,
"showMemory": task_stage.result_detail.mem,
}
)
return conf_stage
def fix_dummy(
task_stage: task.Stage, conf_stage: result.StageDetail
) -> result.StageDetail:
dummy_parser = [
"dummy",
"result-status",
]
if task_stage.parsers is not None:
for parser in task_stage.parsers:
if parser in dummy_parser:
dummy_parser_ = next(p for p in conf_stage.parsers if p.name == parser)
if (
getattr(task_stage, parser.replace("-", "_"), None) is not None
) and (task_stage.result_status is not None):
dummy_parser_.with_.update(
{
"score": task_stage.result_status.score,
"comment": task_stage.result_status.comment,
"forceQuitOnNotAccepted": task_stage.result_status.forcequit,
}
)
else:
continue
return conf_stage
def fix_file(task_stage: task.Stage, conf_stage: result.StageDetail) -> result.StageDetail:
file_parser = ["file"]
if task_stage.parsers is not None:
for parser in task_stage.parsers:
if parser in file_parser:
file_parser_ = next(p for p in conf_stage.parsers if p.name == parser)
if task_stage.file is not None:
file_parser_.with_.update(
{
"name": task_stage.file.name
}
)
else:
continue
return conf_stage
def fix_diff(
task_stage: task.Stage, conf_stage: result.StageDetail, task_conf: task.Config
) -> result.StageDetail:
if task_stage.parsers is not None and "diff" in task_stage.parsers:
diff_parser = next((p for p in conf_stage.parsers if p.name == "diff"), None)
skip = task_stage.skip or []
cases = task_stage.cases or {}
finalized_cases = [case for case in cases if case not in skip]
stage_cases = []
parser_cases = []
for case in finalized_cases:
case_stage = task_stage.cases.get(case) if task_stage.cases else None
if not case_stage:
continue
# Ensure case_stage.limit is defined before accessing .cpu and .mem
cpu_limit = (
case_stage.limit.cpu * 1_000_000_000
if case_stage.limit and case_stage.limit.cpu is not None
else 0
)
clock_limit = (
2 * case_stage.limit.cpu * 1_000_000_000
if case_stage.limit and case_stage.limit.cpu is not None
else 0
)
memory_limit = (
case_stage.limit.mem * 1_024 * 1_024
if case_stage.limit and case_stage.limit.mem is not None
else 0
)
command = case_stage.command if case_stage.command is not None else None
stdin = case_stage.in_ if case_stage.in_ is not None else f"{case}.in"
stdout = case_stage.out_ if case_stage.out_ is not None else f"{case}.out"
stage_cases.append(
result.OptionalCmd(
stdin=result.CmdFile(
src=f"/home/tt/.config/joj/{task_conf.task.type_}/{stdin}"
# src=f"/home/tt/.config/joj/{task_stage.path}/{stdin}"
),
args=(
shlex.split(case_stage.command) if command is not None else None
),
cpu_limit=cpu_limit,
clock_limit=clock_limit,
memory_limit=memory_limit,
proc_limit=50,
)
)
# Ensure case_stage.diff and case_stage.diff.output are defined
diff_output = (
case_stage.diff.output
if case_stage.diff and case_stage.diff.output
else None
)
if diff_output:
parser_cases.append(
{
"outputs": [
{
"score": diff_output.score,
"fileName": "stdout",
"answerPath": f"/home/tt/.config/joj/{task_conf.task.type_}/{stdout}",
# "answerPath": f"/home/tt/.config/joj/{task_stage.path}/{stdin}",
"forceQuitOnDiff": diff_output.forcequit,
"alwaysHide": diff_output.hide,
"compareSpace": not diff_output.ignorespaces,
}
]
}
)
if diff_parser and task_stage.diff is not None:
diff_parser.with_.update({"name": "diff", "cases": parser_cases})
conf_stage.executor.with_.cases = stage_cases
return conf_stage