Commit 84293023 authored by Sietse Ringers's avatar Sietse Ringers
Browse files

feat: stop depending on forked pflag functionality for inserting headers in command help messages

parent 3f743367
package cmd
import (
"regexp"
"strings"
)
// headerFlagsTemplate is copied from cobra.Command.UsageTemplate, modified to include an invocation
// of insertHeaders on the flags, which intersperses the flags with headers.
var headerFlagsTemplate = `Usage:{{if .Runnable}}
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
Aliases:
{{.NameAndAliases}}{{end}}{{if .HasExample}}
Examples:
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}
Available Commands:{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
Flags:
{{.LocalFlags.FlagUsages | trimTrailingWhitespaces | insertHeaders .CommandPath}}{{end}}{{if .HasAvailableInheritedFlags}}
Global Flags:
{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}
`
var flagHeaders = map[string]map[string]string{}
func insertHeaders(cmdPath string, flags string) string {
headers := flagHeaders[cmdPath]
if len(headers) == 0 {
return flags
}
in := strings.Split(flags, "\n")
out := make([]string, 0, len(in)+len(headers))
r := regexp.MustCompile(`^\s+(-\w, )?--([^ ]*)`)
for _, line := range in {
matches := r.FindStringSubmatch(line)
header := headers[matches[2]]
if header != "" {
out = append(out, "\n"+header)
}
out = append(out, line)
}
return strings.Join(out, "\n")
}
......@@ -31,6 +31,16 @@ var myirmaServerCmd = &cobra.Command{
func init() {
keyshareRootCmd.AddCommand(myirmaServerCmd)
myirmaServerCmd.SetUsageTemplate(headerFlagsTemplate)
flagHeaders["irma keyshare myirmaserver"] = map[string]string{
"port": "Server address and port to listen on",
"db-type": "Database configuration",
"keyshare-attributes": "IRMA session configuration",
"email-server": "Email configuration (leave empty to disable sending emails)",
"tls-cert": "TLS configuration (leave empty to disable TLS)",
"verbose": "Other options",
}
flags := myirmaServerCmd.Flags()
flags.SortFlags = false
......@@ -46,16 +56,13 @@ func init() {
flags.IntP("port", "p", 8080, "port at which to listen")
flags.StringP("listen-addr", "l", "", "address at which to listen (default 0.0.0.0)")
flags.StringSlice("cors-allowed-origins", nil, "CORS allowed origins")
flags.Lookup("port").Header = `Server address and port to listen on`
flags.String("db-type", string(myirmaserver.DBTypePostgres), "Type of database to connect keyshare server to")
flags.String("db", "", "Database server connection string")
flags.Lookup("db-type").Header = `Database configuration`
flags.StringSlice("keyshare-attributes", nil, "Attributes allowed for login to myirma")
flags.StringSlice("email-attributes", nil, "Attributes allowed for adding email addresses")
flags.Int("session-lifetime", myirmaserver.SessionLifetimeDefault, "Session lifetime in seconds")
flags.Lookup("keyshare-attributes").Header = `IRMA session configuration`
flags.String("email-server", "", "Email server to use for sending email address confirmation emails")
flags.String("email-hostname", "", "Hostname used in email server tls certificate (leave empty when mail server does not use tls)")
......@@ -71,20 +78,17 @@ func init() {
flags.StringToString("delete-account-subjects", nil, "Translated subject lines for the delete account email")
flags.StringToString("delete-account-files", nil, "Translated emails for the delete account email")
flags.Int("delete-delay", 0, "delay in days before a user or email address deletion becomes effective")
flags.Lookup("email-server").Header = `Email configuration (leave empty to disable sending emails)`
flags.String("tls-cert", "", "TLS certificate (chain)")
flags.String("tls-cert-file", "", "path to TLS certificate (chain)")
flags.String("tls-privkey", "", "TLS private key")
flags.String("tls-privkey-file", "", "path to TLS private key")
flags.Bool("no-tls", false, "Disable TLS")
flags.Lookup("tls-cert").Header = `TLS configuration (leave empty to disable TLS)`
flags.CountP("verbose", "v", "verbose (repeatable)")
flags.BoolP("quiet", "q", false, "quiet")
flags.Bool("log-json", false, "Log in JSON format")
flags.Bool("production", false, "Production mode")
flags.Lookup("verbose").Header = `Other options`
}
func configureMyirmaServer(cmd *cobra.Command) (*myirmaserver.Configuration, error) {
......
......@@ -32,6 +32,17 @@ var keyshareServerCmd = &cobra.Command{
func init() {
keyshareRootCmd.AddCommand(keyshareServerCmd)
keyshareServerCmd.SetUsageTemplate(headerFlagsTemplate)
flagHeaders["irma keyshare server"] = map[string]string{
"port": "Server address and port to listen on",
"db-type": "Database configuration",
"jwt-privkey": "Cryptographic keys",
"keyshare-attribute": "Keyshare server attribute issued during registration",
"email-server": "Email configuration (leave empty to disable sending emails)",
"tls-cert": "TLS configuration (leave empty to disable TLS)",
"verbose": "Other options",
}
flags := keyshareServerCmd.Flags()
flags.SortFlags = false
flags.StringP("config", "c", "", "path to configuration file")
......@@ -43,11 +54,9 @@ func init() {
flags.IntP("port", "p", 8080, "port at which to listen")
flags.StringP("listen-addr", "l", "", "address at which to listen (default 0.0.0.0)")
flags.Lookup("port").Header = `Server address and port to listen on`
flags.String("db-type", string(keyshareserver.DBTypePostgres), "Type of database to connect keyshare server to")
flags.String("db", "", "Database server connection string")
flags.Lookup("db-type").Header = `Database configuration`
flags.String("jwt-privkey", "", "Private jwt key of keyshare server")
flags.String("jwt-privkey-file", "", "Path to file containing private jwt key of keyshare server")
......@@ -56,10 +65,8 @@ func init() {
flags.Int("jwt-pin-expiry", keysharecore.JWTPinExpiryDefault, "Expiry of PIN JWT in seconds")
flags.String("storage-primary-keyfile", "", "Primary key used for encrypting and decrypting secure containers")
flags.StringSlice("storage-fallback-keyfile", nil, "Fallback key(s) used to decrypt older secure containers")
flags.Lookup("jwt-privkey").Header = `Cryptographic keys`
flags.String("keyshare-attribute", "", "Attribute identifier that contains username")
flags.Lookup("keyshare-attribute").Header = `Keyshare server attribute issued during registration`
flags.String("email-server", "", "Email server to use for sending email address confirmation emails")
flags.String("email-hostname", "", "Hostname used in email server tls certificate (leave empty when mail server does not use tls)")
......@@ -70,20 +77,17 @@ func init() {
flags.StringToString("registration-email-subjects", nil, "Translated subject lines for the registration email")
flags.StringToString("registration-email-files", nil, "Translated emails for the registration email")
flags.StringToString("verification-url", nil, "Base URL for the email verification link (localized)")
flags.Lookup("email-server").Header = `Email configuration (leave empty to disable sending emails)`
flags.String("tls-cert", "", "TLS certificate (chain)")
flags.String("tls-cert-file", "", "path to TLS certificate (chain)")
flags.String("tls-privkey", "", "TLS private key")
flags.String("tls-privkey-file", "", "path to TLS private key")
flags.Bool("no-tls", false, "Disable TLS")
flags.Lookup("tls-cert").Header = `TLS configuration (leave empty to disable TLS)`
flags.CountP("verbose", "v", "verbose (repeatable)")
flags.BoolP("quiet", "q", false, "quiet")
flags.Bool("log-json", false, "Log in JSON format")
flags.Bool("production", false, "Production mode")
flags.Lookup("verbose").Header = `Other options`
}
func configureKeyshareServer(cmd *cobra.Command) (*keyshareserver.Configuration, error) {
......
......@@ -20,17 +20,23 @@ var keyshareTaskCmd = &cobra.Command{
func init() {
keyshareRootCmd.AddCommand(keyshareTaskCmd)
keyshareTaskCmd.SetUsageTemplate(headerFlagsTemplate)
flagHeaders["irma keyshare tasks"] = map[string]string{
"db": "Database configuration",
"expiry-delay": "Time period configuraiton",
"email-server": "Email configuration (leave empty to disable sending emails)",
"verbose": "Other options",
}
flags := keyshareTaskCmd.Flags()
flags.SortFlags = false
flags.StringP("config", "c", "", "path to configuration file")
flags.String("db", "", "Database server connection string")
flags.Lookup("db").Header = `Database configuration`
flags.Int("expiry-delay", 365, "Number of days of inactivity until account expires")
flags.Int("delete-delay", 30, "Number of days until expired account should be deleted")
flags.Lookup("expiry-delay").Header = `Time period configuraiton`
flags.String("email-server", "", "Email server to use for sending email address confirmation emails")
flags.String("email-hostname", "", "Hostname used in email server tls certificate (leave empty when mail server does not use tls)")
......@@ -40,12 +46,10 @@ func init() {
flags.String("default-language", "en", "Default language, used as fallback when users preferred language is not available")
flags.StringToString("expired-email-subjects", nil, "Translated subject lines for the expired account email")
flags.StringToString("expired-email-files", nil, "Translated emails for the expired account email")
flags.Lookup("email-server").Header = `Email configuration (leave empty to disable sending emails)`
flags.CountP("verbose", "v", "verbose (repeatable)")
flags.BoolP("quiet", "q", false, "quiet")
flags.Bool("log-json", false, "Log in JSON format")
flags.Lookup("verbose").Header = `Other options`
}
func configureKeyshareTasks(cmd *cobra.Command) *tasks.Configuration {
......
......@@ -37,6 +37,8 @@ func Execute() {
func init() {
RootCmd.AddCommand(versionCmd)
cobra.AddTemplateFunc("insertHeaders", insertHeaders)
}
func die(message string, err error) {
......
......@@ -67,8 +67,15 @@ func init() {
}
func setFlags(cmd *cobra.Command, production bool) error {
flags := cmd.Flags()
flags.SortFlags = false
cmd.SetUsageTemplate(headerFlagsTemplate)
flagHeaders["irma server"] = map[string]string{
"port": "Server address and port to listen on",
"no-auth": "Requestor authentication and default requestor permissions",
"jwt-issuer": "JWT configuration",
"tls-cert": "TLS configuration (leave empty to disable TLS)",
"email": "Email address (see README for more info)",
"verbose": "Other options",
}
var defaulturl string
if !production {
......@@ -79,6 +86,9 @@ func setFlags(cmd *cobra.Command, production bool) error {
schemespath := irma.DefaultSchemesPath()
flags := cmd.Flags()
flags.SortFlags = false
flags.StringP("config", "c", "", "path to configuration file")
flags.StringP("schemes-path", "s", schemespath, "path to irma_configuration")
flags.String("schemes-assets-path", "", "if specified, copy schemes from here into --schemes-path")
......@@ -96,7 +106,6 @@ func setFlags(cmd *cobra.Command, production bool) error {
flags.StringP("api-prefix", "a", "/", "prefix API endpoints with this string, e.g. POST /session becomes POST {api-prefix}/session")
flags.Int("client-port", 0, "if specified, start a separate server for the IRMA app at this port")
flags.String("client-listen-addr", "", "address at which server for IRMA app listens")
flags.Lookup("port").Header = `Server address and port to listen on`
flags.Bool("no-auth", !production, "whether or not to authenticate requestors (and reject all authenticated requests)")
flags.String("requestors", "", "requestor configuration (in JSON)")
......@@ -110,7 +119,6 @@ func setFlags(cmd *cobra.Command, production bool) error {
flags.StringSlice("revoke-perms", nil, "list of credentials that all requestors may revoke")
flags.Bool("skip-private-keys-check", false, "whether or not to skip checking whether the private keys that requestors have permission for using are present in the configuration")
flags.String("static-sessions", "", "preconfigured static sessions (in JSON)")
flags.Lookup("no-auth").Header = `Requestor authentication and default requestor permissions`
flags.String("revocation-settings", "", "revocation settings (in JSON)")
......@@ -120,7 +128,6 @@ func setFlags(cmd *cobra.Command, production bool) error {
flags.Int("max-request-age", 300, "max age in seconds of a session request JWT")
flags.Bool("allow-unsigned-callbacks", false, "Allow callbackUrl in session requests when no JWT privatekey is installed (potentially unsafe)")
flags.Bool("augment-client-return-url", false, "Augment the client return url with the server session token if present")
flags.Lookup("jwt-issuer").Header = `JWT configuration`
flags.String("tls-cert", "", "TLS certificate (chain)")
flags.String("tls-cert-file", "", "path to TLS certificate (chain)")
......@@ -131,17 +138,14 @@ func setFlags(cmd *cobra.Command, production bool) error {
flags.String("client-tls-privkey", "", "TLS private key for IRMA app server")
flags.String("client-tls-privkey-file", "", "path to TLS private key for IRMA app server")
flags.Bool("no-tls", false, "Disable TLS")
flags.Lookup("tls-cert").Header = "TLS configuration (leave empty to disable TLS)"
flags.StringP("email", "e", "", "Email address of server admin, for incidental notifications such as breaking API changes")
flags.Bool("no-email", !production, "Opt out of providing an email address with --email")
flags.Lookup("email").Header = "Email address (see README for more info)"
flags.CountP("verbose", "v", "verbose (repeatable)")
flags.BoolP("quiet", "q", false, "quiet")
flags.Bool("log-json", false, "Log in JSON format")
flags.Bool("production", false, "Production mode")
flags.Lookup("verbose").Header = `Other options`
return nil
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment