[telemetry] internal/configgen: generate upload configs from graph configs

338 views
Skip to first unread message

Robert Findley (Gerrit)

unread,
Aug 15, 2023, 1:02:55 PM8/15/23
to goph...@pubsubhelper.golang.org, golang-...@googlegroups.com, Jamal Carvalho, Gopher Robot, Hyang-Ah Hana Kim, golang-co...@googlegroups.com

Robert Findley submitted this change.

View Change

Approvals: Jamal Carvalho: Looks good to me, approved Gopher Robot: TryBots succeeded Robert Findley: Run TryBots
internal/configgen: generate upload configs from graph configs

Add a new main package to generate upload configs from graph configs,
add an initial graph config, and update config/config.json with the
resulting payload.

Per discussion, modify the behavior of the `version` line in graph
configs. It is now just an optional semantic version specifying the
first program version for which this graph applies, as a hint to reduce
collection from irrelevant program versions.

Subsequent CLs will add consistency tests.

Change-Id: Iaa8c1f8aafd82bdbdfbff4da671edfb7c723d791
Reviewed-on: https://go-review.googlesource.com/c/telemetry/+/517415
Run-TryBot: Robert Findley <rfin...@google.com>
TryBot-Result: Gopher Robot <go...@golang.org>
Reviewed-by: Jamal Carvalho <ja...@golang.org>
---
M config/config.json
A internal/configgen/config.txt
A internal/configgen/main.go
A internal/configgen/main_test.go
A internal/configgen/syslist.go
M internal/graphconfig/graphconfig.go
M internal/graphconfig/parse.go
M internal/graphconfig/parse_test.go
M internal/graphconfig/validate.go
M internal/graphconfig/validate_test.go
M internal/proxy/proxy.go
M types.go
12 files changed, 711 insertions(+), 118 deletions(-)

