podman
848 строк · 22.7 Кб
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
5package properties
6
7// BUG(frank): Set() does not check for invalid unicode literals since this is currently handled by the lexer.
8// BUG(frank): Write() does not allow to configure the newline character. Therefore, on Windows LF is used.
9
10import (
11"bytes"
12"fmt"
13"io"
14"log"
15"os"
16"regexp"
17"sort"
18"strconv"
19"strings"
20"time"
21"unicode/utf8"
22)
23
24const maxExpansionDepth = 64
25
26// ErrorHandlerFunc defines the type of function which handles failures
27// of the MustXXX() functions. An error handler function must exit
28// the application after handling the error.
29type ErrorHandlerFunc func(error)
30
31// ErrorHandler is the function which handles failures of the MustXXX()
32// functions. The default is LogFatalHandler.
33var ErrorHandler ErrorHandlerFunc = LogFatalHandler
34
35// LogHandlerFunc defines the function prototype for logging errors.
36type LogHandlerFunc func(fmt string, args ...interface{})
37
38// LogPrintf defines a log handler which uses log.Printf.
39var LogPrintf LogHandlerFunc = log.Printf
40
41// LogFatalHandler handles the error by logging a fatal error and exiting.
42func LogFatalHandler(err error) {
43log.Fatal(err)
44}
45
46// PanicHandler handles the error by panicking.
47func PanicHandler(err error) {
48panic(err)
49}
50
51// -----------------------------------------------------------------------------
52
53// A Properties contains the key/value pairs from the properties input.
54// All values are stored in unexpanded form and are expanded at runtime
55type Properties struct {
56// Pre-/Postfix for property expansion.
57Prefix string
58Postfix string
59
60// DisableExpansion controls the expansion of properties on Get()
61// and the check for circular references on Set(). When set to
62// true Properties behaves like a simple key/value store and does
63// not check for circular references on Get() or on Set().
64DisableExpansion bool
65
66// Stores the key/value pairs
67m map[string]string
68
69// Stores the comments per key.
70c map[string][]string
71
72// Stores the keys in order of appearance.
73k []string
74
75// WriteSeparator specifies the separator of key and value while writing the properties.
76WriteSeparator string
77}
78
79// NewProperties creates a new Properties struct with the default
80// configuration for "${key}" expressions.
81func NewProperties() *Properties {
82return &Properties{
83Prefix: "${",
84Postfix: "}",
85m: map[string]string{},
86c: map[string][]string{},
87k: []string{},
88}
89}
90
91// Load reads a buffer into the given Properties struct.
92func (p *Properties) Load(buf []byte, enc Encoding) error {
93l := &Loader{Encoding: enc, DisableExpansion: p.DisableExpansion}
94newProperties, err := l.LoadBytes(buf)
95if err != nil {
96return err
97}
98p.Merge(newProperties)
99return nil
100}
101
102// Get returns the expanded value for the given key if exists.
103// Otherwise, ok is false.
104func (p *Properties) Get(key string) (value string, ok bool) {
105v, ok := p.m[key]
106if p.DisableExpansion {
107return v, ok
108}
109if !ok {
110return "", false
111}
112
113expanded, err := p.expand(key, v)
114
115// we guarantee that the expanded value is free of
116// circular references and malformed expressions
117// so we panic if we still get an error here.
118if err != nil {
119ErrorHandler(err)
120}
121
122return expanded, true
123}
124
125// MustGet returns the expanded value for the given key if exists.
126// Otherwise, it panics.
127func (p *Properties) MustGet(key string) string {
128if v, ok := p.Get(key); ok {
129return v
130}
131ErrorHandler(invalidKeyError(key))
132panic("ErrorHandler should exit")
133}
134
135// ----------------------------------------------------------------------------
136
137// ClearComments removes the comments for all keys.
138func (p *Properties) ClearComments() {
139p.c = map[string][]string{}
140}
141
142// ----------------------------------------------------------------------------
143
144// GetComment returns the last comment before the given key or an empty string.
145func (p *Properties) GetComment(key string) string {
146comments, ok := p.c[key]
147if !ok || len(comments) == 0 {
148return ""
149}
150return comments[len(comments)-1]
151}
152
153// ----------------------------------------------------------------------------
154
155// GetComments returns all comments that appeared before the given key or nil.
156func (p *Properties) GetComments(key string) []string {
157if comments, ok := p.c[key]; ok {
158return comments
159}
160return nil
161}
162
163// ----------------------------------------------------------------------------
164
165// SetComment sets the comment for the key.
166func (p *Properties) SetComment(key, comment string) {
167p.c[key] = []string{comment}
168}
169
170// ----------------------------------------------------------------------------
171
172// SetComments sets the comments for the key. If the comments are nil then
173// all comments for this key are deleted.
174func (p *Properties) SetComments(key string, comments []string) {
175if comments == nil {
176delete(p.c, key)
177return
178}
179p.c[key] = comments
180}
181
182// ----------------------------------------------------------------------------
183
184// GetBool checks if the expanded value is one of '1', 'yes',
185// 'true' or 'on' if the key exists. The comparison is case-insensitive.
186// If the key does not exist the default value is returned.
187func (p *Properties) GetBool(key string, def bool) bool {
188v, err := p.getBool(key)
189if err != nil {
190return def
191}
192return v
193}
194
195// MustGetBool checks if the expanded value is one of '1', 'yes',
196// 'true' or 'on' if the key exists. The comparison is case-insensitive.
197// If the key does not exist the function panics.
198func (p *Properties) MustGetBool(key string) bool {
199v, err := p.getBool(key)
200if err != nil {
201ErrorHandler(err)
202}
203return v
204}
205
206func (p *Properties) getBool(key string) (value bool, err error) {
207if v, ok := p.Get(key); ok {
208return boolVal(v), nil
209}
210return false, invalidKeyError(key)
211}
212
213func boolVal(v string) bool {
214v = strings.ToLower(v)
215return v == "1" || v == "true" || v == "yes" || v == "on"
216}
217
218// ----------------------------------------------------------------------------
219
220// GetDuration parses the expanded value as an time.Duration (in ns) if the
221// key exists. If key does not exist or the value cannot be parsed the default
222// value is returned. In almost all cases you want to use GetParsedDuration().
223func (p *Properties) GetDuration(key string, def time.Duration) time.Duration {
224v, err := p.getInt64(key)
225if err != nil {
226return def
227}
228return time.Duration(v)
229}
230
231// MustGetDuration parses the expanded value as an time.Duration (in ns) if
232// the key exists. If key does not exist or the value cannot be parsed the
233// function panics. In almost all cases you want to use MustGetParsedDuration().
234func (p *Properties) MustGetDuration(key string) time.Duration {
235v, err := p.getInt64(key)
236if err != nil {
237ErrorHandler(err)
238}
239return time.Duration(v)
240}
241
242// ----------------------------------------------------------------------------
243
244// GetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
245// If key does not exist or the value cannot be parsed the default
246// value is returned.
247func (p *Properties) GetParsedDuration(key string, def time.Duration) time.Duration {
248s, ok := p.Get(key)
249if !ok {
250return def
251}
252v, err := time.ParseDuration(s)
253if err != nil {
254return def
255}
256return v
257}
258
259// MustGetParsedDuration parses the expanded value with time.ParseDuration() if the key exists.
260// If key does not exist or the value cannot be parsed the function panics.
261func (p *Properties) MustGetParsedDuration(key string) time.Duration {
262s, ok := p.Get(key)
263if !ok {
264ErrorHandler(invalidKeyError(key))
265}
266v, err := time.ParseDuration(s)
267if err != nil {
268ErrorHandler(err)
269}
270return v
271}
272
273// ----------------------------------------------------------------------------
274
275// GetFloat64 parses the expanded value as a float64 if the key exists.
276// If key does not exist or the value cannot be parsed the default
277// value is returned.
278func (p *Properties) GetFloat64(key string, def float64) float64 {
279v, err := p.getFloat64(key)
280if err != nil {
281return def
282}
283return v
284}
285
286// MustGetFloat64 parses the expanded value as a float64 if the key exists.
287// If key does not exist or the value cannot be parsed the function panics.
288func (p *Properties) MustGetFloat64(key string) float64 {
289v, err := p.getFloat64(key)
290if err != nil {
291ErrorHandler(err)
292}
293return v
294}
295
296func (p *Properties) getFloat64(key string) (value float64, err error) {
297if v, ok := p.Get(key); ok {
298value, err = strconv.ParseFloat(v, 64)
299if err != nil {
300return 0, err
301}
302return value, nil
303}
304return 0, invalidKeyError(key)
305}
306
307// ----------------------------------------------------------------------------
308
309// GetInt parses the expanded value as an int if the key exists.
310// If key does not exist or the value cannot be parsed the default
311// value is returned. If the value does not fit into an int the
312// function panics with an out of range error.
313func (p *Properties) GetInt(key string, def int) int {
314v, err := p.getInt64(key)
315if err != nil {
316return def
317}
318return intRangeCheck(key, v)
319}
320
321// MustGetInt parses the expanded value as an int if the key exists.
322// If key does not exist or the value cannot be parsed the function panics.
323// If the value does not fit into an int the function panics with
324// an out of range error.
325func (p *Properties) MustGetInt(key string) int {
326v, err := p.getInt64(key)
327if err != nil {
328ErrorHandler(err)
329}
330return intRangeCheck(key, v)
331}
332
333// ----------------------------------------------------------------------------
334
335// GetInt64 parses the expanded value as an int64 if the key exists.
336// If key does not exist or the value cannot be parsed the default
337// value is returned.
338func (p *Properties) GetInt64(key string, def int64) int64 {
339v, err := p.getInt64(key)
340if err != nil {
341return def
342}
343return v
344}
345
346// MustGetInt64 parses the expanded value as an int if the key exists.
347// If key does not exist or the value cannot be parsed the function panics.
348func (p *Properties) MustGetInt64(key string) int64 {
349v, err := p.getInt64(key)
350if err != nil {
351ErrorHandler(err)
352}
353return v
354}
355
356func (p *Properties) getInt64(key string) (value int64, err error) {
357if v, ok := p.Get(key); ok {
358value, err = strconv.ParseInt(v, 10, 64)
359if err != nil {
360return 0, err
361}
362return value, nil
363}
364return 0, invalidKeyError(key)
365}
366
367// ----------------------------------------------------------------------------
368
369// GetUint parses the expanded value as an uint if the key exists.
370// If key does not exist or the value cannot be parsed the default
371// value is returned. If the value does not fit into an int the
372// function panics with an out of range error.
373func (p *Properties) GetUint(key string, def uint) uint {
374v, err := p.getUint64(key)
375if err != nil {
376return def
377}
378return uintRangeCheck(key, v)
379}
380
381// MustGetUint parses the expanded value as an int if the key exists.
382// If key does not exist or the value cannot be parsed the function panics.
383// If the value does not fit into an int the function panics with
384// an out of range error.
385func (p *Properties) MustGetUint(key string) uint {
386v, err := p.getUint64(key)
387if err != nil {
388ErrorHandler(err)
389}
390return uintRangeCheck(key, v)
391}
392
393// ----------------------------------------------------------------------------
394
395// GetUint64 parses the expanded value as an uint64 if the key exists.
396// If key does not exist or the value cannot be parsed the default
397// value is returned.
398func (p *Properties) GetUint64(key string, def uint64) uint64 {
399v, err := p.getUint64(key)
400if err != nil {
401return def
402}
403return v
404}
405
406// MustGetUint64 parses the expanded value as an int if the key exists.
407// If key does not exist or the value cannot be parsed the function panics.
408func (p *Properties) MustGetUint64(key string) uint64 {
409v, err := p.getUint64(key)
410if err != nil {
411ErrorHandler(err)
412}
413return v
414}
415
416func (p *Properties) getUint64(key string) (value uint64, err error) {
417if v, ok := p.Get(key); ok {
418value, err = strconv.ParseUint(v, 10, 64)
419if err != nil {
420return 0, err
421}
422return value, nil
423}
424return 0, invalidKeyError(key)
425}
426
427// ----------------------------------------------------------------------------
428
429// GetString returns the expanded value for the given key if exists or
430// the default value otherwise.
431func (p *Properties) GetString(key, def string) string {
432if v, ok := p.Get(key); ok {
433return v
434}
435return def
436}
437
438// MustGetString returns the expanded value for the given key if exists or
439// panics otherwise.
440func (p *Properties) MustGetString(key string) string {
441if v, ok := p.Get(key); ok {
442return v
443}
444ErrorHandler(invalidKeyError(key))
445panic("ErrorHandler should exit")
446}
447
448// ----------------------------------------------------------------------------
449
450// Filter returns a new properties object which contains all properties
451// for which the key matches the pattern.
452func (p *Properties) Filter(pattern string) (*Properties, error) {
453re, err := regexp.Compile(pattern)
454if err != nil {
455return nil, err
456}
457
458return p.FilterRegexp(re), nil
459}
460
461// FilterRegexp returns a new properties object which contains all properties
462// for which the key matches the regular expression.
463func (p *Properties) FilterRegexp(re *regexp.Regexp) *Properties {
464pp := NewProperties()
465for _, k := range p.k {
466if re.MatchString(k) {
467// TODO(fs): we are ignoring the error which flags a circular reference.
468// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
469pp.Set(k, p.m[k])
470}
471}
472return pp
473}
474
475// FilterPrefix returns a new properties object with a subset of all keys
476// with the given prefix.
477func (p *Properties) FilterPrefix(prefix string) *Properties {
478pp := NewProperties()
479for _, k := range p.k {
480if strings.HasPrefix(k, prefix) {
481// TODO(fs): we are ignoring the error which flags a circular reference.
482// TODO(fs): since we are just copying a subset of keys this cannot happen (fingers crossed)
483pp.Set(k, p.m[k])
484}
485}
486return pp
487}
488
489// FilterStripPrefix returns a new properties object with a subset of all keys
490// with the given prefix and the prefix removed from the keys.
491func (p *Properties) FilterStripPrefix(prefix string) *Properties {
492pp := NewProperties()
493n := len(prefix)
494for _, k := range p.k {
495if len(k) > len(prefix) && strings.HasPrefix(k, prefix) {
496// TODO(fs): we are ignoring the error which flags a circular reference.
497// TODO(fs): since we are modifying keys I am not entirely sure whether we can create a circular reference
498// TODO(fs): this function should probably return an error but the signature is fixed
499pp.Set(k[n:], p.m[k])
500}
501}
502return pp
503}
504
505// Len returns the number of keys.
506func (p *Properties) Len() int {
507return len(p.m)
508}
509
510// Keys returns all keys in the same order as in the input.
511func (p *Properties) Keys() []string {
512keys := make([]string, len(p.k))
513copy(keys, p.k)
514return keys
515}
516
517// Set sets the property key to the corresponding value.
518// If a value for key existed before then ok is true and prev
519// contains the previous value. If the value contains a
520// circular reference or a malformed expression then
521// an error is returned.
522// An empty key is silently ignored.
523func (p *Properties) Set(key, value string) (prev string, ok bool, err error) {
524if key == "" {
525return "", false, nil
526}
527
528// if expansion is disabled we allow circular references
529if p.DisableExpansion {
530prev, ok = p.Get(key)
531p.m[key] = value
532if !ok {
533p.k = append(p.k, key)
534}
535return prev, ok, nil
536}
537
538// to check for a circular reference we temporarily need
539// to set the new value. If there is an error then revert
540// to the previous state. Only if all tests are successful
541// then we add the key to the p.k list.
542prev, ok = p.Get(key)
543p.m[key] = value
544
545// now check for a circular reference
546_, err = p.expand(key, value)
547if err != nil {
548
549// revert to the previous state
550if ok {
551p.m[key] = prev
552} else {
553delete(p.m, key)
554}
555
556return "", false, err
557}
558
559if !ok {
560p.k = append(p.k, key)
561}
562
563return prev, ok, nil
564}
565
566// SetValue sets property key to the default string value
567// as defined by fmt.Sprintf("%v").
568func (p *Properties) SetValue(key string, value interface{}) error {
569_, _, err := p.Set(key, fmt.Sprintf("%v", value))
570return err
571}
572
573// MustSet sets the property key to the corresponding value.
574// If a value for key existed before then ok is true and prev
575// contains the previous value. An empty key is silently ignored.
576func (p *Properties) MustSet(key, value string) (prev string, ok bool) {
577prev, ok, err := p.Set(key, value)
578if err != nil {
579ErrorHandler(err)
580}
581return prev, ok
582}
583
584// String returns a string of all expanded 'key = value' pairs.
585func (p *Properties) String() string {
586var s string
587for _, key := range p.k {
588value, _ := p.Get(key)
589s = fmt.Sprintf("%s%s = %s\n", s, key, value)
590}
591return s
592}
593
594// Sort sorts the properties keys in alphabetical order.
595// This is helpfully before writing the properties.
596func (p *Properties) Sort() {
597sort.Strings(p.k)
598}
599
600// Write writes all unexpanded 'key = value' pairs to the given writer.
601// Write returns the number of bytes written and any write error encountered.
602func (p *Properties) Write(w io.Writer, enc Encoding) (n int, err error) {
603return p.WriteComment(w, "", enc)
604}
605
606// WriteComment writes all unexpanced 'key = value' pairs to the given writer.
607// If prefix is not empty then comments are written with a blank line and the
608// given prefix. The prefix should be either "# " or "! " to be compatible with
609// the properties file format. Otherwise, the properties parser will not be
610// able to read the file back in. It returns the number of bytes written and
611// any write error encountered.
612func (p *Properties) WriteComment(w io.Writer, prefix string, enc Encoding) (n int, err error) {
613var x int
614
615for _, key := range p.k {
616value := p.m[key]
617
618if prefix != "" {
619if comments, ok := p.c[key]; ok {
620// don't print comments if they are all empty
621allEmpty := true
622for _, c := range comments {
623if c != "" {
624allEmpty = false
625break
626}
627}
628
629if !allEmpty {
630// add a blank line between entries but not at the top
631if len(comments) > 0 && n > 0 {
632x, err = fmt.Fprintln(w)
633if err != nil {
634return
635}
636n += x
637}
638
639for _, c := range comments {
640x, err = fmt.Fprintf(w, "%s%s\n", prefix, c)
641if err != nil {
642return
643}
644n += x
645}
646}
647}
648}
649sep := " = "
650if p.WriteSeparator != "" {
651sep = p.WriteSeparator
652}
653x, err = fmt.Fprintf(w, "%s%s%s\n", encode(key, " :", enc), sep, encode(value, "", enc))
654if err != nil {
655return
656}
657n += x
658}
659return
660}
661
662// Map returns a copy of the properties as a map.
663func (p *Properties) Map() map[string]string {
664m := make(map[string]string)
665for k, v := range p.m {
666m[k] = v
667}
668return m
669}
670
671// FilterFunc returns a copy of the properties which includes the values which passed all filters.
672func (p *Properties) FilterFunc(filters ...func(k, v string) bool) *Properties {
673pp := NewProperties()
674outer:
675for k, v := range p.m {
676for _, f := range filters {
677if !f(k, v) {
678continue outer
679}
680pp.Set(k, v)
681}
682}
683return pp
684}
685
686// ----------------------------------------------------------------------------
687
688// Delete removes the key and its comments.
689func (p *Properties) Delete(key string) {
690delete(p.m, key)
691delete(p.c, key)
692newKeys := []string{}
693for _, k := range p.k {
694if k != key {
695newKeys = append(newKeys, k)
696}
697}
698p.k = newKeys
699}
700
701// Merge merges properties, comments and keys from other *Properties into p
702func (p *Properties) Merge(other *Properties) {
703for _, k := range other.k {
704if _, ok := p.m[k]; !ok {
705p.k = append(p.k, k)
706}
707}
708for k, v := range other.m {
709p.m[k] = v
710}
711for k, v := range other.c {
712p.c[k] = v
713}
714}
715
716// ----------------------------------------------------------------------------
717
718// check expands all values and returns an error if a circular reference or
719// a malformed expression was found.
720func (p *Properties) check() error {
721for key, value := range p.m {
722if _, err := p.expand(key, value); err != nil {
723return err
724}
725}
726return nil
727}
728
729func (p *Properties) expand(key, input string) (string, error) {
730// no pre/postfix -> nothing to expand
731if p.Prefix == "" && p.Postfix == "" {
732return input, nil
733}
734
735return expand(input, []string{key}, p.Prefix, p.Postfix, p.m)
736}
737
738// expand recursively expands expressions of '(prefix)key(postfix)' to their corresponding values.
739// The function keeps track of the keys that were already expanded and stops if it
740// detects a circular reference or a malformed expression of the form '(prefix)key'.
741func expand(s string, keys []string, prefix, postfix string, values map[string]string) (string, error) {
742if len(keys) > maxExpansionDepth {
743return "", fmt.Errorf("expansion too deep")
744}
745
746for {
747start := strings.Index(s, prefix)
748if start == -1 {
749return s, nil
750}
751
752keyStart := start + len(prefix)
753keyLen := strings.Index(s[keyStart:], postfix)
754if keyLen == -1 {
755return "", fmt.Errorf("malformed expression")
756}
757
758end := keyStart + keyLen + len(postfix) - 1
759key := s[keyStart : keyStart+keyLen]
760
761// fmt.Printf("s:%q pp:%q start:%d end:%d keyStart:%d keyLen:%d key:%q\n", s, prefix + "..." + postfix, start, end, keyStart, keyLen, key)
762
763for _, k := range keys {
764if key == k {
765var b bytes.Buffer
766b.WriteString("circular reference in:\n")
767for _, k1 := range keys {
768fmt.Fprintf(&b, "%s=%s\n", k1, values[k1])
769}
770return "", fmt.Errorf(b.String())
771}
772}
773
774val, ok := values[key]
775if !ok {
776val = os.Getenv(key)
777}
778new_val, err := expand(val, append(keys, key), prefix, postfix, values)
779if err != nil {
780return "", err
781}
782s = s[:start] + new_val + s[end+1:]
783}
784}
785
786// encode encodes a UTF-8 string to ISO-8859-1 and escapes some characters.
787func encode(s string, special string, enc Encoding) string {
788switch enc {
789case UTF8:
790return encodeUtf8(s, special)
791case ISO_8859_1:
792return encodeIso(s, special)
793default:
794panic(fmt.Sprintf("unsupported encoding %v", enc))
795}
796}
797
798func encodeUtf8(s string, special string) string {
799v := ""
800for pos := 0; pos < len(s); {
801r, w := utf8.DecodeRuneInString(s[pos:])
802pos += w
803v += escape(r, special)
804}
805return v
806}
807
808func encodeIso(s string, special string) string {
809var r rune
810var w int
811var v string
812for pos := 0; pos < len(s); {
813switch r, w = utf8.DecodeRuneInString(s[pos:]); {
814case r < 1<<8: // single byte rune -> escape special chars only
815v += escape(r, special)
816case r < 1<<16: // two byte rune -> unicode literal
817v += fmt.Sprintf("\\u%04x", r)
818default: // more than two bytes per rune -> can't encode
819v += "?"
820}
821pos += w
822}
823return v
824}
825
826func escape(r rune, special string) string {
827switch r {
828case '\f':
829return "\\f"
830case '\n':
831return "\\n"
832case '\r':
833return "\\r"
834case '\t':
835return "\\t"
836case '\\':
837return "\\\\"
838default:
839if strings.ContainsRune(special, r) {
840return "\\" + string(r)
841}
842return string(r)
843}
844}
845
846func invalidKeyError(key string) error {
847return fmt.Errorf("unknown property: %s", key)
848}
849