WIP: commit msg parser #39
							
								
								
									
										120
									
								
								cmd/joj3/conf.go
									
									
									
									
									
								
							
							
						
						
									
										120
									
								
								cmd/joj3/conf.go
									
									
									
									
									
								
							|  | @ -1,32 +1,45 @@ | |||
| package main | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log/slog" | ||||
| 	"regexp" | ||||
| 	"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 Stage struct { | ||||
| 	Name     string | ||||
| 	Executor struct { | ||||
| 		Name string | ||||
| 		With struct { | ||||
| 			Default stage.Cmd | ||||
| 			Cases   []OptionalCmd | ||||
| 		} | ||||
| 	} | ||||
| 	Parser struct { | ||||
| 		Name string | ||||
| 		With interface{} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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{} | ||||
| 		} | ||||
| 	} | ||||
| 	Stages            []Stage | ||||
| } | ||||
| 
 | ||||
| type OptionalCmd struct { | ||||
|  | @ -60,40 +73,113 @@ type OptionalCmd struct { | |||
| 	AddressSpaceLimit *bool | ||||
| } | ||||
| 
 | ||||
| func parseConfFile(path string) (conf Conf, err error) { | ||||
| func parseConfFile(path string, jobtype JobType) (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 | ||||
| 	} | ||||
| 
 | ||||
| 	filteredStages := []Stage{} | ||||
| 	for _, stage := range conf.Stages { | ||||
| 		if filterStage(stage, jobtype) { | ||||
| 			filteredStages = append(filteredStages, stage) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	conf.Stages = filteredStages | ||||
| 
 | ||||
| 	return | ||||
| } | ||||
| 
 | ||||
| func filterStage(stage Stage, jobtype JobType) bool { | ||||
| 	switch jobtype { | ||||
| 	case HC: | ||||
| 		return stage.Name == "healthcheck" | ||||
| 	case CQ: | ||||
| 		return stage.Name == "compile" || stage.Name == "healthcheck" | ||||
| 	case OJ: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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 commitMsgToConf() (conf Conf, 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 | ||||
| 	} | ||||
| 
 | ||||
| 	file := "conf.json" | ||||
| 	jobtype := HC | ||||
| 
 | ||||
| 	msg := commit.Message | ||||
| 	slog.Debug("commit msg to conf", "msg", msg) | ||||
| 	// TODO: parse msg to conf name
 | ||||
| 	conf, err = parseConfFile("conf.json") | ||||
| 	if msg == "" { | ||||
| 		conf, err = parseConfFile(file, jobtype) | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	line := strings.Split(msg, "\n")[0] | ||||
| 
 | ||||
| 	words := strings.Fields(line) | ||||
| 
 | ||||
| 	head := words[0] | ||||
| 	var hw string | ||||
| 
 | ||||
| 	if strings.HasSuffix(head, ":") || strings.HasSuffix(head, ".") { | ||||
| 		head = head[:len(head)-1] | ||||
| 	} | ||||
| 
 | ||||
| 	if len(words) == 3 { | ||||
| 		hw = words[1] | ||||
| 		if err = validateHw(hw); err != nil { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		switch head { | ||||
| 		case "feat", "fix", "refactor", "perf", "test", "build", "revert": | ||||
| 			file = strings.Replace(file, "conf", "conf-"+hw, 1) | ||||
| 			jobtype = CQ | ||||
| 		case "joj", "grading": | ||||
| 			file = strings.Replace(file, "conf", "conf-"+hw, 1) | ||||
| 			jobtype = OJ | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	conf, err = parseConfFile(file, jobtype) | ||||
| 	return | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	Block a user