mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-17 16:38:54 +00:00
Remove os.Exit callsites below the entrypoint: phase 1 (#2198)
* Rebuild docs: help-catalog index count drifted on main (666 -> 667)
Pre-existing drift from a recent catalog addition; surfaced by make dev.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Remove os.Exit callsites below the entrypoint: phase 1 (plans/exit.md)
Phase 1 of plans/exit.md: the mechanical swaps, plus the single-exit-point
scaffolding.
- New sentinel lib.ExitRequest{Code} (io.EOF-style control flow): returned by
code paths that have already printed what they wanted (--version, -h,
'put --explain' on a valid expression, 'put -x') instead of exiting mid-stack.
- pkg/entrypoint: new exitOnError() maps errors to exit codes in one place:
ErrHelpRequested -> 0, ErrUsagePrinted -> 1, ExitRequest -> its code,
anything else printed (JSON if --errors-json) -> 1.
- pkg/climain: version/help/usage/validation exits become returned errors;
the ErrHelpRequested/ErrUsagePrinted -> exit translation moves up to the
entrypoint; loadMlrrcOrDie becomes error-returning loadMlrrcFiles.
- Transformer ParseCLI/constructor exits -> returned errors (cut,
having_fields, nest, reorder, merge_fields, reshape, rename, split, tee,
subs, put_or_filter). merge_fields' bad-regex message formerly mis-reported
itself as coming from the cut verb; tee's unrecognized-option exit was
formerly silent; split/tee constructor failures formerly exited without
printing the constructor's error.
- YAML/JSON record-writer marshal errors -> returned through Write, matching
the CSV writer's error path.
- lib.WriteTempFileOrDie -> WriteTempFile (string, error); its sole caller
(regtest diff helper) degrades gracefully.
Stderr messages and exit codes are byte-identical for all regression-covered
paths (4779 cases pass); runtime Transform-path exits are phase 3.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Add lib.NewExitZeroRequest() constructor for exit-0 sentinel returns
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
707e3dbf06
commit
40ac1b309e
21 changed files with 171 additions and 171 deletions
24
pkg/lib/exit.go
Normal file
24
pkg/lib/exit.go
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
package lib
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ExitRequest is a sentinel error requesting process termination with the
|
||||
// given exit code. Code paths that have already produced all the output they
|
||||
// want (e.g. --version, or 'mlr put --explain' on a valid expression) return
|
||||
// an ExitRequest instead of calling os.Exit mid-stack; the entrypoint unwraps
|
||||
// it with errors.As and exits with the requested code. This is control flow
|
||||
// in the io.EOF style: an "error" that isn't a failure. See plans/exit.md.
|
||||
type ExitRequest struct {
|
||||
Code int
|
||||
}
|
||||
|
||||
func (e *ExitRequest) Error() string {
|
||||
return fmt.Sprintf("exit status %d", e.Code)
|
||||
}
|
||||
|
||||
// NewExitZeroRequest is for the common case of requesting a normal, exit-0
|
||||
// termination: e.g. --version or -h, where the requested output has been
|
||||
// printed and nothing further should run.
|
||||
func NewExitZeroRequest() *ExitRequest {
|
||||
return &ExitRequest{Code: 0}
|
||||
}
|
||||
|
|
@ -158,27 +158,24 @@ func GetArrayKeysSorted(input map[string]string) []string {
|
|||
|
||||
// WriteTempFile places the contents string into a temp file, which the caller
|
||||
// must remove.
|
||||
func WriteTempFileOrDie(contents string) string {
|
||||
func WriteTempFile(contents string) (string, error) {
|
||||
// Use "" as first argument to os.CreateTemp to use default directory.
|
||||
// Nominally "/tmp" or somesuch on all unix-like systems, but not for Windows.
|
||||
handle, err := os.CreateTemp("", "mlr-temp")
|
||||
if err != nil {
|
||||
fmt.Printf("mlr: could not create temp file.\n")
|
||||
os.Exit(1)
|
||||
return "", fmt.Errorf("could not create temp file: %w", err)
|
||||
}
|
||||
|
||||
_, err = handle.WriteString(contents)
|
||||
if err != nil {
|
||||
fmt.Printf("mlr: could not populate temp file.\n")
|
||||
os.Exit(1)
|
||||
return "", fmt.Errorf("could not populate temp file: %w", err)
|
||||
}
|
||||
|
||||
err = handle.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("mlr: could not finish write of temp file.\n")
|
||||
os.Exit(1)
|
||||
return "", fmt.Errorf("could not finish write of temp file: %w", err)
|
||||
}
|
||||
return handle.Name()
|
||||
return handle.Name(), nil
|
||||
}
|
||||
|
||||
func StripEmpties(input []string) []string {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue