GitHub

@@ -0,0 +1,106 @@

1+

package config

2+3+

import (

4+

"errors"

5+

"fmt"

6+

"regexp"

7+

"strconv"

8+

"time"

9+10+

"github.com/kr/pretty"

11+

"github.com/zrepl/yaml-config"

12+

)

13+14+

type Duration struct{ d time.Duration }

15+16+

func (d Duration) Duration() time.Duration { return d.d }

17+18+

var _ yaml.Unmarshaler = &Duration{}

19+20+

func (d *Duration) UnmarshalYAML(unmarshal func(v interface{}, not_strict bool) error) error {

21+

var s string

22+

err := unmarshal(&s, false)

23+

if err != nil {

24+

return err

25+

}

26+

d.d, err = parseDuration(s)

27+

if err != nil {

28+

d.d = 0

29+

return &yaml.TypeError{Errors: []string{fmt.Sprintf("cannot parse value %q: %s", s, err)}}

30+

}

31+

return nil

32+

}

33+34+

type PositiveDuration struct{ d Duration }

35+36+

var _ yaml.Unmarshaler = &PositiveDuration{}

37+38+

func (d PositiveDuration) Duration() time.Duration { return d.d.Duration() }

39+40+

func (d *PositiveDuration) UnmarshalYAML(unmarshal func(v interface{}, not_strict bool) error) error {

41+

err := d.d.UnmarshalYAML(unmarshal)

42+

if err != nil {

43+

return err

44+

}

45+

if d.d.Duration() <= 0 {

46+

return fmt.Errorf("duration must be positive, got %s", d.d.Duration())

47+

}

48+

return nil

49+

}

50+51+

func parsePositiveDuration(e string) (time.Duration, error) {

52+

d, err := parseDuration(e)

53+

if err != nil {

54+

return d, err

55+

}

56+

if d <= 0 {

57+

return 0, errors.New("duration must be positive integer")

58+

}

59+

return d, err

60+

}

61+62+

var durationStringRegex *regexp.Regexp = regexp.MustCompile(`^\s*([\+-]?\d+)\s*(|s|m|h|d|w)\s*$`)

63+64+

func parseDuration(e string) (d time.Duration, err error) {

65+

comps := durationStringRegex.FindStringSubmatch(e)

66+

if comps == nil {

67+

err = fmt.Errorf("must match %s", durationStringRegex)

68+

return

69+

}

70+

if len(comps) != 3 {

71+

panic(pretty.Sprint(comps))

72+

}

73+74+

durationFactor, err := strconv.ParseInt(comps[1], 10, 64)

75+

if err != nil {

76+

return 0, err

77+

}

78+79+

var durationUnit time.Duration

80+

switch comps[2] {

81+

case "":

82+

if durationFactor != 0 {

83+

err = fmt.Errorf("missing time unit")

84+

return

85+

} else {

86+

// It's the case where user specified '0'.

87+

// We want to allow this, just like time.ParseDuration.

88+

}

89+

case "s":

90+

durationUnit = time.Second

91+

case "m":

92+

durationUnit = time.Minute

93+

case "h":

94+

durationUnit = time.Hour

95+

case "d":

96+

durationUnit = 24 * time.Hour

97+

case "w":

98+

durationUnit = 24 * 7 * time.Hour

99+

default:

100+

err = fmt.Errorf("contains unknown time unit '%s'", comps[2])

101+

return

102+

}

103+104+

d = time.Duration(durationFactor) * durationUnit

105+

return

106+

}

Read the original on github.com ↗