diff --git a/pkg/cli/app.go b/pkg/cli/app.go index 5cb68a7..5f6d2a9 100644 --- a/pkg/cli/app.go +++ b/pkg/cli/app.go @@ -34,9 +34,16 @@ var ( ) // SemVer returns the full SemVer 2.0.0 version string. -// - Release: 1.2.0 -// - Pre-release: 1.2.0-dev.8 -// - Full: 1.2.0-dev.8+df94c24.20260206 +// +// Examples: +// // Release only: +// // AppVersion=1.2.0 -> 1.2.0 +// cli.AppVersion = "1.2.0" +// fmt.Println(cli.SemVer()) +// +// // Pre-release + commit + date: +// // AppVersion=1.2.0, BuildPreRelease=dev.8, BuildCommit=df94c24, BuildDate=20260206 +// // -> 1.2.0-dev.8+df94c24.20260206 func SemVer() string { v := AppVersion if BuildPreRelease != "" { @@ -64,19 +71,37 @@ func WithAppName(name string) { type LocaleSource = i18n.FSSource // WithLocales returns a locale source for use with MainWithLocales. +// +// Example: +// fs := embed.FS{} +// locales := cli.WithLocales(fs, "locales") +// cli.MainWithLocales([]cli.LocaleSource{locales}) func WithLocales(fsys fs.FS, dir string) LocaleSource { return LocaleSource{FS: fsys, Dir: dir} } // CommandSetup is a function that registers commands on the CLI after init. +// +// Example: +// cli.Main( +// cli.WithCommands("doctor", doctor.AddDoctorCommands), +// ) type CommandSetup func(c *core.Core) // Main initialises and runs the CLI with the framework's built-in translations. +// +// Example: +// cli.WithAppName("core") +// cli.Main(config.AddConfigCommands) func Main(commands ...CommandSetup) { MainWithLocales(nil, commands...) } // MainWithLocales initialises and runs the CLI with additional translation sources. +// +// Example: +// locales := []cli.LocaleSource{cli.WithLocales(embeddedLocales, "locales")} +// cli.MainWithLocales(locales, doctor.AddDoctorCommands) func MainWithLocales(locales []LocaleSource, commands ...CommandSetup) { // Recovery from panics defer func() { diff --git a/pkg/cli/commands.go b/pkg/cli/commands.go index 63a9119..cf66fe2 100644 --- a/pkg/cli/commands.go +++ b/pkg/cli/commands.go @@ -29,6 +29,13 @@ func WithCommands(name string, register func(root *Command), localeFS ...fs.FS) } // CommandRegistration is a function that adds commands to the CLI root. +// +// Example: +// func addCommands(root *cobra.Command) { +// root.AddCommand(cli.NewRun("ping", "Ping API", "", func(cmd *cli.Command, args []string) { +// cli.Println("pong") +// })) +// } type CommandRegistration func(root *cobra.Command) var ( @@ -44,6 +51,13 @@ var ( // func init() { // cli.RegisterCommands(AddCommands, locales.FS) // } +// +// Example: +// cli.RegisterCommands(func(root *cobra.Command) { +// root.AddCommand(cli.NewRun("version", "Show version", "", func(cmd *cli.Command, args []string) { +// cli.Println(cli.SemVer()) +// })) +// }) func RegisterCommands(fn CommandRegistration, localeFS ...fs.FS) { registeredCommandsMu.Lock() registeredCommands = append(registeredCommands, fn) @@ -102,6 +116,11 @@ func loadLocaleSources(sources ...LocaleSource) { } // RegisteredLocales returns all locale filesystems registered by command packages. +// +// Example: +// for _, fs := range cli.RegisteredLocales() { +// _ = fs +// } func RegisteredLocales() []fs.FS { registeredCommandsMu.Lock() defer registeredCommandsMu.Unlock() @@ -114,6 +133,11 @@ func RegisteredLocales() []fs.FS { } // RegisteredCommands returns an iterator over the registered command functions. +// +// Example: +// for attach := range cli.RegisteredCommands() { +// _ = attach +// } func RegisteredCommands() iter.Seq[CommandRegistration] { return func(yield func(CommandRegistration) bool) { registeredCommandsMu.Lock() diff --git a/pkg/cli/runtime.go b/pkg/cli/runtime.go index 065e269..28cec08 100644 --- a/pkg/cli/runtime.go +++ b/pkg/cli/runtime.go @@ -39,6 +39,12 @@ type runtime struct { } // Options configures the CLI runtime. +// +// Example: +// opts := cli.Options{ +// AppName: "core", +// Version: "1.0.0", +// } type Options struct { AppName string Version string @@ -52,6 +58,11 @@ type Options struct { // Init initialises the global CLI runtime. // Call this once at startup (typically in main.go or cmd.Execute). +// +// Example: +// err := cli.Init(cli.Options{AppName: "core"}) +// if err != nil { panic(err) } +// defer cli.Shutdown() func Init(opts Options) error { var initErr error once.Do(func() { @@ -141,6 +152,11 @@ func RootCmd() *cobra.Command { // Execute runs the CLI root command. // Returns an error if the command fails. +// +// Example: +// if err := cli.Execute(); err != nil { +// cli.Warn("command failed:", "err", err) +// } func Execute() error { mustInit() return instance.root.Execute() @@ -149,6 +165,13 @@ func Execute() error { // Run executes the CLI and watches an external context for cancellation. // If the context is cancelled first, the runtime is shut down and the // command error is returned if execution failed during shutdown. +// +// Example: +// ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second) +// defer cancel() +// if err := cli.Run(ctx); err != nil { +// cli.Error(err.Error()) +// } func Run(ctx context.Context) error { mustInit() if ctx == nil { @@ -174,6 +197,10 @@ func Run(ctx context.Context) error { // RunWithTimeout returns a shutdown helper that waits for the runtime to stop // for up to timeout before giving up. It is intended for deferred cleanup. +// +// Example: +// stop := cli.RunWithTimeout(5 * time.Second) +// defer stop() func RunWithTimeout(timeout time.Duration) func() { return func() { if timeout <= 0 { @@ -197,12 +224,20 @@ func RunWithTimeout(timeout time.Duration) func() { // Context returns the CLI's root context. // Cancelled on SIGINT/SIGTERM. +// +// Example: +// if ctx := cli.Context(); ctx != nil { +// _ = ctx +// } func Context() context.Context { mustInit() return instance.ctx } // Shutdown gracefully shuts down the CLI. +// +// Example: +// cli.Shutdown() func Shutdown() { if instance == nil { return