github.com/Rookout/GoSDK@v0.1.48/pkg/utils/build_flags1.18.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package utils
     5  
     6  import (
     7  	"fmt"
     8  	"github.com/Rookout/GoSDK/pkg/rookoutErrors"
     9  	"runtime/debug"
    10  	"strconv"
    11  	"strings"
    12  )
    13  
    14  const (
    15  	gcflags = "-gcflags"
    16  
    17  	ldflags = "-ldflags"
    18  )
    19  
    20  type packageType int
    21  
    22  const (
    23  	packageTypeNone packageType = iota
    24  	packageTypeAll
    25  	packageTypeElse
    26  )
    27  
    28  func packageNameToType(name string) packageType {
    29  	switch strings.TrimSpace(name) {
    30  	case "":
    31  		return packageTypeNone
    32  	case "all":
    33  		return packageTypeAll
    34  	default:
    35  		return packageTypeElse
    36  	}
    37  }
    38  
    39  type flagMatcher struct {
    40  	flag         string                      
    41  	validPackage map[packageType]interface{} 
    42  	defaultOk    bool                        
    43  	expectedVal  bool                        
    44  }
    45  
    46  type flagRes struct {
    47  	flag      string
    48  	pType     packageType
    49  	isDefault bool
    50  	val       bool
    51  }
    52  
    53  var (
    54  	legalFlags = map[string]map[string]flagMatcher{
    55  		gcflags: {
    56  			"-N":                  {"-N", map[packageType]interface{}{packageTypeAll: nil}, true, true},                  
    57  			"-dwarflocationlists": {"-dwarflocationlists", map[packageType]interface{}{packageTypeAll: nil}, true, true}, 
    58  		},
    59  	}
    60  
    61  	illegalFlags = map[string]map[string]flagMatcher{
    62  		ldflags: {
    63  			"-s": {"-s", map[packageType]interface{}{packageTypeAll: nil}, false, false}, 
    64  			"-w": {"-w", map[packageType]interface{}{packageTypeAll: nil}, false, false}, 
    65  		},
    66  	}
    67  
    68  	parseFlagsCategories = map[string]interface{}{
    69  		gcflags: nil,
    70  		ldflags: nil,
    71  	}
    72  )
    73  
    74  func parseFlag(prevPackageType packageType, packageName *string, flag string, val *string) *flagRes {
    75  	isFlag := func(f string) bool {
    76  		return strings.HasPrefix(f, "-")
    77  	}
    78  	isPackage := func(p string) bool {
    79  		return !isFlag(p)
    80  	}
    81  	currentPackageType := prevPackageType
    82  	if packageName != nil {
    83  		if !isPackage(*packageName) {
    84  			return nil
    85  		}
    86  		currentPackageType = packageNameToType(*packageName)
    87  	}
    88  	if !isFlag(flag) {
    89  		return nil
    90  	}
    91  	if val == nil {
    92  		return &flagRes{flag: flag, pType: currentPackageType, isDefault: true, val: false}
    93  	}
    94  
    95  	boolVal, err := strconv.ParseBool(*val)
    96  	if err != nil {
    97  		return nil
    98  	}
    99  	return &flagRes{flag: flag, pType: currentPackageType, isDefault: false, val: boolVal}
   100  }
   101  
   102  func flagStr2FlagRes(flag string, prevPackageType packageType) (*flagRes, error) {
   103  	splitted := strings.Split(flag, "=")
   104  	var parsed *flagRes = nil
   105  	switch len(splitted) {
   106  	case 1: 
   107  		parsed = parseFlag(prevPackageType, nil, splitted[0], nil)
   108  	case 2: 
   109  		parsed = parseFlag(prevPackageType, &splitted[0], splitted[1], nil)
   110  		if parsed == nil {
   111  			parsed = parseFlag(prevPackageType, nil, splitted[0], &splitted[1])
   112  		}
   113  	case 3: 
   114  		parsed = parseFlag(prevPackageType, &splitted[0], splitted[1], &splitted[2])
   115  	}
   116  	if parsed == nil {
   117  		return nil, fmt.Errorf("flag must be of the form [<PACKAGE>=]-<FLAG>[=<BOOL_VAL>] given %s", flag)
   118  	}
   119  	return parsed, nil
   120  }
   121  
   122  func parseFlagsLine(line string) ([]flagRes, error) {
   123  	prevPackageType := packageTypeNone
   124  	vals := strings.Fields(line)
   125  	res := make([]flagRes, 0, len(vals))
   126  	for _, v := range vals {
   127  		parsed, err := flagStr2FlagRes(v, prevPackageType)
   128  		if err != nil {
   129  			return nil, err
   130  		}
   131  		res = append(res, *parsed)
   132  		prevPackageType = parsed.pType
   133  	}
   134  	return res, nil
   135  }
   136  
   137  func (m flagMatcher) isFlagMatching(flag flagRes) bool {
   138  	if _, ok := m.validPackage[flag.pType]; !ok {
   139  		return false
   140  	}
   141  	if flag.isDefault {
   142  		return m.defaultOk
   143  	}
   144  	return flag.val == m.expectedVal
   145  }
   146  
   147  func validateTrueVals(opts map[string][]flagRes) error {
   148  	for requiredFlag, flagSpec := range legalFlags {
   149  		flags, found := opts[requiredFlag]
   150  		if !found {
   151  			return fmt.Errorf("didn't provide required flag %s", requiredFlag)
   152  		}
   153  		matched := false
   154  		for _, flag := range flags {
   155  			if matcher, ok := flagSpec[flag.flag]; ok {
   156  				if matcher.isFlagMatching(flag) {
   157  					matched = true
   158  					break
   159  				}
   160  			}
   161  		}
   162  		if !matched {
   163  			return fmt.Errorf("didn't provide any of the required flags for %s", requiredFlag)
   164  		}
   165  	}
   166  	return nil
   167  }
   168  
   169  func validateFalseVals(opts map[string][]flagRes) error {
   170  	for optionalFlag, flagSpec := range illegalFlags {
   171  		flags, found := opts[optionalFlag]
   172  		if !found {
   173  			continue
   174  		}
   175  		for _, flag := range flags {
   176  			if matcher, ok := flagSpec[flag.flag]; ok {
   177  				if !matcher.isFlagMatching(flag) {
   178  					return fmt.Errorf("provided illegal value %s for %s", flag.flag, optionalFlag)
   179  				}
   180  			}
   181  		}
   182  	}
   183  	return nil
   184  }
   185  
   186  func GetBuildOpts() (map[string]string, *debug.BuildInfo, error) {
   187  	opts := make(map[string]string)
   188  	info, ok := debug.ReadBuildInfo()
   189  	if !ok {
   190  		return nil, nil, rookoutErrors.NewReadBuildFlagsError()
   191  	}
   192  	for _, setting := range info.Settings {
   193  		opts[setting.Key] = setting.Value
   194  	}
   195  	return opts, info, nil
   196  }
   197  
   198  func ValidateBuildOpts(opts map[string]string) error {
   199  	parsed := make(map[string][]flagRes)
   200  	for optName := range opts {
   201  		if _, ok := parseFlagsCategories[optName]; ok {
   202  			parsedFlags, err := parseFlagsLine(opts[optName])
   203  			if err != nil {
   204  				return err
   205  			}
   206  			parsed[optName] = parsedFlags
   207  		}
   208  	}
   209  
   210  	if err := validateTrueVals(parsed); err != nil {
   211  		return rookoutErrors.NewValidateBuildFlagsError(err)
   212  	}
   213  	if err := validateFalseVals(parsed); err != nil {
   214  		return rookoutErrors.NewValidateBuildFlagsError(err)
   215  	}
   216  	return nil
   217  }