Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

misc: improve flags help #135

Merged
merged 2 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,14 @@ Additional Commands:
limits Show the current rate limits
version Display the version of your installed Globalping CLI

Flags:
-C, --ci disable real-time terminal updates and colors, suitable for CI and
scripting (default false)
Global Measurement Flags:
-F, --from string specify the probe locations as a comma-separated list; you may use:
- names of continents, regions, countries, US states, cities, or
networks
- [@1 | first, @2 ... @-2, @-1 | last | previous] to run with the probes
from previous measurements in this session
- an ID of a previous measurement to run with its probes
(default "world")
-h, --help help for globalping
-4, --ipv4 resolve names to IPv4 addresses
-6, --ipv6 resolve names to IPv6 addresses
-J, --json output results in JSON format (default false)
Expand All @@ -116,6 +113,11 @@ Flags:
--share print a link at the end of the results to visualize them online (default
false)

Global Flags:
-C, --ci disable real-time terminal updates and colors, suitable for CI and scripting
(default false)
-h, --help help for globalping

Use "globalping [command] --help" for more information about a command.
```

Expand Down
17 changes: 10 additions & 7 deletions cmd/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import (
"github.com/jsdelivr/globalping-cli/globalping"
"github.com/jsdelivr/globalping-cli/view"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func (r *Root) initDNS() {
func (r *Root) initDNS(measurementFlags *pflag.FlagSet, localFlags *pflag.FlagSet) {
dnsCmd := &cobra.Command{
RunE: r.RunDNS,
Use: "dns [target] from [location | measurement ID | @1 | first | @-1 | last | previous]",
Expand Down Expand Up @@ -53,12 +54,14 @@ Examples:
}

// dns specific flags
flags := dnsCmd.Flags()
flags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for the DNS query: TCP or UDP (default \"udp\")")
flags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify a non-standard port on the server to send the query to (default 53)")
flags.StringVar(&r.ctx.Resolver, "resolver", r.ctx.Resolver, "specify the hostname or IP address of the name server to use as the resolver (default defined by the probe)")
flags.StringVar(&r.ctx.QueryType, "type", r.ctx.QueryType, "specify the type of DNS query to perform (default \"A\")")
flags.BoolVar(&r.ctx.Trace, "trace", r.ctx.Trace, "enable tracing of the delegation path from the root name servers (default false)")
localFlags.BoolP("help", "h", false, "help for dns")
localFlags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for the DNS query: TCP or UDP (default \"udp\")")
localFlags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify a non-standard port on the server to send the query to (default 53)")
localFlags.StringVar(&r.ctx.Resolver, "resolver", r.ctx.Resolver, "specify the hostname or IP address of the name server to use as the resolver (default defined by the probe)")
localFlags.StringVar(&r.ctx.QueryType, "type", r.ctx.QueryType, "specify the type of DNS query to perform (default \"A\")")
localFlags.BoolVar(&r.ctx.Trace, "trace", r.ctx.Trace, "enable tracing of the delegation path from the root name servers (default false)")
dnsCmd.Flags().AddFlagSet(measurementFlags)
dnsCmd.Flags().AddFlagSet(localFlags)

r.Cmd.AddCommand(dnsCmd)
}
Expand Down
25 changes: 14 additions & 11 deletions cmd/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
"github.com/jsdelivr/globalping-cli/view"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func (r *Root) initHTTP() {
func (r *Root) initHTTP(measurementFlags *pflag.FlagSet, localFlags *pflag.FlagSet) {
httpCmd := &cobra.Command{
RunE: r.RunHTTP,
Use: "http [target] from [location | measurement ID | @1 | first | @-1 | last | previous]",
Expand Down Expand Up @@ -68,16 +69,18 @@ Examples:
}

// http specific flags
flags := httpCmd.Flags()
flags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use: HTTP, HTTPS, or HTTP2 (default \"HTTP\")")
flags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use (default 80 for HTTP, 443 for HTTPS and HTTP2)")
flags.StringVar(&r.ctx.Resolver, "resolver", r.ctx.Resolver, "specify the hostname or IP address of the name server to use for the DNS lookup (default defined by the probe)")
flags.StringVar(&r.ctx.Host, "host", r.ctx.Host, "specify the Host header to add to the request (default host's defined in command target)")
flags.StringVar(&r.ctx.Path, "path", r.ctx.Path, "specify the URL pathname (default \"/\")")
flags.StringVar(&r.ctx.Query, "query", r.ctx.Query, "specify a query string to add")
flags.StringVarP(&r.ctx.Method, "method", "X", r.ctx.Method, "specify the HTTP method to use: HEAD or GET (default \"HEAD\")")
flags.StringArrayVarP(&r.ctx.Headers, "header", "H", r.ctx.Headers, "add HTTP headers to the request in the format \"Key: Value\"; to add multiple headers, define the flag for each one separately")
flags.BoolVar(&r.ctx.Full, "full", r.ctx.Full, "enable full output when performing an HTTP GET request to display the status, headers, and body")
localFlags.BoolP("help", "h", false, "help for http")
localFlags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use: HTTP, HTTPS, or HTTP2 (default \"HTTP\")")
localFlags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use (default 80 for HTTP, 443 for HTTPS and HTTP2)")
localFlags.StringVar(&r.ctx.Resolver, "resolver", r.ctx.Resolver, "specify the hostname or IP address of the name server to use for the DNS lookup (default defined by the probe)")
localFlags.StringVar(&r.ctx.Host, "host", r.ctx.Host, "specify the Host header to add to the request (default host's defined in command target)")
localFlags.StringVar(&r.ctx.Path, "path", r.ctx.Path, "specify the URL pathname (default \"/\")")
localFlags.StringVar(&r.ctx.Query, "query", r.ctx.Query, "specify a query string to add")
localFlags.StringVarP(&r.ctx.Method, "method", "X", r.ctx.Method, "specify the HTTP method to use: HEAD or GET (default \"HEAD\")")
localFlags.StringArrayVarP(&r.ctx.Headers, "header", "H", r.ctx.Headers, "add HTTP headers to the request in the format \"Key: Value\"; to add multiple headers, define the flag for each one separately")
localFlags.BoolVar(&r.ctx.Full, "full", r.ctx.Full, "enable full output when performing an HTTP GET request to display the status, headers, and body")
httpCmd.Flags().AddFlagSet(measurementFlags)
httpCmd.Flags().AddFlagSet(localFlags)

r.Cmd.AddCommand(httpCmd)
}
Expand Down
13 changes: 8 additions & 5 deletions cmd/mtr.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"github.com/jsdelivr/globalping-cli/globalping"
"github.com/jsdelivr/globalping-cli/view"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func (r *Root) initMTR() {
func (r *Root) initMTR(measurementFlags *pflag.FlagSet, localFlags *pflag.FlagSet) {
mtrCmd := &cobra.Command{
RunE: r.RunMTR,
Use: "mtr [target] from [location | measurement ID | @1 | first | @-1 | last | previous]",
Expand Down Expand Up @@ -46,10 +47,12 @@ Examples:
}

// mtr specific flags
flags := mtrCmd.Flags()
flags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for MTR: ICMP, TCP, or UDP (default \"icmp\")")
flags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use for MTR; only applicable for the TCP protocol (default 53)")
flags.IntVar(&r.ctx.Packets, "packets", r.ctx.Packets, "specify the number of packets to send to each hop (default 3)")
localFlags.BoolP("help", "h", false, "help for mtr")
localFlags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for MTR: ICMP, TCP, or UDP (default \"icmp\")")
localFlags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use for MTR; only applicable for the TCP protocol (default 53)")
localFlags.IntVar(&r.ctx.Packets, "packets", r.ctx.Packets, "specify the number of packets to send to each hop (default 3)")
mtrCmd.Flags().AddFlagSet(measurementFlags)
mtrCmd.Flags().AddFlagSet(localFlags)

r.Cmd.AddCommand(mtrCmd)
}
Expand Down
11 changes: 7 additions & 4 deletions cmd/ping.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import (
"github.com/jsdelivr/globalping-cli/globalping"
"github.com/jsdelivr/globalping-cli/view"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func (r *Root) initPing() {
func (r *Root) initPing(measurementFlags *pflag.FlagSet, localFlags *pflag.FlagSet) {
pingCmd := &cobra.Command{
RunE: r.RunPing,
Use: "ping [target] from [location | measurement ID | @1 | first | @-1 | last | previous]",
Expand Down Expand Up @@ -51,9 +52,11 @@ Examples:
}

// ping specific flags
flags := pingCmd.Flags()
flags.IntVar(&r.ctx.Packets, "packets", r.ctx.Packets, "specify the number of ECHO_REQUEST packets to send (default 3)")
flags.BoolVar(&r.ctx.Infinite, "infinite", r.ctx.Infinite, "enable continuous pinging of the target until manually stopped (default false)")
localFlags.BoolP("help", "h", false, "help for ping")
localFlags.IntVar(&r.ctx.Packets, "packets", r.ctx.Packets, "specify the number of ECHO_REQUEST packets to send (default 3)")
localFlags.BoolVar(&r.ctx.Infinite, "infinite", r.ctx.Infinite, "enable continuous pinging of the target until manually stopped (default false)")
pingCmd.Flags().AddFlagSet(measurementFlags)
pingCmd.Flags().AddFlagSet(localFlags)

r.Cmd.AddCommand(pingCmd)
}
Expand Down
75 changes: 59 additions & 16 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"github.com/spf13/cobra"
)

var flagGroups = map[string]*pflag.FlagSet{}

type Root struct {
printer *view.Printer
ctx *view.Context
Expand Down Expand Up @@ -119,31 +121,45 @@ For more information about the platform, tips, and best practices, visit our Git
root.Cmd.SetErr(printer.ErrWriter)

cobra.AddTemplateFunc("wrappedFlagUsages", wrappedFlagUsages)
cobra.AddTemplateFunc("isMeasurementCommand", isMeasurementCommand)
cobra.AddTemplateFunc("localMeasurementFlags", localMeasurementFlags)
cobra.AddTemplateFunc("globalMeasurementFlags", globalMeasurementFlags)

root.Cmd.SetUsageTemplate(usageTemplate)
root.Cmd.SetHelpTemplate(helpTemplate)

// Global flags
flags := root.Cmd.PersistentFlags()
flags.StringVarP(&ctx.From, "from", "F", ctx.From, `specify the probe locations as a comma-separated list; you may use:
root.Cmd.PersistentFlags().BoolVarP(&ctx.CIMode, "ci", "C", ctx.CIMode, "disable real-time terminal updates and colors, suitable for CI and scripting (default false)")

