podman

Форк
0
293 строки · 9.2 Кб
1
// Copyright 2013-2022 Frank Schroeder. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
package properties
6

7
import (
8
	"fmt"
9
	"io/ioutil"
10
	"net/http"
11
	"os"
12
	"strings"
13
)
14

15
// Encoding specifies encoding of the input data.
16
type Encoding uint
17

18
const (
19
	// utf8Default is a private placeholder for the zero value of Encoding to
20
	// ensure that it has the correct meaning. UTF8 is the default encoding but
21
	// was assigned a non-zero value which cannot be changed without breaking
22
	// existing code. Clients should continue to use the public constants.
23
	utf8Default Encoding = iota
24

25
	// UTF8 interprets the input data as UTF-8.
26
	UTF8
27

28
	// ISO_8859_1 interprets the input data as ISO-8859-1.
29
	ISO_8859_1
30
)
31

32
type Loader struct {
33
	// Encoding determines how the data from files and byte buffers
34
	// is interpreted. For URLs the Content-Type header is used
35
	// to determine the encoding of the data.
36
	Encoding Encoding
37

38
	// DisableExpansion configures the property expansion of the
39
	// returned property object. When set to true, the property values
40
	// will not be expanded and the Property object will not be checked
41
	// for invalid expansion expressions.
42
	DisableExpansion bool
43

44
	// IgnoreMissing configures whether missing files or URLs which return
45
	// 404 are reported as errors. When set to true, missing files and 404
46
	// status codes are not reported as errors.
47
	IgnoreMissing bool
48
}
49

50
// Load reads a buffer into a Properties struct.
51
func (l *Loader) LoadBytes(buf []byte) (*Properties, error) {
52
	return l.loadBytes(buf, l.Encoding)
53
}
54

55
// LoadAll reads the content of multiple URLs or files in the given order into
56
// a Properties struct. If IgnoreMissing is true then a 404 status code or
57
// missing file will not be reported as error. Encoding sets the encoding for
58
// files. For the URLs see LoadURL for the Content-Type header and the
59
// encoding.
60
func (l *Loader) LoadAll(names []string) (*Properties, error) {
61
	all := NewProperties()
62
	for _, name := range names {
63
		n, err := expandName(name)
64
		if err != nil {
65
			return nil, err
66
		}
67

68
		var p *Properties
69
		switch {
70
		case strings.HasPrefix(n, "http://"):
71
			p, err = l.LoadURL(n)
72
		case strings.HasPrefix(n, "https://"):
73
			p, err = l.LoadURL(n)
74
		default:
75
			p, err = l.LoadFile(n)
76
		}
77
		if err != nil {
78
			return nil, err
79
		}
80
		all.Merge(p)
81
	}
82

83
	all.DisableExpansion = l.DisableExpansion
84
	if all.DisableExpansion {
85
		return all, nil
86
	}
87
	return all, all.check()
88
}
89

90
// LoadFile reads a file into a Properties struct.
91
// If IgnoreMissing is true then a missing file will not be
92
// reported as error.
93
func (l *Loader) LoadFile(filename string) (*Properties, error) {
94
	data, err := ioutil.ReadFile(filename)
95
	if err != nil {
96
		if l.IgnoreMissing && os.IsNotExist(err) {
97
			LogPrintf("properties: %s not found. skipping", filename)
98
			return NewProperties(), nil
99
		}
100
		return nil, err
101
	}
102
	return l.loadBytes(data, l.Encoding)
103
}
104

105
// LoadURL reads the content of the URL into a Properties struct.
106
//
107
// The encoding is determined via the Content-Type header which
108
// should be set to 'text/plain'. If the 'charset' parameter is
109
// missing, 'iso-8859-1' or 'latin1' the encoding is set to
110
// ISO-8859-1. If the 'charset' parameter is set to 'utf-8' the
111
// encoding is set to UTF-8. A missing content type header is
112
// interpreted as 'text/plain; charset=utf-8'.
113
func (l *Loader) LoadURL(url string) (*Properties, error) {
114
	resp, err := http.Get(url)
115
	if err != nil {
116
		return nil, fmt.Errorf("properties: error fetching %q. %s", url, err)
117
	}
118
	defer resp.Body.Close()
119

120
	if resp.StatusCode == 404 && l.IgnoreMissing {
121
		LogPrintf("properties: %s returned %d. skipping", url, resp.StatusCode)
122
		return NewProperties(), nil
123
	}
124

125
	if resp.StatusCode != 200 {
126
		return nil, fmt.Errorf("properties: %s returned %d", url, resp.StatusCode)
127
	}
128

129
	body, err := ioutil.ReadAll(resp.Body)
130
	if err != nil {
131
		return nil, fmt.Errorf("properties: %s error reading response. %s", url, err)
132
	}
133

134
	ct := resp.Header.Get("Content-Type")
135
	ct = strings.Join(strings.Fields(ct), "")
136
	var enc Encoding
137
	switch strings.ToLower(ct) {
138
	case "text/plain", "text/plain;charset=iso-8859-1", "text/plain;charset=latin1":
139
		enc = ISO_8859_1
140
	case "", "text/plain;charset=utf-8":
141
		enc = UTF8
142
	default:
143
		return nil, fmt.Errorf("properties: invalid content type %s", ct)
144
	}
145

146
	return l.loadBytes(body, enc)
147
}
148

149
func (l *Loader) loadBytes(buf []byte, enc Encoding) (*Properties, error) {
150
	p, err := parse(convert(buf, enc))
151
	if err != nil {
152
		return nil, err
153
	}
154
	p.DisableExpansion = l.DisableExpansion
155
	if p.DisableExpansion {
156
		return p, nil
157
	}
158
	return p, p.check()
159
}
160

