Add: Building golang cli tools update
This commit is contained in:
parent
64c3b87e88
commit
eed92f9df5
112
content/posts/2015-10-12-building-golang-cli-tools-update.md
Normal file
112
content/posts/2015-10-12-building-golang-cli-tools-update.md
Normal file
|
@ -0,0 +1,112 @@
|
|||
+++
|
||||
date = "2015-10-12"
|
||||
title = "Building Golang CLI Tools Update"
|
||||
tags = ["golang"]
|
||||
description = "After my previous post on using a `Makefile` to set version and build info I got some valuable feedback from other Gophers. Here's an update."
|
||||
slug = "building-golang-cli-tools-update"
|
||||
+++
|
||||
|
||||
In my [previous post][previous] I discussed how to use a `Makefile` to set version and
|
||||
build information at compile time. Although this approach may work fine for you, it has
|
||||
three drawbacks I want to discuss.
|
||||
|
||||
### 1. Simplicity
|
||||
|
||||
Andrew responded on the [golang-nuts mailing list][golang-nuts] with the following comment:
|
||||
|
||||
> To me it seems like you took something simple and cross platform "go generate" + "go install/build" and turned it into something more complicated and less portable.
|
||||
|
||||
Although I'm not sure `go generate` is relevant in this case, I agree that on some level
|
||||
a `Makefile` is complicating things unnecessarily. Let's remove it!
|
||||
|
||||
### 2. Non-reproducable builds
|
||||
|
||||
Guilio responded with:
|
||||
|
||||
> I only have an issue with buildTime: it makes the build not reproducible.
|
||||
|
||||
This is a valid point. The idea that if you compile a given version of your application,
|
||||
the resulting binary's hash (be it MD5 or whatever) should be equal to that of any other
|
||||
binary build from that specific version.
|
||||
|
||||
By using `BuildTime` the binary is never the same.
|
||||
|
||||
Build time is also irrelevant. It does not matter _when_ a binary was compiled, but it
|
||||
_does matter_ which precise version was build.
|
||||
|
||||
Let's replace `BuildTime` with the current git commit hash instead.
|
||||
|
||||
### 3. Why is there a `VERSION` file?
|
||||
|
||||
If you're going to store version information under version control, you might as well
|
||||
put it right in the code, where it belongs.
|
||||
|
||||
Let's remove `VERSION` and instead create a nice `version.go` to handle everything.
|
||||
|
||||
## Let's refactor
|
||||
|
||||
Okay, first things to go are `Makefile` and `VERSION`.
|
||||
|
||||
Next, I created a `core/version.go` which contains the necessary version information.
|
||||
I've also taken the liberty of creating a proper struct for the version information,
|
||||
including major, minor and patch numbers, as well as a label and release name.
|
||||
|
||||
package core
|
||||
|
||||
import "fmt"
|
||||
|
||||
type version struct {
|
||||
Major, Minor, Patch int
|
||||
Label string
|
||||
Name string
|
||||
}
|
||||
|
||||
var Version = version{1, 2, 3, "dev", "Chuck Norris"}
|
||||
|
||||
var Build string
|
||||
|
||||
func (v version) String() string {
|
||||
if v.Label != "" {
|
||||
return fmt.Sprintf("Roll version %d.%d.%d-%s \"%s\"\nGit commit hash: %s", v.Major, v.Minor, v.Patch, v.Label, v.Name, Build)
|
||||
} else {
|
||||
return fmt.Sprintf("Roll version %d.%d.%d \"%s\"\nGit commit hash: %s", v.Major, v.Minor, v.Patch, v.Name, Build)
|
||||
}
|
||||
}
|
||||
|
||||
As you can see, it's quite easy to set and update the version numbers, label and release name.
|
||||
|
||||
`Build` is still set at compile time and contains the current git commit hash.
|
||||
|
||||
Because the `go build` command is quite long, I've put it in a nice `build.sh` file that
|
||||
makes building easier.
|
||||
|
||||
go build -ldflags "-X github.com/ariejan/roll/core.Build=`git rev-parse HEAD`" -o roll main.go
|
||||
|
||||
This will result in a build that reports version information like this:
|
||||
|
||||
$ ./roll version
|
||||
Roll version 1.2.3-dev "Chuck Norris"
|
||||
Git commit hash: b72b076af8b18ef4f6b10296f12840f23258acec
|
||||
|
||||
### Check that SHA
|
||||
|
||||
If you want, you can [grab the code][code] and run `./build.sh` yourself. The resulting binary
|
||||
has a SHA-1 of `3ad7509279690d99e4144332dc200ede732663fd`. Yay for reproducable builds!
|
||||
|
||||
### Naming variables in ldlags
|
||||
|
||||
A short note on Peter Kleiweg's comment. He pointed out that I could use
|
||||
|
||||
"-X main.Build=`git rev-parse HEAD`"
|
||||
|
||||
This would be true if the `Build` variable is in the `main` package. But because it's
|
||||
not (it's in `core`) I have to specify the full package name.
|
||||
|
||||
## Thank you!
|
||||
|
||||
Thanks to all the awesome gophers responding to my previous post! It's great to get
|
||||
feedback and get to learn more about Golang. Keep the comments coming, please!
|
||||
|
||||
[previous]: https://ariejan.net/2015/10/03/a-makefile-for-golang-cli-tools/
|
||||
[golang-nuts]: https://groups.google.com/forum/#!forum/golang-nuts
|
||||
[code]: https://github.com/ariejan/roll
|
Loading…
Reference in New Issue
Block a user