Documentation
¶
Overview ¶
Package protocli provides framework features for generated gRPC CLI commands.
This package is automatically imported by generated CLI code and provides lifecycle hooks, output formatting, configuration options, and utilities for CLI applications.
Options ¶
The Option type provides a functional options pattern for configuring CLI behavior:
cmd := proto.BuildUserServiceCLI(ctx, impl,
protocli.BeforeCommand(func(ctx context.Context, cmd *cli.Command) error {
log.Printf("Running command: %s", cmd.Name)
return nil
}),
protocli.WithAfterCommand(func(ctx context.Context, cmd *cli.Command) error {
log.Printf("Completed command: %s", cmd.Name)
return nil
}),
protocli.WithOutputFormats(
protocli.JSON(),
protocli.YAML(),
),
)
Lifecycle Hooks ¶
- BeforeCommand: Runs before each command execution
- AfterCommand: Runs after each command execution
Hooks receive the context and command, allowing for logging, validation, metrics collection, or other cross-cutting concerns.
Output Formats ¶
The CLI automatically supports --format and --output flags for all commands:
- --format: Specifies output format (go, json, yaml, or custom)
- --output: Specifies output file (- or empty for stdout)
Built-in formats (use factory functions to create them):
- protocli.Go(): Default Go %+v formatting (automatically used if no formats registered)
- protocli.JSON(): JSON output with optional --pretty flag
- protocli.YAML(): YAML-style output
If no formats are explicitly registered via WithOutputFormats, the Go format is used as the default. Custom formats can be registered and will define additional flags (e.g., --pretty for JSON) that are automatically added to all commands.
Example custom format without additional flags:
type CSVFormat struct{}
func (f *CSVFormat) Name() string { return "csv" }
func (f *CSVFormat) Format(ctx context.Context, cmd *cli.Command, w io.Writer, msg proto.Message) error {
// Format as CSV...
return nil
}
Example custom format with additional flags (implements FlagConfiguredOutputFormat):
type CSVFormat struct{}
func (f *CSVFormat) Name() string { return "csv" }
func (f *CSVFormat) Flags() []cli.Flag {
return []cli.Flag{
&cli.StringFlag{Name: "delimiter", Value: ",", Usage: "CSV delimiter"},
}
}
func (f *CSVFormat) Format(ctx context.Context, cmd *cli.Command, w io.Writer, msg proto.Message) error {
delimiter := cmd.String("delimiter")
// Format as CSV...
return nil
}
The Flags() method is optional - implement it only if your format needs custom flags. The generated CLI code checks for the FlagConfiguredOutputFormat interface at runtime.
Template-Based Formats ¶
For simpler cases, use TemplateFormat to create formats using Go text templates:
templates := map[string]string{
"example.UserResponse": `User: {{.user.name}} ({{.user.email}})`,
"example.CreateUserRequest": `Creating: {{.name}}`,
}
format, err := protocli.TemplateFormat("user-compact", templates)
Templates support:
- Field access: {{.fieldName}}
- Conditionals: {{if .field}}...{{end}}
- Loops: {{range .list}}...{{end}}
- Custom functions via template.FuncMap
- Nested fields: {{.user.address.city}}
Message types are identified by fully qualified name (e.g., "example.UserResponse").
Example (TemplateFormat) ¶
Example_templateFormat demonstrates template format usage
package main
import (
protocli "github.com/drewfead/proto-cli"
)
func main() {
// Define templates for message types
templates := map[string]string{
"example.UserResponse": `{{$f := protoFields .}}User: {{$f.user.name}} (ID: {{$f.user.id}})
Email: {{$f.user.email}}
Status: {{if $f.user.verified}}Verified{{else}}Unverified{{end}}`,
}
// Create the format
format, err := protocli.TemplateFormat("user-detail", templates)
if err != nil {
panic(err)
}
// Use in CLI
_ = format // protocli.WithOutputFormats(format)
}
Index ¶
- Variables
- func CallFactory(factory any, config proto.Message) (any, error)
- func DefaultConfigPaths(rootCommandName string) []string
- func DefaultTemplateFunctions() template.FuncMap
- func NewConfigMessage(configType proto.Message) proto.Message
- func NewDaemonizeCommand(_ context.Context, services []*ServiceCLI, _ ServiceConfig) *cli.Command
- func RootCommand(appName string, opts ...RootOption) (*cli.Command, error)
- type ConfigDebugInfo
- type ConfigLoader
- type ConfigLoaderOption
- type ConfigMode
- type DaemonReadyHook
- type DaemonShutdownHook
- type DaemonStartupHook
- type FlagConfiguredOutputFormat
- type FlagContainer
- type FlagDeserializer
- type HelpCustomization
- type LoggingConfigCallback
- type OutputFormat
- type RootConfig
- type RootOnlyOption
- func ConfigureLogging(configFunc LoggingConfigCallback) RootOnlyOption
- func OnDaemonReady(hook DaemonReadyHook) RootOnlyOption
- func OnDaemonShutdown(hook DaemonShutdownHook) RootOnlyOption
- func OnDaemonStartup(hook DaemonStartupHook) RootOnlyOption
- func Service(service *ServiceCLI, opts ...ServiceRegistrationOption) RootOnlyOption
- func WithConfigFactory(serviceName string, factory any) RootOnlyOption
- func WithConfigFile(path string) RootOnlyOption
- func WithDefaultVerbosity(level slog.Level) RootOnlyOption
- func WithEnvPrefix(prefix string) RootOnlyOption
- func WithGRPCServerOptions(opts ...grpc.ServerOption) RootOnlyOption
- func WithGracefulShutdownTimeout(timeout time.Duration) RootOnlyOption
- func WithHelpCustomization(custom *HelpCustomization) RootOnlyOption
- func WithRootCommandHelpTemplate(template string) RootOnlyOption
- func WithStreamInterceptor(interceptor grpc.StreamServerInterceptor) RootOnlyOption
- func WithTranscoding(httpPort int) RootOnlyOption
- func WithUnaryInterceptor(interceptor grpc.UnaryServerInterceptor) RootOnlyOption
- type RootOption
- type ServiceCLI
- type ServiceConfig
- type ServiceOnlyOption
- type ServiceOption
- type ServiceRegistrationOption
- type SharedOption
- type SlogConfigurationContext
- type TemplateFunctionRegistry
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( ErrUnexpectedFieldValueType = errors.New("unexpected field value type") ErrOverflow = errors.New("overflow") )
var ( ErrWrongConfigType = errors.New("wrong config type") ErrAmbiguousCommandInvocation = errors.New("more than one action registered for the same command") )
var ErrNoTemplate = errors.New("no template registered for message type")
ErrNoTemplate is returned when no template is registered for a message type.
var ErrUnknownField = errors.New("unknown field")
Functions ¶
func CallFactory ¶
CallFactory calls a factory function with a config message using reflection. Returns the service implementation.
func DefaultConfigPaths ¶
DefaultConfigPaths returns default paths for config files.
func DefaultTemplateFunctions ¶
DefaultTemplateFunctions returns the default set of template functions. These functions are available in all templates unless overridden.
func NewConfigMessage ¶
NewConfigMessage creates a new config message instance using the proto registry. The configType should be a pointer to the config message type (e.g., &UserServiceConfig{}).
func NewDaemonizeCommand ¶
func NewDaemonizeCommand(_ context.Context, services []*ServiceCLI, _ ServiceConfig) *cli.Command
NewDaemonizeCommand creates a daemonize command for the given services. This is useful for single-service CLIs using the flat command structure.
func RootCommand ¶
func RootCommand(appName string, opts ...RootOption) (*cli.Command, error)
RootCommand creates a root CLI command with the given app name and options. Returns an error if there are naming collisions between hoisted service commands.
Types ¶
type ConfigDebugInfo ¶
type ConfigDebugInfo struct {
PathsChecked []string // All paths that were checked
FilesLoaded []string // Paths that were successfully loaded
FilesFailed map[string]string // Paths that failed with error message
EnvVarsApplied map[string]string // Env vars that were applied (name -> value)
FlagsApplied map[string]string // CLI flags that were applied (name -> value)
FinalConfig any // Final merged config (for display)
}
ConfigDebugInfo tracks config loading for debugging.
type ConfigLoader ¶
type ConfigLoader struct {
// contains filtered or unexported fields
}
ConfigLoader loads configuration with precedence: CLI flags > env vars > files.
func NewConfigLoader ¶
func NewConfigLoader(mode ConfigMode, opts ...ConfigLoaderOption) *ConfigLoader
NewConfigLoader creates a new config loader with options.
func (*ConfigLoader) DebugInfo ¶
func (l *ConfigLoader) DebugInfo() *ConfigDebugInfo
DebugInfo returns the config debug information (only populated if debug mode is enabled).
func (*ConfigLoader) LoadServiceConfig ¶
func (l *ConfigLoader) LoadServiceConfig( cmd *cli.Command, serviceName string, target proto.Message, ) error
LoadServiceConfig loads config for a specific service.
serviceName: lowercase service name (e.g., "userservice") target: pointer to config message instance
type ConfigLoaderOption ¶
type ConfigLoaderOption func(*ConfigLoader)
ConfigLoaderOption is a functional option for configuring a ConfigLoader.
func DebugMode ¶
func DebugMode(enabled bool) ConfigLoaderOption
DebugMode enables config loading debug information.
func EnvPrefix ¶
func EnvPrefix(prefix string) ConfigLoaderOption
EnvPrefix sets the environment variable prefix for config overrides.
func FileConfig ¶
func FileConfig(paths ...string) ConfigLoaderOption
FileConfig adds config file paths to load.
func ReaderConfig ¶
func ReaderConfig(readers ...io.Reader) ConfigLoaderOption
ReaderConfig adds io.Readers to load config from (for testing).
type ConfigMode ¶
type ConfigMode int
ConfigMode determines which config sources are used.
const ( // SingleCommandMode uses files + env + flags (all sources). SingleCommandMode ConfigMode = iota // DaemonMode uses files + env only (no CLI flag overrides). DaemonMode )
type DaemonReadyHook ¶
DaemonReadyHook is called after the gRPC server is listening and ready to accept connections Errors must be handled within the hook (no error return).
type DaemonShutdownHook ¶
DaemonShutdownHook is called during graceful shutdown after stop accepting new connections The context will be cancelled when the graceful shutdown timeout expires Errors must be handled within the hook (no error return).
type DaemonStartupHook ¶
DaemonStartupHook is called before the gRPC server starts listening Receives the gRPC server instance and gateway mux (if transcoding is enabled) Returning an error prevents the daemon from starting.
type FlagConfiguredOutputFormat ¶
type FlagConfiguredOutputFormat interface {
OutputFormat
// Flags returns additional flags this format needs (e.g., --pretty for JSON).
Flags() []cli.Flag
}
FlagConfiguredOutputFormat is an optional interface for formats that need custom flags.
type FlagContainer ¶
type FlagContainer interface {
// Primary flag accessors (use the encapsulated flag name)
String() string
Int() int
Int64() int64
Uint() uint
Uint64() uint64
Bool() bool
Float() float64
StringSlice() []string
IsSet() bool
// Named flag accessors (for accessing other flags)
StringNamed(flagName string) string
IntNamed(flagName string) int
Int64Named(flagName string) int64
BoolNamed(flagName string) bool
FloatNamed(flagName string) float64
StringSliceNamed(flagName string) []string
IsSetNamed(flagName string) bool
// FlagName returns the primary flag name for this container
FlagName() string
}
FlagContainer provides type-safe access to flag values for a specific flag It encapsulates the CLI command and flag name, exposing convenient accessors This abstraction allows deserializers to be reusable across different flag names
For deserializers that need to access multiple flags (e.g., top-level request deserializers), use the *Named() methods to read other flags by name.
func NewFlagContainer ¶
func NewFlagContainer(cmd *cli.Command, flagName string) FlagContainer
NewFlagContainer creates a new FlagContainer for the given command and flag name.
type FlagDeserializer ¶
FlagDeserializer builds a proto message from CLI flags This allows users to implement custom logic for constructing complex messages from simple CLI flags. The FlagContainer provides type-safe access to the flag value without requiring knowledge of the flag name, making deserializers reusable.
Example of a reusable timestamp deserializer:
func(ctx context.Context, flags FlagContainer) (proto.Message, error) {
timeStr := flags.String() // No need to know the flag name!
t, err := time.Parse(time.RFC3339, timeStr)
if err != nil {
return nil, err
}
return timestamppb.New(t), nil
}
type HelpCustomization ¶
type HelpCustomization struct {
// RootCommandHelpTemplate overrides the default root command help template
RootCommandHelpTemplate string
// CommandHelpTemplate overrides the default command help template
CommandHelpTemplate string
// SubcommandHelpTemplate overrides the default subcommand help template
SubcommandHelpTemplate string
}
HelpCustomization holds options for customizing help text display. Based on urfave/cli v3 help customization capabilities.
type LoggingConfigCallback ¶
type LoggingConfigCallback func(ctx context.Context, config SlogConfigurationContext) *slog.Logger
LoggingConfigCallback is a function that configures the slog logger. It receives a context with configuration details and returns a configured logger.
type OutputFormat ¶
type OutputFormat interface {
// Name returns the format identifier (e.g., "json", "text")
Name() string
// Format writes the formatted proto message to the writer
Format(ctx context.Context, cmd *cli.Command, w io.Writer, msg proto.Message) error
}
OutputFormat defines how to format proto messages for output.
func JSON ¶
func JSON() OutputFormat
JSON returns a new JSON output format with optional --pretty flag.
func MustTemplateFormat ¶
func MustTemplateFormat(name string, templates map[string]string, funcMaps ...template.FuncMap) OutputFormat
MustTemplateFormat is like TemplateFormat but panics on error. Useful for package-level initialization where template errors should be caught at startup.
Example:
var userFormat = protocli.MustTemplateFormat("user", map[string]string{
"example.UserResponse": `{{.user.name}} <{{.user.email}}>`,
})
func TemplateFormat ¶
func TemplateFormat(name string, templates map[string]string, funcMaps ...template.FuncMap) (OutputFormat, error)
TemplateFormat creates an output format that renders proto messages using Go text templates.
Templates are specified as a map from fully qualified message type name to template string. The message type name format is "package.MessageName" (e.g., "example.UserResponse").
Templates receive the actual proto message directly. Custom template functions receive actual proto types (e.g., *timestamppb.Timestamp), not JSON strings or maps.
Default template functions available:
- protoField: access message fields by JSON name, preserving proto types
- protoJSON: convert proto message to JSON string
- protoJSONIndent: convert proto message to indented JSON string
- protoFields: convert proto message to map for dot-chain field access
Field access patterns:
- Use protoFields for easy dot-chain access (proto types become JSON types): {{$fields := protoFields .}}{{$fields.user.name}}
- Use protoField helper to preserve proto types: {{protoField . "fieldName"}}
- Register custom accessor functions for your message types (recommended for complex templates)
Optional function maps can be provided to add custom template functions. Functions are merged in order: defaults, global registry, then provided funcMaps.
Example with protoFields (simplest):
templates := map[string]string{
"example.UserResponse": `{{$f := protoFields .}}User: {{$f.user.name}}
Email: {{$f.user.email}}
ID: {{$f.user.id}}`,
}
format := protocli.TemplateFormat("user-table", templates)
Example with custom accessor (best for proto types):
// Register type-specific accessor functions globally
protocli.TemplateFunctions().Register("user", func(resp *simple.UserResponse) *simple.User {
return resp.GetUser()
})
protocli.TemplateFunctions().Register("formatTime", func(ts *timestamppb.Timestamp) string {
if ts == nil || !ts.IsValid() {
return "N/A"
}
return ts.AsTime().Format("2006-01-02")
})
templates := map[string]string{
"example.UserResponse": `User: {{(user .).GetName}}
Created: {{formatTime (user .).GetCreatedAt}}`,
}
format := protocli.TemplateFormat("user-table", templates)
type RootConfig ¶
type RootConfig interface {
Services() []*ServiceCLI
GRPCServerOptions() []grpc.ServerOption
EnableTranscoding() bool
TranscodingPort() int
ConfigPaths() []string
EnvPrefix() string
ServiceFactory(serviceName string) (any, bool)
GracefulShutdownTimeout() time.Duration
DaemonStartupHooks() []DaemonStartupHook
DaemonReadyHooks() []DaemonReadyHook
DaemonShutdownHooks() []DaemonShutdownHook
LoggingConfig() LoggingConfigCallback
DefaultVerbosity() string
HelpCustomization() *HelpCustomization
}
RootConfig is the configuration returned by ApplyRootOptions. Used by RootCommand.
func ApplyRootOptions ¶
func ApplyRootOptions(opts ...RootOption) RootConfig
ApplyRootOptions applies functional options and returns configured root settings.
type RootOnlyOption ¶
type RootOnlyOption func(*rootCommandOptions)
RootOnlyOption is a concrete option type that only works with root level. It implements only the RootOption interface.
func ConfigureLogging ¶
func ConfigureLogging(configFunc LoggingConfigCallback) RootOnlyOption
ConfigureLogging provides a custom slog logger configuration function. If not specified, the framework uses sensible defaults:
- Single commands: human-friendly colored logs to stderr (via clilog.HumanFriendlySlogHandler)
- Daemon mode: JSON-formatted logs to stdout
The function receives a context and a SlogConfigurationContext providing:
- IsDaemon(): true for daemon mode, false for single commands
- Level(): the configured log level from the --verbosity flag
IMPORTANT: Your custom logger factory MUST respect config.Level() to honor the --verbosity flag.
Type-safe: only works with RootOptions.
Example - Custom handler that respects verbosity:
protocli.ConfigureLogging(func(ctx context.Context, config protocli.SlogConfigurationContext) *slog.Logger {
handler := clilog.HumanFriendlySlogHandler(os.Stderr, &slog.HandlerOptions{
Level: config.Level(), // IMPORTANT: Use config.Level() to respect --verbosity flag
})
return slog.New(handler)
})
Example - Different loggers for daemon vs single-command mode:
protocli.ConfigureLogging(func(ctx context.Context, config protocli.SlogConfigurationContext) *slog.Logger {
if config.IsDaemon() {
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: config.Level()})
return slog.New(handler)
}
handler := clilog.HumanFriendlySlogHandler(os.Stderr, &slog.HandlerOptions{Level: config.Level()})
return slog.New(handler)
})
Example - Use the convenience function for always human-friendly logging:
protocli.ConfigureLogging(clilog.AlwaysHumanFriendly())
func OnDaemonReady ¶
func OnDaemonReady(hook DaemonReadyHook) RootOnlyOption
OnDaemonReady registers a hook that runs after the gRPC server is listening and ready. Multiple hooks can be registered and will run in registration order. The hook cannot return errors - errors must be handled within the hook. Type-safe: only works with RootOptions.
func OnDaemonShutdown ¶
func OnDaemonShutdown(hook DaemonShutdownHook) RootOnlyOption
OnDaemonShutdown registers a hook that runs during graceful shutdown. Multiple hooks can be registered and will run in REVERSE registration order. The hook runs after stop accepting new connections but before forcing shutdown. The context will be cancelled when the graceful shutdown timeout expires. The hook cannot return errors - errors must be handled within the hook. Type-safe: only works with RootOptions.
func OnDaemonStartup ¶
func OnDaemonStartup(hook DaemonStartupHook) RootOnlyOption
OnDaemonStartup registers a hook that runs before the gRPC server starts listening. Multiple hooks can be registered and will run in registration order. The hook receives the gRPC server instance and gateway mux (may be nil if transcoding disabled). Returning an error prevents the daemon from starting. Type-safe: only works with RootOptions.
func Service ¶
func Service(service *ServiceCLI, opts ...ServiceRegistrationOption) RootOnlyOption
Service registers a service CLI (root level only). Accepts optional ServiceRegistrationOptions to customize registration (e.g., Hoisted()). Type-safe: only works with RootOptions.
func WithConfigFactory ¶
func WithConfigFactory(serviceName string, factory any) RootOnlyOption
WithConfigFactory registers a factory function for a service. The factory function takes a config message and returns a service implementation. Example: WithConfigFactory("userservice", func(cfg *UserServiceConfig) UserServiceServer { ... }). Type-safe: only works with RootOptions.
func WithConfigFile ¶
func WithConfigFile(path string) RootOnlyOption
WithConfigFile adds a config file path to load. Can be called multiple times to specify multiple config files (deep merge). Type-safe: only works with RootOptions.
func WithDefaultVerbosity ¶
func WithDefaultVerbosity(level slog.Level) RootOnlyOption
WithDefaultVerbosity sets the default verbosity level for the --verbosity flag. Accepts standard slog.Level values: slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError. Note: In slog, higher numeric values = less verbose logging:
- slog.LevelDebug (-4) = most verbose
- slog.LevelInfo (0) = normal
- slog.LevelWarn (4) = warnings and errors only
- slog.LevelError (8) = errors only
- slog.Level(1000) or higher = effectively disables logging
Default is slog.LevelInfo if not specified. Users can still override via the --verbosity flag or -v shorthand. Type-safe: only works with RootOptions.
Example:
protocli.WithDefaultVerbosity(slog.LevelDebug) // Most verbose (debug and above) protocli.WithDefaultVerbosity(slog.LevelWarn) // Less verbose (warn and error only) protocli.WithDefaultVerbosity(slog.Level(1000)) // Disable logging
func WithEnvPrefix ¶
func WithEnvPrefix(prefix string) RootOnlyOption
WithEnvPrefix sets the environment variable prefix for config overrides. Example: WithEnvPrefix("USERCLI") enables USERCLI_DB_URL env var. Type-safe: only works with RootOptions.
func WithGRPCServerOptions ¶
func WithGRPCServerOptions(opts ...grpc.ServerOption) RootOnlyOption
WithGRPCServerOptions adds gRPC server options (e.g., for interceptors). Type-safe: only works with RootOptions.
func WithGracefulShutdownTimeout ¶
func WithGracefulShutdownTimeout(timeout time.Duration) RootOnlyOption
WithGracefulShutdownTimeout sets the timeout for graceful daemon shutdown. Default is 15 seconds if not specified. During graceful shutdown, the daemon will wait for in-flight requests to complete. before forcefully terminating after this timeout. Type-safe: only works with RootOptions.
func WithHelpCustomization ¶
func WithHelpCustomization(custom *HelpCustomization) RootOnlyOption
WithHelpCustomization sets custom help templates and printer functions. This allows full customization of help text display following urfave/cli v3 patterns.
Example:
protocli.WithHelpCustomization(&protocli.HelpCustomization{
RootCommandHelpTemplate: myCustomTemplate,
CustomizeRootCommand: func(cmd *cli.Command) {
cmd.Usage = "My custom usage text"
},
})
func WithRootCommandHelpTemplate ¶
func WithRootCommandHelpTemplate(template string) RootOnlyOption
WithRootCommandHelpTemplate sets a custom template for root command help. This is a convenience function for the most common help customization.
Example:
protocli.WithRootCommandHelpTemplate(`
NAME:
{{.Name}} - {{.Usage}}
USAGE:
{{.HelpName}} {{if .VisibleFlags}}[options]{{end}} command [command options]
VERSION:
{{.Version}}
`)
func WithStreamInterceptor ¶
func WithStreamInterceptor(interceptor grpc.StreamServerInterceptor) RootOnlyOption
WithStreamInterceptor adds a stream interceptor to the gRPC server. Type-safe: only works with RootOptions.
func WithTranscoding ¶
func WithTranscoding(httpPort int) RootOnlyOption
WithTranscoding enables gRPC-Gateway transcoding (HTTP/JSON to gRPC). This allows clients to call gRPC services via REST/JSON on the specified port. Type-safe: only works with RootOptions.
func WithUnaryInterceptor ¶
func WithUnaryInterceptor(interceptor grpc.UnaryServerInterceptor) RootOnlyOption
WithUnaryInterceptor adds a unary interceptor to the gRPC server. Type-safe: only works with RootOptions.
type RootOption ¶
type RootOption interface {
// contains filtered or unexported methods
}
RootOption interface for root-level configuration.
type ServiceCLI ¶
type ServiceCLI struct {
Command *cli.Command
ServiceName string // Service name (e.g., "userservice")
ConfigMessageType string // Config message type name (empty if no config)
ConfigPrototype proto.Message // Prototype config message instance (for cloning)
FactoryOrImpl any // Factory function or direct service implementation
RegisterFunc func(*grpc.Server, any) // Register service with gRPC server (takes impl)
GatewayRegisterFunc func(ctx context.Context, mux any) error // mux is *runtime.ServeMux from grpc-gateway
}
ServiceCLI represents a service CLI with its command and gRPC registration function.
type ServiceConfig ¶
type ServiceConfig interface {
BeforeCommandHooks() []func(context.Context, *cli.Command) error
AfterCommandHooks() []func(context.Context, *cli.Command) error
OutputFormats() []OutputFormat
FlagDeserializer(messageName string) (FlagDeserializer, bool)
}
ServiceConfig is the configuration returned by ApplyServiceOptions. Used by generated service command code.
func ApplyServiceOptions ¶
func ApplyServiceOptions(opts ...ServiceOption) ServiceConfig
ApplyServiceOptions applies functional options and returns configured service settings.
type ServiceOnlyOption ¶
type ServiceOnlyOption func(*serviceCommandOptions)
ServiceOnlyOption is a concrete option type that only works with service level. It implements only the ServiceOption interface.
func WithFlagDeserializer ¶
func WithFlagDeserializer(messageName string, deserializer FlagDeserializer) ServiceOnlyOption
WithFlagDeserializer registers a custom deserializer for a specific message type This allows users to implement custom logic for constructing complex proto messages from CLI flags, enabling advanced transformations and validation.
Example:
WithFlagDeserializer("GetUserRequest", func(ctx context.Context, cmd *cli.Command) (proto.Message, error) {
// Custom logic to build GetUserRequest from flags
userId := cmd.String("user-id")
return &pb.GetUserRequest{
UserId: userId,
IncludeDetails: cmd.Bool("details"),
}, nil
})
Type-safe: only works with ServiceOptions.
type ServiceOption ¶
type ServiceOption interface {
// contains filtered or unexported methods
}
ServiceOption interface for service-level configuration.
type ServiceRegistrationOption ¶
type ServiceRegistrationOption func(*serviceRegistration)
ServiceRegistrationOption configures how a service is registered in the root command.
func Hoisted ¶
func Hoisted() ServiceRegistrationOption
Hoisted returns an option that hoists service RPC commands to the root level. When hoisted, RPC commands appear as siblings of the daemonize command instead of nested under the service name. Multiple services can be hoisted - naming collisions will cause a runtime error. Example: protocli.WithService(serviceCLI, protocli.Hoisted())
type SharedOption ¶
type SharedOption func(baseOptions)
SharedOption is a concrete option type that works with both service and root levels. It implements both ServiceOption and RootOption interfaces.
func AfterCommand ¶
AfterCommand registers a hook that runs after each command execution. Works with both ServiceCommand and RootCommand. Multiple hooks can be registered and will run in REVERSE registration order. This allows cleanup to happen in the opposite order of setup (LIFO pattern). Works with both ServiceCommand and RootCommand.
func BeforeCommand ¶
BeforeCommand registers a hook that runs before each command execution. Multiple hooks can be registered and will run in registration order. Works with both ServiceCommand and RootCommand.
func WithOutputFormats ¶
func WithOutputFormats(formats ...OutputFormat) SharedOption
WithOutputFormats registers output formatters for response rendering. Works with both ServiceCommand and RootCommand.
type SlogConfigurationContext ¶
type SlogConfigurationContext interface {
// IsDaemon returns true if the logger is being configured for daemon mode.
IsDaemon() bool
// Level returns the configured log level from the --verbosity flag.
Level() slog.Level
}
SlogConfigurationContext provides context information for slog configuration.
type TemplateFunctionRegistry ¶
type TemplateFunctionRegistry struct {
// contains filtered or unexported fields
}
TemplateFunctionRegistry manages custom template functions for use in template-based output formats. It provides a way to register custom functions that templates can use to format proto messages.
func NewTemplateFunctionRegistry ¶
func NewTemplateFunctionRegistry() *TemplateFunctionRegistry
NewTemplateFunctionRegistry creates a new registry with default template functions. Default functions include:
- protoField: access message fields by JSON name, preserving proto types
- protoJSON: converts a proto message to JSON string using protojson
- protoJSONIndent: converts a proto message to indented JSON string
- protoFields: converts a proto message to map for dot-chain field access
func TemplateFunctions ¶
func TemplateFunctions() *TemplateFunctionRegistry
TemplateFunctions returns the global template function registry. This can be used to register custom template functions globally.
Example:
protocli.TemplateFunctions().Register("formatDate", func(ts *timestamppb.Timestamp) string {
return ts.AsTime().Format("2006-01-02")
})
func (*TemplateFunctionRegistry) Functions ¶
func (r *TemplateFunctionRegistry) Functions() template.FuncMap
Functions returns the complete set of registered template functions. This includes both default functions and any user-registered functions.
func (*TemplateFunctionRegistry) Register ¶
func (r *TemplateFunctionRegistry) Register(name string, fn any)
Register adds or replaces a template function. If a function with the same name already exists, it will be replaced.
func (*TemplateFunctionRegistry) RegisterMap ¶
func (r *TemplateFunctionRegistry) RegisterMap(funcMap template.FuncMap)
RegisterMap adds multiple template functions at once. Existing functions with the same names will be replaced.
Directories
¶
| Path | Synopsis |
|---|---|
|
cli
|
|
|
cmd
|
|
|
gen
command
|
|
|
examples
|
|
|
simple
Package simple demonstrates basic proto-cli usage with unary gRPC methods.
|
Package simple demonstrates basic proto-cli usage with unary gRPC methods. |
|
simple/usercli
command
|
|
|
simple/usercli_flat
command
|
|
|
streaming
Package streaming demonstrates server streaming gRPC support in proto-cli.
|
Package streaming demonstrates server streaming gRPC support in proto-cli. |
|
streaming/streamcli
command
|
|
|
streaming/streamcli_flat
command
|
|
|
proto
|
|
|
cli/v1
Package cli provides Protocol Buffer definitions for CLI annotations.
|
Package cli provides Protocol Buffer definitions for CLI annotations. |