~juju-qa/ubuntu/xenial/juju/xenial-2.0-beta3

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/version/version.go

  • Committer: Martin Packman
  • Date: 2016-03-30 19:31:08 UTC
  • mfrom: (1.1.41)
  • Revision ID: martin.packman@canonical.com-20160330193108-h9iz3ak334uk0z5r
Merge new upstream source 2.0~beta3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// Copyright 2012, 2013 Canonical Ltd.
2
2
// Licensed under the AGPLv3, see LICENCE file for details.
3
3
 
4
 
// The version package implements version parsing.
5
 
// It also acts as guardian of the current client Juju version number.
 
4
// Package version contains versioning information for juju.  It also
 
5
// acts as guardian of the current client Juju version number.
6
6
package version
7
7
 
8
8
import (
9
 
        "encoding/json"
10
9
        "fmt"
11
10
        "io/ioutil"
12
11
        "os"
13
12
        "path/filepath"
14
 
        "regexp"
15
 
        "strconv"
 
13
        "runtime"
16
14
        "strings"
17
15
 
18
 
        "github.com/juju/utils/series"
19
 
        "gopkg.in/mgo.v2/bson"
 
16
        semversion "github.com/juju/version"
20
17
)
21
18
 
22
19
// The presence and format of this constant is very important.
23
20
// The debian/rules build recipe uses this value for the version
24
21
// number of the release package.
25
 
const version = "2.0-beta2"
 
22
const version = "2.0-beta3"
26
23
 
27
24
// The version that we switched over from old style numbering to new style.
28
 
var switchOverVersion = MustParse("1.19.9")
29
 
 
30
 
// osReleaseFile is the name of the file that is read in order to determine
31
 
// the linux type release version.
32
 
var osReleaseFile = "/etc/os-release"
 
25
var switchOverVersion = semversion.MustParse("1.19.9")
33
26
 
34
27
// Current gives the current version of the system.  If the file
35
28
// "FORCE-VERSION" is present in the same directory as the running
36
29
// binary, it will override this.
37
 
var Current = MustParse(version)
 
30
var Current = semversion.MustParse(version)
 
31
 
 
32
var Compiler = runtime.Compiler
38
33
 
39
34
func init() {
40
35
        toolsDir := filepath.Dir(os.Args[0])
45
40
                }
46
41
                return
47
42
        }
48
 
        Current = MustParse(strings.TrimSpace(string(v)))
49
 
}
50
 
 
51
 
// Number represents a juju version.  When bugs are fixed the patch number is
52
 
// incremented; when new features are added the minor number is incremented
53
 
// and patch is reset; and when compatibility is broken the major version is
54
 
// incremented and minor and patch are reset.  The build number is
55
 
// automatically assigned and has no well defined sequence.  If the build
56
 
// number is greater than zero or the tag is non-empty it indicates that the
57
 
// release is still in development.  For versions older than 1.19.3,
58
 
// development releases were indicated by an odd Minor number of any non-zero
59
 
// build number.
60
 
type Number struct {
61
 
        Major int
62
 
        Minor int
63
 
        Tag   string
64
 
        Patch int
65
 
        Build int
66
 
}
67
 
 
68
 
// Zero is occasionally convenient and readable.
69
 
// Please don't change its value.
70
 
var Zero = Number{}
71
 
 
72
 
// Binary specifies a binary version of juju.
73
 
type Binary struct {
74
 
        Number
75
 
        Series string
76
 
        Arch   string
77
 
}
78
 
 
79
 
func (v Binary) String() string {
80
 
        return fmt.Sprintf("%v-%s-%s", v.Number, v.Series, v.Arch)
81
 
}
82
 
 
83
 
// GetBSON turns v into a bson.Getter so it can be saved directly
84
 
// on a MongoDB database with mgo.
85
 
func (v Binary) GetBSON() (interface{}, error) {
86
 
        return v.String(), nil
87
 
}
88
 
 
89
 
// SetBSON turns v into a bson.Setter so it can be loaded directly
90
 
// from a MongoDB database with mgo.
91
 
func (vp *Binary) SetBSON(raw bson.Raw) error {
92
 
        var s string
93
 
        err := raw.Unmarshal(&s)
94
 
        if err != nil {
95
 
                return err
96
 
        }
97
 
        v, err := ParseBinary(s)
98
 
        if err != nil {
99
 
                return err
100
 
        }
101
 
        *vp = v
102
 
        return nil
103
 
}
104
 
 
105
 
func (v Binary) MarshalJSON() ([]byte, error) {
106
 
        return json.Marshal(v.String())
107
 
}
108
 
 
109
 
