Membuat Contoh Protokol Peristiwa

Tetap teratur dengan koleksi Simpan dan kategorikan konten berdasarkan preferensi Anda.
Laporkan masalah Lihat sumber

Spesifikasi lengkap Build Event Protocol dapat ditemukan dalam definisi buffering protokolnya. Namun, mungkin ada baiknya untuk membangun beberapa intuisi sebelum melihat spesifikasinya.

Pertimbangkan ruang kerja Bazel sederhana yang terdiri dari dua skrip shell kosong foo.sh dan foo_test.sh serta file BUILD berikut:

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

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

Saat menjalankan bazel test ... di project ini, grafik build peristiwa build yang dihasilkan akan menyerupai grafik di bawah. Panah tersebut menunjukkan hubungan induk dan turunan yang disebutkan di atas. Perlu diingat bahwa beberapa peristiwa build dan sebagian besar kolom telah dihilangkan agar lebih singkat.

grafik bep

Gambar 1. Grafik BEP.

Awalnya, peristiwa BuildStarted dipublikasikan. Peristiwa ini memberi tahu kita bahwa build dipanggil melalui perintah bazel test dan mengumumkan peristiwa turunan:

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

Tiga peristiwa pertama memberikan informasi tentang bagaimana Bazel dipanggil.

Peristiwa build PatternExpanded memberikan insight mengenai target tertentu yang diperluas pola ...: //foo:foo_lib dan //foo:foo_test. Ini dilakukan dengan mendeklarasikan dua peristiwa TargetConfigured sebagai turunan. Perhatikan bahwa peristiwa TargetConfigured mendeklarasikan peristiwa Configuration sebagai peristiwa turunan, meskipun Configuration telah diposting sebelum peristiwa TargetConfigured.

Selain hubungan induk dan turunan, peristiwa juga dapat saling merujuk menggunakan ID peristiwa build. Misalnya, dalam grafik di atas, peristiwa TargetComplete merujuk pada peristiwa NamedSetOfFiles di kolom fileSets-nya.

Peristiwa build yang merujuk ke file biasanya tidak menyematkan nama dan jalur file dalam peristiwa tersebut. Sebagai gantinya, peristiwa tersebut berisi ID peristiwa build dari peristiwa NamedSetOfFiles, yang kemudian akan berisi nama dan jalur file yang sebenarnya. Peristiwa NamedSetOfFiles memungkinkan sekumpulan file dilaporkan satu kali dan dirujuk oleh banyak target. Struktur ini diperlukan karena, dalam beberapa kasus, ukuran output Protokol Peristiwa Build akan bertambah secara kuadrat dengan jumlah file. Peristiwa NamedSetOfFiles mungkin juga tidak menyematkan semua filenya, tetapi merujuk ke peristiwa NamedSetOfFiles lainnya melalui ID peristiwa build-nya.

Berikut adalah instance peristiwa TargetComplete untuk target //foo:foo_lib dari grafik di atas, yang dicetak dalam representasi JSON buffering protokol. ID peristiwa build berisi target sebagai string buram dan merujuk ke peristiwa Configuration menggunakan ID peristiwa build-nya. Peristiwa ini tidak mengumumkan peristiwa turunan apa pun. Payload berisi informasi tentang apakah target berhasil dibuat, kumpulan file output, dan jenis target yang dibuat.

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

Hasil Aspek dalam BEP

Build biasa mengevaluasi tindakan yang terkait dengan pasangan (target, configuration). Saat mem-build dengan aspek yang diaktifkan, Bazel juga akan mengevaluasi target yang terkait dengan (target, configuration, aspect) tiga kali lipat, untuk setiap target yang terpengaruh oleh aspek aktif tertentu.

Hasil evaluasi untuk aspek tersedia di BEP meskipun tidak ada jenis peristiwa khusus aspek. Untuk setiap pasangan (target, configuration) dengan aspek yang berlaku, Bazel memublikasikan peristiwa TargetConfigured dan TargetComplete tambahan yang berisi hasil dari penerapan aspek ke target. Misalnya, jika //:foo_lib di-build dengan --aspects=aspects/myaspect.bzl%custom_aspect, peristiwa ini juga akan muncul di 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"
      }]
    }]
  }
}

Menggunakan NamedSetOfFiles

Menentukan artefak yang dihasilkan oleh target (atau aspek) tertentu adalah kasus penggunaan BEP umum yang dapat dilakukan secara efisien dengan beberapa persiapan. Bagian ini membahas struktur bersama rekursif yang ditawarkan oleh peristiwa NamedSetOfFiles, yang cocok dengan struktur Depset Starlark.

Konsumen harus berhati-hati untuk menghindari algoritme kuadrat saat memproses peristiwa NamedSetOfFiles karena build besar dapat berisi puluhan ribu peristiwa seperti itu, yang memerlukan ratusan juta operasi dalam traversal dengan kompleksitas kuadrat.

grafik-nama-kumpulan-bep

Gambar 2. Grafik BEP NamedSetOfFiles.

Peristiwa NamedSetOfFiles selalu muncul dalam aliran BEP sebelum peristiwa TargetComplete atau NamedSetOfFiles yang mereferensikannya. Ini adalah kebalikan dari hubungan peristiwa "induk-turunan", dengan semua kecuali peristiwa pertama muncul setelah minimal satu peristiwa mengumumkannya. Peristiwa NamedSetOfFiles diumumkan oleh peristiwa Progress tanpa semantik.

Dengan batasan pengurutan dan berbagi ini, konsumen pada umumnya harus buffering semua peristiwa NamedSetOfFiles sampai aliran BEP habis. Aliran peristiwa JSON berikut dan kode Python menunjukkan cara mengisi peta dari target/aspek hingga artefak yang dibuat dalam grup output "default", dan cara memproses output untuk subset target/aspek yang dibuat:

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)