cli/serve: shorten help text on error

Our BETA serve help text is long and often hides the actual error
in the user's usage. Instead of printing the full text, prompt
users to use `serve --help` if they want the help info.

Fixes #14274

Signed-off-by: Sonia Appasamy <sonia@tailscale.com>
This commit is contained in:
Sonia Appasamy 2023-08-29 10:55:38 -04:00 committed by Sonia Appasamy
parent 3280c81c95
commit f824274093
2 changed files with 20 additions and 16 deletions

View File

@ -120,6 +120,10 @@ func newServeCommand(e *serveEnv) *ffcli.Command {
} }
} }
// errHelp is standard error text that prompts users to
// run `serve --help` for information on how to use serve.
var errHelp = errors.New("try `tailscale serve --help` for usage info")
func (e *serveEnv) newFlags(name string, setup func(fs *flag.FlagSet)) *flag.FlagSet { func (e *serveEnv) newFlags(name string, setup func(fs *flag.FlagSet)) *flag.FlagSet {
onError, out := flag.ExitOnError, Stderr onError, out := flag.ExitOnError, Stderr
if e.testFlagOut != nil { if e.testFlagOut != nil {
@ -244,7 +248,7 @@ func (e *serveEnv) runServe(ctx context.Context, args []string) error {
if len(args) < 2 || ((srcType == "https" || srcType == "http") && !turnOff && len(args) < 3) { if len(args) < 2 || ((srcType == "https" || srcType == "http") && !turnOff && len(args) < 3) {
fmt.Fprintf(os.Stderr, "error: invalid number of arguments\n\n") fmt.Fprintf(os.Stderr, "error: invalid number of arguments\n\n")
return flag.ErrHelp return errHelp
} }
if srcType == "https" && !turnOff { if srcType == "https" && !turnOff {
@ -286,7 +290,7 @@ func (e *serveEnv) runServe(ctx context.Context, args []string) error {
default: default:
fmt.Fprintf(os.Stderr, "error: invalid serve type %q\n", srcType) fmt.Fprintf(os.Stderr, "error: invalid serve type %q\n", srcType)
fmt.Fprint(os.Stderr, "must be one of: http:<port>, https:<port>, tcp:<port> or tls-terminated-tcp:<port>\n\n", srcType) fmt.Fprint(os.Stderr, "must be one of: http:<port>, https:<port>, tcp:<port> or tls-terminated-tcp:<port>\n\n", srcType)
return flag.ErrHelp return errHelp
} }
} }
@ -322,13 +326,13 @@ func (e *serveEnv) handleWebServe(ctx context.Context, srvPort uint16, useTLS bo
} }
if !filepath.IsAbs(source) { if !filepath.IsAbs(source) {
fmt.Fprintf(os.Stderr, "error: path must be absolute\n\n") fmt.Fprintf(os.Stderr, "error: path must be absolute\n\n")
return flag.ErrHelp return errHelp
} }
source = filepath.Clean(source) source = filepath.Clean(source)
fi, err := os.Stat(source) fi, err := os.Stat(source)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error: invalid path: %v\n\n", err) fmt.Fprintf(os.Stderr, "error: invalid path: %v\n\n", err)
return flag.ErrHelp return errHelp
} }
if fi.IsDir() && !strings.HasSuffix(mount, "/") { if fi.IsDir() && !strings.HasSuffix(mount, "/") {
// dir mount points must end in / // dir mount points must end in /
@ -354,7 +358,7 @@ func (e *serveEnv) handleWebServe(ctx context.Context, srvPort uint16, useTLS bo
if sc.IsTCPForwardingOnPort(srvPort) { if sc.IsTCPForwardingOnPort(srvPort) {
fmt.Fprintf(os.Stderr, "error: cannot serve web; already serving TCP\n") fmt.Fprintf(os.Stderr, "error: cannot serve web; already serving TCP\n")
return flag.ErrHelp return errHelp
} }
mak.Set(&sc.TCP, srvPort, &ipn.TCPPortHandler{HTTPS: useTLS, HTTP: !useTLS}) mak.Set(&sc.TCP, srvPort, &ipn.TCPPortHandler{HTTPS: useTLS, HTTP: !useTLS})
@ -542,18 +546,18 @@ func (e *serveEnv) handleTCPServe(ctx context.Context, srcType string, srcPort u
terminateTLS = true terminateTLS = true
default: default:
fmt.Fprintf(os.Stderr, "error: invalid TCP source %q\n\n", dest) fmt.Fprintf(os.Stderr, "error: invalid TCP source %q\n\n", dest)
return flag.ErrHelp return errHelp
} }
dstURL, err := url.Parse(dest) dstURL, err := url.Parse(dest)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error: invalid TCP source %q: %v\n\n", dest, err) fmt.Fprintf(os.Stderr, "error: invalid TCP source %q: %v\n\n", dest, err)
return flag.ErrHelp return errHelp
} }
host, dstPortStr, err := net.SplitHostPort(dstURL.Host) host, dstPortStr, err := net.SplitHostPort(dstURL.Host)
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "error: invalid TCP source %q: %v\n\n", dest, err) fmt.Fprintf(os.Stderr, "error: invalid TCP source %q: %v\n\n", dest, err)
return flag.ErrHelp return errHelp
} }
switch host { switch host {
@ -562,12 +566,12 @@ func (e *serveEnv) handleTCPServe(ctx context.Context, srcType string, srcPort u
default: default:
fmt.Fprintf(os.Stderr, "error: invalid TCP source %q\n", dest) fmt.Fprintf(os.Stderr, "error: invalid TCP source %q\n", dest)
fmt.Fprint(os.Stderr, "must be one of: localhost or 127.0.0.1\n\n", dest) fmt.Fprint(os.Stderr, "must be one of: localhost or 127.0.0.1\n\n", dest)
return flag.ErrHelp return errHelp
} }
if p, err := strconv.ParseUint(dstPortStr, 10, 16); p == 0 || err != nil { if p, err := strconv.ParseUint(dstPortStr, 10, 16); p == 0 || err != nil {
fmt.Fprintf(os.Stderr, "error: invalid port %q\n\n", dstPortStr) fmt.Fprintf(os.Stderr, "error: invalid port %q\n\n", dstPortStr)
return flag.ErrHelp return errHelp
} }
cursc, err := e.lc.GetServeConfig(ctx) cursc, err := e.lc.GetServeConfig(ctx)

View File

@ -339,19 +339,19 @@ type step struct {
add(step{reset: true}) add(step{reset: true})
add(step{ // must include scheme for tcp add(step{ // must include scheme for tcp
command: cmd("tls-terminated-tcp:443 localhost:5432"), command: cmd("tls-terminated-tcp:443 localhost:5432"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{ // !somehost, must be localhost or 127.0.0.1 add(step{ // !somehost, must be localhost or 127.0.0.1
command: cmd("tls-terminated-tcp:443 tcp://somehost:5432"), command: cmd("tls-terminated-tcp:443 tcp://somehost:5432"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{ // bad target port, too low add(step{ // bad target port, too low
command: cmd("tls-terminated-tcp:443 tcp://somehost:0"), command: cmd("tls-terminated-tcp:443 tcp://somehost:0"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{ // bad target port, too high add(step{ // bad target port, too high
command: cmd("tls-terminated-tcp:443 tcp://somehost:65536"), command: cmd("tls-terminated-tcp:443 tcp://somehost:65536"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{ add(step{
command: cmd("tls-terminated-tcp:443 tcp://localhost:5432"), command: cmd("tls-terminated-tcp:443 tcp://localhost:5432"),
@ -472,7 +472,7 @@ type step struct {
}) })
add(step{ // bad path add(step{ // bad path
command: cmd("https:443 / bad/path"), command: cmd("https:443 / bad/path"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{reset: true}) add(step{reset: true})
add(step{ add(step{
@ -666,7 +666,7 @@ type step struct {
}) })
add(step{ // try to start a web handler on the same port add(step{ // try to start a web handler on the same port
command: cmd("https:443 / localhost:3000"), command: cmd("https:443 / localhost:3000"),
wantErr: exactErr(flag.ErrHelp, "flag.ErrHelp"), wantErr: exactErr(errHelp, "errHelp"),
}) })
add(step{reset: true}) add(step{reset: true})
add(step{ // start a web handler on port 443 add(step{ // start a web handler on port 443