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}