Xây dựng ví dụ về giao thức sự kiện

Sử dụng bộ sưu tập để sắp xếp ngăn nắp các trang Lưu và phân loại nội dung dựa trên lựa chọn ưu tiên của bạn.
Báo cáo sự cố Xem nguồn

Bạn có thể xem thông số kỹ thuật đầy đủ của Giao thức sự kiện xây dựng trong định nghĩa vùng đệm giao thức. Tuy nhiên, bạn nên xây dựng một số trực giác trước khi xem xét thông số kỹ thuật.

Hãy xem xét một không gian làm việc đơn giản của Bazel bao gồm hai tập lệnh shell trống foo.shfoo_test.sh cùng 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 chỉ ra mối quan hệ mẹ và con nói 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.

biểu đồ

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

Ban đầu, sự kiện BuildStarted đượ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 gọi Bazel.

Sự kiện xây dựng PatternExpanded cung cấp thông tin chi tiết về mục tiêu cụ thể nào mà mẫu ... được mở rộng thành: //foo:foo_lib//foo:foo_test. Bạn thực hiện việc này bằng cách khai báo hai sự kiện TargetConfigured là con. 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 giá trị 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 tạo bản dựng tham chiếu đến các tệp thường không nhúng tên tệp và đường dẫn vào sự kiện đó. Thay vào đó, chúng chứa giá trị nhận dạng sự kiện tạo bản dựng của một sự kiện NamedSetOfFiles. Sau đó, sự kiện này sẽ chứa tên tệp và đường dẫn thực tế. Sự kiện NamedSetOfFiles cho phép báo cáo một nhóm tệp một lần và được nhiều mục tiêu tham chiếu đến. 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 Giao thức sự kiện xây dựng sẽ tăng gấp đôi về số lượng tệp. Sự kiện NamedSetOfFiles cũng có thể không được nhúng tất cả tệp, 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 tạo bản dựng.

Dưới đây là bản sao của sự kiện TargetComplete cho mục tiêu //foo:foo_lib từ biểu đồ trên, được in trong bản trình bày JSON của vùng đệm giao thức. Giá trị nhận dạng sự kiện xây dựng chứa mục tiêu dưới dạng 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 xây dựng. Sự kiện này không thông báo cho bất kỳ sự kiện con nào. Trọng tải chứa thông tin về việc mục tiêu có được xây dựng 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ề tỷ lệ khung hình trong BEP

Bản dựng thông thường đánh giá các hành động liên kết với các cặp (target, configuration). Khi bật tính năng xây dựng góc nhìn, Bazel sẽ đánh giá thêm các mục tiêu liên kết với bộ ba (target, configuration, aspect), đối với mỗi mục tiêu chịu ảnh hưởng của một khía cạnh nhất định đã bật.

Bạn có thể xem kết quả đánh giá về các khía cạnh trong BEP mặc dù không có loại sự kiện dành riêng cho quy trình kiểm tra. Đối với mỗi cặp (target, configuration) có một khía cạnh có thể áp dụng, Bazel sẽ phát hành một sự kiện TargetConfiguredTargetComplete bổ sung, mang lại 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

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à một trường hợp sử dụng BEP phổ biến 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, chia sẻ được cung cấp bởi sự kiện NamedSetOfFiles, 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 sử dụng 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 hoạt động truyền tải có độ phức tạp theo phương trình bậc bốn.

được đặt tên là tệp-bep-biểu đồ

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

Sự kiện NamedSetOfFiles luôn xuất hiện trong luồng BEP trước một sự kiện TargetComplete hoặc NamedSetOfFiles tham chiếu đến sự kiện đó. Điều này ngược lại với mối quan hệ của sự kiện "parent-child", trong đó tất cả trừ sự kiện đầu tiên sẽ xuất hiện sau ít nhất một sự kiện thông báo sự kiện đó. Sự kiện NamedSetOfFiles được thông báo từ một sự kiện Progress không có ngữ nghĩa.

Do các hạn chế sắp xếp và chia sẻ này, một người tiêu dùng thông thường phải lưu vào bộ đệm tất cả các sự kiện NamedSetOfFiles cho đến khi luồng BEP đã hết. Luồng sự kiện JSON và mã Python sau đây minh họa cách điền sẵn bản đồ từ mục tiêu/giá trị vào các cấu phần phần mềm được tạo trong nhóm đầu ra "mặc định" và cách xử lý kết quả đầu ra cho một tập hợp con các mục tiêu/khối lượng đã xây dựng:

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)