github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/pkg/bindings/generator/generator.go (about) 1 //go:build ignore 2 // +build ignore 3 4 package main 5 6 // This program generates *_options_.go files to be used by the bindings calls to API service. 7 // It can be invoked by running go generate 8 9 import ( 10 "errors" 11 "fmt" 12 "go/ast" 13 "go/parser" 14 "go/token" 15 "io/ioutil" 16 "os" 17 "os/exec" 18 "strings" 19 "text/template" 20 "unicode" 21 "unicode/utf8" 22 ) 23 24 var bodyTmpl = `// Code generated by go generate; DO NOT EDIT. 25 package {{.PackageName}} 26 27 import ( 28 {{range $import := .Imports}} {{$import}} 29 {{end}} 30 ) 31 32 // Changed returns true if named field has been set 33 func (o *{{.StructName}}) Changed(fieldName string) bool { 34 return util.Changed(o, fieldName) 35 } 36 37 // ToParams formats struct fields to be passed to API service 38 func (o *{{.StructName}}) ToParams() (url.Values, error) { 39 return util.ToParams(o) 40 } 41 42 {{range $field := .Fields}} 43 // With{{.Name}} set {{if .Comment}}{{.Comment}}{{else}}field {{.Name}} to given value{{end}} 44 func(o *{{.StructName}}) With{{.Name}}(value {{.Type}}) *{{.StructName}} { 45 o.{{.Name}} = {{if not .Composite}}&{{end}}value 46 return o 47 } 48 49 // Get{{.Name}} returns value of {{if .Comment}}{{.Comment}}{{else}}field {{.Name}}{{end}} 50 func(o *{{.StructName}}) Get{{.Name}}() {{.Type}} { 51 if o.{{.Name}} == nil { 52 var z {{.Type}} 53 return z 54 } 55 return {{if not .Composite}}*{{end}}o.{{.Name}} 56 } 57 {{end}} 58 ` 59 60 type fieldStruct struct { 61 Comment string 62 Composite bool 63 Name string 64 StructName string 65 Type string 66 } 67 68 func main() { 69 var ( 70 closed bool 71 fieldStructs []fieldStruct 72 ) 73 srcFile := os.Getenv("GOFILE") 74 inputStructName := os.Args[1] 75 b, err := ioutil.ReadFile(srcFile) 76 if err != nil { 77 panic(err) 78 } 79 fset := token.NewFileSet() // positions are relative to fset 80 f, err := parser.ParseFile(fset, "", b, parser.ParseComments) 81 if err != nil { 82 panic(err) 83 } 84 85 // always add reflect 86 imports := []string{"\"reflect\"", "\"github.com/hanks177/podman/v4/pkg/bindings/internal/util\""} 87 for _, imp := range f.Imports { 88 imports = append(imports, imp.Path.Value) 89 } 90 91 out, err := os.Create(strings.TrimRight(srcFile, ".go") + "_" + strings.Replace(strings.ToLower(inputStructName), "options", "_options", 1) + ".go") 92 if err != nil { 93 panic(err) 94 } 95 defer func() { 96 if !closed { 97 out.Close() 98 } 99 }() 100 101 body := template.Must(template.New("body").Parse(bodyTmpl)) 102 103 ast.Inspect(f, func(n ast.Node) bool { 104 ref, refOK := n.(*ast.TypeSpec) 105 if !(refOK && ref.Name.Name == inputStructName) { 106 return true 107 } 108 109 x := ref.Type.(*ast.StructType) 110 for _, field := range x.Fields.List { 111 var name string 112 if len(field.Names) > 0 { 113 name = field.Names[0].Name 114 if len(name) < 1 { 115 panic(errors.New("bad name")) 116 } 117 } 118 119 var composite bool 120 switch field.Type.(type) { 121 case *ast.MapType, *ast.StructType, *ast.ArrayType: 122 composite = true 123 } 124 125 //sub := "*" 126 typeExpr := field.Type 127 start := typeExpr.Pos() - 1 128 end := typeExpr.End() - 1 129 fieldType := strings.Replace(string(b[start:end]), "*", "", 1) 130 131 fieldStructs = append(fieldStructs, fieldStruct{ 132 Comment: fmtComment(field.Comment.Text()), 133 Composite: composite, 134 Name: name, 135 StructName: inputStructName, 136 Type: fieldType, 137 }) 138 } // for 139 140 bodyStruct := struct { 141 PackageName string 142 Imports []string 143 StructName string 144 Fields []fieldStruct 145 }{ 146 PackageName: os.Getenv("GOPACKAGE"), 147 Imports: imports, 148 StructName: inputStructName, 149 Fields: fieldStructs, 150 } 151 152 // create the body 153 if err := body.Execute(out, bodyStruct); err != nil { 154 fmt.Println(err) 155 os.Exit(1) 156 } 157 158 // close out file 159 if err := out.Close(); err != nil { 160 fmt.Println(err) 161 os.Exit(1) 162 } 163 closed = true 164 165 // go fmt file 166 gofmt := exec.Command("go", "fmt", out.Name()) 167 gofmt.Stderr = os.Stdout 168 if err := gofmt.Run(); err != nil { 169 fmt.Println(err) 170 os.Exit(1) 171 } 172 173 // go import file 174 goimport := exec.Command("../../../test/tools/build/goimports", "-w", out.Name()) 175 goimport.Stderr = os.Stdout 176 if err := goimport.Run(); err != nil { 177 fmt.Println(err) 178 os.Exit(1) 179 } 180 return true 181 }) 182 } 183 184 func fmtComment(comment string) string { 185 r, n := utf8.DecodeRuneInString(comment) 186 if r != utf8.RuneError { 187 comment = string(unicode.ToLower(r)) + comment[n:] 188 } 189 comment = strings.TrimSpace(comment) 190 return comment 191 }