-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
prop.go
194 lines (168 loc) · 5.85 KB
/
prop.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
// Copyright (c) Tailscale Inc & AUTHORS
// SPDX-License-Identifier: BSD-3-Clause
package version
import (
"os"
"path/filepath"
"runtime"
"strconv"
"strings"
"tailscale.com/tailcfg"
"tailscale.com/types/lazy"
)
// IsMobile reports whether this is a mobile client build.
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 isSandboxedMacOS lazy.SyncValue[bool]
// IsSandboxedMacOS reports whether this process is a sandboxed macOS
// 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
// tailscaled-on-macOS.
func IsSandboxedMacOS() bool {
if runtime.GOOS != "darwin" {
return false
}
return isSandboxedMacOS.Get(func() bool {
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
// Extension" (a.k.a. "macsys") version of Tailscale for macOS.
func IsMacSysExt() bool {
if runtime.GOOS != "darwin" {
return false
}
return isMacSysExt.Get(func() bool {
exe, err := os.Executable()
if err != nil {
return false
}
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.
func IsWindowsGUI() bool {
if runtime.GOOS != "windows" {
return false
}
return isWindowsGUI.Get(func() bool {
exe, err := os.Executable()
if err != nil {
return false
}
return strings.EqualFold(exe, "tailscale-ipn.exe") || strings.EqualFold(exe, "tailscale-ipn")
})
}
var isUnstableBuild lazy.SyncValue[bool]
// IsUnstableBuild reports whether this is an unstable build.
// That is, whether its minor version number is odd.
func IsUnstableBuild() bool {
return isUnstableBuild.Get(func() bool {
_, rest, ok := strings.Cut(Short(), ".")
if !ok {
return false
}
minorStr, _, ok := strings.Cut(rest, ".")
if !ok {
return false
}
minor, err := strconv.Atoi(minorStr)
if err != nil {
return false
}
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
// information.
type Meta struct {
// MajorMinorPatch is the "major.minor.patch" version string, without
// any hyphenated suffix.
MajorMinorPatch string `json:"majorMinorPatch"`
// IsDev is whether Short contains a -dev suffix. This is whether the build
// is a development build (as opposed to an official stable or unstable
// build stamped in the usual ways). If you just run "go install" or "go
// build" on a dev branch, this will be true.
IsDev bool `json:"isDev,omitempty"`
// Short is MajorMinorPatch but optionally adding "-dev" or "-devYYYYMMDD"
// for dev builds, depending on how it was build.
Short string `json:"short"`
// Long is the full version string, including git commit hash(es) as the
// suffix.
Long string `json:"long"`
// UnstableBranch is whether the build is from an unstable (development)
// branch. That is, it reports whether the minor version is odd.
UnstableBranch bool `json:"unstableBranch,omitempty"`
// 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 `json:"gitCommit,omitempty"`
// 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 `json:"gitDirty,omitempty"`
// 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 string `json:"extraGitCommit,omitempty"`
// DaemonLong is the version number from the tailscaled
// daemon, if requested.
DaemonLong string `json:"daemonLong,omitempty"`
// Cap is the current Tailscale capability version. It's a monotonically
// incrementing integer that's incremented whenever a new capability is
// added.
Cap int `json:"cap"`
}
var getMeta lazy.SyncValue[Meta]
// GetMeta returns version metadata about the current build.
func GetMeta() Meta {
return Meta{
MajorMinorPatch: majorMinorPatch(),
Short: Short(),
Long: Long(),
GitCommit: gitCommit(),
GitDirty: gitDirty(),
ExtraGitCommit: extraGitCommitStamp,
IsDev: isDev(),
UnstableBranch: IsUnstableBuild(),
Cap: int(tailcfg.CurrentCapabilityVersion),
}
}