// Measurement flags
measurementFlags := pflag.NewFlagSet("measurements", pflag.ExitOnError)
measurementFlags.StringVarP(&ctx.From, "from", "F", ctx.From, `specify the probe locations as a comma-separated list; you may use:
- names of continents, regions, countries, US states, cities, or networks
- [@1 | first, @2 ... @-2, @-1 | last | previous] to run with the probes from previous measurements in this session
- an ID of a previous measurement to run with its probes
`)
flags.IntVarP(&ctx.Limit, "limit", "L", ctx.Limit, "define the number of probes to use")
flags.BoolVarP(&ctx.ToJSON, "json", "J", ctx.ToJSON, "output results in JSON format (default false)")
flags.BoolVarP(&ctx.CIMode, "ci", "C", ctx.CIMode, "disable real-time terminal updates and colors, suitable for CI and scripting (default false)")
flags.BoolVar(&ctx.ToLatency, "latency", ctx.ToLatency, "output only the latency stats; applicable only to dns, http, and ping commands (default false)")
flags.BoolVar(&ctx.Share, "share", ctx.Share, "print a link at the end of the results to visualize them online (default false)")
flags.BoolVarP(&ctx.Ipv4, "ipv4", "4", ctx.Ipv4, "resolve names to IPv4 addresses")
flags.BoolVarP(&ctx.Ipv6, "ipv6", "6", ctx.Ipv6, "resolve names to IPv6 addresses")
measurementFlags.IntVarP(&ctx.Limit, "limit", "L", ctx.Limit, "define the number of probes to use")
measurementFlags.BoolVarP(&ctx.ToJSON, "json", "J", ctx.ToJSON, "output results in JSON format (default false)")
measurementFlags.BoolVar(&ctx.ToLatency, "latency", ctx.ToLatency, "output only the latency stats; applicable only to dns, http, and ping commands (default false)")
measurementFlags.BoolVar(&ctx.Share, "share", ctx.Share, "print a link at the end of the results to visualize them online (default false)")
measurementFlags.BoolVarP(&ctx.Ipv4, "ipv4", "4", ctx.Ipv4, "resolve names to IPv4 addresses")
measurementFlags.BoolVarP(&ctx.Ipv6, "ipv6", "6", ctx.Ipv6, "resolve names to IPv6 addresses")

