/
cfg.go
99 lines (79 loc) · 1.89 KB
/
cfg.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Package cfg implements the baur configuration file parser.
package cfg
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
"github.com/pelletier/go-toml"
)
type toFileOpts struct {
overwrite bool
commented bool
}
// toFileOpt is an option that can be passed to the ToFile functions
type toFileOpt func(*toFileOpts)
// ToFileOptOverwrite overwrite an existing file instead of returning an error
func ToFileOptOverwrite() toFileOpt { // nolint: revive // returns unexported type
return func(o *toFileOpts) {
o.overwrite = true
}
}
// ToFileOptCommented comment every line in the config
func ToFileOptCommented() toFileOpt { // nolint: revive // returns unexported type
return func(o *toFileOpts) {
o.commented = true
}
}
// toFile marshals a struct to TOML format and writes it to a file.
func toFile(data interface{}, filepath string, opts ...toFileOpt) error {
var buf bytes.Buffer
var settings toFileOpts
for _, opt := range opts {
opt(&settings)
}
encoder := toml.NewEncoder(&buf)
encoder.ArraysWithOneElementPerLine(true)
encoder.Order(toml.OrderPreserve)
err := encoder.Encode(data)
if err != nil {
return err
}
f, err := os.OpenFile(filepath, fileOpenFlags(settings.overwrite), 0640)
if err != nil {
return err
}
if settings.commented {
if err := writeCommented(f, &buf); err != nil {
f.Close()
return err
}
} else {
if _, err := io.Copy(f, &buf); err != nil {
f.Close()
return err
}
}
err = f.Close()
if err != nil {
return fmt.Errorf("closing file failed: %w", err)
}
return err
}
func fileOpenFlags(overwrite bool) int {
if overwrite {
return os.O_WRONLY | os.O_CREATE | os.O_TRUNC
}
return os.O_WRONLY | os.O_CREATE | os.O_EXCL
}
func writeCommented(out io.Writer, in io.Reader) error {
s := bufio.NewScanner(in)
for s.Scan() {
line := s.Text()
if _, err := fmt.Fprintf(out, "# %s\n", line); err != nil {
return err
}
}
return s.Err()
}