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  }