aboutsummaryrefslogtreecommitdiffstats
path: root/repository/config.go
blob: 7e1ee6e85ec6e45dfa224e7df7e751f5cfc8af23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package repository

import (
	"errors"
	"fmt"
	"strconv"
	"time"
)

var (
	ErrNoConfigEntry       = errors.New("no config entry for the given key")
	ErrMultipleConfigEntry = errors.New("multiple config entry for the given key")
)

func newErrNoConfigEntry(key string) error {
	return fmt.Errorf("%w: missing key %s", ErrNoConfigEntry, key)
}

func newErrMultipleConfigEntry(key string) error {
	return fmt.Errorf("%w: duplicated key %s", ErrMultipleConfigEntry, key)
}

// Config represent the common function interacting with the repository config storage
type Config interface {
	ConfigRead
	ConfigWrite
}

type ConfigRead interface {
	// ReadAll reads all key/value pair matching the key prefix
	ReadAll(keyPrefix string) (map[string]string, error)

	// ReadBool read a single boolean value from the config
	// Return ErrNoConfigEntry or ErrMultipleConfigEntry if
	// there is zero or more than one entry for this key
	ReadBool(key string) (bool, error)

	// ReadString read a single string value from the config
	// Return ErrNoConfigEntry or ErrMultipleConfigEntry if
	// there is zero or more than one entry for this key
	ReadString(key string) (string, error)

	// ReadTimestamp read a single timestamp value from the config
	// Return ErrNoConfigEntry or ErrMultipleConfigEntry if
	// there is zero or more than one entry for this key
	ReadTimestamp(key string) (time.Time, error)
}

type ConfigWrite interface {
	// StoreString writes a single string key/value pair in the config
	StoreString(key, value string) error

	// StoreTimestamp writes a key and timestamp value to the config
	StoreTimestamp(key string, value time.Time) error

	// StoreBool writes a key and boolean value to the config
	StoreBool(key string, value bool) error

	// RemoveAll removes all key/value pair matching the key prefix
	RemoveAll(keyPrefix string) error
}

func ParseTimestamp(s string) (time.Time, error) {
	timestamp, err := strconv.Atoi(s)
	if err != nil {
		return time.Time{}, err
	}

	return time.Unix(int64(timestamp), 0), nil
}

// mergeConfig is a helper to easily support RepoConfig.AnyConfig()
// from two separate local and global Config
func mergeConfig(local ConfigRead, global ConfigRead) *mergedConfig {
	return &mergedConfig{
		local:  local,
		global: global,
	}
}

var _ ConfigRead = &mergedConfig{}

type mergedConfig struct {
	local  ConfigRead
	global ConfigRead
}

func (m *mergedConfig) ReadAll(keyPrefix string) (map[string]string, error) {
	values, err := m.global.ReadAll(keyPrefix)
	if err != nil {
		return nil, err
	}
	locals, err := m.local.ReadAll(keyPrefix)
	if err != nil {
		return nil, err
	}
	for k, val := range locals {
		values[k] = val
	}
	return values, nil
}

func (m *mergedConfig) ReadBool(key string) (bool, error) {
	v, err := m.local.ReadBool(key)
	if err == nil {
		return v, nil
	}
	if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
		return false, err
	}
	return m.global.ReadBool(key)
}

func (m *mergedConfig) ReadString(key string) (string, error) {
	val, err := m.local.ReadString(key)
	if err == nil {
		return val, nil
	}
	if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
		return "", err
	}
	return m.global.ReadString(key)
}

func (m *mergedConfig) ReadTimestamp(key string) (time.Time, error) {
	val, err := m.local.ReadTimestamp(key)
	if err == nil {
		return val, nil
	}
	if !errors.Is(err, ErrNoConfigEntry) && !errors.Is(err, ErrMultipleConfigEntry) {
		return time.Time{}, err
	}
	return m.global.ReadTimestamp(key)
}

var _ ConfigWrite = &configPanicWriter{}

type configPanicWriter struct{}

func (c configPanicWriter) StoreString(key, value string) error {
	panic("not implemented")
}

func (c configPanicWriter) StoreTimestamp(key string, value time.Time) error {
	panic("not implemented")
}

func (c configPanicWriter) StoreBool(key string, value bool) error {
	panic("not implemented")
}

func (c configPanicWriter) RemoveAll(keyPrefix string) error {
	panic("not implemented")
}