1package repository
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7 "time"
8
9 gogit "github.com/go-git/go-git/v5"
10)
11
12var _ Config = &goGitConfig{}
13
14type goGitConfig struct {
15 repo *gogit.Repository
16}
17
18func newGoGitConfig(repo *gogit.Repository) *goGitConfig {
19 return &goGitConfig{repo: repo}
20}
21
22func (ggc *goGitConfig) StoreString(key, value string) error {
23 cfg, err := ggc.repo.Config()
24 if err != nil {
25 return err
26 }
27
28 split := strings.Split(key, ".")
29
30 switch {
31 case len(split) <= 1:
32 return fmt.Errorf("invalid key")
33 case len(split) == 2:
34 cfg.Raw.Section(split[0]).SetOption(split[1], value)
35 default:
36 section := split[0]
37 subsection := strings.Join(split[1:len(split)-1], ".")
38 option := split[len(split)-1]
39 cfg.Raw.Section(section).Subsection(subsection).SetOption(option, value)
40 }
41
42 return ggc.repo.SetConfig(cfg)
43}
44
45func (ggc *goGitConfig) StoreTimestamp(key string, value time.Time) error {
46 return ggc.StoreString(key, strconv.Itoa(int(value.Unix())))
47}
48
49func (ggc *goGitConfig) StoreBool(key string, value bool) error {
50 return ggc.StoreString(key, strconv.FormatBool(value))
51}
52
53func (ggc *goGitConfig) ReadAll(keyPrefix string) (map[string]string, error) {
54 cfg, err := ggc.repo.Config()
55 if err != nil {
56 return nil, err
57 }
58
59 split := strings.Split(keyPrefix, ".")
60 result := make(map[string]string)
61
62 switch {
63 case keyPrefix == "":
64 for _, section := range cfg.Raw.Sections {
65 for _, option := range section.Options {
66 result[fmt.Sprintf("%s.%s", section.Name, option.Key)] = option.Value
67 }
68 for _, subsection := range section.Subsections {
69 for _, option := range subsection.Options {
70 result[fmt.Sprintf("%s.%s.%s", section.Name, subsection.Name, option.Key)] = option.Value
71 }
72 }
73 }
74 case len(split) == 1:
75 if !cfg.Raw.HasSection(split[0]) {
76 return nil, fmt.Errorf("invalid section")
77 }
78 section := cfg.Raw.Section(split[0])
79 for _, option := range section.Options {
80 result[fmt.Sprintf("%s.%s", section.Name, option.Key)] = option.Value
81 }
82 for _, subsection := range section.Subsections {
83 for _, option := range subsection.Options {
84 result[fmt.Sprintf("%s.%s.%s", section.Name, subsection.Name, option.Key)] = option.Value
85 }
86 }
87 default:
88 if !cfg.Raw.HasSection(split[0]) {
89 return nil, fmt.Errorf("invalid section")
90 }
91 section := cfg.Raw.Section(split[0])
92 rest := strings.Join(split[1:], ".")
93 for _, subsection := range section.Subsections {
94 if strings.HasPrefix(subsection.Name, rest) {
95 for _, option := range subsection.Options {
96 result[fmt.Sprintf("%s.%s.%s", section.Name, subsection.Name, option.Key)] = option.Value
97 }
98 }
99 }
100 }
101
102 if len(result) == 0 {
103 return nil, fmt.Errorf("invalid section")
104 }
105
106 return result, nil
107}
108
109func (ggc *goGitConfig) ReadBool(key string) (bool, error) {
110 val, err := ggc.ReadString(key)
111 if err != nil {
112 return false, err
113 }
114
115 return strconv.ParseBool(val)
116}
117
118func (ggc *goGitConfig) ReadString(key string) (string, error) {
119 cfg, err := ggc.repo.Config()
120 if err != nil {
121 return "", err
122 }
123
124 split := strings.Split(key, ".")
125
126 if len(split) <= 1 {
127 return "", fmt.Errorf("invalid key")
128 }
129
130 sectionName := split[0]
131 if !cfg.Raw.HasSection(sectionName) {
132 return "", ErrNoConfigEntry
133 }
134 section := cfg.Raw.Section(sectionName)
135
136 switch {
137 case len(split) == 2:
138 optionName := split[1]
139 if !section.HasOption(optionName) {
140 return "", ErrNoConfigEntry
141 }
142 if len(section.OptionAll(optionName)) > 1 {
143 return "", ErrMultipleConfigEntry
144 }
145 return section.Option(optionName), nil
146 default:
147 subsectionName := strings.Join(split[1:len(split)-2], ".")
148 optionName := split[len(split)-1]
149 if !section.HasSubsection(subsectionName) {
150 return "", ErrNoConfigEntry
151 }
152 subsection := section.Subsection(subsectionName)
153 if !subsection.HasOption(optionName) {
154 return "", ErrNoConfigEntry
155 }
156 if len(subsection.OptionAll(optionName)) > 1 {
157 return "", ErrMultipleConfigEntry
158 }
159 return subsection.Option(optionName), nil
160 }
161}
162
163func (ggc *goGitConfig) ReadTimestamp(key string) (time.Time, error) {
164 value, err := ggc.ReadString(key)
165 if err != nil {
166 return time.Time{}, err
167 }
168 return ParseTimestamp(value)
169}
170
171func (ggc *goGitConfig) RemoveAll(keyPrefix string) error {
172 cfg, err := ggc.repo.Config()
173 if err != nil {
174 return err
175 }
176
177 split := strings.Split(keyPrefix, ".")
178
179 switch {
180 case keyPrefix == "":
181 cfg.Raw.Sections = nil
182 // warning: this does not actually remove everything as go-git config hold
183 // some entries in multiple places (cfg.User ...)
184 case len(split) == 1:
185 if cfg.Raw.HasSection(split[0]) {
186 cfg.Raw.RemoveSection(split[0])
187 } else {
188 return fmt.Errorf("invalid key prefix")
189 }
190 default:
191 if !cfg.Raw.HasSection(split[0]) {
192 return fmt.Errorf("invalid key prefix")
193 }
194 section := cfg.Raw.Section(split[0])
195 rest := strings.Join(split[1:], ".")
196
197 ok := false
198 if section.HasSubsection(rest) {
199 section.RemoveSubsection(rest)
200 ok = true
201 }
202 if section.HasOption(rest) {
203 section.RemoveOption(rest)
204 ok = true
205 }
206 if !ok {
207 return fmt.Errorf("invalid key prefix")
208 }
209 }
210
211 return ggc.repo.SetConfig(cfg)
212}