I'm trying to bake the mercurial version into my Bazel file, so that I can get something like this:
# These I set manually, since they're "semantic"
MAJOR_VERSION = 2
MINOR_VERSION = 3
BUGFIX_VERSION = 1
# This should be the result of `hg id -n`
BUILD_VERSION = ?
apple_bundle_version(
name = "my_version",
build_version = "{}.{}.{}.{}".format(MAJOR_VERSION, MINOR_VERSION, BUGFIX_VERSION, BUILD_VERSION),
short_version_string = "{}.{}.{}".format(MAJOR_VERSION, MINOR_VERSION, BUGFIX_VERSION),
)
This obviously is not hermetic, so I know it violates some of Bazel's assumptions, so I'm open to other options.
Here's some possible options:
Actually run
hg id -n
during Bazel analysis, which I don't know how to do.Pass the build version in via command line, e.g.,
--define=build_version=$(hg id -n)
. Unfortunately, this requires a separate command to wrapbazel build
.Manually set the
BUILD_VERSION
. Obviously, this would be annoying.
Is there a way to do #1? What are my other options?
Yes, you can do this with a custom
--workspace_status_command
and a genrule that processes the information and generates source files with this data.EDIT: I removed the parts about the
--stamp
flag, it's not needed.Summary
--workspace_status_command=/path/to/binary
with a custom binary or shell script that runshg
and outputs the information you need.genrule
withstamp=1
.Details
1.
--workspace_status_command=/path/to/binary
The
--workspace_status_command=<path>
flag lets you specify a binary.Bazel runs this binary before each build. The binary should write key-value pairs to stdout. Bazel partitions the keys into two buckets: "stable" and "volatile". (The names "stable" and "volatile" are a bit counter-intuitive, so don't think much about them.)
Bazel then writes the key-value pairs into two files:
bazel-out/stable-status.txt
contains all keys and values where the key's name starts withSTABLE_
bazel-out/volatile-status.txt
contains the rest of the keys and their valuesThe contract is:
stable-status.txt
change, it invalidates the actions that depend on them, e.g. thegenrule.cmd
if that genrule hasstamp=1
. In other words, if a stable key's value changes, it'll make Bazel rebuild stamped actions. Therefore the stable status should not contain things like timestamps, because they change all the time, and would make Bazel rebuild the stamped actions with each build.volatile-status.txt
file. In order to avoid rebuilding stamped actions all the time though, Bazel pretends that the volatile file never changes. In other words, if the volatile status file is the only one whose contents changed, that will not invalidate actions that depend on it. If other inputs of the actions have changed, then Bazel rebuilds that action, and the action may then use the updated volatile status. But just the volatile status changing alone will not invalidate the action.Example for
my-status.sh
:2. Write a
genrule
withstamp=1
.This attribute is undocumented, which surprises me. I'll file a bug about that.
Example for
foo/BUILD
:Putting it all together
The genrule isn't rebuilt
...when only
bazel-out/volatile-status.txt
changes:The genrule is rebuilt
...when the stable status or the genrule's inputs change:
By default, the
apple_bundle_version
rule uses regular expressions to parse whatever you pass in to--embed_label
on the Bazel command line.So, the simplest way to achieve this would be first writing something like this:
bazel build //your:target --embed_label="$(hd id -n)"
That will set
BUILD_EMBED_LABEL
to the your Mercurial version in your workspace info file, for example:Then you have to tell
apple_bundle_version
what your version numbers should look like:Something like that should do the trick.
Getting more advanced
If you don't want to manually pass the result of
hg id -n
each time you build, theapple_bundle_version
rule is extensible so you can make it happen automatically. The only requirement of theversion
attribute onios_application
and related rules is that it point to a target that returns anAppleBundleVersionInfo
provider—it doesn't have to beapple_bundle_version
.That provider propagates a small JSON file containing your bundle version and short bundle version string, so you could write your own rule that invokes
hg id -n
as a custom action, writes it out to a JSON formatted file with the right keys, and then use that target as yourversion
attribute on your application instead.