-
Notifications
You must be signed in to change notification settings - Fork 55
/
versions.go
92 lines (82 loc) · 2.89 KB
/
versions.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
86
87
88
89
90
91
92
package transformer
import (
"math"
rpb "github.com/ampproject/amppackager/transformer/request"
"github.com/pkg/errors"
)
// SupportedVersions is a set of all transform versions supported by this
// snapshot of the library. This should not include transforms not yet
// snapshotted to a finalized version.
// The ranges should be non-overlapping and in descending order.
// Visible for test.
var SupportedVersions = []*rpb.VersionRange{{Min: 1, Max: 8}}
func min(a, b int64) int64 {
if a < b {
return a
}
return b
}
// intervalsOverlap returns true if there exists at least one value in both `a`
// and `b`. This assumes `a` and `b` are not malformed.
func intervalsOverlap(a, b *rpb.VersionRange) bool {
return a.Max >= b.Min && a.Min <= b.Max
}
// isGreater returns true if all of the values in `a` are greater than all of
// the values in `b`. This assumes `a` and `b` are not malformed.
func isGreater(a, b *rpb.VersionRange) bool {
return a.Min > b.Max
}
// validateRequest verifies the request is properly formed.
func validateRequest(rs []*rpb.VersionRange) error {
var lastMin int64 = math.MaxInt64
for i, r := range rs {
if r.Min > r.Max {
return errors.Errorf("malformed range %v at index %d", r, i)
}
if r.Min < 1 || r.Max < 1 {
return errors.Errorf("non-positive value in range %v at index %d", r, i)
}
if r.Max >= lastMin {
return errors.Errorf("overlapping or out-of-order range %v at index %d", r, i)
}
lastMin = r.Min
}
return nil
}
func selectVersion(requested, supported []*rpb.VersionRange) (int64, error) {
// If request is invalid, then error.
if err := validateRequest(requested); err != nil {
return 0, err
}
// If no versions are supported, then huh.
if len(supported) == 0 {
return 0, errors.New("no version at all is supported by this transformer")
}
// If no requested versions are specified, then return the highest
// support version.
if len(requested) == 0 {
return supported[0].Max, nil
}
// Otherwise, search for the highest number in both sets.
for r, s := 0, 0; r < len(requested) && s < len(supported); {
if intervalsOverlap(requested[r], supported[s]) {
return min(requested[r].Max, supported[s].Max), nil
} else if isGreater(requested[r], supported[s]) {
r++
} else {
s++
}
}
return 0, errors.New("no requested version is supported by this transformer")
}
// SelectVersion returns the highest requested version number that the
// transformer supports, or an error if no such version exists. The requested
// list must consist of non-overlapping ranges in descending order.
//
// The transfomer will select the highest version from requested that it
// supports. If requested is nil or empty, the transfomer will select the
// highest version it supports. In both cases, it shouldn't include
// in-development versions.
func SelectVersion(requested []*rpb.VersionRange) (int64, error) {
return selectVersion(requested, SupportedVersions)
}