github.com/osievert/jfrog-cli-core@v1.2.7/artifactory/utils/argsutils.go (about) 1 package utils 2 3 import ( 4 "errors" 5 "fmt" 6 "strconv" 7 "strings" 8 9 "github.com/jfrog/jfrog-client-go/utils/errorutils" 10 "github.com/mattn/go-shellwords" 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 // Boolean flag can be provided in one of the following forms: 60 // 1. --flag=value, where value can be true/false 61 // 2. --flag, here the value is true 62 // Return values: 63 // flagIndex - index of flagName in args. 64 // flagValue - value of flagName. 65 // err - error if flag exists, but we failed to extract its value. 66 // If flag does not exist flagIndex = -1 with false value and nil error. 67 func FindBooleanFlag(flagName string, args []string) (flagIndex int, flagValue bool, err error) { 68 var arg string 69 for flagIndex, arg = range args { 70 if strings.HasPrefix(arg, flagName) { 71 value := strings.TrimPrefix(arg, flagName) 72 if len(value) == 0 { 73 flagValue = true 74 } else if strings.HasPrefix(value, "=") { 75 flagValue, err = strconv.ParseBool(value[1:]) 76 } else { 77 continue 78 } 79 return 80 } 81 } 82 return -1, false, nil 83 } 84 85 // Get the provided flag's value, and the index of the value. 86 // Value-index can either be same as flag's index, or the next one. 87 // Return error if flag is found, but couldn't extract value. 88 // If the provided index doesn't contain the searched flag, return flagIndex = -1. 89 func getFlagValueAndValueIndex(flagName string, args []string, flagIndex int) (flagValue string, flagValueIndex int, err error) { 90 indexValue := args[flagIndex] 91 92 // Check if flag is in form '--key=value' 93 indexValue = strings.TrimPrefix(indexValue, flagName) 94 if strings.HasPrefix(indexValue, "=") { 95 if len(indexValue) > 1 { 96 return indexValue[1:], flagIndex, nil 97 } 98 return "", -1, errorutils.CheckError(errors.New(fmt.Sprintf("Flag %s is provided with empty value.", flagName))) 99 } 100 101 // Check if it is a different flag with same prefix, e.g --server-id-another 102 if len(indexValue) > 0 { 103 return "", -1, nil 104 } 105 106 // If reached here, expect the flag value in next argument. 107 if len(args) < flagIndex+2 { 108 // Flag value does not exist. 109 return "", -1, errorutils.CheckError(errors.New(fmt.Sprintf("Failed extracting value of provided flag: %s.", flagName))) 110 } 111 112 nextIndexValue := args[flagIndex+1] 113 // Don't allow next value to be a flag. 114 if strings.HasPrefix(nextIndexValue, "-") { 115 // Flag value does not exist. 116 return "", -1, errorutils.CheckError(errors.New(fmt.Sprintf("Failed extracting value of provided flag: %s.", flagName))) 117 } 118 119 return nextIndexValue, flagIndex + 1, nil 120 } 121 122 // Find the first match of any of the provided flags in args. 123 // Return same values as FindFlag. 124 func FindFlagFirstMatch(flags, args []string) (flagIndex, flagValueIndex int, flagValue string, err error) { 125 // Look for provided flags. 126 for _, flag := range flags { 127 flagIndex, flagValueIndex, flagValue, err = FindFlag(flag, args) 128 if err != nil { 129 return 130 } 131 if flagIndex != -1 { 132 // Found value for flag. 133 return 134 } 135 } 136 return 137 } 138 139 func ExtractBuildDetailsFromArgs(args []string) (cleanArgs []string, buildConfig *BuildConfiguration, err error) { 140 var flagIndex, valueIndex int 141 buildConfig = &BuildConfiguration{} 142 cleanArgs = append([]string(nil), args...) 143 144 // Extract build-info information from the args. 145 flagIndex, valueIndex, buildConfig.BuildName, err = FindFlag("--build-name", cleanArgs) 146 if err != nil { 147 return 148 } 149 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 150 151 flagIndex, valueIndex, buildConfig.BuildNumber, err = FindFlag("--build-number", cleanArgs) 152 if err != nil { 153 return 154 } 155 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 156 157 // Retrieve build name and build number from env if both missing 158 buildConfig.BuildName, buildConfig.BuildNumber = GetBuildNameAndNumber(buildConfig.BuildName, buildConfig.BuildNumber) 159 flagIndex, valueIndex, buildConfig.Module, err = FindFlag("--module", cleanArgs) 160 if err != nil { 161 return 162 } 163 RemoveFlagFromCommand(&cleanArgs, flagIndex, valueIndex) 164 err = ValidateBuildAndModuleParams(buildConfig) 165 return 166 } 167 168 func ExtractInsecureTlsFromArgs(args []string) (cleanArgs []string, insecureTls bool, err error) { 169 cleanArgs = append([]string(nil), args...) 170 171 flagIndex, insecureTls, err := FindBooleanFlag("--insecure-tls", args) 172 if err != nil { 173 return 174 } 175 RemoveFlagFromCommand(&cleanArgs, flagIndex, flagIndex) 176 return 177 } 178 179 // Iterate over each argument, if env variable is found (e.g $HOME) replace it with env value. 180 func ParseArgs(args []string) ([]string, error) { 181 // Escape backslash & space 182 for i := 0; i < len(args); i++ { 183 args[i] = strings.ReplaceAll(args[i], `\`, `\\`) 184 if strings.Index(args[i], ` `) != -1 && !isQuote(args[i]) { 185 args[i] = strings.ReplaceAll(args[i], `"`, ``) 186 args[i] = strings.ReplaceAll(args[i], `'`, ``) 187 args[i] = `"` + args[i] + `"` 188 } 189 } 190 parser := shellwords.NewParser() 191 parser.ParseEnv = true 192 return parser.Parse(strings.Join(args, " ")) 193 } 194 195 func isQuote(s string) bool { 196 return len(s) > 0 && ((s[0] == '"' && s[len(s)-1] == '"') || (s[0] == '\'' && s[len(s)-1] == '\'')) 197 }