feat: diff parser with example
This commit is contained in:
		
							parent
							
								
									a3deb3d974
								
							
						
					
					
						commit
						ab956f5662
					
				
							
								
								
									
										31
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								README.md
									
									
									
									
									
								
							|  | @ -13,20 +13,20 @@ go build -o ./build/joj3 ./cmd/joj3 | ||||||
| + DIRNAME=./_example/simple | + DIRNAME=./_example/simple | ||||||
| + cd ./_example/simple | + cd ./_example/simple | ||||||
| + ./../../build/joj3 | + ./../../build/joj3 | ||||||
| 2024/03/04 02:09:42 INFO stage start name=compile | 2024/03/04 02:57:50 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: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:09:42 INFO sandbox run copyInCwd=true | 2024/03/04 02:57:50 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: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: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: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:09:42 INFO parser done result="&{Score:100 Comment:compile done, executor status: run time: 321988110 ns, memory: 57888768 bytes}" | 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:09:42 INFO stage start name=run | 2024/03/04 02:57:50 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: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: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: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: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: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:09:42 INFO parser done result="&{Score:100 Comment:run done, executor status: run time: 2284978 ns, memory: 15384576 bytes}" | 2024/03/04 02:57:50 INFO parser done result="&{Score:100 Comment:}" | ||||||
| 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: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: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:57:50 INFO stage result name=run score=100 comment="" | ||||||
| 2024/03/04 02:09:42 INFO sandbox cleanup | 2024/03/04 02:57:50 INFO sandbox cleanup | ||||||
| + cd - | + 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>. | 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`. | -   `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`. | -   `CopyInCached map[string]string`: key: file name in sandbox, value: file name used in `CopyOutCached`. | ||||||
|  | -   `LocalFile`: now support relative path | ||||||
| 
 | 
 | ||||||
| ### `ExecutorResult` | ### `ExecutorResult` | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								_example/simple/1.stdin
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								_example/simple/1.stdin
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | 1 1 | ||||||
							
								
								
									
										1
									
								
								_example/simple/1.stdout
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								_example/simple/1.stdout
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | ||||||
|  | 2 | ||||||
|  | @ -38,7 +38,7 @@ copyOut = ["stdout", "stderr"] | ||||||
| [stages.executor.with.copyInCached] | [stages.executor.with.copyInCached] | ||||||
| a = "a" | a = "a" | ||||||
| [[stages.executor.with.files]] | [[stages.executor.with.files]] | ||||||
| content = "1 1" | src = "1.stdin" | ||||||
| [[stages.executor.with.files]] | [[stages.executor.with.files]] | ||||||
| name = "stdout" | name = "stdout" | ||||||
| max = 4_096 | max = 4_096 | ||||||
|  | @ -46,7 +46,7 @@ max = 4_096 | ||||||
| name = "stderr" | name = "stderr" | ||||||
| max = 4_096 | max = 4_096 | ||||||
| [stages.parser] | [stages.parser] | ||||||
| name = "dummy" | name = "diff" | ||||||
| [stages.parser.with] | [stages.parser.with] | ||||||
| score = 100 | score = 100 | ||||||
| comment = "run done" | stdoutPath = "1.stdout" | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package sandbox | package sandbox | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"path/filepath" | ||||||
| 	"strings" | 	"strings" | ||||||
| 
 | 
 | ||||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | 	"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 | 	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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -46,6 +46,16 @@ func (e *Sandbox) Run(cmd stage.Cmd) (*stage.ExecutorResult, error) { | ||||||
| 			return nil, err | 			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})} | 	req := &pb.Request{Cmd: convertPBCmd([]stage.Cmd{cmd})} | ||||||
| 	ret, err := e.execClient.Exec(context.TODO(), req) | 	ret, err := e.execClient.Exec(context.TODO(), req) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package parsers | package parsers | ||||||
| 
 | 
 | ||||||
| import ( | 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" | 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								internal/parsers/diff/meta.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/parsers/diff/meta.go
									
									
									
									
									
										Normal 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{}) | ||||||
|  | } | ||||||
							
								
								
									
										36
									
								
								internal/parsers/diff/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								internal/parsers/diff/parser.go
									
									
									
									
									
										Normal 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 | ||||||
|  | } | ||||||
|  | @ -2,10 +2,8 @@ package dummy | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"log/slog" |  | ||||||
| 
 | 
 | ||||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||||
| 	"github.com/mitchellh/mapstructure" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type Config struct { | type Config struct { | ||||||
|  | @ -18,10 +16,8 @@ type Dummy struct{} | ||||||
| func (e *Dummy) Run(result *stage.ExecutorResult, configAny any) ( | func (e *Dummy) Run(result *stage.ExecutorResult, configAny any) ( | ||||||
| 	*stage.ParserResult, error, | 	*stage.ParserResult, error, | ||||||
| ) { | ) { | ||||||
| 	var config Config | 	config, err := stage.DecodeConfig[Config](configAny) | ||||||
| 	err := mapstructure.Decode(configAny, &config) |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		slog.Error("failed to decode config", "err", err) |  | ||||||
| 		return nil, err | 		return nil, err | ||||||
| 	} | 	} | ||||||
| 	return &stage.ParserResult{ | 	return &stage.ParserResult{ | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								internal/stage/util.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								internal/stage/util.go
									
									
									
									
									
										Normal 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 | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user