github.com/kazu/loncha@v0.6.3/structer/structer.go (about) 1 package structer 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/importer" 7 "go/parser" 8 "go/token" 9 "go/types" 10 "io" 11 "io/ioutil" 12 "path" 13 "path/filepath" 14 "strings" 15 16 "github.com/pkg/errors" 17 18 "text/template" 19 20 "github.com/davecgh/go-spew/spew" 21 "go.uber.org/zap" 22 ) 23 24 type StructInfo struct { 25 PkgName string 26 Name string 27 Fields []FieldInfo 28 Embedded []string 29 } 30 31 type FieldInfo struct { 32 Name string 33 Type string 34 } 35 36 var Logger *zap.Logger 37 38 func SetupLogger() { 39 Logger, _ = zap.NewProduction() 40 } 41 42 func LoadAstf(dir string, fset *token.FileSet) (astfs []*ast.File, err error) { 43 44 files, err := filepath.Glob(filepath.Join(dir, "*")) 45 if err != nil { 46 return 47 } 48 49 for _, file := range files { 50 if filepath.Ext(file) != ".go" { 51 continue 52 } 53 if match, _ := filepath.Match("*_test.go", filepath.Base(file)); match { 54 continue 55 } 56 57 astf, err := parser.ParseFile(fset, file, LoadFile(file), 0) 58 if err != nil { 59 return nil, err 60 } 61 astfs = append(astfs, astf) 62 } 63 return 64 } 65 66 func StrcutInfos(src string, pkgname string) (infos []StructInfo, err error) { 67 68 SetupLogger() 69 70 fset := token.NewFileSet() 71 72 //astf, _ := parser.ParseFile(fset, src, LoadFile(src), 0) 73 astfs, err := LoadAstf(path.Dir(src), fset) 74 if err != nil { 75 err = errors.Wrap(err, "parse fail") 76 return 77 } 78 79 conf := types.Config{Importer: importer.For("source", nil), DisableUnusedImportCheck: true} 80 pkg, err := conf.Check(pkgname, fset, astfs, nil) 81 _ = pkg 82 if err != nil { 83 err = errors.Wrap(err, fmt.Sprintf("fail check\n\tastfs=%+v\n\tfset=%+v\n\tpkg=%s\n\n", astfs, fset, spew.Sdump(pkg))) 84 return 85 } 86 87 Logger.Debug("Package info", 88 zap.String("Package", pkg.Path()), 89 zap.String("Name", pkg.Name()), 90 zap.Reflect("Imports", pkg.Imports()), 91 zap.Strings("Scope.Names", pkg.Scope().Names()), 92 zap.String("Scope", pkg.Scope().String())) 93 94 scope := pkg.Scope() 95 96 for _, name := range scope.Names() { 97 obj := scope.Lookup(name) 98 _ = obj 99 100 internal, found_struct := obj.Type().Underlying().(*types.Struct) 101 if !found_struct { 102 continue 103 } 104 sinfo := StructInfo{ 105 PkgName: pkgname, 106 Name: obj.Name(), 107 //Fields: map[string]string{}, 108 } 109 for i := 0; i < internal.NumFields(); i++ { 110 f := internal.Field(i) 111 if !f.IsField() { 112 continue 113 } 114 if f.Embedded() { 115 sinfo.Embedded = append(sinfo.Embedded, f.Name()) 116 } else { 117 //sinfo.Fields[f.Name()] = f.Type().String() 118 sinfo.Fields = append(sinfo.Fields, FieldInfo{Name: f.Name(), Type: f.Type().String()}) 119 } 120 } 121 Logger.Debug("Object", 122 zap.String("Object", spew.Sdump(obj)), 123 zap.String("Type", spew.Sdump(obj.Type())), 124 zap.String("Field: %s\n", spew.Sdump(sinfo.Fields))) 125 infos = append(infos, sinfo) 126 } 127 return 128 } 129 130 func LoadFile(src string) string { 131 data, _ := ioutil.ReadFile(src) 132 return string(data) 133 } 134 135 func Dump(s io.Writer, fset *token.FileSet, d ast.Decl) { 136 ast.Fprint(s, fset, d, ast.NotNilFilter) 137 fmt.Fprint(s, "\n") 138 139 } 140 141 func (info StructInfo) FromTemplate(path string) (out string, err error) { 142 tmpStr := LoadFile(path) 143 144 t := template.Must(template.New("info").Parse(tmpStr)) 145 s := &strings.Builder{} 146 err = t.Execute(s, info) 147 out = s.String() 148 return 149 }