Spesifikasi lengkap Build Event Protocol dapat ditemukan dalam definisi buffering protokolnya. Namun, membangun beberapa intuisi sebelum melihat spesifikasinya mungkin akan bermanfaat.
Pertimbangkan ruang kerja Bazel sederhana yang terdiri dari dua skrip shell kosong
foo.sh
dan foo_test.sh
, serta file BUILD
berikut:
sh_library(
name = "foo_lib",
srcs = ["foo.sh"],
)
sh_test(
name = "foo_test",
srcs = ["foo_test.sh"],
deps = [":foo_lib"],
)
Saat menjalankan bazel test ...
di project ini, grafik build peristiwa build yang dihasilkan akan terlihat seperti grafik di bawah. Tanda panah menunjukkan
hubungan induk dan turunan yang disebutkan di atas. Perlu diperhatikan bahwa beberapa peristiwa build dan sebagian besar kolom telah dihilangkan agar lebih singkat.
Gambar 1. Grafik BEP.
Awalnya, peristiwa BuildStarted
dipublikasikan. Peristiwa ini memberi tahu kita bahwa build dipanggil melalui perintah bazel test
dan mengumumkan peristiwa turunan:
OptionsParsed
WorkspaceStatus
CommandLine
UnstructuredCommandLine
BuildMetadata
BuildFinished
PatternExpanded
Progress
Tiga kejadian pertama memberikan informasi tentang bagaimana Bazel dipanggil.
Peristiwa build PatternExpanded
memberikan insight tentang target spesifik yang diperluas pola ...
ke:
//foo:foo_lib
dan //foo:foo_test
. Hal ini dilakukan dengan mendeklarasikan dua
peristiwa TargetConfigured
sebagai turunan. Perhatikan bahwa peristiwa TargetConfigured
mendeklarasikan peristiwa Configuration
sebagai peristiwa turunan, meskipun Configuration
telah diposting sebelum peristiwa TargetConfigured
.
Selain hubungan induk dan turunan, peristiwa juga dapat saling merujuk
menggunakan ID peristiwa build-nya. Misalnya, dalam grafik di atas,
peristiwa TargetComplete
merujuk ke peristiwa NamedSetOfFiles
di kolom
fileSets
-nya.
Peristiwa build yang merujuk ke file biasanya tidak menyematkan nama
file dan jalur dalam peristiwa. Sebaliknya, modul ini berisi ID peristiwa build
dari peristiwa NamedSetOfFiles
, yang kemudian akan berisi nama file dan jalur
yang sebenarnya. Peristiwa NamedSetOfFiles
memungkinkan kumpulan file dilaporkan sekali dan
disebut oleh banyak target. Struktur ini diperlukan karena jika tidak,
dalam beberapa kasus, ukuran output Build Event Protocol akan bertambah secara kuadrat sesuai
jumlah file. Peristiwa NamedSetOfFiles
mungkin juga tidak semua filenya disematkan, tetapi merujuk ke peristiwa NamedSetOfFiles
lain melalui ID peristiwa build-nya.
Berikut adalah instance peristiwa TargetComplete
untuk target //foo:foo_lib
dari grafik di atas, yang dicetak dalam representasi JSON buffering protokol.
ID peristiwa build berisi target sebagai string buram dan merujuk ke peristiwa Configuration
menggunakan ID peristiwa build-nya. Peristiwa ini tidak
mengumumkan peristiwa turunan apa pun. Payload berisi informasi tentang apakah
target berhasil dibuat, kumpulan file output, dan jenis target
yang dibangun.
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
}
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "0"
}]
}],
"targetKind": "sh_library rule"
}
}
Hasil Aspect di BEP
Build biasa mengevaluasi tindakan yang terkait dengan pasangan
(target, configuration)
. Saat membuat build dengan aspects diaktifkan, Bazel
juga mengevaluasi target yang terkait dengan (target, configuration,
aspect)
triple, untuk setiap target yang terpengaruh oleh aspek yang diaktifkan tertentu.
Hasil evaluasi untuk aspek tersedia di BEP meskipun tidak ada
jenis peristiwa khusus aspek. Untuk setiap pasangan (target, configuration)
dengan
aspek yang berlaku, Bazel memublikasikan peristiwa TargetConfigured
dan
TargetComplete
tambahan yang hasilnya diperoleh dari penerapan aspek tersebut ke
target. Misalnya, jika //:foo_lib
di-build dengan
--aspects=aspects/myaspect.bzl%custom_aspect
, peristiwa ini juga akan muncul di
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"
}]
}]
}
}
Memakai NamedSetOfFiles
Menentukan artefak yang dihasilkan oleh target (atau aspek) tertentu adalah kasus penggunaan
BEP umum yang dapat dilakukan secara efisien dengan beberapa persiapan. Bagian ini
membahas struktur bersama rekursif yang ditawarkan oleh peristiwa
NamedSetOfFiles
, yang cocok dengan struktur Depset Starlark.
Konsumen harus berhati-hati untuk menghindari algoritma kuadrat saat memproses peristiwa NamedSetOfFiles
karena build berukuran besar dapat berisi puluhan ribu peristiwa tersebut, yang memerlukan ratusan juta operasi dalam traversal dengan kompleksitas kuadrat.
Gambar 2. Grafik BEP NamedSetOfFiles
.
Peristiwa NamedSetOfFiles
selalu muncul di aliran BEP sebelum peristiwa TargetComplete
atau NamedSetOfFiles
yang mereferensikannya. Ini adalah
kebalikan dari hubungan peristiwa "induk-turunan", dengan semua peristiwa kecuali peristiwa pertama
muncul setelah setidaknya satu peristiwa yang mengumumkannya. Peristiwa NamedSetOfFiles
diumumkan oleh peristiwa Progress
tanpa semantik.
Dengan adanya batasan pengurutan dan pembagian ini, konsumen standar harus melakukan buffering semua
peristiwa NamedSetOfFiles
hingga aliran data BEP habis. Aliran peristiwa JSON dan kode Python berikut menunjukkan cara mengisi peta dari target/aspek ke artefak yang dibangun dalam grup output "default", dan cara memproses output untuk subset target/aspek yang dibuat:
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)