func (vp *Binary) UnmarshalJSON(data []byte) error {
110
 
        var s string
111
 
        if err := json.Unmarshal(data, &s); err != nil {
112
 
                return err
113
 
        }
114
 
        v, err := ParseBinary(s)
115
 
        if err != nil {
116
 
                return err
117
 
        }
118
 
        *vp = v
119
 
        return nil
120
 
}
121
 
 
122
 
// MarshalYAML implements yaml.v2.Marshaller interface
123
 
func (v Binary) MarshalYAML() (interface{}, error) {
124
 
        return v.String(), nil
125
 
}
126
 
 
127
 
// UnmarshalYAML implements the yaml.Unmarshaller interface
128
 
func (vp *Binary) UnmarshalYAML(unmarshal func(interface{}) error) error {
129
 
        var vstr string
130
 
        err := unmarshal(&vstr)
131
 
        if err != nil {
132
 
                return err
133
 
        }
134
 
        v, err := ParseBinary(vstr)
135
 
        if err != nil {
136
 
                return err
137
 
        }
138
 
        *vp = v
139
 
        return nil
140
 
}
141
 
 
142
 
var (
143
 
        binaryPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})(\.|-(\w+))(\d{1,9})(\.\d{1,9})?-([^-]+)-([^-]+)$`)
144
 
        numberPat = regexp.MustCompile(`^(\d{1,9})\.(\d{1,9})(\.|-(\w+))(\d{1,9})(\.\d{1,9})?$`)
145
 
)
146
 
 
147
 
// MustParse parses a version and panics if it does
148
 
// not parse correctly.
149
 
func MustParse(s string) Number {
150
 
        v, err := Parse(s)
151
 
        if err != nil {
152
 
                panic(err)
153
 
        }
154
 
        return v
155
 
}
156
 
 
157
 
// MustParseBinary parses a binary version and panics if it does
158
 
// not parse correctly.
159
 
func MustParseBinary(s string) Binary {
160
 
        v, err := ParseBinary(s)
161
 
        if err != nil {
162
 
                panic(err)
163
 
        }
164
 
        return v
165
 
}
166
 
 
167
 
// ParseBinary parses a binary version of the form "1.2.3-series-arch".
168
 
func ParseBinary(s string) (Binary, error) {
169
 
        m := binaryPat.FindStringSubmatch(s)
170
 
        if m == nil {
171
 
                return Binary{}, fmt.Errorf("invalid binary version %q", s)
172
 
        }
173
 
        var v Binary
174
 
        v.Major = atoi(m[1])
175
 
        v.Minor = atoi(m[2])
176
 
        v.Tag = m[4]
177
 
        v.Patch = atoi(m[5])
178
 
        if m[6] != "" {
179
 
                v.Build = atoi(m[6][1:])
180
 
        }
181
 
        v.Series = m[7]
182
 
        v.Arch = m[8]
183
 
        _, err := series.GetOSFromSeries(v.Series)
184
 
        return v, err
185
 
}
186
 
 
187
 
// Parse parses the version, which is of the form 1.2.3
188
 
// giving the major, minor and release versions
189
 
// respectively.
190
 
func Parse(s string) (Number, error) {
191
 
        m := numberPat.FindStringSubmatch(s)
192
 
        if m == nil {
193
 
                return Number{}, fmt.Errorf("invalid version %q", s)
194
 
        }
195
 
        var v Number
196
 
        v.Major = atoi(m[1])
197
 
        v.Minor = atoi(m[2])
198
 
        v.Tag = m[4]
199
 
        v.Patch = atoi(m[5])
200
 
        if m[6] != "" {
201
 
                v.Build = atoi(m[6][1:])
202
 
        }
203
 
        return v, nil
204
 
}
205
 
 
206
 
// atoi is the same as strconv.Atoi but assumes that
207
 
// the string has been verified to be a valid integer.
208
 
func atoi(s string) int {
209
 
        n, err := strconv.Atoi(s)
210
 
        if err != nil {
211
 
                panic(err)
212
 
        }
213
 
        return n
214
 
}
215
 
 
216
 
func (v Number) String() string {
217
 
        var s string
218
 
        if v.Tag == "" {
219
 
                s = fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Patch)
220
 
        } else {
221
 
                s = fmt.Sprintf("%d.%d-%s%d", v.Major, v.Minor, v.Tag, v.Patch)
222
 
        }
223
 
        if v.Build > 0 {
224
 
                s += fmt.Sprintf(".%d", v.Build)
225
 
        }
226
 
        return s
227
 
}
228
 
 
229
 
// Compare returns -1, 0 or 1 depending on whether
230
 
// v is less than, equal to or greater than w.
231
 
func (v Number) Compare(w Number) int {
232
 
        if v == w {
233
 
                return 0
234
 
        }
235
 
        less := false
236
 
        switch {
237
 
        case v.Major != w.Major:
238
 
                less = v.Major < w.Major
239
 
        case v.Minor != w.Minor:
240
 
                less = v.Minor < w.Minor
241
 
        case v.Tag != w.Tag:
242
 
                switch {
243
 
                case v.Tag == "":
244
 
                        less = false
245
 
                case w.Tag == "":
246
 
                        less = true
247
 
                default:
248
 
                        less = v.Tag < w.Tag
249
 
                }
250
 
        case v.Patch != w.Patch:
251
 
                less = v.Patch < w.Patch
252
 
        case v.Build != w.Build:
253
 
                less = v.Build < w.Build
254
 
        }
255
 
        if less {
256
 
                return -1
257
 
        }
258
 
        return 1
259
 
}
260
 
 
261
 
// GetBSON turns v into a bson.Getter so it can be saved directly
262
 
// on a MongoDB database with mgo.
263
 
func (v Number) GetBSON() (interface{}, error) {
264
 
        return v.String(), nil
265
 
}
266
 
 
267
 
// SetBSON turns v into a bson.Setter so it can be loaded directly
268
 
// from a MongoDB database with mgo.
269
 
func (vp *Number) SetBSON(raw bson.Raw) error {
270
 
        var s string
271
 
        err := raw.Unmarshal(&s)
272
 
        if err != nil {
273
 
                return err
274
 
        }
275
 
        v, err := Parse(s)
276
 
        if err != nil {
277
 
                return err
278
 
        }
279
 
        *vp = v
280
 
        return nil
281
 
}
282
 
 
283
 
func (v Number) MarshalJSON() ([]byte, error) {
284
 
        return json.Marshal(v.String())
285
 
}
286
 
 
287
 
func (vp *Number) UnmarshalJSON(data []byte) error {
288
 
        var s string
289
 
        if err := json.Unmarshal(data, &s); err != nil {
290
 
                return err
291
 
        }
292
 
        v, err := Parse(s)
293
 
        if err != nil {
294
 
                return err
295
 
        }
296
 
        *vp = v
297
 
        return nil
298
 
}
299
 
 
300
 
// MarshalYAML implements yaml.v2.Marshaller interface
301
 
func (v Number) MarshalYAML() (interface{}, error) {
302
 
        return v.String(), nil
303
 
}
304
 
 
305
 
// UnmarshalYAML implements the yaml.Unmarshaller interface
306
 
func (vp *Number) UnmarshalYAML(unmarshal func(interface{}) error) error {
307
 
        var vstr string
308
 
        err := unmarshal(&vstr)
309
 
        if err != nil {
310
 
                return err
311
 
        }
312
 
        v, err := Parse(vstr)
313
 
        if err != nil {
314
 
                return err
315
 
        }
316
 
        *vp = v
317
 
        return nil
 
43
        Current = semversion.MustParse(strings.TrimSpace(string(v)))
318
44
}
319
45
 
320
46
func isOdd(x int) bool {
325
51
// version with a tag or a nonzero build component is considered to be a
326
52
// development version.  Versions older than or equal to 1.19.3 (the switch
327
53
// over time) check for odd minor versions.
328
 
func (v Number) IsDev() bool {
 
54
func IsDev(v semversion.Number) bool {
329
55
        if v.Compare(switchOverVersion) <= 0 {
330
56
                return isOdd(v.Minor) || v.Build > 0
331
57
        }
332
58
        return v.Tag != "" || v.Build > 0
333
59
}
334
 
 
335
 
// ParseMajorMinor takes an argument of the form "major.minor" and returns ints major and minor.
336
 
func ParseMajorMinor(vers string) (int, int, error) {
337
 
        parts := strings.Split(vers, ".")
338
 
        major, err := strconv.Atoi(parts[0])
339
 
        minor := -1
340
 
        if err != nil {
341
 
                return -1, -1, fmt.Errorf("invalid major version number %s: %v", parts[0], err)
342
 
        }
343
 
        if len(parts) == 2 {
344
 
                minor, err = strconv.Atoi(parts[1])
345
 
                if err != nil {
346
 
                        return -1, -1, fmt.Errorf("invalid minor version number %s: %v", parts[1], err)
347
 
                }
348
 
        } else if len(parts) > 2 {
349
 
                return -1, -1, fmt.Errorf("invalid major.minor version number %s", vers)
350
 
        }
351
 
        return major, minor, nil
352
 
}