diff --git a/config/config.json b/config/config.json
index b9fb5f9..1035728 100644
--- a/config/config.json
+++ b/config/config.json
@@ -1,10 +1,13 @@
{
- "GOOS": [
+ "GOOS": [
+ "aix",
"android",
"darwin",
"dragonfly",
"freebsd",
+ "hurd",
"illumos",
+ "ios",
"js",
"linux",
"nacl",
@@ -12,58 +15,315 @@
"openbsd",
"plan9",
"solaris",
- "windows"
- ],
- "GOARCH": [
+ "wasip1",
+ "windows",
+ "zos"
+ ],
+ "GOARCH": [
"386",
"amd64",
"amd64p32",
"arm",
- "armbe",
"arm64",
"arm64be",
+ "armbe",
+ "loong64",
"mips",
- "mipsle",
"mips64",
"mips64le",
"mips64p32",
"mips64p32le",
+ "mipsle",
+ "ppc",
"ppc64",
"ppc64le",
"riscv",
"riscv64",
+ "s390",
"s390x",
"sparc",
"sparc64",
"wasm"
- ],
- "GoVersion": [
- "go1.20",
- "go1.20.1",
- "go1.20.2",
- "go1.20.3",
- "go1.20.4",
- "go1.20.5",
- "go1.20.6",
- "go1.20.7",
- "go1.20.8",
- "go1.20.9",
- "go1.20.10",
- "go1.20.11",
- "go1.20.12",
- "go1.21.0",
- "go1.21.1",
- "go1.21.2",
- "go1.21.3",
- "go1.21.4",
- "go1.21.5",
- "go1.21.6",
- "go1.21.7",
- "go1.21.8",
- "go1.21.9",
- "go1.21.10",
- "go1.21.11",
- "go1.21.12"
- ],
- "Programs": []
+ ],
+ "GoVersion": [
+ "go1.10",
+ "go1.10.1",
+ "go1.10.2",
+ "go1.10.3",
+ "go1.10.4",
+ "go1.10.5",
+ "go1.10.6",
+ "go1.10.7",
+ "go1.10.8",
+ "go1.10beta2",
+ "go1.10rc1",
+ "go1.10rc2",
+ "go1.11",
+ "go1.11.1",
+ "go1.11.10",
+ "go1.11.11",
+ "go1.11.12",
+ "go1.11.13",
+ "go1.11.2",
+ "go1.11.3",
+ "go1.11.4",
+ "go1.11.5",
+ "go1.11.6",
+ "go1.11.7",
+ "go1.11.8",
+ "go1.11.9",
+ "go1.11beta1",
+ "go1.11beta2",
+ "go1.11beta3",
+ "go1.11rc1",
+ "go1.11rc2",
+ "go1.12",
+ "go1.12.1",
+ "go1.12.10",
+ "go1.12.11",
+ "go1.12.12",
+ "go1.12.13",
+ "go1.12.14",
+ "go1.12.15",
+ "go1.12.16",
+ "go1.12.17",
+ "go1.12.2",
+ "go1.12.3",
+ "go1.12.4",
+ "go1.12.5",
+ "go1.12.6",
+ "go1.12.7",
+ "go1.12.8",
+ "go1.12.9",
+ "go1.12beta1",
+ "go1.12beta2",
+ "go1.12rc1",
+ "go1.13",
+ "go1.13.1",
+ "go1.13.10",
+ "go1.13.11",
+ "go1.13.12",
+ "go1.13.13",
+ "go1.13.14",
+ "go1.13.15",
+ "go1.13.2",
+ "go1.13.3",
+ "go1.13.4",
+ "go1.13.5",
+ "go1.13.6",
+ "go1.13.7",
+ "go1.13.8",
+ "go1.13.9",
+ "go1.13beta1",
+ "go1.13rc1",
+ "go1.13rc2",
+ "go1.14",
+ "go1.14.1",
+ "go1.14.10",
+ "go1.14.11",
+ "go1.14.12",
+ "go1.14.13",
+ "go1.14.14",
+ "go1.14.15",
+ "go1.14.2",
+ "go1.14.3",
+ "go1.14.4",
+ "go1.14.5",
+ "go1.14.6",
+ "go1.14.7",
+ "go1.14.8",
+ "go1.14.9",
+ "go1.14beta1",
+ "go1.14rc1",
+ "go1.15",
+ "go1.15.1",
+ "go1.15.10",
+ "go1.15.11",
+ "go1.15.12",
+ "go1.15.13",
+ "go1.15.14",
+ "go1.15.15",
+ "go1.15.2",
+ "go1.15.3",
+ "go1.15.4",
+ "go1.15.5",
+ "go1.15.6",
+ "go1.15.7",
+ "go1.15.8",
+ "go1.15.9",
+ "go1.15beta1",
+ "go1.15rc1",
+ "go1.15rc2",
+ "go1.16",
+ "go1.16.1",
+ "go1.16.10",
+ "go1.16.11",
+ "go1.16.12",
+ "go1.16.13",
+ "go1.16.14",
+ "go1.16.15",
+ "go1.16.2",
+ "go1.16.3",
+ "go1.16.4",
+ "go1.16.5",
+ "go1.16.6",
+ "go1.16.7",
+ "go1.16.8",
+ "go1.16.9",
+ "go1.16beta1",
+ "go1.16rc1",
+ "go1.17",
+ "go1.17.1",
+ "go1.17.10",
+ "go1.17.11",
+ "go1.17.12",
+ "go1.17.13",
+ "go1.17.2",
+ "go1.17.3",
+ "go1.17.4",
+ "go1.17.5",
+ "go1.17.6",
+ "go1.17.7",
+ "go1.17.8",
+ "go1.17.9",
+ "go1.17beta1",
+ "go1.17rc1",
+ "go1.17rc2",
+ "go1.18",
+ "go1.18.1",
+ "go1.18.10",
+ "go1.18.2",
+ "go1.18.3",
+ "go1.18.4",
+ "go1.18.5",
+ "go1.18.6",
+ "go1.18.7",
+ "go1.18.8",
+ "go1.18.9",
+ "go1.18beta1",
+ "go1.18beta2",
+ "go1.18rc1",
+ "go1.19",
+ "go1.19.1",
+ "go1.19.10",
+ "go1.19.11",
+ "go1.19.12",
+ "go1.19.2",
+ "go1.19.3",
+ "go1.19.4",
+ "go1.19.5",
+ "go1.19.6",
+ "go1.19.7",
+ "go1.19.8",
+ "go1.19.9",
+ "go1.19beta1",
+ "go1.19rc1",
+ "go1.19rc2",
+ "go1.2.2",
+ "go1.20",
+ "go1.20.1",
+ "go1.20.2",
+ "go1.20.3",
+ "go1.20.4",
+ "go1.20.5",
+ "go1.20.6",
+ "go1.20.7",
+ "go1.20rc1",
+ "go1.20rc2",
+ "go1.20rc3",
+ "go1.21.0",
+ "go1.21rc2",
+ "go1.21rc3",
+ "go1.21rc4",
+ "go1.3",
+ "go1.3.1",
+ "go1.3.2",
+ "go1.3.3",
+ "go1.3rc1",
+ "go1.3rc2",
+ "go1.4",
+ "go1.4.1",
+ "go1.4.2",
+ "go1.4.3",
+ "go1.4beta1",
+ "go1.4rc1",
+ "go1.4rc2",
+ "go1.5",
+ "go1.5.1",
+ "go1.5.2",
+ "go1.5.3",
+ "go1.5.4",
+ "go1.5beta1",
+ "go1.5beta2",
+ "go1.5beta3",
+ "go1.5rc1",
+ "go1.6",
+ "go1.6.1",
+ "go1.6.2",
+ "go1.6.3",
+ "go1.6.4",
+ "go1.6beta1",
+ "go1.6beta2",
+ "go1.6rc1",
+ "go1.6rc2",
+ "go1.7",
+ "go1.7.1",
+ "go1.7.3",
+ "go1.7.4",
+ "go1.7.5",
+ "go1.7.6",
+ "go1.7beta1",
+ "go1.7beta2",
+ "go1.7rc1",
+ "go1.7rc2",
+ "go1.7rc3",
+ "go1.7rc4",
+ "go1.7rc5",
+ "go1.7rc6",
+ "go1.8",
+ "go1.8.1",
+ "go1.8.2",
+ "go1.8.3",
+ "go1.8.4",
+ "go1.8.5",
+ "go1.8.6",
+ "go1.8.7",
+ "go1.8beta1",
+ "go1.8beta2",
+ "go1.8rc1",
+ "go1.8rc2",
+ "go1.8rc3",
+ "go1.9",
+ "go1.9.1",
+ "go1.9.2",
+ "go1.9.2rc2",
+ "go1.9.3",
+ "go1.9.4",
+ "go1.9.5",
+ "go1.9.6",
+ "go1.9.7",
+ "go1.9beta1",
+ "go1.9beta2",
+ "go1.9rc1",
+ "go1.9rc2"
+ ],
+ "Programs": [
+ {
+ "Name": "golang.org/x/tools/gopls",
+ "Versions": [
+ "v0.13.0",
+ "v0.13.1-pre.1",
+ "v0.13.1-pre.2",
+ "v0.13.1",
+ "v0.13.2-pre.1",
+ "v0.13.2"
+ ],
+ "Counters": [
+ {
+ "Name": "gopls/editor:{emacs,vim,vscode,other}",
+ "Rate": 0.1
+ }
+ ]
+ }
+ ]
}
\ No newline at end of file
diff --git a/internal/configgen/config.txt b/internal/configgen/config.txt
new file mode 100644
index 0000000..395d73d
--- /dev/null
+++ b/internal/configgen/config.txt
@@ -0,0 +1,10 @@
+# Note: this is not an approved graph config, but merely demonstrates the
+# config generation feature during development.
+
+title: Editor Distribution
+counter: gopls/editor:{emacs,vim,vscode,other}
+description: measure editor distribution for gopls users.
+type: partition
+issue: https://go.dev/issue/61038
+program: golang.org/x/tools/gopls
+version: v0.13.0 # temporarily back-version to demonstrate config generation.
diff --git a/internal/configgen/main.go b/internal/configgen/main.go
new file mode 100644
index 0000000..7471411
--- /dev/null
+++ b/internal/configgen/main.go
@@ -0,0 +1,248 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package configgen generates the upload config file stored in the config.json
+// file of golang.org/x/telemetry/config.
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "sort"
+ "strings"
+
+ _ "embed"
+
+ "golang.org/x/mod/semver"
+ "golang.org/x/telemetry"
+ "golang.org/x/telemetry/internal/graphconfig"
+)
+
+var write = flag.Bool("w", false, "if set, write the config file; otherwise, print to stdout")
+
+//go:embed config.txt
+var graphConfig []byte
+
+func main() {
+ flag.Parse()
+
+ ucfg, err := generate(graphConfig)
+ if err != nil {
+ log.Fatal(err)
+ }
+ ucfgJSON, err := json.MarshalIndent(ucfg, "", "\t")
+ if err != nil {
+ log.Fatal(err)
+ }
+ if !*write {
+ fmt.Println(string(ucfgJSON))
+ os.Exit(0)
+ }
+ configFile, err := configFile()
+ if err != nil {
+ log.Fatalf("finding config file: %v", err)
+ }
+ os.WriteFile(configFile, ucfgJSON, 0666)
+}
+
+// configFile returns the path to the x/telemetry/config config.json file in
+// this repo.
+//
+// The file must already exist: this won't be a valid location if running from
+// the module cache; this functionality only works when executed from the
+// telemetry repo.
+func configFile() (string, error) {
+ out, err := exec.Command("go", "list", "-f", "{{.Dir}}", "golang.org/x/telemetry/internal/configgen").Output()
+ if err != nil {
+ return "", err
+ }
+ dir := strings.TrimSpace(string(out))
+ configFile := filepath.Join(dir, "..", "..", "config", "config.json")
+ if _, err := os.Stat(configFile); err != nil {
+ return "", err
+ }
+ return configFile, nil
+}
+
+// generate computes the upload config from graph configs and module
+// information, returning the resulting formatted JSON.
+func generate(graphConfig []byte, env ...string) (*telemetry.UploadConfig, error) {
+ ucfg := &telemetry.UploadConfig{
+ GOOS: goos(),
+ GOARCH: goarch(),
+ }
+ var err error
+ ucfg.GoVersion, err = goVersions()
+ if err != nil {
+ return nil, fmt.Errorf("querying go info: %v", err)
+ }
+
+ gcfgs, err := graphconfig.Parse(graphConfig)
+ if err != nil {
+ return nil, fmt.Errorf("parsing graph config records: %v", err)
+ }
+
+ for i, r := range gcfgs {
+ if err := graphconfig.Validate(r); err != nil {
+ // TODO(rfindley): this is a poor way to identify the faulty record. We
+ // should probably store position information in the GraphConfig.
+ return nil, fmt.Errorf("graph config #%d (%q): %v", i, r.Title, err)
+ }
+ }
+
+ var (
+ programs = make(map[string]*telemetry.ProgramConfig) // package path -> config
+ minVersions = make(map[string]string) // package path -> min version required, or "" for all
+ )
+ for _, gcfg := range gcfgs {
+ pcfg := programs[gcfg.Program]
+ if pcfg == nil {
+ pcfg = &telemetry.ProgramConfig{
+ Name: gcfg.Program,
+ }
+ programs[gcfg.Program] = pcfg
+ minVersions[gcfg.Program] = gcfg.Version
+ }
+ minVersions[gcfg.Program] = minVersion(minVersions[gcfg.Program], gcfg.Version)
+ ccfg := telemetry.CounterConfig{
+ Name: gcfg.Counter,
+ Rate: 0.1, // TODO(rfindley): how should rate be configured?
+ Depth: gcfg.Depth,
+ }
+ if gcfg.Depth > 0 {
+ pcfg.Stacks = append(pcfg.Stacks, ccfg)
+ } else {
+ pcfg.Counters = append(pcfg.Counters, ccfg)
+ }
+ }
+
+ for _, p := range programs {
+ minVersion := minVersions[p.Name]
+ versions, err := listProxyVersions(p.Name)
+ if err != nil {
+ return nil, fmt.Errorf("listing versions for %q: %v", p.Name, err)
+ }
+ // Filter proxy versions in place.
+ i := 0
+ for _, v := range versions {
+ if !semver.IsValid(v) {
+ // In order to perform semver comparison below, we must have valid
+ // versions. This should always be the case for the proxy.
+ // Trust, but verify.
+ return nil, fmt.Errorf("invalid semver %q returned from proxy for %q", v, p.Name)
+ }
+ if minVersion == "" || semver.Compare(minVersion, v) <= 0 {
+ versions[i] = v
+ i++
+ }
+ }
+ p.Versions = versions[:i]
+ ucfg.Programs = append(ucfg.Programs, p)
+ }
+ sort.Slice(ucfg.Programs, func(i, j int) bool {
+ return ucfg.Programs[i].Name < ucfg.Programs[j].Name
+ })
+
+ return ucfg, nil
+}
+
+// minVersion returns the lesser semantic version of v1 and v2.
+//
+// As a special case, the empty string is treated as an absolute minimum
+// (empty => all versions are greater).
+func minVersion(v1, v2 string) string {
+ if v1 == "" || v2 == "" {
+ return ""
+ }
+ if semver.Compare(v1, v2) > 0 {
+ return v2
+ }
+ return v1
+}
+
+// goos returns a sorted slice of known GOOS values.
+func goos() []string {
+ var gooses []string
+ for goos := range knownOS {
+ gooses = append(gooses, goos)
+ }
+ sort.Strings(gooses)
+ return gooses
+}
+
+// goarch returns a sorted slice of known GOARCH values.
+func goarch() []string {
+ var arches []string
+ for arch := range knownArch {
+ arches = append(arches, arch)
+ }
+ sort.Strings(arches)
+ return arches
+}
+
+// goInfo queries the proxy for information about go distributions, including
+// versions, GOOS, and GOARCH values.
+func goVersions() ([]string, error) {
+ // Trick: read Go distribution information from the module versions of
+ // golang.org/toolchain. These define the set of valid toolchains, and
+ // therefore are a reasonable source for version information.
+ //
+ // A more authoritative source for this information may be
+ // https://go.dev/dl?mode=json&include=all.
+ proxyVersions, err := listProxyVersions("golang.org/toolchain")
+ if err != nil {
+ return nil, fmt.Errorf("listing toolchain versions: %v", err)
+ }
+ var goVersionRx = regexp.MustCompile(`^-(go.+)\.[^.]+-[^.]+$`)
+ verSet := make(map[string]struct{})
+ for _, v := range proxyVersions {
+ pre := semver.Prerelease(v)
+ match := goVersionRx.FindStringSubmatch(pre)
+ if match == nil {
+ return nil, fmt.Errorf("proxy version %q does not match prerelease regexp %q", v, goVersionRx)
+ }
+ verSet[match[1]] = struct{}{}
+ }
+ var vers []string
+ for v := range verSet {
+ vers = append(vers, v)
+ }
+ sort.Strings(vers)
+ return vers, nil
+}
+
+// versionsForTesting contains versions to use for testing, rather than
+// querying the proxy.
+var versionsForTesting map[string][]string
+
+// listProxyVersions queries the Go module mirror for published versions of the
+// given modulePath.
+//
+// modulePath must be lower-case (or already escaped): this function doesn't do
+// any escaping of upper-cased letters, as is required by the proxy prototol
+// (https://go.dev/ref/mod#goproxy-protocol).
+func listProxyVersions(modulePath string) ([]string, error) {
+ if vers, ok := versionsForTesting[modulePath]; ok {
+ return vers, nil
+ }
+ cmd := exec.Command("go", "list", "-m", "--versions", modulePath)
+ var stderr bytes.Buffer
+ cmd.Stderr = &stderr
+ out, err := cmd.Output()
+ if err != nil {
+ return nil, fmt.Errorf("listing versions: %v (stderr: %v)", err, stderr.String())
+ }
+ fields := strings.Fields(strings.TrimSpace(string(out)))
+ if len(fields) == 0 {
+ return nil, fmt.Errorf("invalid version list output: %q", string(out))
+ }
+ return fields[1:], nil
+}
diff --git a/internal/configgen/main_test.go b/internal/configgen/main_test.go
new file mode 100644
index 0000000..751f746
--- /dev/null
+++ b/internal/configgen/main_test.go
@@ -0,0 +1,62 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "reflect"
+ "testing"
+
+ "golang.org/x/telemetry"
+)
+
+func TestGenerate(t *testing.T) {
+ defer func(vers map[string][]string) {
+ versionsForTesting = vers
+ }(versionsForTesting)
+ versionsForTesting = map[string][]string{
+ "golang.org/toolchain": {"v0.0.1-go1.21.0.linux-arm", "v0.0.1-go1.20.linux-arm"},
+ "golang.org/x/tools/gopls": {"v0.13.0", "v0.14.0", "v0.15.0"},
+ }
+ const gcfg = `
+title: Editor Distribution
+counter: gopls/editor:{emacs,vim,vscode,other}
+description: measure editor distribution for gopls users.
+type: partition
+issue: https://go.dev/issue/61038
+program: golang.org/x/tools/gopls
+version: v0.14.0
+`
+ got, err := generate([]byte(gcfg))
+ if err != nil {
+ t.Fatal(err)
+ }
+ want := telemetry.UploadConfig{
+ GOOS: goos(),
+ GOARCH: goarch(),
+ GoVersion: []string{"go1.20", "go1.21.0"},
+ Programs: []*telemetry.ProgramConfig{{
+ Name: "golang.org/x/tools/gopls",
+ Versions: []string{"v0.14.0", "v0.15.0"},
+ Counters: []telemetry.CounterConfig{{
+ Name: "gopls/editor:{emacs,vim,vscode,other}",
+ Rate: 0.1,
+ }},
+ }},
+ }
+ if !reflect.DeepEqual(*got, want) {
+ if len(got.Programs) != len(want.Programs) {
+ t.Errorf("generate(): got %d programs, want %d", len(got.Programs), len(want.Programs))
+ } else {
+ for i, gotp := range got.Programs {
+ want := *want.Programs[i]
+ if !reflect.DeepEqual(*gotp, want) {
+ t.Errorf("generate() program #%d =\n%+v\nwant:\n%+v", i, *gotp, want)
+
+ }
+ }
+ }
+ t.Errorf("generate() =\n%+v\nwant:\n%+v", *got, want)
+ }
+}
diff --git a/internal/configgen/syslist.go b/internal/configgen/syslist.go
new file mode 100644
index 0000000..9291607
--- /dev/null
+++ b/internal/configgen/syslist.go
@@ -0,0 +1,77 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// knownOS is the list of past, present, and future known GOOS values.
+// Do not remove from this list, as it is used for filename matching.
+// If you add an entry to this list, look at unixOS, below.
+var knownOS = map[string]bool{
+ "aix": true,
+ "android": true,
+ "darwin": true,
+ "dragonfly": true,
+ "freebsd": true,
+ "hurd": true,
+ "illumos": true,
+ "ios": true,
+ "js": true,
+ "linux": true,
+ "nacl": true,
+ "netbsd": true,
+ "openbsd": true,
+ "plan9": true,
+ "solaris": true,
+ "wasip1": true,
+ "windows": true,
+ "zos": true,
+}
+
+// unixOS is the set of GOOS values matched by the "unix" build tag.
+// This is not used for filename matching.
+// This list also appears in cmd/dist/build.go and
+// cmd/go/internal/imports/build.go.
+var unixOS = map[string]bool{
+ "aix": true,
+ "android": true,
+ "darwin": true,
+ "dragonfly": true,
+ "freebsd": true,
+ "hurd": true,
+ "illumos": true,
+ "ios": true,
+ "linux": true,
+ "netbsd": true,
+ "openbsd": true,
+ "solaris": true,
+}
+
+// knownArch is the list of past, present, and future known GOARCH values.
+// Do not remove from this list, as it is used for filename matching.
+var knownArch = map[string]bool{
+ "386": true,
+ "amd64": true,
+ "amd64p32": true,
+ "arm": true,
+ "armbe": true,
+ "arm64": true,
+ "arm64be": true,
+ "loong64": true,
+ "mips": true,
+ "mipsle": true,
+ "mips64": true,
+ "mips64le": true,
+ "mips64p32": true,
+ "mips64p32le": true,
+ "ppc": true,
+ "ppc64": true,
+ "ppc64le": true,
+ "riscv": true,
+ "riscv64": true,
+ "s390": true,
+ "s390x": true,
+ "sparc": true,
+ "sparc64": true,
+ "wasm": true,
+}
diff --git a/internal/graphconfig/graphconfig.go b/internal/graphconfig/graphconfig.go
index b3117b0..abab80b 100644
--- a/internal/graphconfig/graphconfig.go
+++ b/internal/graphconfig/graphconfig.go
@@ -29,14 +29,11 @@
// - issue: a go issue tracker URL proposing the graph configuration.
// Multiple issues may be provided by including additional 'issue:' lines.
// All proposals must be in the 'accepted' state.
-// - type: the graph type: currently only partition, histograph, and stack
-// are supported.
+// - type: the graph type: currently only partition, histogram, and stack are
+// supported.
// - program: the package path of the program for which this graph applies.
-// - version: (optional) range of version for which graph applies. Must be a
-// valid singular semver value, or a semver interval [vA.B.C, vX.Y.Z].
-// Intervals may be half-open, e.g. [vA.B.C,], in which case the missing
-// bound is not enforced. Multiple version ranges may be provided by
-// including additional 'version:' lines.
+// - version: (optional) the first version for which this graph applies. Must
+// be a valid semver value.
// - counter: the primary counter this graph illustrates, including buckets
// for histogram and partition graphs
// - depth: (optional) stack counters only; the maximum stack depth to collect
@@ -84,13 +81,5 @@
Counter string
Depth int
Error float64 // TODO(rfindley) is Error still useful?
- Version []VersionInterval
-}
-
-// A VersionInterval matches semantic versions v where Low <= v <= High.
-// VersionIntervals may be half-open:
-// - If Low is unset, it matches v <= High.
-// - If High is unset, it matches Low <= v.
-type VersionInterval struct {
- Low, High string
+ Version string
}
diff --git a/internal/graphconfig/parse.go b/internal/graphconfig/parse.go
index ba68b05..f391130 100644
--- a/internal/graphconfig/parse.go
+++ b/internal/graphconfig/parse.go
@@ -107,7 +107,7 @@
"counter": parseString,
"depth": parseInt,
"error": parseFloat,
- "version": parseSlice(parseVersionInterval),
+ "version": parseString,
}

