1package repository
2
3import (
4 "errors"
5 "fmt"
6 "strconv"
7 "time"
8)
9
10var (
11 ErrNoConfigEntry = errors.New("no config entry for the given key")
12 ErrMultipleConfigEntry = errors.New("multiple config entry for the given key")
13)
14
15func newErrNoConfigEntry(key string) error {
16 return fmt.Errorf("%w: missing key %s", ErrNoConfigEntry, key)
17}
18
19func newErrMultipleConfigEntry(key string) error {
20 return fmt.Errorf("%w: duplicated key %s", ErrMultipleConfigEntry, key)
21}
22
23// Config represent the common function interacting with the repository config storage
24type Config interface {
25 ConfigRead
26 ConfigWrite
27}
28
29type ConfigRead interface {
30 // ReadAll reads all key/value pair matching the key prefix
31 ReadAll(keyPrefix string) (map[string]string, error)
32
33 // ReadBool read a single boolean value from the config
34 // Return ErrNoConfigEntry or ErrMultipleConfigEntry if
35 // there is zero or more than one entry for this key
36 ReadBool(key string) (bool, error)
37
38 // ReadString read a single string value from the config
39 // Return ErrNoConfigEntry or ErrMultipleConfigEntry if
40 // there is zero or more than one entry for this key
41 ReadString(key string) (string, error)
42
43 // ReadTimestamp read a single timestamp value from the config
44 // Return ErrNoConfigEntry or ErrMultipleConfigEntry if
45 // there is zero or more than one entry for this key
46 ReadTimestamp(key string) (time.Time, error)
47}
48
49type ConfigWrite interface {
50 // StoreString writes a single string key/value pair in the config
51 StoreString(key, value string) error
52
53 // StoreTimestamp writes a key and timestamp value to the config
54 StoreTimestamp(key string, value time.Time) error
55
56 // StoreBool writes a key and boolean value to the config
57 StoreBool(key string, value bool) error
58
59 // RemoveAll removes all key/value pair matching the key prefix
60 RemoveAll(keyPrefix string) error
61}
62
63func GetDefaultString(key string, cfg ConfigRead, def string) (string, error) {
64 val, err := cfg.ReadString(key)
65 if err == nil {
66 return val, nil
67 } else if errors.Is(err, ErrNoConfigEntry) {
68 return def, nil
69 } else {
70 return "", err
71 }
72}
73
74func ParseTimestamp(s string) (time.Time, error) {
75 timestamp, err := strconv.Atoi(s)
76 if err != nil {
77 return time.Time{}, err
78 }
79
80 return time.Unix(int64(timestamp), 0), nil
81}
82
83// mergeConfig is a helper to easily support RepoConfig.AnyConfig()
84// from two separate local and global Config
85func mergeConfig(local ConfigRead, global ConfigRead) *mergedConfig {
86 return &mergedConfig{
87 local: local,
88 global: global,
89 }
90}
91
92var _ ConfigRead = &mergedConfig{}
93
94type mergedConfig struct {
95 local ConfigRead
96 global ConfigRead
97}
98
99func (m *mergedConfig) ReadAll(keyPrefix string) (map[string]string, error) {
100 values, err := m.global.ReadAll(keyPrefix)
101 if err != nil {
102 return nil, err
103 }
104 locals, err := m.local.ReadAll(keyPrefix)
105 if err != nil {
106 return nil, err
107 }
108 for k, val := range locals {
109 values[k] = val
110 }
111 return values, nil
112}
113
114func (m *mergedConfig) ReadBool(key string) (bool, error) {
115 v, err := m.local.ReadBool(key)
116 if err == nil {
117 return v, nil
118 }
119 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
120 return false, err
121 }
122 return m.global.ReadBool(key)
123}
124
125func (m *mergedConfig) ReadString(key string) (string, error) {
126 val, err := m.local.ReadString(key)
127 if err == nil {
128 return val, nil
129 }
130 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
131 return "", err
132 }
133 return m.global.ReadString(key)
134}
135
136func (m *mergedConfig) ReadTimestamp(key string) (time.Time, error) {
137 val, err := m.local.ReadTimestamp(key)
138 if err == nil {
139 return val, nil
140 }
141 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
142 return time.Time{}, err
143 }
144 return m.global.ReadTimestamp(key)
145}
146
147var _ ConfigWrite = &configPanicWriter{}
148
149type configPanicWriter struct{}
150
151func (c configPanicWriter) StoreString(key, value string) error {
152 panic("not implemented")
153}
154
155func (c configPanicWriter) StoreTimestamp(key string, value time.Time) error {
156 panic("not implemented")
157}
158
159func (c configPanicWriter) StoreBool(key string, value bool) error {
160 panic("not implemented")
161}
162
163func (c configPanicWriter) RemoveAll(keyPrefix string) error {
164 panic("not implemented")
165}