// ParseFlags is a helper function for parsing command line flags using Go's // Flag library. This is extracted into a helper to keep the main function // small, but it also makes writing tests for parsing command line arguments // much easier and cleaner. func (cli *CLI) ParseFlags(args []string) (*config.Config, bool, bool, bool, error) { var dry, once, version bool c := config.DefaultConfig() // configPaths stores the list of configuration paths on disk configPaths := make([]string, 0, 6) // Parse the flags and options flags := flag.NewFlagSet(Name, flag.ContinueOnError) flags.SetOutput(cli.errStream) flags.Usage = func() { fmt.Fprintf(cli.errStream, usage, Name) } flags.Var((funcVar)(func(s string) error { configPaths = append(configPaths, s) return nil }), "config", "") flags.Var((funcVar)(func(s string) error { c.Consul.Address = config.String(s) return nil }), "consul-addr", "") flags.Var((funcVar)(func(s string) error { a, err := config.ParseAuthConfig(s) if err != nil { return err } c.Consul.Auth = a return nil }), "consul-auth", "") flags.Var((funcBoolVar)(func(b bool) error { c.Consul.Retry.Enabled = config.Bool(b) return nil }), "consul-retry", "") flags.Var((funcIntVar)(func(i int) error { c.Consul.Retry.Attempts = config.Int(i) return nil }), "consul-retry-attempts", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Consul.Retry.Backoff = config.TimeDuration(d) return nil }), "consul-retry-backoff", "") flags.Var((funcBoolVar)(func(b bool) error { c.Consul.SSL.Enabled = config.Bool(b) return nil }), "consul-ssl", "") flags.Var((funcVar)(func(s string) error { c.Consul.SSL.CaCert = config.String(s) return nil }), "consul-ssl-ca-cert", "") flags.Var((funcVar)(func(s string) error { c.Consul.SSL.CaPath = config.String(s) return nil }), "consul-ssl-ca-path", "") flags.Var((funcVar)(func(s string) error { c.Consul.SSL.Cert = config.String(s) return nil }), "consul-ssl-cert", "") flags.Var((funcVar)(func(s string) error { c.Consul.SSL.Key = config.String(s) return nil }), "consul-ssl-key", "") flags.Var((funcVar)(func(s string) error { c.Consul.SSL.ServerName = config.String(s) return nil }), "consul-ssl-server-name", "") flags.Var((funcBoolVar)(func(b bool) error { c.Consul.SSL.Verify = config.Bool(b) return nil }), "consul-ssl-verify", "") flags.Var((funcBoolVar)(func(b bool) error { c.Dedup.Enabled = config.Bool(b) return nil }), "dedup", "") flags.BoolVar(&dry, "dry", false, "") flags.Var((funcVar)(func(s string) error { c.Exec.Enabled = config.Bool(true) c.Exec.Command = config.String(s) return nil }), "exec", "") flags.Var((funcVar)(func(s string) error { sig, err := signals.Parse(s) if err != nil { return err } c.Exec.KillSignal = config.Signal(sig) return nil }), "exec-kill-signal", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Exec.KillTimeout = config.TimeDuration(d) return nil }), "exec-kill-timeout", "") flags.Var((funcVar)(func(s string) error { sig, err := signals.Parse(s) if err != nil { return err } c.Exec.ReloadSignal = config.Signal(sig) return nil }), "exec-reload-signal", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Exec.Splay = config.TimeDuration(d) return nil }), "exec-splay", "") flags.Var((funcVar)(func(s string) error { sig, err := signals.Parse(s) if err != nil { return err } c.KillSignal = config.Signal(sig) return nil }), "kill-signal", "") flags.Var((funcVar)(func(s string) error { c.LogLevel = config.String(s) return nil }), "log-level", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.MaxStale = config.TimeDuration(d) return nil }), "max-stale", "") flags.BoolVar(&once, "once", false, "") flags.Var((funcVar)(func(s string) error { c.PidFile = config.String(s) return nil }), "pid-file", "") flags.Var((funcVar)(func(s string) error { sig, err := signals.Parse(s) if err != nil { return err } c.ReloadSignal = config.Signal(sig) return nil }), "reload-signal", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Consul.Retry.Backoff = config.TimeDuration(d) return nil }), "retry", "") flags.Var((funcBoolVar)(func(b bool) error { c.Syslog.Enabled = config.Bool(b) return nil }), "syslog", "") flags.Var((funcVar)(func(s string) error { c.Syslog.Facility = config.String(s) return nil }), "syslog-facility", "") flags.Var((funcVar)(func(s string) error { t, err := config.ParseTemplateConfig(s) if err != nil { return err } *c.Templates = append(*c.Templates, t) return nil }), "template", "") flags.Var((funcVar)(func(s string) error { c.Consul.Token = config.String(s) return nil }), "token", "") flags.Var((funcVar)(func(s string) error { c.Vault.Address = config.String(s) return nil }), "vault-addr", "") flags.Var((funcBoolVar)(func(b bool) error { c.Vault.RenewToken = config.Bool(b) return nil }), "vault-renew-token", "") flags.Var((funcBoolVar)(func(b bool) error { c.Vault.Retry.Enabled = config.Bool(b) return nil }), "vault-retry", "") flags.Var((funcIntVar)(func(i int) error { c.Vault.Retry.Attempts = config.Int(i) return nil }), "vault-retry-attempts", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Vault.Retry.Backoff = config.TimeDuration(d) return nil }), "vault-retry-backoff", "") flags.Var((funcBoolVar)(func(b bool) error { c.Vault.SSL.Enabled = config.Bool(b) return nil }), "vault-ssl", "") flags.Var((funcVar)(func(s string) error { c.Vault.SSL.CaCert = config.String(s) return nil }), "vault-ssl-ca-cert", "") flags.Var((funcVar)(func(s string) error { c.Vault.SSL.CaPath = config.String(s) return nil }), "vault-ssl-ca-path", "") flags.Var((funcVar)(func(s string) error { c.Vault.SSL.Cert = config.String(s) return nil }), "vault-ssl-cert", "") flags.Var((funcVar)(func(s string) error { c.Vault.SSL.Key = config.String(s) return nil }), "vault-ssl-key", "") flags.Var((funcVar)(func(s string) error { c.Vault.SSL.ServerName = config.String(s) return nil }), "vault-ssl-server-name", "") flags.Var((funcBoolVar)(func(b bool) error { c.Vault.SSL.Verify = config.Bool(b) return nil }), "vault-ssl-verify", "") flags.Var((funcVar)(func(s string) error { c.Vault.Token = config.String(s) return nil }), "vault-token", "") flags.Var((funcBoolVar)(func(b bool) error { c.Vault.UnwrapToken = config.Bool(b) return nil }), "vault-unwrap-token", "") flags.Var((funcVar)(func(s string) error { w, err := config.ParseWaitConfig(s) if err != nil { return err } c.Wait = w return nil }), "wait", "") flags.BoolVar(&version, "v", false, "") flags.BoolVar(&version, "version", false, "") // TODO: Deprecations for i, a := range args { if a == "-auth" || strings.HasPrefix(a, "-auth=") { log.Println("[WARN] -auth has been renamed to -consul-auth") args[i] = strings.Replace(a, "-auth", "-consul-auth", 1) } if a == "-consul" || strings.HasPrefix(a, "-consul=") { log.Println("[WARN] -consul has been renamed to -consul-addr") args[i] = strings.Replace(a, "-consul", "-consul-addr", 1) } if strings.HasPrefix(a, "-ssl") { log.Println("[WARN] -ssl options should be prefixed with -consul") args[i] = strings.Replace(a, "-ssl", "-consul-ssl", 1) } } // If there was a parser error, stop if err := flags.Parse(args); err != nil { return nil, false, false, false, err } // Error if extra arguments are present args = flags.Args() if len(args) > 0 { return nil, false, false, false, fmt.Errorf("cli: extra args: %q", args) } // Create the final configuration finalC := config.DefaultConfig() // Merge all the provided configurations in the order supplied for _, path := range configPaths { c, err := config.FromPath(path) if err != nil { return nil, false, false, false, err } finalC = finalC.Merge(c) } // Add any CLI configuration options, since that's highest precedence finalC = finalC.Merge(c) // Finalize the configuration finalC.Finalize() return finalC, once, dry, version, nil }
// parseFlags is a helper function for parsing command line flags using Go's // Flag library. This is extracted into a helper to keep the main function // small, but it also makes writing tests for parsing command line arguments // much easier and cleaner. func (cli *CLI) parseFlags(args []string) (*Config, bool, bool, error) { var once, version bool c := DefaultConfig() // Parse the flags and options flags := flag.NewFlagSet(Name, flag.ContinueOnError) flags.SetOutput(cli.errStream) flags.Usage = func() { fmt.Fprintf(cli.errStream, usage, Name) } flags.Var((funcVar)(func(s string) error { c.Consul = s c.set("consul") return nil }), "consul", "") flags.Var((funcVar)(func(s string) error { c.Token = s c.set("token") return nil }), "token", "") flags.Var((funcVar)(func(s string) error { c.Auth.Enabled = true c.set("auth.enabled") if strings.Contains(s, ":") { split := strings.SplitN(s, ":", 2) c.Auth.Username = split[0] c.set("auth.username") c.Auth.Password = split[1] c.set("auth.password") } else { c.Auth.Username = s c.set("auth.username") } return nil }), "auth", "") flags.Var((funcBoolVar)(func(b bool) error { c.SSL.Enabled = b c.set("ssl") c.set("ssl.enabled") return nil }), "ssl", "") flags.Var((funcBoolVar)(func(b bool) error { c.SSL.Verify = b c.set("ssl") c.set("ssl.verify") return nil }), "ssl-verify", "") flags.Var((funcVar)(func(s string) error { c.SSL.Cert = s c.set("ssl") c.set("ssl.cert") return nil }), "ssl-cert", "") flags.Var((funcVar)(func(s string) error { c.SSL.Key = s c.set("ssl") c.set("ssl.key") return nil }), "ssl-key", "") flags.Var((funcVar)(func(s string) error { c.SSL.CaCert = s c.set("ssl") c.set("ssl.ca_cert") return nil }), "ssl-ca-cert", "") flags.Var((funcVar)(func(s string) error { c.SSL.CaPath = s c.set("ssl") c.set("ssl.ca_path") return nil }), "ssl-ca-path", "") flags.Var((funcVar)(func(s string) error { c.SSL.ServerName = s c.set("ssl") c.set("ssl.server_name") return nil }), "ssl-server-name", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.MaxStale = d c.set("max_stale") return nil }), "max-stale", "") flags.Var((funcVar)(func(s string) error { p, err := ParsePrefix(s) if err != nil { return err } if c.Prefixes == nil { c.Prefixes = make([]*Prefix, 0, 1) } c.Prefixes = append(c.Prefixes, p) return nil }), "prefix", "") flags.Var((funcVar)(func(s string) error { if c.Excludes == nil { c.Excludes = make([]*Exclude, 0, 1) } c.Excludes = append(c.Excludes, &Exclude{Source: s}) return nil }), "exclude", "") flags.Var((funcBoolVar)(func(b bool) error { c.Syslog.Enabled = b c.set("syslog") c.set("syslog.enabled") return nil }), "syslog", "") flags.Var((funcVar)(func(s string) error { c.Syslog.Facility = s c.set("syslog.facility") return nil }), "syslog-facility", "") flags.Var((funcVar)(func(s string) error { w, err := config.ParseWaitConfig(s) if err != nil { return err } c.Wait.Min = w.Min c.Wait.Max = w.Max c.set("wait") return nil }), "wait", "") flags.Var((funcDurationVar)(func(d time.Duration) error { c.Retry = d c.set("retry") return nil }), "retry", "") flags.Var((funcVar)(func(s string) error { c.Path = s c.set("path") return nil }), "config", "") flags.Var((funcVar)(func(s string) error { c.PidFile = s c.set("pid_file") return nil }), "pid-file", "") flags.Var((funcVar)(func(s string) error { c.StatusDir = s c.set("status_dir") return nil }), "status-dir", "") flags.Var((funcVar)(func(s string) error { c.LogLevel = s c.set("log_level") return nil }), "log-level", "") flags.BoolVar(&once, "once", false, "") flags.BoolVar(&version, "v", false, "") flags.BoolVar(&version, "version", false, "") // If there was a parser error, stop if err := flags.Parse(args); err != nil { return nil, false, false, err } // Error if extra arguments are present args = flags.Args() if len(args) > 0 { return nil, false, false, fmt.Errorf("cli: extra argument(s): %q", args) } return c, once, version, nil }