func parseString(v reflect.Value, input string) error {
@@ -144,32 +144,3 @@
return nil
}
}
-
-func parseVersionInterval(v reflect.Value, input string) error {
- bad := func() error {
- return fmt.Errorf("versions must be of the form v<version> or [v<low>, v<high>]")
- }
- if input[0] != '[' { // a single version value
- vi := VersionInterval{Low: input, High: input}
- v.Set(reflect.ValueOf(vi))
- return nil
- }
- if input[len(input)-1] != ']' {
- return bad()
- }
- input = input[1 : len(input)-1]
- parts := strings.Split(input, ",")
- if len(parts) != 2 {
- return bad()
- }
- low, high := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1])
- var vi VersionInterval
- if low != "" {
- vi.Low = low
- }
- if high != "" {
- vi.High = high
- }
- v.Set(reflect.ValueOf(vi))
- return nil
-}
diff --git a/internal/graphconfig/parse_test.go b/internal/graphconfig/parse_test.go
index 34bfae6..19d74fc 100644
--- a/internal/graphconfig/parse_test.go
+++ b/internal/graphconfig/parse_test.go
@@ -30,10 +30,7 @@
issue: F2
depth: 2
error: 0.1
-version: [v1.0.0, v1.2.3]
version: v2.0.0
-version: [v3.0.0, ]
-version: [, v4.0.0]
`,
[]graphconfig.GraphConfig{{
Title: "A",
@@ -44,12 +41,7 @@
Issue: []string{"F1", "F2"},
Depth: 2,
Error: 0.1,
- Version: []graphconfig.VersionInterval{
- {"v1.0.0", "v1.2.3"},
- {"v2.0.0", "v2.0.0"},
- {"v3.0.0", ""},
- {"", "v4.0.0"},
- },
+ Version: "v2.0.0",
}},
},
{
@@ -165,12 +157,6 @@
depth: notanint
`,
},
- {
- "invalid interval",
- `
-version: [v1.2.3,
-`,
- },
}

