Pet and Go intercourse #2
2025-10-06
TL;DR
In its attempts to study Go in depth, pet tries to resolve dependencies by its own paws, gets discouraged, and blames Go for nothing.
Go lovers should close this page right now to save mental health.
Insane pets and their brave masters, come on!
In the previous Go session pet created its own static site generator that produced, in particular, this site and this page. Now it's time to extend its functionality.
What pet wants is a source code browser that generates static pages for pet's codebase.
As long as pet has to use Git at the moment, it needs some library that can work with that.
Every human suggests go-git
, so pet downloads it.
go-git/go.mod
looks spooky:
require (
dario.cat/mergo v1.0.0
github.com/ProtonMail/go-crypto v1.1.6
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5
github.com/elazarl/goproxy v1.7.2
github.com/emirpasic/gods v1.18.1
github.com/gliderlabs/ssh v0.3.8
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376
github.com/go-git/go-billy/v5 v5.6.2
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8
github.com/google/go-cmp v0.7.0
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/kevinburke/ssh_config v1.2.0
github.com/pjbgf/sha1cd v0.3.2
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
github.com/skeema/knownhosts v1.3.1
github.com/stretchr/testify v1.10.0
github.com/xanzy/ssh-agent v0.3.3
golang.org/x/crypto v0.37.0
golang.org/x/net v0.39.0
golang.org/x/sys v0.32.0
golang.org/x/text v0.24.0
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
)
require (
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
You know, pet loves to run Go compiler offline, trying to resolve all dependencies manually, by downloading and adding packages to the project, one by one.
Running compiler after each step gives a clue what else is missing.
Such an approach worked for all languages pet dealt with through all its lives so nothing can go wrong.
Per creates a directory with a sample application based on go-git examples and simple go.mod
:
module test
go 1.25.0
require (
github.com/go-git/go-git/v5 v5.16.2
)
replace (
github.com/go-git/go-git/v5 v5.16.2 => ./deps/go-git-5.16.2
)
Now, let's Go:
go-git
requires mergo
mergo
requires yaml.v3
yaml.v3
requires check.v1
... wait! go build
says:
go-git-5.16.2/options.go:10:2: gopkg.in/yaml.v3@v3.0.1 requires
gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405: missing go.sum entry for go.mod file; to add it:
go mod download gopkg.in/check.v1
See that? The version of check.v1
is not v1.0.0-20201130134442-10cb98267c6c
as in go-git/go.mod
.
It's strange, isn't it?
Indeed, yaml.v3
contains "gopkg.in/check.v1" v0.0.0-20161208181325-20d25e280405
in its go.mod
.
So where can pet get that version from?
Without go mod download
or go get
?
Pet goes to https://gopkg.in/check.v1 and sees only v1
.
The source code https://github.com/go-check/check/tree/v1
neither has any other tags and branches.
Pet has to read the documentation. This one https://go.dev/doc/modules/managing-dependencies refers to https://go.dev/doc/modules/version-numbers which describes such version format as "pseudo-version number", used
When a module has not been tagged in its repository
Great. To resolve such dependency pet has to search for specific revision.
But pet is stubborn. Nothing but hardcore. It downloads https://github.com/go-check/check/tree/20d25e2804050c1cd24a7eea1e7a6447dd0e74ec and adds
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 => ./deps/check-20d25e2804050c1cd24a7eea1e7a6447dd0e74ec
to require
and replace
sections of go.mod
.
However, go build
refuses to work:
go: updates to go.mod needed; to update it:
go mod tidy
Well, maybe it's because go-git
requires newer version?
Pet downloads https://github.com/go-check/check/tree/10cb98267c6cb43ea9cd6793f29ff4089c306974
(which actually is the head at the time of writing) and updates go.mod
.
Yay! go build
passes to the next dependencies, kr/pretty
, kr/text
, and github.com/rogpeppe/go-internal v1.9.0
.
But pet just learned it should use higher version 1.14.1, as in go-git/go.mod
Pet downloads and unpacks it, but go build
is still insisting on 1.9.0:
go-git-5.16.2/options.go:10:2: github.com/kr/pretty@v0.3.1 requires
github.com/rogpeppe/go-internal@v1.9.0: missing go.sum entry for go.mod file; to add it:
go mod download github.com/rogpeppe/go-internal
Okay, let it be 1.9.0, but pet gets back to
go: updates to go.mod needed; to update it:
go mod tidy
Maybe, leave both in go.mod
? That's ridiculous, but... Nope. The error is the same.
Pet asks go mod help
and go build help
, hoping to find any troubleshooting options.
None exists. Maybe -x
? Nope again. It sucks. Silently.
Okay then. Pet has to run go mod tidy
. Offline.
But it's worth to save how go.mod
looks like at the moment:
module test
go 1.25.0
require (
github.com/go-git/go-git/v5 v5.16.2
dario.cat/mergo v1.0.0
gopkg.in/yaml.v3 v3.0.1
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c
github.com/kr/pretty v0.3.1
github.com/kr/text v0.2.0
github.com/rogpeppe/go-internal v1.14.1
github.com/rogpeppe/go-internal v1.9.0
)
replace (
github.com/go-git/go-git/v5 v5.16.2 => ./deps/go-git-5.16.2
dario.cat/mergo v1.0.0 => ./deps/mergo-1.0.0
gopkg.in/yaml.v3 v3.0.1 => ./deps/yaml-3.0.1
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c => ./deps/check-10cb98267c6cb43ea9cd6793f29ff4089c306974
github.com/kr/pretty v0.3.1 => ./deps/pretty-0.3.1
github.com/kr/text v0.2.0 => ./deps/text-0.2.0
github.com/rogpeppe/go-internal v1.14.1 => ./deps/go-internal-1.14.1
github.com/rogpeppe/go-internal v1.9.0 => ./deps/go-internal-1.9.0
)
After half a minute of hanging go mod tidy
pukes
go: github.com/kr/text@v0.2.0 requires
github.com/creack/pty@v1.1.9: Get "https://proxy.golang.org/github.com/creack/pty/@v/v1.1.9.mod": dial tcp 64.233.164.141:443: i/o timeout
It looks like old farts who designed Go totally forgot about offline mode in their attempts to dial IP addresses. Dial, LOL! Pet wonders if vacuum tube mainframes from their adolescence were equipped with rotary dials for IP connectivity.
At least, go mod tidy
gave pet a clue.
But before adding this dependency, pet removes go-internal v1.9.0
and runs it again.
The result makes pet wonder:
go: dario.cat/mergo@v1.0.0 requires
gopkg.in/yaml.v3@v3.0.1 requires
gopkg.in/check.v1@v0.0.0-20161208181325-20d25e280405: Get "https://proxy.golang.org/gopkg.in/check.v1/@v/v0.0.0-20161208181325-20d25e280405.mod": dial tcp 64.233.164.141:443: i/o timeout
What if we remove 1.14.1 and leave 1.9.0? - Same thing.
Pet has to lick balls a bit to accept the result and think.
Maybe, it's worth trying Go tools? Pet does not want to be dragged into a Google's codemonkey cell but it has no choice. At least, it's just a test, not a real project, so it can jump off at any moment.
On a separate clean machine pet creates a directory with the basic go.mod
module test
go 1.25.0
require (
github.com/go-git/go-git/v5 v5.16.2
)
and runs go get .
What has it got? Here's what:
module test
go 1.25.0
require github.com/go-git/go-git/v5 v5.16.2
require (
dario.cat/mergo v1.0.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/ProtonMail/go-crypto v1.1.6 // indirect
github.com/cloudflare/circl v1.6.1 // indirect
github.com/cyphar/filepath-securejoin v0.4.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.2 // indirect
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/skeema/knownhosts v1.3.1 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
golang.org/x/crypto v0.37.0 // indirect
golang.org/x/net v0.39.0 // indirect
golang.org/x/sys v0.32.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
Surprise, mazafaka!
Where all those yaml
, check
, go-internal
?
Where?
Why?
Why go build
does not fail with this after all?
Pet has a thought that everything it saw before sucked in predictable ways, but Go...
Go is different.
Pet is unable to comprehend that. At the moment, at least.
Maybe pet fell into a mental trap trying to extrapolate all its irrelevant experience on the Go? Maybe Go is created by true geniuses and pet must peg thier pardon for its ignorance and all the crap above?
Well, enough wondering, let's try to reproduce.
While downloading and unpacking packages, and updating go.mod
, pet wonders why all those filepath-securejoin
,
gods
(Go data structures) are not in the standard library in the first place?
Why go-git
depends on so many different cryptography packages?
And how comes groupcache
and go-context
are v0, with no stability or backward compatibility guarantees
according to https://go.dev/doc/modules/version-numbers?
How comes a stable project with 6.9K stars, 283 contributors, a project "being used extensively by Keybase, Gitea or Pulumi, and by many other...", how comes it depends on unstable v0 packages? How comes nobody of all those 283 contributors made those packages stable?
Packages from golang.org/x is like a special hell. https://go.dev/wiki/X-Repositories says
Install them with “go get”.
Pet sees no alternative way!
https://cs.opensource.google/go/x sucks even more than GitHub.
No links to download packages. No hints for git
. Nothing but poor repository browser.
As for gopkg.in
, pet has no idea how to get anything from there.
Pet has no desire to figure out how to download remaining four packages,
it just copies them from the machine where it ran go get
.
But there's yet another interesting design decision beyond pet's comprehension:
files in ~/go
directory have read-only permission.
Which means pet has to chmod -R +w
before rm -rf
.
Why?
Pet should stop asking why when talking about humans.
All packages are in place at last, in deps
directoiry, and pet is ready to run go build
.
It fails:
./deps/gcfg-3a3c6141e376c06bf6ca92f0450e974250b4367a/errors.go:4:2: module ./deps/warnings.v0@v0.1.2: reading ./deps/warnings.v0@v0.1.2/go.mod: open /home/user/projects/thoughtful-pet/sitegen/deps/warnings.v0@v0.1.2/go.mod: no such file or directory
./deps/go-git-5.16.2/utils/ioutil/common.go:10:2: module ./deps/go-context-d14ea06fba99483203c19d92cfcd13ebe73135f4: reading ./deps/go-context-d14ea06fba99483203c19d92cfcd13ebe73135f4/go.mod: open /home/user/projects/thoughtful-pet/sitegen/deps/go-context-d14ea06fba99483203c19d92cfcd13ebe73135f4/go.mod: no such file or directory
./deps/go-git-5.16.2/plumbing/transport/ssh/common.go:15:2: module ./deps/ssh_config-1.2.0: reading ./deps/ssh_config-1.2.0/go.mod: open /home/user/projects/thoughtful-pet/sitegen/deps/ssh_config-1.2.0/go.mod: no such file or directory
Meooooow!
Conclusion
Pet gives up investigating this black box, although it feels to be very close...
Anyway, it's a waste of time.
The Go ecosystem looks heavily walled.
It smells. It stinks.
The presence of ~/.config/go/telemetry
crap is telling.
It's much worse than pissing in shoes.
How can pet trust Go developers?
How can pet trust their way of thinking?
The documentation does not unveil all details and suggests blindly using Go tools. All "In Depths" and "Deep Dive" articles pet found on the Internet are just castrated versions of it.
Yes, Go is open source but pet does not think it's worth studying the code. Pet does not see any practical purpose for that given that its curiosity has exhausted.
Nevertheless, shit was worth learning. But not too deep. No deeper than to understand how not to do things. No deeper than to understand how to make something better.
Shit may contain grains to consume, like kopi luwak, but no more than that.
Learning shit in depth is damaging, it paves the way to improving it. The most life wasting task ever.
Pet has to stick to the narrow "effective" way with a small modification to the process:
- put
~/go
directory on a shared volume - run
go get
on machine A - compile offline on machine B
Appendix
Here's the resulting go.mod
module test
go 1.25.0
require (
github.com/go-git/go-git/v5 v5.16.2
dario.cat/mergo v1.0.0
github.com/Microsoft/go-winio v0.6.2
github.com/ProtonMail/go-crypto v1.1.6
github.com/cloudflare/circl v1.6.1
github.com/cyphar/filepath-securejoin v0.4.1
github.com/emirpasic/gods v1.18.1
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376
github.com/go-git/go-billy/v5 v5.6.2
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99
github.com/kevinburke/ssh_config v1.2.0
github.com/pjbgf/sha1cd v0.3.2
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3
github.com/skeema/knownhosts v1.3.1
github.com/xanzy/ssh-agent v0.3.3
golang.org/x/crypto v0.37.0
golang.org/x/net v0.39.0
golang.org/x/sys v0.32.0
gopkg.in/warnings.v0 v0.1.2
)
replace (
github.com/go-git/go-git/v5 v5.16.2 => ./deps/go-git-5.16.2
dario.cat/mergo v1.0.0 => ./deps/mergo-1.0.0
github.com/Microsoft/go-winio v0.6.2 => ./deps/go-winio-0.6.2
github.com/ProtonMail/go-crypto v1.1.6 => ./deps/go-crypto-1.1.6
github.com/cloudflare/circl v1.6.1 => ./deps/circl-1.6.1
github.com/cyphar/filepath-securejoin v0.4.1 => ./deps/filepath-securejoin-0.4.1
github.com/emirpasic/gods v1.18.1 => ./deps/gods-1.18.1
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 => ./deps/gcfg-3a3c6141e376c06bf6ca92f0450e974250b4367a
github.com/go-git/go-billy/v5 v5.6.2 => ./deps/go-billy-5.6.2
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 => ./deps/groupcache-2c02b8208cf8c02a3e358cb1d9b60950647543fc
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 => ./deps/go-context-d14ea06fba99483203c19d92cfcd13ebe73135f4
github.com/kevinburke/ssh_config v1.2.0 => ./deps/ssh_config-1.2.0
github.com/pjbgf/sha1cd v0.3.2 => ./deps/sha1cd-0.3.2
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 => ./deps/go-diff-5b0b94c5c0d3d261e044521f7f46479ef869cf76
github.com/skeema/knownhosts v1.3.1 => ./deps/knownhosts-1.3.1
github.com/xanzy/ssh-agent v0.3.3 => ./deps/ssh-agent-0.3.3
golang.org/x/crypto v0.37.0 => ./deps/crypto@v0.37.0
golang.org/x/net v0.39.0 => ./deps/net@v0.39.0
golang.org/x/sys v0.32.0 => ./deps/sys@v0.32.0
gopkg.in/warnings.v0 v0.1.2 => ./deps/warnings.v0@v0.1.2
)