बिल्ड इवेंट प्रोटोकॉल के उदाहरण

Build Event Protocol की पूरी जानकारी, इसके प्रोटोकॉल बफ़र की परिभाषा में देखी जा सकती है. हालांकि, जानकारी देखने से पहले, इसके बारे में कुछ बुनियादी बातें जान लेना मददगार साबित हो सकता है.

Bazel के एक सामान्य वर्कस्पेस का उदाहरण देखें. इसमें दो खाली शेल स्क्रिप्ट 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

पहली इमेज. बीईपी ग्राफ़.

शुरुआत में, BuildStarted इवेंट पब्लिश किया जाता है. इस इवेंट से हमें पता चलता है कि bazel test कमांड के ज़रिए बिल्ड शुरू किया गया था. साथ ही, यह चाइल्ड इवेंट के बारे में भी बताता है:

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

पहले तीन इवेंट से, यह जानकारी मिलती है कि Bazel को कैसे शुरू किया गया था.

PatternExpanded बिल्ड इवेंट से यह जानकारी मिलती है कि ... पैटर्न, किन खास टारगेट के लिए बढ़ाया गया था: //foo:foo_lib और //foo:foo_test. इसके लिए, दो TargetConfigured इवेंट को चाइल्ड के तौर पर दिखाया जाता है. ध्यान दें कि TargetConfigured इवेंट, Configuration इवेंट को चाइल्ड इवेंट के तौर पर दिखाता है. भले ही, Configuration इवेंट, TargetConfigured इवेंट से पहले पोस्ट किया गया हो.

पैरंट और चाइल्ड के बीच के संबंध के अलावा, इवेंट, अपने बिल्ड इवेंट आइडेंटिफ़ायर का इस्तेमाल करके एक-दूसरे से भी जुड़ सकते हैं. उदाहरण के लिए, ऊपर दिए गए ग्राफ़ में, TargetComplete इवेंट, अपने fileSets फ़ील्ड में NamedSetOfFiles इवेंट से जुड़ा है.

आम तौर पर, फ़ाइलों से जुड़े बिल्ड इवेंट में, फ़ाइल के नाम और पाथ शामिल नहीं होते. इसके बजाय, इनमें NamedSetOfFiles इवेंट का बिल्ड इवेंट आइडेंटिफ़ायर होता है. इसमें फ़ाइल के असली नाम और पाथ शामिल होते हैं. NamedSetOfFiles इवेंट की मदद से, फ़ाइलों के सेट की जानकारी एक बार दी जा सकती है. साथ ही, कई टारगेट के लिए इसका रेफ़रंस दिया जा सकता है. यह स्ट्रक्चर ज़रूरी है, क्योंकि ऐसा न होने पर, कुछ मामलों में Build Event Protocol के आउटपुट का साइज़, फ़ाइलों की संख्या के हिसाब से काफ़ी बढ़ जाएगा. ऐसा भी हो सकता है कि NamedSetOfFiles इवेंट में, उसकी सभी फ़ाइलें शामिल न हों. इसके बजाय, वह अपने बिल्ड इवेंट आइडेंटिफ़ायर के ज़रिए, दूसरे NamedSetOfFiles इवेंट से जुड़ा हो.

यहां, ऊपर दिए गए ग्राफ़ में मौजूद //foo:foo_lib टारगेट के लिए, TargetComplete इवेंट का एक इंस्टेंस दिखाया गया है. इसे प्रोटोकॉल बफ़र के JSON फ़ॉर्मैट में प्रिंट किया गया है. बिल्ड इवेंट आइडेंटिफ़ायर में, टारगेट को ओपेक स्ट्रिंग के तौर पर दिखाया जाता है. साथ ही, यह अपने बिल्ड इवेंट आइडेंटिफ़ायर का इस्तेमाल करके, Configuration इवेंट से जुड़ा होता है. इस इवेंट में, किसी भी चाइल्ड इवेंट के बारे में जानकारी नहीं दी जाती. पेलोड में, यह जानकारी शामिल होती है कि टारगेट को सफलतापूर्वक बनाया गया है या नहीं, आउटपुट फ़ाइलों का सेट, और किस तरह का टारगेट बनाया गया है.

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

