github.com/lzy4123/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 }