Ví dụ về giao thức sự kiện cho bản dựng

Báo cáo vấn đề Xem nguồn Hằng đêm · 7.3 · 7.2 · 7.1 · 7 · 6,5

Bạn có thể xem toàn bộ thông số kỹ thuật của Giao thức sự kiện bản dựng trong giao thức định nghĩa vùng đệm. Tuy nhiên, việc hình thành trực giác có thể cũng rất hữu ích trước khi xem thông số kỹ thuật.

Hãy cân nhắc 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.shfoo_test.sh và 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 tạo sẽ giống như biểu đồ bên dưới. Các mũi tên biểu thị mối quan hệ cha 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 đã được lược bỏ để cho ngắn gọn.

đồ thị nhật ký

Hình 1. Biểu đồ BEP.

Ban đầu, một sự kiện BuildStarted sẽ được xuất bản. Sự kiện này cho chúng tôi 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 tạo bản dựng PatternExpanded cung cấp thông tin chi tiết mà cụ thể nhắm mục tiêu mẫu ... được mở rộng thành: //foo:foo_lib//foo:foo_test. Thực hiện điều đó bằng cách khai báo hai TargetConfigured sự kiện khi là trẻ em. Xin lưu ý rằng sự kiện TargetConfigured khai báo sự kiện Configuration là sự kiện con, mặc dù 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 đế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 fileSets của nó .

Tạo các sự kiện tham chiếu đến tệp thường không nhúng tệp tên và đường dẫn trong sự kiện. Thay vào đó, các sự kiện này chứa giá trị nhận dạng sự kiện bản dựng của một sự kiện NamedSetOfFiles, sau đó sẽ chứa các tên tệp thực tế và đường dẫn. 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 khảo. Cấu trúc này cần thiết vì nếu không thì trong một số trường hợp, kích thước đầu ra của Giao thức sự kiện xây dựng sẽ tăng gấp bốn lần với số lượng tệp. Sự kiện NamedSetOfFiles cũng có thể không có tất 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 tạo giá trị nhận dạng sự kiện.

Dưới đây là một bản sao của sự kiện TargetComplete cho //foo:foo_lib từ biểu đồ trên được in trong cách biểu diễn 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 mờ và tham chiếu đến sự kiện Configuration bằng cách sử dụng giá trị nhận dạng sự kiện bản dựng. Sự kiện 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 tạo thành công, tập hợp các tệp đầu ra và loại mục tiêu 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ả Aspect tính bằng BEP

Các bản dựng thông thường sẽ đánh giá các hành động được liên kết với (target, configuration) cặp. Khi toà nhà bật các phương diện, Bazel đánh giá thêm các mục tiêu được liên kết với (target, configuration, aspect) bộ ba, cho mỗi mục tiêu chịu ảnh hưởng của một khía cạnh cụ thể đã bật.

Hiện đã có kết quả đánh giá cho các khía cạnh trong BEP mặc dù không có loại sự kiện theo từng khía cạnh cụ thể. Đối với mỗi cặp (target, configuration) có một khía cạnh phù hợp, Bazel xuất bản một TargetConfigured bổ sung và Sự kiện TargetComplete mang kết quả từ việc áp dụng khía cạnh cho phương diện . Ví dụ: nếu //:foo_lib được tạo bằng --aspects=aspects/myaspect.bzl%custom_aspect, 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"
      }]
    }]
  }
}

Đang tiêu thụ NamedSetOfFiles

Việc xác định các cấu phần phần mềm được tạo bởi một mục tiêu (hoặc khía cạnh) nhất định là điều bình thường Trường hợp sử dụng BEP có thể được thực hiện hiệu quả với một số chuẩn bị. Phần này thảo luận về cấu trúc đệ quy, dùng chung do NamedSetOfFiles cung cấp sự kiện khớp với cấu trúc của Depset Starlark.

Người tiêu dùng phải cẩn thận để tránh các thuật toán bậc hai khi xử lý NamedSetOfFiles sự kiện vì các bản dựng lớn có thể chứa hàng chục nghìn các sự kiện như vậy, đòi hỏi hàng trăm triệu thao tác trong một quá trình truyền tải bằng độ phức tạp bậc hai.

namedsetoffiles-bep-graph

Hình 2. Biểu đồ BEP NamedSetOfFiles.

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à giá trị nghịch đảo của giá trị "parent-child" mối quan hệ sự kiện, trong đó tất cả trừ sự kiện đầu tiên xuất hiện sau ít nhất một sự kiện công bố sự kiện đó. Một sự kiện NamedSetOfFiles là do một sự kiện Progress thông báo không có ngữ nghĩa.

Với những ràng buộc về thứ tự và chia sẻ này, người tiêu dùng thông thường phải lưu tất cả NamedSetOfFiles sự kiện cho đến khi luồng BEP hết. JSON sau luồng sự kiện và mã Python minh hoạ cách điền bản đồ từ nhắm mục tiêu/đối với cấu phần phần mềm đã tạo ở chế độ "mặc định" nhóm đầu ra và cách xử lý dữ liệu đầu ra cho một tập hợp con gồm các mục tiêu/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)