-
Notifications
You must be signed in to change notification settings - Fork 96
Expand file tree
/
Copy pathversion.go
More file actions
148 lines (134 loc) · 3.23 KB
/
version.go
File metadata and controls
148 lines (134 loc) · 3.23 KB
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package claircore
import (
"bytes"
"strconv"
"strings"
"github.com/Masterminds/semver"
)
// Version describes a revision of some sort that is ordered correctly within
// its "Kind".
//
// Versions of different kinds do not have any sensible ordering.
type Version struct {
Kind string
V [10]int32
}
// UnmatchableKind is a version kind that is used to indicate a version that
// should not be matched against.
var UnmatchableKind = "unmatchable"
// VersionSort returns a function suitable for passing to sort.Slice or
// sort.SliceStable.
func VersionSort(vs []Version) func(int, int) bool {
return func(i, j int) bool { return vs[i].Compare(&vs[j]) == -1 }
}
// FromSemver is the SemVer to claircore.Version mapping used by this package.
func FromSemver(v *semver.Version) (out Version) {
out.Kind = `semver`
// Leave a leading epoch, for good measure.
out.V[1] = int32(v.Major())
out.V[2] = int32(v.Minor())
out.V[3] = int32(v.Patch())
return out
}
// MarshalText implments encoding.TextMarshaler.
func (v *Version) MarshalText() ([]byte, error) {
if v.Kind == "" {
return []byte{}, nil
}
var buf bytes.Buffer
b := make([]byte, 0, 16) // 16 byte wide scratch buffer
buf.WriteString(v.Kind)
buf.WriteByte(':')
for i := range 10 {
if i != 0 {
buf.WriteByte('.')
}
buf.Write(strconv.AppendInt(b, int64(v.V[i]), 10))
}
return buf.Bytes(), nil
}
// UnmarshalText implments encoding.TextUnmarshaler.
func (v *Version) UnmarshalText(text []byte) (err error) {
idx := bytes.IndexByte(text, ':')
if idx == -1 {
return nil
}
if v == nil {
*v = Version{}
}
v.Kind = string(text[:idx])
var n int64
for i, b := range bytes.Split(text[idx+1:], []byte(".")) {
n, err = strconv.ParseInt(string(b), 10, 32)
if err != nil {
return err
}
v.V[i] = int32(n)
}
return nil
}
func (v *Version) String() string {
var buf strings.Builder
b := make([]byte, 0, 16) // 16 byte wide scratch buffer
if v.V[0] != 0 {
buf.Write(strconv.AppendInt(b, int64(v.V[0]), 10))
buf.WriteByte('!')
}
var f, l int
for i := 1; i < 10; i++ {
if v.V[i] != 0 {
if f == 0 {
f = i
}
l = i
}
}
// If we didn't set the offsets in the above loop, bump to make them
// absolute to the version array.
if f == 0 {
f++
}
if l == 0 {
l++
}
for i, n := range v.V[f : l+1] {
if i != 0 {
buf.WriteByte('.')
}
buf.Write(strconv.AppendInt(b, int64(n), 10))
}
return buf.String()
}
// Compare returns an integer describing the relationship of two Versions.
//
// The result will be 0 if a==b, -1 if a < b, and +1 if a > b. If the Versions
// are of different kinds, the Kinds will be compared lexographically.
func (v *Version) Compare(x *Version) int {
if v.Kind != x.Kind {
return strings.Compare(v.Kind, x.Kind)
}
for i := range 10 {
if v.V[i] > x.V[i] {
return 1
}
if v.V[i] < x.V[i] {
return -1
}
}
return 0
}
// Range is a half-open interval of two Versions.
//
// In the usual notation, it is: [Lower, Upper)
type Range struct {
Lower Version `json:"["`
Upper Version `json:")"`
}
// Contains reports whether the Version falls within the Range.
func (r *Range) Contains(v *Version) bool {
if r == nil {
return false
}
// Lower <= v && Upper > v
return r.Lower.Compare(v) != 1 && r.Upper.Compare(v) == 1
}