config.go

  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}