diff --git a/cmd/joj3/conf.go b/cmd/joj3/conf.go index 0556478..038a4ac 100644 --- a/cmd/joj3/conf.go +++ b/cmd/joj3/conf.go @@ -3,7 +3,9 @@ package main import ( "fmt" "log/slog" + "os" "regexp" + "strconv" "strings" "focs.ji.sjtu.edu.cn/git/FOCS-dev/JOJ3/internal/stage" @@ -11,6 +13,14 @@ import ( "github.com/koding/multiconfig" ) +type JobType int + +const ( + HC JobType = iota + CQ + OJ +) + type Conf struct { SandboxExecServer string `default:"localhost:5051"` SandboxToken string `default:""` @@ -81,7 +91,7 @@ func parseConfFile(path string) (conf Conf, err error) { return } -func validateHw(hw string) error { +func _validateHw(hw string) error { matched, err := regexp.MatchString(`^hw[0-9]+$`, hw) if err != nil { return fmt.Errorf("error compiling regex: %w", err) @@ -92,7 +102,36 @@ func validateHw(hw string) error { return nil } -func commitMsgToConf() (conf Conf, err error) { +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 @@ -108,51 +147,75 @@ func commitMsgToConf() (conf Conf, err error) { 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 == "" { - conf, err = parseConfFile(file) 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": - // TODO: Decide strategy to give students error - // if len(words) < 2 { - // return Conf{}, fmt.Errorf("error: hw not assigned") - // } - if len(words) >= 2 { - hw = words[1] - if err = validateHw(hw); err == nil { - file = strings.Replace(file, "conf", "conf-"+hw+"-cq", 1) - } - } + jobtype = CQ case "joj", "grading": - // TODO: Decide strategy to give students error - // if len(words) < 2 { - // return Conf{}, fmt.Errorf("error: hw not assigned") - // } - if len(words) >= 2 { - hw = words[1] - if err = validateHw(hw); err == nil { - file = strings.Replace(file, "conf", "conf-"+hw+"-oj", 1) + 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 } } - conf, err = parseConfFile(file) + for _, ex := range exList { + conf, err = parseConfFile(ex) + if err != nil { + return + } + confs = append(confs, conf) + } + return } diff --git a/cmd/joj3/main.go b/cmd/joj3/main.go index 8d9f91c..c4039ee 100644 --- a/cmd/joj3/main.go +++ b/cmd/joj3/main.go @@ -71,11 +71,12 @@ func outputResult(conf Conf, results []stage.StageResult) error { } func mainImpl() error { - conf, err := commitMsgToConf() + conf, jobtype, err := commitMsgToConf() if err != nil { slog.Error("no conf found", "error", err) return err } + // TODO: implementation for multiple configs setupSlog(conf) executors.InitWithConf(conf.SandboxExecServer, conf.SandboxToken) stages, err := generateStages(conf)