go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/descriptor-adapter/generator.go (about) 1 // Copyright (c) 2018 Cisco and/or its affiliates. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at: 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // descriptor-generator generates all boiler-plate code needed to adapt type-safe 16 // KV descriptor for the KVDescriptor structure definition. 17 // 18 // To use the generator, add go generate command into your descriptor as a comment: 19 // //go:generate descriptor-adapter --descriptor-name <descriptor-name> --value-type <typename> [--meta-type <typename>] [--output-dir <path>] [--import <path>]... 20 // 21 // Note: import paths can be relative to the file with the go:generate comment. 22 23 package main 24 25 import ( 26 "bytes" 27 "flag" 28 "fmt" 29 "os" 30 "path/filepath" 31 "strings" 32 "text/template" 33 ) 34 35 // ArrayFlag implements repeated flag. 36 type ArrayFlag struct { 37 values []string 38 } 39 40 // String return human-readable string representation of the array of flags. 41 func (af *ArrayFlag) String() string { 42 str := "[" 43 for idx, value := range af.values { 44 str += value 45 if idx < len(af.values)-1 { 46 str += ", " 47 } 48 } 49 str += "]" 50 return str 51 } 52 53 // Set add value into the array. 54 func (af *ArrayFlag) Set(value string) error { 55 af.values = append(af.values, value) 56 return nil 57 } 58 59 var ( 60 imports ArrayFlag 61 62 outputDirFlag = flag.String("output-dir", ".", "Output directory where adapter package will be generated.") 63 descriptorNameFlag = flag.String("descriptor-name", "", "Name of the descriptor.") 64 valueTypeFlag = flag.String("value-type", "", "Type of the described values.") 65 metaTypeFlag = flag.String("meta-type", "interface{}", "Type of the metadata used by the descriptor.") 66 ) 67 68 // TemplateData encapsulates input arguments for the template. 69 type TemplateData struct { 70 DescriptorName string 71 ValueT string 72 MetadataT string 73 Imports []string 74 } 75 76 // PathExists return true if the given path already exist in the file system. 77 func PathExists(path string) bool { 78 _, err := os.Stat(path) 79 return !os.IsNotExist(err) 80 } 81 82 func main() { 83 flag.Var(&imports, "import", "Package to be imported in the generated adapter (can be relative path).") 84 flag.Parse() 85 86 // prepare input data for the template 87 inputData := TemplateData{ 88 DescriptorName: *descriptorNameFlag, 89 ValueT: *valueTypeFlag, 90 MetadataT: *metaTypeFlag, 91 } 92 93 // expand relative import paths 94 gopath := os.Getenv("GOPATH") 95 cwd, err := os.Getwd() 96 if err != nil { 97 fmt.Fprintln(os.Stderr, "ERROR: ", err) 98 os.Exit(2) 99 } 100 101 for _, importPath := range imports.values { 102 if !PathExists(filepath.Join(gopath, "src", importPath)) { 103 asRelative := filepath.Join(cwd, importPath) 104 if PathExists(asRelative) { 105 importPath = filepath.Clean(asRelative) 106 importPath = strings.TrimPrefix(importPath, gopath+"/src") 107 importPath = strings.TrimLeft(importPath, "/") 108 } 109 } 110 inputData.Imports = append(inputData.Imports, importPath) 111 } 112 113 if inputData.ValueT == "" || inputData.DescriptorName == "" { 114 fmt.Fprintln(os.Stderr, "ERROR: value-type and descriptor-name must be specified") 115 os.Exit(1) 116 } 117 118 // generate adapter source code from the template 119 var buf bytes.Buffer 120 t := template.Must(template.New("").Parse(adapterTemplate)) 121 err = t.Execute(&buf, inputData) 122 if err != nil { 123 fmt.Fprintln(os.Stderr, "ERROR: ", err) 124 os.Exit(2) 125 } 126 127 // prepare directory for the generated adapter 128 directory := *outputDirFlag + "/adapter/" 129 err = os.MkdirAll(directory, 0777) 130 if err != nil { 131 fmt.Fprintln(os.Stderr, "ERROR: ", err) 132 os.Exit(3) 133 } 134 135 // output the generated adapter into the file 136 filename := directory + "/" + strings.ToLower(*descriptorNameFlag) + ".go" 137 err = os.WriteFile(filename, buf.Bytes(), 0644) 138 if err != nil { 139 fmt.Fprintln(os.Stderr, "ERROR: ", err) 140 os.Exit(4) 141 } 142 }