syncthing/lib/build/build.go
Jakob Borg df2ac7aaeb
gui, lib/api: Add possibility to feed through extra version information (#8980)
This adds an environment variable STVERSIONEXTRA that, when set, gets
added to the version information in the API and GUI.

The purpose of all this is to be able to communicate something about the
bundling or packaging, through the log & GUI and the end user, to the
potential person supporting it -- i.e., us. :) A wrapper can set this
variable to indicate that Syncthing is being run via `SyncTrayzor`,
`Syncthing-macOS`, etc., and thus indicate to the end user that the GUI
they are looking at is perhaps not the only source of truth and
management for this instance.
2023-07-16 17:43:10 +02:00

129 lines
3.5 KiB
Go

// Copyright (C) 2019 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.
package build
import (
"fmt"
"log"
"os"
"regexp"
"runtime"
"sort"
"strconv"
"strings"
"time"
)
var (
// Injected by build script
Version = "unknown-dev"
Host = "unknown"
User = "unknown"
Stamp = "0"
Tags = ""
// Static
Codename = "Fermium Flea"
// Set by init()
Date time.Time
IsRelease bool
IsCandidate bool
IsBeta bool
LongVersion string
Extra string
allowedVersionExp = regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z0-9]+)*(\.\d+)*(\+\d+-g[0-9a-f]+)?(-[^\s]+)?$`)
envTags = []string{
"STGUIASSETS",
"STHASHING",
"STNORESTART",
"STNOUPGRADE",
}
)
const versionExtraAllowedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-. "
func init() {
if Version != "unknown-dev" {
// If not a generic dev build, version string should come from git describe
if !allowedVersionExp.MatchString(Version) {
log.Fatalf("Invalid version string %q;\n\tdoes not match regexp %v", Version, allowedVersionExp)
}
}
setBuildData()
}
func setBuildData() {
// Check for a clean release build. A release is something like
// "v0.1.2", with an optional suffix of letters and dot separated
// numbers like "-beta3.47". If there's more stuff, like a plus sign and
// a commit hash and so on, then it's not a release. If it has a dash in
// it, it's some sort of beta, release candidate or special build. If it
// has "-rc." in it, like "v0.14.35-rc.42", then it's a candidate build.
//
// So, every build that is not a stable release build has IsBeta = true.
// This is used to enable some extra debugging (the deadlock detector).
//
// Release candidate builds are also "betas" from this point of view and
// will have that debugging enabled. In addition, some features are
// forced for release candidates - auto upgrade, and usage reporting.
exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-[a-z]+[\d\.]+)?$`)
IsRelease = exp.MatchString(Version)
IsCandidate = strings.Contains(Version, "-rc.")
IsBeta = strings.Contains(Version, "-")
Extra = filterString(os.Getenv("STVERSIONEXTRA"), versionExtraAllowedChars)
stamp, _ := strconv.Atoi(Stamp)
Date = time.Unix(int64(stamp), 0)
LongVersion = LongVersionFor("syncthing")
}
// LongVersionFor returns the long version string for the given program name.
func LongVersionFor(program string) string {
// This string and date format is essentially part of our external API. Never change it.
date := Date.UTC().Format("2006-01-02 15:04:05 MST")
v := fmt.Sprintf(`%s %s "%s" (%s %s-%s) %s@%s %s`, program, Version, Codename, runtime.Version(), runtime.GOOS, runtime.GOARCH, User, Host, date)
if tags := TagsList(); len(tags) > 0 {
v = fmt.Sprintf("%s [%s]", v, strings.Join(tags, ", "))
}
return v
}
func TagsList() []string {
tags := strings.Split(Tags, ",")
if len(tags) == 1 && tags[0] == "" {
tags = tags[:0]
}
for _, envVar := range envTags {
if os.Getenv(envVar) != "" {
tags = append(tags, strings.ToLower(envVar))
}
}
if Extra != "" {
tags = append(tags, Extra)
}
sort.Strings(tags)
return tags
}
// filterString returns a copy of s with all characters not in allowedChars
// removed.
func filterString(s, allowedChars string) string {
var res strings.Builder
for _, c := range s {
if strings.ContainsRune(allowedChars, c) {
res.WriteRune(c)
}
}
return res.String()
}