...
1 package cli
2
3 import (
4 "bytes"
5 "errors"
6 "flag"
7 "fmt"
8 "io"
9 "io/ioutil"
10 "os"
11
12 "github.com/pelletier/go-toml/v2"
13 )
14
15 type ConvertFn func(r io.Reader, w io.Writer) error
16
17 type Program struct {
18 Usage string
19 Fn ConvertFn
20
21
22 Inplace bool
23 }
24
25 func (p *Program) Execute() {
26 flag.Usage = func() { fmt.Fprintf(os.Stderr, p.Usage) }
27 flag.Parse()
28 os.Exit(p.main(flag.Args(), os.Stdin, os.Stdout, os.Stderr))
29 }
30
31 func (p *Program) main(files []string, input io.Reader, output, error io.Writer) int {
32 err := p.run(files, input, output)
33 if err != nil {
34
35 var derr *toml.DecodeError
36 if errors.As(err, &derr) {
37 fmt.Fprintln(error, derr.String())
38 row, col := derr.Position()
39 fmt.Fprintln(error, "error occurred at row", row, "column", col)
40 } else {
41 fmt.Fprintln(error, err.Error())
42 }
43
44 return -1
45 }
46 return 0
47 }
48
49 func (p *Program) run(files []string, input io.Reader, output io.Writer) error {
50 if len(files) > 0 {
51 if p.Inplace {
52 return p.runAllFilesInPlace(files)
53 }
54 f, err := os.Open(files[0])
55 if err != nil {
56 return err
57 }
58 defer f.Close()
59 input = f
60 }
61 return p.Fn(input, output)
62 }
63
64 func (p *Program) runAllFilesInPlace(files []string) error {
65 for _, path := range files {
66 err := p.runFileInPlace(path)
67 if err != nil {
68 return err
69 }
70 }
71 return nil
72 }
73
74 func (p *Program) runFileInPlace(path string) error {
75 in, err := ioutil.ReadFile(path)
76 if err != nil {
77 return err
78 }
79
80 out := new(bytes.Buffer)
81
82 err = p.Fn(bytes.NewReader(in), out)
83 if err != nil {
84 return err
85 }
86
87 return ioutil.WriteFile(path, out.Bytes(), 0600)
88 }
89
View as plain text