zapp

package
v0.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package zapp provides a small lifecycle wrapper for command-line apps.

A Program creates a typed app instance, runs it, and returns a process exit code. App handles signal cancellation, panic recovery, and deterministic cleanup of named io.Closer resources.

Typical usage keeps main.go small:

type Zarlcode struct {
	// config, stores, services, TUI handles, etc.
}

type CLI struct{}

func (CLI) Name() string { return "zarlcode" }

func (CLI) Create(ctx context.Context, app *zapp.App[*Zarlcode]) (*Zarlcode, error) {
	z := &Zarlcode{}
	// app.AddCloser("state-db", db)
	return z, nil
}

func (CLI) Run(ctx context.Context, app *zapp.App[*Zarlcode], z *Zarlcode) int {
	return zapp.ExitOK
}

func main() {
	app := zapp.New[*Zarlcode](CLI{})
	os.Exit(app.Run(context.Background()))
}

Index

Examples

Constants

View Source
const (
	// ExitOK is the default successful process exit code.
	ExitOK = 0

	// ExitFailure is the default process exit code for expected failures.
	ExitFailure = 1

	// ExitPanic is the default process exit code for recovered panics.
	ExitPanic = 2
)

Variables

View Source
var (
	ErrNilProgram    = errors.New("zapp: nil program")
	ErrEmptyName     = errors.New("zapp: empty resource name")
	ErrNilCloser     = errors.New("zapp: nil closer")
	ErrDuplicateName = errors.New("zapp: duplicate resource name")
	ErrClosed        = errors.New("zapp: app is closing or closed")
)

Registration and lifecycle errors. All are programmer errors surfaced at wire-up time except ErrClosed, which callers can race against legitimately during shutdown.

Functions

func WithCleanupFailureExitCode

func WithCleanupFailureExitCode[T any](code int) options.Option[App[T]]

WithCleanupFailureExitCode configures the exit code returned when cleanup fails after an otherwise successful run.

func WithCreateFailureExitCode

func WithCreateFailureExitCode[T any](code int) options.Option[App[T]]

WithCreateFailureExitCode configures the exit code returned when Create fails.

func WithPanicExitCode

func WithPanicExitCode[T any](code int) options.Option[App[T]]

WithPanicExitCode configures the exit code returned when Run recovers a panic.

func WithPanicHandler

func WithPanicHandler[T any](handler PanicHandler) options.Option[App[T]]

WithPanicHandler configures a callback for panics recovered by Run.

func WithShutdownTimeout

func WithShutdownTimeout[T any](timeout time.Duration) options.Option[App[T]]

WithShutdownTimeout configures the maximum time allowed for cleanup.

func WithSignals

func WithSignals[T any](signals ...os.Signal) options.Option[App[T]]

WithSignals configures the signals that cancel the run context. Passing no signals disables signal handling.

Types

type App

type App[T any] struct {
	// contains filtered or unexported fields
}

App wraps a Program with signal handling, panic recovery, and deterministic resource cleanup.

Example
package main

import (
	"context"
	"fmt"

	"github.com/zarldev/zarlmono/zkit/zapp"
)

type exampleProgram struct{}

func (exampleProgram) Name() string { return "example" }

func (exampleProgram) Create(_ context.Context, app *zapp.App[string]) (string, error) {
	_ = app.AddCloser("cleanup", zapp.CloseFunc(func() error {
		fmt.Println("cleanup")
		return nil
	}))
	return "ready", nil
}

func (exampleProgram) Run(_ context.Context, _ *zapp.App[string], value string) int {
	fmt.Println(value)
	return zapp.ExitOK
}

func main() {
	code := zapp.New[string](exampleProgram{}).Run(context.Background())
	fmt.Println(code)
}
Output:
ready
cleanup
0

func New

func New[T any](program Program[T], opts ...options.Option[App[T]]) *App[T]

New creates an App for program using sensible defaults.

Example
package main

import (
	"context"
	"fmt"

	"github.com/zarldev/zarlmono/zkit/zapp"
)

type exampleZarlcode struct{}

type exampleCLI struct{}

func (exampleCLI) Name() string { return "zarlcode" }

func (exampleCLI) Create(context.Context, *zapp.App[*exampleZarlcode]) (*exampleZarlcode, error) {
	return &exampleZarlcode{}, nil
}

func (exampleCLI) Run(context.Context, *zapp.App[*exampleZarlcode], *exampleZarlcode) int {
	return zapp.ExitOK
}

func main() {
	app := zapp.New(exampleCLI{})
	fmt.Println(app.Name())
}
Output:
zarlcode

func (*App[T]) AddCloser

func (a *App[T]) AddCloser(name string, closer io.Closer) error

AddCloser registers a named resource for cleanup.

func (*App[T]) AddContextCloser added in v0.16.0

func (a *App[T]) AddContextCloser(name string, closer ContextCloser) error

AddContextCloser registers a named context-aware resource for cleanup.

func (*App[T]) Close

func (a *App[T]) Close(ctx context.Context) error

Close closes all registered resources in reverse registration order.

func (*App[T]) Name

func (a *App[T]) Name() string

Name returns the app's normalized program name.

func (*App[T]) Run

func (a *App[T]) Run(ctx context.Context) int

Run creates and runs the program, then always attempts cleanup.

type CloseFunc

type CloseFunc func() error

CloseFunc adapts a cleanup function to io.Closer so callers can register function-shaped cleanup with App.AddCloser without defining local adapter types.

func (CloseFunc) Close

func (f CloseFunc) Close() error

Close invokes f. A nil CloseFunc is a no-op.

type ContextCloseFunc added in v0.16.0

type ContextCloseFunc func(context.Context) error

ContextCloseFunc adapts a context-aware cleanup function to ContextCloser.

func (ContextCloseFunc) Close added in v0.16.0

func (f ContextCloseFunc) Close(ctx context.Context) error

Close invokes f. A nil ContextCloseFunc is a no-op.

type ContextCloser added in v0.16.0

type ContextCloser interface {
	Close(context.Context) error
}

ContextCloser releases a resource while honoring the caller's shutdown deadline. Long-running cleanup should implement this contract rather than hiding its own timeout inside an io.Closer.

type PanicHandler

type PanicHandler func(appName string, recovered any)

PanicHandler observes a panic recovered by App.Run.

type Program

type Program[T any] interface {
	Name() string
	Create(context.Context, *App[T]) (T, error)
	Run(context.Context, *App[T], T) int
}

Program defines the lifecycle for a command-line application.

Create builds the typed application instance and may register resources with AddCloser. Run executes the application and returns the desired process exit code. Name identifies the program in errors and metadata.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL