ตัวอย่างโปรโตคอลเหตุการณ์การสร้าง

รายงานปัญหา ดูแหล่งที่มา Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

ดูข้อกำหนดทั้งหมดของ Build Event Protocol ได้ในคำจำกัดความของ Protocol Buffer อย่างไรก็ตาม การสร้างสัญชาตญาณบางอย่างอาจเป็นประโยชน์ ก่อนที่จะดูข้อกำหนด

ลองพิจารณาพื้นที่ทำงาน Bazel อย่างง่ายที่ประกอบด้วยสคริปต์เชลล์ว่าง 2 รายการ foo.sh และ foo_test.sh รวมถึงไฟล์ BUILD ต่อไปนี้

sh_library(
    name = "foo_lib",
    srcs = ["foo.sh"],
)

sh_test(
    name = "foo_test",
    srcs = ["foo_test.sh"],
    deps = [":foo_lib"],
)

เมื่อเรียกใช้ bazel test ... ในโปรเจ็กต์นี้ กราฟการสร้างของเหตุการณ์การสร้างที่สร้างขึ้นจะคล้ายกับกราฟด้านล่าง ลูกศรแสดงถึง ความสัมพันธ์หลักและย่อยที่กล่าวถึงข้างต้น โปรดทราบว่าเราได้ละเว้นเหตุการณ์การสร้างบางอย่างและฟิลด์ส่วนใหญ่เพื่อความกระชับ

bep-graph

รูปที่ 1 กราฟ BEP

ในตอนแรก ระบบจะเผยแพร่เหตุการณ์ BuildStarted เหตุการณ์นี้จะแจ้งให้เราทราบว่ามีการเรียกใช้บิลด์ผ่านคำสั่ง bazel test และประกาศเหตุการณ์ย่อย ดังนี้

  • OptionsParsed
  • WorkspaceStatus
  • CommandLine
  • UnstructuredCommandLine
  • BuildMetadata
  • BuildFinished
  • PatternExpanded
  • Progress

เหตุการณ์ 3 รายการแรกให้ข้อมูลเกี่ยวกับวิธีเรียกใช้ Bazel

PatternExpanded เหตุการณ์การสร้างให้ข้อมูลเชิงลึก เกี่ยวกับเป้าหมายที่เฉพาะเจาะจงซึ่ง... รูปแบบขยายไปถึง //foo:foo_lib และ //foo:foo_test โดยทำได้ด้วยการประกาศเหตุการณ์ 2 รายการ TargetConfigured เป็นเหตุการณ์ย่อย โปรดทราบว่าTargetConfigured event จะประกาศ Configuration event เป็นเหตุการณ์ย่อย แม้ว่า Configuration จะโพสต์ก่อน TargetConfigured event

นอกจากความสัมพันธ์ระหว่างผู้ปกครองกับบุตรหลานแล้ว เหตุการณ์ยังอาจอ้างอิงถึงกัน โดยใช้ตัวระบุเหตุการณ์ที่สร้างขึ้น ตัวอย่างเช่น ในกราฟด้านบน เหตุการณ์ TargetComplete หมายถึงเหตุการณ์ NamedSetOfFiles ในฟิลด์ fileSets

โดยปกติแล้ว เหตุการณ์การสร้างที่อ้างอิงถึงไฟล์จะไม่ฝังชื่อและเส้นทางของไฟล์ไว้ในเหตุการณ์ แต่จะมีตัวระบุเหตุการณ์บิลด์ของเหตุการณ์ NamedSetOfFiles ซึ่งจะมีชื่อไฟล์และเส้นทางจริง NamedSetOfFiles เหตุการณ์ช่วยให้ระบบรายงานชุดไฟล์ได้ครั้งเดียวและ อ้างอิงได้โดยเป้าหมายหลายรายการ โครงสร้างนี้จำเป็นเนื่องจากในบางกรณีขนาดเอาต์พุตของ Build Event Protocol จะเพิ่มขึ้นแบบกำลังสองตามจำนวนไฟล์ NamedSetOfFiles เหตุการณ์อาจไม่มีไฟล์ทั้งหมด ฝังอยู่ แต่อ้างอิงถึงNamedSetOfFiles เหตุการณ์อื่นๆ ผ่าน ตัวระบุเหตุการณ์บิลด์แทน

ด้านล่างนี้เป็นอินสแตนซ์ของTargetComplete event สำหรับ//foo:foo_lib target จากกราฟด้านบน ซึ่งพิมพ์ในการแสดง JSON ของ Protocol Buffer ตัวระบุเหตุการณ์บิลด์มีเป้าหมายเป็นสตริงทึบแสงและอ้างอิงถึงConfigurationเหตุการณ์โดยใช้ตัวระบุเหตุการณ์บิลด์ เหตุการณ์นี้ไม่ได้ ประกาศเหตุการณ์ย่อยใดๆ เพย์โหลดมีข้อมูลว่าสร้างเป้าหมายสําเร็จหรือไม่ ชุดไฟล์เอาต์พุต และประเภทเป้าหมายที่สร้าง

{
  "id": {
    "targetCompleted": {
      "label": "//foo:foo_lib",
      "configuration": {
        "id": "544e39a7f0abdb3efdd29d675a48bc6a"
      }
    }
  },
  "completed": {
    "success": true,
    "outputGroup": [{
      "name": "default",
      "fileSets": [{
        "id": "0"
      }]
    }],
    "targetKind": "sh_library rule"
  }
}

ผลลัพธ์ของลักษณะใน BEP

บิลด์ปกติจะประเมินการดำเนินการที่เชื่อมโยงกับ(target, configuration) คู่ เมื่อสร้างโดยเปิดใช้แง่มุม Bazel จะประเมินเป้าหมายที่เชื่อมโยงกับ (target, configuration, aspect) triples เพิ่มเติมสำหรับแต่ละเป้าหมายที่ได้รับผลกระทบจากแง่มุมที่เปิดใช้

ผลการประเมินแง่มุมจะพร้อมใช้งานใน BEP แม้ว่าจะไม่มีประเภทเหตุการณ์เฉพาะแง่มุมก็ตาม สำหรับคู่ (target, configuration) แต่ละคู่ที่มีแง่มุมที่เกี่ยวข้อง Bazel จะเผยแพร่เหตุการณ์ TargetConfigured และ TargetComplete เพิ่มเติมซึ่งมีผลลัพธ์จากการใช้แง่มุมกับเป้าหมาย ตัวอย่างเช่น หากสร้าง //:foo_lib ด้วย --aspects=aspects/myaspect.bzl%custom_aspect เหตุการณ์นี้จะปรากฏใน 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"
      }]
    }]
  }
}

การใช้ NamedSetOfFiles

การระบุอาร์ติแฟกต์ที่สร้างขึ้นโดยเป้าหมาย (หรือแง่มุม) ที่กำหนดเป็น Use Case ทั่วไปของ BEP ซึ่งสามารถทำได้อย่างมีประสิทธิภาพด้วยการเตรียมการบางอย่าง ส่วนนี้ จะอธิบายโครงสร้างแบบเรียกซ้ำและโครงสร้างที่แชร์ซึ่งมีให้ในNamedSetOfFiles เหตุการณ์ ซึ่งตรงกับโครงสร้างของ Depset ของ Starlark

ผู้ใช้ต้องระมัดระวังเพื่อหลีกเลี่ยงอัลกอริทึมแบบกำลังสองเมื่อประมวลผลNamedSetOfFilesเหตุการณ์ เนื่องจากบิลด์ขนาดใหญ่อาจมีเหตุการณ์ดังกล่าวหลายหมื่นรายการ ซึ่งต้องใช้การดำเนินการหลายร้อยล้านรายการในการข้ามผ่านที่มีความซับซ้อนแบบกำลังสอง

namedsetoffiles-bep-graph

รูปที่ 2 NamedSetOfFiles กราฟ BEP

เหตุการณ์ NamedSetOfFiles จะปรากฏในสตรีม BEP ก่อนเหตุการณ์ TargetComplete หรือ NamedSetOfFiles ที่อ้างอิงถึงเหตุการณ์นั้นเสมอ ซึ่งเป็น ส่วนกลับของความสัมพันธ์ของเหตุการณ์ "หลัก-ย่อย" โดยที่เหตุการณ์ทั้งหมด ยกเว้นเหตุการณ์แรกจะปรากฏหลังจากมีเหตุการณ์อย่างน้อย 1 รายการที่ประกาศเหตุการณ์นั้น NamedSetOfFiles เหตุการณ์จะประกาศโดยProgress เหตุการณ์ที่ไม่มีความหมาย

เนื่องจากข้อจำกัดในการจัดลำดับและการแชร์เหล่านี้ ผู้ใช้ทั่วไปจึงต้องบัฟเฟอร์เหตุการณ์ NamedSetOfFiles ทั้งหมดจนกว่าสตรีม BEP จะหมด สตรีมเหตุการณ์ JSON และโค้ด Python ต่อไปนี้แสดงวิธีสร้างแผนที่จาก เป้าหมาย/แง่มุมไปยังอาร์ติแฟกต์ที่สร้างขึ้นในกลุ่มเอาต์พุต "default" และวิธี ประมวลผลเอาต์พุตสำหรับชุดย่อยของเป้าหมาย/แง่มุมที่สร้างขึ้น

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)