github.com/pure-x-eth/consensus_tm@v0.0.0-20230502163723-e3c2ff987250/libs/cli/helper.go (about)

     1  package cli
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"io"
     7  	"os"
     8  	"path/filepath"
     9  
    10  	"github.com/spf13/cobra"
    11  )
    12  
    13  // WriteConfigVals writes a toml file with the given values.
    14  // It returns an error if writing was impossible.
    15  func WriteConfigVals(dir string, vals map[string]string) error {
    16  	data := ""
    17  	for k, v := range vals {
    18  		data += fmt.Sprintf("%s = \"%s\"\n", k, v)
    19  	}
    20  	cfile := filepath.Join(dir, "config.toml")
    21  	return os.WriteFile(cfile, []byte(data), 0o600)
    22  }
    23  
    24  // RunWithArgs executes the given command with the specified command line args
    25  // and environmental variables set. It returns any error returned from cmd.Execute()
    26  func RunWithArgs(cmd Executable, args []string, env map[string]string) error {
    27  	oargs := os.Args
    28  	oenv := map[string]string{}
    29  	// defer returns the environment back to normal
    30  	defer func() {
    31  		os.Args = oargs
    32  		for k, v := range oenv {
    33  			os.Setenv(k, v)
    34  		}
    35  	}()
    36  
    37  	// set the args and env how we want them
    38  	os.Args = args
    39  	for k, v := range env {
    40  		// backup old value if there, to restore at end
    41  		oenv[k] = os.Getenv(k)
    42  		err := os.Setenv(k, v)
    43  		if err != nil {
    44  			return err
    45  		}
    46  	}
    47  
    48  	// and finally run the command
    49  	return cmd.Execute()
    50  }
    51  
    52  // RunCaptureWithArgs executes the given command with the specified command
    53  // line args and environmental variables set. It returns string fields
    54  // representing output written to stdout and stderr, additionally any error
    55  // from cmd.Execute() is also returned
    56  func RunCaptureWithArgs(cmd Executable, args []string, env map[string]string) (stdout, stderr string, err error) {
    57  	oldout, olderr := os.Stdout, os.Stderr // keep backup of the real stdout
    58  	rOut, wOut, _ := os.Pipe()
    59  	rErr, wErr, _ := os.Pipe()
    60  	os.Stdout, os.Stderr = wOut, wErr
    61  	defer func() {
    62  		os.Stdout, os.Stderr = oldout, olderr // restoring the real stdout
    63  	}()
    64  
    65  	// copy the output in a separate goroutine so printing can't block indefinitely
    66  	copyStd := func(reader *os.File) *(chan string) {
    67  		stdC := make(chan string)
    68  		go func() {
    69  			var buf bytes.Buffer
    70  			// io.Copy will end when we call reader.Close() below
    71  			io.Copy(&buf, reader) //nolint:errcheck //ignore error
    72  			stdC <- buf.String()
    73  		}()
    74  		return &stdC
    75  	}
    76  	outC := copyStd(rOut)
    77  	errC := copyStd(rErr)
    78  
    79  	// now run the command
    80  	err = RunWithArgs(cmd, args, env)
    81  
    82  	// and grab the stdout to return
    83  	wOut.Close()
    84  	wErr.Close()
    85  	stdout = <-*outC
    86  	stderr = <-*errC
    87  	return stdout, stderr, err
    88  }
    89  
    90  // NewCompletionCmd returns a cobra.Command that generates bash and zsh
    91  // completion scripts for the given root command. If hidden is true, the
    92  // command will not show up in the root command's list of available commands.
    93  func NewCompletionCmd(rootCmd *cobra.Command, hidden bool) *cobra.Command {
    94  	flagZsh := "zsh"
    95  	cmd := &cobra.Command{
    96  		Use:   "completion",
    97  		Short: "Generate shell completion scripts",
    98  		Long: fmt.Sprintf(`Generate Bash and Zsh completion scripts and print them to STDOUT.
    99  
   100  Once saved to file, a completion script can be loaded in the shell's
   101  current session as shown:
   102  
   103     $ . <(%s completion)
   104  
   105  To configure your bash shell to load completions for each session add to
   106  your $HOME/.bashrc or $HOME/.profile the following instruction:
   107  
   108     . <(%s completion)
   109  `, rootCmd.Use, rootCmd.Use),
   110  		RunE: func(cmd *cobra.Command, _ []string) error {
   111  			zsh, err := cmd.Flags().GetBool(flagZsh)
   112  			if err != nil {
   113  				return err
   114  			}
   115  			if zsh {
   116  				return rootCmd.GenZshCompletion(cmd.OutOrStdout())
   117  			}
   118  			return rootCmd.GenBashCompletion(cmd.OutOrStdout())
   119  		},
   120  		Hidden: hidden,
   121  		Args:   cobra.NoArgs,
   122  	}
   123  
   124  	cmd.Flags().Bool(flagZsh, false, "Generate Zsh completion script")
   125  
   126  	return cmd
   127  }