package main import ( "bytes" "fmt" "os" "path/filepath" "strings" "text/template" "github.com/tealeg/xlsx" ) var XlsxFiles = make(map[string]string) var templates *template.Template type SheetColumnMetaStruct struct { ColIndex int ColName string ColType int CTString string IsArray bool IsMap bool } type SheetMetaStruct struct { AbsPath string FileName string ProtoName string Cols []*SheetColumnMetaStruct } const ( INTTYPE string = "(int)" INT64TYPE string = "(int64)" STRTYPE = "(str)" ARRINTTYPE = "(arrint)" ARRINT64TYPE = "(arrint64)" ARRSTRTYPE = "(arrstr)" INTTYPE_PROTO = "int32" INT64TYPE_PROTO = "int64" STRTYPE_PROTO = "string" MAPTYPE string = "(map)" MAP_PROTO = "map" ) func Init() { var err error wd, err := os.Getwd() if err != nil { return } protoAbsPath := filepath.Join(wd, "..", "protocol") err = os.MkdirAll(protoAbsPath, os.ModePerm) if err != nil { return } xlsxAbsPath := filepath.Join(wd, "..", "xlsx") var fis []os.DirEntry fis, err = os.ReadDir(xlsxAbsPath) if err != nil { return } srvDataAbsPath := filepath.Join(wd, "..", "code") err = os.MkdirAll(srvDataAbsPath, os.ModePerm) if err != nil { return } for _, v := range fis { if !v.IsDir() { if !strings.HasSuffix(v.Name(), ".xlsx") { continue } pfAbs := filepath.Join(xlsxAbsPath, v.Name()) XlsxFiles[v.Name()] = pfAbs } } pattern := filepath.Join(wd, "templ", "*.templ") funcMap := template.FuncMap{ "inc": func(n int) int { n++ return n }, } //fmt.Println("templ目录:", pattern) templates, err = template.Must(template.New("mytempl").Funcs(funcMap).ParseGlob(pattern)).Parse("") } func main() { Init() smsMap := make(map[string]*SheetMetaStruct) for xlsxFileName, xlsxFilePath := range XlsxFiles { xlsxFile, err := xlsx.OpenFile(xlsxFilePath) if err != nil { fmt.Println("excel file open error:", err, " filePath:", xlsxFilePath) continue } for _, sheet := range xlsxFile.Sheets { sms := &SheetMetaStruct{ AbsPath: xlsxFilePath, FileName: xlsxFileName, ProtoName: strings.TrimSuffix(xlsxFileName, ".xlsx"), Cols: make([]*SheetColumnMetaStruct, 0, sheet.MaxCol)} for _, row := range sheet.Rows { for i, cell := range row.Cells { s := cell.String() if strings.HasSuffix(s, INTTYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, INTTYPE), 1, INTTYPE_PROTO, false, false}) } else if strings.HasSuffix(s, STRTYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, STRTYPE), 2, STRTYPE_PROTO, false, false}) } else if strings.HasSuffix(s, ARRINTTYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, ARRINTTYPE), 3, INTTYPE_PROTO, true, false}) } else if strings.HasSuffix(s, ARRSTRTYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, ARRSTRTYPE), 4, STRTYPE_PROTO, true, false}) } else if strings.HasSuffix(s, INT64TYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, INT64TYPE), 5, INT64TYPE_PROTO, false, false}) } else if strings.HasSuffix(s, ARRINT64TYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, ARRINT64TYPE), 6, INT64TYPE_PROTO, true, false}) } else if strings.HasSuffix(s, MAPTYPE) { sms.Cols = append(sms.Cols, &SheetColumnMetaStruct{i, strings.TrimSuffix(s, MAPTYPE), 7, MAP_PROTO, false, true}) } } break //only fetch first row } smsMap[sms.ProtoName] = sms break //only fetch first sheet } } geneProto(smsMap) } func geneProto(xlsxs map[string]*SheetMetaStruct) { if xlsxs == nil { return } geneAgcHelper(xlsxs) //生成go代码 xlsx转二进制文件(.json,.dat) geneDataStructProto(xlsxs) //生成xlsx转protobuf结构文件(pbdata.proto) for _, val := range xlsxs { genGoDataMgr(val) // 生成Go对象文件 } } // geneAgcHelper 生成go代码,读取xlsx数据 func geneAgcHelper(xlsxs map[string]*SheetMetaStruct) { dm := map[string]interface{}{ "data": xlsxs, "opath": filepath.Join("..", "data"), "isMapCol": isMapColumn(xlsxs), } outputHelper := bytes.NewBuffer(nil) err := templates.ExecuteTemplate(outputHelper, "agc", dm) if err != nil { fmt.Println("geneProto ExecuteTemplate error:", err) return } helperGoFile := filepath.Join("..", "xlsx2binary", "agc.go") err = os.WriteFile(helperGoFile, outputHelper.Bytes(), os.ModePerm) if err != nil { fmt.Println("geneProto WriteFile error:", err) return } } // geneDataStructProto 生成xlsx的proto文件 func geneDataStructProto(xlsxs map[string]*SheetMetaStruct) { outputHelper := bytes.NewBuffer(nil) err := templates.ExecuteTemplate(outputHelper, "gpb", xlsxs) if err != nil { fmt.Println("geneDataStructProto ExecuteTemplate error:", err) return } protoFile := "../protocol/server/pbdata.proto" err = os.WriteFile(protoFile, outputHelper.Bytes(), os.ModePerm) if err != nil { fmt.Println("geneDataStructProto error:", err) } } // genGoDataMgr 生成go代码,读取.dat文件数据 func genGoDataMgr(sms *SheetMetaStruct) { if sms == nil { return } outputHelper := bytes.NewBuffer(nil) err := templates.ExecuteTemplate(outputHelper, "gpb_mgr", sms) if err != nil { fmt.Println("genGoDataMgr ExecuteTemplate error:", err) return } opath := filepath.Join("../code", strings.ToLower(fmt.Sprintf("%v.go", sms.ProtoName))) err = os.WriteFile(opath, outputHelper.Bytes(), os.ModePerm) if err != nil { fmt.Println("genGoDataMgr WriteFile error:", err) return } } func isMapColumn(xlsxs map[string]*SheetMetaStruct) bool { for _, sheet := range xlsxs { for _, col := range sheet.Cols { if col.IsMap { return true } } } return false }