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