170 lines
4.3 KiB
Go
170 lines
4.3 KiB
Go
// Copyright IBM Corp. 2020, 2026
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package version
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"strings"
|
|
|
|
gvers "github.com/hashicorp/go-version"
|
|
)
|
|
|
|
const (
|
|
// BoundaryPrefix is the release version prefix used on the wire. It is
|
|
// kept as the emitted prefix so that this binary stays compatible with
|
|
// upstream HashiCorp Boundary peers that parse it.
|
|
BoundaryPrefix = "Boundary v"
|
|
// ThresholdPrefix is the release version prefix used for display and
|
|
// accepted additively when parsing.
|
|
ThresholdPrefix = "Threshold v"
|
|
)
|
|
|
|
// TrimReleasePrefix removes a leading (or embedded) "Boundary v" or
|
|
// "Threshold v" release prefix from s, if present.
|
|
func TrimReleasePrefix(s string) string {
|
|
for _, p := range []string{BoundaryPrefix, ThresholdPrefix} {
|
|
if idx := strings.Index(s, p); idx >= 0 {
|
|
return s[idx+len(p):]
|
|
}
|
|
}
|
|
return s
|
|
}
|
|
|
|
// Info
|
|
type Info struct {
|
|
Revision string `json:"revision,omitempty"`
|
|
Version string `json:"version,omitempty"`
|
|
VersionPrerelease string `json:"version_prerelease,omitempty"`
|
|
VersionMetadata string `json:"version_metadata,omitempty"`
|
|
BuildDate string `json:"build_date,omitempty"`
|
|
CgoEnabled bool `json:"cgo_enabled,omitempty"`
|
|
}
|
|
|
|
func Get() *Info {
|
|
ver := Version
|
|
rel := VersionPrerelease
|
|
md := VersionMetadata
|
|
bd := BuildDate
|
|
if GitDescribe != "" {
|
|
ver = GitDescribe
|
|
}
|
|
if GitDescribe == "" && rel == "" && VersionPrerelease != "" {
|
|
rel = "dev"
|
|
}
|
|
// Remove metadata string from version output for oss
|
|
if md == "oss" {
|
|
md = ""
|
|
}
|
|
|
|
return &Info{
|
|
CgoEnabled: CgoEnabled,
|
|
Revision: GitCommit,
|
|
Version: ver,
|
|
VersionPrerelease: rel,
|
|
VersionMetadata: md,
|
|
BuildDate: bd,
|
|
}
|
|
}
|
|
|
|
func (c *Info) VersionNumber() string {
|
|
if Version == "unknown" && VersionPrerelease == "unknown" {
|
|
return "(version unknown)"
|
|
}
|
|
|
|
version := c.Version
|
|
|
|
if c.VersionPrerelease != "" {
|
|
version = fmt.Sprintf("%s-%s", version, c.VersionPrerelease)
|
|
}
|
|
|
|
if c.VersionMetadata != "" && c.VersionMetadata != "oss" {
|
|
version = fmt.Sprintf("%s+%s", version, c.VersionMetadata)
|
|
}
|
|
|
|
return version
|
|
}
|
|
|
|
// Semver returns a *gvers.Version if the Info is parseable as
|
|
// a semantic version. Otherwise it returns nil.
|
|
func (c *Info) Semver() *gvers.Version {
|
|
if c == nil {
|
|
return nil
|
|
}
|
|
v, err := gvers.NewSemver(c.VersionNumber())
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return v
|
|
}
|
|
|
|
// FromVersionString returns an *Info containing the version, or nil if the
|
|
// string was unable to be parsed.
|
|
func FromVersionString(s string) *Info {
|
|
s = strings.TrimSpace(s)
|
|
s = strings.TrimPrefix(s, BoundaryPrefix)
|
|
s = strings.TrimPrefix(s, ThresholdPrefix)
|
|
i := Info{}
|
|
|
|
// Get the revision
|
|
startOfRevIdx := strings.LastIndex(s, "(")
|
|
endOfRevIdx := strings.LastIndex(s, ")")
|
|
if startOfRevIdx > 0 && endOfRevIdx > 0 {
|
|
if endOfRevIdx < startOfRevIdx {
|
|
return nil
|
|
}
|
|
i.Revision, s = s[startOfRevIdx+1:endOfRevIdx], strings.TrimSpace(s[:startOfRevIdx])
|
|
}
|
|
|
|
v, err := gvers.NewSemver(s)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
|
|
if md := v.Metadata(); len(md) > 0 && md != "oss" {
|
|
i.VersionMetadata = md
|
|
}
|
|
if pr := v.Prerelease(); len(pr) > 0 {
|
|
i.VersionPrerelease = pr
|
|
}
|
|
i.Version = v.Core().String()
|
|
|
|
return &i
|
|
}
|
|
|
|
// FullVersionNumber returns the wire-format release version, which uses the
|
|
// upstream "Boundary v" prefix for compatibility with peers.
|
|
func (c *Info) FullVersionNumber(rev bool) string {
|
|
return c.fullVersionNumber(BoundaryPrefix, "Boundary", rev)
|
|
}
|
|
|
|
// DisplayVersionNumber returns the release version for display to users,
|
|
// using the "Threshold v" prefix. Do not send this value over the wire.
|
|
func (c *Info) DisplayVersionNumber(rev bool) string {
|
|
return c.fullVersionNumber(ThresholdPrefix, "Threshold", rev)
|
|
}
|
|
|
|
func (c *Info) fullVersionNumber(prefix, name string, rev bool) string {
|
|
var versionString bytes.Buffer
|
|
|
|
if Version == "unknown" && VersionPrerelease == "unknown" {
|
|
return name + " (version unknown)"
|
|
}
|
|
|
|
fmt.Fprintf(&versionString, "%s%s", prefix, c.Version)
|
|
if c.VersionPrerelease != "" {
|
|
fmt.Fprintf(&versionString, "-%s", c.VersionPrerelease)
|
|
}
|
|
|
|
if c.VersionMetadata != "" && c.VersionMetadata != "oss" {
|
|
fmt.Fprintf(&versionString, "+%s", c.VersionMetadata)
|
|
}
|
|
|
|
if rev && c.Revision != "" {
|
|
fmt.Fprintf(&versionString, " (%s)", c.Revision)
|
|
}
|
|
|
|
return versionString.String()
|
|
}
|