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  }