for _, test := range tests {
diff --git a/internal/graphconfig/validate.go b/internal/graphconfig/validate.go
index 2c63472..15b7b71 100644
--- a/internal/graphconfig/validate.go
+++ b/internal/graphconfig/validate.go
@@ -39,16 +39,8 @@
if cfg.Depth != 0 && cfg.Type != "stack" {
reportf("depth can only be set for \"stack\" graph types")
}
- for _, vi := range cfg.Version {
- if vi.Low != "" && !semver.IsValid(vi.Low) {
- reportf("%q is not valid semver", vi.Low)
- }
- if vi.High != "" && vi.High != vi.Low && !semver.IsValid(vi.High) {
- reportf("%q is not valid semver", vi.High)
- }
- if vi.Low != "" && vi.High != "" && semver.IsValid(vi.Low) && semver.IsValid(vi.High) && semver.Compare(vi.Low, vi.High) > 0 {
- reportf("low version %q must be <= high version %q", vi.Low, vi.High)
- }
+ if cfg.Version != "" && !semver.IsValid(cfg.Version) {
+ reportf("%q is not valid semver", cfg.Version)
}
return errors.Join(errs...)
}
diff --git a/internal/graphconfig/validate_test.go b/internal/graphconfig/validate_test.go
index 835d0a2..25533ef 100644
--- a/internal/graphconfig/validate_test.go
+++ b/internal/graphconfig/validate_test.go
@@ -38,10 +38,7 @@
"description:bar": {"title", "program", "issue", "counter", "type"},

// validation of semver intervals
- "version:1.2.3": {"semver"},
- "version:[1.2.3, v2.3.4]": {"semver"},
- "version:[v1.2.3, 2.3.4]": {"semver"},
- "version:[v1.2.3, v1.2.2]": {"<="},
+ "version:1.2.3": {"semver"},

// valid of stack configuration
"depth:-1": {"non-negative", "stack"},
diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go
index 9f5b677..0138995 100644
--- a/internal/proxy/proxy.go
+++ b/internal/proxy/proxy.go
@@ -19,7 +19,7 @@
"golang.org/x/mod/module"
)

