github.com/jfrog/jfrog-cli-go@v1.22.1-0.20200318093948-4826ef344ffd/utils/cliutils/utils.go (about) 1 package cliutils 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "path" 8 "path/filepath" 9 "runtime" 10 "strings" 11 12 "github.com/codegangsta/cli" 13 "github.com/jfrog/jfrog-cli-go/utils/summary" 14 "github.com/jfrog/jfrog-client-go/utils" 15 "github.com/jfrog/jfrog-client-go/utils/errorutils" 16 "github.com/jfrog/jfrog-client-go/utils/io/fileutils" 17 "github.com/jfrog/jfrog-client-go/utils/log" 18 "github.com/pkg/errors" 19 20 clientutils "github.com/jfrog/jfrog-client-go/utils" 21 ) 22 23 // Error modes (how should the application behave when the CheckError function is invoked): 24 type OnError string 25 26 var cliTempDir string 27 var cliUserAgent string 28 29 func init() { 30 // Initialize error handling. 31 if os.Getenv(ErrorHandling) == string(OnErrorPanic) { 32 errorutils.CheckError = PanicOnError 33 } 34 35 // Initialize the temp base-dir path of the CLI executions. 36 cliTempDir = os.Getenv(TempDir) 37 if cliTempDir == "" { 38 cliTempDir = os.TempDir() 39 } 40 fileutils.SetTempDirBase(cliTempDir) 41 42 // Initialize agent name and version. 43 cliUserAgent = os.Getenv(UserAgent) 44 if cliUserAgent == "" { 45 cliUserAgent = ClientAgent + "/" + CliVersion 46 } 47 } 48 49 // Exit codes: 50 type ExitCode struct { 51 Code int 52 } 53 54 var ExitCodeNoError = ExitCode{0} 55 var ExitCodeError = ExitCode{1} 56 var ExitCodeFailNoOp = ExitCode{2} 57 var ExitCodeVulnerableBuild = ExitCode{3} 58 59 type CliError struct { 60 ExitCode 61 ErrorMsg string 62 } 63 64 func (err CliError) Error() string { 65 return err.ErrorMsg 66 } 67 68 func PanicOnError(err error) error { 69 if err != nil { 70 panic(err) 71 } 72 return err 73 } 74 75 func ExitOnErr(err error) { 76 if err, ok := err.(CliError); ok { 77 traceExit(err.ExitCode, err) 78 } 79 if exitCode := GetExitCode(err, 0, 0, false); exitCode != ExitCodeNoError { 80 traceExit(exitCode, err) 81 } 82 } 83 84 func GetCliError(err error, success, failed int, failNoOp bool) error { 85 switch GetExitCode(err, success, failed, failNoOp) { 86 case ExitCodeError: 87 { 88 var errorMessage string 89 if err != nil { 90 errorMessage = err.Error() 91 } 92 return CliError{ExitCodeError, errorMessage} 93 } 94 case ExitCodeFailNoOp: 95 return CliError{ExitCodeFailNoOp, "No errors, but also no files affected (fail-no-op flag)."} 96 default: 97 return nil 98 } 99 } 100 101 func GetExitCode(err error, success, failed int, failNoOp bool) ExitCode { 102 // Error occurred - Return 1 103 if err != nil || failed > 0 { 104 return ExitCodeError 105 } 106 // No errors, but also no files affected - Return 2 if failNoOp 107 if success == 0 && failNoOp { 108 return ExitCodeFailNoOp 109 } 110 // Otherwise - Return 0 111 return ExitCodeNoError 112 } 113 114 func traceExit(exitCode ExitCode, err error) { 115 if err != nil && len(err.Error()) > 0 { 116 log.Error(err) 117 } 118 os.Exit(exitCode.Code) 119 } 120 121 // Print summary report. 122 // The given error will pass through and be returned as is if no other errors are raised. 123 func PrintSummaryReport(success, failed int, err error) error { 124 summaryReport := summary.New(err) 125 summaryReport.Totals.Success = success 126 summaryReport.Totals.Failure = failed 127 if err == nil && summaryReport.Totals.Failure != 0 { 128 summaryReport.Status = summary.Failure 129 } 130 content, mErr := summaryReport.Marshal() 131 if errorutils.CheckError(mErr) != nil { 132 log.Error(mErr) 133 return err 134 } 135 log.Output(utils.IndentJson(content)) 136 return err 137 } 138 139 func PrintHelpAndReturnError(msg string, context *cli.Context) error { 140 log.Error(msg + " " + GetDocumentationMessage()) 141 cli.ShowCommandHelp(context, context.Command.Name) 142 return errors.New(msg) 143 } 144 145 // This function indicates whether the command should be executed without 146 // confirmation warning or not. 147 // If the --quiet option was sent, it is used to determine whether to prompt the confirmation or not. 148 // If not, the command will prompt the confirmation, unless the CI environment variable was set to true. 149 func GetQuietValue(c *cli.Context) bool { 150 if c.IsSet("quiet") { 151 return c.Bool("quiet") 152 } 153 154 return getCiValue() 155 } 156 157 // This function indicates whether the command should be executed in 158 // an interactive mode. 159 // If the --interactive option was sent, it is used to determine the mode. 160 // If not, the mode will be interactive, unless the CI environment variable was set to true. 161 func GetInteractiveValue(c *cli.Context) bool { 162 if c.IsSet("interactive") { 163 return c.BoolT("interactive") 164 } 165 166 return !getCiValue() 167 } 168 169 // Return the true if the CI environment variable was set to true. 170 func getCiValue() bool { 171 var ci bool 172 var err error 173 if ci, err = clientutils.GetBoolEnvValue(CI, false); err != nil { 174 return false 175 } 176 return ci 177 } 178 179 func InteractiveConfirm(message string) bool { 180 var confirm string 181 fmt.Print(message + " (y/n): ") 182 fmt.Scanln(&confirm) 183 return confirmAnswer(confirm) 184 } 185 186 func confirmAnswer(answer string) bool { 187 answer = strings.ToLower(answer) 188 return answer == "y" || answer == "yes" 189 } 190 191 func GetVersion() string { 192 return CliVersion 193 } 194 195 func GetConfigVersion() string { 196 return "1" 197 } 198 199 func GetDocumentationMessage() string { 200 return "You can read the documentation at https://www.jfrog.com/confluence/display/CLI/JFrog+CLI" 201 } 202 203 func SumTrueValues(boolArr []bool) int { 204 counter := 0 205 for _, val := range boolArr { 206 counter += utils.Bool2Int(val) 207 } 208 return counter 209 } 210 211 func SpecVarsStringToMap(rawVars string) map[string]string { 212 if len(rawVars) == 0 { 213 return nil 214 } 215 varCandidates := strings.Split(rawVars, ";") 216 varsList := []string{} 217 for _, v := range varCandidates { 218 if len(varsList) > 0 && isEndsWithEscapeChar(varsList[len(varsList)-1]) { 219 currentLastVar := varsList[len(varsList)-1] 220 varsList[len(varsList)-1] = strings.TrimSuffix(currentLastVar, "\\") + ";" + v 221 continue 222 } 223 varsList = append(varsList, v) 224 } 225 return varsAsMap(varsList) 226 } 227 228 func isEndsWithEscapeChar(lastVar string) bool { 229 return strings.HasSuffix(lastVar, "\\") 230 } 231 232 func varsAsMap(vars []string) map[string]string { 233 result := map[string]string{} 234 for _, v := range vars { 235 keyVal := strings.SplitN(v, "=", 2) 236 if len(keyVal) != 2 { 237 continue 238 } 239 result[keyVal[0]] = keyVal[1] 240 } 241 return result 242 } 243 244 func IsWindows() bool { 245 return runtime.GOOS == "windows" 246 } 247 248 // Return the path of CLI temp dir. 249 // This path should be persistent, meaning - should not be cleared at the end of a CLI run. 250 func GetCliPersistentTempDirPath() string { 251 return cliTempDir 252 } 253 254 func GetUserAgent() string { 255 return cliUserAgent 256 } 257 258 type Credentials interface { 259 SetUser(string) 260 SetPassword(string) 261 GetUser() string 262 GetPassword() string 263 } 264 265 func ReplaceVars(content []byte, specVars map[string]string) []byte { 266 log.Debug("Replacing variables in the provided content: \n" + string(content)) 267 for key, val := range specVars { 268 key = "${" + key + "}" 269 log.Debug(fmt.Sprintf("Replacing '%s' with '%s'", key, val)) 270 content = bytes.Replace(content, []byte(key), []byte(val), -1) 271 } 272 log.Debug("The reformatted content is: \n" + string(content)) 273 return content 274 } 275 276 func GetJfrogHomeDir() (string, error) { 277 // The JfrogHomeEnv environment variable has been deprecated and replaced with HomeDir 278 if os.Getenv(HomeDir) != "" { 279 return os.Getenv(HomeDir), nil 280 } else if os.Getenv(JfrogHomeEnv) != "" { 281 return path.Join(os.Getenv(JfrogHomeEnv), ".jfrog"), nil 282 } 283 284 userHomeDir := fileutils.GetHomeDir() 285 if userHomeDir == "" { 286 err := errorutils.CheckError(errors.New("couldn't find home directory. Make sure your HOME environment variable is set")) 287 if err != nil { 288 return "", err 289 } 290 } 291 return filepath.Join(userHomeDir, ".jfrog"), nil 292 } 293 294 func CreateDirInJfrogHome(dirName string) (string, error) { 295 homeDir, err := GetJfrogHomeDir() 296 if err != nil { 297 return "", err 298 } 299 folderName := filepath.Join(homeDir, dirName) 300 err = fileutils.CreateDirIfNotExist(folderName) 301 return folderName, err 302 } 303 304 func GetJfrogSecurityDir() (string, error) { 305 homeDir, err := GetJfrogHomeDir() 306 if err != nil { 307 return "", err 308 } 309 return filepath.Join(homeDir, "security"), nil 310 }