version: undo previous "optimization", do more work lazily

Commit 59c254579e moved a lot of work
from functions that could be eliminated at compile time (because
tests against runtime.GOOS are compile-time constant), into code
that must always run before main().

So, revert that, and instead optimize the package only by moving the
remaining string processing code behind sync.Onces.

Signed-off-by: David Anderson <danderson@tailscale.com>
pull/7253/head
David Anderson 1 year ago committed by Dave Anderson
parent 2ca6dd1f1d
commit 9ad36d17a3

@ -4,34 +4,126 @@
package version package version
import ( import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings" "strings"
"sync"
"tailscale.com/tailcfg" "tailscale.com/tailcfg"
) )
// IsMobile reports whether this is a mobile client build. // IsMobile reports whether this is a mobile client build.
func IsMobile() bool { return isMobile } func IsMobile() bool {
return runtime.GOOS == "android" || runtime.GOOS == "ios"
}
// OS returns runtime.GOOS, except instead of returning "darwin" it returns
// "iOS" or "macOS".
func OS() string {
// If you're wondering why we have this function that just returns
// runtime.GOOS written differently: in the old days, Go reported
// GOOS=darwin for both iOS and macOS, so we needed this function to
// differentiate them. Then a later Go release added GOOS=ios as a separate
// platform, but by then the "iOS" and "macOS" values we'd picked, with that
// exact capitalization, were already baked into databases.
if runtime.GOOS == "ios" {
return "iOS"
}
if runtime.GOOS == "darwin" {
return "macOS"
}
return runtime.GOOS
}
var (
macFlavorOnce sync.Once
isMacSysExt bool
isMacSandboxed bool
)
// OS returns runtime.GOOS, except instead of returning "darwin" it func initMacFlavor() {
// returns "iOS" or "macOS". exe, err := os.Executable()
func OS() string { return legacyOS } 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
// and macsys (System Extension) version on macOS, and false for // and macsys (System Extension) version on macOS, and false for
// tailscaled-on-macOS. // tailscaled-on-macOS.
func IsSandboxedMacOS() bool { return isSandboxedMacOS } func IsSandboxedMacOS() bool {
if runtime.GOOS != "darwin" {
return false
}
macFlavorOnce.Do(initMacFlavor)
return isMacSandboxed
}
// 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.
func IsMacSysExt() bool { return isMacSysExt } func IsMacSysExt() bool {
if runtime.GOOS != "darwin" {
return false
}
macFlavorOnce.Do(initMacFlavor)
return isMacSysExt
}
var (
winFlavorOnce sync.Once
isWindowsGUI bool
)
func initWinFlavor() {
exe, err := os.Executable()
if err != nil {
return
}
isWindowsGUI = strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
}
// IsWindowsGUI reports whether the current process is the Windows GUI. // IsWindowsGUI reports whether the current process is the Windows GUI.
func IsWindowsGUI() bool { return isWindowsGUI } func IsWindowsGUI() bool {
if runtime.GOOS != "windows" {
return false
}
exe, _ := os.Executable()
exe = filepath.Base(exe)
return strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
}
var (
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 { return isUnstable } func IsUnstableBuild() bool {
isUnstableOnce.Do(initUnstable)
return isUnstableBuild
}
func initUnstable() {
_, rest, ok := strings.Cut(Short, ".")
if !ok {
return
}
minorStr, _, ok := strings.Cut(rest, ".")
if !ok {
return
}
minor, err := strconv.Atoi(minorStr)
if err != nil {
return
}
isUnstableBuild = minor%2 == 1
}
// Meta is a JSON-serializable type that contains all the version // Meta is a JSON-serializable type that contains all the version
// information. // information.

@ -5,93 +5,29 @@
package version package version
import ( import (
"os"
"path/filepath"
"runtime"
"runtime/debug" "runtime/debug"
"strconv"
"strings" "strings"
tailscaleroot "tailscale.com" tailscaleroot "tailscale.com"
) )
var ( // Long is a full version number for this build, of the form
// Long is a full version number for this build, of the form // "x.y.z-commithash" for builds stamped in the usual way (see
// "x.y.z-commithash" for builds stamped in the usual way (see build_dist.sh // build_dist.sh in the root) or, for binaries built by hand with the
// in the root) or, for binaries built by hand with the go tool, it's of the // go tool, it's of the form "1.23.0-dev20220316-t29837428937{,-dirty}"
// form "1.23.0-dev20220316-t29837428937{,-dirty}" where "1.23.0" comes from // where "1.23.0" comes from ../VERSION.txt and the part after dev
// ../VERSION.txt and the part after dev is YYYYMMDD of the commit time, and // is YYYYMMDD of the commit time, and the part after -t is the commit
// the part after -t is the commit hash. The dirty suffix is whether there // hash. The dirty suffix is whether there are uncommitted changes.
// are uncommitted changes. var Long = ""
Long string
// Short is a short version number for this build, of the form
// Short is a short version number for this build, of the form // "x.y.z" for builds stamped in the usual way (see
// "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
// build_dist.sh in the root) or, for binaries built by hand with the // go tool, it's like Long's dev form, but ending at the date part,
// go tool, it's like Long's dev form, but ending at the date part, // of the form "1.23.0-dev20220316".
// of the form "1.23.0-dev20220316". var Short = ""
Short string
// GitCommit, if non-empty, is the git commit of the
// github.com/tailscale/tailscale repository at which Tailscale was
// built. Its format is the one returned by `git describe --always
// --exclude "*" --dirty --abbrev=200`.
GitCommit string
// GitDirty is whether Go stamped the binary as having dirty version
// control changes in the working directory (debug.ReadBuildInfo
// setting "vcs.modified" was true).
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.
ExtraGitCommit = ""
// isUnstable is whether the current build appears to be an unstable, i.e. with
// an odd minor version number.
isUnstable bool
// legacyOS is runtime.GOOS, except on apple devices where it's either "iOS" or
// "macOS" (with that exact case).
//
// This used to be a thing because Go reported both macOS and iOS as "darwin"
// and we needed to tell them apart. But then Go learned GOOS=ios and
// GOOS=darwin as separate things, but we're still stuck with this function
// because of the odd casing we picked, which has ossified into databases.
legacyOS string
// isMobile is whether the current build is for a mobile device.
isMobile bool
// isSandboxedMacOS is whether the current binary is any binary in the mac store
// or standalone sysext mac apps.
isSandboxedMacOS bool
// isMacSysExt is whether the current binary is the mac system extension binary.
isMacSysExt bool
// isWindowsGUI is whether the current binary is the Windows GUI binary.
isWindowsGUI bool
// majorMinorPatch is the major.minor.patch portion of Short.
majorMinorPatch string
)
func init() { func init() {
initVersion()
initUnstable()
initMiscTraits()
}
func initVersion() {
defer func() { defer func() {
// Must be run after Short has been initialized, easiest way to do that // Must be run after Short has been initialized, easiest way to do that
// is a defer. // is a defer.
@ -139,38 +75,28 @@ func initVersion() {
Long = Short + "-t" + commitHashAbbrev + dirty Long = Short + "-t" + commitHashAbbrev + dirty
} }
func initUnstable() { // GitCommit, if non-empty, is the git commit of the
_, rest, ok := strings.Cut(Short, ".") // github.com/tailscale/tailscale repository at which Tailscale was
if !ok { // built. Its format is the one returned by `git describe --always
return // --exclude "*" --dirty --abbrev=200`.
} var GitCommit = ""
minorStr, _, ok := strings.Cut(rest, ".")
if !ok { // GitDirty is whether Go stamped the binary as having dirty version
return // control changes in the working directory (debug.ReadBuildInfo
} // setting "vcs.modified" was true).
minor, err := strconv.Atoi(minorStr) var GitDirty bool
if err != nil {
return // ExtraGitCommit, if non-empty, is the git commit of a "supplemental"
} // repository at which Tailscale was built. Its format is the same as
isUnstable = minor%2 == 1 // gitCommit.
} //
// ExtraGitCommit is used to track the source revision when the main
func initMiscTraits() { // Tailscale repository is integrated into and built from another
exe, _ := os.Executable() // repository (for example, Tailscale's proprietary code, or the
base := filepath.Base(exe) // Android OSS repository). Together, GitCommit and ExtraGitCommit
// exactly describe what repositories and commits were used in a
legacyOS = runtime.GOOS // build.
switch runtime.GOOS { var ExtraGitCommit = ""
case "darwin":
legacyOS = "macOS" // majorMinorPatch is the major.minor.patch portion of Short.
isMacSysExt = strings.HasPrefix(base, "io.tailscale.ipn.macsys.network-extension") var majorMinorPatch string
isSandboxedMacOS = isMacSysExt || strings.HasSuffix(exe, "/Contents/MacOS/Tailscale") || strings.HasSuffix(exe, "/Contents/MacOS/IPNExtension")
case "ios":
legacyOS = "iOS"
isMobile = true
case "android":
isMobile = true
case "windows":
isWindowsGUI = strings.EqualFold(base, "tailscale-ipn.exe") || strings.EqualFold(base, "tailscale-ipn")
}
}

Loading…
Cancel
Save