JOJ3/cmd/joj3/conf.go
zzjc1234 0409bee600
Some checks failed
checks / build (push) Failing after 41s
checks / build (pull_request) Failing after 44s
feat: multiple configs
2024-09-20 12:55:17 +08:00

222 lines
4.3 KiB
Go

package main
import (
"fmt"
"log/slog"
"os"
"regexp"
"strconv"
"strings"
"focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage"
"github.com/go-git/go-git/v5"
"github.com/koding/multiconfig"
)
type JobType int
const (
HC JobType = iota
CQ
OJ
)
type Conf struct {
SandboxExecServer string `default:"localhost:5051"`
SandboxToken string `default:""`
LogLevel int `default:"0"`
OutputPath string `default:"joj3_result.json"`
Stages []struct {
Name string
Executor struct {
Name string
With struct {
Default stage.Cmd
Cases []OptionalCmd
}
}
Parser struct {
Name string
With interface{}
}
}
}
type OptionalCmd struct {
Args *[]string
Env *[]string
Stdin *stage.CmdFile
Stdout *stage.CmdFile
Stderr *stage.CmdFile
CPULimit *uint64
RealCPULimit *uint64
ClockLimit *uint64
MemoryLimit *uint64
StackLimit *uint64
ProcLimit *uint64
CPURateLimit *uint64
CPUSetLimit *string
CopyIn *map[string]stage.CmdFile
CopyInCached *map[string]string
CopyInCwd *bool
CopyOut *[]string
CopyOutCached *[]string
CopyOutMax *uint64
CopyOutDir *string
TTY *bool
StrictMemoryLimit *bool
DataSegmentLimit *bool
AddressSpaceLimit *bool
}
func parseConfFile(path string) (conf Conf, err error) {
d := &multiconfig.DefaultLoader{}
d.Loader = multiconfig.MultiLoader(
&multiconfig.TagLoader{},
&multiconfig.JSONLoader{Path: path},
)
d.Validator = multiconfig.MultiValidator(&multiconfig.RequiredValidator{})
if err = d.Load(&conf); err != nil {
slog.Error("parse stages conf", "error", err)
return
}
if err = d.Validate(&conf); err != nil {
slog.Error("validate stages conf", "error", err)
return
}
return
}
func _validateHw(hw string) error {
matched, err := regexp.MatchString(`^hw[0-9]+$`, hw)
if err != nil {
return fmt.Errorf("error compiling regex: %w", err)
}
if !matched {
return fmt.Errorf("error: hw does not match the required pattern")
}
return nil
}
func _getExList(pattern string) (hwList []string, err error) {
re, err := regexp.Compile(pattern)
if err != nil {
return nil, fmt.Errorf("failed to compile regex: %w", err)
}
files, err := os.ReadDir(".")
if err != nil {
return nil, fmt.Errorf("error reading directory: %w", err)
}
for _, file := range files {
if !file.IsDir() && re.MatchString(file.Name()) {
hwList = append(hwList, file.Name())
}
}
return hwList, nil
}
func _contains(list []string, item string) bool {
for _, v := range list {
if v == item {
return true
}
}
return false
}
func commitMsgToConf() (confs []Conf, jobtype JobType, err error) {
r, err := git.PlainOpen(".")
if err != nil {
return
}
ref, err := r.Head()
if err != nil {
return
}
commit, err := r.CommitObject(ref.Hash())
if err != nil {
return
}
var conf Conf
var exList []string
jobtype = HC
file := "conf.json"
msg := commit.Message
slog.Debug("commit msg to conf", "msg", msg)
// INFO: default config
conf, err = parseConfFile(file)
confs = append(confs, conf)
if msg == "" {
return
}
line := strings.Split(msg, "\n")[0]
words := strings.Fields(line)
head := words[0]
var hw string
// INFO: get worktype
if strings.HasSuffix(head, ":") || strings.HasSuffix(head, ".") {
head = head[:len(head)-1]
}
switch head {
case "feat", "fix", "refactor", "perf", "test", "build", "revert":
jobtype = CQ
case "joj", "grading":
jobtype = OJ
}
// INFO: get configs
if len(words) >= 2 {
hw = words[1]
if err = _validateHw(hw); err == nil {
file = strings.Replace(file, "conf", "conf-"+hw, 1)
}
var exTot []string
// INFO: get all hw ex if no args provided
exTot, err = _getExList(file)
if len(words) == 2 {
exList = exTot
} else {
var tmpList []string
for idx := 2; idx < len(words); idx++ {
word := words[idx]
num, err := strconv.Atoi(word)
if err != nil {
return confs, HC, fmt.Errorf("error: bad ex number")
}
file := fmt.Sprintf("conf-"+hw+"-ex%d.json", num)
if !_contains(exList, file) {
return confs, HC, fmt.Errorf("error: bad ex number")
}
tmpList = append(tmpList, file)
}
exList = tmpList
}
}
for _, ex := range exList {
conf, err = parseConfFile(ex)
if err != nil {
return
}
confs = append(confs, conf)
}
return
}