-
Notifications
You must be signed in to change notification settings - Fork 0
CLI Integration
The neomacli package provides an optional CLI for Neoma services, built on Cobra. It bridges configuration from CLI flags, environment variables, and defaults into a type-safe Go struct.
Define your configuration as a struct with tags:
type Options struct {
Host string `doc:"Hostname to listen on" default:"0.0.0.0"`
Port int `doc:"Port to listen on" short:"p" default:"8080"`
Debug bool `doc:"Enable debug mode"`
}| Tag | Description |
|---|---|
doc |
Help text for the flag |
default |
Default value |
short |
Short flag name (single character) |
name |
Override the flag name (default is kebab-case of the field name) |
Supported field types: string, int, int64, bool, time.Duration.
cli := neomacli.New(func(hooks neomacli.Hooks, opts *Options) {
// Set up router, API, server using opts
// ...
hooks.OnStart(func() {
srv.ListenAndServe()
})
hooks.OnStop(func() {
srv.Shutdown(context.Background())
})
})
cli.Run()neomacli.New accepts a generic callback that receives Hooks and a pointer to your options struct. The Hooks interface provides OnStart and OnStop callbacks. OnStart runs in a goroutine; the main goroutine waits for SIGINT/SIGTERM and then calls OnStop.
Flags map to environment variables with a SERVICE_ prefix. The field name is converted to uppercase snake_case:
| Field | Flag | Env Var |
|---|---|---|
Port |
--port |
SERVICE_PORT |
Debug |
--debug |
SERVICE_DEBUG |
Nested structs use dot-separated flag names and underscore-separated env vars:
| Field | Flag | Env Var |
|---|---|---|
Database.Host |
--database.host |
SERVICE_DATABASE_HOST |
Precedence (highest first): CLI flag, environment variable, default tag value.
Access the root Cobra command via Root() to add subcommands. Use neomacli.WithOptions for type-safe access to the parsed options:
cli.Root().AddCommand(&cobra.Command{
Use: "migrate",
Short: "Run database migrations",
Run: neomacli.WithOptions(func(cmd *cobra.Command, args []string, opts *Options) {
fmt.Printf("Running migrations with debug=%v\n", opts.Debug)
}),
})By default, diagnostic messages go to stderr. Override with WithLogger:
cli := neomacli.New(onParsed, neomacli.WithLogger(myLogger))The logger must implement neomacli.Logger:
type Logger interface {
Println(args ...any)
}package main
import (
"context"
"fmt"
"log"
"net/http"
"github.com/MeGaNeKoS/neoma/adapters/neomachi/v5"
"github.com/MeGaNeKoS/neoma/core"
"github.com/MeGaNeKoS/neoma/neoma"
"github.com/MeGaNeKoS/neoma/neomacli"
"github.com/go-chi/chi/v5"
)
type Options struct {
Host string `doc:"Host to listen on" default:"0.0.0.0"`
Port int `doc:"Port to listen on" short:"p" default:"8080"`
Debug bool `doc:"Enable debug logging"`
}
func main() {
cli := neomacli.New(func(hooks neomacli.Hooks, opts *Options) {
router := chi.NewMux()
adapter := neomachi.NewAdapter(router)
config := neoma.DefaultConfig("My API", "1.0.0")
api := neoma.NewAPI(config, adapter)
// Register operations...
_ = api
addr := fmt.Sprintf("%s:%d", opts.Host, opts.Port)
srv := &http.Server{Addr: addr, Handler: router}
hooks.OnStart(func() {
fmt.Printf("Server starting on %s\n", addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatal(err)
}
})
hooks.OnStop(func() {
srv.Shutdown(context.Background())
})
})
cli.Run()
}# Use defaults
./myapp
# Override with flags
./myapp --port 3000 --debug
# Override with environment variables
SERVICE_PORT=3000 SERVICE_DEBUG=true ./myapp