Embedding Data Into Go Programs
In this lesson, we'll use a built-in technique to embed the git tag and the time the program that was built into our executable. Then, we'll use this information inside the program.
We'll cover the following
Incorporating git tag for auto versioning
Versioning your code is a good practice. If you use a source control system like git, then you can tag commits using the git tag
command. However, when you build your code, the program has no notion of the version of the source code it was built from.
One approach is to maintain a VERSION file or a version
constant in your code and increment it every time you make a change. This is somewhat error-prone and redundant if you already tag your code.
Instead, we can embed the git tag automatically during build time. The key is to pass a -X option to -ldflags
that specifies a package and variable in the program and the value.
$ go build -ldflags="-X '<package>.<variable>=<value>'"
To get the git tag during build time we can use the following command:
$ git describe --tags
v0.6
As long as we embed information we can also add the time it was built:
$ date -u
Thu Jul 2 23:51:55 UTC 2020
Embedding information into multi-git
Letโs put everything together and embed the git tag and build time into multi-git.
First, letโs define the GitTag
and Timestamp
variables in main.go:
var (
GitTag string
Timestamp string
)
Then, if the variables are specified, weโll print them out:
func main() {
if GitTag != "" {
fmt.Printf("Git tag : %s\nBuilt at: %s\n\n", GitTag, Timestamp)
}
cmd.Execute()
}
To embed the git tag and the build timestamp, we can use the following build command:
$ go build -ldflags "-X 'main.GitTag=$(git describe --tags)' -X 'main.Timestamp=$(date -u)'"
Here is the result:
$ ./multi-git
Git tag : v0.6
Built at: Fri Jul 3 00:20:51 UTC 2020
Error: accepts 1 arg(s), received 0
Usage:
multi-git [flags]
Flags:
--config string config file path (default is $HOME/multi-git.toml) (default "/Users/gigi.sayfan/.config/multi-git.toml")
-h, --help help for multi-git
--ignore-errors will continue executing the command for all repos if ignore-errors is true
otherwise it will stop execution when an error occurs
2020/07/02 17:20:58 accepts 1 arg(s), received 0
The git tag and the build time are displayed first before any input. If multi-git had a version command or flag, I would probably incorporate this information in the version output.
For convenience, we can write the build command to its own file:
#!/usr/bin/env zsh
go build -ldflags "-X 'main.GitTag=$(git describe --tags)' -X 'main.Timestamp=$(date -u)'"
Letโs commit our changes and try again:
(๐)/multi-git/
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: build.sh
modified: main.go
Untracked files not listed (use -u option to show untracked files)
(๐)/multi-git/
$ git add .
(๐)/multi-git/
$ git commit -m "embed git tag and build time + display at runtime"
[master 385da0a] embed git tag and build time + display at runtime
2 files changed, 15 insertions(+)
create mode 100755 build.sh
Now, letโs build using the shell script and run again:
(๐)/multi-git/
$ ./build.sh
(๐)/multi-git/
$ ./multi-git
Git tag : v0.6-1-g385da0a
Built at: Fri Jul 3 00:28:06 UTC 2020
Error: accepts 1 arg(s), received 0
Usage:
multi-git [flags]
Flags:
--config string config file path (default is $HOME/multi-git.toml) (default "/Users/gigi.sayfan/.config/multi-git.toml")
-h, --help help for multi-git
--ignore-errors will continue executing the command for all repos if ignore-errors is true
otherwise it will stop execution when an error occurs
2020/07/02 17:28:12 accepts 1 arg(s), received 0
As you can see, the tag has changed. Since the last commit wasnโt tagged, git describe --tags
returns the most recent tag (v0.6), followed by the number of commits since this tag (1), followed by a short SHA algorithm of the most recent commit. The result is a human-readable description of the current version of the code and its relation to any tags.
Conclusion
Go has sophisticated tooling as a first-class citizen of the language. You can cross-compile, integrate with C, build self-contained executables with all their dependencies and embed data in your executables. The go build
command provides a lot of knobs to control the build process. In this lesson, we embedded the git tag and built a timestamp into multi-git. I suggest you study the various flags of the go build
command because you may find some hidden treasures.
Quiz
Get hands-on with 1400+ tech skills courses.