root.Cmd.AddGroup(&cobra.Group{ID: "Measurements", Title: "Measurement Commands:"})

root.initDNS()
root.initHTTP()
root.initMTR()
root.initPing()
root.initTraceroute()
flagGroups["globalping"] = root.Cmd.Flags()
flagGroups["globalping dns"] = pflag.NewFlagSet("dns", pflag.ExitOnError)
flagGroups["globalping http"] = pflag.NewFlagSet("http", pflag.ExitOnError)
flagGroups["globalping mtr"] = pflag.NewFlagSet("mtr", pflag.ExitOnError)
flagGroups["globalping ping"] = pflag.NewFlagSet("ping", pflag.ExitOnError)
flagGroups["globalping traceroute"] = pflag.NewFlagSet("traceroute", pflag.ExitOnError)
flagGroups["measurements"] = measurementFlags

root.initDNS(measurementFlags, flagGroups["globalping dns"])
root.initHTTP(measurementFlags, flagGroups["globalping http"])
root.initMTR(measurementFlags, flagGroups["globalping mtr"])
root.initPing(measurementFlags, flagGroups["globalping ping"])
root.initTraceroute(measurementFlags, flagGroups["globalping traceroute"])
root.initInstallProbe()
root.initVersion()
root.initHistory()
Expand All @@ -168,6 +184,18 @@ func wrappedFlagUsages(cmd *pflag.FlagSet) string {
return cmd.FlagUsagesWrapped(width - 1)
}

