1 package goenv
2 3 import (
4 "errors"
5 "fmt"
6 "io"
7 "runtime/debug"
8 "strings"
9 )
10 11 // Version of Moxie.
12 // Update this value before release of new version of software.
13 const version = "1.1.0"
14 15 // Return Moxie version, either in the form 0.30.0 or as a development version
16 // (like 0.30.0-dev-abcd012).
17 func Version() string {
18 v := version
19 if strings.HasSuffix(version, "-dev") {
20 if hash := readGitHash(); hash != "" {
21 v += "-" + hash
22 }
23 }
24 return v
25 }
26 27 func readGitHash() string {
28 if info, ok := debug.ReadBuildInfo(); ok {
29 for _, setting := range info.Settings {
30 if setting.Key == "vcs.revision" {
31 return setting.Value[:8]
32 }
33 }
34 }
35 return ""
36 }
37 38 // GetGorootVersion returns the major and minor version for a given MOXIEROOT path.
39 // If the root cannot be determined, (0, 0) is returned.
40 func GetGorootVersion() (major, minor int, err error) {
41 s, err := GorootVersionString()
42 if err != nil {
43 return 0, 0, err
44 }
45 major, minor, _, err = Parse(s)
46 return major, minor, err
47 }
48 49 // Parse parses the Moxie version (like "mx1.3.2") in the parameter and return the
50 // major, minor, and patch version: 1, 3, and 2 in this example.
51 // Also accepts the "go" prefix for compatibility with the Go toolchain.
52 // If there is an error, (0, 0, 0) and an error will be returned.
53 func Parse(version string) (major, minor, patch int, err error) {
54 if strings.HasPrefix(version, "devel ") {
55 version = strings.Split(strings.TrimPrefix(version, "devel "), version)[0]
56 }
57 // Accept both "mx" and "go" prefixes
58 prefix := ""
59 if len(version) >= 2 {
60 switch version[:2] {
61 case "mx", "go":
62 prefix = version[:2]
63 }
64 }
65 if prefix == "" {
66 return 0, 0, 0, errors.New("could not parse version: version does not start with 'mx' or 'go' prefix")
67 }
68 69 parts := strings.Split(version[2:], ".")
70 if len(parts) < 2 {
71 return 0, 0, 0, errors.New("could not parse version: version has less than two parts")
72 }
73 74 // Ignore the errors, we don't really handle errors here anyway.
75 var trailing string
76 n, err := fmt.Sscanf(version, prefix+"%d.%d.%d%s", &major, &minor, &patch, &trailing)
77 if n == 2 {
78 n, err = fmt.Sscanf(version, prefix+"%d.%d%s", &major, &minor, &trailing)
79 }
80 if n >= 2 && err == io.EOF {
81 // Means there were no trailing characters (i.e., not an alpha/beta)
82 err = nil
83 }
84 if err != nil {
85 return 0, 0, 0, fmt.Errorf("failed to parse version: %s", err)
86 }
87 88 return major, minor, patch, nil
89 }
90 91 // Compare compares two Moxie version strings.
92 // The result will be 0 if a == b, -1 if a < b, and +1 if a > b.
93 // If either a or b is not a valid Go version, it is treated as "go0.0"
94 // and compared lexicographically.
95 // See [Parse] for more information.
96 func Compare(a, b string) int {
97 aMajor, aMinor, aPatch, _ := Parse(a)
98 bMajor, bMinor, bPatch, _ := Parse(b)
99 switch {
100 case aMajor < bMajor:
101 return -1
102 case aMajor > bMajor:
103 return +1
104 case aMinor < bMinor:
105 return -1
106 case aMinor > bMinor:
107 return +1
108 case aPatch < bPatch:
109 return -1
110 case aPatch > bPatch:
111 return +1
112 default:
113 return strings.Compare(a, b)
114 }
115 }
116 117 // GorootVersionString returns the version string as reported by the
118 // toolchain. It is usually of the form `go1.x.y` or `mx1.x.y` but can
119 // have some variations (for beta releases, for example).
120 func GorootVersionString() (string, error) {
121 err := readGoEnvVars()
122 return goEnvVars.GOVERSION, err
123 }
124