diff --git a/README.md b/README.md index c1abe7d..165419a 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ func main() { } ``` -This code is not maintained, and I will not accept PRs. Fork it if you want it. It's like 50 lines, just copy it into your codebase. +This code is not maintained, and I will not accept PRs to add features. Fork it if you want it. It's like 50 lines, just copy it into your codebase and go to town. Please stop using `ldflags` to embed this information. Or if you do, at least embed a reproducible time. @@ -36,6 +36,8 @@ go build -ldflags="-X 'main.commit=$(git rev-parse HEAD)'" This was kinda gross, but it worked, so people did it. And _boy_ did they do it. This little trick got cargo-culted all over the place! Anecdotally, basically any Go application you use has its version embedded this way. +Don't believe me? [Here's about 76,000 hits on GitHub for `ldflags` and `golang` in `Makefile`s](https://github.com/search?type=code&q=ldflags+%22golang%22+path%3AMakefile). Not _all_ of these are embedding version information in `ldflags`, but most of them are. And what's worse, they're all doing the same thing in a very non-standard way, not just writing `main.commit`, but all kinds of stuff like `github.com/wish/eventmaster.Version`, [`k8s.io/client-go/pkg/version.gitCommit`](https://github.com/kubernetes/client-go/blob/kubernetes-1.32.3/pkg/version/base.go#L60), [`k8s.io/release-utils/pkg/version.gitCommit`](https://github.com/kubernetes-sigs/release-utils/blob/v0.11.1/version/version.go#L44), and tons more. The cargo-cult has spread far and wide. + Sometimes folks also wanted a build date embedded, and okay, sure, we can do that too: ``` @@ -52,10 +54,16 @@ go build -ldflags="-X 'main.buildDate=$(date -d@$SOURCE_DATE_EPOCH +%Y-%m-%dT%H: and some sane static value of `SOURCE_DATE_EPOCH` to make that reproducible. Most folks would opt for the date of the commit that it's built from as a sane approach. -_But you don't need to do any of this at all, so stop!_ +As an aside, `k8s.io/client-go` had a [fun bug](https://github.com/kubernetes/kubernetes/issues/99376) where the way they were embedding the abbreviated Git commit would sometimes make the dependency non-reproducible, leading to [non-reproducible builds for anything that depended on that package](https://github.com/ko-build/ko/issues/315), of which there are ...many. -**Since Go 1.12, back in 2019**, the Go compiler has embedded this exact information for you, without you needing to know what an `ldflag` is. You can just call [`debug.ReadBuildInfo`](https://pkg.go.dev/runtime/debug#ReadBuildInfo) and it'll pop right out, along with a bunch of other stuff. +_But you don't need to do any of this nonsense at all, so stop!_ + +**Since Go 1.12, back in 2019**, the Go compiler has embedded this information for you, without you needing to know what an `ldflag` is. You can just call [`debug.ReadBuildInfo`](https://pkg.go.dev/runtime/debug#ReadBuildInfo) and it'll pop right out, along with a bunch of other stuff. + +(The embedded information does not include information about the Git tag, presumably because there could be many of them, and they can easily move after the binary is built, so it's really the commit and its time that you care about.) The `vcs.revision` and `vcs.time` are exactly the same as `git rev-parse HEAD` and "the date of that commit". So stop mucking with `ldflags`, and _especially_ stop embedding a non-reproducible time. You're working too hard. -This package demonstrates this, and encapsulates it in `version.Get`. If you want to change anything about the behavior, copy the code and go for it. I wrapped it in a [`sync.OnceFunc`](https://pkg.go.dev/sync#OnceFunc) so it didn't have to read the info each time, in case you call it multiple times. You're welcome. +This package demonstrates embedding `vcs.revision`, `vcs.time` and `vcs.clean` (whether there are non-committed changes), and encapsulates it in `version.Get`. + +If you want to change anything about the behavior, copy the code and go for it. I wrapped it in a [`sync.OnceFunc`](https://pkg.go.dev/sync#OnceFunc) so it didn't have to read the info each time, in case you call it multiple times. You're welcome.