ส่วนขยายของโมดูล

7.3 · 7.2 · 7.1 · 7.0 · 6.5

ส่วนขยายโมดูลช่วยให้ผู้ใช้ขยายระบบโมดูลได้โดยการอ่านข้อมูลอินพุตจากโมดูลต่างๆ ในกราฟทรัพยากร Dependency ดำเนินการตรรกะที่จำเป็นเพื่อแก้ไขทรัพยากร Dependency และสุดท้ายสร้างที่เก็บด้วยการเรียกใช้กฎที่เก็บ ส่วนขยายเหล่านี้มีความสามารถคล้ายกับกฎที่เก็บ ซึ่งช่วยให้ดำเนินการ I/O ไฟล์ ส่งคำขอเครือข่าย และอื่นๆ ได้ นอกเหนือจากการดำเนินการอื่นๆ แล้ว โมดูลเหล่านี้ยังช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ไปพร้อมกับการเคารพกราฟความเกี่ยวข้องที่สร้างขึ้นจากโมดูล Bazel

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

การใช้งานส่วนขยาย

ส่วนขยายจะโฮสต์ในโมดูล Bazel เอง หากต้องการใช้ส่วนขยายในโมดูลนี้ ก่อนอื่นให้เพิ่ม bazel_dep ในโมดูลที่โฮสต์ส่วนขยาย จากนั้นเรียกใช้ฟังก์ชันในตัวของ use_extension เพื่อทำให้เกิดขอบเขต ลองดูตัวอย่างต่อไปนี้ ซึ่งเป็นข้อมูลโค้ดจากไฟล์ MODULE.bazel เพื่อใช้ส่วนขยาย "maven" ที่กำหนดไว้ในโมดูล rules_jvm_external

bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

ซึ่งจะเชื่อมโยงค่าที่ use_extension ส่งกลับกับตัวแปร ซึ่งอนุญาตให้ผู้ใช้ใช้จุด-ไวยากรณ์เพื่อระบุแท็กสำหรับส่วนขยายได้ แท็กต้องเป็นไปตามสคีมาที่กำหนดโดยคลาสแท็กที่เกี่ยวข้องซึ่งระบุไว้ในคำจำกัดความของส่วนขยาย เช่น การระบุแท็ก maven.install และ maven.artifact บางรายการ

maven.install(artifacts = ["org.junit:junit:4.13.2"])
maven.artifact(group = "com.google.guava",
               artifact = "guava",
               version = "27.0-jre",
               exclusions = ["com.google.j2objc:j2objc-annotations"])

ใช้คำสั่ง use_repo เพื่อนําที่เก็บข้อมูลที่สร้างขึ้นโดยส่วนขยายมาไว้ในขอบเขตของโมดูลปัจจุบัน

use_repo(maven, "maven")

Repos ที่สร้างโดยส่วนขยายเป็นส่วนหนึ่งของ API ในตัวอย่างนี้ ส่วนขยายโมดูล "maven" สัญญาว่าจะสร้างที่เก็บชื่อ maven จากประกาศข้างต้น ส่วนขยายจะแก้ไขป้ายกํากับได้อย่างเหมาะสม เช่น @maven//:org_junit_junit ให้ชี้ไปยังที่เก็บที่สร้างโดยส่วนขยาย "maven"

คำจำกัดความของส่วนขยาย

คุณสามารถระบุส่วนขยายโมดูลได้ในลักษณะเดียวกับกฎที่เก็บ โดยใช้ฟังก์ชัน module_extension อย่างไรก็ตาม แม้ว่ากฎของ repo จะมีแอตทริบิวต์หลายรายการ แต่ส่วนขยายโมดูลจะมีtag_class ซึ่งแต่ละรายการมีแอตทริบิวต์หลายรายการ คลาสแท็กจะกำหนดสคีมาสำหรับแท็กที่ส่วนขยายนี้ใช้ ตัวอย่างเช่น ส่วนขยาย "maven" ด้านบนอาจกำหนดไว้ดังต่อไปนี้

# @rules_jvm_external//:extensions.bzl

_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
maven = module_extension(
  implementation = _maven_impl,
  tag_classes = {"install": _install, "artifact": _artifact},
)

การประกาศเหล่านี้แสดงให้เห็นว่าสามารถระบุแท็ก maven.install และ maven.artifact โดยใช้สคีมาแอตทริบิวต์ที่ระบุ

ฟังก์ชันการใช้งานส่วนขยายโมดูลคล้ายกับกฎที่เก็บ เว้นแต่ว่าจะได้รับออบเจ็กต์ module_ctx ซึ่งให้สิทธิ์เข้าถึงโมดูลทั้งหมดที่ใช้ส่วนขยายและแท็กที่เกี่ยวข้องทั้งหมด จากนั้นฟังก์ชันการใช้งานจะเรียกกฎที่เก็บเพื่อสร้างที่เก็บ

