github.com/hellobchain/third_party@v0.0.0-20230331131523-deb0478a2e52/hyperledger/fabric/common/metrics/gendoc/options.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package gendoc 8 9 import ( 10 "fmt" 11 "go/ast" 12 "path" 13 "reflect" 14 "strconv" 15 "strings" 16 17 "github.com/hellobchain/third_party/hyperledger/fabric/common/metrics" 18 "golang.org/x/tools/go/packages" 19 ) 20 21 // Options scans the provided list of packages for options structs used when 22 // creating metrics and returns instances that are recreated from the source 23 // tree. 24 func Options(pkgs []*packages.Package) ([]interface{}, error) { 25 var options []interface{} 26 for _, p := range pkgs { 27 for _, f := range p.Syntax { 28 opts, err := FileOptions(f) 29 if err != nil { 30 return nil, err 31 } 32 options = append(options, opts...) 33 } 34 } 35 return options, nil 36 } 37 38 // FileOptions walks the specified ast.File for options structs used when 39 // creating metrics and returns instances that are recreated from the source. 40 func FileOptions(f *ast.File) ([]interface{}, error) { 41 var imports = walkImports(f) 42 var options []interface{} 43 var errors []error 44 45 // If the file contains gendoc:ignore, ignore the file 46 for _, c := range f.Comments { 47 if strings.Index(c.Text(), "gendoc:ignore") != -1 { 48 return nil, nil 49 } 50 } 51 52 // Iterate over declarations 53 for i := range f.Decls { 54 ast.Inspect(f.Decls[i], func(x ast.Node) bool { 55 node, ok := x.(*ast.ValueSpec) 56 if !ok { 57 return true 58 } 59 60 for _, v := range node.Values { 61 value, ok := v.(*ast.CompositeLit) 62 if !ok { 63 continue 64 } 65 literalType, ok := value.Type.(*ast.SelectorExpr) 66 if !ok { 67 continue 68 } 69 ident, ok := literalType.X.(*ast.Ident) 70 if !ok { 71 continue 72 } 73 if imports[ident.Name] != "github.com/hellobchain/newcryptosm/metrics" { 74 continue 75 } 76 option, err := createOption(literalType) 77 if err != nil { 78 errors = append(errors, err) 79 break 80 } 81 option, err = populateOption(value, option) 82 if err != nil { 83 errors = append(errors, err) 84 break 85 } 86 options = append(options, option) 87 } 88 return false 89 }) 90 } 91 92 if len(errors) != 0 { 93 return nil, errors[0] 94 } 95 96 return options, nil 97 } 98 99 func walkImports(f *ast.File) map[string]string { 100 imports := map[string]string{} 101 102 for i := range f.Imports { 103 ast.Inspect(f.Imports[i], func(x ast.Node) bool { 104 switch node := x.(type) { 105 case *ast.ImportSpec: 106 importPath, err := strconv.Unquote(node.Path.Value) 107 if err != nil { 108 panic(err) 109 } 110 importName := path.Base(importPath) 111 if node.Name != nil { 112 importName = node.Name.Name 113 } 114 imports[importName] = importPath 115 return false 116 117 default: 118 return true 119 } 120 }) 121 } 122 123 return imports 124 } 125 126 func createOption(lit *ast.SelectorExpr) (interface{}, error) { 127 optionName := lit.Sel.Name 128 switch optionName { 129 case "CounterOpts": 130 return &metrics.CounterOpts{}, nil 131 case "GaugeOpts": 132 return &metrics.GaugeOpts{}, nil 133 case "HistogramOpts": 134 return &metrics.HistogramOpts{}, nil 135 default: 136 return nil, fmt.Errorf("unknown object type: %s", optionName) 137 } 138 } 139 140 func populateOption(lit *ast.CompositeLit, target interface{}) (interface{}, error) { 141 val := reflect.ValueOf(target).Elem() 142 for _, elem := range lit.Elts { 143 if kv, ok := elem.(*ast.KeyValueExpr); ok { 144 name := kv.Key.(*ast.Ident).Name 145 field := val.FieldByName(name) 146 147 switch name { 148 // ignored 149 case "Buckets": 150 151 // slice of strings 152 case "LabelNames": 153 labelNames, err := stringSlice(kv.Value.(*ast.CompositeLit)) 154 if err != nil { 155 return nil, err 156 } 157 labelNamesValue := reflect.ValueOf(labelNames) 158 field.Set(labelNamesValue) 159 160 // simple strings 161 case "Namespace", "Subsystem", "Name", "Help", "StatsdFormat": 162 basicVal := kv.Value.(*ast.BasicLit) 163 val, err := strconv.Unquote(basicVal.Value) 164 if err != nil { 165 return nil, err 166 } 167 field.SetString(val) 168 169 default: 170 return nil, fmt.Errorf("unknown field name: %s", name) 171 } 172 } 173 } 174 return val.Interface(), nil 175 } 176 177 func stringSlice(lit *ast.CompositeLit) ([]string, error) { 178 var slice []string 179 180 for _, elem := range lit.Elts { 181 val, err := strconv.Unquote(elem.(*ast.BasicLit).Value) 182 if err != nil { 183 return nil, err 184 } 185 slice = append(slice, val) 186 } 187 188 return slice, nil 189 }