Build Event Protocol の完全な仕様については、そのプロトコル 使用します。ただし、なんらかの直感を身につけておくと、 確認する必要があります
2 つの空のシェル スクリプトで構成される単純な Bazel ワークスペースについて考えてみましょう。
foo.sh
、foo_test.sh
、および次の BUILD
ファイル:
sh_library(
name = "foo_lib",
srcs = ["foo.sh"],
)
sh_test(
name = "foo_test",
srcs = ["foo_test.sh"],
deps = [":foo_lib"],
)
このプロジェクトで bazel test ...
を実行すると、生成された結果のビルドグラフが表示されます。
ビルドイベントは下のグラフのようになります矢印は
前述した親子関係によって決まります。なお、一部のビルドイベントと
簡略化のためにほとんどのフィールドは省略されています。
図 1. BEP グラフ。
最初に BuildStarted
イベントがパブリッシュされます。このイベントから
bazel test
コマンドでビルドが呼び出され、子イベントが通知されます。
OptionsParsed
WorkspaceStatus
CommandLine
UnstructuredCommandLine
BuildMetadata
BuildFinished
PatternExpanded
Progress
最初の 3 つのイベントは、Bazel の呼び出し方法に関する情報を提供します。
PatternExpanded
ビルドイベントによって分析情報が提供される
...
パターンが展開され、特定のターゲットに展開されます。
//foo:foo_lib
と //foo:foo_test
。そのために、この変数に
TargetConfigured
イベントを子として割り当てます。TargetConfigured
イベントは、
Configuration
であっても、Configuration
イベントを子イベントとして宣言します。
TargetConfigured
イベントの前に投稿されました。
親と子の関係のほかに、イベントは相互を参照する場合もあります。
ビルドイベント識別子を使用しますたとえば、上のグラフでは、
TargetComplete
イベントは、fileSets
の NamedSetOfFiles
イベントを参照します。
表示されます。
通常、ファイルを参照するビルドイベントにファイルが埋め込まれない
イベント内の名前とパスです。代わりに、ビルドイベント ID が含まれます。
NamedSetOfFiles
イベント。これには実際のファイル名と
あります。NamedSetOfFiles
イベントを使用すると、一連のファイルを 1 回報告し、
多くのターゲットから参照されます。この構造が必要になるのは、
場合によっては、Build Event Protocol の出力サイズが
最適化されます。NamedSetOfFiles
イベントにファイルの一部が含まれていない場合もあります。
代わりに他の NamedSetOfFiles
イベントを
ビルドイベント識別子。
以下は、//foo:foo_lib
の TargetComplete
イベントのインスタンスです。
プロトコル バッファの JSON 表現で出力されます。
ビルドイベント ID には、ターゲットが不透明な文字列として含まれており、
ビルドイベント ID を使用して Configuration
イベント。このイベントは
すべての子イベントを通知しますペイロードには、リクエストが
ターゲットが正常にビルドされたかどうか、出力ファイルのセット、ターゲットの種類が確認できます。
構築しました。
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
}
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "0"
}]
}],
"targetKind": "sh_library rule"
}
}
BEP での Aspect 結果
通常のビルドは、(target, configuration)
に関連付けられたアクションを評価します。
あります。アスペクトを有効にしてビルドすると、Bazel
さらに、指定された有効なアスペクトの影響を受けるターゲットごとに、(target, configuration,
aspect)
個のトリプルに関連付けられたターゲットを評価します。
アスペクトの評価結果は、
イベントタイプを指定します。(target, configuration)
ペアごとに、
Bazel は追加の TargetConfigured
を発行し、
TargetComplete
アスペクトを
あります。たとえば、//:foo_lib
が
--aspects=aspects/myaspect.bzl%custom_aspect
、この予定は次の場所でも表示されます
BEP:
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
},
"aspect": "aspects/myaspect.bzl%custom_aspect"
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "1"
}]
}]
}
}
NamedSetOfFiles
の消費
特定の標的(またはアスペクト)によって生成されたアーティファクトを決定することは、一般的です。
ある程度の準備をすれば効率的に実行できる BEP のユースケース。このセクション
NamedSetOfFiles
によって提供される再帰の共有構造について説明します。
このイベントは、Starlark Depset の構造と一致します。
消費者は処理時に二次アルゴリズムを避けるように注意する必要がある
NamedSetOfFiles
イベントを発生させます。これは、大規模なビルドには何万ものビルドが含まれることがあるためです。
トラバーサルで数億件のオペレーションを必要とするため、
二次複雑度です。
図 2. NamedSetOfFiles
BEP グラフ。
NamedSetOfFiles
イベントは、常に BEP ストリームの次の前に表示されます。
それを参照する TargetComplete
イベントまたは NamedSetOfFiles
イベント。これが
「親子」の逆数最初のイベントは 1 つのみとなります。
少なくとも 1 つのイベントがそれを発表した後に表示されます。NamedSetOfFiles
イベントは
(セマンティクスのない Progress
イベント)で通知されるイベントです。
順序と共有に関するこうした制約を考慮すると、一般的なコンシューマでは、
NamedSetOfFiles
イベントを保持し、BEP ストリームがなくなるまで待機します。次の JSON
イベント ストリームと Python コードで、イベントストリームから
「デフォルト」のビルド アーティファクトのターゲット/アスペクト出力グループ、さらには
ビルドされたターゲット/アスペクトのサブセットの出力を処理します。
named_sets = {} # type: dict[str, NamedSetOfFiles]
outputs = {} # type: dict[str, dict[str, set[str]]]
for event in stream:
kind = event.id.WhichOneof("id")
if kind == "named_set":
named_sets[event.id.named_set.id] = event.named_set_of_files
elif kind == "target_completed":
tc = event.id.target_completed
target_id = (tc.label, tc.configuration.id, tc.aspect)
outputs[target_id] = {}
for group in event.completed.output_group:
outputs[target_id][group.name] = {fs.id for fs in group.file_sets}
for result_id in relevant_subset(outputs.keys()):
visit = outputs[result_id].get("default", [])
seen_sets = set(visit)
while visit:
set_name = visit.pop()
s = named_sets[set_name]
for f in s.files:
process_file(result_id, f)
for fs in s.file_sets:
if fs.id not in seen_sets:
visit.add(fs.id)
seen_sets.add(fs.id)