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