Bạn có thể xem toàn bộ quy cách của Build Event Protocol trong định nghĩa bộ đệm giao thức. Tuy nhiên, bạn nên xây dựng một số kiến thức trực quan trước khi xem xét quy cách.
Hãy xem xét một không gian làm việc Bazel đơn giản bao gồm 2 tập lệnh shell trống foo.sh
và foo_test.sh
, cũng như tệp BUILD
sau:
sh_library(
name = "foo_lib",
srcs = ["foo.sh"],
)
sh_test(
name = "foo_test",
srcs = ["foo_test.sh"],
deps = [":foo_lib"],
)
Khi chạy bazel test ...
trên dự án này, biểu đồ bản dựng của các sự kiện bản dựng đã tạo sẽ giống với biểu đồ bên dưới. Các mũi tên cho biết mối quan hệ mẹ và con nêu trên. Xin lưu ý rằng một số sự kiện bản dựng và hầu hết các trường đã bị bỏ qua để cho ngắn gọn.
Hình 1. Biểu đồ điểm hoà vốn.
Ban đầu, sự kiện BuildStarted
sẽ được xuất bản. Sự kiện này cho chúng ta biết rằng bản dựng được gọi thông qua lệnh bazel test
và thông báo các sự kiện con:
OptionsParsed
WorkspaceStatus
CommandLine
UnstructuredCommandLine
BuildMetadata
BuildFinished
PatternExpanded
Progress
Ba sự kiện đầu tiên cung cấp thông tin về cách Bazel được gọi.
Sự kiện PatternExpanded
tạo thông tin chi tiết về những mục tiêu cụ thể mà mẫu ...
đã mở rộng đến: //foo:foo_lib
và //foo:foo_test
. Thao tác này được thực hiện bằng cách khai báo 2 sự kiện TargetConfigured
dưới dạng sự kiện con. Xin lưu ý rằng sự kiện TargetConfigured
khai báo sự kiện Configuration
là sự kiện con, ngay cả khi Configuration
đã được đăng trước sự kiện TargetConfigured
.
Ngoài mối quan hệ mẹ và con, các sự kiện cũng có thể tham chiếu lẫn nhau bằng cách sử dụng mã nhận dạng sự kiện bản dựng. Ví dụ: trong biểu đồ ở trên, sự kiện TargetComplete
đề cập đến sự kiện NamedSetOfFiles
trong trường fileSets
.
Các sự kiện bản dựng tham chiếu đến các tệp thường không nhúng tên và đường dẫn tệp vào sự kiện. Thay vào đó, chúng chứa mã nhận dạng sự kiện bản dựng của một sự kiện NamedSetOfFiles
, sau đó sẽ chứa tên và đường dẫn thực của tệp. Sự kiện NamedSetOfFiles
cho phép một nhóm tệp được báo cáo một lần và được nhiều mục tiêu tham chiếu. Cấu trúc này là cần thiết vì nếu không, trong một số trường hợp, kích thước đầu ra của Build Event Protocol sẽ tăng theo cấp số nhân với số lượng tệp. Một sự kiện NamedSetOfFiles
cũng có thể không có tất cả các tệp được nhúng, mà thay vào đó tham chiếu đến các sự kiện NamedSetOfFiles
khác thông qua giá trị nhận dạng sự kiện bản dựng của chúng.
Dưới đây là một phiên bản của sự kiện TargetComplete
cho mục tiêu //foo:foo_lib
trong biểu đồ ở trên, được in trong biểu thị JSON của vùng đệm giao thức.
Giá trị nhận dạng sự kiện bản dựng chứa mục tiêu dưới dạng một chuỗi không rõ ràng và tham chiếu đến sự kiện Configuration
bằng giá trị nhận dạng sự kiện bản dựng. Sự kiện này không thông báo bất kỳ sự kiện con nào. Tải trọng chứa thông tin về việc mục tiêu có được tạo thành công hay không, tập hợp các tệp đầu ra và loại mục tiêu được tạo.
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
}
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "0"
}]
}],
"targetKind": "sh_library rule"
}
}
Kết quả về khía cạnh trong BEP
Các bản dựng thông thường đánh giá những thao tác liên kết với các cặp (target, configuration)
. Khi tạo bằng các khía cạnh đã bật, Bazel sẽ đánh giá thêm các mục tiêu được liên kết với bộ ba (target, configuration,
aspect)
, cho từng mục tiêu chịu ảnh hưởng của một khía cạnh đã bật nhất định.
Kết quả đánh giá cho các khía cạnh có trong BEP mặc dù không có các loại sự kiện dành riêng cho khía cạnh. Đối với mỗi cặp (target, configuration)
có một khía cạnh có thể áp dụng, Bazel sẽ xuất bản thêm sự kiện TargetConfigured
và TargetComplete
mang kết quả từ việc áp dụng khía cạnh cho mục tiêu. Ví dụ: nếu //:foo_lib
được tạo bằng --aspects=aspects/myaspect.bzl%custom_aspect
, thì sự kiện này cũng sẽ xuất hiện trong 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"
}]
}]
}
}
Tiêu thụ NamedSetOfFiles
Xác định các cấu phần phần mềm do một mục tiêu (hoặc khía cạnh) nhất định tạo ra là một trường hợp sử dụng BEP phổ biến có thể được thực hiện một cách hiệu quả với một số bước chuẩn bị. Phần này thảo luận về cấu trúc đệ quy, dùng chung do sự kiện NamedSetOfFiles
cung cấp, khớp với cấu trúc của một Depset Starlark.
Người dùng phải cẩn thận để tránh các thuật toán bậc hai khi xử lý các sự kiện NamedSetOfFiles
vì các bản dựng lớn có thể chứa hàng chục nghìn sự kiện như vậy, đòi hỏi hàng trăm triệu thao tác trong một lần duyệt qua với độ phức tạp bậc hai.
Hình 2. NamedSetOfFiles
Biểu đồ BEP.
Sự kiện NamedSetOfFiles
luôn xuất hiện trong luồng BEP trước sự kiện TargetComplete
hoặc NamedSetOfFiles
tham chiếu đến sự kiện đó. Đây là mối quan hệ ngược lại của mối quan hệ sự kiện "mẹ con", trong đó tất cả các sự kiện (ngoại trừ sự kiện đầu tiên) đều xuất hiện sau ít nhất một sự kiện thông báo về sự kiện đó. Sự kiện NamedSetOfFiles
được thông báo bằng sự kiện Progress
mà không có ngữ nghĩa.
Với những hạn chế về việc sắp xếp và chia sẻ này, một người dùng thông thường phải lưu vào bộ nhớ đệm tất cả các sự kiện NamedSetOfFiles
cho đến khi luồng BEP cạn kiệt. Luồng sự kiện JSON và mã Python sau đây minh hoạ cách điền sẵn một bản đồ từ đích/khía cạnh đến các cấu phần phần mềm đã tạo trong nhóm đầu ra "mặc định" và cách xử lý đầu ra cho một tập hợp con các đích/khía cạnh đã tạo:
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)