dev #10
|  | @ -19,35 +19,76 @@ from joj3_config_generator.lib.task import ( | |||
|     get_executorWithConfig, | ||||
| ) | ||||
| from joj3_config_generator.models import joj1, repo, result, task | ||||
| from joj3_config_generator.lib.repo import getHealthcheckConfig, getTeapotConfig | ||||
| from joj3_config_generator.models import ( | ||||
|     Cmd, | ||||
|     CmdFile, | ||||
|     ExecutorConfig, | ||||
|     ExecutorWithConfig, | ||||
|     ParserConfig, | ||||
|     Repo, | ||||
|     ResultConfig, | ||||
|     Stage, | ||||
|     StageConfig, | ||||
| 
					
					jon-lee marked this conversation as resolved
					
						
						
							Outdated
						
					
				 | ||||
|     Task, | ||||
|     TeapotConfig, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| 
					
					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(repo_conf: repo.Config, task_conf: task.Config) -> result.Config: | ||||
|     # Create the base ResultConf object | ||||
|     result_conf = result.Config( | ||||
|         name=task_conf.task, | ||||
|         # TODO: specify the exact folder difference | ||||
|         log_path=f"{task_conf.task.replace(' ', '-')}.log", | ||||
|         # TODO: specify the exact folder difference | ||||
|         log_path=f"{task_conf.task.replace(' ', '-')}.log", | ||||
|         expire_unix_timestamp=( | ||||
|             int(task_conf.release.deadline.timestamp()) | ||||
| 
					
					jon-lee marked this conversation as resolved
					
						
						
							Outdated
						
					
				 
				
					
						张泊明518370910136
						commented  why? why? 
				
					
						李衍志523370910113
						commented  forgot to uncommented 😭 forgot to uncommented 😭 
				
					
						李衍志523370910113
						commented  fixed fixed | ||||
|             if task_conf.release.deadline | ||||
|             else -1 | ||||
|         ), | ||||
|         stage=result.Stage(stages=[], sandbox_token=repo_conf.sandbox_token), | ||||
|         teapot=result.Teapot(), | ||||
|         stage=StageConfig(stages=[], sandbox_token=repo_conf.sandbox_token), | ||||
|         teapot=getTeapotConfig(repo_conf, task_conf), | ||||
|     ) | ||||
| 
 | ||||
|     # Construct healthcheck stage | ||||
|     healthcheck_stage = getHealthcheckConfig(repo_conf) | ||||
|     healthcheck_stage = getHealthcheckConfig(repo_conf, task_conf) | ||||
|     result_conf.stage.stages.append(healthcheck_stage) | ||||
|     cached: list[str] = [] | ||||
|     cached = [] | ||||
|     # Convert each stage in the task configuration | ||||
|     for task_stage in task_conf.stages: | ||||
|         executor_with_config, cached = get_executorWithConfig(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_diff(task_stage, conf_stage) | ||||
|         executor_with_config = result.ExecutorWith( | ||||
|             default=result.Cmd( | ||||
|                 args=task_stage.command.split(), | ||||
|                 copy_in={ | ||||
|                     file: result.CmdFile(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" | ||||
|             ) | ||||
|             if task_stage.result_detail is not None: | ||||
|                 result_detail_parser.with_.update(task_stage.result_detail) | ||||
| 
 | ||||
|         result_conf.stage.stages.append(conf_stage) | ||||
| 
 | ||||
|     return result_conf | ||||
|  |  | |||
|  | @ -0,0 +1,11 @@ | |||
| from joj3_config_generator.models.repo import Repo as Repo | ||||
| from joj3_config_generator.models.result import Cmd as Cmd | ||||
| from joj3_config_generator.models.result import CmdFile as CmdFile | ||||
| from joj3_config_generator.models.result import ExecutorConfig as ExecutorConfig | ||||
| from joj3_config_generator.models.result import ExecutorWithConfig as ExecutorWithConfig | ||||
| from joj3_config_generator.models.result import ParserConfig as ParserConfig | ||||
| from joj3_config_generator.models.result import ResultConfig as ResultConfig | ||||
| from joj3_config_generator.models.result import Stage as Stage | ||||
| from joj3_config_generator.models.result import StageConfig as StageConfig | ||||
| from joj3_config_generator.models.result import TeapotConfig as TeapotConfig | ||||
| from joj3_config_generator.models.task import Task as Task | ||||
|  | @ -1,18 +1,40 @@ | |||
| import hashlib | ||||
| import shlex | ||||
| import socket | ||||
| from pathlib import Path | ||||
| import os | ||||
| import tempfile | ||||
| 
 | ||||
| from joj3_config_generator.models import joj1, repo, result, task | ||||
| from dotenv import load_dotenv | ||||
| 
 | ||||
| from joj3_config_generator.models import ( | ||||
|     Cmd, | ||||
|     CmdFile, | ||||
|     ExecutorConfig, | ||||
|     ExecutorWithConfig, | ||||
|     ParserConfig, | ||||
|     Repo, | ||||
|     ResultConfig, | ||||
|     Stage, | ||||
|     StageConfig, | ||||
|     Task, | ||||
|     TeapotConfig, | ||||
| ) | ||||
| 
 | ||||
| 
 | ||||
| def get_temp_directory() -> str: | ||||
|     return tempfile.mkdtemp(prefix="repo-checker-") | ||||
| 
 | ||||
| 
 | ||||
| def getGradingRepoName() -> str: | ||||
|     host_name = socket.gethostname() | ||||
|     return f"{host_name.split('-')[0]}-joj" | ||||
|     path = os.path.expanduser("~/.config/teapot/teapot.env") | ||||
|     if os.path.exists(path): | ||||
|         load_dotenv(path) | ||||
|         repo_name = os.environ.get("GITEA_ORG_NAME") | ||||
|         if repo_name is not None: | ||||
|             return f"{repo_name.split('-')[0]}-joj" | ||||
|     return "ece482-joj" | ||||
| 
 | ||||
| 
 | ||||
| def getTeapotConfig(repo_conf: repo.Config, task_conf: task.Config) -> result.Teapot: | ||||
|     teapot = result.Teapot( | ||||
| def getTeapotConfig(repo_conf: Repo, task_conf: Task) -> TeapotConfig: | ||||
|     teapot = TeapotConfig( | ||||
|         # TODO: fix the log path | ||||
|         log_path=f"{task_conf.task.replace(' ', '-')}-joint-teapot-debug.log", | ||||
|         scoreboard_path=f"{task_conf.task.replace(' ', '-')}-scoreboard.csv", | ||||
|  | @ -22,7 +44,7 @@ def getTeapotConfig(repo_conf: repo.Config, task_conf: task.Config) -> result.Te | |||
|     return teapot | ||||
| 
 | ||||
| 
 | ||||
| def getHealthcheckCmd(repo_conf: repo.Config) -> result.Cmd: | ||||
| def getHealthcheckCmd(repo_conf: Repo) -> Cmd: | ||||
|     repoSize = repo_conf.max_size | ||||
|     immutable = repo_conf.files.immutable | ||||
|     repo_size = f"-repoSize={str(repoSize)} " | ||||
|  | @ -38,7 +60,7 @@ def getHealthcheckCmd(repo_conf: repo.Config) -> result.Cmd: | |||
|         else: | ||||
|             immutable_files = immutable_files + name + "," | ||||
|     # FIXME: need to make solution and make things easier to edit with global scope | ||||
|     chore = f"./repo-health-checker -root=. " | ||||
|     chore = f"/{get_temp_directory}/repo-health-checker -root=. " | ||||
|     args = "" | ||||
|     args = args + chore | ||||
|     args = args + repo_size | ||||
|  | @ -49,25 +71,27 @@ def getHealthcheckCmd(repo_conf: repo.Config) -> result.Cmd: | |||
| 
 | ||||
|     args = args + immutable_files | ||||
| 
 | ||||
|     cmd = result.Cmd( | ||||
|         args=shlex.split(args), | ||||
|     cmd = Cmd( | ||||
|         args=args.split(), | ||||
|         # FIXME: easier to edit within global scope | ||||
|         copy_in={ | ||||
|             f"./repo-health-checker": result.CmdFile(src=f"./repo-health-checker") | ||||
|             f"/{get_temp_directory()}/repo-health-checker": CmdFile( | ||||
|                 src=f"/{get_temp_directory()}/repo-health-checker" | ||||
|             ) | ||||
|         }, | ||||
|     ) | ||||
|     return cmd | ||||
| 
 | ||||
| 
 | ||||
| def getHealthcheckConfig(repo_conf: repo.Config) -> result.StageDetail: | ||||
|     healthcheck_stage = result.StageDetail( | ||||
| def getHealthcheckConfig(repo_conf: Repo, task_conf: Task) -> Stage: | ||||
|     healthcheck_stage = Stage( | ||||
|         name="healthcheck", | ||||
|         group="", | ||||
|         executor=result.Executor( | ||||
|         executor=ExecutorConfig( | ||||
|             name="sandbox", | ||||
|             with_=result.ExecutorWith(default=getHealthcheckCmd(repo_conf), cases=[]), | ||||
|             with_=ExecutorWithConfig(default=getHealthcheckCmd(repo_conf), cases=[]), | ||||
|         ), | ||||
|         parsers=[result.Parser(name="healthcheck", with_={"score": 0, "comment": ""})], | ||||
|         parsers=[ParserConfig(name="healthcheck", with_={"score": 0, "comment": ""})], | ||||
|     ) | ||||
|     return healthcheck_stage | ||||
| 
 | ||||
|  | @ -81,10 +105,7 @@ def calc_sha256sum(file_path: str) -> str: | |||
| 
 | ||||
| 
 | ||||
| def get_hash(immutable_files: list[str]) -> str:  # input should be a list | ||||
|     # FIXME: should be finalized when get into the server | ||||
|     current_file_path = Path(__file__).resolve() | ||||
|     project_root = current_file_path.parents[2] | ||||
|     file_path = f"{project_root}/tests/immutable_file/" | ||||
|     file_path = "../immutable_file/"  # TODO: change this when things are on the server | ||||
|     immutable_hash = [] | ||||
|     for i, file in enumerate(immutable_files): | ||||
|         immutable_files[i] = file_path + file.rsplit("/", 1)[-1] | ||||
|  |  | |||
|  | @ -14,31 +14,17 @@ class ParserResultDetail(BaseModel): | |||
| 
 | ||||
| class ParserDummy(BaseModel): | ||||
|     comment: Optional[str] = "" | ||||
|     score: Optional[int] = 0 | ||||
|     forcequit: Optional[bool] = True | ||||
| 
 | ||||
| 
 | ||||
| class ParserKeyword(BaseModel): | ||||
|     keyword: Optional[list[str]] = [] | ||||
|     weight: Optional[list[int]] = [] | ||||
| 
 | ||||
| 
 | ||||
| class Outputs(BaseModel): | ||||
|     score: Optional[int] = 0 | ||||
|     ignorespaces: Optional[bool] = False | ||||
|     hide: Optional[bool] = False | ||||
|     forcequit: Optional[bool] = True | ||||
| 
 | ||||
| 
 | ||||
| class ParserDiff(BaseModel): | ||||
|     output: Optional[Outputs] = Outputs() | ||||
|     keyword: Optional[list[str]] = None | ||||
|     weight: Optional[list[int]] = None | ||||
| 
 | ||||
| 
 | ||||
| class Files(BaseModel): | ||||
|     import_: Optional[List[str]] = Field( | ||||
|         [], serialization_alias="import", validation_alias="import" | ||||
|     ) | ||||
|     export: Optional[List[str]] = [] | ||||
|     import_: Optional[List[str]] = Field(serialization_alias="import", validation_alias="import") | ||||
|     export: Optional[List[str]] | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| class Limit(BaseModel): | ||||
|  | @ -49,36 +35,20 @@ class Limit(BaseModel): | |||
| 
 | ||||
| 
 | ||||
| class Stage(BaseModel): | ||||
|     name: Optional[str] = None  # Stage name | ||||
|     command: Optional[str] = None  # Command to run | ||||
|     name: str  # Stage name | ||||
|     command: str  # Command to run | ||||
|     files: Optional[Files] = None | ||||
|     score: Optional[int] = 0 | ||||
|     parsers: Optional[list[str]] = []  # list of parsers | ||||
|     limit: Optional[Limit] = Limit() | ||||
|     parsers: list[str]  # list of parsers | ||||
|     limit: Optional[Limit] = None | ||||
|     dummy: Optional[ParserDummy] = ParserDummy() | ||||
|     result_status: Optional[ParserDummy] = Field(ParserDummy(), alias="result-status") | ||||
|     keyword: Optional[ParserKeyword] = ParserKeyword() | ||||
|     clangtidy: Optional[ParserKeyword] = ParserKeyword() | ||||
|     cppcheck: Optional[ParserKeyword] = ParserKeyword() | ||||
|     # FIXME: determine cpplint type | ||||
|     cpplint: Optional[ParserKeyword] = ParserKeyword() | ||||
|     result_detail: Optional[ParserResultDetail] = Field( | ||||
|         ParserResultDetail(), alias="result-detail" | ||||
|     ) | ||||
|     skip: Optional[list[str]] = [] | ||||
|     diff: Optional[ParserDiff] = ParserDiff() | ||||
|     cases: Optional[Dict[str, "Stage"]] = {} | ||||
| 
 | ||||
|     class Config: | ||||
|         extra = "allow" | ||||
| 
 | ||||
|     @root_validator(pre=True) | ||||
|     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: Stage(**v) for k, v in cases.items()} | ||||
|         return values | ||||
| 
 | ||||
| 
 | ||||
| class Release(BaseModel): | ||||
|  |  | |||
|  | @ -6,5 +6,5 @@ sandbox_token = "test" | |||
| [files] | ||||
| whitelist_patterns = ["*.py", "*.txt", "*.md"] | ||||
| whitelist_file = ".whitelist" | ||||
| required = [ "Changelog.md", "Readme.md" ] | ||||
| immutable = [".gitignore", ".gitattributes", ".gitea/workflows/push.yaml", ".gitea/workflows/release.yaml" ] | ||||
| required = ["main.py", "README.md"] | ||||
| immutable = [".gitignore", ".gitattributes", "push.yaml", "release.yaml"] | ||||
|  |  | |||
|  | @ -1,31 +1,20 @@ | |||
| # p2 repo config | ||||
| 
 | ||||
| task="p2 m3" # task name | ||||
| # general task configuration | ||||
| task="Homework 1 exercise 2" # task name | ||||
| 
 | ||||
| release.deadline = 2024-10-12 23:59:00+08:00 | ||||
| release.stages = [ "compile" ] | ||||
| 
 | ||||
| [files] | ||||
| immutable = [".gitignore", ".gitattributes", ".gitea/workflows/push.yaml", ".gitea/workflows/release.yaml" ] | ||||
| required = [ "Changelog.md", "Readme.md" ] | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "Abuse of strings detected" | ||||
| command = "./strdetect src/" | ||||
| files.import = [ "tools/strdetec" ] | ||||
| 
 | ||||
| parsers = [ "result-status" ] | ||||
| 
 | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "Compilation" | ||||
| command = "compile" | ||||
| files.import = [ "tools/compile" ] | ||||
| files.export = [ "build/onecard", "build/asan", "build/ubsan", "build/msan", "build/compile_commands.json" ] | ||||
| command = "make.sh" # eg. script running cmake commands | ||||
| files.import = [ "tools/make.sh", "src/main.c", "src/task.h", "srcCMakelist.txt" ] | ||||
| files.export = [ "driver", "p2", "p2-msan" ] | ||||
| limit.cpu = 180 # p2 takes long to compile | ||||
| limit.stderr = 128 | ||||
| 
 | ||||
| # compile parsers | ||||
| parsers = [ "result-detail", "dummy", "result-status" ] | ||||
| result-status.comment = "Congratulations! Your code compiled successfully." | ||||
| result-status.score = 1 | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
|  | @ -33,28 +22,26 @@ result-detail.time = false | |||
| result-detail.mem = false | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[cq] Filelength" | ||||
| command = "./file-length 400 300 *.c *.h" | ||||
| files.import = [ "tools/filelength" ] | ||||
| name = "File length check" | ||||
| command = "./file-length 500 400 *.c *.h"  # command to run | ||||
| files.import = [ "tools/file-length" ] | ||||
| 
 | ||||
| parsers = [ "keyword", "dummy", "result-detail" ] | ||||
| keyword.keyword = [ "max", "recommended"] | ||||
| keyword.weight = [ 20, 10 ] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stdout = true | ||||
| keyword.keyword = [ "max", "recommend"] # keywords caught by corresponding JOJ plugin | ||||
| keyword.weight = [ 50, 20 ] # weight of each keyword | ||||
| result-detail.exitstatus = false | ||||
| result-detail.stderr = true | ||||
| result-detail.time = false | ||||
| result-detail.mem = false | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[cq] Clang-tidy" | ||||
| name = "Clang-tidy checks" | ||||
| command = "run-clang-tidy-18 -header-filter=.* -quiet -load=/usr/local/lib/libcodequality.so -p build" | ||||
| files.import = [ "projects/p2/.clang-tidy", "build/compile_commands.json" ] | ||||
| limit.stdout = 65 | ||||
| 
 | ||||
| parsers = [ "clangtidy", "dummy", "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] | ||||
| clangtidy.keyword = [ "codequality-no-global-variables", "codequality-no-header-guard", "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" ] | ||||
| clangtidy.weight = [10, 10, 50, 10, 5, 5, 10, 5, 5, 8, 5, 5, 5, 5, 8] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stdout = true | ||||
|  | @ -62,13 +49,13 @@ 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 ./" | ||||
| name = "Cppcheck check" | ||||
| command = "cppcheck --template='{\"file\":\"{file}\",\"line\":{line}, \"column\":{column}, \"severity\":\"{severity}\", \"message\":\"{message}\", \"id\":\"{id}\"}' --force --enable=all --quiet ./" | ||||
| limit.stderr = 65 | ||||
| 
 | ||||
| parsers = [ "cppcheck", "dummy", "result-detail" ] | ||||
| cppcheck.keyword = ["error", "warning", "portability", "performance", "style"] | ||||
| cppcheck.weight = [15, 5, 5, 5, 5] | ||||
| cppcheck.weight = [20, 10, 15, 15, 10] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
|  | @ -76,62 +63,57 @@ result-detail.time = false | |||
| result-detail.mem = false | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[cq] Cpplint" | ||||
| name = "Cpplint check" | ||||
| command = "cpplint --linelength=120 --filter=-legal,-readability/casting,-whitespace,-runtime/printf,-runtime/threadsafe_fn,-readability/todo,-build/include_subdir,-build/header_guard --recursive --exclude=build ." | ||||
| 
					
					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 | ||||
| limit.stdout = 65 | ||||
| 
 | ||||
| parsers = [ "cpplint", "dummy", "result-detail" ] | ||||
| cpplint.keyword = [ "runtime", "readability", "build" ] | ||||
| cpplint.weight = [ 5, 20, 10] | ||||
| cpplint.weight = [ 10, 20, 15] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
| result-detail.stdout = true | ||||
| result-detail.time = false | ||||
| result-detail.mem = false | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[run] onecard" | ||||
| group = "run" | ||||
| command="./onecard -a" | ||||
| files.import = [ "build/onecard" ] | ||||
| name = "judge-base" | ||||
| command="./driver ./mumsh" | ||||
| limit.cpu = 3 | ||||
| limit.mem = 75 | ||||
| score = 10 | ||||
| 
 | ||||
| parsers = [ "result-status", "result-detail" ] | ||||
| result-status.score = 1 | ||||
| result-status.forcequit = false | ||||
| parsers = ["diff", "dummy", "result-detail"] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
| 
 | ||||
| case4.score = 15 | ||||
| case4.limit.cpu = 30 | ||||
| case4.limit.mem = 10 | ||||
| case4.limit.stdout = 8 | ||||
| 
 | ||||
| case5.score = 25 | ||||
| 
 | ||||
| case8.limit.stderr = 128 | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[run] address sanitizer" | ||||
| group = "run" | ||||
| command="./asan -a" | ||||
| files.import = [ "build/asan" ] | ||||
| name = "judge-msan" | ||||
| command="./driver ./mumsh-msan" | ||||
| limit.cpu = 10 # default cpu limit (in sec) for each test case | ||||
| limit.mem = 500 # set default mem limit (in MB) for all OJ test cases | ||||
| score = 10 | ||||
| skip = ["case0", "case11"] | ||||
| 
 | ||||
| parsers = [ "result-status", "result-detail" ] | ||||
| result-status.score = 1 | ||||
| result-status.forcequit = false | ||||
| parsers = ["diff", "dummy", "result-detail"] | ||||
| dummy.comment = "\n\n### Details\n" | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[run] memory sanitizer" | ||||
| group = "run" | ||||
| command="./msan -a" | ||||
| files.import = [ "build/msan" ] | ||||
| case4.score = 15 | ||||
| case4.limit.cpu = 30 | ||||
| case4.limit.mem = 10 | ||||
| 
 | ||||
| parsers = [ "result-status", "result-detail" ] | ||||
| result-status.score = 1 | ||||
| result-status.forcequit = false | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
| case5.diff.output.ignorespaces = false | ||||
| 
 | ||||
| [[stages]] | ||||
| name = "[run] undefined behavior sanitizer" | ||||
| command="./ubsan -a" | ||||
| files.import = [ "build/ubsan" ] | ||||
| 
 | ||||
| parsers = [ "result-status", "result-detail" ] | ||||
| result-status.score = 1 | ||||
| result-status.forcequit = false | ||||
| result-detail.exitstatus = true | ||||
| result-detail.stderr = true | ||||
| case6.diff.output.hide = true | ||||
|  |  | |||
Make this
Path.home()default to/home/tt. For now, create a const for this dir.fixed