github.com/jfrog/jfrog-cli-core/v2@v2.52.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 return extractStringOptionFromArgs(args, "server-id") 142 } 143 144 func ExtractThreadsFromArgs(args []string, defaultValue int) (cleanArgs []string, threads int, err error) { 145 cleanArgs = append([]string(nil), args...) 146 threads = defaultValue 147 // Extract threads information from the args. 148 flagIndex, valueIndex, numOfThreads, err := FindFlag("--threads", cleanArgs) 149 if err != nil { 150 return 151 } 152 153 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 154 if numOfThreads != "" { 155 threads, err = strconv.Atoi(numOfThreads) 156 if err != nil { 157 err = errorutils.CheckError(err) 158 } 159 } 160 return 161 } 162 163 func ExtractInsecureTlsFromArgs(args []string) (cleanArgs []string, insecureTls bool, err error) { 164 return extractBoolOptionFromArgs(args, "insecure-tls") 165 } 166 167 // Used by docker 168 func ExtractSkipLoginFromArgs(args []string) (cleanArgs []string, skipLogin bool, err error) { 169 return extractBoolOptionFromArgs(args, "skip-login") 170 } 171 172 // Used by docker 173 func ExtractFailFromArgs(args []string) (cleanArgs []string, fail bool, err error) { 174 return extractBoolOptionFromArgs(args, "fail") 175 } 176 177 // Used by docker scan (Xray) 178 func ExtractLicensesFromArgs(args []string) (cleanArgs []string, licenses bool, err error) { 179 return extractBoolOptionFromArgs(args, "licenses") 180 } 181 182 // Used by docker scan (Xray) 183 func ExtractRepoPathFromArgs(args []string) (cleanArgs []string, repoPath string, err error) { 184 return extractStringOptionFromArgs(args, "repo-path") 185 } 186 187 // Used by docker scan (Xray) 188 func ExtractWatchesFromArgs(args []string) (cleanArgs []string, watches string, err error) { 189 return extractStringOptionFromArgs(args, "watches") 190 } 191 192 func ExtractDetailedSummaryFromArgs(args []string) (cleanArgs []string, detailedSummary bool, err error) { 193 return extractBoolOptionFromArgs(args, "detailed-summary") 194 } 195 196 func ExtractXrayScanFromArgs(args []string) (cleanArgs []string, xrayScan bool, err error) { 197 return extractBoolOptionFromArgs(args, "scan") 198 } 199 200 func ExtractXrayOutputFormatFromArgs(args []string) (cleanArgs []string, format string, err error) { 201 return extractStringOptionFromArgs(args, "format") 202 } 203 204 func ExtractTagFromArgs(args []string) (cleanArgs []string, tag string, err error) { 205 return extractStringOptionFromArgs(args, "tag") 206 } 207 208 func extractStringOptionFromArgs(args []string, optionName string) (cleanArgs []string, value string, err error) { 209 cleanArgs = append([]string(nil), args...) 210 211 flagIndex, valIndex, value, err := FindFlag("--"+optionName, cleanArgs) 212 if err != nil { 213 return 214 } 215 RemoveFlagFromCommand(&cleanArgs, flagIndex, valIndex) 216 return 217 } 218 219 func extractBoolOptionFromArgs(args []string, optionName string) (cleanArgs []string, value bool, err error) { 220 cleanArgs = append([]string(nil), args...) 221 222 flagIndex, value, err := FindBooleanFlag("--"+optionName, cleanArgs) 223 if err != nil { 224 return 225 } 226 // Since boolean flag might appear as --flag or --flag=value, the value index is the same as the flag index. 227 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 228 return 229 } 230 231 // Add green color style to the string if possible. 232 func PrintTitle(str string) string { 233 return colorStr(str, color.Green) 234 } 235 236 // Add cyan color style to the string if possible. 237 func PrintLink(str string) string { 238 return colorStr(str, color.Cyan) 239 } 240 241 // Add bold style to the string if possible. 242 func PrintBold(str string) string { 243 return colorStr(str, color.Bold) 244 } 245 246 // Add bold and green style to the string if possible. 247 func PrintBoldTitle(str string) string { 248 return PrintBold(PrintTitle(str)) 249 } 250 251 // Add gray color style to the string if possible. 252 func PrintComment(str string) string { 253 return colorStr(str, color.Gray) 254 } 255 256 // Add yellow color style to the string if possible. 257 func PrintYellow(str string) string { 258 return colorStr(str, color.Yellow) 259 } 260 261 // Add the requested style to the string if possible. 262 func colorStr(str string, c color.Color) string { 263 // Add styles only on supported terminals 264 if log.IsStdOutTerminal() && log.IsColorsSupported() { 265 return c.Render(str) 266 } 267 // Remove emojis from non-supported terminals 268 if gomoji.ContainsEmoji(str) { 269 str = gomoji.RemoveEmojis(str) 270 } 271 return str 272 } 273 274 // Remove emojis from non-supported terminals 275 func RemoveEmojisIfNonSupportedTerminal(msg string) string { 276 if !(log.IsStdOutTerminal() && log.IsColorsSupported()) { 277 if gomoji.ContainsEmoji(msg) { 278 msg = gomoji.RemoveEmojis(msg) 279 } 280 } 281 return msg 282 }