package version import ( "fmt" "regexp" "runtime" "strconv" "strings" ) // Info : data structure for program version information type info struct { Major int Minor int Patch int Prerelease []string BuildMeta []string } // gitDescribe : Git's "git describe --always --dirty" output var gitDescribe = "" // GoVersion : The go version used to compile this binary var GoVersion = runtime.Version() // OsArch : The OS and archetcture used for this binary var OsArch = fmt.Sprintf("%s (%s)", runtime.GOOS, runtime.GOARCH) // Version : the complete version data var Version = parseGitDescribe(gitDescribe) // Equal compares two Info structs for equality func (i info) Equal(o info) bool { if i.Major != o.Major || i.Minor != o.Minor || i.Patch != o.Patch { return false } if len(i.Prerelease) != len(o.Prerelease) || len(i.BuildMeta) != len(o.BuildMeta) { return false } for j := 0; j < len(i.Prerelease); j++ { if i.Prerelease[j] != o.Prerelease[j] { return false } } for j := 0; j < len(i.BuildMeta); j++ { if i.BuildMeta[j] != o.BuildMeta[j] { return false } } return true } // String returns a human friendly version string func (i info) String() string { var b strings.Builder fmt.Fprintf(&b, "v%d.%d.%d", i.Major, i.Minor, i.Patch) if len(i.Prerelease) > 0 { fmt.Fprintf(&b, "-%s", strings.Join(i.Prerelease, ".")) } if len(i.BuildMeta) > 0 { fmt.Fprintf(&b, "+%s", strings.Join(i.BuildMeta, ".")) } return b.String() } /* reStr is a regular expression string to parse the output of git describe Match groups: 1. version number (without "v") 2. major version 3. minor version 4. patch version 5. prerelease identifier 6. commit count 7. git short hash 8. "-dirty" if dirty, else "" */ const reStr = `^(?:v(([0-9]+)(?:\.([0-9]+)(?:\.([0-9]+))?)?))?(?:-((?:alpha|beta|rc|dev)(?:\.[a-zA-Z0-9]+)*))?(?:-([0-9]+)-g)?([a-f0-9A-F]+)?(?:(-dirty))?$` var re = regexp.MustCompile(reStr) func parseGitDescribe(input string) info { matches := re.FindStringSubmatch(input) if matches == nil || matches[0] == "" { return info{0, 0, 0, []string{"dev"}, []string{"unknown"}} } info := info{} if matches[2] != "" { num, _ := strconv.Atoi(matches[2]) info.Major = num } if matches[3] != "" { num, _ := strconv.Atoi(matches[3]) info.Minor = num } if matches[4] != "" { num, _ := strconv.Atoi(matches[4]) info.Patch = num } if matches[5] != "" { info.Prerelease = strings.Split(matches[5], ".") } if matches[6] != "" || matches[7] != "" || matches[8] != "" { info.BuildMeta = append(info.BuildMeta, "git") if matches[6] != "" { info.BuildMeta = append(info.BuildMeta, matches[6]) } if matches[7] != "" { info.BuildMeta = append(info.BuildMeta, matches[7]) } if matches[8] != "" { info.BuildMeta = append(info.BuildMeta, "dirty") } } return info }