mirror of
https://github.com/tailscale/tailscale.git
synced 2025-04-22 08:51:41 +00:00
cmd/tailscale: add --json-docs flag
This prints all command and flag docs as JSON. To be used for generating the contents of https://tailscale.com/kb/1080/cli. Updates https://github.com/tailscale/tailscale-www/issues/4722
This commit is contained in:
parent
a93dc6cdb1
commit
776ab357b1
@ -7,6 +7,7 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -159,8 +160,10 @@ func newRootCmd() *ffcli.Command {
|
|||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
rootfs.Lookup("socket").DefValue = localClient.Socket
|
rootfs.Lookup("socket").DefValue = localClient.Socket
|
||||||
|
jsonDocs := rootfs.Bool("json-docs", false, hidden+"print JSON-encoded docs for all subcommands and flags")
|
||||||
|
|
||||||
rootCmd := &ffcli.Command{
|
var rootCmd *ffcli.Command
|
||||||
|
rootCmd = &ffcli.Command{
|
||||||
Name: "tailscale",
|
Name: "tailscale",
|
||||||
ShortUsage: "tailscale [flags] <subcommand> [command flags]",
|
ShortUsage: "tailscale [flags] <subcommand> [command flags]",
|
||||||
ShortHelp: "The easiest, most secure way to use WireGuard.",
|
ShortHelp: "The easiest, most secure way to use WireGuard.",
|
||||||
@ -202,6 +205,9 @@ change in the future.
|
|||||||
},
|
},
|
||||||
FlagSet: rootfs,
|
FlagSet: rootfs,
|
||||||
Exec: func(ctx context.Context, args []string) error {
|
Exec: func(ctx context.Context, args []string) error {
|
||||||
|
if *jsonDocs {
|
||||||
|
return printJSONDocs(rootCmd)
|
||||||
|
}
|
||||||
if len(args) > 0 {
|
if len(args) > 0 {
|
||||||
return fmt.Errorf("tailscale: unknown subcommand: %s", args[0])
|
return fmt.Errorf("tailscale: unknown subcommand: %s", args[0])
|
||||||
}
|
}
|
||||||
@ -401,3 +407,54 @@ func colorableOutput() (w io.Writer, ok bool) {
|
|||||||
}
|
}
|
||||||
return colorable.NewColorableStdout(), true
|
return colorable.NewColorableStdout(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type commandDoc struct {
|
||||||
|
Name string
|
||||||
|
Desc string
|
||||||
|
Subcommands []commandDoc `json:",omitempty"`
|
||||||
|
Flags []flagDoc `json:",omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type flagDoc struct {
|
||||||
|
Name string
|
||||||
|
Desc string
|
||||||
|
}
|
||||||
|
|
||||||
|
func printJSONDocs(root *ffcli.Command) error {
|
||||||
|
docs := jsonDocsWalk(root)
|
||||||
|
return json.NewEncoder(os.Stdout).Encode(docs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func jsonDocsWalk(cmd *ffcli.Command) *commandDoc {
|
||||||
|
res := &commandDoc{
|
||||||
|
Name: cmd.Name,
|
||||||
|
}
|
||||||
|
if cmd.LongHelp != "" {
|
||||||
|
res.Desc = cmd.LongHelp
|
||||||
|
} else if cmd.ShortHelp != "" {
|
||||||
|
res.Desc = cmd.ShortHelp
|
||||||
|
} else {
|
||||||
|
res.Desc = cmd.ShortUsage
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(res.Desc, hidden) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if cmd.FlagSet != nil {
|
||||||
|
cmd.FlagSet.VisitAll(func(f *flag.Flag) {
|
||||||
|
if strings.HasPrefix(f.Usage, hidden) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res.Flags = append(res.Flags, flagDoc{
|
||||||
|
Name: f.Name,
|
||||||
|
Desc: f.Usage,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for _, sub := range cmd.Subcommands {
|
||||||
|
subj := jsonDocsWalk(sub)
|
||||||
|
if subj != nil {
|
||||||
|
res.Subcommands = append(res.Subcommands, *subj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user