profile
viewpoint
Andrew Gerrand adg Google Inc. Sydney, Australia https://golang.org/

nf/sigourney 338

A modular audio synthesizer

adg/game 134

adg/github-gmail 67

Chrome extension to show GitHub issue status in Gmail

adg/dt 48

diff traversal tool

rsc/quote 27

Pithy sayings.

campoy/httplog 17

Easy and flexible logging of HTTP requests

adg/sched 16

Goroutine scheduling latency profiling

adg/gostrip 15

Command gostrip builds a minimal Go repository

rsc/sampler 7

sampler

Pull request review commentgoogle/exposure-notifications-server

Gracefully stop servers on interrupt

 package main  import ( 	"context"-	"log"+	"fmt" 	"net/http"--	"go.opencensus.io/plugin/ochttp"+	"time"  	"github.com/google/exposure-notifications-server/internal/cleanup"+	"github.com/google/exposure-notifications-server/internal/interrupt" 	"github.com/google/exposure-notifications-server/internal/logging" 	_ "github.com/google/exposure-notifications-server/internal/observability"+	"github.com/google/exposure-notifications-server/internal/server" 	"github.com/google/exposure-notifications-server/internal/setup" )  func main() {-	ctx := context.Background()+	ctx, done := interrupt.Context()+	defer done()++	if err := realMain(ctx); err != nil {+		logger := logging.FromContext(ctx)+		logger.Fatal(err)+	}+}++func realMain(ctx context.Context) error { 	logger := logging.FromContext(ctx)  	var config cleanup.Config 	env, closer, err := setup.Setup(ctx, &config) 	if err != nil {-		logger.Fatalf("setup.Setup: %v", err)+		return fmt.Errorf("setup.Setup: %w", err) 	} 	defer closer()  	handler, err := cleanup.NewExportHandler(&config, env) 	if err != nil {-		logger.Fatalf("cleanup.NewExportHandler: %v", err)+		return fmt.Errorf("cleanup.NewExportHandler: %w", err) 	}+ 	mux := http.NewServeMux() 	mux.Handle("/", handler)-	logger.Infof("starting export cleanup server on :%s", config.Port)-	instrumentedHandler := &ochttp.Handler{Handler: mux}-	log.Fatal(http.ListenAndServe(":"+config.Port, instrumentedHandler))++	server := server.New(config.Port, mux)

Right, I can see that. I'm saying have a single Serve method that takes a ctx and have it block until that context is done, then it does the graceful shutdown (using a background context, with timeout, for any shutdown-related things that require a context), then returns. Then the last line of your main function can be return server.Serve(ctx)

sethvargo

comment created time in a month

Pull request review commentgoogle/exposure-notifications-server

Gracefully stop servers on interrupt

 package main  import ( 	"context"-	"log"+	"fmt" 	"net/http"--	"go.opencensus.io/plugin/ochttp"+	"time"  	"github.com/google/exposure-notifications-server/internal/cleanup"+	"github.com/google/exposure-notifications-server/internal/interrupt" 	"github.com/google/exposure-notifications-server/internal/logging" 	_ "github.com/google/exposure-notifications-server/internal/observability"+	"github.com/google/exposure-notifications-server/internal/server" 	"github.com/google/exposure-notifications-server/internal/setup" )  func main() {-	ctx := context.Background()+	ctx, done := interrupt.Context()+	defer done()++	if err := realMain(ctx); err != nil {+		logger := logging.FromContext(ctx)+		logger.Fatal(err)+	}+}++func realMain(ctx context.Context) error { 	logger := logging.FromContext(ctx)  	var config cleanup.Config 	env, closer, err := setup.Setup(ctx, &config) 	if err != nil {-		logger.Fatalf("setup.Setup: %v", err)+		return fmt.Errorf("setup.Setup: %w", err) 	} 	defer closer()  	handler, err := cleanup.NewExportHandler(&config, env) 	if err != nil {-		logger.Fatalf("cleanup.NewExportHandler: %v", err)+		return fmt.Errorf("cleanup.NewExportHandler: %w", err) 	}+ 	mux := http.NewServeMux() 	mux.Handle("/", handler)-	logger.Infof("starting export cleanup server on :%s", config.Port)-	instrumentedHandler := &ochttp.Handler{Handler: mux}-	log.Fatal(http.ListenAndServe(":"+config.Port, instrumentedHandler))++	server := server.New(config.Port, mux)

usually it's server.Serve(ctx) that blocks until it shuts down gracefully. that way you don't need a stop method.

I think separate constructor is fine lets you separate serve errors from init errors

sethvargo

comment created time in a month

issue commentgolang/go

cmd/doc: -src flag misbehaves on some systems [1.14 backport]

Note that only the authors of the original CL (or maintainers with the "impersonate" permission) have the ability to create the cherry-pick.

I don't have that permission anymore it seems. :)

adg

comment created time in a month

issue openedgolang/go

cmd/doc: -src flag misbehaves on some systems [1.14 backport]

Under go1.14.2, if you run go doc -src strings.Compare on macOS you get a bunch of unrelated comments.

Commit 585e31df63f6879c03b285711de6f9dcba1f2cb0 fixes this issue, but it is not applied in the current release (go1.14.2). It would be great to get this trivial fix cherry picked into the next point release.

(Apologies if I should be using @gopherbot to create this issue; I would have but there wasn't a corresponding issue for the original fix.)

created time in 2 months

issue commentrivo/tview

please publish a release

At the moment every time you push a new commit the Go tool uses a 'pseudo-version' semver string like v0.0.0-20200414130344-8e06c826b3a5 to refer to that specific commit. These are valid semver tags that monotonically increase, so if you want your users to live at HEAD then don't change anything.

If, by tagging commits, all you'd be doing is tagging v0.0.1, v0.0.2, etc, with no intention of supporting any particular major/minor release in the long term, then there's no point in introducing tags.

In fact, if you did introduce a tag and then failed to tag subsequent versions, new users of tview would get the most recently tagged version instead of what's at HEAD, which with your current dev process seems like the wrong thing.

jossef

comment created time in 2 months

issue commentrivo/tview

please publish a release

Doing so would make literally no difference except for the string that appears in your go.mod file. Why push the maintainer into doing this?

jossef

comment created time in 2 months

issue commentgolang/go

Proposal: improve UX for major module versions

A major version number must always be present in the import path, else you get the latest major version

@bep that's kind of a non-starter because v0/v1 do not have the major version in the path, and the go tool should do what you ask it to, not what it thinks you mean.

adg

comment created time in 2 months

issue commentgolang/go

Proposal: improve UX for major module versions

@kokes one thing we discussed, but didn't include in this proposal, was including in the deprecation error message a mention of the previous minor/patch version in addition to the pointer to the next available major version. Something like:

error: module github.com/user/repo@v1.7.1 is deprecated
error: try the latest major version: go get github.com/user/repo/v2
error: or the previous patch version: go get github.com/user/repo@v1.7.0

(This is just off the top of my head - such a message should be finessed to emphasise the major version, while still offering a path to the previous working version.) I think that would address the cases you describe.

With regard to external tools, they'd need to understand deprecation as much as it affects their operation, the same way they need to understand various other aspects of Go modules.

adg

comment created time in 2 months

issue commentgolang/go

Proposal: improve UX for major module versions

it gives them "don't install this, it's deprecated, try v2 instead" - which might confuse them as v2 is not really usable due to the breaking change, but they cannot install v1 at all - unless they dig out the last non-deprecated v1.x.y version

adg

comment created time in 2 months

issue commentgolang/go

Proposal: improve UX for major module versions

@mvdan thanks for the pointer to that proposal; missed that in our review of related issues. Added to the appendix.

adg

comment created time in 2 months

issue openedgolang/go

Proposal: improve UX for major module versions

Proposal: improve UX for major module versions

Peter Bourgon (@peterbourgon), Andrew Gerrand (@adg)

Problem statement

When a user wants to use a module, it is the v0/v1 version of that module which is most prominent, as it is selected by the base repository path: github.com/user/repo is in effect a constraint to v0.x.y/v1.x.y.

To use v2 or above, Semantic Import Versioning requires that the major version number is a suffix of the module path: github.com/user/repo/v2 (constrained to v2.x.y), github.com/user/repo/v3 (constrained to v3.x.y), and so on.

It’s easy for module consumers to default to v0/v1, even if that version is obsoleted by a more recent major version. Module consumers may even be totally unaware of later major versions.

Discoverability is a key issue. The mechanisms for module authors to advertise recent major versions are inconsistent, and can be low-visibility (documentation? README.md?) or highly disruptive (printing deprecation warnings in init, broken builds to force an investigation).

Abstract

We propose two improvements: one targeted at module consumers, and the other at producers.

For consumers, we propose a mechanism that notifies users of the latest major version of a module dependency when that dependency is first added to a project.

For producers, we propose adding a deprecated directive to go.mod files to signify the end-of-life of a major version.

These are just preliminary ideas which we hope to refine and improve in response to feedback gathered here.

Proposal 1: Notification of latest major version

We propose notifying users of new major versions when:

  • They first add a requirement for an old major version of a module
  • They update a requirement for an old major version of a module

There are a few ways users add requirements to their modules:

  • By running go get github.com/user/repo
  • By adding a require github.com/user/repo line to their go.mod file manually
  • By adding an import line to a Go source file, and having goimports or gopls editor integration add the import line on save

For the latter two, the module isn't fetched until the go command is invoked within the module.

There are a few ways users update requirements:

  • By running go get [-u] github.com/user/repo
  • By running go get -u ./... from the module root
  • Or to find out about available updates, they may run go list -m -u all

In each of these cases, the go tool plays a key role, and so we propose to make the go tool print a note if a requirement is being added when there is a more recent major version of the module available.

Examples

Consider a user fetching peterbourgon/ff with go get. We propose adding a notification to the output, alerting the user to a new major version:

$ go get github.com/peterbourgon/ff
go: finding github.com/pelletier/go-toml v1.6.0
go: finding gopkg.in/yaml.v2 v2.2.4
go: finding github.com/davecgh/go-spew v1.1.1
go: downloading github.com/peterbourgon/ff v1.7.0
go: extracting github.com/peterbourgon/ff v1.7.0
go: note: more recent major versions of github.com/peterbourgon/ff are available     👈
go: note: to install the most recent one, run `go get github.com/peterbourgon/ff/v3` 👈

Consider a user listing all of the most recent versions of their dependencies. We propose adding the latest major version alongside any new minor or patch versions:

$ go list -m -u all
example.com/my-module
github.com/BurntSushi/toml v0.3.1
github.com/mitchellh/go-wordwrap v1.0.0
github.com/peterbourgon/ff v1.6.0 [v1.7.0] <v3.0.1>                        👈 ONE OF
github.com/peterbourgon/ff v1.6.0 [v1.7.0] <github.com/peterbourgon/ff/v3> 👈 THESE
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 [v0.0.0-20191204190536-9bdfabe68543]
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 [v1.0.0-20200227125254-8fa46927fb4f]
gopkg.in/yaml.v2 v2.2.2 [v2.2.8]

If a new requirement is added to a go.mod file manually, the go tool would print the notification when it first fetches the new module, as part of a go build, go test, etc. run.

Proposal 2: A new deprecated directive

Producer-side deprecation feature: add a deprecated line, which will cause the module to fail to fetch at that version, printing an error with the most recent non-deprecated version of the same major version.

module github.com/user/repo

deprecated

require (...)

If the go tool were asked to fetch this deprecated module, it would fail:

error: module github.com/user/repo@v1.7.1 is deprecated

If the Proposal 1 were adopted, the error message could be more useful:

error: module github.com/user/repo@v1.7.1 is deprecated
error: try the latest major version: go get github.com/user/repo/v2

The deprecated directive may optionally include a successor module identifier. If specified, the error printed when fetching this module version would also include a reference to the successor module. This can be used to point to the next major version:

deprecated github.com/user/repo/v2

Or to a new import path altogether:

deprecated gitlab.com/newuser/newrepo

If the go tool were asked to fetch this deprecated module, it would fail with a more explicit suggestion to the user:

error: module github.com/user/repo@v1.7.1 is deprecated
error: try its successor: go get github.com/user/repo/v2

If the successor module is also marked as deprecated and includes a successor module, the go tool might follow those links, and print the final non-deprecated module in the error message.

When package producers decide that a major version is deprecated, the intent is for them to create a new minor or patch release of that major version with the deprecated directive in the go.mod. This version will only be selected by the go tool when the corresponding major version is first added to a project, or if someone tries to update from an earlier version of that major version. In both cases, the go tool fails to fetch the module and provides a useful and actionable message: the user is instructed to pick a non-deprecated version.

Users can always use earlier versions of that major version, and MVS should ensure that the deprecated version will not be selected. If module A has a requirement for B at v1.7.0, and B v1.7.1 is later tagged as deprecated, A can continue to use B at v1.7.0, and the maintainer of A will only become aware of the deprecation when they try to update B.

It should not be possible for the go tool to mechanically add a deprecated version to a go.mod file.

A major version may be "un-deprecated" by publishing a subsequent minor or patch version without a deprecated directive in its go.mod. The specific deprecated version remains unusable, but the earlier and later versions still work normally.

Examples

A producer deprecating v1 of their module:

  • Producer tags github.com/user/repo v1.0.0, v1.1.0, ... up to v1.7.0
  • Producer tags github.com/user/repo/v2 v2.0.0, and soon afterward v2.0.1
  • Producer adds a deprecated or deprecated github.com/user/repo/v2 line to the go.mod of the v1 branch and tags it v1.7.1

A consumer using a module that is then deprecated:

  • Consumer has a module requirement require github.com/user/repo v1.7.0
  • Producer tags the deprecated v1.7.1 version
  • Consumer continues to use v1.7.0 without issue
  • If the user tries to upgrade the dependency, the deprecation prevents it
  • The user can keep their existing v1.7.0 or migrate to the new v2.x.y

A consumer tries to fetch a module at a deprecated major version:

  • Consumer runs go get github.com/user/repo as a new dependency
  • go get selects the highest version in the v0 or v1 trees, which is v1.7.1
  • go get prints an error message:
error: module github.com/user/repo@v1.7.1 is deprecated
error: try the latest major version: go get github.com/user/repo/v2
  • Consumer runs the suggested command, installing v2 of the module

Composition

One of Go’s strengths is the orthogonality of its features. We believe the proposed features compose nicely and strengthen each other.

Taken separately, the proposals can stand on their own: P1 provides package consumers with useful information without direct action from package producers; P2 allows package producers to give their consumers more specific guidance on an opt-in basis.

Taken together, the proposals enrich each other: P1 improves the error messages that accompany P2; P2 funnels users into the upgrade paths created by P1.

Integrations

pkg.go.dev

The Go package discovery website at pkg.go.dev shows modules and their versions. However, it obscures successive major versions when they exist, apparently treating major module versions as completely distinct. For example, the landing page for peterbourgon/ff shows v1.7.0 with a "Latest" bubble beside it. The versions tab does list other major versions, but under the heading "Other modules containing this package", which is confusing.

Instead, pkg.go.dev could feature a prominent indicator on the landing page for a v0/v1 module that there are two successive major versions (v2 and v3), to funnel the user toward the latter.

Editor integration (gopls, goimports)

Go text editor integrations typically include a feature that automatically adds import statements to source files based on the mentioned identifiers. Because of Semantic Import Versioning, this also gives those tools the responsibility of choosing the major version of the imported module. In the case where there is no suitable existing requirement in the project’s go.mod file, these editor integrations could alert the user to the availability of newer major module versions. How this works is outside the scope of this proposal.

Appendix

created time in 2 months

issue commentupspin/upspin

double compressed download archive

Being unable to reproduce this, I propose closing the issue. Any objections?

srlehn

comment created time in 2 months

issue commentupspin/upspin

double compressed download archive

I just tried it in both Firefox 75.0 and 68.7.0esr and in both cases it left a .tar.gz file in my Downloads directory, which appears to correctly be a gzipped tar file (and only gzipped once).

Being unable to reproduce this here I'm not sure how to push this issue forward. Perhaps someone reading this has a linux machine they could try downloading from? (I'm on macOS here)

srlehn

comment created time in 2 months

issue commentupspin/upspin

double compressed download archive

What are you using to download it?

The HTTP response has Content-Type: application/x-gzip, so it is technically gzipped twice, but the second layer should be transparent to whatever downloads the file.

It's possible your HTTP client is broken, or that our HTTP server is somehow misconfigured, but I'm unable to reproduce the issue here either with Chrome, Safari, or curl.

srlehn

comment created time in 2 months

issue openedkubernetes/k8s.io

k8s.io go-get redirector should only allow canonical names

The way that the go-get metadata redirector in nginx is configured just redirects k8s.io/ANYTHING to github.com/kubernetes/ANYTHING.

This means that k8s.io/Kubernetes can be used to name the github.com/kubernetes/Kubernetes repo, which could create some confusion as Go import and module paths are case-sensitive, thus effectively creating two base import paths: k8s.io/kubernetes and k8s.io/Kubernetes.

Is it possible to add a rule to the nginx config to only permit lowercase repo names, and return 404s otherwise?

created time in 3 months

pull request commentsdefresne/gerrit-monitor

Differentiate between CLs without reviewers and WIPs

Thanks for the handy extension! =D

adg

comment created time in 3 months

pull request commentsdefresne/gerrit-monitor

Differentiate between CLs without reviewers and WIPs

Done.

adg

comment created time in 3 months

push eventadg/gerrit-monitor

Andrew Gerrand

commit sha 01b4a7eba6e839c025e0c4145cf0dac32008f764

Differentiate between CLs without reviewers and WIPs There should be a distinction between CLs that have been sent out for review but that do not have assigned reviewers, and those that are published to Gerrit with the "work in progress" label attached. This change splits these distinct states into separate categories with different labels, but they still use the same grey icon as before (now renamed to "not_ready").

view details

push time in 3 months

issue commentsdefresne/gerrit-monitor

Make Work in Progress outgoing CL's (with comments) not count as requiring my attention

My pull request #21 should fix this.

garymm

comment created time in 3 months

PR opened sdefresne/gerrit-monitor

Differentiate between CLs without reviewers and WIPs

There should be a distinction between CLs that have been sent out for review but that do not have assigned reviewers, and those that are published to Gerrit with the "work in progress" label attached.

This change splits these distinct states into separate categories with different labels, but they still use the same grey icon as before (now renamed to "not_ready").

+43 -13

0 comment

4 changed files

pr created time in 3 months

push eventadg/gerrit-monitor

Andrew Gerrand

commit sha 9be4f36c10dc06dde6838d5aed6d88b806e24cc0

Differentiate between CLs without reviewers and WIPs There should be a distinction between CLs that have been sent out for review but that do not have assigned reviewers, and those that are published to Gerrit with the "work in progress" label attached. This change splits these distinct states into separate categories with different labels, but they still use the same grey icon as before (now renamed to "not_ready").

view details

push time in 3 months

fork adg/gerrit-monitor

Source for Gerrit Monitor Chrome extension

fork in 3 months

more