github.com/xiaqingdoc/fabric@v2.1.1+incompatible/cmd/common/cli.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package common
     8  
     9  import (
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"path/filepath"
    14  
    15  	"github.com/hyperledger/fabric/cmd/common/comm"
    16  	"github.com/hyperledger/fabric/cmd/common/signer"
    17  	"gopkg.in/alecthomas/kingpin.v2"
    18  )
    19  
    20  const (
    21  	saveConfigCommand = "saveConfig"
    22  )
    23  
    24  var (
    25  	// Function used to terminate the CLI
    26  	terminate = os.Exit
    27  	// Function used to redirect output to
    28  	outWriter io.Writer = os.Stderr
    29  
    30  	// CLI arguments
    31  	mspID                                     *string
    32  	tlsCA, tlsCert, tlsKey, userKey, userCert **os.File
    33  	configFile                                *string
    34  )
    35  
    36  // CLICommand defines a command that is added to the CLI
    37  // via an external consumer.
    38  type CLICommand func(Config) error
    39  
    40  // CLI defines a command line interpreter
    41  type CLI struct {
    42  	app         *kingpin.Application
    43  	dispatchers map[string]CLICommand
    44  }
    45  
    46  // NewCLI creates a new CLI with the given name and help message
    47  func NewCLI(name, help string) *CLI {
    48  	return &CLI{
    49  		app:         kingpin.New(name, help),
    50  		dispatchers: make(map[string]CLICommand),
    51  	}
    52  }
    53  
    54  // Command adds a new top-level command to the CLI
    55  func (cli *CLI) Command(name, help string, onCommand CLICommand) *kingpin.CmdClause {
    56  	cmd := cli.app.Command(name, help)
    57  	cli.dispatchers[name] = onCommand
    58  	return cmd
    59  }
    60  
    61  // Run makes the CLI process the arguments and executes the command(s) with the flag(s)
    62  func (cli *CLI) Run(args []string) {
    63  	configFile = cli.app.Flag("configFile", "Specifies the config file to load the configuration from").String()
    64  	persist := cli.app.Command(saveConfigCommand, fmt.Sprintf("Save the config passed by flags into the file specified by --configFile"))
    65  	configureFlags(cli.app)
    66  
    67  	command := kingpin.MustParse(cli.app.Parse(args))
    68  	if command == persist.FullCommand() {
    69  		if *configFile == "" {
    70  			out("--configFile must be used to specify the configuration file")
    71  			return
    72  		}
    73  		persistConfig(parseFlagsToConfig(), *configFile)
    74  		return
    75  	}
    76  
    77  	var conf Config
    78  	if *configFile == "" {
    79  		conf = parseFlagsToConfig()
    80  	} else {
    81  		conf = loadConfig(*configFile)
    82  	}
    83  
    84  	f, exists := cli.dispatchers[command]
    85  	if !exists {
    86  		out("Unknown command:", command)
    87  		terminate(1)
    88  		return
    89  	}
    90  	err := f(conf)
    91  	if err != nil {
    92  		out(err)
    93  		terminate(1)
    94  		return
    95  	}
    96  }
    97  
    98  func configureFlags(persistCommand *kingpin.Application) {
    99  	// TLS flags
   100  	tlsCA = persistCommand.Flag("peerTLSCA", "Sets the TLS CA certificate file path that verifies the TLS peer's certificate").File()
   101  	tlsCert = persistCommand.Flag("tlsCert", "(Optional) Sets the client TLS certificate file path that is used when the peer enforces client authentication").File()
   102  	tlsKey = persistCommand.Flag("tlsKey", "(Optional) Sets the client TLS key file path that is used when the peer enforces client authentication").File()
   103  	// Enrollment flags
   104  	userKey = persistCommand.Flag("userKey", "Sets the user's key file path that is used to sign messages sent to the peer").File()
   105  	userCert = persistCommand.Flag("userCert", "Sets the user's certificate file path that is used to authenticate the messages sent to the peer").File()
   106  	mspID = persistCommand.Flag("MSP", "Sets the MSP ID of the user, which represents the CA(s) that issued its user certificate").String()
   107  }
   108  
   109  func persistConfig(conf Config, file string) {
   110  	if err := conf.ToFile(file); err != nil {
   111  		out("Failed persisting configuration:", err)
   112  		terminate(1)
   113  	}
   114  }
   115  
   116  func loadConfig(file string) Config {
   117  	conf, err := ConfigFromFile(file)
   118  	if err != nil {
   119  		out("Failed loading config", err)
   120  		terminate(1)
   121  		return Config{}
   122  	}
   123  	return conf
   124  }
   125  
   126  func parseFlagsToConfig() Config {
   127  	conf := Config{
   128  		SignerConfig: signer.Config{
   129  			MSPID:        *mspID,
   130  			IdentityPath: evaluateFileFlag(userCert),
   131  			KeyPath:      evaluateFileFlag(userKey),
   132  		},
   133  		TLSConfig: comm.Config{
   134  			KeyPath:        evaluateFileFlag(tlsKey),
   135  			CertPath:       evaluateFileFlag(tlsCert),
   136  			PeerCACertPath: evaluateFileFlag(tlsCA),
   137  		},
   138  	}
   139  	return conf
   140  }
   141  
   142  func evaluateFileFlag(f **os.File) string {
   143  	if f == nil {
   144  		return ""
   145  	}
   146  	if *f == nil {
   147  		return ""
   148  	}
   149  	path, err := filepath.Abs((*f).Name())
   150  	if err != nil {
   151  		out("Failed listing", (*f).Name(), ":", err)
   152  		terminate(1)
   153  	}
   154  	return path
   155  }
   156  func out(a ...interface{}) {
   157  	fmt.Fprintln(outWriter, a...)
   158  }