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 ParseTimestamp(s string) (time.Time, error) {
64 timestamp, err := strconv.Atoi(s)
65 if err != nil {
66 return time.Time{}, err
67 }
68
69 return time.Unix(int64(timestamp), 0), nil
70}
71
72// mergeConfig is a helper to easily support RepoConfig.AnyConfig()
73// from two separate local and global Config
74func mergeConfig(local ConfigRead, global ConfigRead) *mergedConfig {
75 return &mergedConfig{
76 local: local,
77 global: global,
78 }
79}
80
81var _ ConfigRead = &mergedConfig{}
82
83type mergedConfig struct {
84 local ConfigRead
85 global ConfigRead
86}
87
88func (m *mergedConfig) ReadAll(keyPrefix string) (map[string]string, error) {
89 values, err := m.global.ReadAll(keyPrefix)
90 if err != nil {
91 return nil, err
92 }
93 locals, err := m.local.ReadAll(keyPrefix)
94 if err != nil {
95 return nil, err
96 }
97 for k, val := range locals {
98 values[k] = val
99 }
100 return values, nil
101}
102
103func (m *mergedConfig) ReadBool(key string) (bool, error) {
104 v, err := m.local.ReadBool(key)
105 if err == nil {
106 return v, nil
107 }
108 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
109 return false, err
110 }
111 return m.global.ReadBool(key)
112}
113
114func (m *mergedConfig) ReadString(key string) (string, error) {
115 val, err := m.local.ReadString(key)
116 if err == nil {
117 return val, nil
118 }
119 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
120 return "", err
121 }
122 return m.global.ReadString(key)
123}
124
125func (m *mergedConfig) ReadTimestamp(key string) (time.Time, error) {
126 val, err := m.local.ReadTimestamp(key)
127 if err == nil {
128 return val, nil
129 }
130 if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
131 return time.Time{}, err
132 }
133 return m.global.ReadTimestamp(key)
134}
135
136var _ ConfigWrite = &configPanicWriter{}
137
138type configPanicWriter struct{}
139
140func (c configPanicWriter) StoreString(key, value string) error {
141 panic("not implemented")
142}
143
144func (c configPanicWriter) StoreTimestamp(key string, value time.Time) error {
145 panic("not implemented")
146}
147
148func (c configPanicWriter) StoreBool(key string, value bool) error {
149 panic("not implemented")
150}
151
152func (c configPanicWriter) RemoveAll(keyPrefix string) error {
153 panic("not implemented")
154}