summaryrefslogtreecommitdiffhomepage
path: root/version
diff options
context:
space:
mode:
authorNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
committerNick Khyl <nickk@tailscale.com>2024-12-05 13:16:48 -0600
commit0267fe83b200f1702a2fa0a395442c02a053fadb (patch)
tree63654c55225eeb834de59a5a0bc8d19033c6145b /version
parent87546a5edf6b6503a87eeb2d666baba57398a066 (diff)
downloadtailscale-1.78.0.tar.xz
tailscale-1.78.0.zip
VERSION.txt: this is v1.78.0v1.78.0
Signed-off-by: Nick Khyl <nickk@tailscale.com>
Diffstat (limited to 'version')
-rw-r--r--version/.gitignore20
-rw-r--r--version/cmdname.go278
-rw-r--r--version/cmdname_ios.go36
-rw-r--r--version/cmp_test.go164
-rw-r--r--version/export_test.go28
-rw-r--r--version/print.go66
-rw-r--r--version/race.go20
-rw-r--r--version/race_off.go20
-rw-r--r--version/version_test.go102
9 files changed, 367 insertions, 367 deletions
diff --git a/version/.gitignore b/version/.gitignore
index 58d19bfc2..8878450fa 100644
--- a/version/.gitignore
+++ b/version/.gitignore
@@ -1,10 +1,10 @@
-describe.txt
-long.txt
-short.txt
-gitcommit.txt
-extragitcommit.txt
-version-info.sh
-version.h
-version.xcconfig
-ver.go
-version
+describe.txt
+long.txt
+short.txt
+gitcommit.txt
+extragitcommit.txt
+version-info.sh
+version.h
+version.xcconfig
+ver.go
+version
diff --git a/version/cmdname.go b/version/cmdname.go
index 51e065438..9f85ef96d 100644
--- a/version/cmdname.go
+++ b/version/cmdname.go
@@ -1,139 +1,139 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !ios
-
-package version
-
-import (
- "bytes"
- "encoding/hex"
- "errors"
- "io"
- "os"
- "path"
- "path/filepath"
- "strings"
-)
-
-// CmdName returns either the base name of the current binary
-// using os.Executable. If os.Executable fails (it shouldn't), then
-// "cmd" is returned.
-func CmdName() string {
- e, err := os.Executable()
- if err != nil {
- return "cmd"
- }
- return cmdName(e)
-}
-
-func cmdName(exe string) string {
- // fallbackName, the lowercase basename of the executable, is what we return if
- // we can't find the Go module metadata embedded in the file.
- fallbackName := filepath.Base(strings.TrimSuffix(strings.ToLower(exe), ".exe"))
-
- var ret string
- info, err := findModuleInfo(exe)
- if err != nil {
- return fallbackName
- }
- // v is like:
- // "path\ttailscale.com/cmd/tailscale\nmod\ttailscale.com\t(devel)\t\ndep\tgithub.com/apenwarr/fixconsole\tv0.0.0-20191012055117-5a9f6489cc29\th1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=\ndep\tgithub....
- for _, line := range strings.Split(info, "\n") {
- if goPkg, ok := strings.CutPrefix(line, "path\t"); ok { // like "tailscale.com/cmd/tailscale"
- ret = path.Base(goPkg) // goPkg is always forward slashes; use path, not filepath
- break
- }
- }
- if strings.HasPrefix(ret, "wg") && fallbackName == "tailscale-ipn" {
- // The tailscale-ipn.exe binary for internal build system packaging reasons
- // has a path of "tailscale.io/win/wg64", "tailscale.io/win/wg32", etc.
- // Ignore that name and use "tailscale-ipn" instead.
- return fallbackName
- }
- if ret == "" {
- return fallbackName
- }
- return ret
-}
-
-// findModuleInfo returns the Go module info from the executable file.
-func findModuleInfo(file string) (s string, err error) {
- f, err := os.Open(file)
- if err != nil {
- return "", err
- }
- defer f.Close()
- // Scan through f until we find infoStart.
- buf := make([]byte, 65536)
- start, err := findOffset(f, buf, infoStart)
- if err != nil {
- return "", err
- }
- start += int64(len(infoStart))
- // Seek to the end of infoStart and scan for infoEnd.
- _, err = f.Seek(start, io.SeekStart)
- if err != nil {
- return "", err
- }
- end, err := findOffset(f, buf, infoEnd)
- if err != nil {
- return "", err
- }
- length := end - start
- // As of Aug 2021, tailscaled's mod info was about 2k.
- if length > int64(len(buf)) {
- return "", errors.New("mod info too large")
- }
- // We have located modinfo. Read it into buf.
- buf = buf[:length]
- _, err = f.Seek(start, io.SeekStart)
- if err != nil {
- return "", err
- }
- _, err = io.ReadFull(f, buf)
- if err != nil {
- return "", err
- }
- return string(buf), nil
-}
-
-// findOffset finds the absolute offset of needle in f,
-// starting at f's current read position,
-// using temporary buffer buf.
-func findOffset(f *os.File, buf, needle []byte) (int64, error) {
- for {
- // Fill buf and look within it.
- n, err := f.Read(buf)
- if err != nil {
- return -1, err
- }
- i := bytes.Index(buf[:n], needle)
- if i < 0 {
- // Not found. Rewind a little bit in case we happened to end halfway through needle.
- rewind, err := f.Seek(int64(-len(needle)), io.SeekCurrent)
- if err != nil {
- return -1, err
- }
- // If we're at EOF and rewound exactly len(needle) bytes, return io.EOF.
- _, err = f.ReadAt(buf[:1], rewind+int64(len(needle)))
- if err == io.EOF {
- return -1, err
- }
- continue
- }
- // Found! Figure out exactly where.
- cur, err := f.Seek(0, io.SeekCurrent)
- if err != nil {
- return -1, err
- }
- return cur - int64(n) + int64(i), nil
- }
-}
-
-// These constants are taken from rsc.io/goversion.
-
-var (
- infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
- infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
-)
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !ios
+
+package version
+
+import (
+ "bytes"
+ "encoding/hex"
+ "errors"
+ "io"
+ "os"
+ "path"
+ "path/filepath"
+ "strings"
+)
+
+// CmdName returns either the base name of the current binary
+// using os.Executable. If os.Executable fails (it shouldn't), then
+// "cmd" is returned.
+func CmdName() string {
+ e, err := os.Executable()
+ if err != nil {
+ return "cmd"
+ }
+ return cmdName(e)
+}
+
+func cmdName(exe string) string {
+ // fallbackName, the lowercase basename of the executable, is what we return if
+ // we can't find the Go module metadata embedded in the file.
+ fallbackName := filepath.Base(strings.TrimSuffix(strings.ToLower(exe), ".exe"))
+
+ var ret string
+ info, err := findModuleInfo(exe)
+ if err != nil {
+ return fallbackName
+ }
+ // v is like:
+ // "path\ttailscale.com/cmd/tailscale\nmod\ttailscale.com\t(devel)\t\ndep\tgithub.com/apenwarr/fixconsole\tv0.0.0-20191012055117-5a9f6489cc29\th1:muXWUcay7DDy1/hEQWrYlBy+g0EuwT70sBHg65SeUc4=\ndep\tgithub....
+ for _, line := range strings.Split(info, "\n") {
+ if goPkg, ok := strings.CutPrefix(line, "path\t"); ok { // like "tailscale.com/cmd/tailscale"
+ ret = path.Base(goPkg) // goPkg is always forward slashes; use path, not filepath
+ break
+ }
+ }
+ if strings.HasPrefix(ret, "wg") && fallbackName == "tailscale-ipn" {
+ // The tailscale-ipn.exe binary for internal build system packaging reasons
+ // has a path of "tailscale.io/win/wg64", "tailscale.io/win/wg32", etc.
+ // Ignore that name and use "tailscale-ipn" instead.
+ return fallbackName
+ }
+ if ret == "" {
+ return fallbackName
+ }
+ return ret
+}
+
+// findModuleInfo returns the Go module info from the executable file.
+func findModuleInfo(file string) (s string, err error) {
+ f, err := os.Open(file)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ // Scan through f until we find infoStart.
+ buf := make([]byte, 65536)
+ start, err := findOffset(f, buf, infoStart)
+ if err != nil {
+ return "", err
+ }
+ start += int64(len(infoStart))
+ // Seek to the end of infoStart and scan for infoEnd.
+ _, err = f.Seek(start, io.SeekStart)
+ if err != nil {
+ return "", err
+ }
+ end, err := findOffset(f, buf, infoEnd)
+ if err != nil {
+ return "", err
+ }
+ length := end - start
+ // As of Aug 2021, tailscaled's mod info was about 2k.
+ if length > int64(len(buf)) {
+ return "", errors.New("mod info too large")
+ }
+ // We have located modinfo. Read it into buf.
+ buf = buf[:length]
+ _, err = f.Seek(start, io.SeekStart)
+ if err != nil {
+ return "", err
+ }
+ _, err = io.ReadFull(f, buf)
+ if err != nil {
+ return "", err
+ }
+ return string(buf), nil
+}
+
+// findOffset finds the absolute offset of needle in f,
+// starting at f's current read position,
+// using temporary buffer buf.
+func findOffset(f *os.File, buf, needle []byte) (int64, error) {
+ for {
+ // Fill buf and look within it.
+ n, err := f.Read(buf)
+ if err != nil {
+ return -1, err
+ }
+ i := bytes.Index(buf[:n], needle)
+ if i < 0 {
+ // Not found. Rewind a little bit in case we happened to end halfway through needle.
+ rewind, err := f.Seek(int64(-len(needle)), io.SeekCurrent)
+ if err != nil {
+ return -1, err
+ }
+ // If we're at EOF and rewound exactly len(needle) bytes, return io.EOF.
+ _, err = f.ReadAt(buf[:1], rewind+int64(len(needle)))
+ if err == io.EOF {
+ return -1, err
+ }
+ continue
+ }
+ // Found! Figure out exactly where.
+ cur, err := f.Seek(0, io.SeekCurrent)
+ if err != nil {
+ return -1, err
+ }
+ return cur - int64(n) + int64(i), nil
+ }
+}
+
+// These constants are taken from rsc.io/goversion.
+
+var (
+ infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
+ infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
+)
diff --git a/version/cmdname_ios.go b/version/cmdname_ios.go
index 6bfed38b6..5e338944c 100644
--- a/version/cmdname_ios.go
+++ b/version/cmdname_ios.go
@@ -1,18 +1,18 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build ios
-
-package version
-
-import (
- "os"
-)
-
-func CmdName() string {
- e, err := os.Executable()
- if err != nil {
- return "cmd"
- }
- return e
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build ios
+
+package version
+
+import (
+ "os"
+)
+
+func CmdName() string {
+ e, err := os.Executable()
+ if err != nil {
+ return "cmd"
+ }
+ return e
+}
diff --git a/version/cmp_test.go b/version/cmp_test.go
index e244d5e16..59153f0dd 100644
--- a/version/cmp_test.go
+++ b/version/cmp_test.go
@@ -1,82 +1,82 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package version_test
-
-import (
- "testing"
-
- "github.com/google/go-cmp/cmp"
- "tailscale.com/tstest"
- "tailscale.com/version"
-)
-
-func TestParse(t *testing.T) {
- parse := version.ExportParse
- type parsed = version.ExportParsed
-
- tests := []struct {
- version string
- parsed parsed
- want bool
- }{
- {"1", parsed{Major: 1}, true},
- {"1.2", parsed{Major: 1, Minor: 2}, true},
- {"1.2.3", parsed{Major: 1, Minor: 2, Patch: 3}, true},
- {"1.2.3-4", parsed{Major: 1, Minor: 2, Patch: 3, ExtraCommits: 4}, true},
- {"1.2-4", parsed{Major: 1, Minor: 2, ExtraCommits: 4}, true},
- {"1.2.3-4-extra", parsed{Major: 1, Minor: 2, Patch: 3, ExtraCommits: 4}, true},
- {"1.2.3-4a-test", parsed{Major: 1, Minor: 2, Patch: 3}, true},
- {"1.2-extra", parsed{Major: 1, Minor: 2}, true},
- {"1.2.3-extra", parsed{Major: 1, Minor: 2, Patch: 3}, true},
- {"date.20200612", parsed{Datestamp: 20200612}, true},
- {"borkbork", parsed{}, false},
- {"1a.2.3", parsed{}, false},
- {"", parsed{}, false},
- }
-
- for _, test := range tests {
- gotParsed, got := parse(test.version)
- if got != test.want {
- t.Errorf("version(%q) = %v, want %v", test.version, got, test.want)
- }
- if diff := cmp.Diff(gotParsed, test.parsed); diff != "" {
- t.Errorf("parse(%q) diff (-got+want):\n%s", test.version, diff)
- }
- err := tstest.MinAllocsPerRun(t, 0, func() {
- gotParsed, got = parse(test.version)
- })
- if err != nil {
- t.Errorf("parse(%q): %v", test.version, err)
- }
- }
-}
-
-func TestAtLeast(t *testing.T) {
- tests := []struct {
- v, m string
- want bool
- }{
- {"1", "1", true},
- {"1.2", "1", true},
- {"1.2.3", "1", true},
- {"1.2.3-4", "1", true},
- {"0.98-0", "0.98", true},
- {"0.97.1-216", "0.98", false},
- {"0.94", "0.98", false},
- {"0.98", "0.98", true},
- {"0.98.0-0", "0.98", true},
- {"1.2.3-4", "1.2.4-4", false},
- {"1.2.3-4", "1.2.3-4", true},
- {"date.20200612", "date.20200612", true},
- {"date.20200701", "date.20200612", true},
- {"date.20200501", "date.20200612", false},
- }
-
- for _, test := range tests {
- got := version.AtLeast(test.v, test.m)
- if got != test.want {
- t.Errorf("AtLeast(%q, %q) = %v, want %v", test.v, test.m, got, test.want)
- }
- }
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package version_test
+
+import (
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+ "tailscale.com/tstest"
+ "tailscale.com/version"
+)
+
+func TestParse(t *testing.T) {
+ parse := version.ExportParse
+ type parsed = version.ExportParsed
+
+ tests := []struct {
+ version string
+ parsed parsed
+ want bool
+ }{
+ {"1", parsed{Major: 1}, true},
+ {"1.2", parsed{Major: 1, Minor: 2}, true},
+ {"1.2.3", parsed{Major: 1, Minor: 2, Patch: 3}, true},
+ {"1.2.3-4", parsed{Major: 1, Minor: 2, Patch: 3, ExtraCommits: 4}, true},
+ {"1.2-4", parsed{Major: 1, Minor: 2, ExtraCommits: 4}, true},
+ {"1.2.3-4-extra", parsed{Major: 1, Minor: 2, Patch: 3, ExtraCommits: 4}, true},
+ {"1.2.3-4a-test", parsed{Major: 1, Minor: 2, Patch: 3}, true},
+ {"1.2-extra", parsed{Major: 1, Minor: 2}, true},
+ {"1.2.3-extra", parsed{Major: 1, Minor: 2, Patch: 3}, true},
+ {"date.20200612", parsed{Datestamp: 20200612}, true},
+ {"borkbork", parsed{}, false},
+ {"1a.2.3", parsed{}, false},
+ {"", parsed{}, false},
+ }
+
+ for _, test := range tests {
+ gotParsed, got := parse(test.version)
+ if got != test.want {
+ t.Errorf("version(%q) = %v, want %v", test.version, got, test.want)
+ }
+ if diff := cmp.Diff(gotParsed, test.parsed); diff != "" {
+ t.Errorf("parse(%q) diff (-got+want):\n%s", test.version, diff)
+ }
+ err := tstest.MinAllocsPerRun(t, 0, func() {
+ gotParsed, got = parse(test.version)
+ })
+ if err != nil {
+ t.Errorf("parse(%q): %v", test.version, err)
+ }
+ }
+}
+
+func TestAtLeast(t *testing.T) {
+ tests := []struct {
+ v, m string
+ want bool
+ }{
+ {"1", "1", true},
+ {"1.2", "1", true},
+ {"1.2.3", "1", true},
+ {"1.2.3-4", "1", true},
+ {"0.98-0", "0.98", true},
+ {"0.97.1-216", "0.98", false},
+ {"0.94", "0.98", false},
+ {"0.98", "0.98", true},
+ {"0.98.0-0", "0.98", true},
+ {"1.2.3-4", "1.2.4-4", false},
+ {"1.2.3-4", "1.2.3-4", true},
+ {"date.20200612", "date.20200612", true},
+ {"date.20200701", "date.20200612", true},
+ {"date.20200501", "date.20200612", false},
+ }
+
+ for _, test := range tests {
+ got := version.AtLeast(test.v, test.m)
+ if got != test.want {
+ t.Errorf("AtLeast(%q, %q) = %v, want %v", test.v, test.m, got, test.want)
+ }
+ }
+}
diff --git a/version/export_test.go b/version/export_test.go
index 8e8ce5ecb..fabba13e8 100644
--- a/version/export_test.go
+++ b/version/export_test.go
@@ -1,14 +1,14 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package version
-
-var (
- ExportParse = parse
- ExportFindModuleInfo = findModuleInfo
- ExportCmdName = cmdName
-)
-
-type (
- ExportParsed = parsed
-)
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package version
+
+var (
+ ExportParse = parse
+ ExportFindModuleInfo = findModuleInfo
+ ExportCmdName = cmdName
+)
+
+type (
+ ExportParsed = parsed
+)
diff --git a/version/print.go b/version/print.go
index 7d8554279..e3bfc38ef 100644
--- a/version/print.go
+++ b/version/print.go
@@ -1,33 +1,33 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package version
-
-import (
- "fmt"
- "runtime"
- "strings"
-
- "tailscale.com/types/lazy"
-)
-
-var stringLazy = lazy.SyncFunc(func() string {
- var ret strings.Builder
- ret.WriteString(Short())
- ret.WriteByte('\n')
- if IsUnstableBuild() {
- fmt.Fprintf(&ret, " track: unstable (dev); frequent updates and bugs are likely\n")
- }
- if gitCommit() != "" {
- fmt.Fprintf(&ret, " tailscale commit: %s%s\n", gitCommit(), dirtyString())
- }
- if extraGitCommitStamp != "" {
- fmt.Fprintf(&ret, " other commit: %s\n", extraGitCommitStamp)
- }
- fmt.Fprintf(&ret, " go version: %s\n", runtime.Version())
- return strings.TrimSpace(ret.String())
-})
-
-func String() string {
- return stringLazy()
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package version
+
+import (
+ "fmt"
+ "runtime"
+ "strings"
+
+ "tailscale.com/types/lazy"
+)
+
+var stringLazy = lazy.SyncFunc(func() string {
+ var ret strings.Builder
+ ret.WriteString(Short())
+ ret.WriteByte('\n')
+ if IsUnstableBuild() {
+ fmt.Fprintf(&ret, " track: unstable (dev); frequent updates and bugs are likely\n")
+ }
+ if gitCommit() != "" {
+ fmt.Fprintf(&ret, " tailscale commit: %s%s\n", gitCommit(), dirtyString())
+ }
+ if extraGitCommitStamp != "" {
+ fmt.Fprintf(&ret, " other commit: %s\n", extraGitCommitStamp)
+ }
+ fmt.Fprintf(&ret, " go version: %s\n", runtime.Version())
+ return strings.TrimSpace(ret.String())
+})
+
+func String() string {
+ return stringLazy()
+}
diff --git a/version/race.go b/version/race.go
index e1dc76591..bc3ca8db6 100644
--- a/version/race.go
+++ b/version/race.go
@@ -1,10 +1,10 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build race
-
-package version
-
-// IsRace reports whether the current binary was built with the Go
-// race detector enabled.
-func IsRace() bool { return true }
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build race
+
+package version
+
+// IsRace reports whether the current binary was built with the Go
+// race detector enabled.
+func IsRace() bool { return true }
diff --git a/version/race_off.go b/version/race_off.go
index 6db901974..d55288d9c 100644
--- a/version/race_off.go
+++ b/version/race_off.go
@@ -1,10 +1,10 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-//go:build !race
-
-package version
-
-// IsRace reports whether the current binary was built with the Go
-// race detector enabled.
-func IsRace() bool { return false }
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+//go:build !race
+
+package version
+
+// IsRace reports whether the current binary was built with the Go
+// race detector enabled.
+func IsRace() bool { return false }
diff --git a/version/version_test.go b/version/version_test.go
index a51565058..4d676f9f5 100644
--- a/version/version_test.go
+++ b/version/version_test.go
@@ -1,51 +1,51 @@
-// Copyright (c) Tailscale Inc & AUTHORS
-// SPDX-License-Identifier: BSD-3-Clause
-
-package version_test
-
-import (
- "bytes"
- "os"
- "testing"
-
- ts "tailscale.com"
- "tailscale.com/version"
-)
-
-func TestAlpineTag(t *testing.T) {
- if tag := readAlpineTag(t, "../Dockerfile.base"); tag == "" {
- t.Fatal(`"FROM alpine:" not found in Dockerfile.base`)
- } else if tag != ts.AlpineDockerTag {
- t.Errorf("alpine version mismatch: Dockerfile.base has %q; ALPINE.txt has %q", tag, ts.AlpineDockerTag)
- }
- if tag := readAlpineTag(t, "../Dockerfile"); tag == "" {
- t.Fatal(`"FROM alpine:" not found in Dockerfile`)
- } else if tag != ts.AlpineDockerTag {
- t.Errorf("alpine version mismatch: Dockerfile has %q; ALPINE.txt has %q", tag, ts.AlpineDockerTag)
- }
-}
-
-func readAlpineTag(t *testing.T, file string) string {
- f, err := os.ReadFile(file)
- if err != nil {
- t.Fatal(err)
- }
- for _, line := range bytes.Split(f, []byte{'\n'}) {
- line = bytes.TrimSpace(line)
- _, suf, ok := bytes.Cut(line, []byte("FROM alpine:"))
- if !ok {
- continue
- }
- return string(suf)
- }
- return ""
-}
-
-func TestShortAllocs(t *testing.T) {
- allocs := int(testing.AllocsPerRun(10000, func() {
- _ = version.Short()
- }))
- if allocs > 0 {
- t.Errorf("allocs = %v; want 0", allocs)
- }
-}
+// Copyright (c) Tailscale Inc & AUTHORS
+// SPDX-License-Identifier: BSD-3-Clause
+
+package version_test
+
+import (
+ "bytes"
+ "os"
+ "testing"
+
+ ts "tailscale.com"
+ "tailscale.com/version"
+)
+
+func TestAlpineTag(t *testing.T) {
+ if tag := readAlpineTag(t, "../Dockerfile.base"); tag == "" {
+ t.Fatal(`"FROM alpine:" not found in Dockerfile.base`)
+ } else if tag != ts.AlpineDockerTag {
+ t.Errorf("alpine version mismatch: Dockerfile.base has %q; ALPINE.txt has %q", tag, ts.AlpineDockerTag)
+ }
+ if tag := readAlpineTag(t, "../Dockerfile"); tag == "" {
+ t.Fatal(`"FROM alpine:" not found in Dockerfile`)
+ } else if tag != ts.AlpineDockerTag {
+ t.Errorf("alpine version mismatch: Dockerfile has %q; ALPINE.txt has %q", tag, ts.AlpineDockerTag)
+ }
+}
+
+func readAlpineTag(t *testing.T, file string) string {
+ f, err := os.ReadFile(file)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, line := range bytes.Split(f, []byte{'\n'}) {
+ line = bytes.TrimSpace(line)
+ _, suf, ok := bytes.Cut(line, []byte("FROM alpine:"))
+ if !ok {
+ continue
+ }
+ return string(suf)
+ }
+ return ""
+}
+
+func TestShortAllocs(t *testing.T) {
+ allocs := int(testing.AllocsPerRun(10000, func() {
+ _ = version.Short()
+ }))
+ if allocs > 0 {
+ t.Errorf("allocs = %v; want 0", allocs)
+ }
+}