feat(bonfire): global flags, Artisan list and exit codes
- Global options -v/-vv/-vvv, -q, --ansi/--no-ansi, -n and --env on every command; PeekGlobals reads them before config loads, OnGlobals hooks re-apply them after parsing (diary.ApplyGlobals in the generated main) - Bare binary, --help and list print the Artisan list with the version header from BuildVersion and namespace blocks - Execute runs the root through fang (no version, man page or completions) and returns 0, 1 or 2; Fail renders errors before the root exists - NewRoot rejects duplicate command names (ErrDuplicateCommand) and flags that reuse a global option (ErrReservedFlag) - Generated main and summer use PeekGlobals, compass.Open with --env, diary.FromGlobals and bonfire.Execute; docs checker knows the globals
This commit is contained in:
@@ -10,7 +10,7 @@ Application logging modelled on Laravel's logging config: named channels (consol
|
||||
|
||||
`diary` owns the process logger of a SummerCMS application. `config/log.yaml` names a default channel, a global level and a map of channels, the way Laravel's `config/logging.php` does: a console channel that prints styled lines on a terminal, daily files with retention, and a stack that fans a record out to several channels. Code logs through named component loggers (`diary.For`), so every record carries the plugin or module it came from. Every channel is wrapped by `sunscreen.Wrap`, so credentials are redacted whichever channel a record reaches.
|
||||
|
||||
The application `main` that `summer build` generates calls `diary.Bootstrap` as its first statement, which installs a console channel before configuration is read, and `diary.Setup` right after `compass` loads `config/`.
|
||||
The application `main` that `summer build` generates reads the console global options first (`bonfire.PeekGlobals`), calls `diary.Bootstrap` with them, which installs a console channel before configuration is read, and `diary.Setup` right after `compass` loads `config/`. Once the command line is parsed, `diary.ApplyGlobals` re-applies `-v`, `-q` and `--ansi`/`--no-ansi`.
|
||||
|
||||
## Role in the framework
|
||||
|
||||
@@ -33,6 +33,7 @@ Use cases:
|
||||
- Daily files: the path `storage/logs/summer.log` gives files `storage/logs/summer-2026-10-21.log`, created mode 0640 in directories created 0750, opened on the first record, rotated at local midnight, and deleted after the retention in days (only files of that name pattern). A relative path resolves against the application root. A directory that cannot be written logs one warning from component `diary` on the console and disables the channel; it never fails the start-up.
|
||||
- Redaction: every channel leaf is wrapped by `sunscreen.Wrap`.
|
||||
- Runtime verbosity: `diary.SetVerbosity` lets info (1) or debug (2) through for every component and adds source locations on styled lines (3); quiet raises only the console channels to warn.
|
||||
- Console global options: `diary.FromGlobals` turns `-v`/`-vv`/`-vvv`, `-q` and `--ansi`/`--no-ansi` into `diary.Options`, and `diary.ApplyGlobals` applies them to the running setup (the generated main registers it with `bonfire.OnGlobals`).
|
||||
- The process default logger (`slog.Default`) and the standard `log` package log through the configured channels without a component.
|
||||
|
||||
## Usage
|
||||
@@ -58,16 +59,20 @@ and writes warnings and errors as JSON to `storage/logs/summer-YYYY-MM-DD.log`.
|
||||
The generated `main` installs it:
|
||||
|
||||
```go
|
||||
func run(args []string, out io.Writer) error {
|
||||
diary.Bootstrap(os.Stderr, diary.Options{})
|
||||
cfg, err := compass.Load("config")
|
||||
func run(args []string, out io.Writer) int {
|
||||
g := bonfire.PeekGlobals(args)
|
||||
diary.Bootstrap(os.Stderr, diary.FromGlobals(g))
|
||||
cfg, err := compass.Open(compass.Options{Dir: "config", Env: g.Env})
|
||||
if err != nil {
|
||||
return err
|
||||
return bonfire.Fail(os.Stderr, "acme", err, g)
|
||||
}
|
||||
if err := diary.Setup(cfg, diary.Options{}); err != nil {
|
||||
return err
|
||||
if err := diary.Setup(cfg, diary.FromGlobals(g)); err != nil {
|
||||
return bonfire.Fail(os.Stderr, "acme", err, g)
|
||||
}
|
||||
// ...
|
||||
root, err := bonfire.NewRoot("acme", commands, out,
|
||||
bonfire.WithVersion(bonfire.BuildVersion()), bonfire.OnGlobals(diary.ApplyGlobals))
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
@@ -81,6 +86,8 @@ Tests that set diary up restore the previous process logger with `t.Cleanup(diar
|
||||
| `diary.Bootstrap` | Installs a console channel on a writer before configuration is read and makes diary the process default logger. |
|
||||
| `diary.Setup` | Parses `log.*` from a `compass` configuration, builds the channels and installs them; returns configuration errors. |
|
||||
| `diary.SetVerbosity` | Changes verbosity and quiet at runtime. |
|
||||
| `diary.FromGlobals` | Returns the `diary.Options` (verbosity, quiet, color mode) of the console global options in a `bonfire.Globals`. |
|
||||
| `diary.ApplyGlobals` | Applies parsed `bonfire.Globals` to the running setup: verbosity and quiet, and the console color mode when it changed. |
|
||||
| `diary.Verbosity` | Returns the current verbosity. |
|
||||
| `diary.Reset` | Drops the setup, closes its files and restores the process default logger captured at the first setup. |
|
||||
| `diary.Close` | Closes the open daily files; later records open them again. |
|
||||
|
||||
Reference in New Issue
Block a user