diff --git a/cmd/tailscale/cli/bugreport.go b/cmd/tailscale/cli/bugreport.go index 1c2640c2d..d671f3df6 100644 --- a/cmd/tailscale/cli/bugreport.go +++ b/cmd/tailscale/cli/bugreport.go @@ -17,7 +17,7 @@ var bugReportCmd = &ffcli.Command{ Name: "bugreport", Exec: runBugReport, ShortHelp: "Print a shareable identifier to help diagnose issues", - ShortUsage: "bugreport [note]", + ShortUsage: "tailscale bugreport [note]", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("bugreport") fs.BoolVar(&bugReportArgs.diagnose, "diagnose", false, "run additional in-depth checks") diff --git a/cmd/tailscale/cli/cert.go b/cmd/tailscale/cli/cert.go index eeafa2b33..db0f057ce 100644 --- a/cmd/tailscale/cli/cert.go +++ b/cmd/tailscale/cli/cert.go @@ -28,7 +28,7 @@ var certCmd = &ffcli.Command{ Name: "cert", Exec: runCert, ShortHelp: "Get TLS certs", - ShortUsage: "cert [flags] ", + ShortUsage: "tailscale cert [flags] ", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("cert") fs.StringVar(&certArgs.certFile, "cert-file", "", "output cert file or \"-\" for stdout; defaults to DOMAIN.crt if --cert-file and --key-file are both unset") diff --git a/cmd/tailscale/cli/cli.go b/cmd/tailscale/cli/cli.go index 5eb75772e..fe6288ddf 100644 --- a/cmd/tailscale/cli/cli.go +++ b/cmd/tailscale/cli/cli.go @@ -14,7 +14,6 @@ import ( "log" "os" "runtime" - "slices" "strings" "sync" "text/tabwriter" @@ -95,6 +94,49 @@ func Run(args []string) (err error) { }) }) + rootCmd := newRootCmd() + if err := rootCmd.Parse(args); err != nil { + if errors.Is(err, flag.ErrHelp) { + return nil + } + return err + } + + if envknob.Bool("TS_DUMP_HELP") { + walkCommands(rootCmd, func(c *ffcli.Command) { + fmt.Println("===") + // UsageFuncs are typically called during Command.Run which ensures + // FlagSet is not nil. + if c.FlagSet == nil { + c.FlagSet = flag.NewFlagSet(c.Name, flag.ContinueOnError) + } + if c.UsageFunc != nil { + fmt.Println(c.UsageFunc(c)) + } else { + fmt.Println(ffcli.DefaultUsageFunc(c)) + } + }) + return + } + + localClient.Socket = rootArgs.socket + rootCmd.FlagSet.Visit(func(f *flag.Flag) { + if f.Name == "socket" { + localClient.UseSocketOnly = true + } + }) + + err = rootCmd.Run(context.Background()) + if tailscale.IsAccessDeniedError(err) && os.Getuid() != 0 && runtime.GOOS != "windows" { + return fmt.Errorf("%v\n\nUse 'sudo tailscale %s' or 'tailscale up --operator=$USER' to not require root.", err, strings.Join(args, " ")) + } + if errors.Is(err, flag.ErrHelp) { + return nil + } + return err +} + +func newRootCmd() *ffcli.Command { rootfs := newFlagSet("tailscale") rootfs.StringVar(&rootArgs.socket, "socket", paths.DefaultTailscaledSocket(), "path to tailscaled socket") @@ -134,10 +176,11 @@ change in the future. exitNodeCmd(), updateCmd, whoisCmd, + debugCmd, + driveCmd, }, - FlagSet: rootfs, - Exec: func(context.Context, []string) error { return flag.ErrHelp }, - UsageFunc: usageFunc, + FlagSet: rootfs, + Exec: func(context.Context, []string) error { return flag.ErrHelp }, } if envknob.UseWIPCode() { rootCmd.Subcommands = append(rootCmd.Subcommands, @@ -145,45 +188,16 @@ change in the future. ) } - // Don't advertise these commands, but they're still explicitly available. - switch { - case slices.Contains(args, "debug"): - rootCmd.Subcommands = append(rootCmd.Subcommands, debugCmd) - case slices.Contains(args, "drive"): - rootCmd.Subcommands = append(rootCmd.Subcommands, driveCmd) - } if runtime.GOOS == "linux" && distro.Get() == distro.Synology { rootCmd.Subcommands = append(rootCmd.Subcommands, configureHostCmd) } - for _, c := range rootCmd.Subcommands { + walkCommands(rootCmd, func(c *ffcli.Command) { if c.UsageFunc == nil { c.UsageFunc = usageFunc } - } - - if err := rootCmd.Parse(args); err != nil { - if errors.Is(err, flag.ErrHelp) { - return nil - } - return err - } - - localClient.Socket = rootArgs.socket - rootfs.Visit(func(f *flag.Flag) { - if f.Name == "socket" { - localClient.UseSocketOnly = true - } }) - - err = rootCmd.Run(context.Background()) - if tailscale.IsAccessDeniedError(err) && os.Getuid() != 0 && runtime.GOOS != "windows" { - return fmt.Errorf("%v\n\nUse 'sudo tailscale %s' or 'tailscale up --operator=$USER' to not require root.", err, strings.Join(args, " ")) - } - if errors.Is(err, flag.ErrHelp) { - return nil - } - return err + return rootCmd } func fatalf(format string, a ...any) { @@ -202,6 +216,13 @@ var rootArgs struct { socket string } +func walkCommands(cmd *ffcli.Command, f func(*ffcli.Command)) { + f(cmd) + for _, sub := range cmd.Subcommands { + walkCommands(sub, f) + } +} + // usageFuncNoDefaultValues is like usageFunc but doesn't print default values. func usageFuncNoDefaultValues(c *ffcli.Command) string { return usageFuncOpt(c, false) @@ -213,23 +234,32 @@ func usageFunc(c *ffcli.Command) string { func usageFuncOpt(c *ffcli.Command, withDefaults bool) string { var b strings.Builder + const hiddenPrefix = "HIDDEN: " + + if c.ShortHelp != "" { + fmt.Fprintf(&b, "%s\n\n", c.ShortHelp) + } fmt.Fprintf(&b, "USAGE\n") if c.ShortUsage != "" { - fmt.Fprintf(&b, " %s\n", c.ShortUsage) + fmt.Fprintf(&b, " %s\n", strings.ReplaceAll(c.ShortUsage, "\n", "\n ")) } else { fmt.Fprintf(&b, " %s\n", c.Name) } fmt.Fprintf(&b, "\n") if c.LongHelp != "" { - fmt.Fprintf(&b, "%s\n\n", c.LongHelp) + help, _ := strings.CutPrefix(c.LongHelp, hiddenPrefix) + fmt.Fprintf(&b, "%s\n\n", help) } if len(c.Subcommands) > 0 { fmt.Fprintf(&b, "SUBCOMMANDS\n") tw := tabwriter.NewWriter(&b, 0, 2, 2, ' ', 0) for _, subcommand := range c.Subcommands { + if strings.HasPrefix(subcommand.LongHelp, hiddenPrefix) { + continue + } fmt.Fprintf(tw, " %s\t%s\n", subcommand.Name, subcommand.ShortHelp) } tw.Flush() @@ -242,7 +272,7 @@ func usageFuncOpt(c *ffcli.Command, withDefaults bool) string { c.FlagSet.VisitAll(func(f *flag.Flag) { var s string name, usage := flag.UnquoteUsage(f) - if strings.HasPrefix(usage, "HIDDEN: ") { + if strings.HasPrefix(usage, hiddenPrefix) { return } if isBoolFlag(f) { diff --git a/cmd/tailscale/cli/cli_test.go b/cmd/tailscale/cli/cli_test.go index 604a1511b..5b438ec9c 100644 --- a/cmd/tailscale/cli/cli_test.go +++ b/cmd/tailscale/cli/cli_test.go @@ -16,6 +16,7 @@ import ( qt "github.com/frankban/quicktest" "github.com/google/go-cmp/cmp" + "github.com/peterbourgon/ff/v3/ffcli" "tailscale.com/envknob" "tailscale.com/health/healthmsg" "tailscale.com/ipn" @@ -29,15 +30,37 @@ import ( "tailscale.com/version/distro" ) +func TestPanicIfAnyEnvCheckedInInit(t *testing.T) { + envknob.PanicIfAnyEnvCheckedInInit() +} + +func TestShortUsage_FullCmd(t *testing.T) { + t.Setenv("TAILSCALE_USE_WIP_CODE", "1") + if !envknob.UseWIPCode() { + t.Fatal("expected envknob.UseWIPCode() to be true") + } + + // Some commands have more than one path from the root, so investigate all + // paths before we report errors. + ok := make(map[*ffcli.Command]bool) + root := newRootCmd() + walkCommands(root, func(c *ffcli.Command) { + if !ok[c] { + ok[c] = strings.HasPrefix(c.ShortUsage, "tailscale ") && (c.Name == "tailscale" || strings.Contains(c.ShortUsage, " "+c.Name+" ") || strings.HasSuffix(c.ShortUsage, " "+c.Name)) + } + }) + walkCommands(root, func(c *ffcli.Command) { + if !ok[c] { + t.Errorf("subcommand %s should show full usage ('tailscale ... %s ...') in ShortUsage (%q)", c.Name, c.Name, c.ShortUsage) + } + }) +} + // geese is a collection of gooses. It need not be complete. // But it should include anything handled specially (e.g. linux, windows) // and at least one thing that's not (darwin, freebsd). var geese = []string{"linux", "darwin", "windows", "freebsd"} -func TestPanicIfAnyEnvCheckedInInit(t *testing.T) { - envknob.PanicIfAnyEnvCheckedInInit() -} - // Test that checkForAccidentalSettingReverts's updateMaskedPrefsFromUpFlag can handle // all flags. This will panic if a new flag creeps in that's unhandled. // diff --git a/cmd/tailscale/cli/configure-kube.go b/cmd/tailscale/cli/configure-kube.go index a663a65bc..6af15e3d9 100644 --- a/cmd/tailscale/cli/configure-kube.go +++ b/cmd/tailscale/cli/configure-kube.go @@ -27,7 +27,7 @@ func init() { var configureKubeconfigCmd = &ffcli.Command{ Name: "kubeconfig", ShortHelp: "[ALPHA] Connect to a Kubernetes cluster using a Tailscale Auth Proxy", - ShortUsage: "kubeconfig ", + ShortUsage: "tailscale configure kubeconfig ", LongHelp: strings.TrimSpace(` Run this command to configure kubectl to connect to a Kubernetes cluster over Tailscale. diff --git a/cmd/tailscale/cli/configure-synology.go b/cmd/tailscale/cli/configure-synology.go index b44828d01..3c189d5ef 100644 --- a/cmd/tailscale/cli/configure-synology.go +++ b/cmd/tailscale/cli/configure-synology.go @@ -22,10 +22,11 @@ import ( // used to configure Synology devices, but is now a compatibility alias to // "tailscale configure synology". var configureHostCmd = &ffcli.Command{ - Name: "configure-host", - Exec: runConfigureSynology, - ShortHelp: synologyConfigureCmd.ShortHelp, - LongHelp: synologyConfigureCmd.LongHelp, + Name: "configure-host", + Exec: runConfigureSynology, + ShortUsage: "tailscale configure-host", + ShortHelp: synologyConfigureCmd.ShortHelp, + LongHelp: synologyConfigureCmd.LongHelp, FlagSet: (func() *flag.FlagSet { fs := newFlagSet("configure-host") return fs @@ -33,9 +34,10 @@ var configureHostCmd = &ffcli.Command{ } var synologyConfigureCmd = &ffcli.Command{ - Name: "synology", - Exec: runConfigureSynology, - ShortHelp: "Configure Synology to enable outbound connections", + Name: "synology", + Exec: runConfigureSynology, + ShortUsage: "tailscale configure synology", + ShortHelp: "Configure Synology to enable outbound connections", LongHelp: strings.TrimSpace(` This command is intended to run at boot as root on a Synology device to create the /dev/net/tun device and give the tailscaled binary permission diff --git a/cmd/tailscale/cli/configure.go b/cmd/tailscale/cli/configure.go index e8e9cd8f2..0b4703e79 100644 --- a/cmd/tailscale/cli/configure.go +++ b/cmd/tailscale/cli/configure.go @@ -14,8 +14,9 @@ import ( ) var configureCmd = &ffcli.Command{ - Name: "configure", - ShortHelp: "[ALPHA] Configure the host to enable more Tailscale features", + Name: "configure", + ShortUsage: "tailscale configure ", + ShortHelp: "[ALPHA] Configure the host to enable more Tailscale features", LongHelp: strings.TrimSpace(` The 'configure' set of commands are intended to provide a way to enable different services on the host to use Tailscale in more ways. diff --git a/cmd/tailscale/cli/debug.go b/cmd/tailscale/cli/debug.go index 92ae7bb0b..b8ac7bd9b 100644 --- a/cmd/tailscale/cli/debug.go +++ b/cmd/tailscale/cli/debug.go @@ -45,9 +45,10 @@ import ( ) var debugCmd = &ffcli.Command{ - Name: "debug", - Exec: runDebug, - LongHelp: `"tailscale debug" contains misc debug facilities; it is not a stable interface.`, + Name: "debug", + Exec: runDebug, + ShortUsage: "tailscale debug ", + LongHelp: `HIDDEN: "tailscale debug" contains misc debug facilities; it is not a stable interface.`, FlagSet: (func() *flag.FlagSet { fs := newFlagSet("debug") fs.StringVar(&debugArgs.file, "file", "", "get, delete:NAME, or NAME") @@ -58,15 +59,16 @@ var debugCmd = &ffcli.Command{ })(), Subcommands: []*ffcli.Command{ { - Name: "derp-map", - Exec: runDERPMap, - ShortHelp: "print DERP map", + Name: "derp-map", + ShortUsage: "tailscale debug derp-map", + Exec: runDERPMap, + ShortHelp: "Print DERP map", }, { Name: "component-logs", - Exec: runDebugComponentLogs, - ShortHelp: "enable/disable debug logs for a component", ShortUsage: "tailscale debug component-logs [" + strings.Join(ipn.DebuggableComponents, "|") + "]", + Exec: runDebugComponentLogs, + ShortHelp: "Enable/disable debug logs for a component", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("component-logs") fs.DurationVar(&debugComponentLogsArgs.forDur, "for", time.Hour, "how long to enable debug logs for; zero or negative means to disable") @@ -74,14 +76,16 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "daemon-goroutines", - Exec: runDaemonGoroutines, - ShortHelp: "print tailscaled's goroutines", + Name: "daemon-goroutines", + ShortUsage: "tailscale debug daemon-goroutines", + Exec: runDaemonGoroutines, + ShortHelp: "Print tailscaled's goroutines", }, { - Name: "daemon-logs", - Exec: runDaemonLogs, - ShortHelp: "watch tailscaled's server logs", + Name: "daemon-logs", + ShortUsage: "tailscale debug daemon-logs", + Exec: runDaemonLogs, + ShortHelp: "Watch tailscaled's server logs", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("daemon-logs") fs.IntVar(&daemonLogsArgs.verbose, "verbose", 0, "verbosity level") @@ -90,9 +94,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "metrics", - Exec: runDaemonMetrics, - ShortHelp: "print tailscaled's metrics", + Name: "metrics", + ShortUsage: "tailscale debug metrics", + Exec: runDaemonMetrics, + ShortHelp: "Print tailscaled's metrics", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("metrics") fs.BoolVar(&metricsArgs.watch, "watch", false, "print JSON dump of delta values") @@ -100,80 +105,95 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "env", - Exec: runEnv, - ShortHelp: "print cmd/tailscale environment", + Name: "env", + ShortUsage: "tailscale debug env", + Exec: runEnv, + ShortHelp: "Print cmd/tailscale environment", }, { - Name: "stat", - Exec: runStat, - ShortHelp: "stat a file", + Name: "stat", + ShortUsage: "tailscale debug stat ", + Exec: runStat, + ShortHelp: "Stat a file", }, { - Name: "hostinfo", - Exec: runHostinfo, - ShortHelp: "print hostinfo", + Name: "hostinfo", + ShortUsage: "tailscale debug hostinfo", + Exec: runHostinfo, + ShortHelp: "Print hostinfo", }, { - Name: "local-creds", - Exec: runLocalCreds, - ShortHelp: "print how to access Tailscale LocalAPI", + Name: "local-creds", + ShortUsage: "tailscale debug local-creds", + Exec: runLocalCreds, + ShortHelp: "Print how to access Tailscale LocalAPI", }, { - Name: "restun", - Exec: localAPIAction("restun"), - ShortHelp: "force a magicsock restun", + Name: "restun", + ShortUsage: "tailscale debug restun", + Exec: localAPIAction("restun"), + ShortHelp: "Force a magicsock restun", }, { - Name: "rebind", - Exec: localAPIAction("rebind"), - ShortHelp: "force a magicsock rebind", + Name: "rebind", + ShortUsage: "tailscale debug rebind", + Exec: localAPIAction("rebind"), + ShortHelp: "Force a magicsock rebind", }, { - Name: "derp-set-on-demand", - Exec: localAPIAction("derp-set-homeless"), - ShortHelp: "enable DERP on-demand mode (breaks reachability)", + Name: "derp-set-on-demand", + ShortUsage: "tailscale debug derp-set-on-demand", + Exec: localAPIAction("derp-set-homeless"), + ShortHelp: "Enable DERP on-demand mode (breaks reachability)", }, { - Name: "derp-unset-on-demand", - Exec: localAPIAction("derp-unset-homeless"), - ShortHelp: "disable DERP on-demand mode", + Name: "derp-unset-on-demand", + ShortUsage: "tailscale debug derp-unset-on-demand", + Exec: localAPIAction("derp-unset-homeless"), + ShortHelp: "Disable DERP on-demand mode", }, { - Name: "break-tcp-conns", - Exec: localAPIAction("break-tcp-conns"), - ShortHelp: "break any open TCP connections from the daemon", + Name: "break-tcp-conns", + ShortUsage: "tailscale debug break-tcp-conns", + Exec: localAPIAction("break-tcp-conns"), + ShortHelp: "Break any open TCP connections from the daemon", }, { - Name: "break-derp-conns", - Exec: localAPIAction("break-derp-conns"), - ShortHelp: "break any open DERP connections from the daemon", + Name: "break-derp-conns", + ShortUsage: "tailscale debug break-derp-conns", + Exec: localAPIAction("break-derp-conns"), + ShortHelp: "Break any open DERP connections from the daemon", }, { - Name: "pick-new-derp", - Exec: localAPIAction("pick-new-derp"), - ShortHelp: "switch to some other random DERP home region for a short time", + Name: "pick-new-derp", + ShortUsage: "tailscale debug pick-new-derp", + Exec: localAPIAction("pick-new-derp"), + ShortHelp: "Switch to some other random DERP home region for a short time", }, { - Name: "force-netmap-update", - Exec: localAPIAction("force-netmap-update"), - ShortHelp: "force a full no-op netmap update (for load testing)", + Name: "force-netmap-update", + ShortUsage: "tailscale debug force-netmap-update", + Exec: localAPIAction("force-netmap-update"), + ShortHelp: "Force a full no-op netmap update (for load testing)", }, { // TODO(bradfitz,maisem): eventually promote this out of debug - Name: "reload-config", - Exec: reloadConfig, - ShortHelp: "reload config", + Name: "reload-config", + ShortUsage: "tailscale debug reload-config", + Exec: reloadConfig, + ShortHelp: "Reload config", }, { - Name: "control-knobs", - Exec: debugControlKnobs, - ShortHelp: "see current control knobs", + Name: "control-knobs", + ShortUsage: "tailscale debug control-knobs", + Exec: debugControlKnobs, + ShortHelp: "See current control knobs", }, { - Name: "prefs", - Exec: runPrefs, - ShortHelp: "print prefs", + Name: "prefs", + ShortUsage: "tailscale debug prefs", + Exec: runPrefs, + ShortHelp: "Print prefs", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("prefs") fs.BoolVar(&prefsArgs.pretty, "pretty", false, "If true, pretty-print output") @@ -181,9 +201,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "watch-ipn", - Exec: runWatchIPN, - ShortHelp: "subscribe to IPN message bus", + Name: "watch-ipn", + ShortUsage: "tailscale debug watch-ipn", + Exec: runWatchIPN, + ShortHelp: "Subscribe to IPN message bus", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("watch-ipn") fs.BoolVar(&watchIPNArgs.netmap, "netmap", true, "include netmap in messages") @@ -194,9 +215,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "netmap", - Exec: runNetmap, - ShortHelp: "print the current network map", + Name: "netmap", + ShortUsage: "tailscale debug netmap", + Exec: runNetmap, + ShortHelp: "Print the current network map", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("netmap") fs.BoolVar(&netmapArgs.showPrivateKey, "show-private-key", false, "include node private key in printed netmap") @@ -204,14 +226,17 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "via", + Name: "via", + ShortUsage: "tailscale via \n" + + "tailscale via ", Exec: runVia, - ShortHelp: "convert between site-specific IPv4 CIDRs and IPv6 'via' routes", + ShortHelp: "Convert between site-specific IPv4 CIDRs and IPv6 'via' routes", }, { - Name: "ts2021", - Exec: runTS2021, - ShortHelp: "debug ts2021 protocol connectivity", + Name: "ts2021", + ShortUsage: "tailscale debug ts2021", + Exec: runTS2021, + ShortHelp: "Debug ts2021 protocol connectivity", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("ts2021") fs.StringVar(&ts2021Args.host, "host", "controlplane.tailscale.com", "hostname of control plane") @@ -221,9 +246,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "set-expire", - Exec: runSetExpire, - ShortHelp: "manipulate node key expiry for testing", + Name: "set-expire", + ShortUsage: "tailscale debug set-expire --in=1m", + Exec: runSetExpire, + ShortHelp: "Manipulate node key expiry for testing", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("set-expire") fs.DurationVar(&setExpireArgs.in, "in", 0, "if non-zero, set node key to expire this duration from now") @@ -231,9 +257,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "dev-store-set", - Exec: runDevStoreSet, - ShortHelp: "set a key/value pair during development", + Name: "dev-store-set", + ShortUsage: "tailscale debug dev-store-set", + Exec: runDevStoreSet, + ShortHelp: "Set a key/value pair during development", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("store-set") fs.BoolVar(&devStoreSetArgs.danger, "danger", false, "accept danger") @@ -241,14 +268,16 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "derp", - Exec: runDebugDERP, - ShortHelp: "test a DERP configuration", + Name: "derp", + ShortUsage: "tailscale debug derp", + Exec: runDebugDERP, + ShortHelp: "Test a DERP configuration", }, { - Name: "capture", - Exec: runCapture, - ShortHelp: "streams pcaps for debugging", + Name: "capture", + ShortUsage: "tailscale debug capture", + Exec: runCapture, + ShortHelp: "Streams pcaps for debugging", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("capture") fs.StringVar(&captureArgs.outFile, "o", "", "path to stream the pcap (or - for stdout), leave empty to start wireshark") @@ -256,9 +285,10 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "portmap", - Exec: debugPortmap, - ShortHelp: "run portmap debugging", + Name: "portmap", + ShortUsage: "tailscale debug portmap", + Exec: debugPortmap, + ShortHelp: "Run portmap debugging", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("portmap") fs.DurationVar(&debugPortmapArgs.duration, "duration", 5*time.Second, "timeout for port mapping") @@ -270,14 +300,16 @@ var debugCmd = &ffcli.Command{ })(), }, { - Name: "peer-endpoint-changes", - Exec: runPeerEndpointChanges, - ShortHelp: "prints debug information about a peer's endpoint changes", + Name: "peer-endpoint-changes", + ShortUsage: "tailscale debug peer-endpoint-changes ", + Exec: runPeerEndpointChanges, + ShortHelp: "Prints debug information about a peer's endpoint changes", }, { - Name: "dial-types", - Exec: runDebugDialTypes, - ShortHelp: "prints debug information about connecting to a given host or IP", + Name: "dial-types", + ShortUsage: "tailscale debug dial-types ", + Exec: runDebugDialTypes, + ShortHelp: "Prints debug information about connecting to a given host or IP", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("dial-types") fs.StringVar(&debugDialTypesArgs.network, "network", "tcp", `network type to dial ("tcp", "udp", etc.)`) @@ -867,7 +899,7 @@ var setExpireArgs struct { func runSetExpire(ctx context.Context, args []string) error { if len(args) != 0 || setExpireArgs.in == 0 { - return errors.New("usage --in=") + return errors.New("usage: tailscale debug set-expire --in=") } return localClient.DebugSetExpireIn(ctx, setExpireArgs.in) } @@ -966,7 +998,7 @@ func runPeerEndpointChanges(ctx context.Context, args []string) error { } if len(args) != 1 || args[0] == "" { - return errors.New("usage: peer-status ") + return errors.New("usage: tailscale debug peer-endpoint-changes ") } var ip string @@ -1042,7 +1074,7 @@ func runDebugDialTypes(ctx context.Context, args []string) error { } if len(args) != 2 || args[0] == "" || args[1] == "" { - return errors.New("usage: dial-types ") + return errors.New("usage: tailscale debug dial-types ") } port, err := strconv.ParseUint(args[1], 10, 16) diff --git a/cmd/tailscale/cli/down.go b/cmd/tailscale/cli/down.go index e2b5b97f6..1eb85a13e 100644 --- a/cmd/tailscale/cli/down.go +++ b/cmd/tailscale/cli/down.go @@ -14,7 +14,7 @@ import ( var downCmd = &ffcli.Command{ Name: "down", - ShortUsage: "down", + ShortUsage: "tailscale down", ShortHelp: "Disconnect from Tailscale", Exec: runDown, diff --git a/cmd/tailscale/cli/drive.go b/cmd/tailscale/cli/drive.go index fe55b82a6..3b3de26a6 100644 --- a/cmd/tailscale/cli/drive.go +++ b/cmd/tailscale/cli/drive.go @@ -14,10 +14,10 @@ import ( ) const ( - driveShareUsage = "drive share " - driveRenameUsage = "drive rename " - driveUnshareUsage = "drive unshare " - driveListUsage = "drive list" + driveShareUsage = "tailscale drive share " + driveRenameUsage = "tailscale drive rename " + driveUnshareUsage = "tailscale drive unshare " + driveListUsage = "tailscale drive list" ) var driveCmd = &ffcli.Command{ @@ -33,28 +33,32 @@ var driveCmd = &ffcli.Command{ UsageFunc: usageFuncNoDefaultValues, Subcommands: []*ffcli.Command{ { - Name: "share", - Exec: runDriveShare, - ShortHelp: "[ALPHA] create or modify a share", - UsageFunc: usageFunc, + Name: "share", + ShortUsage: driveShareUsage, + Exec: runDriveShare, + ShortHelp: "[ALPHA] create or modify a share", + UsageFunc: usageFunc, }, { - Name: "rename", - ShortHelp: "[ALPHA] rename a share", - Exec: runDriveRename, - UsageFunc: usageFunc, + Name: "rename", + ShortUsage: driveRenameUsage, + ShortHelp: "[ALPHA] rename a share", + Exec: runDriveRename, + UsageFunc: usageFunc, }, { - Name: "unshare", - ShortHelp: "[ALPHA] remove a share", - Exec: runDriveUnshare, - UsageFunc: usageFunc, + Name: "unshare", + ShortUsage: driveUnshareUsage, + ShortHelp: "[ALPHA] remove a share", + Exec: runDriveUnshare, + UsageFunc: usageFunc, }, { - Name: "list", - ShortHelp: "[ALPHA] list current shares", - Exec: runDriveList, - UsageFunc: usageFunc, + Name: "list", + ShortUsage: driveListUsage, + ShortHelp: "[ALPHA] list current shares", + Exec: runDriveList, + UsageFunc: usageFunc, }, }, Exec: func(context.Context, []string) error { @@ -237,8 +241,8 @@ You can get a list of currently published shares by running: $ tailscale drive list` -var shareLongHelpAs = ` +const shareLongHelpAs = ` If you want a share to be accessed as a different user, you can use sudo to accomplish this. For example, to create the aforementioned share as "theuser", you could run: - $ sudo -u theuser tailscale drive share docs /Users/theuser/Documents` + $ sudo -u theuser tailscale drive share docs /Users/theuser/Documents` diff --git a/cmd/tailscale/cli/exitnode.go b/cmd/tailscale/cli/exitnode.go index 40aabc53f..39b540856 100644 --- a/cmd/tailscale/cli/exitnode.go +++ b/cmd/tailscale/cli/exitnode.go @@ -23,7 +23,7 @@ import ( func exitNodeCmd() *ffcli.Command { return &ffcli.Command{ Name: "exit-node", - ShortUsage: "exit-node [flags]", + ShortUsage: "tailscale exit-node [flags]", ShortHelp: "Show machines on your tailnet configured as exit nodes", LongHelp: "Show machines on your tailnet configured as exit nodes", Exec: func(context.Context, []string) error { @@ -32,7 +32,7 @@ func exitNodeCmd() *ffcli.Command { Subcommands: append([]*ffcli.Command{ { Name: "list", - ShortUsage: "exit-node list [flags]", + ShortUsage: "tailscale exit-node list [flags]", ShortHelp: "Show exit nodes", Exec: runExitNodeList, FlagSet: (func() *flag.FlagSet { @@ -48,13 +48,13 @@ func exitNodeCmd() *ffcli.Command { return []*ffcli.Command{ { Name: "connect", - ShortUsage: "exit-node connect", + ShortUsage: "tailscale exit-node connect", ShortHelp: "connect to most recently used exit node", Exec: exitNodeSetUse(true), }, { Name: "disconnect", - ShortUsage: "exit-node disconnect", + ShortUsage: "tailscale exit-node disconnect", ShortHelp: "disconnect from current exit node, if any", Exec: exitNodeSetUse(false), }, diff --git a/cmd/tailscale/cli/file.go b/cmd/tailscale/cli/file.go index 1c8fc60c1..c76ad80bb 100644 --- a/cmd/tailscale/cli/file.go +++ b/cmd/tailscale/cli/file.go @@ -38,7 +38,7 @@ import ( var fileCmd = &ffcli.Command{ Name: "file", - ShortUsage: "file ...", + ShortUsage: "tailscale file ...", ShortHelp: "Send or receive files", Subcommands: []*ffcli.Command{ fileCpCmd, @@ -65,7 +65,7 @@ func (c *countingReader) Read(buf []byte) (int, error) { var fileCpCmd = &ffcli.Command{ Name: "cp", - ShortUsage: "file cp :", + ShortUsage: "tailscale file cp :", ShortHelp: "Copy file(s) to a host", Exec: runCp, FlagSet: (func() *flag.FlagSet { @@ -412,7 +412,7 @@ func (v *onConflict) Set(s string) error { var fileGetCmd = &ffcli.Command{ Name: "get", - ShortUsage: "file get [--wait] [--verbose] [--conflict=(skip|overwrite|rename)] ", + ShortUsage: "tailscale file get [--wait] [--verbose] [--conflict=(skip|overwrite|rename)] ", ShortHelp: "Move files out of the Tailscale file inbox", Exec: runFileGet, FlagSet: (func() *flag.FlagSet { @@ -420,7 +420,7 @@ var fileGetCmd = &ffcli.Command{ fs.BoolVar(&getArgs.wait, "wait", false, "wait for a file to arrive if inbox is empty") fs.BoolVar(&getArgs.loop, "loop", false, "run get in a loop, receiving files as they come in") fs.BoolVar(&getArgs.verbose, "verbose", false, "verbose output") - fs.Var(&getArgs.conflict, "conflict", `behavior when a conflicting (same-named) file already exists in the target directory. + fs.Var(&getArgs.conflict, "conflict", "`behavior`"+` when a conflicting (same-named) file already exists in the target directory. skip: skip conflicting files: leave them in the taildrop inbox and print an error. get any non-conflicting files overwrite: overwrite existing file rename: write to a new number-suffixed filename`) diff --git a/cmd/tailscale/cli/funnel.go b/cmd/tailscale/cli/funnel.go index 39f4af745..a95f9e270 100644 --- a/cmd/tailscale/cli/funnel.go +++ b/cmd/tailscale/cli/funnel.go @@ -36,9 +36,9 @@ func newFunnelCommand(e *serveEnv) *ffcli.Command { Name: "funnel", ShortHelp: "Turn on/off Funnel service", ShortUsage: strings.Join([]string{ - "funnel {on|off}", - "funnel status [--json]", - }, "\n "), + "tailscale funnel {on|off}", + "tailscale funnel status [--json]", + }, "\n"), LongHelp: strings.Join([]string{ "Funnel allows you to publish a 'tailscale serve'", "server publicly, open to the entire internet.", @@ -46,17 +46,16 @@ func newFunnelCommand(e *serveEnv) *ffcli.Command { "Turning off Funnel only turns off serving to the internet.", "It does not affect serving to your tailnet.", }, "\n"), - Exec: e.runFunnel, - UsageFunc: usageFunc, + Exec: e.runFunnel, Subcommands: []*ffcli.Command{ { - Name: "status", - Exec: e.runServeStatus, - ShortHelp: "show current serve/funnel status", + Name: "status", + Exec: e.runServeStatus, + ShortUsage: "tailscale funnel status [--json]", + ShortHelp: "Show current serve/funnel status", FlagSet: e.newFlags("funnel-status", func(fs *flag.FlagSet) { fs.BoolVar(&e.json, "json", false, "output JSON") }), - UsageFunc: usageFunc, }, }, } diff --git a/cmd/tailscale/cli/id-token.go b/cmd/tailscale/cli/id-token.go index 13d186b7c..7efd42d62 100644 --- a/cmd/tailscale/cli/id-token.go +++ b/cmd/tailscale/cli/id-token.go @@ -12,8 +12,8 @@ import ( var idTokenCmd = &ffcli.Command{ Name: "id-token", - ShortUsage: "id-token ", - ShortHelp: "fetch an OIDC id-token for the Tailscale machine", + ShortUsage: "tailscale id-token ", + ShortHelp: "Fetch an OIDC id-token for the Tailscale machine", Exec: runIDToken, } diff --git a/cmd/tailscale/cli/ip.go b/cmd/tailscale/cli/ip.go index ea103c5b7..837932912 100644 --- a/cmd/tailscale/cli/ip.go +++ b/cmd/tailscale/cli/ip.go @@ -16,7 +16,7 @@ import ( var ipCmd = &ffcli.Command{ Name: "ip", - ShortUsage: "ip [-1] [-4] [-6] [peer hostname or ip address]", + ShortUsage: "tailscale ip [-1] [-4] [-6] [peer hostname or ip address]", ShortHelp: "Show Tailscale IP addresses", LongHelp: "Show Tailscale IP addresses for peer. Peer defaults to the current machine.", Exec: runIP, diff --git a/cmd/tailscale/cli/licenses.go b/cmd/tailscale/cli/licenses.go index 72c0b80fd..bede827ed 100644 --- a/cmd/tailscale/cli/licenses.go +++ b/cmd/tailscale/cli/licenses.go @@ -12,7 +12,7 @@ import ( var licensesCmd = &ffcli.Command{ Name: "licenses", - ShortUsage: "licenses", + ShortUsage: "tailscale licenses", ShortHelp: "Get open source license information", LongHelp: "Get open source license information", Exec: runLicenses, diff --git a/cmd/tailscale/cli/login.go b/cmd/tailscale/cli/login.go index f2f3913a1..fb5b78692 100644 --- a/cmd/tailscale/cli/login.go +++ b/cmd/tailscale/cli/login.go @@ -14,11 +14,10 @@ var loginArgs upArgsT var loginCmd = &ffcli.Command{ Name: "login", - ShortUsage: "login [flags]", + ShortUsage: "tailscale login [flags]", ShortHelp: "Log in to a Tailscale account", LongHelp: `"tailscale login" logs this machine in to your Tailscale network. This command is currently in alpha and may change in the future.`, - UsageFunc: usageFunc, FlagSet: func() *flag.FlagSet { return newUpFlagSet(effectiveGOOS(), &loginArgs, "login") }(), diff --git a/cmd/tailscale/cli/logout.go b/cmd/tailscale/cli/logout.go index 0e77844cd..0c2007a66 100644 --- a/cmd/tailscale/cli/logout.go +++ b/cmd/tailscale/cli/logout.go @@ -13,7 +13,7 @@ import ( var logoutCmd = &ffcli.Command{ Name: "logout", - ShortUsage: "logout [flags]", + ShortUsage: "tailscale logout", ShortHelp: "Disconnect from Tailscale and expire current node key", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/nc.go b/cmd/tailscale/cli/nc.go index e0cef8ccd..21e69c220 100644 --- a/cmd/tailscale/cli/nc.go +++ b/cmd/tailscale/cli/nc.go @@ -16,7 +16,7 @@ import ( var ncCmd = &ffcli.Command{ Name: "nc", - ShortUsage: "nc ", + ShortUsage: "tailscale nc ", ShortHelp: "Connect to a port on a host, connected to stdin/stdout", Exec: runNC, } diff --git a/cmd/tailscale/cli/netcheck.go b/cmd/tailscale/cli/netcheck.go index f430414eb..a33ee067f 100644 --- a/cmd/tailscale/cli/netcheck.go +++ b/cmd/tailscale/cli/netcheck.go @@ -28,7 +28,7 @@ import ( var netcheckCmd = &ffcli.Command{ Name: "netcheck", - ShortUsage: "netcheck", + ShortUsage: "tailscale netcheck", ShortHelp: "Print an analysis of local network conditions", Exec: runNetcheck, FlagSet: (func() *flag.FlagSet { diff --git a/cmd/tailscale/cli/network-lock.go b/cmd/tailscale/cli/network-lock.go index c3ef5c149..09f87f1d4 100644 --- a/cmd/tailscale/cli/network-lock.go +++ b/cmd/tailscale/cli/network-lock.go @@ -26,7 +26,7 @@ import ( var netlockCmd = &ffcli.Command{ Name: "lock", - ShortUsage: "lock ", + ShortUsage: "tailscale lock ", ShortHelp: "Manage tailnet lock", LongHelp: "Manage tailnet lock", Subcommands: []*ffcli.Command{ @@ -61,7 +61,7 @@ var nlInitArgs struct { var nlInitCmd = &ffcli.Command{ Name: "init", - ShortUsage: "init [--gen-disablement-for-support] --gen-disablements N ...", + ShortUsage: "tailscale lock init [--gen-disablement-for-support] --gen-disablements N ...", ShortHelp: "Initialize tailnet lock", LongHelp: strings.TrimSpace(` @@ -183,7 +183,7 @@ var nlStatusArgs struct { var nlStatusCmd = &ffcli.Command{ Name: "status", - ShortUsage: "status", + ShortUsage: "tailscale lock status", ShortHelp: "Outputs the state of tailnet lock", LongHelp: "Outputs the state of tailnet lock", Exec: runNetworkLockStatus, @@ -280,7 +280,7 @@ func runNetworkLockStatus(ctx context.Context, args []string) error { var nlAddCmd = &ffcli.Command{ Name: "add", - ShortUsage: "add ...", + ShortUsage: "tailscale lock add ...", ShortHelp: "Adds one or more trusted signing keys to tailnet lock", LongHelp: "Adds one or more trusted signing keys to tailnet lock", Exec: func(ctx context.Context, args []string) error { @@ -294,7 +294,7 @@ var nlRemoveArgs struct { var nlRemoveCmd = &ffcli.Command{ Name: "remove", - ShortUsage: "remove [--re-sign=false] ...", + ShortUsage: "tailscale lock remove [--re-sign=false] ...", ShortHelp: "Removes one or more trusted signing keys from tailnet lock", LongHelp: "Removes one or more trusted signing keys from tailnet lock", Exec: runNetworkLockRemove, @@ -435,7 +435,7 @@ func runNetworkLockModify(ctx context.Context, addArgs, removeArgs []string) err var nlSignCmd = &ffcli.Command{ Name: "sign", - ShortUsage: "sign [] or sign ", + ShortUsage: "tailscale lock sign [] or sign ", ShortHelp: "Signs a node or pre-approved auth key", LongHelp: `Either: - signs a node key and transmits the signature to the coordination server, or @@ -479,7 +479,7 @@ func runNetworkLockSign(ctx context.Context, args []string) error { var nlDisableCmd = &ffcli.Command{ Name: "disable", - ShortUsage: "disable ", + ShortUsage: "tailscale lock disable ", ShortHelp: "Consumes a disablement secret to shut down tailnet lock for the tailnet", LongHelp: strings.TrimSpace(` @@ -508,7 +508,7 @@ func runNetworkLockDisable(ctx context.Context, args []string) error { var nlLocalDisableCmd = &ffcli.Command{ Name: "local-disable", - ShortUsage: "local-disable", + ShortUsage: "tailscale lock local-disable", ShortHelp: "Disables tailnet lock for this node only", LongHelp: strings.TrimSpace(` @@ -530,7 +530,7 @@ func runNetworkLockLocalDisable(ctx context.Context, args []string) error { var nlDisablementKDFCmd = &ffcli.Command{ Name: "disablement-kdf", - ShortUsage: "disablement-kdf ", + ShortUsage: "tailscale lock disablement-kdf ", ShortHelp: "Computes a disablement value from a disablement secret (advanced users only)", LongHelp: "Computes a disablement value from a disablement secret (advanced users only)", Exec: runNetworkLockDisablementKDF, @@ -555,7 +555,7 @@ var nlLogArgs struct { var nlLogCmd = &ffcli.Command{ Name: "log", - ShortUsage: "log [--limit N]", + ShortUsage: "tailscale lock log [--limit N]", ShortHelp: "List changes applied to tailnet lock", LongHelp: "List changes applied to tailnet lock", Exec: runNetworkLockLog, @@ -719,7 +719,7 @@ var nlRevokeKeysArgs struct { var nlRevokeKeysCmd = &ffcli.Command{ Name: "revoke-keys", - ShortUsage: "revoke-keys ...\n revoke-keys [--cosign] [--finish] ", + ShortUsage: "tailscale lock revoke-keys ...\n revoke-keys [--cosign] [--finish] ", ShortHelp: "Revoke compromised tailnet-lock keys", LongHelp: `Retroactively revoke the specified tailnet lock keys (tlpub:abc). diff --git a/cmd/tailscale/cli/ping.go b/cmd/tailscale/cli/ping.go index 2c5dfed22..fd59183f2 100644 --- a/cmd/tailscale/cli/ping.go +++ b/cmd/tailscale/cli/ping.go @@ -23,7 +23,7 @@ import ( var pingCmd = &ffcli.Command{ Name: "ping", - ShortUsage: "ping ", + ShortUsage: "tailscale ping ", ShortHelp: "Ping a host at the Tailscale layer, see how it routed", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/serve_legacy.go b/cmd/tailscale/cli/serve_legacy.go index 77dc3888f..285bb932e 100644 --- a/cmd/tailscale/cli/serve_legacy.go +++ b/cmd/tailscale/cli/serve_legacy.go @@ -44,13 +44,13 @@ func newServeLegacyCommand(e *serveEnv) *ffcli.Command { Name: "serve", ShortHelp: "Serve content and local servers", ShortUsage: strings.Join([]string{ - "serve http: [off]", - "serve https: [off]", - "serve tcp: tcp://localhost: [off]", - "serve tls-terminated-tcp: tcp://localhost: [off]", - "serve status [--json]", - "serve reset", - }, "\n "), + "tailscale serve http: [off]", + "tailscale serve https: [off]", + "tailscale serve tcp: tcp://localhost: [off]", + "tailscale serve tls-terminated-tcp: tcp://localhost: [off]", + "tailscale serve status [--json]", + "tailscale serve reset", + }, "\n"), LongHelp: strings.TrimSpace(` *** BETA; all of this is subject to change *** @@ -91,24 +91,21 @@ EXAMPLES local plaintext server on port 80: $ tailscale serve tls-terminated-tcp:443 tcp://localhost:80 `), - Exec: e.runServe, - UsageFunc: usageFunc, + Exec: e.runServe, Subcommands: []*ffcli.Command{ { Name: "status", Exec: e.runServeStatus, - ShortHelp: "show current serve/funnel status", + ShortHelp: "Show current serve/funnel status", FlagSet: e.newFlags("serve-status", func(fs *flag.FlagSet) { fs.BoolVar(&e.json, "json", false, "output JSON") }), - UsageFunc: usageFunc, }, { Name: "reset", Exec: e.runServeReset, - ShortHelp: "reset current serve/funnel config", + ShortHelp: "Reset current serve/funnel config", FlagSet: e.newFlags("serve-reset", nil), - UsageFunc: usageFunc, }, }, } diff --git a/cmd/tailscale/cli/serve_v2.go b/cmd/tailscale/cli/serve_v2.go index aabe48217..009a61198 100644 --- a/cmd/tailscale/cli/serve_v2.go +++ b/cmd/tailscale/cli/serve_v2.go @@ -110,10 +110,10 @@ func newServeV2Command(e *serveEnv, subcmd serveMode) *ffcli.Command { Name: info.Name, ShortHelp: info.ShortHelp, ShortUsage: strings.Join([]string{ - fmt.Sprintf("%s ", info.Name), - fmt.Sprintf("%s status [--json]", info.Name), - fmt.Sprintf("%s reset", info.Name), - }, "\n "), + fmt.Sprintf("tailscale %s ", info.Name), + fmt.Sprintf("tailscale %s status [--json]", info.Name), + fmt.Sprintf("tailscale %s reset", info.Name), + }, "\n"), LongHelp: info.LongHelp + fmt.Sprintf(strings.TrimSpace(serveHelpCommon), info.Name), Exec: e.runServeCombined(subcmd), @@ -131,20 +131,20 @@ func newServeV2Command(e *serveEnv, subcmd serveMode) *ffcli.Command { UsageFunc: usageFuncNoDefaultValues, Subcommands: []*ffcli.Command{ { - Name: "status", - Exec: e.runServeStatus, - ShortHelp: "view current proxy configuration", + Name: "status", + ShortUsage: "tailscale " + info.Name + " status [--json]", + Exec: e.runServeStatus, + ShortHelp: "View current " + info.Name + " configuration", FlagSet: e.newFlags("serve-status", func(fs *flag.FlagSet) { fs.BoolVar(&e.json, "json", false, "output JSON") }), - UsageFunc: usageFunc, }, { - Name: "reset", - ShortHelp: "reset current serve/funnel config", - Exec: e.runServeReset, - FlagSet: e.newFlags("serve-reset", nil), - UsageFunc: usageFunc, + Name: "reset", + ShortUsage: "tailscale " + info.Name + " reset", + ShortHelp: "Reset current " + info.Name + " config", + Exec: e.runServeReset, + FlagSet: e.newFlags("serve-reset", nil), }, }, } diff --git a/cmd/tailscale/cli/set.go b/cmd/tailscale/cli/set.go index 4049eb12e..fedd07603 100644 --- a/cmd/tailscale/cli/set.go +++ b/cmd/tailscale/cli/set.go @@ -25,7 +25,7 @@ import ( var setCmd = &ffcli.Command{ Name: "set", - ShortUsage: "set [flags]", + ShortUsage: "tailscale set [flags]", ShortHelp: "Change specified preferences", LongHelp: `"tailscale set" allows changing specific preferences. diff --git a/cmd/tailscale/cli/ssh.go b/cmd/tailscale/cli/ssh.go index 46dfb689f..2ba8b3d9e 100644 --- a/cmd/tailscale/cli/ssh.go +++ b/cmd/tailscale/cli/ssh.go @@ -26,7 +26,7 @@ import ( var sshCmd = &ffcli.Command{ Name: "ssh", - ShortUsage: "ssh [user@] [args...]", + ShortUsage: "tailscale ssh [user@] [args...]", ShortHelp: "SSH to a Tailscale machine", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/status.go b/cmd/tailscale/cli/status.go index 6655c1469..863bed15b 100644 --- a/cmd/tailscale/cli/status.go +++ b/cmd/tailscale/cli/status.go @@ -29,7 +29,7 @@ import ( var statusCmd = &ffcli.Command{ Name: "status", - ShortUsage: "status [--active] [--web] [--json]", + ShortUsage: "tailscale status [--active] [--web] [--json]", ShortHelp: "Show state of tailscaled and its connections", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/switch.go b/cmd/tailscale/cli/switch.go index f0bda7350..e5adc2ce5 100644 --- a/cmd/tailscale/cli/switch.go +++ b/cmd/tailscale/cli/switch.go @@ -17,26 +17,22 @@ import ( ) var switchCmd = &ffcli.Command{ - Name: "switch", - ShortHelp: "Switches to a different Tailscale account", + Name: "switch", + ShortUsage: "tailscale switch ", + ShortHelp: "Switches to a different Tailscale account", + LongHelp: `"tailscale switch" switches between logged in accounts. You can +use the ID that's returned from 'tailnet switch -list' +to pick which profile you want to switch to. Alternatively, you +can use the Tailnet or the account names to switch as well. + +This command is currently in alpha and may change in the future.`, + FlagSet: func() *flag.FlagSet { fs := flag.NewFlagSet("switch", flag.ExitOnError) fs.BoolVar(&switchArgs.list, "list", false, "list available accounts") return fs }(), Exec: switchProfile, - UsageFunc: func(*ffcli.Command) string { - return `USAGE - switch - switch --list - -"tailscale switch" switches between logged in accounts. You can -use the ID that's returned from 'tailnet switch -list' -to pick which profile you want to switch to. Alternatively, you -can use the Tailnet or the account names to switch as well. - -This command is currently in alpha and may change in the future.` - }, } var switchArgs struct { diff --git a/cmd/tailscale/cli/up.go b/cmd/tailscale/cli/up.go index 43f36f819..a9dc8a3b5 100644 --- a/cmd/tailscale/cli/up.go +++ b/cmd/tailscale/cli/up.go @@ -44,7 +44,7 @@ import ( var upCmd = &ffcli.Command{ Name: "up", - ShortUsage: "up [flags]", + ShortUsage: "tailscale up [flags]", ShortHelp: "Connect to Tailscale, logging in if needed", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/update.go b/cmd/tailscale/cli/update.go index ecc231d39..8e6a9fcb1 100644 --- a/cmd/tailscale/cli/update.go +++ b/cmd/tailscale/cli/update.go @@ -19,7 +19,7 @@ import ( var updateCmd = &ffcli.Command{ Name: "update", - ShortUsage: "update", + ShortUsage: "tailscale update", ShortHelp: "Update Tailscale to the latest/different version", Exec: runUpdate, FlagSet: (func() *flag.FlagSet { diff --git a/cmd/tailscale/cli/version.go b/cmd/tailscale/cli/version.go index 18c7526fa..b25502d5a 100644 --- a/cmd/tailscale/cli/version.go +++ b/cmd/tailscale/cli/version.go @@ -17,7 +17,7 @@ import ( var versionCmd = &ffcli.Command{ Name: "version", - ShortUsage: "version [flags]", + ShortUsage: "tailscale version [flags]", ShortHelp: "Print Tailscale version", FlagSet: (func() *flag.FlagSet { fs := newFlagSet("version") diff --git a/cmd/tailscale/cli/web.go b/cmd/tailscale/cli/web.go index 1e03c933f..e209d388e 100644 --- a/cmd/tailscale/cli/web.go +++ b/cmd/tailscale/cli/web.go @@ -26,7 +26,7 @@ import ( var webCmd = &ffcli.Command{ Name: "web", - ShortUsage: "web [flags]", + ShortUsage: "tailscale web [flags]", ShortHelp: "Run a web server for controlling Tailscale", LongHelp: strings.TrimSpace(` diff --git a/cmd/tailscale/cli/whois.go b/cmd/tailscale/cli/whois.go index d0af73817..2d9da6d07 100644 --- a/cmd/tailscale/cli/whois.go +++ b/cmd/tailscale/cli/whois.go @@ -17,13 +17,12 @@ import ( var whoisCmd = &ffcli.Command{ Name: "whois", - ShortUsage: "whois [--json] ip[:port]", + ShortUsage: "tailscale whois [--json] ip[:port]", ShortHelp: "Show the machine and user associated with a Tailscale IP (v4 or v6)", LongHelp: strings.TrimSpace(` 'tailscale whois' shows the machine and user associated with a Tailscale IP (v4 or v6). `), - UsageFunc: usageFunc, - Exec: runWhoIs, + Exec: runWhoIs, FlagSet: func() *flag.FlagSet { fs := newFlagSet("whois") fs.BoolVar(&whoIsArgs.json, "json", false, "output in JSON format")