diff --git a/cmd/abigen/main.go b/cmd/abigen/main.go index ed4a3b887..a74b0396d 100644 --- a/cmd/abigen/main.go +++ b/cmd/abigen/main.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common/compiler" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "gopkg.in/urfave/cli.v1" ) @@ -100,7 +101,7 @@ var ( ) func init() { - app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") + app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Flags = []cli.Flag{ abiFlag, binFlag, @@ -117,7 +118,7 @@ func init() { aliasFlag, } app.Action = utils.MigrateFlags(abigen) - cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate + cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } func abigen(c *cli.Context) error { diff --git a/cmd/checkpoint-admin/main.go b/cmd/checkpoint-admin/main.go index b4d8e0db5..0fb553214 100644 --- a/cmd/checkpoint-admin/main.go +++ b/cmd/checkpoint-admin/main.go @@ -22,8 +22,8 @@ import ( "fmt" "os" - "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common/fdlimit" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "gopkg.in/urfave/cli.v1" ) @@ -37,7 +37,7 @@ var ( var app *cli.App func init() { - app = utils.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") + app = flags.NewApp(gitCommit, gitDate, "ethereum checkpoint helper tool") app.Commands = []cli.Command{ commandStatus, commandDeploy, @@ -48,7 +48,7 @@ func init() { oracleFlag, nodeURLFlag, } - cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate + cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } // Commonly used command line flags. diff --git a/cmd/clef/README.md b/cmd/clef/README.md index 93f78ac2d..700f0a144 100644 --- a/cmd/clef/README.md +++ b/cmd/clef/README.md @@ -33,12 +33,12 @@ GLOBAL OPTIONS: --lightkdf Reduce key-derivation RAM & CPU usage at some expense of KDF strength --nousb Disables monitoring for and managing USB hardware wallets --pcscdpath value Path to the smartcard daemon (pcscd) socket file (default: "/run/pcscd/pcscd.comm") - --rpcaddr value HTTP-RPC server listening interface (default: "localhost") - --rpcvhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost") + --http.addr value HTTP-RPC server listening interface (default: "localhost") + --http.vhosts value Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard. (default: "localhost") --ipcdisable Disable the IPC-RPC server --ipcpath Filename for IPC socket/pipe within the datadir (explicit paths escape it) - --rpc Enable the HTTP-RPC server - --rpcport value HTTP-RPC server listening port (default: 8550) + --http Enable the HTTP-RPC server + --http.port value HTTP-RPC server listening port (default: 8550) --signersecret value A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash --4bytedb-custom value File used for writing new 4byte-identifiers submitted via API (default: "./4byte-custom.json") --auditlog value File used to emit audit logs. Set to "" to disable (default: "audit.log") @@ -113,7 +113,7 @@ Some snags and todos ### External API -Clef listens to HTTP requests on `rpcaddr`:`rpcport` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification). +Clef listens to HTTP requests on `http.addr`:`http.port` (or to IPC on `ipcpath`), with the same JSON-RPC standard as Geth. The messages are expected to be [JSON-RPC 2.0 standard](https://www.jsonrpc.org/specification). Some of these calls can require user interaction. Clients must be aware that responses may be delayed significantly or may never be received if a user decides to ignore the confirmation request. diff --git a/cmd/clef/main.go b/cmd/clef/main.go index 10cb4628b..8c8778c24 100644 --- a/cmd/clef/main.go +++ b/cmd/clef/main.go @@ -32,6 +32,7 @@ import ( "os/user" "path/filepath" "runtime" + "sort" "strings" "time" @@ -43,6 +44,7 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/internal/ethapi" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" @@ -52,6 +54,7 @@ import ( "github.com/ethereum/go-ethereum/signer/fourbyte" "github.com/ethereum/go-ethereum/signer/rules" "github.com/ethereum/go-ethereum/signer/storage" + colorable "github.com/mattn/go-colorable" "github.com/mattn/go-isatty" "gopkg.in/urfave/cli.v1" @@ -101,10 +104,15 @@ var ( Usage: "Chain id to use for signing (1=mainnet, 3=Ropsten, 4=Rinkeby, 5=Goerli)", } rpcPortFlag = cli.IntFlag{ - Name: "rpcport", + Name: "http.port", Usage: "HTTP-RPC server listening port", Value: node.DefaultHTTPPort + 5, } + legacyRPCPortFlag = cli.IntFlag{ + Name: "rpcport", + Usage: "HTTP-RPC server listening port (Deprecated, please use --http.port).", + Value: node.DefaultHTTPPort + 5, + } signerSecretFlag = cli.StringFlag{ Name: "signersecret", Usage: "A file containing the (encrypted) master seed to encrypt Clef data, e.g. keystore credentials and ruleset hash", @@ -215,6 +223,42 @@ The gendoc generates example structures of the json-rpc communication types. `} ) +// AppHelpFlagGroups is the application flags, grouped by functionality. +var AppHelpFlagGroups = []flags.FlagGroup{ + { + Name: "FLAGS", + Flags: []cli.Flag{ + logLevelFlag, + keystoreFlag, + configdirFlag, + chainIdFlag, + utils.LightKDFFlag, + utils.NoUSBFlag, + utils.SmartCardDaemonPathFlag, + utils.HTTPListenAddrFlag, + utils.HTTPVirtualHostsFlag, + utils.IPCDisabledFlag, + utils.IPCPathFlag, + utils.HTTPEnabledFlag, + rpcPortFlag, + signerSecretFlag, + customDBFlag, + auditLogFlag, + ruleFlag, + stdiouiFlag, + testFlag, + advancedMode, + acceptFlag, + }, + }, + { + Name: "ALIASED (deprecated)", + Flags: []cli.Flag{ + legacyRPCPortFlag, + }, + }, +} + func init() { app.Name = "Clef" app.Usage = "Manage Ethereum account operations" @@ -240,6 +284,7 @@ func init() { testFlag, advancedMode, acceptFlag, + legacyRPCPortFlag, } app.Action = signer app.Commands = []cli.Command{initCommand, @@ -248,7 +293,41 @@ func init() { delCredentialCommand, newAccountCommand, gendocCommand} - cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate + cli.CommandHelpTemplate = flags.CommandHelpTemplate + // Override the default app help template + cli.AppHelpTemplate = flags.ClefAppHelpTemplate + + // Override the default app help printer, but only for the global app help + originalHelpPrinter := cli.HelpPrinter + cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) { + if tmpl == flags.ClefAppHelpTemplate { + // Render out custom usage screen + originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups}) + } else if tmpl == flags.CommandHelpTemplate { + // Iterate over all command specific flags and categorize them + categorized := make(map[string][]cli.Flag) + for _, flag := range data.(cli.Command).Flags { + if _, ok := categorized[flag.String()]; !ok { + categorized[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag) + } + } + + // sort to get a stable ordering + sorted := make([]flags.FlagGroup, 0, len(categorized)) + for cat, flgs := range categorized { + sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs}) + } + sort.Sort(flags.ByCategory(sorted)) + + // add sorted array to data and render with default printer + originalHelpPrinter(w, tmpl, map[string]interface{}{ + "cmd": data, + "categorizedFlags": sorted, + }) + } else { + originalHelpPrinter(w, tmpl, data) + } + } } func main() { @@ -597,8 +676,17 @@ func signer(c *cli.Context) error { } handler := node.NewHTTPHandlerStack(srv, cors, vhosts) + // set port + port := c.Int(rpcPortFlag.Name) + if c.GlobalIsSet(legacyRPCPortFlag.Name) { + if !c.GlobalIsSet(rpcPortFlag.Name) { + port = c.Int(legacyRPCPortFlag.Name) + } + log.Warn("The flag --rpcport is deprecated and will be removed in the future, please use --http.port") + } + // start http server - httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), c.Int(rpcPortFlag.Name)) + httpEndpoint := fmt.Sprintf("%s:%d", c.GlobalString(utils.HTTPListenAddrFlag.Name), port) httpServer, addr, err := node.StartHTTPEndpoint(httpEndpoint, rpc.DefaultHTTPTimeouts, handler) if err != nil { utils.Fatalf("Could not start RPC api: %v", err) diff --git a/cmd/ethkey/main.go b/cmd/ethkey/main.go index dbc496058..6db39174c 100644 --- a/cmd/ethkey/main.go +++ b/cmd/ethkey/main.go @@ -20,7 +20,7 @@ import ( "fmt" "os" - "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/internal/flags" "gopkg.in/urfave/cli.v1" ) @@ -35,7 +35,7 @@ var gitDate = "" var app *cli.App func init() { - app = utils.NewApp(gitCommit, gitDate, "an Ethereum key manager") + app = flags.NewApp(gitCommit, gitDate, "an Ethereum key manager") app.Commands = []cli.Command{ commandGenerate, commandInspect, @@ -43,7 +43,7 @@ func init() { commandSignMessage, commandVerifyMessage, } - cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate + cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } // Commonly used command line flags. diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 473020d5f..2d5e9763d 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -24,6 +24,7 @@ import ( "github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/internal/flags" "gopkg.in/urfave/cli.v1" ) @@ -31,7 +32,7 @@ var gitCommit = "" // Git SHA1 commit hash of the release (set via linker flags) var gitDate = "" var ( - app = utils.NewApp(gitCommit, gitDate, "the evm command line interface") + app = flags.NewApp(gitCommit, gitDate, "the evm command line interface") DebugFlag = cli.BoolFlag{ Name: "debug", @@ -180,7 +181,7 @@ func init() { stateTestCommand, stateTransitionCommand, } - cli.CommandHelpTemplate = utils.OriginCommandHelpTemplate + cli.CommandHelpTemplate = flags.OriginCommandHelpTemplate } func main() { diff --git a/cmd/geth/main.go b/cmd/geth/main.go index e82e0ec54..1592f774a 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -36,6 +36,7 @@ import ( "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -53,7 +54,7 @@ var ( gitCommit = "" gitDate = "" // The app that holds all commands and flags. - app = utils.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") + app = flags.NewApp(gitCommit, gitDate, "the go-ethereum command line interface") // flags that configure the node nodeFlags = []cli.Flag{ utils.IdentityFlag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index 05bd28130..b80f05edb 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -24,44 +24,12 @@ import ( "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/internal/debug" + "github.com/ethereum/go-ethereum/internal/flags" cli "gopkg.in/urfave/cli.v1" ) -// AppHelpTemplate is the test template for the default, global app help topic. -var AppHelpTemplate = `NAME: - {{.App.Name}} - {{.App.Usage}} - - Copyright 2013-2019 The go-ethereum Authors - -USAGE: - {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} - {{if .App.Version}} -VERSION: - {{.App.Version}} - {{end}}{{if len .App.Authors}} -AUTHOR(S): - {{range .App.Authors}}{{ . }}{{end}} - {{end}}{{if .App.Commands}} -COMMANDS: - {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .FlagGroups}} -{{range .FlagGroups}}{{.Name}} OPTIONS: - {{range .Flags}}{{.}} - {{end}} -{{end}}{{end}}{{if .App.Copyright }} -COPYRIGHT: - {{.App.Copyright}} - {{end}} -` - -// flagGroup is a collection of flags belonging to a single topic. -type flagGroup struct { - Name string - Flags []cli.Flag -} - // AppHelpFlagGroups is the application flags, grouped by functionality. -var AppHelpFlagGroups = []flagGroup{ +var AppHelpFlagGroups = []flags.FlagGroup{ { Name: "ETHEREUM", Flags: []cli.Flag{ @@ -272,53 +240,14 @@ var AppHelpFlagGroups = []flagGroup{ }, } -// byCategory sorts an array of flagGroup by Name in the order -// defined in AppHelpFlagGroups. -type byCategory []flagGroup - -func (a byCategory) Len() int { return len(a) } -func (a byCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] } -func (a byCategory) Less(i, j int) bool { - iCat, jCat := a[i].Name, a[j].Name - iIdx, jIdx := len(AppHelpFlagGroups), len(AppHelpFlagGroups) // ensure non categorized flags come last - - for i, group := range AppHelpFlagGroups { - if iCat == group.Name { - iIdx = i - } - if jCat == group.Name { - jIdx = i - } - } - - return iIdx < jIdx -} - -func flagCategory(flag cli.Flag) string { - for _, category := range AppHelpFlagGroups { - for _, flg := range category.Flags { - if flg.GetName() == flag.GetName() { - return category.Name - } - } - } - return "MISC" -} - func init() { // Override the default app help template - cli.AppHelpTemplate = AppHelpTemplate - - // Define a one shot struct to pass to the usage template - type helpData struct { - App interface{} - FlagGroups []flagGroup - } + cli.AppHelpTemplate = flags.AppHelpTemplate // Override the default app help printer, but only for the global app help originalHelpPrinter := cli.HelpPrinter cli.HelpPrinter = func(w io.Writer, tmpl string, data interface{}) { - if tmpl == AppHelpTemplate { + if tmpl == flags.AppHelpTemplate { // Iterate over all the flags and add any uncategorized ones categorized := make(map[string]struct{}) for _, group := range AppHelpFlagGroups { @@ -350,22 +279,22 @@ func init() { }() } // Render out custom usage screen - originalHelpPrinter(w, tmpl, helpData{data, AppHelpFlagGroups}) - } else if tmpl == utils.CommandHelpTemplate { + originalHelpPrinter(w, tmpl, flags.HelpData{App: data, FlagGroups: AppHelpFlagGroups}) + } else if tmpl == flags.CommandHelpTemplate { // Iterate over all command specific flags and categorize them categorized := make(map[string][]cli.Flag) for _, flag := range data.(cli.Command).Flags { if _, ok := categorized[flag.String()]; !ok { - categorized[flagCategory(flag)] = append(categorized[flagCategory(flag)], flag) + categorized[flags.FlagCategory(flag, AppHelpFlagGroups)] = append(categorized[flags.FlagCategory(flag, AppHelpFlagGroups)], flag) } } // sort to get a stable ordering - sorted := make([]flagGroup, 0, len(categorized)) + sorted := make([]flags.FlagGroup, 0, len(categorized)) for cat, flgs := range categorized { - sorted = append(sorted, flagGroup{cat, flgs}) + sorted = append(sorted, flags.FlagGroup{Name: cat, Flags: flgs}) } - sort.Sort(byCategory(sorted)) + sort.Sort(flags.ByCategory(sorted)) // add sorted array to data and render with default printer originalHelpPrinter(w, tmpl, map[string]interface{}{ diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index c5e2aa8d6..30e4f783b 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -48,6 +48,7 @@ import ( "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethstats" "github.com/ethereum/go-ethereum/graphql" + "github.com/ethereum/go-ethereum/internal/flags" "github.com/ethereum/go-ethereum/les" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" @@ -67,30 +68,6 @@ import ( cli "gopkg.in/urfave/cli.v1" ) -var ( - CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...] -{{if .cmd.Description}}{{.cmd.Description}} -{{end}}{{if .cmd.Subcommands}} -SUBCOMMANDS: - {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .categorizedFlags}} -{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: -{{range $categorized.Flags}}{{"\t"}}{{.}} -{{end}} -{{end}}{{end}}` - - OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] -{{if .Description}}{{.Description}} -{{end}}{{if .Subcommands}} -SUBCOMMANDS: - {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} - {{end}}{{end}}{{if .Flags}} -OPTIONS: -{{range $.Flags}} {{.}} -{{end}} -{{end}}` -) - func init() { cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] @@ -104,21 +81,10 @@ GLOBAL OPTIONS: {{range .Flags}}{{.}} {{end}}{{end}} ` - cli.CommandHelpTemplate = CommandHelpTemplate + cli.CommandHelpTemplate = flags.CommandHelpTemplate cli.HelpPrinter = printHelp } -// NewApp creates an app with sane defaults. -func NewApp(gitCommit, gitDate, usage string) *cli.App { - app := cli.NewApp() - app.Name = filepath.Base(os.Args[0]) - app.Author = "" - app.Email = "" - app.Version = params.VersionWithCommit(gitCommit, gitDate) - app.Usage = usage - return app -} - func printHelp(out io.Writer, templ string, data interface{}) { funcMap := template.FuncMap{"join": strings.Join} t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go new file mode 100644 index 000000000..900fec454 --- /dev/null +++ b/internal/flags/helpers.go @@ -0,0 +1,152 @@ +// Copyright 2020 The go-ethereum Authors +// This file is part of go-ethereum. +// +// go-ethereum is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// go-ethereum is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with go-ethereum. If not, see . + +package flags + +import ( + "os" + "path/filepath" + + "github.com/ethereum/go-ethereum/params" + cli "gopkg.in/urfave/cli.v1" +) + +var ( + CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...] +{{if .cmd.Description}}{{.cmd.Description}} +{{end}}{{if .cmd.Subcommands}} +SUBCOMMANDS: + {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .categorizedFlags}} +{{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: +{{range $categorized.Flags}}{{"\t"}}{{.}} +{{end}} +{{end}}{{end}}` + + OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] +{{if .Description}}{{.Description}} +{{end}}{{if .Subcommands}} +SUBCOMMANDS: + {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .Flags}} +OPTIONS: +{{range $.Flags}} {{.}} +{{end}} +{{end}}` + + // AppHelpTemplate is the test template for the default, global app help topic. + AppHelpTemplate = `NAME: + {{.App.Name}} - {{.App.Usage}} + + Copyright 2013-2019 The go-ethereum Authors + +USAGE: + {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if .App.Version}} +VERSION: + {{.App.Version}} + {{end}}{{if len .App.Authors}} +AUTHOR(S): + {{range .App.Authors}}{{ . }}{{end}} + {{end}}{{if .App.Commands}} +COMMANDS: + {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .FlagGroups}} +{{range .FlagGroups}}{{.Name}} OPTIONS: + {{range .Flags}}{{.}} + {{end}} +{{end}}{{end}}{{if .App.Copyright }} +COPYRIGHT: + {{.App.Copyright}} + {{end}} +` + // ClefAppHelpTemplate is the template for the default, global app help topic. + ClefAppHelpTemplate = `NAME: + {{.App.Name}} - {{.App.Usage}} + + Copyright 2013-2019 The go-ethereum Authors + +USAGE: + {{.App.HelpName}} [options]{{if .App.Commands}} command [command options]{{end}} {{if .App.ArgsUsage}}{{.App.ArgsUsage}}{{else}}[arguments...]{{end}} + {{if .App.Version}} +COMMANDS: + {{range .App.Commands}}{{join .Names ", "}}{{ "\t" }}{{.Usage}} + {{end}}{{end}}{{if .FlagGroups}} +{{range .FlagGroups}}{{.Name}} OPTIONS: + {{range .Flags}}{{.}} + {{end}} +{{end}}{{end}}{{if .App.Copyright }} +COPYRIGHT: + {{.App.Copyright}} + {{end}} +` +) + +// HelpData is a one shot struct to pass to the usage template +type HelpData struct { + App interface{} + FlagGroups []FlagGroup +} + +// FlagGroup is a collection of flags belonging to a single topic. +type FlagGroup struct { + Name string + Flags []cli.Flag +} + +// byCategory sorts an array of FlagGroup by Name in the order +// defined in AppHelpFlagGroups. +type ByCategory []FlagGroup + +func (a ByCategory) Len() int { return len(a) } +func (a ByCategory) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a ByCategory) Less(i, j int) bool { + iCat, jCat := a[i].Name, a[j].Name + iIdx, jIdx := len(a), len(a) // ensure non categorized flags come last + + for i, group := range a { + if iCat == group.Name { + iIdx = i + } + if jCat == group.Name { + jIdx = i + } + } + + return iIdx < jIdx +} + +func FlagCategory(flag cli.Flag, flagGroups []FlagGroup) string { + for _, category := range flagGroups { + for _, flg := range category.Flags { + if flg.GetName() == flag.GetName() { + return category.Name + } + } + } + return "MISC" +} + +// NewApp creates an app with sane defaults. +func NewApp(gitCommit, gitDate, usage string) *cli.App { + app := cli.NewApp() + app.Name = filepath.Base(os.Args[0]) + app.Author = "" + app.Email = "" + app.Version = params.VersionWithCommit(gitCommit, gitDate) + app.Usage = usage + return app +}