# @rules_jvm_external//:extensions.bzl

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")  # a repo rule
def _maven_impl(ctx):
  # This is a fake implementation for demonstration purposes only

  # collect artifacts from across the dependency graph
  artifacts = []
  for mod in ctx.modules:
    for install in mod.tags.install:
      artifacts += install.artifacts
    artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]

  # call out to the coursier CLI tool to resolve dependencies
  output = ctx.execute(["coursier", "resolve", artifacts])
  repo_attrs = _process_coursier_output(output)

  # call repo rules to generate repos
  for attrs in repo_attrs:
    http_file(**attrs)
  _generate_hub_repo(name = "maven", repo_attrs)

ข้อมูลประจำตัวส่วนขยาย

ส่วนขยายโมดูลจะระบุตามชื่อและไฟล์ .bzl ที่ปรากฏในการเรียก use_extension ในตัวอย่างต่อไปนี้ ส่วนขยาย maven จะระบุโดยไฟล์ .bzl @rules_jvm_external//:extension.bzl และชื่อ maven

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

การส่งออกส่วนขยายอีกครั้งจากไฟล์ .bzl อื่นจะทำให้ส่วนขยายมีข้อมูลระบุใหม่ และหากมีการใช้ทั้ง 2 เวอร์ชันของส่วนขยายในกราฟโมดูลแบบทรานซิทีฟ ระบบจะประเมินแยกกันและจะเห็นเฉพาะแท็กที่เชื่อมโยงกับข้อมูลระบุนั้น

ในฐานะผู้เขียนส่วนขยาย คุณควรตรวจสอบว่าผู้ใช้จะใช้ส่วนขยายโมดูลจากไฟล์ .bzl ไฟล์เดียวเท่านั้น

ชื่อและระดับการเข้าถึงที่เก็บ

Repo ที่สร้างขึ้นโดยส่วนขยายจะมีชื่อตามแบบฉบับในรูปแบบ module_repo_canonical_name~extension_name~repo_name สําหรับส่วนขยายที่โฮสต์ในไฟล์ .js ของโมดูลรูท ระบบจะแทนที่ส่วน module_repo_canonical_name ด้วยสตริง _main โปรดทราบว่ารูปแบบของชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ เนื่องจากอาจเปลี่ยนแปลงได้ตลอดเวลา

นโยบายการตั้งชื่อนี้หมายความว่าส่วนขยายแต่ละรายการจะมี "เนมสเปซที่เก็บ" ของตนเอง โดยส่วนขยาย 2 รายการที่แตกต่างกันจะกำหนดที่เก็บที่มีชื่อเดียวกันได้โดยไม่ต้องเสี่ยงการปะทะ นอกจากนี้ยังหมายความว่า repository_ctx.name รายงานชื่อ Canonical ของที่เก็บ ซึ่งไม่เหมือนกับชื่อที่ระบุในการเรียกกฎที่เก็บ

การพิจารณาที่เก็บข้อมูลที่สร้างขึ้นโดยส่วนขยายโมดูลมีกฎการแสดงผลที่เก็บข้อมูลหลายข้อดังนี้

  • Repo โมดูล Bazel จะดู repo ทั้งหมดที่ระบุไว้ในไฟล์ MODULE.bazel ได้ผ่าน bazel_dep และ use_repo
  • รีโปที่สร้างขึ้นโดยส่วนขยายโมดูลจะดูรีโปทั้งหมดที่มองเห็นได้ของโมดูลที่โฮสต์ส่วนขยายได้ รวมถึงรีโปอื่นๆ ทั้งหมดที่สร้างขึ้นโดยส่วนขยายโมดูลเดียวกัน (โดยใช้ชื่อที่ระบุในการเรียกใช้กฎของรีโปเป็นชื่อที่ปรากฏ)
    • ซึ่งอาจทำให้เกิดข้อขัดแย้ง หากที่เก็บโมดูลเห็นที่เก็บที่ใช้ชื่อ foo อย่างชัดเจน และส่วนขยายสร้างที่เก็บที่มีชื่อที่ระบุ foo ที่เก็บทั้งหมดที่สร้างขึ้นโดยส่วนขยายนั้น foo จะหมายถึงที่เก็บเก่า

แนวทางปฏิบัติแนะนำ

ส่วนนี้จะอธิบายแนวทางปฏิบัติแนะนำเมื่อเขียนชิ้นงานเพื่อให้ใช้งานได้ง่าย ดูแลรักษาได้ และปรับให้เข้ากับการเปลี่ยนแปลงเมื่อเวลาผ่านไป

ใส่ส่วนขยายแต่ละรายการในไฟล์แยกกัน

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