Spesifikasi lengkap Protokol Peristiwa Build dapat ditemukan dalam definisi buffering protokolnya. Namun, sebaiknya buat beberapa intuisi sebelum melihat spesifikasi.
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 ...
pada project ini, grafik build dari peristiwa build yang dihasilkan akan menyerupai grafik di bawah ini. Panah menunjukkan
hubungan induk dan turunan yang disebutkan di atas. Perhatikan bahwa beberapa peristiwa build dan
sebagian besar kolom 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 peristiwa pertama memberikan informasi tentang cara Bazel dipanggil.
Peristiwa build PatternExpanded
memberikan insight tentang target spesifik mana yang diperluas ke pola ...
: //foo:foo_lib
dan //foo:foo_test
. Cara ini melakukannya 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
mengacu pada peristiwa NamedSetOfFiles
di kolom fileSets
.
Peristiwa build yang merujuk pada file biasanya tidak menyematkan nama dan jalur file dalam peristiwa tersebut. Sebagai gantinya, file tersebut berisi ID peristiwa build dari peristiwa NamedSetOfFiles
, yang kemudian akan berisi nama file dan jalur sebenarnya. Peristiwa NamedSetOfFiles
memungkinkan sekumpulan file dilaporkan sekali dan dirujuk ke banyak target. Struktur ini diperlukan karena, dalam beberapa kasus, ukuran output
Protokol Peristiwa Build akan bertambah secara kuadrat dengan
jumlah file. Peristiwa NamedSetOfFiles
mungkin juga tidak memiliki semua file-nya, tetapi lihat 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 dibuat.
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
}
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "0"
}]
}],
"targetKind": "sh_library rule"
}
}
Hasil Aspek di BEP
Build biasa mengevaluasi tindakan yang terkait dengan pasangan (target, configuration)
. Saat mem-build dengan aspek diaktifkan, Bazel juga mengevaluasi target yang terkait dengan (target, configuration,
aspect)
tiga kali lipat, untuk setiap target yang terpengaruh oleh aspek aktif 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 membawa 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"
}]
}]
}
}
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 berulang yang ditawarkan oleh peristiwa NamedSetOfFiles
, yang cocok dengan struktur Depset Starlark.
Konsumen harus berhati-hati untuk menghindari algoritme kuadrat saat memproses
peristiwa NamedSetOfFiles
karena build besar dapat berisi puluhan ribu
peristiwa tersebut, yang memerlukan ratusan juta operasi dalam traversal dengan
kompleks kuadrat.
Gambar 2. Grafik BEP NamedSetOfFiles
.
Peristiwa NamedSetOfFiles
selalu muncul di aliran BEP sebelum peristiwa TargetComplete
atau NamedSetOfFiles
yang mereferensikannya. Ini merupakan kebalikan dari hubungan peristiwa "induk-turunan", di mana semua kecuali peristiwa pertama muncul setelah setidaknya satu peristiwa mengumumkannya. Peristiwa NamedSetOfFiles
diumumkan oleh peristiwa Progress
tanpa semantik.
Dengan mempertimbangkan urutan dan pembagian ini, konsumen biasa harus melakukan buffer semua
peristiwa NamedSetOfFiles
hingga aliran BEP habis. Aliran peristiwa JSON
dan kode Python berikut menunjukkan cara mengisi peta dari
target/aspek hingga artefak yang dibuat dalam grup output "default", dan cara
memproses output untuk subset target/aspek yang di-build:
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)