88a8aecdd4
For example when failing to decode toml, display the context around the error and the location of the problem.
89 lines
1.7 KiB
Go
89 lines
1.7 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"flag"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
|
|
"github.com/pelletier/go-toml/v2"
|
|
)
|
|
|
|
type ConvertFn func(r io.Reader, w io.Writer) error
|
|
|
|
type Program struct {
|
|
Usage string
|
|
Fn ConvertFn
|
|
// Inplace allows the command to take more than one file as argument and
|
|
// perform convertion in place on each provided file.
|
|
Inplace bool
|
|
}
|
|
|
|
func (p *Program) Execute() {
|
|
flag.Usage = func() { fmt.Fprintf(os.Stderr, p.Usage) }
|
|
flag.Parse()
|
|
os.Exit(p.main(flag.Args(), os.Stdin, os.Stdout, os.Stderr))
|
|
}
|
|
|
|
func (p *Program) main(files []string, input io.Reader, output, error io.Writer) int {
|
|
err := p.run(files, input, output)
|
|
if err != nil {
|
|
|
|
var derr *toml.DecodeError
|
|
if errors.As(err, &derr) {
|
|
fmt.Fprintln(error, derr.String())
|
|
row, col := derr.Position()
|
|
fmt.Fprintln(error, "error occurred at row", row, "column", col)
|
|
} else {
|
|
fmt.Fprintln(error, err.Error())
|
|
}
|
|
|
|
return -1
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func (p *Program) run(files []string, input io.Reader, output io.Writer) error {
|
|
if len(files) > 0 {
|
|
if p.Inplace {
|
|
return p.runAllFilesInPlace(files)
|
|
}
|
|
f, err := os.Open(files[0])
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
input = f
|
|
}
|
|
return p.Fn(input, output)
|
|
}
|
|
|
|
func (p *Program) runAllFilesInPlace(files []string) error {
|
|
for _, path := range files {
|
|
err := p.runFileInPlace(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *Program) runFileInPlace(path string) error {
|
|
in, err := ioutil.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
out := new(bytes.Buffer)
|
|
|
|
err = p.Fn(bytes.NewReader(in), out)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return ioutil.WriteFile(path, out.Bytes(), 0600)
|
|
}
|