-
Notifications
You must be signed in to change notification settings - Fork 1
/
version.go
85 lines (72 loc) · 1.99 KB
/
version.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
package internal
import (
"errors"
"regexp"
"strconv"
"time"
)
// Version is for comparing migrations to each other.
type Version interface {
Before(u Version) bool
String() string
Value() int64
}
type timestamp struct {
value int64
label string
}
func (v *timestamp) Before(u Version) bool {
// Until there's more than 1 interface implementation, this is fine. So,
// panic here? Yeah, maybe. Fail loudly, not silently.
w := u.(*timestamp)
return v.value < w.value
}
func (v *timestamp) String() string {
if v.label == "" {
return strconv.FormatInt(int64(v.value), 10)
}
return v.label
}
func (v *timestamp) Value() int64 { return v.value }
const (
// TimeFormat provides a consistent timestamp layout for migrations.
TimeFormat = "20060102150405"
unixTimestampSecLen = len("1574079194")
)
// Some reasonable lower, upper limits for migration versions.
var (
MinVersion = time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC).Format(TimeFormat)
MaxVersion = time.Date(9999, 12, 31, 23, 59, 59, 0, time.UTC).Format(TimeFormat)
)
var timeformatMatcher = regexp.MustCompile(`\d{4,14}`)
// ParseVersion extracts Version info from a file's basename.
func ParseVersion(basename string) (version Version, err error) {
written := timeformatMatcher.FindString(basename)
if len(written) < 1 {
err = errors.New("could not parse version from filename")
return
}
if ts, perr := time.Parse(TimeFormat, written); perr != nil {
err = perr // keep going
} else {
version = ×tamp{value: ts.UTC().Unix(), label: written}
return
}
if perr, ok := err.(*time.ParseError); ok {
if len(perr.Value) < len(TimeFormat) {
ts, qerr := time.Parse(TimeFormat[:len(perr.Value)], perr.Value)
if qerr == nil {
version = ×tamp{value: ts.UTC().Unix(), label: perr.Value}
err = nil
return
}
}
}
// try parsing as unix epoch timestamp
num, err := strconv.ParseInt(written[:unixTimestampSecLen], 10, 64)
if err != nil {
return
}
version = ×tamp{value: num, label: written}
return
}