func isMeasurementCommand(name string) bool {
return flagGroups[name] != nil
}

func localMeasurementFlags(name string) string {
return wrappedFlagUsages(flagGroups[name])
}

func globalMeasurementFlags() string {
return wrappedFlagUsages(flagGroups["measurements"])
}

// Identical to the default cobra usage template,
// but utilizes wrappedFlagUsages to ensure flag usages don't wrap around
var usageTemplate = `
Expand All @@ -192,13 +220,28 @@ Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help")
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}

Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if (eq .CommandPath "globalping")}}

Global Measurement Flags:
{{globalMeasurementFlags | trimTrailingWhitespaces}}

Global Flags:
{{wrappedFlagUsages .LocalFlags | trimTrailingWhitespaces}}{{else}}{{if isMeasurementCommand .CommandPath}}

Flags:
{{localMeasurementFlags .CommandPath | trimTrailingWhitespaces}}

Global Measurement Flags:
{{globalMeasurementFlags | trimTrailingWhitespaces}}{{if .HasAvailableInheritedFlags}}

Global Flags:
{{wrappedFlagUsages .InheritedFlags | trimTrailingWhitespaces}}{{end}}{{else}}{{if .HasAvailableLocalFlags}}

Flags:
{{wrappedFlagUsages .LocalFlags | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}

Global Flags:
{{wrappedFlagUsages .InheritedFlags | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
{{wrappedFlagUsages .InheritedFlags | trimTrailingWhitespaces}}{{end}}{{end}}{{end}}{{if .HasHelpSubCommands}}

Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
Expand Down
11 changes: 7 additions & 4 deletions cmd/traceroute.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"github.com/jsdelivr/globalping-cli/globalping"
"github.com/jsdelivr/globalping-cli/view"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)

func (r *Root) initTraceroute() {
func (r *Root) initTraceroute(measurementFlags *pflag.FlagSet, localFlags *pflag.FlagSet) {
var tracerouteCmd = &cobra.Command{
RunE: r.RunTraceroute,
Use: "traceroute [target] from [location | measurement ID | @1 | first | @-1 | last | previous]",
Expand Down Expand Up @@ -49,9 +50,11 @@ Examples:
}

// traceroute specific flags
flags := tracerouteCmd.Flags()
flags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for tracerouting: ICMP, TCP, or UDP (default \"icmp\")")
flags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use for the traceroute; only applicable for the TCP protocol (default 80)")
localFlags.BoolP("help", "h", false, "help for traceroute")
localFlags.StringVar(&r.ctx.Protocol, "protocol", r.ctx.Protocol, "specify the protocol to use for tracerouting: ICMP, TCP, or UDP (default \"icmp\")")
localFlags.IntVar(&r.ctx.Port, "port", r.ctx.Port, "specify the port to use for the traceroute; only applicable for the TCP protocol (default 80)")
tracerouteCmd.Flags().AddFlagSet(measurementFlags)
tracerouteCmd.Flags().AddFlagSet(localFlags)

r.Cmd.AddCommand(tracerouteCmd)
}
Expand Down