Posted at

bazelでMacroを作成する

More than 3 years have passed since last update.


version

henteko@~  $ bazel version

Build label: 0.1.1
Build target: bazel-out/local_darwin-fastbuild/bin/src/main/java/bazel-main_deploy.jar
Build time: Thu Oct 15 20:51:11 2015 (1444942271)
Build timestamp: 1444942271
Build timestamp as int: 1444942271


プロジェクト構成

今回のサンプルプロジェクトです

以下がプロジェクト構成です

Macroを作成するだけなのでシンプルにしました

henteko@~/Desktop/dev/sample  $ tree

.
├── BUILD
├── WORKSPACE
├── android.apk
└── deploygate.bzl

0 directories, 4 files


Macroを作成する

基本はBazel公式のドキュメントに書いてあります

今回作成するMacroは、ローカルにあるapkをDeployGateにアップロードするようなMacroです

最終的にはBUILDファイルに以下のように書くことで、Macroを実行できるようにします

load("deploygate", "deploygate")

deploygate(
name = "deploy",
user_name = "your_deploygate_name",
api_key = "your_deploygate_api_key",
apk = "android.apk"
)

$ bazel build //:deploy


deploygate.bzlの作成

bazelのMacroでは.bzlファイルを作成して、各Macroごとの引数の指定や実際の処理を書きます


処理の記述

実際の処理は以下のように書きます

def _impl(ctx):

out = ctx.outputs.result
apk = ctx.file.apk
name = ctx.attr.user_name
api_key = ctx.attr.api_key
ctx.action(
outputs = [out],
inputs = [apk],
command = "curl -F 'file=@%s' -F 'token=%s' -F 'message=sample' https://deploygate.com/api/users/%s/apps > %s" % (apk.path, api_key, name, out.path),
)

処理の記述にはPaythonに似たbazel独自言語を使って記述します

ctx.fileやctx.attrにはMacroの引数指定で指定した文字列などが渡ってきます

今回はDeployGateにcurlを使ってapkをアップロードするためにcurlを実行するようにしてます

ctx.actionはコマンドをそのまま実行することができるんですが、outputsファイルを指定しなければいけないので、curlで得た文字列(deploygateの場合はjson)をそのままoutputsとして吐き出すようにしてます


Macroの引数指定

Macroの引数指定にはrule関数を使います

これがMacro自身のインターフェースを表します

deploygate = rule(

implementation=_impl,
attrs={
"user_name": attr.string(mandatory=True),
"api_key": attr.string(mandatory=True),
"apk": attr.label(mandatory=True, allow_files=True, single_file=True),
},
outputs = {"result": "%{name}_result.txt"},
)

これだとuser_name, api_key, apkが引数指定されています

また、mandatory=Trueにしているとこの引数は必須となり、引数として足らないと実行時にエラーになって怒ってくれます、便利

attrにはstringやlabel以外にも色々な型があるので、詳しくは公式ドキュメントを参照してください

これでMacroの作成は終了です

あとは BUILDファイルに上で説明したように記述すると、deployビルドを実行することができます


deploygate.bzlの全体


deploygate.bzl

def _impl(ctx):

out = ctx.outputs.result
apk = ctx.file.apk
name = ctx.attr.user_name
api_key = ctx.attr.api_key
ctx.action(
outputs = [out],
inputs = [apk],
command = "curl -F 'file=@%s' -F 'token=%s' -F 'message=sample' https://deploygate.com/api/users/%s/apps > %s" % (apk.path, api_key, name, out.path),
)

deploygate = rule(
implementation=_impl,
attrs={
"user_name": attr.string(mandatory=True),
"api_key": attr.string(mandatory=True),
"apk": attr.label(mandatory=True, allow_files=True, single_file=True),
},
outputs = {"result": "%{name}_result.txt"},
)



さいごに

今回bazel周りを触ってみた感想としては、 Androidをビルドするにしてもまだまだ環境が整ってなくて結構苦労するなという印象でした

ただ、Macroの作成などは比較的簡単に行えそうな感じがしました

それと、buildでは何もdiffがないとそもそも実行されないので、余分なCPUリソースを使わなくてすんで親切な気がします

来年のAndroidStudio統合が待ち遠しいですね