github.com/opendevstack/tailor@v1.3.5-0.20220119161809-cab064e60a67/pkg/cli/cli.go (about) 1 package cli 2 3 import ( 4 "bufio" 5 "bytes" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "log" 10 "os" 11 "os/exec" 12 "strings" 13 14 "github.com/fatih/color" 15 ) 16 17 var verbose bool 18 var debug bool 19 var ocBinary string 20 21 // PrintGreenf prints in green. 22 var PrintGreenf func(format string, a ...interface{}) 23 24 // FprintGreenf prints in green to w. 25 var FprintGreenf func(w io.Writer, format string, a ...interface{}) 26 27 // PrintBluef prints in blue. 28 var PrintBluef func(format string, a ...interface{}) 29 30 // FprintBluef prints in green to w. 31 var FprintBluef func(w io.Writer, format string, a ...interface{}) 32 33 // PrintYellowf prints in yellow. 34 var PrintYellowf func(format string, a ...interface{}) 35 36 // FprintYellowf prints in green to w. 37 var FprintYellowf func(w io.Writer, format string, a ...interface{}) 38 39 // PrintRedf prints in red. 40 var PrintRedf func(format string, a ...interface{}) 41 42 // FprintRedf prints in green to w. 43 var FprintRedf func(w io.Writer, format string, a ...interface{}) 44 45 func init() { 46 color.Output = os.Stderr 47 PrintGreenf = color.New(color.FgGreen).PrintfFunc() 48 PrintBluef = color.New(color.FgBlue).PrintfFunc() 49 PrintYellowf = color.New(color.FgYellow).PrintfFunc() 50 PrintRedf = color.New(color.FgRed).PrintfFunc() 51 FprintGreenf = color.New(color.FgGreen).FprintfFunc() 52 FprintBluef = color.New(color.FgBlue).FprintfFunc() 53 FprintYellowf = color.New(color.FgYellow).FprintfFunc() 54 FprintRedf = color.New(color.FgRed).FprintfFunc() 55 verbose = false 56 } 57 58 // VerboseMsg prints given message when verbose mode is on. 59 // Verbose mode is implicitly turned on when debug mode is on. 60 func VerboseMsg(messages ...string) { 61 if verbose { 62 PrintBluef("--> %s\n", strings.Join(messages, " ")) 63 } 64 } 65 66 // DebugMsg prints given message when debug mode is on. 67 func DebugMsg(messages ...string) { 68 if debug { 69 PrintBluef("--> %s\n", strings.Join(messages, " ")) 70 } 71 } 72 73 // ExecOcCmd executes "oc" with given namespace and selector applied. 74 func ExecOcCmd(args []string, namespace string, selector string) *exec.Cmd { 75 if len(namespace) > 0 { 76 args = append(args, "--namespace="+namespace) 77 } 78 if len(selector) > 0 { 79 args = append(args, "--selector="+selector) 80 } 81 return ExecPlainOcCmd(args) 82 } 83 84 // ExecPlainOcCmd executes "oc" with given arguments applied. 85 func ExecPlainOcCmd(args []string) *exec.Cmd { 86 return execCmd(ocBinary, args) 87 } 88 89 // RunCmd runs the given command and returns the result 90 func RunCmd(cmd *exec.Cmd) (outBytes, errBytes []byte, err error) { 91 var stdout, stderr bytes.Buffer 92 cmd.Stdout = &stdout 93 cmd.Stderr = &stderr 94 err = cmd.Run() 95 outBytes = stdout.Bytes() 96 errBytes = stderr.Bytes() 97 return outBytes, errBytes, err 98 } 99 100 func execCmd(executable string, args []string) *exec.Cmd { 101 VerboseMsg(executable + " " + strings.Join(args, " ")) 102 return exec.Command(executable, args...) 103 } 104 105 // AskForAction asks the user the given question. A user must type in one of the presented options and 106 // then press enter.If the input is not recognized, it will ask again. The function does not return 107 // until it gets a valid response from the user. 108 // Options are of form "y=yes". The matching is fuzzy, which means allowed values are 109 // "y", "Y", "yes", "YES", "Yes" and so on. The returned value is always the "key" ("y" in this case), 110 // regardless if the input was "y" or "yes" etc. 111 func AskForAction(question string, options []string, reader *bufio.Reader) string { 112 validAnswers := map[string]string{} 113 for _, v := range options { 114 p := strings.Split(v, "=") 115 validAnswers[p[0]] = p[0] 116 validAnswers[p[1]] = p[0] 117 } 118 119 for { 120 fmt.Printf("%s [%s]: ", question, strings.Join(options, ", ")) 121 122 answer, err := reader.ReadString('\n') 123 if err != nil { 124 log.Fatal(err) 125 } 126 127 answer = strings.ToLower(strings.TrimSpace(answer)) 128 129 if v, ok := validAnswers[answer]; !ok { 130 fmt.Printf("'%s' is not a valid option. Please try again.\n", answer) 131 } else { 132 return v 133 } 134 } 135 } 136 137 // EditEnvFile opens content in EDITOR, and returns saved content. 138 func EditEnvFile(content string) (string, error) { 139 err := ioutil.WriteFile(".ENV.DEC", []byte(content), 0644) 140 if err != nil { 141 return "", err 142 } 143 editor := os.Getenv("EDITOR") 144 if len(editor) == 0 { 145 editor = "vim" 146 } 147 148 _, err = exec.LookPath(editor) 149 if err != nil { 150 return "", fmt.Errorf( 151 "Please install '%s' or set/change $EDITOR", 152 editor, 153 ) 154 } 155 156 cmd := exec.Command(editor, ".ENV.DEC") 157 cmd.Stdin = os.Stdin 158 cmd.Stdout = os.Stdout 159 err = cmd.Run() 160 if err != nil { 161 return "", err 162 } 163 data, err := ioutil.ReadFile(".ENV.DEC") 164 if err != nil { 165 return "", err 166 } 167 os.Remove(".ENV.DEC") 168 return string(data), nil 169 }