dev #10
22
README.md
|
@ -16,3 +16,25 @@
|
|||
4. Install deps by `pdm install && pdm run pre-commit install`
|
||||
5. Run the cli app by `pdm run app --help`
|
||||
6. Check other commands or scripts with `pdm run --list`
|
||||
|
||||
## How to use?
|
||||
|
||||
- `joj3-config-generator convert` function is now supported, currently support one argument as input, it indicates the **convert root**
|
||||
- default value on the server can be given as `/home/tt/.config/joj`
|
||||
- **NOTE:** the user should ensure that the ideal `repo.toml` file is in the sub-directory of the **convert root**
|
||||
- the intended immutable files should be placed at a sub-directory named `immutable_files` at same position as the `repo.toml` file
|
||||
|
||||
```shell
|
||||
$ tree .
|
||||
.
|
||||
|- immutable_files
|
||||
| |-- push.yaml
|
||||
| |-- release.yaml
|
||||
|-- repo.toml
|
||||
```
|
||||
|
||||
- sample command on the server
|
||||
|
||||
```shell
|
||||
joj3-config-generator convert /home/tt/.config/joj
|
||||
```
|
||||
|
|
|
@ -1,93 +1,41 @@
|
|||
from typing import List
|
||||
import os
|
||||
from typing import Dict
|
||||
|
||||
from joj3_config_generator.models import joj1, repo, result, task
|
||||
from joj3_config_generator.models.const import CACHE_ROOT, JOJ3_CONFIG_ROOT
|
||||
from joj3_config_generator.processers.repo import (
|
||||
get_health_check_stage,
|
||||
get_teapot_stage,
|
||||
)
|
||||
from joj3_config_generator.processers.task import get_conf_stage
|
||||
|
||||
|
||||
# FIXME: LLM generated convert function, only for demostration
|
||||
def convert(repo_conf: repo.Config, task_conf: task.Config) -> result.Config:
|
||||
# Create the base ResultConf object
|
||||
result_conf = result.Config(
|
||||
name=task_conf.task,
|
||||
log_path=f"{task_conf.task.replace(' ', '_')}.log",
|
||||
expire_unix_timestamp=(
|
||||
int(task_conf.release.deadline.timestamp())
|
||||
if task_conf.release.deadline
|
||||
else -1
|
||||
),
|
||||
stage=result.Stage(stages=[], sandbox_token=repo_conf.sandbox_token),
|
||||
teapot=result.Teapot(),
|
||||
name=task_conf.task.name,
|
||||
# exact folder difference specified by type
|
||||
log_path=str(CACHE_ROOT / "joj3" / f"{task_conf.task.type_}.log"),
|
||||
expire_unix_timestamp=int(task_conf.release.end_time.timestamp()),
|
||||
effective_unix_timestamp=int(task_conf.release.begin_time.timestamp()),
|
||||
actor_csv_path=str(JOJ3_CONFIG_ROOT / "students.csv"), # students.csv position
|
||||
max_total_score=repo_conf.max_total_score,
|
||||
stage=result.Stage(sandbox_token=repo_conf.sandbox_token),
|
||||
)
|
||||
|
||||
current_test = os.environ.get("PYTEST_CURRENT_TEST") is not None
|
||||
# Construct health check stage
|
||||
if not repo_conf.force_skip_health_check_on_test or not current_test:
|
||||
result_conf.stage.stages.append(get_health_check_stage(repo_conf))
|
||||
cached: Dict[str, None] = {}
|
||||
# Convert each stage in the task configuration
|
||||
for task_stage in task_conf.stages:
|
||||
jon-lee marked this conversation as resolved
Outdated
|
||||
executor_with_config = result.ExecutorWith(
|
||||
default=result.Cmd(
|
||||
args=task_stage.command.split(),
|
||||
copy_in={
|
||||
file: result.LocalFile(src=file)
|
||||
for file in task_stage.files.import_
|
||||
},
|
||||
copy_out_cached=task_stage.files.export,
|
||||
),
|
||||
cases=[], # You can add cases if needed
|
||||
)
|
||||
conf_stage = result.StageDetail(
|
||||
name=task_stage.name,
|
||||
group=task_conf.task,
|
||||
executor=result.Executor(
|
||||
name="sandbox",
|
||||
with_=executor_with_config,
|
||||
),
|
||||
parsers=[
|
||||
result.Parser(name=parser, with_={}) for parser in task_stage.parsers
|
||||
],
|
||||
)
|
||||
|
||||
if "result-detail" in task_stage.parsers:
|
||||
result_detail_parser = next(
|
||||
p for p in conf_stage.parsers if p.name == "result-detail"
|
||||
)
|
||||
result_detail_parser.with_.update(task_stage.result_detail)
|
||||
|
||||
result_conf.stage.stages.append(conf_stage)
|
||||
result_conf.stage.stages.append(get_conf_stage(task_conf, task_stage, cached))
|
||||
if not repo_conf.force_skip_teapot_on_test or not current_test:
|
||||
result_conf.stage.post_stages.append(get_teapot_stage(repo_conf))
|
||||
|
||||
return result_conf
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
where is it used? where is it used?
李衍志523370910113
commented
this should be storing all the files that are about to be copy in or out this should be storing all the files that are about to be copy in or out
李衍志523370910113
commented
It is as the input and output for the following functions about parsers It is as the input and output for the following functions about parsers
张泊明518370910136
commented
so this feature is not implemented? so this feature is not implemented?
李衍志523370910113
commented
it is
this is a loop, so this ```python
if not repo_conf.force_skip_health_check_on_test or not current_test:
result_conf.stage.stages.append(get_health_check_config(repo_conf))
cached: List[str] = []
# Convert each stage in the task configuration
for task_stage in task_conf.stages:
executor_with_config, cached = get_executor_with_config(task_stage, cached)
conf_stage = get_conf_stage(task_stage, executor_with_config)
conf_stage = fix_result_detail(task_stage, conf_stage)
conf_stage = fix_dummy(task_stage, conf_stage)
conf_stage = fix_keyword(task_stage, conf_stage)
conf_stage = fix_file(task_stage, conf_stage)
conf_stage = fix_diff(task_stage, conf_stage, task_conf)
result_conf.stage.stages.append(conf_stage)
```
it is
```python
for task_stage in task_conf.stages:
executor_with_config, cached = get_executor_with_config(task_stage, cached)
```
this is a loop, so this `cached` will be updated in every round of stage
张泊明518370910136
commented
The return value is unnecessary. The return value is unnecessary.
李衍志523370910113
commented
I have a lazing coding style here, everything has get imported would get exported, so should maintain this until the end of the loop. Everything is exported in previous stage would be imported in the next stage. I have a lazing coding style here, everything has get imported would get exported, so should maintain this until the end of the loop. Everything is exported in previous stage would be imported in the next stage.
张泊明518370910136
commented
1. The return value is unnecessary
2. It should be a `set`
张泊明518370910136
commented
try it yourself try it yourself
李衍志523370910113
commented
I see why I see why
李衍志523370910113
commented
resolved. resolved.
|
||||
|
||||
|
||||
# FIXME: LLM generated convert function, only for demostration
|
||||
def convert_joj1(joj1_conf: joj1.Config) -> task.Config:
|
||||
stages = []
|
||||
for language in joj1_conf.languages:
|
||||
# Here you might want to create a stage for each language
|
||||
# You can define a command based on language properties
|
||||
command = f"run {language.language}"
|
||||
# Assuming we don't have explicit files, we will set empty ones or default behavior
|
||||
files = task.Files(import_=[], export=[])
|
||||
# Score can be derived from the first case or set to a default
|
||||
score = 0
|
||||
parsers: List[str] = [] # Define parsers if applicable
|
||||
if joj1_conf.cases:
|
||||
score = sum(
|
||||
case.score for case in joj1_conf.cases
|
||||
) # Sum scores for all cases
|
||||
# Creating a stage for each language
|
||||
stages.append(
|
||||
task.Stage(
|
||||
name=language.language,
|
||||
command=command,
|
||||
files=files,
|
||||
score=score,
|
||||
parsers=parsers,
|
||||
result_detail=task.ParserResultDetail(), # You can customize this further if needed
|
||||
)
|
||||
)
|
||||
# Assuming no deadline is provided in `joj1`, you can set it accordingly
|
||||
release_deadline = (
|
||||
None # Placeholder for future implementation if deadlines are defined
|
||||
)
|
||||
|
||||
return task.Config(
|
||||
task=joj1_conf.languages[0].language if joj1_conf.languages else "Unnamed Task",
|
||||
release=task.Release(deadline=release_deadline),
|
||||
stages=stages,
|
||||
)
|
||||
return task.Config()
|
||||
|
|
39
joj3_config_generator/load.py
Normal file
|
@ -0,0 +1,39 @@
|
|||
from pathlib import Path
|
||||
from typing import Dict, Tuple
|
||||
|
||||
import inquirer
|
||||
import rtoml
|
||||
import yaml
|
||||
|
||||
from joj3_config_generator.models import joj1, repo, task
|
||||
|
||||
|
||||
def load_joj3_toml_answers() -> Dict[str, str]:
|
||||
questions = [
|
||||
inquirer.List(
|
||||
"size",
|
||||
message="What size do you need?",
|
||||
choices=["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
|
||||
),
|
||||
]
|
||||
answers = inquirer.prompt(questions)
|
||||
return answers
|
||||
|
||||
|
||||
def load_joj1_yaml(yaml_path: Path) -> joj1.Config:
|
||||
joj1_obj = yaml.safe_load(yaml_path.read_text())
|
||||
return joj1.Config(**joj1_obj)
|
||||
|
||||
|
||||
def load_joj3_toml(
|
||||
root_path: Path, repo_toml_path: Path, task_toml_path: Path
|
||||
) -> Tuple[repo.Config, task.Config]:
|
||||
repo_obj = rtoml.loads(repo_toml_path.read_text())
|
||||
task_obj = rtoml.loads(task_toml_path.read_text())
|
||||
repo_conf = repo.Config(**repo_obj)
|
||||
repo_conf.root = root_path
|
||||
repo_conf.path = repo_toml_path.relative_to(root_path)
|
||||
task_conf = task.Config(**task_obj)
|
||||
task_conf.root = root_path
|
||||
task_conf.path = task_toml_path.relative_to(root_path)
|
||||
return repo_conf, task_conf
|
|
@ -1,48 +1,44 @@
|
|||
import json
|
||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
this file should not be changed this file should not be changed
|
||||
from pathlib import Path
|
||||
|
||||
import inquirer
|
||||
import rtoml
|
||||
import typer
|
||||
import yaml
|
||||
from typing_extensions import Annotated
|
||||
|
||||
from joj3_config_generator.convert import convert as convert_conf
|
||||
from joj3_config_generator.convert import convert_joj1 as convert_joj1_conf
|
||||
from joj3_config_generator.models import joj1, repo, task
|
||||
from joj3_config_generator.load import (
|
||||
load_joj1_yaml,
|
||||
load_joj3_toml,
|
||||
load_joj3_toml_answers,
|
||||
)
|
||||
from joj3_config_generator.models.const import JOJ3_CONFIG_ROOT
|
||||
from joj3_config_generator.utils.logger import logger
|
||||
|
||||
app = typer.Typer(add_completion=False)
|
||||
|
||||
|
||||
@app.command()
|
||||
def create(toml: typer.FileTextWrite) -> None:
|
||||
def create(toml_path: Path) -> None:
|
||||
"""
|
||||
Create a new JOJ3 toml config file
|
||||
"""
|
||||
logger.info("Creating")
|
||||
questions = [
|
||||
inquirer.List(
|
||||
"size",
|
||||
message="What size do you need?",
|
||||
choices=["Jumbo", "Large", "Standard", "Medium", "Small", "Micro"],
|
||||
),
|
||||
]
|
||||
answers = inquirer.prompt(questions)
|
||||
logger.info(answers)
|
||||
logger.info(f"Creating toml file {toml_path}")
|
||||
answers = load_joj3_toml_answers()
|
||||
logger.debug(f"Got answers: {answers}")
|
||||
toml_path.write_text(rtoml.dumps({}))
|
||||
|
||||
|
||||
@app.command()
|
||||
def convert_joj1(yaml_file: typer.FileText, toml_file: typer.FileTextWrite) -> None:
|
||||
def convert_joj1(yaml_path: Path, toml_path: Path) -> None:
|
||||
"""
|
||||
Convert a JOJ1 yaml config file to JOJ3 toml config file
|
||||
"""
|
||||
logger.info(f"Converting yaml file {yaml_file}")
|
||||
joj1_obj = yaml.safe_load(yaml_file.read())
|
||||
joj1_model = joj1.Config(**joj1_obj)
|
||||
logger.info(f"Converting yaml file {yaml_path}")
|
||||
joj1_model = load_joj1_yaml(yaml_path)
|
||||
task_model = convert_joj1_conf(joj1_model)
|
||||
result_dict = task_model.model_dump(by_alias=True)
|
||||
toml_file.write(rtoml.dumps(result_dict))
|
||||
result_dict = task_model.model_dump(mode="json", by_alias=True, exclude_none=True)
|
||||
toml_path.write_text(rtoml.dumps(result_dict))
|
||||
|
||||
|
||||
@app.command()
|
||||
|
@ -50,8 +46,7 @@ def convert(
|
|||
root: Annotated[
|
||||
Path,
|
||||
typer.Argument(
|
||||
help="root directory of config files, "
|
||||
"located at /home/tt/.config/joj in JTC"
|
||||
help=f"root directory of config files, located at {JOJ3_CONFIG_ROOT} in JTC"
|
||||
),
|
||||
] = Path(".")
|
||||
) -> None:
|
||||
|
@ -60,9 +55,7 @@ def convert(
|
|||
"""
|
||||
logger.info(f"Converting files in {root.absolute()}")
|
||||
for repo_toml_path in root.glob("**/repo.toml"):
|
||||
repo_path = repo_toml_path.parent
|
||||
repo_obj = rtoml.loads(repo_toml_path.read_text())
|
||||
for task_toml_path in repo_path.glob("**/*.toml"):
|
||||
for task_toml_path in repo_toml_path.parent.glob("**/*.toml"):
|
||||
if repo_toml_path == task_toml_path:
|
||||
continue
|
||||
toml_name = task_toml_path.name.removesuffix(".toml")
|
||||
|
@ -70,15 +63,11 @@ def convert(
|
|||
logger.info(
|
||||
f"Converting {repo_toml_path} & {task_toml_path} to {result_json_path}"
|
||||
)
|
||||
task_obj = rtoml.loads(task_toml_path.read_text())
|
||||
repo_conf = repo.Config(**repo_obj)
|
||||
repo_conf.root = root
|
||||
repo_conf.path = repo_toml_path.relative_to(root)
|
||||
task_conf = task.Config(**task_obj)
|
||||
task_conf.root = root
|
||||
task_conf.path = task_toml_path.relative_to(root)
|
||||
repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path)
|
||||
result_model = convert_conf(repo_conf, task_conf)
|
||||
result_dict = result_model.model_dump(by_alias=True, exclude_none=True)
|
||||
result_dict = result_model.model_dump(
|
||||
mode="json", by_alias=True, exclude_none=True
|
||||
)
|
||||
with result_json_path.open("w") as result_file:
|
||||
json.dump(result_dict, result_file, ensure_ascii=False, indent=4)
|
||||
result_file.write("\n")
|
||||
|
|
19
joj3_config_generator/models/common.py
Normal file
|
@ -0,0 +1,19 @@
|
|||
from typing import Union
|
||||
|
||||
import humanfriendly
|
||||
|
||||
|
||||
class Memory(int):
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
what compact? what compact?
李衍志523370910113
commented
no int input, should be done already, so it can be removed. I added that several commit before before you removed that 😇 no int input, should be done already, so it can be removed. I added that several commit before before you removed that 😇
|
||||
def __new__(cls, value: Union[str, int]) -> "Memory":
|
||||
if isinstance(value, str):
|
||||
parsed = humanfriendly.parse_size(value, binary=True)
|
||||
return super().__new__(cls, parsed)
|
||||
return super().__new__(cls, value)
|
||||
|
||||
|
||||
class Time(int):
|
||||
def __new__(cls, value: Union[str, int]) -> "Time":
|
||||
if isinstance(value, str):
|
||||
parsed = humanfriendly.parse_timespan(value) * 1_000_000_000 # ns
|
||||
return super().__new__(cls, round(parsed))
|
||||
return super().__new__(cls, value)
|
11
joj3_config_generator/models/const.py
Normal file
|
@ -0,0 +1,11 @@
|
|||
from pathlib import Path
|
||||
|
||||
from joj3_config_generator.models.common import Memory, Time
|
||||
|
||||
DEFAULT_CPU_LIMIT = Time("1s")
|
||||
DEFAULT_MEMORY_LIMIT = Memory("128m")
|
||||
DEFAULT_FILE_LIMIT = Memory("32m")
|
||||
|
||||
JOJ3_CONFIG_ROOT = Path("/home/tt/.config/joj")
|
||||
TEAPOT_CONFIG_ROOT = Path("/home/tt/.config/teapot")
|
||||
CACHE_ROOT = Path("/home/tt/.cache")
|
|
@ -1,21 +1,29 @@
|
|||
import socket
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from typing import List
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class Files(BaseModel):
|
||||
whitelist_patterns: List[str]
|
||||
whitelist_file: Optional[str]
|
||||
required: List[str]
|
||||
immutable: List[str]
|
||||
required: List[str] = []
|
||||
immutable: List[str] = []
|
||||
|
||||
|
||||
class Groups(BaseModel):
|
||||
name: List[str] = []
|
||||
max_count: List[int] = []
|
||||
time_period_hour: List[int] = []
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
max_size: float = Field(10, ge=0)
|
||||
files: Files = Files()
|
||||
sandbox_token: str = Field("")
|
||||
max_total_score: int = Field(100)
|
||||
force_skip_health_check_on_test: bool = False
|
||||
force_skip_teapot_on_test: bool = False
|
||||
groups: Groups = Groups()
|
||||
root: Path = Path(".")
|
||||
path: Path = Path("repo.toml")
|
||||
teaching_team: List[str]
|
||||
max_size: float = Field(..., ge=0)
|
||||
release_tags: List[str]
|
||||
files: Files
|
||||
sandbox_token: str
|
||||
grading_repo_name: str = f"{socket.gethostname().split('-')[0]}-joj"
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
from typing import Any, Dict, List, Optional, Union
|
||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
|
||||
from joj3_config_generator.models.const import (
|
||||
DEFAULT_CPU_LIMIT,
|
||||
DEFAULT_FILE_LIMIT,
|
||||
DEFAULT_MEMORY_LIMIT,
|
||||
)
|
||||
|
||||
|
||||
class LocalFile(BaseModel):
|
||||
|
@ -17,7 +23,7 @@ class PreparedFile(BaseModel):
|
|||
|
||||
class Collector(BaseModel):
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
default value too large, should be 1s 128MB default value too large, should be 1s 128MB
李衍志523370910113
commented
will fix later, we need to hold some test I reckon? will fix later, we need to hold some test I reckon?
张泊明518370910136
commented
no no
李衍志523370910113
commented
@bomingzh fixed @bomingzh fixed
|
||||
name: str
|
||||
max: int
|
||||
max: int = DEFAULT_FILE_LIMIT
|
||||
pipe: bool = True
|
||||
|
||||
|
||||
|
@ -33,27 +39,26 @@ class StreamOut(BaseModel):
|
|||
stream_out: bool = Field(..., alias="streamOut")
|
||||
|
||||
|
||||
InputFile = Union[LocalFile | MemoryFile | PreparedFile | Symlink]
|
||||
InputFile = Union[LocalFile, MemoryFile, PreparedFile, Symlink]
|
||||
|
||||
|
||||
class Cmd(BaseModel):
|
||||
args: List[str]
|
||||
args: List[str] = []
|
||||
env: List[str] = []
|
||||
stdin: Optional[Union[InputFile | StreamIn]] = None
|
||||
stdout: Optional[Union[Collector | StreamOut]] = None
|
||||
stderr: Optional[Union[Collector | StreamOut]] = None
|
||||
cpu_limit: int = Field(0, serialization_alias="cpuLimit")
|
||||
real_cpu_limit: int = Field(0, serialization_alias="realCpuLimit")
|
||||
clock_limit: int = Field(0, serialization_alias="clockLimit")
|
||||
memory_limit: int = Field(0, serialization_alias="memoryLimit")
|
||||
stdin: Union[InputFile, StreamIn] = MemoryFile(content="")
|
||||
stdout: Union[Collector, StreamOut] = Collector(name="stdout")
|
||||
stderr: Union[Collector, StreamOut] = Collector(name="stderr")
|
||||
cpu_limit: int = Field(DEFAULT_CPU_LIMIT, serialization_alias="cpuLimit")
|
||||
clock_limit: int = Field(2 * DEFAULT_CPU_LIMIT, serialization_alias="clockLimit")
|
||||
memory_limit: int = Field(DEFAULT_MEMORY_LIMIT, serialization_alias="memoryLimit")
|
||||
stack_limit: int = Field(0, serialization_alias="stackLimit")
|
||||
proc_limit: int = Field(0, serialization_alias="procLimit")
|
||||
proc_limit: int = Field(50, serialization_alias="procLimit")
|
||||
cpu_rate_limit: int = Field(0, serialization_alias="cpuRateLimit")
|
||||
cpu_set_limit: str = Field("", serialization_alias="cpuSetLimit")
|
||||
copy_in: Dict[str, InputFile] = Field({}, serialization_alias="copyIn")
|
||||
copy_in_cached: Dict[str, str] = Field({}, serialization_alias="copyInCached")
|
||||
copy_in_dir: str = Field(".", serialization_alias="copyInDir")
|
||||
copy_out: List[str] = Field([], serialization_alias="copyOut")
|
||||
copy_out: List[str] = Field(["stdout", "stderr"], serialization_alias="copyOut")
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
What is the conclusion? What is the conclusion?
李衍志523370910113
commented
should be already solved. should be already solved.
|
||||
copy_out_cached: List[str] = Field([], serialization_alias="copyOutCached")
|
||||
copy_out_max: int = Field(0, serialization_alias="copyOutMax")
|
||||
copy_out_dir: str = Field("", serialization_alias="copyOutDir")
|
||||
|
@ -66,11 +71,10 @@ class Cmd(BaseModel):
|
|||
class OptionalCmd(BaseModel):
|
||||
args: Optional[List[str]] = None
|
||||
env: Optional[List[str]] = None
|
||||
stdin: Optional[Union[InputFile | StreamIn]] = None
|
||||
stdout: Optional[Union[Collector | StreamOut]] = None
|
||||
stderr: Optional[Union[Collector | StreamOut]] = None
|
||||
stdin: Optional[Union[InputFile, StreamIn]] = None
|
||||
stdout: Optional[Union[Collector, StreamOut]] = None
|
||||
stderr: Optional[Union[Collector, StreamOut]] = None
|
||||
cpu_limit: Optional[int] = Field(None, serialization_alias="cpuLimit")
|
||||
real_cpu_limit: Optional[int] = Field(None, serialization_alias="realCpuLimit")
|
||||
clock_limit: Optional[int] = Field(None, serialization_alias="clockLimit")
|
||||
memory_limit: Optional[int] = Field(None, serialization_alias="memoryLimit")
|
||||
stack_limit: Optional[int] = Field(None, serialization_alias="stackLimit")
|
||||
|
@ -101,23 +105,39 @@ class OptionalCmd(BaseModel):
|
|||
|
||||
|
||||
class ExecutorWith(BaseModel):
|
||||
default: Cmd
|
||||
cases: List[OptionalCmd]
|
||||
default: Cmd = Cmd()
|
||||
cases: List[OptionalCmd] = []
|
||||
|
||||
|
||||
class Executor(BaseModel):
|
||||
name: str
|
||||
with_: ExecutorWith = Field(..., serialization_alias="with")
|
||||
with_: ExecutorWith = Field(ExecutorWith(), serialization_alias="with")
|
||||
|
||||
|
||||
class Parser(BaseModel):
|
||||
name: str
|
||||
with_: Dict[str, Any] = Field(..., serialization_alias="with")
|
||||
if TYPE_CHECKING:
|
||||
|
||||
class Empty(BaseModel):
|
||||
pass
|
||||
|
||||
with_: BaseModel = Field(Empty(), serialization_alias="with")
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
Should it be optional? Should it be optional?
|
||||
else:
|
||||
with_: Dict[str, Any] = Field({}, serialization_alias="with")
|
||||
|
||||
model_config = ConfigDict(validate_assignment=True)
|
||||
|
||||
@field_validator("with_", mode="before")
|
||||
@classmethod
|
||||
def validate_with(cls, v: Any) -> Dict[str, Any]:
|
||||
if isinstance(v, BaseModel):
|
||||
return v.model_dump(by_alias=True)
|
||||
raise ValueError("Must be a BaseModel instance")
|
||||
|
||||
|
||||
class StageDetail(BaseModel):
|
||||
name: str
|
||||
group: str
|
||||
group: str = ""
|
||||
executor: Executor
|
||||
parsers: List[Parser]
|
||||
|
||||
|
@ -130,26 +150,74 @@ class Stage(BaseModel):
|
|||
output_path: str = Field(
|
||||
"/tmp/joj3_result.json", serialization_alias="outputPath"
|
||||
) # nosec: B108
|
||||
stages: List[StageDetail]
|
||||
|
||||
|
||||
class Teapot(BaseModel):
|
||||
log_path: str = Field(
|
||||
"/home/tt/.cache/joint-teapot-debug.log", serialization_alias="logPath"
|
||||
)
|
||||
scoreboard_path: str = Field("scoreboard.csv", serialization_alias="scoreboardPath")
|
||||
failed_table_path: str = Field(
|
||||
"failed-table.md", serialization_alias="failedTablePath"
|
||||
)
|
||||
grading_repo_name: str = Field("", serialization_alias="gradingRepoName")
|
||||
skip_issue: bool = Field(False, serialization_alias="skipIssue")
|
||||
skip_scoreboard: bool = Field(False, serialization_alias="skipScoreboard")
|
||||
skip_failed_table: bool = Field(False, serialization_alias="skipFailedTable")
|
||||
stages: List[StageDetail] = []
|
||||
pre_stages: List[StageDetail] = Field([], serialization_alias="preStages")
|
||||
post_stages: List[StageDetail] = Field([], serialization_alias="postStages")
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
name: str = "unknown"
|
||||
name: str = ""
|
||||
log_path: str = Field("", serialization_alias="logPath")
|
||||
expire_unix_timestamp: int = Field(-1, serialization_alias="expireUnixTimestamp")
|
||||
effective_unix_timestamp: int = Field(
|
||||
-1, serialization_alias="effectiveUnixTimestamp"
|
||||
)
|
||||
actor_csv_path: str = Field("", serialization_alias="actorCsvPath")
|
||||
max_total_score: int = Field(100, serialization_alias="maxTotalScore")
|
||||
stage: Stage
|
||||
teapot: Teapot
|
||||
|
||||
|
||||
class DummyConfig(BaseModel):
|
||||
score: int = 0
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
Are these Are these `Optional` necessary?
|
||||
comment: Optional[str] = None
|
||||
force_quit_on_not_accepted: Optional[bool] = Field(
|
||||
False, serialization_alias="forceQuitOnNotAccepted"
|
||||
)
|
||||
|
||||
|
||||
class DiffOutputConfig(BaseModel):
|
||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
also these also these `Optional`?
李衍志523370910113
commented
I guess some of the field have default within JOJ3, so I choose optional just to reduce the length of json previously I guess some of the field have default within JOJ3, so I choose optional just to reduce the length of json previously
张泊明518370910136
commented
better put all defaults here then we only need to check the code here better put all defaults here then we only need to check the code here
李衍志523370910113
commented
indeed. indeed.
|
||||
score: int = 100
|
||||
file_name: str = Field("", serialization_alias="fileName")
|
||||
answer_path: str = Field("", serialization_alias="answerPath")
|
||||
force_quit_on_diff: bool = Field(False, serialization_alias="forceQuitOnDiff")
|
||||
always_hide: bool = Field(False, serialization_alias="alwaysHide")
|
||||
compare_space: bool = Field(False, serialization_alias="compareSpace")
|
||||
|
||||
|
||||
class ResultDetailConfig(BaseModel):
|
||||
score: int = 0
|
||||
comment: str = ""
|
||||
show_files: List[str] = Field([], serialization_alias="showFiles")
|
||||
show_exit_status: bool = Field(True, serialization_alias="showExitStatus")
|
||||
show_runtime: bool = Field(True, serialization_alias="showRuntime")
|
||||
show_memory: bool = Field(False, serialization_alias="showMemory")
|
||||
|
||||
|
||||
class KeywordConfig(BaseModel):
|
||||
keywords: List[str] = []
|
||||
score: int = 0
|
||||
|
||||
|
||||
class KeywordMatchConfig(BaseModel):
|
||||
matches: List[KeywordConfig] = []
|
||||
|
||||
|
||||
class FileConfig(BaseModel):
|
||||
name: str = ""
|
||||
|
||||
|
||||
class DiffCasesConfig(BaseModel):
|
||||
outputs: List[DiffOutputConfig] = []
|
||||
|
||||
|
||||
class DiffConfig(BaseModel):
|
||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
what needs to be refined? what needs to be refined?
李衍志523370910113
commented
just feels bit waste since this outputs only have one field before I coded the logic, I wrote that comment without checking the details of diff parser. But it should be the best strategy to show the structures as well as give flexiblity for extension now. just feels bit waste since this outputs only have one field before I coded the logic, I wrote that comment without checking the details of diff parser. But it should be the best strategy to show the structures as well as give flexiblity for extension now.
|
||||
name: str = "diff"
|
||||
cases: List[DiffCasesConfig] = []
|
||||
|
||||
|
||||
class MsgConfig(BaseModel):
|
||||
msg: str = ""
|
||||
|
||||
|
||||
class ScoreConfig(BaseModel):
|
||||
score: int = 0
|
||||
|
|
|
@ -1,8 +1,16 @@
|
|||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
every field in this file should not be optional. we give an default value here if any field does not exist every field in this file should not be optional. we give an default value here if any field does not exist
张泊明518370910136
commented
and use underscore naming in this file and use underscore naming in this file
李衍志523370910113
commented
fixed > every field in this file should not be optional. we give an default value here if any field does not exist
fixed
李衍志523370910113
commented
fixed. > and use underscore naming in this file
fixed.
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
from typing import Any, Dict, List, Type
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
|
||||
|
||||
from joj3_config_generator.models.common import Memory, Time
|
||||
from joj3_config_generator.models.const import (
|
||||
DEFAULT_CPU_LIMIT,
|
||||
DEFAULT_FILE_LIMIT,
|
||||
DEFAULT_MEMORY_LIMIT,
|
||||
)
|
||||
|
||||
|
||||
class ParserResultDetail(BaseModel):
|
||||
|
@ -10,31 +18,136 @@ class ParserResultDetail(BaseModel):
|
|||
mem: bool = True # Display memory usage
|
||||
stdout: bool = False # Display stdout messages
|
||||
stderr: bool = False # Display stderr messages
|
||||
exit_status: bool = True
|
||||
|
||||
|
||||
class ParserFile(BaseModel):
|
||||
name: str = ""
|
||||
|
||||
|
||||
class ParserLog(BaseModel):
|
||||
filename: str
|
||||
msg: str = ""
|
||||
level: str = ""
|
||||
|
||||
|
||||
class ParserDummy(BaseModel):
|
||||
comment: str = ""
|
||||
score: int = 0
|
||||
force_quit: bool = False
|
||||
|
||||
|
||||
class ParserKeyword(BaseModel):
|
||||
keyword: List[str] = []
|
||||
weight: List[int] = []
|
||||
|
||||
|
||||
class Outputs(BaseModel):
|
||||
score: int = 0
|
||||
ignore_spaces: bool = True
|
||||
hide: bool = False
|
||||
force_quit: bool = False
|
||||
|
||||
|
||||
class ParserDiff(BaseModel):
|
||||
output: Outputs = Outputs()
|
||||
|
||||
|
||||
class Files(BaseModel):
|
||||
import_: List[str] = Field(serialization_alias="import", validation_alias="import")
|
||||
export: List[str]
|
||||
import_: List[str] = Field([], alias="import")
|
||||
export: List[str] = []
|
||||
|
||||
|
||||
class Limit(BaseModel):
|
||||
mem: int = DEFAULT_MEMORY_LIMIT
|
||||
cpu: int = DEFAULT_CPU_LIMIT
|
||||
stdout: int = DEFAULT_FILE_LIMIT
|
||||
stderr: int = DEFAULT_FILE_LIMIT
|
||||
|
||||
model_config = ConfigDict(validate_assignment=True)
|
||||
|
||||
@field_validator("cpu", mode="before")
|
||||
@classmethod
|
||||
def ensure_time(cls, v: Any) -> Time:
|
||||
if isinstance(v, str):
|
||||
return Time(v)
|
||||
raise ValueError("Must be a string")
|
||||
|
||||
@field_validator("mem", "stdout", "stderr", mode="before")
|
||||
@classmethod
|
||||
def ensure_mem(cls, v: Any) -> Memory:
|
||||
if isinstance(v, str):
|
||||
return Memory(v)
|
||||
raise ValueError("Must be a string")
|
||||
|
||||
|
||||
class Parser(str, Enum):
|
||||
CLANG_TIDY = "clangtidy"
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
deprecated deprecated
李衍志523370910113
commented
@bomingzh any suggestions on the structure? @bomingzh any suggestions on the structure?
张泊明518370910136
commented
```
PydanticDeprecatedSince20: Support for class-based `config` is deprecated, use ConfigDict instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.9/migration/
```
李衍志523370910113
commented
fixed with fixed with `model_config`
张泊明518370910136
commented
str here need to be a str here need to be a `StrEnum` now.
李衍志523370910113
commented
But I guess we don't know the set of case in advance, making it dynamic But I guess we don't know the set of case in advance, making it dynamic `StrEnum` is meaningless
张泊明518370910136
commented
line changed, the comment is for line changed, the comment is for `parsers`
|
||||
CPPCHECK = "cppcheck"
|
||||
CPPLINT = "cpplint"
|
||||
jon-lee marked this conversation as resolved
Outdated
李衍志523370910113
commented
this should be the this should be the `StrEnum`
张泊明518370910136
commented
yes yes
李衍志523370910113
commented
It is supported now. It is supported now.
|
||||
KEYWORD = "keyword"
|
||||
RESULT_STATUS = "result-status"
|
||||
RESULT_DETAIL = "result-detail"
|
||||
DUMMY = "dummy"
|
||||
FILE = "file"
|
||||
DIFF = "diff"
|
||||
|
||||
|
||||
class Stage(BaseModel):
|
||||
name: str # Stage name
|
||||
command: str # Command to run
|
||||
files: Files # Files to import and export
|
||||
score: int # Score for the task
|
||||
parsers: List[str] # list of parsers
|
||||
result_detail: ParserResultDetail = (
|
||||
ParserResultDetail()
|
||||
) # for result-detail parser
|
||||
name: str = "" # Stage name
|
||||
env: List[str] = []
|
||||
command: str = "" # Command to run
|
||||
files: Files = Files()
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
`begin_time` and `end_time` to make them match
李衍志523370910113
commented
resolved resolved
|
||||
in_: str = Field("", alias="in")
|
||||
out_: str = Field("", alias="out")
|
||||
score: int = 0
|
||||
parsers: List[Parser] = [] # list of parsers
|
||||
limit: Limit = Limit()
|
||||
dummy: ParserDummy = ParserDummy()
|
||||
result_status: ParserDummy = Field(ParserDummy(), alias="result-status")
|
||||
keyword: ParserKeyword = ParserKeyword()
|
||||
clangtidy: ParserKeyword = ParserKeyword()
|
||||
cppcheck: ParserKeyword = ParserKeyword()
|
||||
cpplint: ParserKeyword = ParserKeyword()
|
||||
result_detail: ParserResultDetail = Field(
|
||||
ParserResultDetail(), alias="result-detail"
|
||||
)
|
||||
file: ParserFile = ParserFile()
|
||||
skip: List[str] = []
|
||||
|
||||
# cases related
|
||||
cases: Dict[str, "Stage"] = {}
|
||||
diff: ParserDiff = ParserDiff()
|
||||
|
||||
model_config = ConfigDict(extra="allow")
|
||||
|
||||
@model_validator(mode="before")
|
||||
@classmethod
|
||||
def gather_cases(cls: Type["Stage"], values: Dict[str, Any]) -> Dict[str, Any]:
|
||||
cases = {k: v for k, v in values.items() if k.startswith("case")}
|
||||
for key in cases:
|
||||
values.pop(key)
|
||||
values["cases"] = {k: v for k, v in cases.items()}
|
||||
return values
|
||||
|
||||
|
||||
class Release(BaseModel):
|
||||
deadline: Optional[datetime] # RFC 3339 formatted date-time with offset
|
||||
end_time: datetime = datetime.now() + timedelta(
|
||||
days=365
|
||||
) # RFC 3339 formatted date-time with offset
|
||||
begin_time: datetime = datetime.fromtimestamp(
|
||||
0
|
||||
) # RFC 3339 formatted date-time with offset
|
||||
|
||||
|
||||
class Task(BaseModel):
|
||||
type_: str = Field("unknown", serialization_alias="type", validation_alias="type")
|
||||
name: str = "unknown"
|
||||
|
||||
|
||||
class Config(BaseModel):
|
||||
root: Path = Path(".")
|
||||
path: Path = Path("task.toml")
|
||||
task: str # Task name (e.g., hw3 ex5)
|
||||
release: Release # Release configuration
|
||||
stages: List[Stage] # list of stage configurations
|
||||
task: Task = Task() # Task name (e.g., hw3 ex5)
|
||||
release: Release = Release() # Release configuration
|
||||
stages: List[Stage] = [] # list of stage configurations
|
||||
|
|
0
joj3_config_generator/processers/__init__.py
Normal file
108
joj3_config_generator/processers/repo.py
Normal file
|
@ -0,0 +1,108 @@
|
|||
import hashlib
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from joj3_config_generator.models import repo, result
|
||||
from joj3_config_generator.models.const import CACHE_ROOT, TEAPOT_CONFIG_ROOT
|
||||
|
||||
|
||||
def get_teapot_stage(repo_conf: repo.Config) -> result.StageDetail:
|
||||
args = [
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
make it a field in repo.toml, if it is unset, then use make it a field in repo.toml, if it is unset, then use `socket.gethostname`. We set this value to pass the test.
李衍志523370910113
commented
resolved. resolved.
|
||||
"/usr/local/bin/joint-teapot",
|
||||
"joj3-all-env",
|
||||
str(TEAPOT_CONFIG_ROOT / "teapot.env"),
|
||||
"--grading-repo-name",
|
||||
repo_conf.grading_repo_name,
|
||||
"--max-total-score",
|
||||
str(repo_conf.max_total_score),
|
||||
]
|
||||
|
||||
stage_conf = result.StageDetail(
|
||||
name="teapot",
|
||||
executor=result.Executor(
|
||||
name="local",
|
||||
with_=result.ExecutorWith(
|
||||
default=result.Cmd(
|
||||
args=args,
|
||||
env=[f"LOG_FILE_PATH={CACHE_ROOT}/joint-teapot-debug.log"],
|
||||
),
|
||||
cases=[],
|
||||
),
|
||||
),
|
||||
parsers=[result.Parser(name="log", with_=result.MsgConfig(msg="joj3 summary"))],
|
||||
)
|
||||
return stage_conf
|
||||
|
||||
|
||||
def get_health_check_args(repo_conf: repo.Config) -> List[str]:
|
||||
return [
|
||||
"/usr/local/bin/repo-health-checker",
|
||||
"-root=.",
|
||||
f"-repoSize={str(repo_conf.max_size)}",
|
||||
*[f"-meta={meta}" for meta in repo_conf.files.required],
|
||||
f"-checkFileSumList={','.join(get_hashs(repo_conf))}",
|
||||
f"-checkFileNameList={','.join(repo_conf.files.immutable)}",
|
||||
]
|
||||
|
||||
|
||||
def get_teapot_check_args(repo_conf: repo.Config) -> List[str]:
|
||||
return [
|
||||
"/usr/local/bin/joint-teapot",
|
||||
"joj3-check-env",
|
||||
str(TEAPOT_CONFIG_ROOT / "teapot.env"),
|
||||
"--grading-repo-name",
|
||||
repo_conf.grading_repo_name,
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
why not why not `args = "hc -root=. "`
李衍志523370910113
commented
resolved. resolved.
|
||||
"--group-config",
|
||||
",".join(
|
||||
f"{name}={max_count}:{time_period}"
|
||||
for name, max_count, time_period in zip(
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
do we need that default? do we need that default?
李衍志523370910113
commented
what is the situation internally in JOJ3? I just added that blindly when I reached that stage. Overall I think 100 times per day should be a reasonable and safe default? considering that there may be group works and due date what is the situation internally in JOJ3? I just added that blindly when I reached that stage. Overall I think 100 times per day should be a reasonable and safe default? considering that there may be group works and due date
张泊明518370910136
commented
They can manually add it if needed. Or just move it to the model default. They can manually add it if needed. Or just move it to the model default.
李衍志523370910113
commented
removed. removed.
|
||||
repo_conf.groups.name,
|
||||
repo_conf.groups.max_count,
|
||||
repo_conf.groups.time_period_hour,
|
||||
)
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def get_health_check_stage(repo_conf: repo.Config) -> result.StageDetail:
|
||||
health_check_stage = result.StageDetail(
|
||||
name="Health Check",
|
||||
group="",
|
||||
executor=result.Executor(
|
||||
name="local",
|
||||
with_=result.ExecutorWith(
|
||||
default=result.Cmd(),
|
||||
cases=[
|
||||
result.OptionalCmd(
|
||||
args=get_health_check_args(repo_conf),
|
||||
),
|
||||
result.OptionalCmd(
|
||||
args=get_teapot_check_args(repo_conf),
|
||||
env=[f"LOG_FILE_PATH={CACHE_ROOT}/joint-teapot-debug.log"],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
parsers=[
|
||||
result.Parser(name="healthcheck", with_=result.ScoreConfig(score=1)),
|
||||
result.Parser(name="debug", with_=result.ScoreConfig(score=0)),
|
||||
],
|
||||
)
|
||||
return health_check_stage
|
||||
|
||||
|
||||
def calc_sha256sum(file_path: Path) -> str:
|
||||
sha256_hash = hashlib.sha256()
|
||||
with open(file_path, "rb") as f:
|
||||
for byte_block in iter(lambda: f.read(64 * 1024), b""):
|
||||
sha256_hash.update(byte_block)
|
||||
return sha256_hash.hexdigest()
|
||||
|
||||
|
||||
def get_hashs(repo_conf: repo.Config) -> List[str]:
|
||||
base_dir = (repo_conf.root / repo_conf.path).parent
|
||||
immutable_dir = base_dir / "immutable_files"
|
||||
immutable_files = [
|
||||
immutable_dir / Path(file).name for file in repo_conf.files.immutable
|
||||
]
|
||||
return [calc_sha256sum(file) for file in immutable_files]
|
206
joj3_config_generator/processers/task.py
Normal file
|
@ -0,0 +1,206 @@
|
|||
import re
|
||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
Path should not be relative to Path should not be relative to `JOJ3_CONFIG_ROOT` in this file, should be relative to `task.toml` dir
李衍志523370910113
commented
I reckon you said things is relative to I reckon you said things is relative to `JOJ3_CONFIG_ROOT` in JTC before. we have a `task.type` in `task.toml` to mend the path
张泊明518370910136
commented
`config.path` is relative to `JOJ3_CONFIG_ROOT`.
李衍志523370910113
commented
could you explain further? I m not quite sure my understanding is clear. could you explain further? I m not quite sure my understanding is clear.
张泊明518370910136
commented
In In `joj3_config_generator/models/task.py`, `Config.path` is relative to `JOJ3_CONFIG_ROOT`, so `task.toml` will located at `JOJ3_CONFIG_ROOT / task_conf.path` in JTC.
|
||||
import shlex
|
||||
jon-lee marked this conversation as resolved
张泊明518370910136
commented
Some Some `with_.update` is still using raw dict, not model with `model_dump`.
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable, Dict, List, Tuple
|
||||
|
||||
from joj3_config_generator.models import result, task
|
||||
from joj3_config_generator.models.common import Memory, Time
|
||||
from joj3_config_generator.models.const import JOJ3_CONFIG_ROOT
|
||||
from joj3_config_generator.models.task import Parser as ParserEnum
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
`ParserEnum`
|
||||
|
||||
|
||||
def get_conf_stage(
|
||||
task_conf: task.Config,
|
||||
task_stage: task.Stage,
|
||||
cached: Dict[str, None],
|
||||
) -> result.StageDetail:
|
||||
jon-lee marked this conversation as resolved
Outdated
李衍志523370910113
commented
BTW, is this outdated? BTW, is this outdated?
张泊明518370910136
commented
Never heard about this rule. Never heard about this rule.
李衍志523370910113
commented
@manuel what would be the current intended rule for @manuel what would be the current intended rule for `group`?
李衍志523370910113
commented
seems current strategy is fine, resolved. seems current strategy is fine, resolved.
|
||||
conf_stage = result.StageDetail(
|
||||
name=task_stage.name,
|
||||
# group is determined by adding between "[]" in the name of the task
|
||||
group=(
|
||||
match.group(1)
|
||||
if (match := re.search(r"\[([^\[\]]+)\]", task_stage.name or ""))
|
||||
else ""
|
||||
),
|
||||
executor=result.Executor(
|
||||
name="sandbox",
|
||||
with_=get_executor_with(task_stage, cached),
|
||||
),
|
||||
parsers=([result.Parser(name=parser) for parser in task_stage.parsers]),
|
||||
)
|
||||
processed_dict = get_processed_dict(task_stage)
|
||||
for idx, parser in enumerate(task_stage.parsers):
|
||||
if parser in processed_dict:
|
||||
fn, parser_model = processed_dict[parser]
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
should loop through should loop through `conf_stage.parsers` here and update the `with` field according to the parser name.
李衍志523370910113
commented
I think its already implemented in each of the I think its already implemented in each of the `fix_parsers` functions
张泊明518370910136
commented
No, do not find the parser in the No, do not find the parser in the `fix_xxx` function. Instead, iterate through the parsers here and decide how to fill in the `with`.
李衍志523370910113
commented
resolved. resolved.
张泊明518370910136
commented
Use a dict to store parser name, field, function to process.
Use a dict to store parser name, field, function to process.
```
process_dict: Dict[
str, Tuple[Callable[[result.ParserConfig, BaseModel], None], BaseModel]
] = {
"clangtidy": (fix_keyword, task_stage.clangtidy),
"keyword": (fix_keyword, task_stage.keyword),
"diff": (fix_diff, task_stage.diff),
}
for i, parser in enumerate(task_stage.parsers):
if parser in process_dict:
func, parser_model = process_dict[parser]
func(conf_stage.parsers[i], parser_model)
```
李衍志523370910113
commented
resolved. resolved.
|
||||
fn(parser_model, conf_stage.parsers[idx])
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
Do we need to support both kinds of names? Do we need to support both kinds of names?
李衍志523370910113
commented
probably yes, since it is easy for new ta to type it wrong probably yes, since it is easy for new ta to type it wrong
张泊明518370910136
commented
parsers name should be a str enum, force them to use the correct names parsers name should be a str enum, force them to use the correct names
李衍志523370910113
commented
ok, then removed. ok, then removed.
|
||||
elif parser == ParserEnum.DIFF:
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
underscore underscore
李衍志523370910113
commented
fixed fixed
|
||||
fix_diff(
|
||||
task_stage,
|
||||
conf_stage.parsers[idx],
|
||||
conf_stage.executor,
|
||||
JOJ3_CONFIG_ROOT / task_conf.path.parent,
|
||||
)
|
||||
else:
|
||||
continue
|
||||
return conf_stage
|
||||
|
||||
|
||||
def get_processed_dict(
|
||||
task_stage: task.Stage,
|
||||
) -> Dict[ParserEnum, Tuple[Callable[[Any, result.Parser], None], Any]]:
|
||||
processed_dict: Dict[
|
||||
ParserEnum, Tuple[Callable[[Any, result.Parser], None], Any]
|
||||
] = {
|
||||
ParserEnum.CLANG_TIDY: (fix_keyword, task_stage.clangtidy),
|
||||
ParserEnum.KEYWORD: (fix_keyword, task_stage.keyword),
|
||||
ParserEnum.CPPCHECK: (fix_keyword, task_stage.cppcheck),
|
||||
ParserEnum.CPPLINT: (fix_keyword, task_stage.cpplint),
|
||||
ParserEnum.RESULT_DETAIL: (fix_result_detail, task_stage.result_detail),
|
||||
ParserEnum.DUMMY: (fix_dummy, task_stage.dummy),
|
||||
ParserEnum.RESULT_STATUS: (fix_dummy, task_stage.result_status),
|
||||
ParserEnum.FILE: (fix_file, task_stage.file),
|
||||
}
|
||||
return processed_dict
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
not necessary not necessary
李衍志523370910113
commented
resolved. resolved.
|
||||
|
||||
|
||||
def get_executor_with(
|
||||
task_stage: task.Stage, cached: Dict[str, None]
|
||||
) -> result.ExecutorWith:
|
||||
file_import = task_stage.files.import_
|
||||
copy_in_files = (file for file in file_import if file not in cached)
|
||||
file_export = task_stage.files.export
|
||||
copy_out_files = ["stdout", "stderr"]
|
||||
executor_with_config = result.ExecutorWith(
|
||||
default=result.Cmd(
|
||||
args=shlex.split(task_stage.command),
|
||||
copy_in={
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
do not use do not use `getattr`, visit the field explictly
李衍志523370910113
commented
resolved. resolved.
|
||||
file: result.LocalFile(src=str(JOJ3_CONFIG_ROOT / file))
|
||||
# all copyin files store in this tools folder
|
||||
# TODO: are there any corner cases?
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
is there a conclusion now? or it should have a prefix is there a conclusion now? or it should have a prefix `TODO: `?
李衍志523370910113
commented
so far works fine on 280 sides, indicating that pbs in 151 can be resolved with proper guidelines I think. so far works fine on 280 sides, indicating that pbs in 151 can be resolved with proper guidelines I think.
张泊明518370910136
commented
ok, then add that prefix ok, then add that prefix
|
||||
for file in copy_in_files
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
is it in the correct unit? is it in the correct unit?
Give all the fields in `Limit` a default value and make it non optional in task_stage.limit
李衍志523370910113
commented
resolved resolved
|
||||
},
|
||||
copy_out=copy_out_files,
|
||||
copy_in_cached={file: file for file in cached},
|
||||
copy_out_cached=file_export,
|
||||
cpu_limit=Time(task_stage.limit.cpu),
|
||||
clock_limit=2 * Time(task_stage.limit.cpu),
|
||||
memory_limit=Memory(task_stage.limit.mem),
|
||||
stderr=result.Collector(
|
||||
name="stderr", pipe=True, max=Memory(task_stage.limit.stderr)
|
||||
),
|
||||
stdout=result.Collector(
|
||||
name="stdout", pipe=True, max=Memory(task_stage.limit.stdout)
|
||||
),
|
||||
),
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
The reason for the suffix in The reason for the suffix in `keyword_parser_`?
李衍志523370910113
commented
just forgot to remove, sorry just forgot to remove, sorry
|
||||
cases=[],
|
||||
)
|
||||
for file in file_export:
|
||||
cached[file] = None
|
||||
return executor_with_config
|
||||
|
||||
|
||||
def fix_keyword(
|
||||
keyword_config: task.ParserKeyword, keyword_parser: result.Parser
|
||||
) -> None:
|
||||
if len(keyword_config.keyword) != len(keyword_config.weight):
|
||||
raise ValueError("Keywords and weights must have the same length")
|
||||
score_groups: Dict[int, List[str]] = {}
|
||||
for keyword, score in zip(keyword_config.keyword, keyword_config.weight):
|
||||
score_groups.setdefault(score, []).append(keyword)
|
||||
keyword_parser.with_ = result.KeywordMatchConfig(
|
||||
matches=[
|
||||
result.KeywordConfig(keywords=keywords, score=score)
|
||||
for score, keywords in score_groups.items()
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def fix_result_detail(
|
||||
result_detail_parser_config: task.ParserResultDetail,
|
||||
result_detail_parser: result.Parser,
|
||||
) -> None:
|
||||
show_files = []
|
||||
if result_detail_parser_config.stdout:
|
||||
show_files.append("stdout")
|
||||
if result_detail_parser_config.stderr:
|
||||
show_files.append("stderr")
|
||||
result_detail_parser.with_ = result.ResultDetailConfig(
|
||||
score=0,
|
||||
comment="",
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
->
```
if task_stage.parsers is not None:
for parser in task_stage.parsers:
```
->
```
for parser in task_stage.parsers or []:
```
李衍志523370910113
commented
resolved. resolved.
|
||||
show_files=show_files,
|
||||
show_exit_status=result_detail_parser_config.exit_status,
|
||||
show_runtime=result_detail_parser_config.time,
|
||||
show_memory=result_detail_parser_config.mem,
|
||||
)
|
||||
|
||||
|
||||
def fix_dummy(
|
||||
dummy_parser_config: task.ParserDummy, dummy_parser: result.Parser
|
||||
) -> None:
|
||||
# we don't use dummy parser in real application
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
When will it be None? When will it be None?
|
||||
dummy_parser.with_ = result.DummyConfig(
|
||||
score=dummy_parser_config.score,
|
||||
comment=dummy_parser_config.comment,
|
||||
force_quit_on_not_accepted=dummy_parser_config.force_quit,
|
||||
)
|
||||
|
||||
|
||||
def fix_file(file_parser_config: task.ParserFile, file_parser: result.Parser) -> None:
|
||||
file_parser.with_ = result.FileConfig(name=file_parser_config.name)
|
||||
|
||||
|
||||
def fix_diff(
|
||||
task_stage: task.Stage,
|
||||
diff_parser_config: result.Parser,
|
||||
diff_executor: result.Executor,
|
||||
bomingzh marked this conversation as resolved
Outdated
张泊明518370910136
commented
these fields do not exist now these fields do not exist now
李衍志523370910113
commented
resolved resolved
张泊明518370910136
commented
No description provided.
|
||||
base_dir: Path,
|
||||
) -> None:
|
||||
skip = task_stage.skip
|
||||
cases = task_stage.cases
|
||||
finalized_cases = [case for case in cases if case not in skip]
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
move move `continue` to the other branch to reduce nesting
张泊明518370910136
commented
I mean
I mean
```
if parser not in keyword_parser:
continue
```
```
if getattr(task_stage, parser, None) is None:
continue
````
```
if score != score_:
continue
````
李衍志523370910113
commented
fixed. fixed.
|
||||
|
||||
stage_cases = []
|
||||
parser_cases = []
|
||||
|
||||
for case in finalized_cases:
|
||||
case_stage = task_stage.cases.get(case) if task_stage.cases else None
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
Is it necessary to rename? Is it necessary to rename?
|
||||
if not case_stage:
|
||||
continue
|
||||
|
||||
cpu_limit = case_stage.limit.cpu
|
||||
clock_limit = 2 * case_stage.limit.cpu
|
||||
memory_limit = case_stage.limit.mem
|
||||
command = case_stage.command
|
||||
stdin = case_stage.in_ if case_stage.in_ != "" else f"{case}.in"
|
||||
stdout = case_stage.out_ if case_stage.out_ != "" else f"{case}.out"
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
just just `if task_stage.result_detail.stdout:`
|
||||
|
||||
stage_cases.append(
|
||||
result.OptionalCmd(
|
||||
stdin=result.LocalFile(
|
||||
src=str(base_dir / stdin),
|
||||
),
|
||||
args=shlex.split(command) if command else None,
|
||||
cpu_limit=cpu_limit,
|
||||
clock_limit=clock_limit,
|
||||
memory_limit=memory_limit,
|
||||
proc_limit=50,
|
||||
)
|
||||
)
|
||||
diff_output = case_stage.diff.output
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
Pass Pass `JOJ3_CONFIG_ROOT / task_conf.path.parent` as `base_dir` in parameters.
李衍志523370910113
commented
resolved. resolved.
|
||||
parser_cases.append(
|
||||
result.DiffCasesConfig(
|
||||
outputs=[
|
||||
result.DiffOutputConfig(
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
will it be None now? will it be None now?
李衍志523370910113
commented
nope 😂 bad coding strategy before nope 😂 bad coding strategy before
|
||||
score=diff_output.score,
|
||||
file_name="stdout",
|
||||
answer_path=str(base_dir / stdout),
|
||||
force_quit_on_diff=diff_output.force_quit,
|
||||
always_hide=diff_output.hide,
|
||||
compare_space=not diff_output.ignore_spaces,
|
||||
)
|
||||
]
|
||||
)
|
||||
)
|
||||
|
||||
diff_executor.with_.cases = stage_cases
|
||||
diff_parser_config.with_ = result.DiffConfig(name="diff", cases=parser_cases)
|
|
@ -2,7 +2,7 @@ import logging
|
|||
import sys
|
||||
from sys import stderr
|
||||
from types import FrameType
|
||||
from typing import Optional
|
||||
from typing import Optional, Union
|
||||
|
||||
from loguru import logger as logger
|
||||
|
||||
|
@ -10,7 +10,7 @@ from loguru import logger as logger
|
|||
# recipe from https://loguru.readthedocs.io/en/stable/overview.html#entirely-compatible-with-standard-logging
|
||||
class InterceptHandler(logging.Handler):
|
||||
def emit(self, record: logging.LogRecord) -> None:
|
||||
level: str | int
|
||||
level: Union[str, int]
|
||||
try:
|
||||
level = logger.level(record.levelname).name
|
||||
except ValueError:
|
||||
|
|
|
@ -12,6 +12,7 @@ dependencies = [
|
|||
"pydantic>=2.9.2",
|
||||
"inquirer>=3.4.0",
|
||||
"rtoml>=0.11.0",
|
||||
"humanfriendly>=10.0",
|
||||
]
|
||||
requires-python = ">=3.9"
|
||||
authors = [{ name = "JOJ3-dev", email = "joj3@focs.ji.sjtu.edu.cn" }]
|
||||
|
|
33
tests/convert/basic/immutable_files/.gitattributes
vendored
Normal file
|
@ -0,0 +1,33 @@
|
|||
*.avi filter=lfs diff=lfs merge=lfs -text
|
||||
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
||||
*.djvu filter=lfs diff=lfs merge=lfs -text
|
||||
*.doc filter=lfs diff=lfs merge=lfs -text
|
||||
*.docx filter=lfs diff=lfs merge=lfs -text
|
||||
*.epub filter=lfs diff=lfs merge=lfs -text
|
||||
*.gz filter=lfs diff=lfs merge=lfs -text
|
||||
*.ipynb filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpeg filter=lfs diff=lfs merge=lfs -text
|
||||
*.JPEG filter=lfs diff=lfs merge=lfs -text
|
||||
*.jpg filter=lfs diff=lfs merge=lfs -text
|
||||
*.JPG filter=lfs diff=lfs merge=lfs -text
|
||||
*.mkv filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
||||
*.ods filter=lfs diff=lfs merge=lfs -text
|
||||
*.odt filter=lfs diff=lfs merge=lfs -text
|
||||
*.otf filter=lfs diff=lfs merge=lfs -text
|
||||
*.pdf filter=lfs diff=lfs merge=lfs -text
|
||||
*.PDF filter=lfs diff=lfs merge=lfs -text
|
||||
*.png filter=lfs diff=lfs merge=lfs -text
|
||||
*.PNG filter=lfs diff=lfs merge=lfs -text
|
||||
*.ppt filter=lfs diff=lfs merge=lfs -text
|
||||
*.pptx filter=lfs diff=lfs merge=lfs -text
|
||||
*.ps filter=lfs diff=lfs merge=lfs -text
|
||||
*.rar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tar filter=lfs diff=lfs merge=lfs -text
|
||||
*.tgz filter=lfs diff=lfs merge=lfs -text
|
||||
*.ttf filter=lfs diff=lfs merge=lfs -text
|
||||
*.webm filter=lfs diff=lfs merge=lfs -text
|
||||
*.xls filter=lfs diff=lfs merge=lfs -text
|
||||
*.xlsx filter=lfs diff=lfs merge=lfs -text
|
||||
*.xz filter=lfs diff=lfs merge=lfs -text
|
||||
*.zip filter=lfs diff=lfs merge=lfs -text
|
23
tests/convert/basic/immutable_files/.gitignore
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
################################
|
||||
## White list based gitignore ##
|
||||
################################
|
||||
|
||||
# forbidden
|
||||
*
|
||||
.*
|
||||
|
||||
# allowed
|
||||
!.gitignore
|
||||
!.gitattributes
|
||||
!.gitea/
|
||||
!.gitea/issue_template/
|
||||
!.gitea/workflows/
|
||||
!*.yaml
|
||||
!Makefile
|
||||
!CMakeLists.txt
|
||||
!h[0-8]/
|
||||
!*.m
|
||||
!*.c
|
||||
!*.cpp
|
||||
!*.h
|
||||
!*.md
|
19
tests/convert/basic/immutable_files/push.yaml
Normal file
|
@ -0,0 +1,19 @@
|
|||
name: Run JOJ3 on Push
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
run:
|
||||
container:
|
||||
runs-on: focs-latest-slim
|
||||
volumes:
|
||||
- /home/tt/.config:/home/tt/.config
|
||||
- /home/tt/.cache:/home/tt/.cache
|
||||
- /home/tt/.ssh:/home/tt/.ssh
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@focs
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run joj3
|
||||
run: |
|
||||
sudo -E -u tt joj3 -conf-root /home/tt/.config/joj/tests/homework
|
21
tests/convert/basic/immutable_files/release.yaml
Normal file
|
@ -0,0 +1,21 @@
|
|||
name: Run JOJ3 on Release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: focs-latest-slim
|
||||
container:
|
||||
volumes:
|
||||
- /home/tt/.config:/home/tt/.config
|
||||
- /home/tt/.cache:/home/tt/.cache
|
||||
- /home/tt/.ssh:/home/tt/.ssh
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@focs
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run joj3
|
||||
run: |
|
||||
sudo -E -u tt joj3 -conf-root "/home/tt/.config/joj/tests/homework" -conf-name "conf-release.json" -tag "${{ github.ref_name }}"
|
|
@ -1,10 +1,16 @@
|
|||
teaching_team = ["prof_john", "ta_alice", "ta_bob"]
|
||||
max_size = 50.5
|
||||
release_tags = ["v1.0", "v2.0", "final"]
|
||||
grading_repo_name = "ece280-joj"
|
||||
|
||||
sandbox_token = "test"
|
||||
# reconfigure later
|
||||
max_total_score = 100
|
||||
max_size = 50.5
|
||||
|
||||
# for tests
|
||||
[groups]
|
||||
name = ["joj", "run"]
|
||||
max_count = [1000, 1000]
|
||||
time_period_hour = [24, 24]
|
||||
|
||||
[files]
|
||||
whitelist_patterns = ["*.py", "*.txt", "*.md"]
|
||||
whitelist_file = ".whitelist"
|
||||
required = ["main.py", "README.md"]
|
||||
immutable = ["config.yaml", "setup.py"]
|
||||
required = ["README.md", "Changelog.md"]
|
||||
immutable = [".gitignore", ".gitattributes",".gitea/workflows/push.yaml", ".gitea/workflows/release.yaml"]
|
||||
|
|
|
@ -1,47 +1,52 @@
|
|||
{
|
||||
"name": "hw3 ex5",
|
||||
"logPath": "hw3_ex5.log",
|
||||
"expireUnixTimestamp": 1729267140,
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "test",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "judge_base",
|
||||
"group": "hw3 ex5",
|
||||
"name": "Health Check",
|
||||
"group": "",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"name": "local",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./matlab-joj",
|
||||
"./h3/ex5.m"
|
||||
],
|
||||
"args": [],
|
||||
"env": [],
|
||||
"cpuLimit": 0,
|
||||
"realCpuLimit": 0,
|
||||
"clockLimit": 0,
|
||||
"memoryLimit": 0,
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tools/matlab-joj": {
|
||||
"src": "tools/matlab-joj"
|
||||
},
|
||||
"tools/matlab_formatter.py": {
|
||||
"src": "tools/matlab_formatter.py"
|
||||
}
|
||||
},
|
||||
"copyIn": {},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [],
|
||||
"copyOutCached": [
|
||||
"output/ex5_results.txt",
|
||||
"output/ex5_logs.txt"
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
|
@ -49,59 +54,98 @@
|
|||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
"cases": [
|
||||
{
|
||||
"args": [
|
||||
"/usr/local/bin/repo-health-checker",
|
||||
"-root=.",
|
||||
"-repoSize=50.5",
|
||||
"-meta=README.md",
|
||||
"-meta=Changelog.md",
|
||||
"-checkFileSumList=a5b63323a692d3d8b952442969649b4f823d58dae26429494f613df160710dfc,b1bbad25b830db0a77b15a033f9ca1b7ab44c1d2d05056412bd3e4421645f0bf,2ba059f3977e2e3dee6cacbfbf0ba2578baa1b8e04b4977aec400868b6e49856,bf7d181362affdcc72aac33f3520e4e6371adc48ea62a6f24524b4a3e76724c5",
|
||||
"-checkFileNameList=.gitignore,.gitattributes,.gitea/workflows/push.yaml,.gitea/workflows/release.yaml"
|
||||
]
|
||||
},
|
||||
{
|
||||
"args": [
|
||||
"/usr/local/bin/joint-teapot",
|
||||
"joj3-check-env",
|
||||
"/home/tt/.config/teapot/teapot.env",
|
||||
"--grading-repo-name",
|
||||
"ece280-joj",
|
||||
"--group-config",
|
||||
"joj=1000:24,run=1000:24"
|
||||
],
|
||||
"env": [
|
||||
"LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "diff",
|
||||
"with": {}
|
||||
"name": "healthcheck",
|
||||
"with": {
|
||||
"score": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"name": "debug",
|
||||
"with": {
|
||||
"time": false,
|
||||
"mem": false,
|
||||
"stdout": false,
|
||||
"stderr": true
|
||||
"score": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "judge_base2",
|
||||
"group": "hw3 ex5",
|
||||
"name": "Compilation",
|
||||
"group": "",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./matlab-joj",
|
||||
"./h3/ex5.m"
|
||||
"./tools/compile"
|
||||
],
|
||||
"env": [],
|
||||
"cpuLimit": 0,
|
||||
"realCpuLimit": 0,
|
||||
"clockLimit": 0,
|
||||
"memoryLimit": 0,
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tools/matlab-joj": {
|
||||
"src": "tools/matlab-joj"
|
||||
},
|
||||
"tools/matlab_formatter.py": {
|
||||
"src": "tools/matlab_formatter.py"
|
||||
"tools/compile": {
|
||||
"src": "/home/tt/.config/joj/tools/compile"
|
||||
}
|
||||
},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [],
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [
|
||||
"output/ex5_results2.txt",
|
||||
"output/ex5_logs2.txt"
|
||||
"h7/build/ex2",
|
||||
"h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json"
|
||||
],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
|
@ -115,29 +159,691 @@
|
|||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "diff",
|
||||
"with": {}
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-status",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "Congratulations! Your code compiled successfully.",
|
||||
"forceQuitOnNotAccepted": true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[cq] Filelength",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./tools/filelength",
|
||||
"400",
|
||||
"300",
|
||||
"*.cpp",
|
||||
"*.h"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tools/filelength": {
|
||||
"src": "/home/tt/.config/joj/tools/filelength"
|
||||
}
|
||||
},
|
||||
"copyInCached": {
|
||||
"h7/build/ex2": "h7/build/ex2",
|
||||
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||
},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "keyword",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"max"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"recommended"
|
||||
],
|
||||
"score": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"time": true,
|
||||
"mem": true,
|
||||
"stdout": false,
|
||||
"stderr": false
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stdout"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[cq] Clang-tidy",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"run-clang-tidy-18",
|
||||
"-header-filter=.*",
|
||||
"-quiet",
|
||||
"-load=/usr/local/lib/libcodequality.so",
|
||||
"-p",
|
||||
"h7/build",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 4194304,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tests/homework/h7/.clang-tidy": {
|
||||
"src": "/home/tt/.config/joj/tests/homework/h7/.clang-tidy"
|
||||
}
|
||||
},
|
||||
"copyInCached": {
|
||||
"h7/build/ex2": "h7/build/ex2",
|
||||
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||
},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "clangtidy",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"codequality-unchecked-malloc-result",
|
||||
"readability-duplicate-include",
|
||||
"readability-identifier-naming",
|
||||
"readability-redundant",
|
||||
"readability-misplaced-array-index",
|
||||
"cppcoreguidelines-init-variables",
|
||||
"bugprone-suspicious-string-compare",
|
||||
"google-global-names-in-headers",
|
||||
"clang-diagnostic",
|
||||
"clang-analyzer",
|
||||
"misc",
|
||||
"performance",
|
||||
"portability"
|
||||
],
|
||||
"score": 5
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"codequality-no-global-variables",
|
||||
"codequality-no-header-guard",
|
||||
"codequality-no-fflush-stdin"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability-function-size"
|
||||
],
|
||||
"score": 10
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability-misleading-indentation"
|
||||
],
|
||||
"score": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stdout"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[cq] Cppcheck",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"cppcheck",
|
||||
"--template={\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}",
|
||||
"--force",
|
||||
"--enable=all",
|
||||
"--suppress=missingIncludeSystem",
|
||||
"--quiet",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 8388608,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {
|
||||
"h7/build/ex2": "h7/build/ex2",
|
||||
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||
},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "keyword",
|
||||
"with": {
|
||||
"matches": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cppcheck",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"error"
|
||||
],
|
||||
"score": 15
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"warning",
|
||||
"portability",
|
||||
"performance",
|
||||
"style"
|
||||
],
|
||||
"score": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "clangtidy",
|
||||
"with": {
|
||||
"matches": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "cpplint",
|
||||
"with": {
|
||||
"matches": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-status",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"forceQuitOnNotAccepted": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "file",
|
||||
"with": {
|
||||
"name": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "dummy",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"forceQuitOnNotAccepted": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "diff",
|
||||
"with": {
|
||||
"name": "diff",
|
||||
"cases": []
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[cq] Cpplint",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"cpplint",
|
||||
"--linelength=120",
|
||||
"--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use",
|
||||
"--recursive",
|
||||
"--exclude=build",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 68157440,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {
|
||||
"h7/build/ex2": "h7/build/ex2",
|
||||
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||
},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "cpplint",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"runtime"
|
||||
],
|
||||
"score": 5
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"build"
|
||||
],
|
||||
"score": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "[joj] ex2-asan",
|
||||
"group": "joj",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./h7/build/ex2-asan",
|
||||
"-a"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {
|
||||
"h7/build/ex2": "h7/build/ex2",
|
||||
"h7/build/ex2-asan": "h7/build/ex2-asan",
|
||||
"h7/build/ex2-ubsan": "h7/build/ex2-ubsan",
|
||||
"h7/build/ex2-msan": "h7/build/ex2-msan",
|
||||
"h7/build/compile_commands.json": "h7/build/compile_commands.json"
|
||||
},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"stdin": {
|
||||
"src": "/home/tt/.config/joj/basic/case0.in"
|
||||
},
|
||||
"cpuLimit": 500000000,
|
||||
"clockLimit": 1000000000,
|
||||
"memoryLimit": 5242880,
|
||||
"procLimit": 50
|
||||
},
|
||||
{
|
||||
"stdin": {
|
||||
"src": "/home/tt/.config/joj/basic/case1.in"
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 5242880,
|
||||
"procLimit": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "diff",
|
||||
"with": {
|
||||
"name": "diff",
|
||||
"cases": [
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"score": 5,
|
||||
"fileName": "stdout",
|
||||
"answerPath": "/home/tt/.config/joj/basic/case0.out",
|
||||
"forceQuitOnDiff": false,
|
||||
"alwaysHide": false,
|
||||
"compareSpace": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"score": 5,
|
||||
"fileName": "stdout",
|
||||
"answerPath": "/home/tt/.config/joj/basic/case1.out",
|
||||
"forceQuitOnDiff": false,
|
||||
"alwaysHide": false,
|
||||
"compareSpace": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": true,
|
||||
"showMemory": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": [
|
||||
{
|
||||
"name": "teapot",
|
||||
"group": "",
|
||||
"executor": {
|
||||
"name": "local",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"/usr/local/bin/joint-teapot",
|
||||
"joj3-all-env",
|
||||
"/home/tt/.config/teapot/teapot.env",
|
||||
"--grading-repo-name",
|
||||
"ece280-joj",
|
||||
"--max-total-score",
|
||||
"100"
|
||||
],
|
||||
"env": [
|
||||
"LOG_FILE_PATH=/home/tt/.cache/joint-teapot-debug.log"
|
||||
],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "log",
|
||||
"with": {
|
||||
"msg": "joj3 summary"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"teapot": {
|
||||
"logPath": "/home/tt/.cache/joint-teapot-debug.log",
|
||||
"scoreboardPath": "scoreboard.csv",
|
||||
"failedTablePath": "failed-table.md",
|
||||
"gradingRepoName": "",
|
||||
"skipIssue": false,
|
||||
"skipScoreboard": false,
|
||||
"skipFailedTable": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,30 +1,102 @@
|
|||
task = "hw3 ex5"
|
||||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
[release]
|
||||
deadline = "2024-10-18T23:59:00+08:00"
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "judge_base"
|
||||
command = "./matlab-joj ./h3/ex5.m"
|
||||
score = 100
|
||||
parsers = ["diff", "result-detail"]
|
||||
name = "Compilation"
|
||||
command = "./tools/compile" # eg. script running cmake commands
|
||||
files.import = [ "tools/compile" ]
|
||||
files.export = [ "h7/build/ex2", "h7/build/ex2-asan", "h7/build/ex2-ubsan", "h7/build/ex2-msan", "h7/build/compile_commands.json" ]
|
||||
score = 1
|
||||
|
||||
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
|
||||
files.export = ["output/ex5_results.txt", "output/ex5_logs.txt"]
|
||||
|
||||
result_detail.time = false
|
||||
result_detail.mem = false
|
||||
result_detail.stderr = true
|
||||
# compile parsers
|
||||
parsers = [ "result-detail", "result-status" ]
|
||||
result-status.comment = "Congratulations! Your code compiled successfully."
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
||||
result-status.force_quit = true
|
||||
|
||||
[[stages]]
|
||||
name = "judge_base2"
|
||||
command = "./matlab-joj ./h3/ex5.m"
|
||||
score = 80
|
||||
parsers = ["diff", "result-detail"]
|
||||
name = "[cq] Filelength"
|
||||
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||
files.import = [ "tools/filelength" ]
|
||||
|
||||
files.import = ["tools/matlab-joj", "tools/matlab_formatter.py"]
|
||||
files.export = ["output/ex5_results2.txt", "output/ex5_logs2.txt"]
|
||||
parsers = [ "keyword", "result-detail" ]
|
||||
keyword.keyword = [ "max", "recommended"]
|
||||
keyword.weight = [ 20, 10 ]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stdout = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
||||
|
||||
result_detail.time = true
|
||||
result_detail.mem = true
|
||||
result_detail.stderr = false
|
||||
[[stages]]
|
||||
name = "[cq] Clang-tidy"
|
||||
command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p h7/build h7/ex2.cpp"
|
||||
files.import = [ "tests/homework/h7/.clang-tidy", "h7/build/compile_commands.json" ]
|
||||
limit.stdout = "4m"
|
||||
|
||||
parsers = [ "clangtidy", "result-detail" ]
|
||||
clangtidy.keyword = [ "codequality-unchecked-malloc-result", "codequality-no-global-variables", "codequality-no-header-guard", "codequality-no-fflush-stdin", "readability-function-size", "readability-duplicate-include", "readability-identifier-naming", "readability-redundant", "readability-misleading-indentation", "readability-misplaced-array-index", "cppcoreguidelines-init-variables", "bugprone-suspicious-string-compare", "google-global-names-in-headers", "clang-diagnostic", "clang-analyzer", "misc", "performance", "portability" ]
|
||||
clangtidy.weight = [ 5, 20, 20, 20, 10, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stdout = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Cppcheck"
|
||||
command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --suppress=missingIncludeSystem --quiet h7/ex2.cpp"
|
||||
limit.stderr = "8m"
|
||||
|
||||
parsers = [ "keyword", "cppcheck", "clangtidy", "result-detail", "cpplint", "result-status", "file", "dummy", "diff" ]
|
||||
cppcheck.keyword = ["error", "warning", "portability", "performance", "style"]
|
||||
cppcheck.weight = [15, 5, 5, 5, 5]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Cpplint"
|
||||
command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use --recursive --exclude=build h7/ex2.cpp"
|
||||
limit.stdout = "65m"
|
||||
jon-lee marked this conversation as resolved
Outdated
张泊明518370910136
commented
is it used? is it used?
李衍志523370910113
commented
testcases in basic is intend to show a comprehensive situation. testcases in basic is intend to show a comprehensive situation.
张泊明518370910136
commented
if unused, leave a comment if unused, leave a comment
张泊明518370910136
commented
Then why is there a Then why is there a `stdout` field in `class Limit`
李衍志523370910113
commented
@bomingzh in toml now should we accept both @bomingzh in toml now should we accept both `32m` and `32` or just `32m` now?
李衍志523370910113
commented
I reckon only I reckon only `32m` would be good
张泊明518370910136
commented
yes, just str yes, just str
|
||||
|
||||
parsers = [ "cpplint", "result-detail" ]
|
||||
cpplint.keyword = [ "runtime", "readability", "build" ]
|
||||
cpplint.weight = [ 5, 20, 10]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
||||
|
||||
[[stages]]
|
||||
name = "[joj] ex2-asan"
|
||||
command="./h7/build/ex2-asan -a"
|
||||
files.import = [ "h7/build/ex2-asan" ]
|
||||
limit.mem = "128m"
|
||||
|
||||
parsers = [ "diff", "result-detail" ]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
|
||||
# will be removed as long as the name is fixed
|
||||
case0.diff.output.score = 5
|
||||
case0.limit.cpu = "0.5s"
|
||||
case0.limit.mem = "5m"
|
||||
case0.diff.output.ignore_spaces = true
|
||||
#case0.limit.stdout = 8
|
||||
#case0.command = "./h7/build/ex2"
|
||||
case0.in = "case0.in"
|
||||
|
||||
case1.diff.output.score = 5
|
||||
case1.limit.cpu = "1s"
|
||||
case1.limit.mem = "5m"
|
||||
case1.diff.output.ignore_spaces = true
|
||||
#case1.limit.stdout = 8
|
||||
#case1.command = "./h7/build/ex2"
|
||||
case1.in = "case1.in"
|
||||
|
|
2
tests/convert/clang-tidy/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
140
tests/convert/clang-tidy/task.json
Normal file
|
@ -0,0 +1,140 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[cq] Clang-tidy",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"run-clang-tidy-18",
|
||||
"-header-filter=.*",
|
||||
"-quiet",
|
||||
"-load=/usr/local/lib/libcodequality.so",
|
||||
"-p",
|
||||
"h7/build",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 68157440,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tests/homework/h7/.clang-tidy": {
|
||||
"src": "/home/tt/.config/joj/tests/homework/h7/.clang-tidy"
|
||||
},
|
||||
"h7/build/compile_commands.json": {
|
||||
"src": "/home/tt/.config/joj/h7/build/compile_commands.json"
|
||||
}
|
||||
},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "clangtidy",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"codequality-unchecked-malloc-result",
|
||||
"readability-duplicate-include",
|
||||
"readability-identifier-naming",
|
||||
"readability-redundant",
|
||||
"readability-misplaced-array-index",
|
||||
"cppcoreguidelines-init-variables",
|
||||
"bugprone-suspicious-string-compare",
|
||||
"google-global-names-in-headers",
|
||||
"clang-diagnostic",
|
||||
"clang-analyzer",
|
||||
"misc",
|
||||
"performance",
|
||||
"portability"
|
||||
],
|
||||
"score": 5
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"codequality-no-global-variables",
|
||||
"codequality-no-header-guard",
|
||||
"codequality-no-fflush-stdin"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability-function-size"
|
||||
],
|
||||
"score": 10
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability-misleading-indentation"
|
||||
],
|
||||
"score": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stdout"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
20
tests/convert/clang-tidy/task.toml
Normal file
|
@ -0,0 +1,20 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Clang-tidy"
|
||||
command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p h7/build h7/ex2.cpp"
|
||||
files.import = [ "tests/homework/h7/.clang-tidy", "h7/build/compile_commands.json" ]
|
||||
limit.stdout = "65m"
|
||||
|
||||
parsers = [ "clangtidy", "result-detail" ]
|
||||
clangtidy.keyword = [ "codequality-unchecked-malloc-result", "codequality-no-global-variables", "codequality-no-header-guard", "codequality-no-fflush-stdin", "readability-function-size", "readability-duplicate-include", "readability-identifier-naming", "readability-redundant", "readability-misleading-indentation", "readability-misplaced-array-index", "cppcoreguidelines-init-variables", "bugprone-suspicious-string-compare", "google-global-names-in-headers", "clang-diagnostic", "clang-analyzer", "misc", "performance", "portability" ]
|
||||
clangtidy.weight = [ 5, 20, 20, 20, 10, 5, 5, 5, 15, 5, 5, 5, 5, 5, 5, 5, 5, 5]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stdout = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
2
tests/convert/cppcheck/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
110
tests/convert/cppcheck/task.json
Normal file
|
@ -0,0 +1,110 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[cq] Cppcheck",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"cppcheck",
|
||||
"--template={\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}",
|
||||
"--force",
|
||||
"--enable=all",
|
||||
"--suppress=missingIncludeSystem",
|
||||
"--quiet",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 68157440,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "cppcheck",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"error"
|
||||
],
|
||||
"score": 15
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"warning",
|
||||
"portability",
|
||||
"performance",
|
||||
"style"
|
||||
],
|
||||
"score": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
19
tests/convert/cppcheck/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Cppcheck"
|
||||
command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --suppress=missingIncludeSystem --quiet h7/ex2.cpp"
|
||||
limit.stderr = "65m"
|
||||
|
||||
parsers = [ "cppcheck", "result-detail" ]
|
||||
cppcheck.keyword = ["error", "warning", "portability", "performance", "style"]
|
||||
cppcheck.weight = [15, 5, 5, 5, 5]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
2
tests/convert/cpplint/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
112
tests/convert/cpplint/task.json
Normal file
|
@ -0,0 +1,112 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[cq] Cpplint",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"cpplint",
|
||||
"--linelength=120",
|
||||
"--filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use",
|
||||
"--recursive",
|
||||
"--exclude=build",
|
||||
"h7/ex2.cpp"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 68157440,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "cpplint",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"runtime"
|
||||
],
|
||||
"score": 5
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"readability"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"build"
|
||||
],
|
||||
"score": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
19
tests/convert/cpplint/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Cpplint"
|
||||
command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-runtime/int,-readability/todo,-build/include_subdir,-build/header_guard,-build/include_what_you_use --recursive --exclude=build h7/ex2.cpp"
|
||||
limit.stdout = "65m"
|
||||
|
||||
parsers = [ "cpplint", "result-detail" ]
|
||||
cpplint.keyword = [ "runtime", "readability", "build" ]
|
||||
cpplint.weight = [ 5, 20, 10]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
2
tests/convert/diff/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
138
tests/convert/diff/task.json
Normal file
|
@ -0,0 +1,138 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[joj] ex2-asan",
|
||||
"group": "joj",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./h7/build/ex2-asan",
|
||||
"-a"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 68157440,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"h7/build/ex2-asan": {
|
||||
"src": "/home/tt/.config/joj/h7/build/ex2-asan"
|
||||
}
|
||||
},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": [
|
||||
{
|
||||
"stdin": {
|
||||
"src": "/home/tt/.config/joj/diff/case0.in"
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 2097152,
|
||||
"procLimit": 50
|
||||
},
|
||||
{
|
||||
"stdin": {
|
||||
"src": "/home/tt/.config/joj/diff/case1.in"
|
||||
},
|
||||
"cpuLimit": 2000000000,
|
||||
"clockLimit": 4000000000,
|
||||
"memoryLimit": 4194304,
|
||||
"procLimit": 50
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "diff",
|
||||
"with": {
|
||||
"name": "diff",
|
||||
"cases": [
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"score": 5,
|
||||
"fileName": "stdout",
|
||||
"answerPath": "/home/tt/.config/joj/diff/case0.out",
|
||||
"forceQuitOnDiff": false,
|
||||
"alwaysHide": false,
|
||||
"compareSpace": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"outputs": [
|
||||
{
|
||||
"score": 5,
|
||||
"fileName": "stdout",
|
||||
"answerPath": "/home/tt/.config/joj/diff/case1.out",
|
||||
"forceQuitOnDiff": false,
|
||||
"alwaysHide": false,
|
||||
"compareSpace": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": true,
|
||||
"showMemory": true
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
33
tests/convert/diff/task.toml
Normal file
|
@ -0,0 +1,33 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[joj] ex2-asan"
|
||||
command="./h7/build/ex2-asan -a"
|
||||
files.import = [ "h7/build/ex2-asan" ]
|
||||
limit.mem = "65m"
|
||||
|
||||
parsers = [ "diff", "result-detail" ]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stderr = true
|
||||
|
||||
# will be removed as long as the name is fixed
|
||||
case0.diff.output.score = 5
|
||||
case0.limit.cpu = "1s"
|
||||
case0.limit.mem = "2m"
|
||||
case0.diff.output.ignore_spaces = true
|
||||
#case0.limit.stdout = 8
|
||||
#case0.command = "./h7/build/ex2"
|
||||
case0.in = "case0.in"
|
||||
|
||||
case1.diff.output.score = 5
|
||||
case1.limit.cpu = "2s"
|
||||
case1.limit.mem = "4m"
|
||||
case1.diff.output.ignore_spaces = true
|
||||
#case1.limit.stdout = 8
|
||||
#case1.command = "./h7/build/ex2"
|
||||
case1.in = "case1.in"
|
2
tests/convert/keyword/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
109
tests/convert/keyword/task.json
Normal file
|
@ -0,0 +1,109 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[cq] Filelength",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./tools/filelength",
|
||||
"400",
|
||||
"300",
|
||||
"*.cpp",
|
||||
"*.h"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tools/filelength": {
|
||||
"src": "/home/tt/.config/joj/tools/filelength"
|
||||
}
|
||||
},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "keyword",
|
||||
"with": {
|
||||
"matches": [
|
||||
{
|
||||
"keywords": [
|
||||
"max"
|
||||
],
|
||||
"score": 20
|
||||
},
|
||||
{
|
||||
"keywords": [
|
||||
"recommended"
|
||||
],
|
||||
"score": 10
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stdout"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
19
tests/convert/keyword/task.toml
Normal file
|
@ -0,0 +1,19 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Filelength"
|
||||
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||
files.import = [ "tools/filelength" ]
|
||||
|
||||
parsers = [ "keyword", "result-detail" ]
|
||||
keyword.keyword = [ "max", "recommended"]
|
||||
keyword.weight = [ 20, 10 ]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stdout = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
2
tests/convert/result-detail/repo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
force_skip_health_check_on_test = true
|
||||
force_skip_teapot_on_test = true
|
91
tests/convert/result-detail/task.json
Normal file
|
@ -0,0 +1,91 @@
|
|||
{
|
||||
"name": "hw7 ex2",
|
||||
"logPath": "/home/tt/.cache/joj3/homework/h7/e2.log",
|
||||
"expireUnixTimestamp": 1735574399,
|
||||
"effectiveUnixTimestamp": 1735487999,
|
||||
"actorCsvPath": "/home/tt/.config/joj/students.csv",
|
||||
"maxTotalScore": 100,
|
||||
"stage": {
|
||||
"sandboxExecServer": "172.17.0.1:5051",
|
||||
"sandboxToken": "",
|
||||
"outputPath": "/tmp/joj3_result.json",
|
||||
"stages": [
|
||||
{
|
||||
"name": "[cq] Filelength",
|
||||
"group": "cq",
|
||||
"executor": {
|
||||
"name": "sandbox",
|
||||
"with": {
|
||||
"default": {
|
||||
"args": [
|
||||
"./tools/filelength",
|
||||
"400",
|
||||
"300",
|
||||
"*.cpp",
|
||||
"*.h"
|
||||
],
|
||||
"env": [],
|
||||
"stdin": {
|
||||
"content": ""
|
||||
},
|
||||
"stdout": {
|
||||
"name": "stdout",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"stderr": {
|
||||
"name": "stderr",
|
||||
"max": 33554432,
|
||||
"pipe": true
|
||||
},
|
||||
"cpuLimit": 1000000000,
|
||||
"clockLimit": 2000000000,
|
||||
"memoryLimit": 134217728,
|
||||
"stackLimit": 0,
|
||||
"procLimit": 50,
|
||||
"cpuRateLimit": 0,
|
||||
"cpuSetLimit": "",
|
||||
"copyIn": {
|
||||
"tools/filelength": {
|
||||
"src": "/home/tt/.config/joj/tools/filelength"
|
||||
}
|
||||
},
|
||||
"copyInCached": {},
|
||||
"copyInDir": ".",
|
||||
"copyOut": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"copyOutCached": [],
|
||||
"copyOutMax": 0,
|
||||
"copyOutDir": "",
|
||||
"tty": false,
|
||||
"strictMemoryLimit": false,
|
||||
"dataSegmentLimit": false,
|
||||
"addressSpaceLimit": false
|
||||
},
|
||||
"cases": []
|
||||
}
|
||||
},
|
||||
"parsers": [
|
||||
{
|
||||
"name": "result-detail",
|
||||
"with": {
|
||||
"score": 0,
|
||||
"comment": "",
|
||||
"showFiles": [
|
||||
"stdout",
|
||||
"stderr"
|
||||
],
|
||||
"showExitStatus": true,
|
||||
"showRuntime": false,
|
||||
"showMemory": false
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"preStages": [],
|
||||
"postStages": []
|
||||
}
|
||||
}
|
18
tests/convert/result-detail/task.toml
Normal file
|
@ -0,0 +1,18 @@
|
|||
# general task configuration
|
||||
task.name = "hw7 ex2" # task name
|
||||
task.type = "homework/h7/e2" # remove this task type later
|
||||
|
||||
release.end_time = 2024-12-30 23:59:59+08:00
|
||||
release.begin_time = 2024-12-29 23:59:59+08:00
|
||||
|
||||
[[stages]]
|
||||
name = "[cq] Filelength"
|
||||
command = "./tools/filelength 400 300 *.cpp *.h"
|
||||
files.import = [ "tools/filelength" ]
|
||||
|
||||
parsers = [ "result-detail" ]
|
||||
result-detail.exitstatus = true
|
||||
result-detail.stdout = true
|
||||
result-detail.stderr = true
|
||||
result-detail.time = false
|
||||
result-detail.mem = false
|
|
@ -3,3 +3,27 @@ from tests.convert.utils import load_case
|
|||
|
||||
def test_basic() -> None:
|
||||
load_case("basic")
|
||||
|
||||
|
||||
def test_clang_tidy() -> None:
|
||||
load_case("clang-tidy")
|
||||
|
||||
|
||||
def test_cppcheck() -> None:
|
||||
load_case("cppcheck")
|
||||
|
||||
|
||||
def test_cpplint() -> None:
|
||||
load_case("cpplint")
|
||||
|
||||
|
||||
def test_diff() -> None:
|
||||
load_case("diff")
|
||||
|
||||
|
||||
def test_keyword() -> None:
|
||||
load_case("keyword")
|
||||
|
||||
|
||||
def test_result_detail() -> None:
|
||||
load_case("result-detail")
|
||||
|
|
|
@ -1,32 +1,18 @@
|
|||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import rtoml
|
||||
|
||||
from joj3_config_generator.convert import convert
|
||||
from joj3_config_generator.models import repo, task
|
||||
|
||||
|
||||
def read_convert_files(
|
||||
case_name: str,
|
||||
) -> Tuple[repo.Config, task.Config, Dict[str, Any]]:
|
||||
root = Path(__file__).resolve().parent / case_name
|
||||
repo_toml_path = root / "repo.toml"
|
||||
repo_toml = repo_toml_path.read_text() if repo_toml_path.exists() else ""
|
||||
task_toml_path = root / "task.toml"
|
||||
task_toml = task_toml_path.read_text() if task_toml_path.exists() else ""
|
||||
result = json.loads((root / "task.json").read_text())
|
||||
return (
|
||||
repo.Config(root=root, **rtoml.loads(repo_toml)),
|
||||
task.Config(root=root, **rtoml.loads(task_toml)),
|
||||
result,
|
||||
)
|
||||
from joj3_config_generator.load import load_joj3_toml
|
||||
|
||||
|
||||
def load_case(case_name: str) -> None:
|
||||
repo, task, expected_result = read_convert_files(case_name)
|
||||
result = convert(repo, task).model_dump(
|
||||
root = Path(__file__).resolve().parent
|
||||
repo_toml_path = root / case_name / "repo.toml"
|
||||
task_toml_path = root / case_name / "task.toml"
|
||||
repo_conf, task_conf = load_joj3_toml(root, repo_toml_path, task_toml_path)
|
||||
result_json_path = root / case_name / "task.json"
|
||||
expected_result = json.loads(result_json_path.read_text())
|
||||
result = convert(repo_conf, task_conf).model_dump(
|
||||
mode="json", by_alias=True, exclude_none=True
|
||||
)
|
||||
assert result == expected_result
|
||||
|
|
|
@ -1,23 +1,19 @@
|
|||
from pathlib import Path
|
||||
from typing import Any, Dict, Tuple
|
||||
|
||||
import rtoml
|
||||
import yaml
|
||||
|
||||
from joj3_config_generator.convert import convert_joj1
|
||||
from joj3_config_generator.models import joj1
|
||||
|
||||
|
||||
def read_convert_joj1_files(case_name: str) -> Tuple[joj1.Config, Dict[str, Any]]:
|
||||
root = Path(__file__).resolve().parent
|
||||
task_yaml_path = root / case_name / "task.yaml"
|
||||
task_yaml = task_yaml_path.read_text()
|
||||
task_toml_path = root / case_name / "task.toml"
|
||||
task_toml = task_toml_path.read_text()
|
||||
return joj1.Config(**yaml.safe_load(task_yaml)), rtoml.loads(task_toml)
|
||||
from joj3_config_generator.load import load_joj1_yaml
|
||||
|
||||
|
||||
def load_case(case_name: str) -> None:
|
||||
joj1, expected_result = read_convert_joj1_files(case_name)
|
||||
result = convert_joj1(joj1).model_dump(by_alias=True, exclude_none=True)
|
||||
root = Path(__file__).resolve().parent
|
||||
task_yaml_path = root / case_name / "task.yaml"
|
||||
task_yaml = load_joj1_yaml(task_yaml_path)
|
||||
task_toml_path = root / case_name / "task.toml"
|
||||
task_toml = task_toml_path.read_text()
|
||||
expected_result = rtoml.loads(task_toml)
|
||||
result = convert_joj1(task_yaml).model_dump(
|
||||
mode="json", by_alias=True, exclude_none=True
|
||||
)
|
||||
assert result == expected_result
|
||||
|
|
Make this
Path.home()
default to/home/tt
. For now, create a const for this dir.fixed