1// Copyright 2024 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package telemetry 6 7import ( 8 "os" 9 "path/filepath" 10 "runtime/debug" 11 "strings" 12) 13 14// IsToolchainProgram reports whether a program with the given path is a Go 15// toolchain program. 16func IsToolchainProgram(progPath string) bool { 17 return strings.HasPrefix(progPath, "cmd/") 18} 19 20// ProgramInfo extracts the go version, program package path, and program 21// version to use for counter files. 22// 23// For programs in the Go toolchain, the program version will be the same as 24// the Go version, and will typically be of the form "go1.2.3", not a semantic 25// version of the form "v1.2.3". Go versions may also include spaces and 26// special characters. 27func ProgramInfo(info *debug.BuildInfo) (goVers, progPath, progVers string) { 28 goVers = info.GoVersion 29 if strings.Contains(goVers, "devel") || strings.Contains(goVers, "-") { 30 goVers = "devel" 31 } 32 33 progPath = info.Path 34 if progPath == "" { 35 progPath = strings.TrimSuffix(filepath.Base(os.Args[0]), ".exe") 36 } 37 38 // Main module version information is not populated for the cmd module, but 39 // we can re-use the Go version here. 40 if IsToolchainProgram(progPath) { 41 progVers = goVers 42 } else { 43 progVers = info.Main.Version 44 if strings.Contains(progVers, "devel") || strings.Count(progVers, "-") > 1 { 45 // Heuristically mark all pseudo-version-like version strings as "devel" 46 // to avoid creating too many counter files. 47 // We should not use regexp that pulls in large dependencies. 48 // Pseudo-versions have at least three parts (https://go.dev/ref/mod#pseudo-versions). 49 // This heuristic still allows use to track prerelease 50 // versions (e.g. gopls@v0.16.0-pre.1, vscgo@v0.42.0-rc.1). 51 progVers = "devel" 52 } 53 } 54 55 return goVers, progPath, progVers 56} 57