ساخت نمونه های پروتکل رویداد

مشخصات کامل پروتکل Build Event را می توان در تعریف بافر پروتکل آن یافت. با این حال، ممکن است قبل از بررسی مشخصات، کمی شهود ایجاد کنید.

یک فضای کاری ساده 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

شکل 1. نمودار BEP.

در ابتدا، یک رویداد BuildStarted منتشر می شود. این رویداد به ما اطلاع می دهد که ساخت از طریق دستور bazel test فراخوانی شده است و رویدادهای فرزند را اعلام می کند:

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

سه رویداد اول اطلاعاتی در مورد چگونگی فراخوانی بازل ارائه می دهد.

رویداد ساخت PatternExpanded بینشی را ارائه می دهد که الگوی ... به کدام اهداف خاص گسترش یافته است: //foo:foo_lib و //foo:foo_test . این کار را با اعلام دو رویداد TargetConfigured در کودکی انجام می دهد. توجه داشته باشید که رویداد TargetConfigured رویداد Configuration را به عنوان یک رویداد فرزند اعلام می کند، حتی اگر Configuration قبل از رویداد TargetConfigured پست شده باشد.

علاوه بر رابطه والد و فرزند، رویدادها همچنین ممکن است با استفاده از شناسه رویداد ساخت خود به یکدیگر اشاره کنند. به عنوان مثال، در نمودار بالا، رویداد TargetComplete به رویداد NamedSetOfFiles در قسمت fileSets آن اشاره دارد.

رویدادهای ساخت که به فایل‌ها اشاره می‌کنند معمولاً نام فایل‌ها و مسیرها را در رویداد جاسازی نمی‌کنند. در عوض، آنها حاوی شناسه رویداد ساخت یک رویداد NamedSetOfFiles ، که سپس شامل نام‌ها و مسیرهای فایل واقعی می‌شود. رویداد NamedSetOfFiles به مجموعه ای از فایل ها اجازه می دهد تا یک بار گزارش شوند و توسط بسیاری از اهداف ارجاع داده شوند. این ساختار ضروری است زیرا در غیر این صورت در برخی موارد اندازه خروجی پروتکل رویداد ساخت به صورت درجه دوم با تعداد فایل ها افزایش می یابد. رویداد NamedSetOfFiles ممکن است همه فایل‌هایش را جاسازی نکرده باشد، اما در عوض از طریق شناسه‌های رویداد ساخت به رویدادهای دیگر NamedSetOfFiles مراجعه کند.

در زیر نمونه‌ای از رویداد TargetComplete برای هدف //foo:foo_lib از نمودار بالا است که در نمایش JSON بافر پروتکل چاپ شده است. شناسه رویداد ساخت شامل هدف به عنوان یک رشته مات است و به رویداد 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) سه‌گانه را برای هر هدفی که تحت تأثیر یک جنبه فعال مشخص قرار می‌گیرد، ارزیابی می‌کند.

نتایج ارزیابی برای جنبه‌ها علیرغم عدم وجود انواع رویدادهای خاص در BEP موجود است. برای هر جفت (target, configuration) با یک جنبه کاربردی، Bazel یک رویداد TargetComplete و TargetConfigured اضافی را منتشر می کند که نتیجه اعمال جنبه را به هدف نشان می دهد. برای مثال، اگر //: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

تعیین مصنوعات تولید شده توسط یک هدف (یا جنبه) یک مورد معمول استفاده از BEP است که می تواند با آمادگی خاصی انجام شود. این بخش ساختار بازگشتی و مشترک ارائه شده توسط رویداد NamedSetOfFiles را مورد بحث قرار می دهد که با ساختار Starlark Depset مطابقت دارد.

مصرف کنندگان باید مراقب باشند که هنگام پردازش رویدادهای NamedSetOfFiles از الگوریتم های درجه دوم اجتناب کنند، زیرا ساخت های بزرگ می توانند حاوی ده ها هزار رویداد از این قبیل باشند که به صدها میلیون عملیات در یک پیمایش با پیچیدگی درجه دوم نیاز دارند.

namedsetoffiles-bep-graph

شکل 2. نمودار BEP NamedSetOfFiles .

یک رویداد NamedSetOfFiles همیشه قبل از رویداد TargetComplete یا NamedSetOfFiles که به آن ارجاع می دهد در جریان BEP ظاهر می شود. این معکوس رابطه رویداد "والد-فرزند" است، جایی که همه رویدادها به جز اولین رویداد حداقل پس از اعلام یک رویداد ظاهر می شوند. یک رویداد NamedSetOfFiles توسط یک رویداد Progress بدون معنایی اعلام می شود.

با توجه به این محدودیت‌های سفارش و اشتراک‌گذاری، یک مصرف‌کننده معمولی باید تمام رویدادهای NamedSetOfFiles را تا زمانی که جریان BEP تمام شود، بافر کند. جریان رویداد JSON و کد پایتون زیر نحوه پر کردن نقشه از هدف/جنبه به مصنوعات ساخته شده در گروه خروجی پیش‌فرض و نحوه پردازش خروجی‌ها برای زیرمجموعه‌ای از اهداف/جنبه‌های ساخته شده را نشان می‌دهد:

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)