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 }