Spesifikasi lengkap Build Event Protocol dapat ditemukan dalam definisi buffer protokolnya. Namun, akan lebih baik jika Anda membangun intuisi terlebih dahulu sebelum melihat spesifikasinya.
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 dari peristiwa build yang dihasilkan akan menyerupai grafik di bawah. Panah menunjukkan hubungan induk dan turunan yang disebutkan di atas. Perhatikan bahwa beberapa peristiwa build dan
sebagian besar kolom telah dihilangkan agar lebih ringkas.
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 peristiwa pertama memberikan informasi tentang cara Bazel dipanggil.
Peristiwa build PatternExpanded
memberikan insight tentang target spesifik yang diperluas oleh pola ...
:
//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 merujuk satu sama lain
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 dan jalur file dalam peristiwa. Sebagai gantinya, file tersebut berisi ID peristiwa build
dari peristiwa NamedSetOfFiles
, yang kemudian akan berisi nama dan
jalur file sebenarnya. Peristiwa NamedSetOfFiles
memungkinkan sekumpulan file dilaporkan satu kali dan
dirujuk oleh banyak target. Struktur ini diperlukan karena jika tidak, dalam beberapa kasus, ukuran output Build Event Protocol akan bertambah secara kuadratik dengan jumlah file. Peristiwa NamedSetOfFiles
mungkin juga tidak menyematkan semua filenya, tetapi merujuk ke peristiwa NamedSetOfFiles
lainnya melalui ID peristiwa build-nya.
Di bawah ini adalah instance peristiwa TargetComplete
untuk target //foo:foo_lib
dari grafik di atas, yang dicetak dalam representasi JSON buffer protokol.
ID peristiwa build berisi target sebagai string buram dan merujuk ke
peristiwa Configuration
menggunakan ID peristiwa build-nya. Peristiwa tidak mengumumkan peristiwa turunan apa pun. Payload berisi informasi tentang apakah
target berhasil dibangun, 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 Aspek dalam BEP
Build biasa mengevaluasi tindakan yang terkait dengan pasangan (target, configuration)
. Saat membangun dengan aspek yang diaktifkan, Bazel juga mengevaluasi target yang terkait dengan tripel (target, configuration,
aspect)
, 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 berisi hasil dari penerapan aspek ke target. Misalnya, jika //:foo_lib
dibuat 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"
}]
}]
}
}
Menggunakan 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 rekursif bersama yang ditawarkan oleh peristiwa NamedSetOfFiles
, yang cocok dengan struktur Depset Starlark.
Konsumen harus berhati-hati untuk menghindari algoritma kuadratik saat memproses peristiwa
NamedSetOfFiles
karena build besar dapat berisi puluhan ribu peristiwa
tersebut, yang memerlukan ratusan juta operasi dalam traversal dengan
kompleksitas kuadratik.
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", di mana semua peristiwa kecuali peristiwa pertama
muncul setelah setidaknya satu peristiwa mengumumkannya. Peristiwa NamedSetOfFiles
diumumkan oleh peristiwa Progress
tanpa semantik.
Mengingat batasan pengurutan dan berbagi ini, konsumen biasa harus melakukan buffering semua acara NamedSetOfFiles
hingga aliran BEP habis. Aliran peristiwa JSON
dan kode Python berikut menunjukkan cara mengisi peta dari
target/aspek ke artefak yang dibuat 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)