walking through the rsc.io/quote example
This post: https://research.swtch.com/vgo-tour
setting up and looking around
import the package by plopping import "rsc.io/quote" into a source file. (and using it because for some reason unused imports are a hard error. just go things tm)
package main
import "fmt"
import "rsc.io/quote"
func main() {
fmt.Println(quote.Hello())
}go commands auto-download missing dependencies (?!), so go run . already works and can print quotes.
Another way to kick the tires is go mod tidy, which ensures go.mod is up-to-date wrt the list of packages mentioned in the source code. (and re-formats the file.)
What versions of packages do you get? this picks:
- the latest non-prerelease version of any packages you explicitly asked for (that would be
rsc.io/quoteversion1.5.2)- eh? there is a v3 and v4 on the site
- any of the transitive dependencies that they specifically asked for
- if the same package ends up in the dependency tree multiple different ways, you’ll get the oldest such package; this is “minimal version selection”
In practice this means that when you install X and the latest version is v2, the transitive dependencies you get are the versions that the author of X had in their dependency file. (Kinda like when i use gradle.)
now go.mod looks like this:
module go.highlysuspect.agency/hello
go 1.25.6
require rsc.io/quote v1.5.2
require (
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c // indirect
rsc.io/sampler v1.3.0 // indirect
)
Let’s check go mod graph
$ go mod graph
go.highlysuspect.agency/hello go@1.25.6
go.highlysuspect.agency/hello golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
go.highlysuspect.agency/hello rsc.io/quote@v1.5.2
go.highlysuspect.agency/hello rsc.io/sampler@v1.3.0
go@1.25.6 toolchain@go1.25.6
rsc.io/quote@v1.5.2 rsc.io/sampler@v1.3.0
rsc.io/sampler@v1.3.0 golang.org/x/text@v0.0.0-20170915032832-14c0d48ead0c
- first four lines are things mentioned in
go.mod - next line seems like something internal (go 1.25.6 depends on go 1.25.6 tooling or something)
- then we see
quotedepends onsampler, andsamplerdepends on a random ancient version ofx/text
this tracks with the source code (quote, sampler)
checking for updates
The magic word is go list -m -u all.
$ go list -m -u all
go.highlysuspect.agency/hello
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c [v0.33.0]
rsc.io/quote v1.5.2
rsc.io/sampler v1.3.0 [v1.99.99]
Can I complain about this CLI?
- It looks like
allis an argument to-ubut it’s reallygo list allwith arguments. -mudoesn’t work.go list all -m -udoens’t work. (it tries to list “-u” and “-m” as packages)- Im not gonna be able to remember that
anyway. It looks like there’s a new version of x/text and sampler. Upgrading x/text:
$ go get golang.org/x/text@v0.33.0
go: upgraded golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c => v0.33.0
checking go.mod reports the indirect dependency has been upgraded from the random commit version to v0.33.0. Nice.
something about go test
There’s a part in the blogpost about go test that I don’t understand the modern version of:
In the original
gocommand, the package patternallmeant all packages found inGOPATH. That’s almost always too many to be useful. Invgo, we’ve narrowed the meaning ofallto be “all packages in the current module, and the packages they import, recursively.”
But go test all started testing all packages on the system including Go internal packages, and go test -m all tested only my package (which doesn’t have any tests). I’m not sure how to test only my dependencies (or, tbh, if i’d even want to)
upgrading sampler
This is the part where you go get -u rsc.io/sampler and discover it has a bug, prints the wrong message instead of hello.
downgrading sampler
Listing versions for a package can be done with go list -m -versions (package)
$ go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1 v1.99.99
-v does not work, gotta spell it out.
Then pin the package to the version you want:
$ go get rsc.io/sampler@v1.3.1
go: downgraded rsc.io/sampler v1.99.99 => v1.3.1
And it can be marked as something we don’t want by adding exclude rsc.io/sampler v1.99.99 to go.mod. Note that adding an exclusion is really strong and other commands act like the version doesn’t even exist. It’s even gone from go list -m -versions.
$ go list -m -versions rsc.io/sampler
rsc.io/sampler v1.0.0 v1.2.0 v1.2.1 v1.3.0 v1.3.1
And exclusions are nontransitive. Downstream consumers can still end up resolving to a version you tried to exclude. Hmm, this seems like a bad idea but what do I know.
vendoring quote
- I checked out rsc quote into a
quotesubdirectory (probably the wrong place for it, it should have gone in an adjacent directory lol) - (Of course you have to check out the v1.5.2 tag since git defaults to plonking you on version 3)
- Made changes and added
replace rsc.io/quote v1.5.2 => ./quotetogo.modand my changes were reflected. Yay.
Works for me.
vendoring everything
go mod vendor plonks the following into vendor/modules.txt
# golang.org/x/text v0.33.0
## explicit; go 1.24.0
golang.org/x/text/internal/language
golang.org/x/text/internal/language/compact
golang.org/x/text/internal/tag
golang.org/x/text/language
# rsc.io/quote v1.5.2 => ./quote
## explicit
rsc.io/quote
# rsc.io/sampler v1.3.1
## explicit
rsc.io/sampler
and copies of the relevant libraries are all under vendor.
This is kind of a node_modules situation.
changes since the original rsc post about go modules
go.mod now includes information about the version of Go used. That didn’t exist at first.
Transitive dependencies are now added to go.mod with an //indirect comment. Apparently this was changed for “lazy loading” purposes but in practice, it means all those “minimal version selection is reproducible, so there’s no need to list the transitive closure of your dependencies!” notes didn’t shake out.
frankly I think it’s kind of a good change because seeing the entire dependency graph is good for your health :)
Apparently you can also get //indirect comments if you dep on pre-modules Go code. This seems wrong though…? (it looks like what actually changed in OP’s question is that Go was dumping all the dependencies into one list, now it sorts direct deps before indirect ones, so it’s easier to spot the module op actually wanted)
other ways to upgrade packages
go get -u: upgrade EVERYTHING
go get (package): upgrade that package (and its transitive dependencies) to the latest version
You don’t need -u. go get -u (package) does the same thing(?).
Seems typosquattable!!! dont fuck up that URL!!!
questions
- when I
go get rsc.io/quote, why do i get versionv1.5.2and notv4.0.1, the newest version?
it seems the other major versions are under rsc.io/quote/v4?
also this: https://go.dev/ref/mod#incompatible-versions
- what is the old way of managing dependencies that modules replace?
some background is in this article.
hm