बीईपी में पहलू के नतीजे

सामान्य बिल्ड, (target, configuration) पेयर से जुड़ी कार्रवाइयों का आकलन करते हैं. पहलू की सुविधा चालू करके बिल्ड करने पर, Bazel ट्रिपल से जुड़े टारगेट का भी आकलन करता है. यह आकलन, चालू किए गए किसी पहलू से प्रभावित हर टारगेट के लिए किया जाता है.(target, configuration, aspect)

पहलू के लिए खास इवेंट टाइप न होने पर भी, बीईपी में पहलुओं के आकलन के नतीजे उपलब्ध होते हैं. लागू किए जा सकने वाले पहलू वाले हर (target, configuration) पेयर के लिए, Bazel एक और TargetConfigured और TargetComplete इवेंट पब्लिश करता है. इसमें टारगेट पर पहलू लागू करने के बाद मिलने वाले नतीजे शामिल होते हैं. उदाहरण के लिए, अगर //:foo_lib को --aspects=aspects/myaspect.bzl%custom_aspect के साथ बनाया जाता है, तो यह इवेंट बीईपी में भी दिखेगा:

{
  "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 का इस्तेमाल करना

किसी टारगेट (या पहलू) से जनरेट हुए आर्टफ़ैक्ट की जानकारी पाना, बीईपी का एक सामान्य इस्तेमाल है. इसे कुछ तैयारी के साथ आसानी से किया जा सकता है. इस सेक्शन में, NamedSetOfFiles इवेंट के ज़रिए उपलब्ध कराए गए, बार-बार इस्तेमाल किए जा सकने वाले और शेयर किए गए स्ट्रक्चर के बारे में बताया गया है. यह स्ट्रक्चर, Starlark Depset के स्ट्रक्चर से मेल खाता है.

उपयोगकर्ताओं को NamedSetOfFiles इवेंट को प्रोसेस करते समय, काफ़ी सावधानी बरतनी चाहिए, ताकि वे ऐसे एल्गोरिदम का इस्तेमाल न करें जो काफ़ी समय लेते हैं. ऐसा इसलिए, क्योंकि बड़े बिल्ड में इस तरह के हज़ारों इवेंट हो सकते हैं. इसके लिए, काफ़ी समय लेने वाले ट्रैवर्सल में करोड़ों कार्रवाइयां करनी पड़ सकती हैं.

namedsetoffiles-bep-graph

दूसरी इमेज. NamedSetOfFiles बीईपी ग्राफ़.

NamedSetOfFiles इवेंट, बीईपी स्ट्रीम में हमेशा उस TargetComplete या NamedSetOfFiles इवेंट से पहले दिखता है जो इसका रेफ़रंस देता है. यह "पैरंट-चाइल्ड" इवेंट के संबंध के उलट है. इसमें पहले इवेंट को छोड़कर, बाकी सभी इवेंट, कम से कम एक ऐसे इवेंट के बाद दिखते हैं जो उनके बारे में जानकारी देता है. NamedSetOfFiles इवेंट की जानकारी, बिना किसी सिमैंटिक वाले Progress इवेंट से मिलती है.

ऑर्डरिंग और शेयर करने से जुड़ी इन पाबंदियों को देखते हुए, किसी सामान्य उपयोगकर्ता को बीईपी स्ट्रीम खत्म होने तक, सभी NamedSetOfFiles इवेंट को बफ़र करना होगा. JSON इवेंट स्ट्रीम और Python कोड से पता चलता है कि "डिफ़ॉल्ट" आउटपुट ग्रुप में, टारगेट/पहलू से बनाए गए आर्टफ़ैक्ट को मैप में कैसे जोड़ा जाता है. साथ ही, बनाए गए टारगेट/पहलू के सबसेट के लिए, आउटपुट को कैसे प्रोसेस किया जाता है:

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)