-// WriteProxy creates a new proxy file tree using the txtar-encoded content,
+// WriteProxy creates a new proxy file tree using the provided content,
// and returns its URL.
func WriteProxy(tmpdir string, files map[string][]byte) (string, error) {
type moduleVersion struct {
diff --git a/types.go b/types.go
index 018989e..361fd1a 100644
--- a/types.go
+++ b/types.go
@@ -10,7 +10,7 @@
"golang.org/x/telemetry/internal/telemetry"
)

-// Common types and directories used by multple packages.
+// Common types and directories used by multiple packages.

// An UploadConfig controls what data is uploaded.
type UploadConfig struct {
@@ -18,7 +18,8 @@
GOARCH []string
GoVersion []string // how does this get changed with new releases?
Programs []*ProgramConfig
- Version string // version of this config. Is this needed?
+ Version string `json:",omitempty" ` // version of this config. TODO(rfindley): Is this needed?
+ // TODO(rfindley): add a 'FormatVersion' field, to allow evolution of the config format?
}

type ProgramConfig struct {
@@ -26,15 +27,15 @@
// repeated for each program. (e.g., if the counters are in a package
// that is used in more than one program.)
Name string
- Versions []string // where do these come from
- Counters []CounterConfig
- Stacks []CounterConfig
+ Versions []string // versions present in a counterconfig
+ Counters []CounterConfig `json:",omitempty"`
+ Stacks []CounterConfig `json:",omitempty"`
}

type CounterConfig struct {
Name string
Rate float64 // If X < Rate, report this counter
- Depth int // for stack counters
+ Depth int `json:",omitempty"` // for stack counters
}

// A Report is what's uploaded (or saved locally)

To view, visit change 517415. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-MessageType: merged
Gerrit-Project: telemetry
Gerrit-Branch: master
Gerrit-Change-Id: Iaa8c1f8aafd82bdbdfbff4da671edfb7c723d791
Gerrit-Change-Number: 517415
Gerrit-PatchSet: 16
Gerrit-Owner: Robert Findley <rfin...@google.com>
Gerrit-Reviewer: Gopher Robot <go...@golang.org>
Gerrit-Reviewer: Hyang-Ah Hana Kim <hya...@gmail.com>
Gerrit-Reviewer: Jamal Carvalho <ja...@golang.org>
Gerrit-Reviewer: Robert Findley <rfin...@google.com>
Gerrit-CC: Peter Weinberger <p...@golang.org>
Reply all
Reply to author
Forward
0 new messages