podman

Форк
0
222 строки · 5.3 Кб
1
// Copyright © 2014 Steve Francia <spf@spf13.com>.
2
//
3
// Use of this source code is governed by an MIT-style
4
// license that can be found in the LICENSE file.
5

6
// Viper is a application configuration system.
7
// It believes that applications can be configured a variety of ways
8
// via flags, ENVIRONMENT variables, configuration files retrieved
9
// from the file system, or a remote key/value store.
10

11
package viper
12

13
import (
14
	"fmt"
15
	"os"
16
	"path/filepath"
17
	"runtime"
18
	"strings"
19
	"unicode"
20

21
	"github.com/spf13/cast"
22
)
23

24
// ConfigParseError denotes failing to parse configuration file.
25
type ConfigParseError struct {
26
	err error
27
}
28

29
// Error returns the formatted configuration error.
30
func (pe ConfigParseError) Error() string {
31
	return fmt.Sprintf("While parsing config: %s", pe.err.Error())
32
}
33

34
// Unwrap returns the wrapped error.
35
func (pe ConfigParseError) Unwrap() error {
36
	return pe.err
37
}
38

39
// toCaseInsensitiveValue checks if the value is a  map;
40
// if so, create a copy and lower-case the keys recursively.
41
func toCaseInsensitiveValue(value interface{}) interface{} {
42
	switch v := value.(type) {
43
	case map[interface{}]interface{}:
44
		value = copyAndInsensitiviseMap(cast.ToStringMap(v))
45
	case map[string]interface{}:
46
		value = copyAndInsensitiviseMap(v)
47
	}
48

49
	return value
50
}
51

52
// copyAndInsensitiviseMap behaves like insensitiviseMap, but creates a copy of
53
// any map it makes case insensitive.
54
func copyAndInsensitiviseMap(m map[string]interface{}) map[string]interface{} {
55
	nm := make(map[string]interface{})
56

57
	for key, val := range m {
58
		lkey := strings.ToLower(key)
59
		switch v := val.(type) {
60
		case map[interface{}]interface{}:
61
			nm[lkey] = copyAndInsensitiviseMap(cast.ToStringMap(v))
62
		case map[string]interface{}:
63
			nm[lkey] = copyAndInsensitiviseMap(v)
64
		default:
65
			nm[lkey] = v
66
		}
67
	}
68

69
	return nm
70
}
71

72
func insensitiviseVal(val interface{}) interface{} {
73
	switch val.(type) {
74
	case map[interface{}]interface{}:
75
		// nested map: cast and recursively insensitivise
76
		val = cast.ToStringMap(val)
77
		insensitiviseMap(val.(map[string]interface{}))
78
	case map[string]interface{}:
79
		// nested map: recursively insensitivise
80
		insensitiviseMap(val.(map[string]interface{}))
81
	case []interface{}:
82
		// nested array: recursively insensitivise
83
		insensitiveArray(val.([]interface{}))
84
	}
85
	return val
86
}
87

88
func insensitiviseMap(m map[string]interface{}) {
89
	for key, val := range m {
90
		val = insensitiviseVal(val)
91
		lower := strings.ToLower(key)
92
		if key != lower {
93
			// remove old key (not lower-cased)
94
			delete(m, key)
95
		}
96
		// update map
97
		m[lower] = val
98
	}
99
}
100

101
func insensitiveArray(a []interface{}) {
102
	for i, val := range a {
103
		a[i] = insensitiviseVal(val)
104
	}
105
}
106

107
func absPathify(logger Logger, inPath string) string {
108
	logger.Info("trying to resolve absolute path", "path", inPath)
109

110
	if inPath == "$HOME" || strings.HasPrefix(inPath, "$HOME"+string(os.PathSeparator)) {
111
		inPath = userHomeDir() + inPath[5:]
112
	}
113

114
	inPath = os.ExpandEnv(inPath)
115

116
	if filepath.IsAbs(inPath) {
117
		return filepath.Clean(inPath)
118
	}
119

120
	p, err := filepath.Abs(inPath)
121
	if err == nil {
122
		return filepath.Clean(p)
123
	}
124

125
	logger.Error(fmt.Errorf("could not discover absolute path: %w", err).Error())
126

127
	return ""
128
}
129

130
func stringInSlice(a string, list []string) bool {
131
	for _, b := range list {
132
		if b == a {
133
			return true
134
		}
135
	}
136
	return false
137
}
138

139
func userHomeDir() string {
140
	if runtime.GOOS == "windows" {
141
		home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
142
		if home == "" {
143
			home = os.Getenv("USERPROFILE")
144
		}
145
		return home
146
	}
147
	return os.Getenv("HOME")
148
}
149

150
func safeMul(a, b uint) uint {
151
	c := a * b
152
	if a > 1 && b > 1 && c/b != a {
153
		return 0
154
	}
155
	return c
156
}
157

158
// parseSizeInBytes converts strings like 1GB or 12 mb into an unsigned integer number of bytes
159
func parseSizeInBytes(sizeStr string) uint {
160
	sizeStr = strings.TrimSpace(sizeStr)
161
	lastChar := len(sizeStr) - 1
162
	multiplier := uint(1)
163

164
	if lastChar > 0 {
165
		if sizeStr[lastChar] == 'b' || sizeStr[lastChar] == 'B' {
166
			if lastChar > 1 {
167
				switch unicode.ToLower(rune(sizeStr[lastChar-1])) {
168
				case 'k':
169
					multiplier = 1 << 10
170
					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
171
				case 'm':
172
					multiplier = 1 << 20
173
					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
174
				case 'g':
175
					multiplier = 1 << 30
176
					sizeStr = strings.TrimSpace(sizeStr[:lastChar-1])
177
				default:
178
					multiplier = 1
179
					sizeStr = strings.TrimSpace(sizeStr[:lastChar])
180
				}
181
			}
182
		}
183
	}
184

185
	size := cast.ToInt(sizeStr)
186
	if size < 0 {
187
		size = 0
188
	}
189

190
	return safeMul(uint(size), multiplier)
191
}
192

193
// deepSearch scans deep maps, following the key indexes listed in the
194
// sequence "path".
195
// The last value is expected to be another map, and is returned.
196
//
197
// In case intermediate keys do not exist, or map to a non-map value,
198
// a new map is created and inserted, and the search continues from there:
199
// the initial map "m" may be modified!
200
func deepSearch(m map[string]interface{}, path []string) map[string]interface{} {
201
	for _, k := range path {
202
		m2, ok := m[k]
203
		if !ok {
204
			// intermediate key does not exist
205
			// => create it and continue from there
206
			m3 := make(map[string]interface{})
207
			m[k] = m3
208
			m = m3
209
			continue
210
		}
211
		m3, ok := m2.(map[string]interface{})
212
		if !ok {
213
			// intermediate key is a value
214
			// => replace with a new map
215
			m3 = make(map[string]interface{})
216
			m[k] = m3
217
		}
218
		// continue search from here
219
		m = m3
220
	}
221
	return m
222
}
223

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.