github.com/jfrog/jfrog-cli-core/v2@v2.51.0/utils/coreutils/cmdutils.go (about) 1 package coreutils 2 3 import ( 4 "github.com/forPelevin/gomoji" 5 "github.com/jfrog/jfrog-client-go/utils/log" 6 "strconv" 7 "strings" 8 9 "github.com/gookit/color" 10 "github.com/jfrog/jfrog-client-go/utils/errorutils" 11 ) 12 13 // Removes the provided flag and value from the command arguments 14 func RemoveFlagFromCommand(args *[]string, flagIndex, flagValueIndex int) { 15 argsCopy := *args 16 // Remove flag from Command if required. 17 if flagIndex != -1 { 18 argsCopy = append(argsCopy[:flagIndex], argsCopy[flagValueIndex+1:]...) 19 } 20 *args = argsCopy 21 } 22 23 // Find value of required CLI flag in Command. 24 // If flag does not exist, the returned index is -1 and nil is returned as the error. 25 // Return values: 26 // err - error if flag exists but failed to extract its value. 27 // flagIndex - index of flagName in Command. 28 // flagValueIndex - index in Command in which the value of the flag exists. 29 // flagValue - value of flagName. 30 func FindFlag(flagName string, args []string) (flagIndex, flagValueIndex int, flagValue string, err error) { 31 flagIndex = -1 32 flagValueIndex = -1 33 for index, arg := range args { 34 // Check current argument. 35 if !strings.HasPrefix(arg, flagName) { 36 continue 37 } 38 39 // Get flag value. 40 flagValue, flagValueIndex, err = getFlagValueAndValueIndex(flagName, args, index) 41 if err != nil { 42 return 43 } 44 45 // If was not the correct flag, continue looking. 46 if flagValueIndex == -1 { 47 continue 48 } 49 50 // Return value. 51 flagIndex = index 52 return 53 } 54 55 // Flag not found. 56 return 57 } 58 59 // Get the provided flag's value, and the index of the value. 60 // Value-index can either be same as flag's index, or the next one. 61 // Return error if flag is found, but couldn't extract value. 62 // If the provided index doesn't contain the searched flag, return flagIndex = -1. 63 func getFlagValueAndValueIndex(flagName string, args []string, flagIndex int) (flagValue string, flagValueIndex int, err error) { 64 indexValue := args[flagIndex] 65 66 // Check if flag is in form '--key=value' 67 indexValue = strings.TrimPrefix(indexValue, flagName) 68 if strings.HasPrefix(indexValue, "=") { 69 if len(indexValue) > 1 { 70 return indexValue[1:], flagIndex, nil 71 } 72 return "", -1, errorutils.CheckErrorf("Flag %s is provided with empty value.", flagName) 73 } 74 75 // Check if it is a different flag with same prefix, e.g --server-id-another 76 if len(indexValue) > 0 { 77 return "", -1, nil 78 } 79 80 // If reached here, expect the flag value in next argument. 81 if len(args) < flagIndex+2 { 82 // Flag value does not exist. 83 return "", -1, errorutils.CheckErrorf("Failed extracting value of provided flag: %s.", flagName) 84 } 85 86 nextIndexValue := args[flagIndex+1] 87 // Don't allow next value to be a flag. 88 if strings.HasPrefix(nextIndexValue, "-") { 89 // Flag value does not exist. 90 return "", -1, errorutils.CheckErrorf("Failed extracting value of provided flag: %s.", flagName) 91 } 92 93 return nextIndexValue, flagIndex + 1, nil 94 } 95 96 // Boolean flag can be provided in one of the following forms: 97 // 1. --flag=value, where value can be true/false 98 // 2. --flag, here the value is true 99 // Return values: 100 // flagIndex - index of flagName in args. 101 // flagValue - value of flagName. 102 // err - error if flag exists, but we failed to extract its value. 103 // If flag does not exist flagIndex = -1 with false value and nil error. 104 func FindBooleanFlag(flagName string, args []string) (flagIndex int, flagValue bool, err error) { 105 var arg string 106 for flagIndex, arg = range args { 107 if strings.HasPrefix(arg, flagName) { 108 value := strings.TrimPrefix(arg, flagName) 109 switch { 110 case len(value) == 0: 111 flagValue = true 112 case strings.HasPrefix(value, "="): 113 flagValue, err = strconv.ParseBool(value[1:]) 114 default: 115 continue 116 } 117 return 118 } 119 } 120 return -1, false, nil 121 } 122 123 // Find the first match of the provided flags in args. 124 // Return same values as FindFlag. 125 func FindFlagFirstMatch(flags, args []string) (flagIndex, flagValueIndex int, flagValue string, err error) { 126 // Look for provided flags. 127 for _, flag := range flags { 128 flagIndex, flagValueIndex, flagValue, err = FindFlag(flag, args) 129 if err != nil { 130 return 131 } 132 if flagIndex != -1 { 133 // Found value for flag. 134 return 135 } 136 } 137 return 138 } 139 140 func ExtractServerIdFromCommand(args []string) (cleanArgs []string, serverId string, err error) { 141 cleanArgs = append([]string(nil), args...) 142 143 // Get --server-id flag value from the command, and remove it. 144 flagIndex, valueIndex, serverId, err := FindFlag("--server-id", cleanArgs) 145 if err != nil { 146 return nil, "", err 147 } 148 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 149 return 150 } 151 152 func ExtractThreadsFromArgs(args []string, defaultValue int) (cleanArgs []string, threads int, err error) { 153 cleanArgs = append([]string(nil), args...) 154 threads = defaultValue 155 // Extract threads information from the args. 156 flagIndex, valueIndex, numOfThreads, err := FindFlag("--threads", cleanArgs) 157 if err != nil { 158 return 159 } 160 161 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 162 if numOfThreads != "" { 163 threads, err = strconv.Atoi(numOfThreads) 164 if err != nil { 165 err = errorutils.CheckError(err) 166 } 167 } 168 return 169 } 170 171 func ExtractInsecureTlsFromArgs(args []string) (cleanArgs []string, insecureTls bool, err error) { 172 cleanArgs = append([]string(nil), args...) 173 174 flagIndex, insecureTls, err := FindBooleanFlag("--insecure-tls", args) 175 if err != nil { 176 return 177 } 178 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 179 return 180 } 181 182 // Used by docker 183 func ExtractSkipLoginFromArgs(args []string) (cleanArgs []string, skipLogin bool, err error) { 184 cleanArgs = append([]string(nil), args...) 185 186 flagIndex, skipLogin, err := FindBooleanFlag("--skip-login", cleanArgs) 187 if err != nil { 188 return 189 } 190 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 191 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 192 return 193 } 194 195 // Used by docker 196 func ExtractFailFromArgs(args []string) (cleanArgs []string, fail bool, err error) { 197 cleanArgs = append([]string(nil), args...) 198 199 flagIndex, fail, err := FindBooleanFlag("--fail", cleanArgs) 200 if err != nil { 201 return 202 } 203 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 204 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 205 return 206 } 207 208 // Used by docker scan (Xray) 209 func ExtractLicensesFromArgs(args []string) (cleanArgs []string, licenses bool, err error) { 210 cleanArgs = append([]string(nil), args...) 211 212 flagIndex, licenses, err := FindBooleanFlag("--licenses", cleanArgs) 213 if err != nil { 214 return 215 } 216 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 217 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 218 return 219 } 220 221 // Used by docker scan (Xray) 222 func ExtractRepoPathFromArgs(args []string) (cleanArgs []string, repoPath string, err error) { 223 cleanArgs = append([]string(nil), args...) 224 225 flagIndex, valIndex, repoPath, err := FindFlag("--repo-path", cleanArgs) 226 if err != nil { 227 return 228 } 229 RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) 230 return 231 } 232 233 // Used by docker scan (Xray) 234 func ExtractWatchesFromArgs(args []string) (cleanArgs []string, watches string, err error) { 235 cleanArgs = append([]string(nil), args...) 236 237 flagIndex, valIndex, watches, err := FindFlag("--watches", cleanArgs) 238 if err != nil { 239 return 240 } 241 RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) 242 return 243 } 244 245 func ExtractDetailedSummaryFromArgs(args []string) (cleanArgs []string, detailedSummary bool, err error) { 246 cleanArgs = append([]string(nil), args...) 247 248 flagIndex, detailedSummary, err := FindBooleanFlag("--detailed-summary", cleanArgs) 249 if err != nil { 250 return 251 } 252 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 253 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 254 return 255 } 256 257 func ExtractXrayScanFromArgs(args []string) (cleanArgs []string, xrayScan bool, err error) { 258 cleanArgs = append([]string(nil), args...) 259 260 flagIndex, xrayScan, err := FindBooleanFlag("--scan", cleanArgs) 261 if err != nil { 262 return 263 } 264 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 265 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 266 return 267 } 268 269 func ExtractXrayOutputFormatFromArgs(args []string) (cleanArgs []string, format string, err error) { 270 cleanArgs = append([]string(nil), args...) 271 272 flagIndex, valIndex, format, err := FindFlag("--format", cleanArgs) 273 if err != nil { 274 return 275 } 276 RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) 277 return 278 } 279 280 // Add green color style to the string if possible. 281 func PrintTitle(str string) string { 282 return colorStr(str, color.Green) 283 } 284 285 // Add cyan color style to the string if possible. 286 func PrintLink(str string) string { 287 return colorStr(str, color.Cyan) 288 } 289 290 // Add bold style to the string if possible. 291 func PrintBold(str string) string { 292 return colorStr(str, color.Bold) 293 } 294 295 // Add bold and green style to the string if possible. 296 func PrintBoldTitle(str string) string { 297 return PrintBold(PrintTitle(str)) 298 } 299 300 // Add gray color style to the string if possible. 301 func PrintComment(str string) string { 302 return colorStr(str, color.Gray) 303 } 304 305 // Add yellow color style to the string if possible. 306 func PrintYellow(str string) string { 307 return colorStr(str, color.Yellow) 308 } 309 310 // Add the requested style to the string if possible. 311 func colorStr(str string, c color.Color) string { 312 // Add styles only on supported terminals 313 if log.IsStdOutTerminal() && log.IsColorsSupported() { 314 return c.Render(str) 315 } 316 // Remove emojis from non-supported terminals 317 if gomoji.ContainsEmoji(str) { 318 str = gomoji.RemoveEmojis(str) 319 } 320 return str 321 } 322 323 // Remove emojis from non-supported terminals 324 func RemoveEmojisIfNonSupportedTerminal(msg string) string { 325 if !(log.IsStdOutTerminal() && log.IsColorsSupported()) { 326 if gomoji.ContainsEmoji(msg) { 327 msg = gomoji.RemoveEmojis(msg) 328 } 329 } 330 return msg 331 }