func (g *generator) initTables() { defer log.WhenDone().Info("Stats", "Package", g.tts.Package, "Step", "InitTables") var err error g.tables, err = codegen.GetTables(g.dbrConn.NewSession(), codegen.ReplaceTablePrefix(g.tts.SQLQuery)) codegen.LogFatal(err) if len(g.tts.EntityTypeCodes) > 0 && g.tts.EntityTypeCodes[0] != "" { g.eavValueTables, err = codegen.GetEavValueTables(g.dbrConn, g.tts.EntityTypeCodes) codegen.LogFatal(err) for _, vTables := range g.eavValueTables { for t := range vTables { if false == isDuplicate(g.tables, t) { g.tables = append(g.tables, t) } } } } if g.tts.GenericsWhiteList == "" { return // do nothing because nothing defined, neither custom SQL nor to copy from SQLQuery field } if false == dbr.Stmt.IsSelect(g.tts.GenericsWhiteList) { // copy result from tables because select key word not found g.whiteListTables = g.tables return } g.whiteListTables, err = codegen.GetTables(g.dbrConn.NewSession(), codegen.ReplaceTablePrefix(g.tts.GenericsWhiteList)) codegen.LogFatal(err) }
// getAttributeValuesForWebsites creates a map where the key is the attribute ID and // each part of the StringEntities slice are the full attribute values for a website ID. func getAttributeValuesForWebsites(ctx *context) map[string][]codegen.StringEntities { var tws store.TableWebsiteSlice tws.Load(ctx.dbrConn.NewSession(nil), func(sb *dbr.SelectBuilder) *dbr.SelectBuilder { return sb.Where("website_id > 0") }) // key contains the attributeID as a string var aws = make(map[string][]codegen.StringEntities) tew, err := ctx.aat.TableEavWebsite() codegen.LogFatal(err) if tew != nil { // only for those who have a wbesite specific table for _, w := range tws { aCollection, err := codegen.LoadStringEntities(ctx.db, getAttrSelect(ctx, w.WebsiteID)) codegen.LogFatal(err) for _, row := range aCollection { if aid, ok := row["attribute_id"]; ok { if nil == aws[aid] { aws[aid] = make([]codegen.StringEntities, 0, 200) // up to 200 websites at once } aws[aid] = append(aws[aid], row) } else { codegen.LogFatal(errgo.Newf("Column attribute_id not found in collection %#v\n", aCollection)) } } } } return aws }
// materializeEntityType writes the data from eav_entity_type into a Go file and transforms // Magento classes and config strings into Go functions. // Depends on generated code from tableToStruct. func materializeEntityType(ctx *context) { defer ctx.wg.Done() type dataContainer struct { ETypeData eav.TableEntityTypeSlice ImportPaths []string Package, Tick string } etData, err := getEntityTypeData(ctx.dbc.NewSession()) codegen.LogFatal(err) tplData := &dataContainer{ ETypeData: etData, ImportPaths: getImportPaths(), Package: codegen.ConfigMaterializationEntityType.Package, Tick: "`", } addFM := template.FuncMap{ "extractFuncType": codegen.ExtractFuncType, } formatted, err := codegen.GenerateCode(codegen.ConfigMaterializationEntityType.Package, tplEav, tplData, addFM) if err != nil { fmt.Printf("\n%s\n", formatted) codegen.LogFatal(err) } codegen.LogFatal(ioutil.WriteFile(codegen.ConfigMaterializationEntityType.OutputFile, formatted, 0600)) }
// materializeAttributes ... // Depends on generated code from tableToStruct. func materializeAttributes(ctx *context) { defer ctx.wg.Done() // generators, order of execution is important var gs = []func(*context, map[string]interface{}) ([]byte, error){ attrCopyright, attrImport, attrTypes, attrGetter, attrCollection, } etc, err := getEntityTypeData(ctx.dbrConn.NewSession(nil)) codegen.LogFatal(err) for _, et := range etc { ctx.et = et ctx.aat = codegen.NewAddAttrTables(ctx.db, ctx.et.EntityTypeCode) data := attrGenerateData(ctx) var cb bytes.Buffer // code buffer for _, g := range gs { code, err := g(ctx, data) if err != nil { println(string(code)) codegen.LogFatal(err) } cb.Write(code) } codegen.LogFatal(ioutil.WriteFile(getOutputFile(ctx.et), cb.Bytes(), 0600)) } }
func (g *generator) runTable() { defer log.WhenDone().Info("Stats", "Package", g.tts.Package, "Step", "RunTable") type OneTable struct { Package string Tick string Name string TableName string Struct string Slice string Table string GoColumns codegen.Columns Columns csdb.Columns MethodRecvPrefix string FindByPk string } for _, table := range g.tables { columns, err := codegen.GetColumns(g.dbrConn.DB, table) codegen.LogFatal(err) codegen.LogFatal(columns.MapSQLToGoDBRType()) name := g.getConsistentName(table) data := OneTable{ Package: g.tts.Package, Tick: "`", Name: name, TableName: g.getMagento2TableName(table), // original table name! Struct: TypePrefix + name, // getTableConstantName Slice: TypePrefix + name + "Slice", // getTableConstantName Table: table, GoColumns: columns, Columns: columns.CopyToCSDB(), } if data.Columns.PrimaryKeys().Len() > 0 { data.FindByPk = "FindBy" + utils.UnderscoreCamelize(data.Columns.PrimaryKeys().JoinFields("_")) } tplFuncs := template.FuncMap{ "typePrefix": func(name string) string { // if the method already exists in package then add the prefix parent // to avoid duplicate function names. search := data.Slice + name if g.existingMethodSets.has(search) { return MethodRecvPrefix + name } return name }, "findBy": findBy, "dbrType": dbrType, } g.appendToFile(g.getGenericTemplate(table), data, tplFuncs) } }
func detectMagentoVersion(dbrSess dbr.SessionRunner) (MageOne, MageTwo bool) { defer log.WhenDone().Info("Stats", "Package", "DetectMagentoVersion") allTables, err := codegen.GetTables(dbrSess) codegen.LogFatal(err) MageOne, MageTwo = utils.MagentoVersion(codegen.TablePrefix, allTables) if MageOne == MageTwo { codegen.LogFatal(errors.New("Cannot detect your Magento version")) } return }
func (g *generator) appendToFile(tpl string, data interface{}, addFM template.FuncMap) { formatted, err := codegen.GenerateCode(g.tts.Package, tpl, data, addFM) if err != nil { fmt.Printf("\n%s\n", formatted) codegen.LogFatal(err) } if _, err := g.outfile.Write(formatted); err != nil { codegen.LogFatal(err) } codegen.LogFatal(g.outfile.Sync()) // flush immediately to disk to prevent a race condition }
func main() { fmt.Println("TODO refactor") os.Exit(-1) gen.Init() // Read the CLDR zip file. Autodownloading if file not found r := gen.OpenCLDRCoreZip() defer r.Close() d := &cldr.Decoder{} d.SetDirFilter("main", "supplemental") d.SetSectionFilter("localeDisplayNames", "numbers") data, err := d.DecodeZip(r) codegen.LogFatal(err) curW := &bytes.Buffer{} for _, loc := range data.Locales() { if false == codegen.ConfigLocalization.EnabledLocale.Include(loc) { continue } ldml, err := data.LDML(loc) codegen.LogFatal(err) fmt.Fprintf(os.Stdout, "Generating: %s\n", loc) curB := curBuilder{ w: curW, locale: loc, data: ldml, } curB.generate() } tplData := map[string]interface{}{ "Package": codegen.ConfigLocalization.Package, "CurrencyDicts": curW.String(), } formatted, err := codegen.GenerateCode(codegen.ConfigLocalization.Package, tplCode, tplData, nil) if err != nil { fmt.Printf("\n\n%s\n\n", formatted) codegen.LogFatal(err) } codegen.LogFatal(ioutil.WriteFile(codegen.ConfigLocalization.OutputFile, formatted, 0600)) }
func (g *generator) run() { defer log.WhenDone().Info("Stats", "Package", g.tts.Package) defer g.wg.Done() g.analyzePackage() var err error g.outfile, err = os.OpenFile(g.tts.OutputFile.String(), os.O_APPEND|os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) codegen.LogFatal(err) g.appendToFile(tpl.Copy, struct{ Package string }{Package: g.tts.Package}, nil) g.initTables() g.runHeader() g.runTable() g.runEAValueTables() codegen.LogFatal(g.outfile.Close()) }
// getEntityTypeData retrieves all EAV models from table eav_entity_type but only those listed in variable // codegen.ConfigEntityType. It then applies the mapping data from codegen.ConfigEntityType to the entity_type struct. // Depends on generated code from tableToStruct. func getEntityTypeData(dbrSess *dbr.Session) (etc eav.TableEntityTypeSlice, err error) { s, err := eav.TableCollection.Structure(eav.TableIndexEntityType) if err != nil { return nil, errgo.Mask(err) } _, err = dbrSess. Select(s.AllColumnAliasQuote(s.Name)...). From(s.Name). Where("entity_type_code IN ?", codegen.ConfigEntityType.Keys()). LoadStructs(&etc) if err != nil { return nil, errgo.Mask(err) } for typeCode, mapData := range codegen.ConfigEntityType { // map the fields from the config struct to the data retrieved from the database. et, err := etc.GetByCode(typeCode) codegen.LogFatal(err) et.EntityModel = codegen.ParseString(mapData.EntityModel, et) et.AttributeModel.String = codegen.ParseString(mapData.AttributeModel, et) et.EntityTable.String = codegen.ParseString(mapData.EntityTable, et) et.IncrementModel.String = codegen.ParseString(mapData.IncrementModel, et) et.AdditionalAttributeTable.String = codegen.ParseString(mapData.AdditionalAttributeTable, et) et.EntityAttributeCollection.String = codegen.ParseString(mapData.EntityAttributeCollection, et) } return etc, nil }
func main() { db, dbrConn, err := csdb.Connect() codegen.LogFatal(err) defer db.Close() for _, tStruct := range codegen.ConfigTableToStruct { generateStructures(tStruct, db, dbrConn) } }
func newContext() *context { dbc, err := csdb.Connect() codegen.LogFatal(err) return &context{ wg: sync.WaitGroup{}, dbc: dbc, goSrcPath: build.Default.GOPATH + "/src/", } }
func getAttrSelect(ctx *context, websiteID int64) *dbr.SelectBuilder { dbrSelect, err := eav.GetAttributeSelectSql( ctx.dbrConn.NewSession(nil), ctx.aat, ctx.et.EntityTypeID, websiteID, ) codegen.LogFatal(err) dbrSelect.OrderDir(csdb.MainTable+".attribute_code", true) tew, err := ctx.aat.TableEavWebsite() codegen.LogFatal(err) if websiteID > 0 && tew != nil { // only here in codegen used to detect any changes if an attribute value will be overridden by a website ID dbrSelect.Where(csdb.ScopeTable + ".website_id IS NOT NULL") dbrSelect.Columns = append(dbrSelect.Columns, csdb.ScopeTable+".website_id") } return dbrSelect }
func (g *generator) getGenericTemplate(tableName string) string { var finalTpl bytes.Buffer // at least we need a type definition if _, err := finalTpl.WriteString(tpl.Type); err != nil { codegen.LogFatal(err) } if false == g.whiteListTables.Include(tableName) { return finalTpl.String() } isAll := (g.tts.GenericsFunctions & tpl.OptAll) == tpl.OptAll if isAll || (g.tts.GenericsFunctions&tpl.OptSQL) == tpl.OptSQL { _, err := finalTpl.WriteString(tpl.SQL) codegen.LogFatal(err) } if isAll || (g.tts.GenericsFunctions&tpl.OptFindBy) == tpl.OptFindBy { _, err := finalTpl.WriteString(tpl.FindBy) codegen.LogFatal(err) } if isAll || (g.tts.GenericsFunctions&tpl.OptSort) == tpl.OptSort { _, err := finalTpl.WriteString(tpl.Sort) codegen.LogFatal(err) } if isAll || (g.tts.GenericsFunctions&tpl.OptSliceFunctions) == tpl.OptSliceFunctions { _, err := finalTpl.WriteString(tpl.SliceFunctions) codegen.LogFatal(err) } if isAll || (g.tts.GenericsFunctions&tpl.OptExtractFromSlice) == tpl.OptExtractFromSlice { _, err := finalTpl.WriteString(tpl.ExtractFromSlice) codegen.LogFatal(err) } return finalTpl.String() }
// runCodec generates the codecs to be used later in JSON or msgpack or etc func runCodec(pkg, outfile, readfile string) { defer log.WhenDone().Info("Stats", "Package", pkg, "Step", "runCodec") if err := codecgen.Generate( outfile, // outfile "", // buildTag codecgen.GenCodecPath, false, // use unsafe "", regexp.MustCompile(TypePrefix+".*"), // Prefix of generated structs and slices true, // delete temp files readfile, // read from file ); err != nil { fmt.Println("codecgen.Generate Error:") codegen.LogFatal(err) } }
func (b *curBuilder) generate() { var nameData = bytes.Buffer{} var nameIDX []uint16 for _, cur := range b.data.Numbers.Currencies.Currency { var d string if len(cur.DisplayName) > 0 { d = cur.DisplayName[0].Data() } nameData.WriteString(d) nameIDX = append(nameIDX, uint16(nameData.Len())) } nameIDX = append(nameIDX, uint16(nameData.Len())) var codeData = bytes.Buffer{} for _, cur := range b.data.Numbers.Currencies.Currency { if len(cur.Type) != 3 { panic(fmt.Errorf("Expecting 3 character long currency code: %v\n", cur)) } codeData.WriteString(cur.Type) } var symbolData = bytes.Buffer{} var symbolIDX []uint16 for _, cur := range b.data.Numbers.Currencies.Currency { var d string if len(cur.Symbol) > 0 { d = cur.Symbol[0].Data() } symbolData.WriteString(d) symbolIDX = append(symbolIDX, uint16(symbolData.Len())) } symbolIDX = append(symbolIDX, uint16(symbolData.Len())) tplData := map[string]interface{}{ "Locale": b.locale, "Codes3": codeData.String(), "NamesData": nameData.String(), "NamesIDX": nameIDX, "SymbolsData": symbolData.String(), "SymbolsIDX": symbolIDX, } err := template.Must(template.New("tpl_code_unit").Parse(tplCodeUnit)).Execute(b.w, tplData) codegen.LogFatal(err) }
// analyzePackage extracts from all types the method receivers and type names. If we found existing // functions we will add a MethodRecvPrefix to the generated functions to avoid conflicts. func (g *generator) analyzePackage() { defer log.WhenDone(PkgLog).Info("Stats", "Package", g.tts.Package, "Step", "AnalyzePackage") fset := token.NewFileSet() path := filepath.Dir(g.tts.OutputFile.String()) pkgs, err := parser.ParseDir(fset, path, nil, parser.AllErrors) codegen.LogFatal(err) var astPkg *ast.Package var ok bool if astPkg, ok = pkgs[g.tts.Package]; !ok { fmt.Printf("Package %s not found in path %s. Skipping.", g.tts.Package, path) return } for fName, astFile := range astPkg.Files { if fName == g.tts.OutputFile.String() || strings.Contains(fName, "_fallback.go") { // skip the generated file (tables_generated.go) or we have recursion 8-) // skip also the _fallback.go files which contain the generated code // because those files get included if no build tag has been specified. continue } ast.Inspect(astFile, func(n ast.Node) bool { switch stmt := n.(type) { case *ast.FuncDecl: if stmt.Recv != nil { // we have a method receiver and not a normal function switch t := stmt.Recv.List[0].Type.(type) { case *ast.Ident: // non-pointer-type if strings.Index(t.Name, TypePrefix) == 0 { g.existingMethodSets.add(t.Name + stmt.Name.Name) // e.g.: TableWebsiteSliceLoad where Load is the function name } case *ast.StarExpr: // pointer-type switch t2 := t.X.(type) { case *ast.Ident: if strings.Index(t2.Name, TypePrefix) == 0 { g.existingMethodSets.add(t2.Name + stmt.Name.Name) // e.g.: *TableWebsiteSliceLoad where Load is the function name } } } } } return true }) } }
func main() { defer log.WhenDone().Info("Stats") dbc, err := csdb.Connect() codegen.LogFatal(err) defer dbc.Close() var wg sync.WaitGroup mageV1, mageV2 := detectMagentoVersion(dbc.NewSession()) for _, tStruct := range codegen.ConfigTableToStruct { go newGenerator(tStruct, dbc, &wg).setMagentoVersion(mageV1, mageV2).run() } wg.Wait() for _, ts := range codegen.ConfigTableToStruct { // due to a race condition the codec generator must run after the newGenerator() calls runCodec(ts.Package, ts.OutputFile.AppendName("_codec").String(), ts.OutputFile.String()) } }
func main() { defer log.WhenDone(PkgLog).Info("Stats") dbc, err := csdb.Connect() codegen.LogFatal(err) defer dbc.Close() var wg sync.WaitGroup mageV1, mageV2 := detectMagentoVersion(dbc.NewSession()) for _, tStruct := range codegen.ConfigTableToStruct { go newGenerator(tStruct, dbc, &wg).setMagentoVersion(mageV1, mageV2).run() } wg.Wait() // for _, ts := range codegen.ConfigTableToStruct { // // due to a race condition the codec generator must run after the newGenerator() calls // // TODO(cs) fix https://github.com/ugorji/go/issues/92#issuecomment-140410732 // runCodec(ts.Package, ts.OutputFile.AppendName("_codec").String(), ts.OutputFile.String()) // } }
func getImportPaths() []string { var paths utils.StringSlice var getPath = func(s string) string { ps, err := codegen.ExtractImportPath(s) codegen.LogFatal(err) return ps } for _, et := range codegen.ConfigEntityType { paths.Append( getPath(et.EntityModel), getPath(et.AttributeModel), getPath(et.EntityTable), getPath(et.IncrementModel), getPath(et.AdditionalAttributeTable), getPath(et.EntityAttributeCollection), ) } return paths.Unique().ToString() }
func generateStructures(tStruct *codegen.TableToStruct, db *sql.DB, dbrConn *dbr.Connection) { tplData := &dataContainer{ Tables: make([]map[string]interface{}, 0, 200), Package: tStruct.Package, Tick: "`", } tables, err := codegen.GetTables(db, codegen.ReplaceTablePrefix(tStruct.SQLQuery)) codegen.LogFatal(err) if len(tStruct.EntityTypeCodes) > 0 && tStruct.EntityTypeCodes[0] != "" { tplData.TypeCodeValueTables, err = codegen.GetEavValueTables(dbrConn, tStruct.EntityTypeCodes) codegen.LogFatal(err) for _, vTables := range tplData.TypeCodeValueTables { for t := range vTables { if false == isDuplicate(tables, t) { tables = append(tables, t) } } } } for _, table := range tables { columns, err := codegen.GetColumns(db, table) codegen.LogFatal(err) codegen.LogFatal(columns.MapSQLToGoDBRType()) var name = table if mappedName, ok := codegen.TableMapMagento1To2[strings.Replace(table, codegen.TablePrefix, "", 1)]; ok { name = mappedName } tplData.Tables = append(tplData.Tables, map[string]interface{}{ "name": name, "table": table, "columns": columns, }) } formatted, err := codegen.GenerateCode(tStruct.Package, tplCode, tplData, nil) if err != nil { fmt.Printf("\n%s\n", formatted) codegen.LogFatal(err) } codegen.LogFatal(ioutil.WriteFile(tStruct.OutputFile, formatted, 0600)) }
func attrGenerateData(ctx *context) map[string]interface{} { websiteID := int64(0) // always 0 because we're building the base struct columns := getAttrColumns(ctx, websiteID) attributeCollection, err := codegen.LoadStringEntities(ctx.db, getAttrSelect(ctx, websiteID)) codegen.LogFatal(err) pkg := getPackage(ctx.et) importPaths := codegen.PrepareForTemplate(columns, attributeCollection, codegen.ConfigAttributeModel, pkg) return map[string]interface{}{ "AttrCol": attributeCollection, "AttrPkg": getAttrPkg(ctx.et), "AttrPkgImp": codegen.ConfigMaterializationAttributes[ctx.et.EntityTypeCode].AttrPkgImp, "AttrStruct": codegen.ConfigMaterializationAttributes[ctx.et.EntityTypeCode].AttrStruct, "FuncCollection": codegen.ConfigMaterializationAttributes[ctx.et.EntityTypeCode].FuncCollection, "FuncGetter": codegen.ConfigMaterializationAttributes[ctx.et.EntityTypeCode].FuncGetter, "ImportPaths": importPaths, "MyStruct": codegen.ConfigMaterializationAttributes[ctx.et.EntityTypeCode].MyStruct, "Name": getStructName(ctx, "attribute"), "PackageName": pkg, } }
func getAttrColumns(ctx *context, websiteID int64) codegen.Columns { columns, err := codegen.SQLQueryToColumns(ctx.db, getAttrSelect(ctx, websiteID)) codegen.LogFatal(err) codegen.LogFatal(columns.MapSQLToGoType(codegen.EavAttributeColumnNameToInterface)) return columns }