feat: basic framework
This commit is contained in:
		
							parent
							
								
									262e253f26
								
							
						
					
					
						commit
						df62496537
					
				
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							|  | @ -1,9 +1,10 @@ | |||
| .PHONY: all clean | ||||
| 
 | ||||
| BUILD_DIR = ./build | ||||
| APP_NAME = joj3 | ||||
| 
 | ||||
| all: | ||||
| 	go build -o $(BUILD_DIR)/tiger ./cmd/tiger | ||||
| 	go build -o $(BUILD_DIR)/$(APP_NAME) ./cmd/$(APP_NAME) | ||||
| 
 | ||||
| clean: | ||||
| 	rm -rf $(BUILD_DIR)/* | ||||
|  |  | |||
							
								
								
									
										18
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								README.md
									
									
									
									
									
								
							|  | @ -1,20 +1,10 @@ | |||
| # JOJ3 | ||||
| 
 | ||||
| ## Try `tiger` | ||||
| 
 | ||||
| ```bash | ||||
| $ make clean && make && sudo ./build/tiger python3 -c 'bytearray(1024 * 1024); 10 ** 10 ** 3; print("out"); import sys; print("err", file=sys.stderr)' | ||||
| $ make clean && make && ./build/joj3 | ||||
| rm -rf ./build/* | ||||
| rm -rf *.out | ||||
| go build -o ./build/tiger ./cmd/tiger | ||||
| 2024/03/01 01:25:34 INFO process created pid=3148763 | ||||
| 2024/03/01 01:25:34 INFO done success time=16.80708ms | ||||
| ReturnCode: 0 | ||||
| Stdout: out | ||||
| 
 | ||||
| Stderr: err | ||||
| 
 | ||||
| TimedOut: false | ||||
| TimeNs: 0 | ||||
| MemoryByte: 0 | ||||
| go build -o ./build/joj3 ./cmd/joj3 | ||||
| dummy stage 0: score: 0, comment: I'm a dummy | ||||
| dummy stage 1: score: 0, comment: I'm a dummy | ||||
| ``` | ||||
|  |  | |||
							
								
								
									
										20
									
								
								cmd/joj3/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								cmd/joj3/main.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/executors" | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers" | ||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	stages := stage.ParseStages() | ||||
| 	results := stage.Run(stages) | ||||
| 	for _, result := range results { | ||||
| 		fmt.Printf( | ||||
| 			"%s: score: %d, comment: %s\n", | ||||
| 			result.Name, result.Score, result.Comment, | ||||
| 		) | ||||
| 	} | ||||
| } | ||||
|  | @ -1,26 +0,0 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 
 | ||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/pkg/runner" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| 	if len(os.Args) < 2 { | ||||
| 		fmt.Println("usage: " + os.Args[0] + " <command>") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	// hard limit of timeout 1000ms
 | ||||
| 	runResult, err := runner.RunInCgroupsV1(os.Args[1:], "nobody", "/joj3.tiger", 1000) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error: %v\n", err) | ||||
| 	} | ||||
| 	fmt.Printf("ReturnCode: %d\n", runResult.ReturnCode) | ||||
| 	fmt.Printf("Stdout: %s\n", runResult.Stdout) | ||||
| 	fmt.Printf("Stderr: %s\n", runResult.Stderr) | ||||
| 	fmt.Printf("TimedOut: %v\n", runResult.TimedOut) | ||||
| 	fmt.Printf("TimeNs: %v\n", runResult.TimeNs) | ||||
| 	fmt.Printf("MemoryByte: %v\n", runResult.MemoryByte) | ||||
| } | ||||
							
								
								
									
										14
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								go.mod
									
									
									
									
									
								
							|  | @ -2,15 +2,11 @@ module focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3 | |||
| 
 | ||||
| go 1.22.0 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/containerd/cgroups v1.1.0 | ||||
| 	github.com/opencontainers/runtime-spec v1.2.0 | ||||
| ) | ||||
| require github.com/criyle/go-judge v1.8.1 | ||||
| 
 | ||||
| require ( | ||||
| 	github.com/coreos/go-systemd/v22 v22.3.2 // indirect | ||||
| 	github.com/docker/go-units v0.4.0 // indirect | ||||
| 	github.com/godbus/dbus/v5 v5.0.4 // indirect | ||||
| 	github.com/gogo/protobuf v1.3.2 // indirect | ||||
| 	golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 // indirect | ||||
| 	github.com/creack/pty v1.1.21 // indirect | ||||
| 	github.com/criyle/go-sandbox v0.10.1 // indirect | ||||
| 	golang.org/x/sync v0.6.0 // indirect | ||||
| 	golang.org/x/sys v0.16.0 // indirect | ||||
| ) | ||||
|  |  | |||
							
								
								
									
										53
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										53
									
								
								go.sum
									
									
									
									
									
								
							|  | @ -1,43 +1,10 @@ | |||
| github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= | ||||
| github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= | ||||
| github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI= | ||||
| github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= | ||||
| github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= | ||||
| github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= | ||||
| github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= | ||||
| github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= | ||||
| github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= | ||||
| github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= | ||||
| github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= | ||||
| github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= | ||||
| github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= | ||||
| github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= | ||||
| github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= | ||||
| golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||||
| golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= | ||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||
| golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= | ||||
| golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||||
| golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= | ||||
| golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||||
| golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||
| golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||||
| golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI= | ||||
| golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||
| golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= | ||||
| golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= | ||||
| golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= | ||||
| golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||
| github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= | ||||
| github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= | ||||
| github.com/criyle/go-judge v1.8.1 h1:VI9OGz1MnLp9cv//gMVL8uruNwxSod5UmNwew8ZnfCA= | ||||
| github.com/criyle/go-judge v1.8.1/go.mod h1:yZepeuMTmQXEJnBgHZQIGVuytRYWlLhQBQHLaL84N5w= | ||||
| github.com/criyle/go-sandbox v0.10.1 h1:z9Il/UXQwKEvIwdr1wVheWWWAqGWtdTItBmEsWqFqT4= | ||||
| github.com/criyle/go-sandbox v0.10.1/go.mod h1:ivPw/HEh5unxVRlXJxCgkgTCuy+cxTkQDX7D2XQf/kg= | ||||
| golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= | ||||
| golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||||
| golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= | ||||
| golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | ||||
|  |  | |||
							
								
								
									
										1
									
								
								internal/app/healthcheck/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								internal/app/healthcheck/main.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| package healthcheck | ||||
							
								
								
									
										8
									
								
								internal/executors/all.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								internal/executors/all.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| package executors | ||||
| 
 | ||||
| import ( | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/executors/dummy" | ||||
| ) | ||||
| 
 | ||||
| // this file does nothing but imports to ensure all the init() functions
 | ||||
| // in the subpackages are called
 | ||||
							
								
								
									
										21
									
								
								internal/executors/dummy/executor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								internal/executors/dummy/executor.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | |||
| package dummy | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/criyle/go-judge/cmd/go-judge/model" | ||||
| 	"github.com/criyle/go-judge/envexec" | ||||
| ) | ||||
| 
 | ||||
| type Dummy struct{} | ||||
| 
 | ||||
| func (e *Dummy) Run(model.Cmd) model.Result { | ||||
| 	return model.Result{ | ||||
| 		Status:     model.Status(envexec.StatusInvalid), | ||||
| 		ExitStatus: 0, | ||||
| 		Error:      "I'm a dummy", | ||||
| 		Time:       0, | ||||
| 		Memory:     0, | ||||
| 		RunTime:    0, | ||||
| 		Files:      map[string]string{}, | ||||
| 		FileIDs:    map[string]string{}, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										9
									
								
								internal/executors/dummy/meta.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/executors/dummy/meta.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| package dummy | ||||
| 
 | ||||
| import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| 
 | ||||
| var name = "dummy" | ||||
| 
 | ||||
| func init() { | ||||
| 	stage.RegisterExecutor(name, &Dummy{}) | ||||
| } | ||||
							
								
								
									
										8
									
								
								internal/parsers/all.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								internal/parsers/all.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| package parsers | ||||
| 
 | ||||
| import ( | ||||
| 	_ "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/parsers/dummy" | ||||
| ) | ||||
| 
 | ||||
| // this file does nothing but imports to ensure all the init() functions
 | ||||
| // in the subpackages are called
 | ||||
							
								
								
									
										9
									
								
								internal/parsers/dummy/meta.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								internal/parsers/dummy/meta.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,9 @@ | |||
| package dummy | ||||
| 
 | ||||
| import "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| 
 | ||||
| var name = "dummy" | ||||
| 
 | ||||
| func init() { | ||||
| 	stage.RegisterParser(name, &Dummy{}) | ||||
| } | ||||
							
								
								
									
										15
									
								
								internal/parsers/dummy/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								internal/parsers/dummy/parser.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| package dummy | ||||
| 
 | ||||
| import ( | ||||
| 	"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" | ||||
| 	"github.com/criyle/go-judge/cmd/go-judge/model" | ||||
| ) | ||||
| 
 | ||||
| type Dummy struct{} | ||||
| 
 | ||||
| func (e *Dummy) Run(result model.Result, config string) stage.ParserResult { | ||||
| 	return stage.ParserResult{ | ||||
| 		Score:   0, | ||||
| 		Comment: "I'm a dummy", | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										15
									
								
								internal/stage/executor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								internal/stage/executor.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| package stage | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/criyle/go-judge/cmd/go-judge/model" | ||||
| ) | ||||
| 
 | ||||
| var executorMap = map[string]Executor{} | ||||
| 
 | ||||
| type Executor interface { | ||||
| 	Run(model.Cmd) model.Result | ||||
| } | ||||
| 
 | ||||
| func RegisterExecutor(name string, executor Executor) { | ||||
| 	executorMap[name] = executor | ||||
| } | ||||
							
								
								
									
										18
									
								
								internal/stage/parser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								internal/stage/parser.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| package stage | ||||
| 
 | ||||
| import "github.com/criyle/go-judge/cmd/go-judge/model" | ||||
| 
 | ||||
| var parserMap = map[string]Parser{} | ||||
| 
 | ||||
| type Parser interface { | ||||
| 	Run(model.Result, string) ParserResult | ||||
| } | ||||
| 
 | ||||
| type ParserResult struct { | ||||
| 	Score   int | ||||
| 	Comment string | ||||
| } | ||||
| 
 | ||||
| func RegisterParser(name string, parser Parser) { | ||||
| 	parserMap[name] = parser | ||||
| } | ||||
							
								
								
									
										49
									
								
								internal/stage/run.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								internal/stage/run.go
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| package stage | ||||
| 
 | ||||
| import ( | ||||
| 	"github.com/criyle/go-judge/cmd/go-judge/model" | ||||
| ) | ||||
| 
 | ||||
| type Stage struct { | ||||
| 	name         string | ||||
| 	executor     Executor | ||||
| 	executorCmd  model.Cmd | ||||
| 	parser       Parser | ||||
| 	parserConfig string | ||||
| } | ||||
| 
 | ||||
| type StageResult struct { | ||||
| 	Name string | ||||
| 	ParserResult | ||||
| } | ||||
| 
 | ||||
| func ParseStages() []Stage { | ||||
| 	stages := []Stage{} | ||||
| 	config := [][]string{ | ||||
| 		{"dummy stage 0", "dummy", "dummy"}, | ||||
| 		{"dummy stage 1", "dummy", "dummy"}, | ||||
| 	} | ||||
| 	for _, v := range config { | ||||
| 		stages = append(stages, Stage{ | ||||
| 			name:         v[0], | ||||
| 			executor:     executorMap[v[1]], | ||||
| 			executorCmd:  model.Cmd{}, | ||||
| 			parser:       parserMap[v[2]], | ||||
| 			parserConfig: "", | ||||
| 		}) | ||||
| 	} | ||||
| 	return stages | ||||
| } | ||||
| 
 | ||||
| func Run(stages []Stage) []StageResult { | ||||
| 	var parserResults []StageResult | ||||
| 	for _, stage := range stages { | ||||
| 		executorResult := stage.executor.Run(stage.executorCmd) | ||||
| 		parserResult := stage.parser.Run(executorResult, stage.parserConfig) | ||||
| 		parserResults = append(parserResults, StageResult{ | ||||
| 			Name:         stage.name, | ||||
| 			ParserResult: parserResult, | ||||
| 		}) | ||||
| 	} | ||||
| 	return parserResults | ||||
| } | ||||
|  | @ -1,96 +0,0 @@ | |||
| package runner | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"log/slog" | ||||
| 	"os/exec" | ||||
| 	"os/user" | ||||
| 	"strconv" | ||||
| 	"syscall" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"github.com/containerd/cgroups" | ||||
| 	"github.com/opencontainers/runtime-spec/specs-go" | ||||
| ) | ||||
| 
 | ||||
| type RunResult struct { | ||||
| 	ReturnCode int | ||||
| 	Stdout     []byte | ||||
| 	Stderr     []byte | ||||
| 	TimedOut   bool | ||||
| 	TimeNs     uint64 | ||||
| 	MemoryByte uint64 | ||||
| } | ||||
| 
 | ||||
| func RunInCgroupsV1( | ||||
| 	args []string, username string, cgroupsPath string, timeoutMs uint, | ||||
| ) (result *RunResult, err error) { | ||||
| 	u, err := user.Lookup(username) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	control, err := cgroups.New( | ||||
| 		cgroups.V1, | ||||
| 		cgroups.StaticPath(cgroupsPath), | ||||
| 		&specs.LinuxResources{}, | ||||
| 	) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	defer func() { | ||||
| 		if err := control.Delete(); err != nil { | ||||
| 			slog.Error("control.Delete", "error", err) | ||||
| 		} | ||||
| 	}() | ||||
| 	cmd := exec.Command(args[0], args[1:]...) | ||||
| 	cmd.SysProcAttr = &syscall.SysProcAttr{} | ||||
| 	uid, _ := strconv.ParseUint(u.Uid, 10, 32) | ||||
| 	gid, _ := strconv.ParseUint(u.Gid, 10, 32) | ||||
| 	cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)} | ||||
| 	var stdout, stderr bytes.Buffer | ||||
| 	cmd.Stdout = &stdout | ||||
| 	cmd.Stderr = &stderr | ||||
| 	start := time.Now() | ||||
| 	err = cmd.Start() | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	pid := cmd.Process.Pid | ||||
| 	slog.Info("process created", "pid", strconv.Itoa(pid)) | ||||
| 	if err = control.Add(cgroups.Process{Pid: pid}); err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	var returnCode int | ||||
| 	exitCode := make(chan int, 1) | ||||
| 	go func(exit_code chan int) { | ||||
| 		if err = cmd.Wait(); err != nil { | ||||
| 			exit_code <- err.(*exec.ExitError).ExitCode() | ||||
| 		} else { | ||||
| 			exit_code <- 0 | ||||
| 		} | ||||
| 	}(exitCode) | ||||
| 	timeoutLimit := time.Duration(timeoutMs) * time.Millisecond | ||||
| 	timedOut := false | ||||
| 	select { | ||||
| 	case returnCode = <-exitCode: | ||||
| 		slog.Info("done success", "time", time.Since(start)) | ||||
| 	case <-time.After(timeoutLimit): | ||||
| 		slog.Info("done timeout", "time", time.Since(start)) | ||||
| 		_ = cmd.Process.Kill() | ||||
| 		returnCode = <-exitCode | ||||
| 		timedOut = true | ||||
| 	} | ||||
| 	stats, err := control.Stat(cgroups.IgnoreNotExist) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	result = &RunResult{ | ||||
| 		ReturnCode: returnCode, | ||||
| 		Stdout:     stdout.Bytes(), | ||||
| 		Stderr:     stderr.Bytes(), | ||||
| 		TimedOut:   timedOut, | ||||
| 		TimeNs:     stats.CPU.Usage.Kernel + stats.CPU.Usage.User, | ||||
| 		MemoryByte: stats.Memory.Usage.Max, // Memory.Usage.Max = 0 when killed
 | ||||
| 	} | ||||
| 	return | ||||
| } | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user