From ab956f56627d94195f4b5c9e5a81505c44c2d17b Mon Sep 17 00:00:00 2001 From: Boming Zhang Date: Mon, 4 Mar 2024 02:59:01 -0500 Subject: [PATCH] feat: diff parser with example --- README.md | 31 +++++++++++----------- _example/simple/1.stdin | 1 + _example/simple/1.stdout | 1 + _example/simple/conf.toml | 6 ++--- internal/executors/sandbox/convert.go | 12 +++++++++ internal/executors/sandbox/executor.go | 10 +++++++ internal/parsers/all.go | 1 + internal/parsers/diff/meta.go | 9 +++++++ internal/parsers/diff/parser.go | 36 ++++++++++++++++++++++++++ internal/parsers/dummy/parser.go | 6 +---- internal/stage/util.go | 12 +++++++++ 11 files changed, 102 insertions(+), 23 deletions(-) create mode 100644 _example/simple/1.stdin create mode 100644 _example/simple/1.stdout create mode 100644 internal/parsers/diff/meta.go create mode 100644 internal/parsers/diff/parser.go create mode 100644 internal/stage/util.go diff --git a/README.md b/README.md index 07c3dbd..ccc301d 100644 --- a/README.md +++ b/README.md @@ -13,20 +13,20 @@ go build -o ./build/joj3 ./cmd/joj3 + DIRNAME=./_example/simple + cd ./_example/simple + ./../../build/joj3 -2024/03/04 02:09:42 INFO stage start name=compile -2024/03/04 02:09:42 INFO sandbox run cmd="{Args:[/usr/bin/g++ a.cc -o a] Env:[PATH=/usr/bin:/bin] Files:[0xc00007f540 0xc00007f580 0xc00007f5c0] CPULimit:10000000000 RealCPULimit:0 ClockLimit:0 MemoryLimit:104857600 StackLimit:0 ProcLimit:50 CPURateLimit:0 CPUSetLimit: CopyIn:map[] CopyInCached:map[] CopyInCwd:true CopyOut:[stdout stderr] CopyOutCached:[a] CopyOutMax:0 CopyOutDir: TTY:false StrictMemoryLimit:false DataSegmentLimit:false AddressSpaceLimit:false}" -2024/03/04 02:09:42 INFO sandbox run copyInCwd=true -2024/03/04 02:09:42 INFO sandbox run ret="results:{status:Accepted time:321003000 runTime:321988110 memory:57888768 files:{key:\"stderr\" value:\"\"} files:{key:\"stdout\" value:\"\"} fileIDs:{key:\"a\" value:\"T6BQPS5B\"}}" -2024/03/04 02:09:42 INFO executor done result="{Status:Accepted ExitStatus:0 Error: Time:321.003ms RunTime:321.98811ms Memory:55.2 MiB Files:map[stderr:len:0 stdout:len:0] FileIDs:map[a:T6BQPS5B] FileError:[]}" -2024/03/04 02:09:42 INFO parser done result="&{Score:100 Comment:compile done, executor status: run time: 321988110 ns, memory: 57888768 bytes}" -2024/03/04 02:09:42 INFO stage start name=run -2024/03/04 02:09:42 INFO sandbox run cmd="{Args:[./a] Env:[PATH=/usr/bin:/bin] Files:[0xc00007f600 0xc00007f640 0xc00007f680] CPULimit:10000000000 RealCPULimit:0 ClockLimit:0 MemoryLimit:104857600 StackLimit:0 ProcLimit:50 CPURateLimit:0 CPUSetLimit: CopyIn:map[] CopyInCached:map[a:a] CopyInCwd:false CopyOut:[stdout stderr] CopyOutCached:[] CopyOutMax:0 CopyOutDir: TTY:false StrictMemoryLimit:false DataSegmentLimit:false AddressSpaceLimit:false}" -2024/03/04 02:09:42 INFO sandbox run ret="results:{status:Accepted time:1446000 runTime:2284978 memory:15384576 files:{key:\"stderr\" value:\"\"} files:{key:\"stdout\" value:\"2\\n\"}}" -2024/03/04 02:09:42 INFO executor done result="{Status:Accepted ExitStatus:0 Error: Time:1.446ms RunTime:2.284978ms Memory:14.7 MiB Files:map[stderr:len:0 stdout:len:2] FileIDs:map[] FileError:[]}" -2024/03/04 02:09:42 INFO parser done result="&{Score:100 Comment:run done, executor status: run time: 2284978 ns, memory: 15384576 bytes}" -2024/03/04 02:09:42 INFO stage result name=compile score=100 comment="compile done, executor status: run time: 321988110 ns, memory: 57888768 bytes" -2024/03/04 02:09:42 INFO stage result name=run score=100 comment="run done, executor status: run time: 2284978 ns, memory: 15384576 bytes" -2024/03/04 02:09:42 INFO sandbox cleanup +2024/03/04 02:57:50 INFO stage start name=compile +2024/03/04 02:57:50 INFO sandbox run cmd="{Args:[/usr/bin/g++ a.cc -o a] Env:[PATH=/usr/bin:/bin] Files:[0xc00007f540 0xc00007f580 0xc00007f5c0] CPULimit:10000000000 RealCPULimit:0 ClockLimit:0 MemoryLimit:104857600 StackLimit:0 ProcLimit:50 CPURateLimit:0 CPUSetLimit: CopyIn:map[] CopyInCached:map[] CopyInCwd:true CopyOut:[stdout stderr] CopyOutCached:[a] CopyOutMax:0 CopyOutDir: TTY:false StrictMemoryLimit:false DataSegmentLimit:false AddressSpaceLimit:false}" +2024/03/04 02:57:50 INFO sandbox run copyInCwd=true +2024/03/04 02:57:50 INFO sandbox run ret="results:{status:Accepted time:298002000 runTime:298694146 memory:57880576 files:{key:\"stderr\" value:\"\"} files:{key:\"stdout\" value:\"\"} fileIDs:{key:\"a\" value:\"DMTRJR3V\"}}" +2024/03/04 02:57:50 INFO executor done result="{Status:Accepted ExitStatus:0 Error: Time:298.002ms RunTime:298.694146ms Memory:55.2 MiB Files:map[stderr:len:0 stdout:len:0] FileIDs:map[a:DMTRJR3V] FileError:[]}" +2024/03/04 02:57:50 INFO parser done result="&{Score:100 Comment:compile done, executor status: run time: 298694146 ns, memory: 57880576 bytes}" +2024/03/04 02:57:50 INFO stage start name=run +2024/03/04 02:57:50 INFO sandbox run cmd="{Args:[./a] Env:[PATH=/usr/bin:/bin] Files:[0xc00007f600 0xc00007f640 0xc00007f680] CPULimit:10000000000 RealCPULimit:0 ClockLimit:0 MemoryLimit:104857600 StackLimit:0 ProcLimit:50 CPURateLimit:0 CPUSetLimit: CopyIn:map[] CopyInCached:map[a:a] CopyInCwd:false CopyOut:[stdout stderr] CopyOutCached:[] CopyOutMax:0 CopyOutDir: TTY:false StrictMemoryLimit:false DataSegmentLimit:false AddressSpaceLimit:false}" +2024/03/04 02:57:50 INFO sandbox run ret="results:{status:Accepted time:1122000 runTime:1723994 memory:15384576 files:{key:\"stderr\" value:\"\"} files:{key:\"stdout\" value:\"2\\n\"}}" +2024/03/04 02:57:50 INFO executor done result="{Status:Accepted ExitStatus:0 Error: Time:1.122ms RunTime:1.723994ms Memory:14.7 MiB Files:map[stderr:len:0 stdout:len:2] FileIDs:map[] FileError:[]}" +2024/03/04 02:57:50 INFO parser done result="&{Score:100 Comment:}" +2024/03/04 02:57:50 INFO stage result name=compile score=100 comment="compile done, executor status: run time: 298694146 ns, memory: 57880576 bytes" +2024/03/04 02:57:50 INFO stage result name=run score=100 comment="" +2024/03/04 02:57:50 INFO sandbox cleanup + cd - ``` @@ -44,10 +44,11 @@ Parser takes a `ExecutorResult` and its config and returns a `ParserResult`. Check `Cmd` in . -Some extra fields: +Some difference: - `CopyInCwd bool`: set to `true` to add everything in the current working directory to `CopyIn`. - `CopyInCached map[string]string`: key: file name in sandbox, value: file name used in `CopyOutCached`. +- `LocalFile`: now support relative path ### `ExecutorResult` diff --git a/_example/simple/1.stdin b/_example/simple/1.stdin new file mode 100644 index 0000000..2fb73a0 --- /dev/null +++ b/_example/simple/1.stdin @@ -0,0 +1 @@ +1 1 diff --git a/_example/simple/1.stdout b/_example/simple/1.stdout new file mode 100644 index 0000000..0cfbf08 --- /dev/null +++ b/_example/simple/1.stdout @@ -0,0 +1 @@ +2 diff --git a/_example/simple/conf.toml b/_example/simple/conf.toml index a5ed250..d7515a3 100644 --- a/_example/simple/conf.toml +++ b/_example/simple/conf.toml @@ -38,7 +38,7 @@ copyOut = ["stdout", "stderr"] [stages.executor.with.copyInCached] a = "a" [[stages.executor.with.files]] -content = "1 1" +src = "1.stdin" [[stages.executor.with.files]] name = "stdout" max = 4_096 @@ -46,7 +46,7 @@ max = 4_096 name = "stderr" max = 4_096 [stages.parser] -name = "dummy" +name = "diff" [stages.parser.with] score = 100 -comment = "run done" +stdoutPath = "1.stdout" diff --git a/internal/executors/sandbox/convert.go b/internal/executors/sandbox/convert.go index 77a9247..1b1a1b8 100644 --- a/internal/executors/sandbox/convert.go +++ b/internal/executors/sandbox/convert.go @@ -1,6 +1,7 @@ package sandbox import ( + "path/filepath" "strings" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" @@ -143,3 +144,14 @@ func convertPBFileError(fe []*pb.Response_FileError) []stage.FileError { } return ret } + +func convertAbsPath(cmdFile *stage.CmdFile) error { + if cmdFile.Src != nil && !filepath.IsAbs(*cmdFile.Src) { + absPath, err := filepath.Abs(*cmdFile.Src) + if err != nil { + return err + } + cmdFile.Src = &absPath + } + return nil +} diff --git a/internal/executors/sandbox/executor.go b/internal/executors/sandbox/executor.go index 81d18da..3bed920 100644 --- a/internal/executors/sandbox/executor.go +++ b/internal/executors/sandbox/executor.go @@ -46,6 +46,16 @@ func (e *Sandbox) Run(cmd stage.Cmd) (*stage.ExecutorResult, error) { return nil, err } } + for _, file := range cmd.Files { + if err := convertAbsPath(file); err != nil { + return nil, err + } + } + for _, file := range cmd.CopyIn { + if err := convertAbsPath(&file); err != nil { + return nil, err + } + } req := &pb.Request{Cmd: convertPBCmd([]stage.Cmd{cmd})} ret, err := e.execClient.Exec(context.TODO(), req) if err != nil { diff --git a/internal/parsers/all.go b/internal/parsers/all.go index 5ee6a62..4319ac6 100644 --- a/internal/parsers/all.go +++ b/internal/parsers/all.go @@ -1,6 +1,7 @@ package parsers import ( + _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/diff" _ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy" ) diff --git a/internal/parsers/diff/meta.go b/internal/parsers/diff/meta.go new file mode 100644 index 0000000..5cb8b82 --- /dev/null +++ b/internal/parsers/diff/meta.go @@ -0,0 +1,9 @@ +package diff + +import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" + +var name = "diff" + +func init() { + stage.RegisterParser(name, &Diff{}) +} diff --git a/internal/parsers/diff/parser.go b/internal/parsers/diff/parser.go new file mode 100644 index 0000000..9610e6c --- /dev/null +++ b/internal/parsers/diff/parser.go @@ -0,0 +1,36 @@ +package diff + +import ( + "os" + + "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" +) + +type Config struct { + Score int + StdoutPath string +} + +type Diff struct{} + +func (e *Diff) Run(result *stage.ExecutorResult, configAny any) ( + *stage.ParserResult, error, +) { + config, err := stage.DecodeConfig[Config](configAny) + if err != nil { + return nil, err + } + score := 0 + stdout, err := os.ReadFile(config.StdoutPath) + if err != nil { + return nil, err + } + // TODO: more compare strategies + if string(stdout) == result.Files["stdout"] { + score = config.Score + } + return &stage.ParserResult{ + Score: score, + Comment: "", + }, nil +} diff --git a/internal/parsers/dummy/parser.go b/internal/parsers/dummy/parser.go index 00bacb3..daa15a2 100644 --- a/internal/parsers/dummy/parser.go +++ b/internal/parsers/dummy/parser.go @@ -2,10 +2,8 @@ package dummy import ( "fmt" - "log/slog" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" - "github.com/mitchellh/mapstructure" ) type Config struct { @@ -18,10 +16,8 @@ type Dummy struct{} func (e *Dummy) Run(result *stage.ExecutorResult, configAny any) ( *stage.ParserResult, error, ) { - var config Config - err := mapstructure.Decode(configAny, &config) + config, err := stage.DecodeConfig[Config](configAny) if err != nil { - slog.Error("failed to decode config", "err", err) return nil, err } return &stage.ParserResult{ diff --git a/internal/stage/util.go b/internal/stage/util.go new file mode 100644 index 0000000..0825f8f --- /dev/null +++ b/internal/stage/util.go @@ -0,0 +1,12 @@ +package stage + +import "github.com/mitchellh/mapstructure" + +func DecodeConfig[T any](configAny any) (*T, error) { + var config T + err := mapstructure.Decode(configAny, &config) + if err != nil { + return nil, err + } + return &config, nil +}