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:

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
)