代码拉取完成,页面将自动刷新
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package gendoc
import (
"fmt"
"go/ast"
"path"
"reflect"
"strconv"
"strings"
"github.com/hyperledger/fabric/common/metrics"
"golang.org/x/tools/go/packages"
)
// Options scans the provided list of packages for options structs used when
// creating metrics and returns instances that are recreated from the source
// tree.
func Options(pkgs []*packages.Package) ([]interface{}, error) {
var options []interface{}
for _, p := range pkgs {
for _, f := range p.Syntax {
opts, err := FileOptions(f)
if err != nil {
return nil, err
}
options = append(options, opts...)
}
}
return options, nil
}
// FileOptions walks the specified ast.File for options structs used when
// creating metrics and returns instances that are recreated from the source.
func FileOptions(f *ast.File) ([]interface{}, error) {
var imports = walkImports(f)
var options []interface{}
var errors []error
// If the file contains gendoc:ignore, ignore the file
for _, c := range f.Comments {
if strings.Index(c.Text(), "gendoc:ignore") != -1 {
return nil, nil
}
}
// Iterate over declarations
for i := range f.Decls {
ast.Inspect(f.Decls[i], func(x ast.Node) bool {
node, ok := x.(*ast.ValueSpec)
if !ok {
return true
}
for _, v := range node.Values {
value, ok := v.(*ast.CompositeLit)
if !ok {
continue
}
literalType, ok := value.Type.(*ast.SelectorExpr)
if !ok {
continue
}
ident, ok := literalType.X.(*ast.Ident)
if !ok {
continue
}
if imports[ident.Name] != "github.com/hyperledger/fabric/common/metrics" {
continue
}
option, err := createOption(literalType)
if err != nil {
errors = append(errors, err)
break
}
option, err = populateOption(value, option)
if err != nil {
errors = append(errors, err)
break
}
options = append(options, option)
}
return false
})
}
if len(errors) != 0 {
return nil, errors[0]
}
return options, nil
}
func walkImports(f *ast.File) map[string]string {
imports := map[string]string{}
for i := range f.Imports {
ast.Inspect(f.Imports[i], func(x ast.Node) bool {
switch node := x.(type) {
case *ast.ImportSpec:
importPath, err := strconv.Unquote(node.Path.Value)
if err != nil {
panic(err)
}
importName := path.Base(importPath)
if node.Name != nil {
importName = node.Name.Name
}
imports[importName] = importPath
return false
default:
return true
}
})
}
return imports
}
func createOption(lit *ast.SelectorExpr) (interface{}, error) {
optionName := lit.Sel.Name
switch optionName {
case "CounterOpts":
return &metrics.CounterOpts{}, nil
case "GaugeOpts":
return &metrics.GaugeOpts{}, nil
case "HistogramOpts":
return &metrics.HistogramOpts{}, nil
default:
return nil, fmt.Errorf("unknown object type: %s", optionName)
}
}
func populateOption(lit *ast.CompositeLit, target interface{}) (interface{}, error) {
val := reflect.ValueOf(target).Elem()
for _, elem := range lit.Elts {
if kv, ok := elem.(*ast.KeyValueExpr); ok {
name := kv.Key.(*ast.Ident).Name
field := val.FieldByName(name)
switch name {
// ignored
case "Buckets":
// slice of strings
case "LabelNames":
labelNames, err := stringSlice(kv.Value.(*ast.CompositeLit))
if err != nil {
return nil, err
}
labelNamesValue := reflect.ValueOf(labelNames)
field.Set(labelNamesValue)
// simple strings
case "Namespace", "Subsystem", "Name", "Help", "StatsdFormat":
basicVal := kv.Value.(*ast.BasicLit)
val, err := strconv.Unquote(basicVal.Value)
if err != nil {
return nil, err
}
field.SetString(val)
default:
return nil, fmt.Errorf("unknown field name: %s", name)
}
}
}
return val.Interface(), nil
}
func stringSlice(lit *ast.CompositeLit) ([]string, error) {
var slice []string
for _, elem := range lit.Elts {
val, err := strconv.Unquote(elem.(*ast.BasicLit).Value)
if err != nil {
return nil, err
}
slice = append(slice, val)
}
return slice, nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。