feat: diff parser with example

This commit is contained in:
张泊明518370910136 2024-03-04 02:59:01 -05:00
parent a3deb3d974
commit ab956f5662
GPG Key ID: D47306D7062CDA9D
11 changed files with 102 additions and 23 deletions

View File

@ -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 <https://github.com/criyle/go-judge#rest-api-interface>.
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`

1
_example/simple/1.stdin Normal file
View File

@ -0,0 +1 @@
1 1

1
_example/simple/1.stdout Normal file
View File

@ -0,0 +1 @@
2

View File

@ -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"

View File

@ -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
}

View File

@ -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 {

View File

@ -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"
)

View File

@ -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{})
}

View File

@ -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
}

View File

@ -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{

12
internal/stage/util.go Normal file
View File

@ -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
}