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