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