version: make all exported funcs compile-time constant or lazy
Signed-off-by: David Anderson <danderson@tailscale.com>pull/7258/head
parent
8b2ae47c31
commit
70a2929a12
|
@ -46,7 +46,7 @@ EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tags=""
|
tags=""
|
||||||
ldflags="-X tailscale.com/version.long=${LONG} -X tailscale.com/version.short=${SHORT} -X tailscale.com/version.gitCommit=${GIT_HASH}"
|
ldflags="-X tailscale.com/version.longStamp=${LONG} -X tailscale.com/version.shortStamp=${SHORT}"
|
||||||
|
|
||||||
# build_dist.sh arguments must precede go build arguments.
|
# build_dist.sh arguments must precede go build arguments.
|
||||||
while [ "$#" -gt 1 ]; do
|
while [ "$#" -gt 1 ]; do
|
||||||
|
|
|
@ -65,6 +65,7 @@ tailscale.com/cmd/derper dependencies: (generated by github.com/tailscale/depawa
|
||||||
tailscale.com/types/empty from tailscale.com/ipn
|
tailscale.com/types/empty from tailscale.com/ipn
|
||||||
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
||||||
tailscale.com/types/key from tailscale.com/cmd/derper+
|
tailscale.com/types/key from tailscale.com/cmd/derper+
|
||||||
|
tailscale.com/types/lazy from tailscale.com/version+
|
||||||
tailscale.com/types/logger from tailscale.com/cmd/derper+
|
tailscale.com/types/logger from tailscale.com/cmd/derper+
|
||||||
tailscale.com/types/netmap from tailscale.com/ipn
|
tailscale.com/types/netmap from tailscale.com/ipn
|
||||||
tailscale.com/types/opt from tailscale.com/client/tailscale+
|
tailscale.com/types/opt from tailscale.com/client/tailscale+
|
||||||
|
|
|
@ -93,6 +93,7 @@ tailscale.com/cmd/tailscale dependencies: (generated by github.com/tailscale/dep
|
||||||
tailscale.com/types/empty from tailscale.com/ipn
|
tailscale.com/types/empty from tailscale.com/ipn
|
||||||
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
||||||
tailscale.com/types/key from tailscale.com/derp+
|
tailscale.com/types/key from tailscale.com/derp+
|
||||||
|
tailscale.com/types/lazy from tailscale.com/version+
|
||||||
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
|
tailscale.com/types/logger from tailscale.com/cmd/tailscale/cli+
|
||||||
tailscale.com/types/netmap from tailscale.com/ipn
|
tailscale.com/types/netmap from tailscale.com/ipn
|
||||||
tailscale.com/types/nettype from tailscale.com/net/netcheck+
|
tailscale.com/types/nettype from tailscale.com/net/netcheck+
|
||||||
|
|
|
@ -272,6 +272,7 @@ tailscale.com/cmd/tailscaled dependencies: (generated by github.com/tailscale/de
|
||||||
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled
|
tailscale.com/types/flagtype from tailscale.com/cmd/tailscaled
|
||||||
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
tailscale.com/types/ipproto from tailscale.com/net/flowtrack+
|
||||||
tailscale.com/types/key from tailscale.com/control/controlbase+
|
tailscale.com/types/key from tailscale.com/control/controlbase+
|
||||||
|
tailscale.com/types/lazy from tailscale.com/version+
|
||||||
tailscale.com/types/logger from tailscale.com/control/controlclient+
|
tailscale.com/types/logger from tailscale.com/control/controlclient+
|
||||||
tailscale.com/types/logid from tailscale.com/logtail+
|
tailscale.com/types/logid from tailscale.com/logtail+
|
||||||
tailscale.com/types/netlogtype from tailscale.com/net/connstats+
|
tailscale.com/types/netlogtype from tailscale.com/net/connstats+
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"tailscale.com/syncs"
|
"tailscale.com/types/lazy"
|
||||||
"tailscale.com/util/lineread"
|
"tailscale.com/util/lineread"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -31,22 +31,20 @@ const (
|
||||||
WDMyCloud = Distro("wdmycloud")
|
WDMyCloud = Distro("wdmycloud")
|
||||||
)
|
)
|
||||||
|
|
||||||
var distroAtomic syncs.AtomicValue[Distro]
|
var distro lazy.SyncValue[Distro]
|
||||||
|
|
||||||
// Get returns the current distro, or the empty string if unknown.
|
// Get returns the current distro, or the empty string if unknown.
|
||||||
func Get() Distro {
|
func Get() Distro {
|
||||||
if d, ok := distroAtomic.LoadOk(); ok {
|
return distro.Get(func() Distro {
|
||||||
return d
|
|
||||||
}
|
|
||||||
var d Distro
|
|
||||||
switch runtime.GOOS {
|
switch runtime.GOOS {
|
||||||
case "linux":
|
case "linux":
|
||||||
d = linuxDistro()
|
return linuxDistro()
|
||||||
case "freebsd":
|
case "freebsd":
|
||||||
d = freebsdDistro()
|
return freebsdDistro()
|
||||||
|
default:
|
||||||
|
return Distro("")
|
||||||
}
|
}
|
||||||
distroAtomic.Store(d) // even if empty
|
})
|
||||||
return d
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func have(file string) bool {
|
func have(file string) bool {
|
||||||
|
@ -99,7 +97,7 @@ func freebsdDistro() Distro {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
var dsmVersion syncs.AtomicValue[int]
|
var dsmVersion lazy.SyncValue[int]
|
||||||
|
|
||||||
// DSMVersion reports the Synology DSM major version.
|
// DSMVersion reports the Synology DSM major version.
|
||||||
//
|
//
|
||||||
|
@ -108,16 +106,13 @@ func DSMVersion() int {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
return dsmVersion.Get(func() int {
|
||||||
if Get() != Synology {
|
if Get() != Synology {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if v, ok := dsmVersion.LoadOk(); ok && v != 0 {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
// This is set when running as a package:
|
// This is set when running as a package:
|
||||||
v, _ := strconv.Atoi(os.Getenv("SYNOPKG_DSM_VERSION_MAJOR"))
|
v, _ := strconv.Atoi(os.Getenv("SYNOPKG_DSM_VERSION_MAJOR"))
|
||||||
if v != 0 {
|
if v != 0 {
|
||||||
dsmVersion.Store(v)
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
// But when run from the command line, we have to read it from the file:
|
// But when run from the command line, we have to read it from the file:
|
||||||
|
@ -133,8 +128,6 @@ func DSMVersion() int {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
if v != 0 {
|
|
||||||
dsmVersion.Store(v)
|
|
||||||
}
|
|
||||||
return v
|
return v
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,25 +7,27 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"tailscale.com/types/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
func String() string {
|
var stringLazy = lazy.SyncFunc(func() string {
|
||||||
var ret strings.Builder
|
var ret strings.Builder
|
||||||
ret.WriteString(short)
|
ret.WriteString(Short())
|
||||||
ret.WriteByte('\n')
|
ret.WriteByte('\n')
|
||||||
if IsUnstableBuild() {
|
if IsUnstableBuild() {
|
||||||
fmt.Fprintf(&ret, " track: unstable (dev); frequent updates and bugs are likely\n")
|
fmt.Fprintf(&ret, " track: unstable (dev); frequent updates and bugs are likely\n")
|
||||||
}
|
}
|
||||||
if gitCommit != "" {
|
if gitCommit() != "" {
|
||||||
var dirty string
|
fmt.Fprintf(&ret, " tailscale commit: %s%s\n", gitCommit(), dirtyString())
|
||||||
if gitDirty {
|
|
||||||
dirty = "-dirty"
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&ret, " tailscale commit: %s%s\n", gitCommit, dirty)
|
if extraGitCommitStamp != "" {
|
||||||
}
|
fmt.Fprintf(&ret, " other commit: %s\n", extraGitCommitStamp)
|
||||||
if extraGitCommit != "" {
|
|
||||||
fmt.Fprintf(&ret, " other commit: %s\n", extraGitCommit)
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&ret, " go version: %s\n", runtime.Version())
|
fmt.Fprintf(&ret, " go version: %s\n", runtime.Version())
|
||||||
return strings.TrimSpace(ret.String())
|
return strings.TrimSpace(ret.String())
|
||||||
|
})
|
||||||
|
|
||||||
|
func String() string {
|
||||||
|
return stringLazy()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
|
"tailscale.com/types/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IsMobile reports whether this is a mobile client build.
|
// IsMobile reports whether this is a mobile client build.
|
||||||
|
@ -37,20 +37,7 @@ func OS() string {
|
||||||
return runtime.GOOS
|
return runtime.GOOS
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var isSandboxedMacOS lazy.SyncValue[bool]
|
||||||
macFlavorOnce sync.Once
|
|
||||||
isMacSysExt bool
|
|
||||||
isMacSandboxed bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func initMacFlavor() {
|
|
||||||
exe, err := os.Executable()
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
isMacSysExt = filepath.Base(exe) == "io.tailscale.ipn.macsys.network-extension"
|
|
||||||
isMacSandboxed = isMacSysExt || strings.HasSuffix(exe, "/Contents/MacOS/Tailscale") || strings.HasSuffix(exe, "/Contents/MacOS/IPNExtension")
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsSandboxedMacOS reports whether this process is a sandboxed macOS
|
// IsSandboxedMacOS reports whether this process is a sandboxed macOS
|
||||||
// process (either the app or the extension). It is true for the Mac App Store
|
// process (either the app or the extension). It is true for the Mac App Store
|
||||||
|
@ -60,9 +47,19 @@ func IsSandboxedMacOS() bool {
|
||||||
if runtime.GOOS != "darwin" {
|
if runtime.GOOS != "darwin" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
macFlavorOnce.Do(initMacFlavor)
|
return isSandboxedMacOS.Get(func() bool {
|
||||||
return isMacSandboxed
|
if IsMacSysExt() {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return filepath.Base(exe) == "io.tailscale.ipn.macsys.network-extension" || strings.HasSuffix(exe, "/Contents/MacOS/Tailscale") || strings.HasSuffix(exe, "/Contents/MacOS/IPNExtension")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var isMacSysExt lazy.SyncValue[bool]
|
||||||
|
|
||||||
// IsMacSysExt whether this binary is from the standalone "System
|
// IsMacSysExt whether this binary is from the standalone "System
|
||||||
// Extension" (a.k.a. "macsys") version of Tailscale for macOS.
|
// Extension" (a.k.a. "macsys") version of Tailscale for macOS.
|
||||||
|
@ -70,61 +67,57 @@ func IsMacSysExt() bool {
|
||||||
if runtime.GOOS != "darwin" {
|
if runtime.GOOS != "darwin" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
macFlavorOnce.Do(initMacFlavor)
|
return isMacSysExt.Get(func() bool {
|
||||||
return isMacSysExt
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
winFlavorOnce sync.Once
|
|
||||||
isWindowsGUI bool
|
|
||||||
)
|
|
||||||
|
|
||||||
func initWinFlavor() {
|
|
||||||
exe, err := os.Executable()
|
exe, err := os.Executable()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
isWindowsGUI = strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
|
return filepath.Base(exe) == "io.tailscale.ipn.macsys.network-extension"
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isWindowsGUI lazy.SyncValue[bool]
|
||||||
|
|
||||||
// IsWindowsGUI reports whether the current process is the Windows GUI.
|
// IsWindowsGUI reports whether the current process is the Windows GUI.
|
||||||
func IsWindowsGUI() bool {
|
func IsWindowsGUI() bool {
|
||||||
if runtime.GOOS != "windows" {
|
if runtime.GOOS != "windows" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
exe, _ := os.Executable()
|
return isWindowsGUI.Get(func() bool {
|
||||||
exe = filepath.Base(exe)
|
exe, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
|
return strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var isUnstableBuild lazy.SyncValue[bool]
|
||||||
isUnstableOnce sync.Once
|
|
||||||
isUnstableBuild bool
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsUnstableBuild reports whether this is an unstable build.
|
// IsUnstableBuild reports whether this is an unstable build.
|
||||||
// That is, whether its minor version number is odd.
|
// That is, whether its minor version number is odd.
|
||||||
func IsUnstableBuild() bool {
|
func IsUnstableBuild() bool {
|
||||||
isUnstableOnce.Do(initUnstable)
|
return isUnstableBuild.Get(func() bool {
|
||||||
return isUnstableBuild
|
_, rest, ok := strings.Cut(Short(), ".")
|
||||||
}
|
|
||||||
|
|
||||||
func initUnstable() {
|
|
||||||
_, rest, ok := strings.Cut(short, ".")
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
minorStr, _, ok := strings.Cut(rest, ".")
|
minorStr, _, ok := strings.Cut(rest, ".")
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
minor, err := strconv.Atoi(minorStr)
|
minor, err := strconv.Atoi(minorStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
isUnstableBuild = minor%2 == 1
|
return minor%2 == 1
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var isDev = lazy.SyncFunc(func() bool {
|
||||||
|
return strings.Contains(Short(), "-dev")
|
||||||
|
})
|
||||||
|
|
||||||
// Meta is a JSON-serializable type that contains all the version
|
// Meta is a JSON-serializable type that contains all the version
|
||||||
// information.
|
// information.
|
||||||
type Meta struct {
|
type Meta struct {
|
||||||
|
@ -183,16 +176,18 @@ type Meta struct {
|
||||||
Cap int `json:"cap"`
|
Cap int `json:"cap"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var getMeta lazy.SyncValue[Meta]
|
||||||
|
|
||||||
// GetMeta returns version metadata about the current build.
|
// GetMeta returns version metadata about the current build.
|
||||||
func GetMeta() Meta {
|
func GetMeta() Meta {
|
||||||
return Meta{
|
return Meta{
|
||||||
MajorMinorPatch: majorMinorPatch,
|
MajorMinorPatch: majorMinorPatch(),
|
||||||
Short: short,
|
Short: Short(),
|
||||||
Long: long,
|
Long: Long(),
|
||||||
GitCommit: gitCommit,
|
GitCommit: gitCommit(),
|
||||||
GitDirty: gitDirty,
|
GitDirty: gitDirty(),
|
||||||
ExtraGitCommit: extraGitCommit,
|
ExtraGitCommit: extraGitCommitStamp,
|
||||||
IsDev: strings.Contains(short, "-dev"), // TODO(bradfitz): could make a bool for this in init
|
IsDev: isDev(),
|
||||||
UnstableBranch: IsUnstableBuild(),
|
UnstableBranch: IsUnstableBuild(),
|
||||||
Cap: int(tailcfg.CurrentCapabilityVersion),
|
Cap: int(tailcfg.CurrentCapabilityVersion),
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,106 +5,160 @@
|
||||||
package version
|
package version
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
tailscaleroot "tailscale.com"
|
tailscaleroot "tailscale.com"
|
||||||
|
"tailscale.com/types/lazy"
|
||||||
)
|
)
|
||||||
|
|
||||||
var long = ""
|
// Stamp vars can have their value set at build time by linker flags (see
|
||||||
|
// build_dist.sh for an example). When set, these stamps serve as additional
|
||||||
|
// inputs to computing the binary's version as returned by the functions in this
|
||||||
|
// package.
|
||||||
|
//
|
||||||
|
// All stamps are optional.
|
||||||
|
var (
|
||||||
|
// longStamp is the full version identifier of the build. If set, it is
|
||||||
|
// returned verbatim by Long() and other functions that return Long()'s
|
||||||
|
// output.
|
||||||
|
longStamp string
|
||||||
|
|
||||||
var short = ""
|
// shortStamp is the short version identifier of the build. If set, it
|
||||||
|
// is returned verbatim by Short() and other functions that return Short()'s
|
||||||
|
// output.
|
||||||
|
shortStamp string
|
||||||
|
|
||||||
// Long is a full version number for this build, of the form
|
// gitCommitStamp is the git commit of the github.com/tailscale/tailscale
|
||||||
// "x.y.z-commithash" for builds stamped in the usual way (see
|
// repository at which Tailscale was built. Its format is the one returned
|
||||||
// build_dist.sh in the root) or, for binaries built by hand with the
|
// by `git rev-parse <commit>`. If set, it is used instead of any git commit
|
||||||
// go tool, it's of the form "1.23.0-dev20220316-t29837428937{,-dirty}"
|
// information embedded by the Go tool.
|
||||||
// where "1.23.0" comes from ../VERSION.txt and the part after dev
|
gitCommitStamp string
|
||||||
// is YYYYMMDD of the commit time, and the part after -t is the commit
|
|
||||||
// hash. The dirty suffix is whether there are uncommitted changes.
|
// gitDirtyStamp is whether the git checkout from which the code was built
|
||||||
|
// was dirty. Its value is ORed with the dirty bit embedded by the Go tool.
|
||||||
|
//
|
||||||
|
// We need this because when we build binaries from another repo that
|
||||||
|
// imports tailscale.com, the Go tool doesn't stamp any dirtiness info into
|
||||||
|
// the binary. Instead, we have to inject the dirty bit ourselves here.
|
||||||
|
gitDirtyStamp bool
|
||||||
|
|
||||||
|
// extraGitCommit, is the git commit of a "supplemental" repository at which
|
||||||
|
// Tailscale was built. Its format is the same as gitCommit.
|
||||||
|
//
|
||||||
|
// extraGitCommit is used to track the source revision when the main
|
||||||
|
// Tailscale repository is integrated into and built from another repository
|
||||||
|
// (for example, Tailscale's proprietary code, or the Android OSS
|
||||||
|
// repository). Together, gitCommit and extraGitCommit exactly describe what
|
||||||
|
// repositories and commits were used in a build.
|
||||||
|
extraGitCommitStamp string
|
||||||
|
)
|
||||||
|
|
||||||
|
var long lazy.SyncValue[string]
|
||||||
|
|
||||||
|
// Long returns a full version number for this build, of one of the forms:
|
||||||
|
//
|
||||||
|
// - "x.y.z-commithash-otherhash" for release builds distributed by Tailscale
|
||||||
|
// - "x.y.z-commithash" for release builds built with build_dist.sh
|
||||||
|
// - "x.y.z-changecount-commithash-otherhash" for untagged release branch
|
||||||
|
// builds by Tailscale (these are not distributed).
|
||||||
|
// - "x.y.z-changecount-commithash" for untagged release branch builds
|
||||||
|
// built with build_dist.sh
|
||||||
|
// - "x.y.z-devYYYYMMDD-commithash{,-dirty}" for builds made with plain "go
|
||||||
|
// build" or "go install"
|
||||||
|
// - "x.y.z-ERR-BuildInfo" for builds made by plain "go run"
|
||||||
func Long() string {
|
func Long() string {
|
||||||
return long
|
return long.Get(func() string {
|
||||||
|
if longStamp != "" {
|
||||||
|
return longStamp
|
||||||
|
}
|
||||||
|
bi := getEmbeddedInfo()
|
||||||
|
if !bi.valid {
|
||||||
|
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-ERR-BuildInfo"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s-dev%s-t%s%s", strings.TrimSpace(tailscaleroot.VersionDotTxt), bi.commitDate, bi.commitAbbrev(), dirtyString())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short is a short version number for this build, of the form
|
var short lazy.SyncValue[string]
|
||||||
// "x.y.z" for builds stamped in the usual way (see
|
|
||||||
// build_dist.sh in the root) or, for binaries built by hand with the
|
// Short returns a short version number for this build, of the forms:
|
||||||
// go tool, it's like Long's dev form, but ending at the date part,
|
//
|
||||||
// of the form "1.23.0-dev20220316".
|
// - "x.y.z" for builds distributed by Tailscale or built with build_dist.sh
|
||||||
|
// - "x.y.z-devYYYYMMDD" for builds made with plain "go build" or "go install"
|
||||||
|
// - "x.y.z-ERR-BuildInfo" for builds made by plain "go run"
|
||||||
func Short() string {
|
func Short() string {
|
||||||
return short
|
return short.Get(func() string {
|
||||||
|
if shortStamp != "" {
|
||||||
|
return shortStamp
|
||||||
|
}
|
||||||
|
bi := getEmbeddedInfo()
|
||||||
|
if !bi.valid {
|
||||||
|
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-ERR-BuildInfo"
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-dev" + bi.commitDate
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
type embeddedInfo struct {
|
||||||
defer func() {
|
valid bool
|
||||||
// Must be run after Short has been initialized, easiest way to do that
|
commit string
|
||||||
// is a defer.
|
commitDate string
|
||||||
majorMinorPatch, _, _ = strings.Cut(short, "-")
|
dirty bool
|
||||||
}()
|
|
||||||
|
|
||||||
if long != "" && short != "" {
|
|
||||||
// Built in the recommended way, using build_dist.sh.
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, make approximate version info using Go 1.18's built-in git
|
func (i embeddedInfo) commitAbbrev() string {
|
||||||
// stamping.
|
if len(i.commit) >= 9 {
|
||||||
|
return i.commit[:9]
|
||||||
|
}
|
||||||
|
return i.commit
|
||||||
|
}
|
||||||
|
|
||||||
|
var getEmbeddedInfo = lazy.SyncFunc(func() embeddedInfo {
|
||||||
bi, ok := debug.ReadBuildInfo()
|
bi, ok := debug.ReadBuildInfo()
|
||||||
if !ok {
|
if !ok {
|
||||||
long = strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-ERR-BuildInfo"
|
return embeddedInfo{}
|
||||||
short = long
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var dirty string // "-dirty" suffix if dirty
|
ret := embeddedInfo{valid: true}
|
||||||
var commitDate string
|
|
||||||
for _, s := range bi.Settings {
|
for _, s := range bi.Settings {
|
||||||
switch s.Key {
|
switch s.Key {
|
||||||
case "vcs.revision":
|
case "vcs.revision":
|
||||||
gitCommit = s.Value
|
ret.commit = s.Value
|
||||||
case "vcs.time":
|
case "vcs.time":
|
||||||
if len(s.Value) >= len("yyyy-mm-dd") {
|
if len(s.Value) >= len("yyyy-mm-dd") {
|
||||||
commitDate = s.Value[:len("yyyy-mm-dd")]
|
ret.commitDate = s.Value[:len("yyyy-mm-dd")]
|
||||||
commitDate = strings.ReplaceAll(commitDate, "-", "")
|
ret.commitDate = strings.ReplaceAll(ret.commitDate, "-", "")
|
||||||
}
|
}
|
||||||
case "vcs.modified":
|
case "vcs.modified":
|
||||||
if s.Value == "true" {
|
ret.dirty = true
|
||||||
dirty = "-dirty"
|
|
||||||
gitDirty = true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ret
|
||||||
|
})
|
||||||
|
|
||||||
|
func gitCommit() string {
|
||||||
|
if gitCommitStamp != "" {
|
||||||
|
return gitCommitStamp
|
||||||
}
|
}
|
||||||
commitHashAbbrev := gitCommit
|
return getEmbeddedInfo().commit
|
||||||
if len(commitHashAbbrev) >= 9 {
|
|
||||||
commitHashAbbrev = commitHashAbbrev[:9]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backup path, using Go 1.18's built-in git stamping.
|
func gitDirty() bool {
|
||||||
short = strings.TrimSpace(tailscaleroot.VersionDotTxt) + "-dev" + commitDate
|
if gitDirtyStamp {
|
||||||
long = short + "-t" + commitHashAbbrev + dirty
|
return true
|
||||||
|
}
|
||||||
|
return getEmbeddedInfo().dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
// GitCommit, if non-empty, is the git commit of the
|
func dirtyString() string {
|
||||||
// github.com/tailscale/tailscale repository at which Tailscale was
|
if gitDirty() {
|
||||||
// built. Its format is the one returned by `git describe --always
|
return "-dirty"
|
||||||
// --exclude "*" --dirty --abbrev=200`.
|
}
|
||||||
var gitCommit = ""
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
// GitDirty is whether Go stamped the binary as having dirty version
|
func majorMinorPatch() string {
|
||||||
// control changes in the working directory (debug.ReadBuildInfo
|
ret, _, _ := strings.Cut(Short(), "-")
|
||||||
// setting "vcs.modified" was true).
|
return ret
|
||||||
var gitDirty bool
|
}
|
||||||
|
|
||||||
// ExtraGitCommit, if non-empty, is the git commit of a "supplemental"
|
|
||||||
// repository at which Tailscale was built. Its format is the same as
|
|
||||||
// gitCommit.
|
|
||||||
//
|
|
||||||
// ExtraGitCommit is used to track the source revision when the main
|
|
||||||
// Tailscale repository is integrated into and built from another
|
|
||||||
// repository (for example, Tailscale's proprietary code, or the
|
|
||||||
// Android OSS repository). Together, GitCommit and ExtraGitCommit
|
|
||||||
// exactly describe what repositories and commits were used in a
|
|
||||||
// build.
|
|
||||||
var extraGitCommit = ""
|
|
||||||
|
|
||||||
// majorMinorPatch is the major.minor.patch portion of Short.
|
|
||||||
var majorMinorPatch string
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
ts "tailscale.com"
|
ts "tailscale.com"
|
||||||
|
"tailscale.com/version"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAlpineTag(t *testing.T) {
|
func TestAlpineTag(t *testing.T) {
|
||||||
|
@ -39,3 +40,12 @@ func readAlpineTag(t *testing.T, file string) string {
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestShortAllocs(t *testing.T) {
|
||||||
|
allocs := int(testing.AllocsPerRun(10000, func() {
|
||||||
|
_ = version.Short()
|
||||||
|
}))
|
||||||
|
if allocs > 0 {
|
||||||
|
t.Errorf("allocs = %v; want 0", allocs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue