Skip to content

Commit bf61457

Browse files
authored
Customize help text and add ServerWithDoc (#7)
1 parent 88e0a38 commit bf61457

File tree

3 files changed

+66
-7
lines changed

3 files changed

+66
-7
lines changed

flags.go

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package pluginrpc
1717
import (
1818
"fmt"
1919
"io"
20+
"sort"
2021
"strconv"
2122
"strings"
2223

@@ -32,6 +33,7 @@ const (
3233
FormatFlagName = "format"
3334

3435
protocolVersion = 1
36+
flagWrapping = 140
3537
)
3638

3739
type flags struct {
@@ -40,10 +42,13 @@ type flags struct {
4042
format Format
4143
}
4244

43-
func parseFlags(output io.Writer, args []string) (*flags, []string, error) {
45+
func parseFlags(output io.Writer, args []string, spec Spec, doc string) (*flags, []string, error) {
4446
flags := &flags{}
4547
var formatString string
4648
flagSet := pflag.NewFlagSet("plugin", pflag.ContinueOnError)
49+
flagSet.Usage = func() {
50+
_, _ = fmt.Fprint(output, getFlagUsage(flagSet, spec, doc))
51+
}
4752
flagSet.SetOutput(output)
4853
flagSet.BoolVar(&flags.printProtocol, ProtocolFlagName, false, "Print the protocol to stdout and exit.")
4954
flagSet.BoolVar(&flags.printSpec, SpecFlagName, false, "Print the spec to stdout in the specified format and exit.")
@@ -68,6 +73,35 @@ func parseFlags(output io.Writer, args []string) (*flags, []string, error) {
6873
return flags, flagSet.Args(), nil
6974
}
7075

76+
func getFlagUsage(flagSet *pflag.FlagSet, spec Spec, doc string) string {
77+
var sb strings.Builder
78+
if doc != "" {
79+
_, _ = sb.WriteString(doc)
80+
_, _ = sb.WriteString("\n\n")
81+
}
82+
_, _ = sb.WriteString("Commands:\n\n")
83+
var argBasedProcedureStrings []string
84+
var pathBasedProcedureStrings []string
85+
for _, procedure := range spec.Procedures() {
86+
if args := procedure.Args(); len(args) > 0 {
87+
argBasedProcedureStrings = append(argBasedProcedureStrings, strings.Join(args, " "))
88+
} else {
89+
pathBasedProcedureStrings = append(pathBasedProcedureStrings, procedure.Path())
90+
}
91+
}
92+
sort.Strings(argBasedProcedureStrings)
93+
sort.Strings(pathBasedProcedureStrings)
94+
for _, procedureString := range append(argBasedProcedureStrings, pathBasedProcedureStrings...) {
95+
_, _ = sb.WriteString(" ")
96+
_, _ = sb.WriteString(procedureString)
97+
_, _ = sb.WriteString("\n")
98+
}
99+
_, _ = sb.WriteString("\nFlags:\n\n")
100+
_, _ = sb.WriteString(flagSet.FlagUsagesWrapped(flagWrapping))
101+
_, _ = sb.WriteString(" -h, --help Show this help.\n")
102+
return sb.String()
103+
}
104+
71105
func marshalProtocol(value int) []byte {
72106
return []byte(strconv.Itoa(value) + "\n")
73107
}

internal/example/cmd/echo-plugin/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,11 @@ func newServer() (pluginrpc.Server, error) {
4949
serverRegistrar := pluginrpc.NewServerRegistrar()
5050
echoServiceServer := examplev1pluginrpc.NewEchoServiceServer(pluginrpc.NewHandler(spec), echoServiceHandler{})
5151
examplev1pluginrpc.RegisterEchoServiceServer(serverRegistrar, echoServiceServer)
52-
return pluginrpc.NewServer(spec, serverRegistrar)
52+
return pluginrpc.NewServer(
53+
spec,
54+
serverRegistrar,
55+
pluginrpc.ServerWithDoc("An example plugin that implements the EchoService."),
56+
)
5357
}
5458

5559
type echoServiceHandler struct{}

server.go

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,35 @@ type Server interface {
4040
//
4141
// Once passed to this constructor, the ServerRegistrar can no longer have new
4242
// paths registered to it.
43-
func NewServer(spec Spec, serverRegistrar ServerRegistrar, _ ...ServerOption) (Server, error) {
44-
return newServer(spec, serverRegistrar)
43+
func NewServer(spec Spec, serverRegistrar ServerRegistrar, options ...ServerOption) (Server, error) {
44+
return newServer(spec, serverRegistrar, options...)
4545
}
4646

4747
// ServerOption is an option for a new Server.
4848
type ServerOption func(*serverOptions)
4949

50+
// ServerWithDoc will attach the given documentation to the server.
51+
//
52+
// This will add ths given docs as a prefix when the flag -h/--help is used.
53+
func ServerWithDoc(doc string) ServerOption {
54+
return func(serverOptions *serverOptions) {
55+
serverOptions.doc = doc
56+
}
57+
}
58+
5059
// *** PRIVATE ***
5160

5261
type server struct {
5362
spec Spec
5463
pathToHandleFunc map[string]func(context.Context, HandleEnv, ...HandleOption) error
64+
doc string
5565
}
5666

57-
func newServer(spec Spec, serverRegistrar ServerRegistrar) (*server, error) {
67+
func newServer(spec Spec, serverRegistrar ServerRegistrar, options ...ServerOption) (*server, error) {
68+
serverOptions := newServerOptions()
69+
for _, option := range options {
70+
option(serverOptions)
71+
}
5872
pathToHandleFunc, err := serverRegistrar.pathToHandleFunc()
5973
if err != nil {
6074
return nil, err
@@ -72,11 +86,12 @@ func newServer(spec Spec, serverRegistrar ServerRegistrar) (*server, error) {
7286
return &server{
7387
spec: spec,
7488
pathToHandleFunc: pathToHandleFunc,
89+
doc: serverOptions.doc,
7590
}, nil
7691
}
7792

7893
func (s *server) Serve(ctx context.Context, env Env) error {
79-
flags, args, err := parseFlags(env.Stderr, env.Args)
94+
flags, args, err := parseFlags(env.Stderr, env.Args, s.spec, s.doc)
8095
if err != nil {
8196
if errors.Is(err, pflag.ErrHelp) {
8297
return nil
@@ -111,4 +126,10 @@ func (s *server) Serve(ctx context.Context, env Env) error {
111126

112127
func (*server) isServer() {}
113128

114-
type serverOptions struct{}
129+
type serverOptions struct {
130+
doc string
131+
}
132+
133+
func newServerOptions() *serverOptions {
134+
return &serverOptions{}
135+
}

0 commit comments

Comments
 (0)