From 6355d8d2d39ea02380988470c5069ce99342bb24 Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Fri, 7 Jul 2023 00:01:41 +0100 Subject: [PATCH] Move cli complexity into the library --- bkl.go | 60 +++++++++++++++++++++++++++++++++++++++++++------ cmd/bkl/main.go | 30 ++++++------------------- error.go | 3 ++- 3 files changed, 62 insertions(+), 31 deletions(-) diff --git a/bkl.go b/bkl.go index 70696c2..5f2103d 100644 --- a/bkl.go +++ b/bkl.go @@ -1,8 +1,8 @@ // Package bkl implements a layered configuration language parser. // -// - Language & tool documentation: https://bkl.gopatchy.io/ -// - Go library source: https://github.com/gopatchy/bkl -// - Go library documentation: https://pkg.go.dev/github.com/gopatchy/bkl +// - Language & tool documentation: https://bkl.gopatchy.io/ +// - Go library source: https://github.com/gopatchy/bkl +// - Go library documentation: https://pkg.go.dev/github.com/gopatchy/bkl package bkl import ( @@ -17,10 +17,10 @@ import ( // A Parser reads input documents, merges layers, and generates outputs. // // Terminology: -// - Each Parser can read multiple files -// - Each file represents a single layer -// - Each file contains one or more documents -// - Each document generates one or more outputs +// - Each Parser can read multiple files +// - Each file represents a single layer +// - Each file contains one or more documents +// - Each document generates one or more outputs type Parser struct { docs []any debug bool @@ -265,6 +265,52 @@ func (p *Parser) Output(ext string) ([]byte, error) { return bytes.Join(outs, []byte("---\n")), nil } +// OutputToFile encodes all documents in the specified format and writes them +// to the specified output path. +// +// If format is "", it is inferred from path's file extension. +func (p *Parser) OutputToFile(path, format string) error { + if format == "" { + format = Ext(path) + } + + fh, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) + if err != nil { + return fmt.Errorf("%s: %w (%w)", path, err, ErrOutputFile) + } + + defer fh.Close() + + err = p.OutputToWriter(fh, format) + if err != nil { + return fmt.Errorf("%s: %s", path, err) + } + + return nil +} + +// OutputToWriter encodes all documents in the specified format and writes them +// to the specified [io.Writer]. +// +// If format is "", it defaults to "json-pretty". +func (p *Parser) OutputToWriter(fh io.Writer, format string) error { + if format == "" { + format = "json-pretty" + } + + out, err := p.Output(format) + if err != nil { + return err + } + + _, err = fh.Write(out) + if err != nil { + return fmt.Errorf("%w (%w)", err, ErrOutputFile) + } + + return nil +} + func (p *Parser) log(format string, v ...any) { if !p.debug { return diff --git a/cmd/bkl/main.go b/cmd/bkl/main.go index 5971d9a..b62d90b 100644 --- a/cmd/bkl/main.go +++ b/cmd/bkl/main.go @@ -46,36 +46,20 @@ func main() { } } - format := "json-pretty" - - if opts.OutputPath != nil { - format = bkl.Ext(*opts.OutputPath) - } - + format := "" if opts.OutputFormat != nil { format = *opts.OutputFormat } - out, err := p.Output(format) + if opts.OutputPath == nil { + err = p.OutputToWriter(os.Stdout, format) + } else { + err = p.OutputToFile(*opts.OutputPath, format) + } + if err != nil { fatal("%s", err) } - - fh := os.Stdout - - if opts.OutputPath != nil { - fh, err = os.OpenFile(*opts.OutputPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) - if err != nil { - fatal("%s: %s", *opts.OutputPath, err) - } - - defer fh.Close() - } - - _, err = fh.Write(out) - if err != nil { - fatal("output: %s", err) - } } func fatal(format string, v ...any) { diff --git a/error.go b/error.go index 7ec285c..6f9fdbb 100644 --- a/error.go +++ b/error.go @@ -7,8 +7,9 @@ var ( Err = fmt.Errorf("bkl error") // Format and system errors - ErrEncode = fmt.Errorf("encoding error (%w)", Err) ErrDecode = fmt.Errorf("decoding error (%w)", Err) + ErrEncode = fmt.Errorf("encoding error (%w)", Err) + ErrOutputFile = fmt.Errorf("error opening output file (%w)", Err) ErrInvalidIndex = fmt.Errorf("invalid index (%w)", Err) ErrInvalidFilename = fmt.Errorf("invalid filename (%w)", Err) ErrInvalidType = fmt.Errorf("invalid type (%w)", Err)