161
// Load reads a buffer into a Properties struct.
162
func Load(buf []byte, enc Encoding) (*Properties, error) {
163
	l := &Loader{Encoding: enc}
164
	return l.LoadBytes(buf)
165
}
166

167
// LoadString reads an UTF8 string into a properties struct.
168
func LoadString(s string) (*Properties, error) {
169
	l := &Loader{Encoding: UTF8}
170
	return l.LoadBytes([]byte(s))
171
}
172

173
// LoadMap creates a new Properties struct from a string map.
174
func LoadMap(m map[string]string) *Properties {
175
	p := NewProperties()
176
	for k, v := range m {
177
		p.Set(k, v)
178
	}
179
	return p
180
}
181

182
// LoadFile reads a file into a Properties struct.
183
func LoadFile(filename string, enc Encoding) (*Properties, error) {
184
	l := &Loader{Encoding: enc}
185
	return l.LoadAll([]string{filename})
186
}
187

188
// LoadFiles reads multiple files in the given order into
189
// a Properties struct. If 'ignoreMissing' is true then
190
// non-existent files will not be reported as error.
191
func LoadFiles(filenames []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
192
	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing}
193
	return l.LoadAll(filenames)
194
}
195

196
// LoadURL reads the content of the URL into a Properties struct.
197
// See Loader#LoadURL for details.
198
func LoadURL(url string) (*Properties, error) {
199
	l := &Loader{Encoding: UTF8}
200
	return l.LoadAll([]string{url})
201
}
202

203
// LoadURLs reads the content of multiple URLs in the given order into a
204
// Properties struct. If IgnoreMissing is true then a 404 status code will
205
// not be reported as error. See Loader#LoadURL for the Content-Type header
206
// and the encoding.
207
func LoadURLs(urls []string, ignoreMissing bool) (*Properties, error) {
208
	l := &Loader{Encoding: UTF8, IgnoreMissing: ignoreMissing}
209
	return l.LoadAll(urls)
210
}
211

212
// LoadAll reads the content of multiple URLs or files in the given order into a
213
// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
214
// not be reported as error. Encoding sets the encoding for files. For the URLs please see
215
// LoadURL for the Content-Type header and the encoding.
216
func LoadAll(names []string, enc Encoding, ignoreMissing bool) (*Properties, error) {
217
	l := &Loader{Encoding: enc, IgnoreMissing: ignoreMissing}
218
	return l.LoadAll(names)
219
}
220

221
// MustLoadString reads an UTF8 string into a Properties struct and
222
// panics on error.
223
func MustLoadString(s string) *Properties {
224
	return must(LoadString(s))
225
}
226

227
// MustLoadFile reads a file into a Properties struct and
228
// panics on error.
229
func MustLoadFile(filename string, enc Encoding) *Properties {
230
	return must(LoadFile(filename, enc))
231
}
232

233
// MustLoadFiles reads multiple files in the given order into
234
// a Properties struct and panics on error. If 'ignoreMissing'
235
// is true then non-existent files will not be reported as error.
236
func MustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties {
237
	return must(LoadFiles(filenames, enc, ignoreMissing))
238
}
239

240
// MustLoadURL reads the content of a URL into a Properties struct and
241
// panics on error.
242
func MustLoadURL(url string) *Properties {
243
	return must(LoadURL(url))
244
}
245

246
// MustLoadURLs reads the content of multiple URLs in the given order into a
247
// Properties struct and panics on error. If 'ignoreMissing' is true then a 404
248
// status code will not be reported as error.
249
func MustLoadURLs(urls []string, ignoreMissing bool) *Properties {
250
	return must(LoadURLs(urls, ignoreMissing))
251
}
252

253
// MustLoadAll reads the content of multiple URLs or files in the given order into a
254
// Properties struct. If 'ignoreMissing' is true then a 404 status code or missing file will
255
// not be reported as error. Encoding sets the encoding for files. For the URLs please see
256
// LoadURL for the Content-Type header and the encoding. It panics on error.
257
func MustLoadAll(names []string, enc Encoding, ignoreMissing bool) *Properties {
258
	return must(LoadAll(names, enc, ignoreMissing))
259
}
260

261
func must(p *Properties, err error) *Properties {
262
	if err != nil {
263
		ErrorHandler(err)
264
	}
265
	return p
266
}
267

268
// expandName expands ${ENV_VAR} expressions in a name.
269
// If the environment variable does not exist then it will be replaced
270
// with an empty string. Malformed expressions like "${ENV_VAR" will
271
// be reported as error.
272
func expandName(name string) (string, error) {
273
	return expand(name, []string{}, "${", "}", make(map[string]string))
274
}
275

276
// Interprets a byte buffer either as an ISO-8859-1 or UTF-8 encoded string.
277
// For ISO-8859-1 we can convert each byte straight into a rune since the
278
// first 256 unicode code points cover ISO-8859-1.
279
func convert(buf []byte, enc Encoding) string {
280
	switch enc {
281
	case utf8Default, UTF8:
282
		return string(buf)
283
	case ISO_8859_1:
284
		runes := make([]rune, len(buf))
285
		for i, b := range buf {
286
			runes[i] = rune(b)
287
		}
288
		return string(runes)
289
	default:
290
		ErrorHandler(fmt.Errorf("unsupported encoding %v", enc))
291
	}
292
	panic("ErrorHandler should exit")
293
}
294

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

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

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

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