ส่วนขยายโมดูลช่วยให้ผู้ใช้ขยายระบบโมดูลได้โดยการอ่านข้อมูลอินพุตจากโมดูลต่างๆ ในกราฟการขึ้นต่อกัน ดำเนินการตรรกะที่จำเป็นเพื่อแก้ปัญหาการขึ้นต่อกัน และสุดท้ายสร้าง repo โดยการเรียกใช้กฎของ repo ส่วนขยายเหล่านี้มีความสามารถคล้ายกับกฎของ repo ซึ่งช่วยให้ดำเนินการ I/O ของไฟล์ ส่งคำขอเครือข่าย และอื่นๆ ได้ นอกจากสิ่งอื่นๆ แล้ว ส่วนขยายยังช่วยให้ Bazel โต้ตอบกับระบบการจัดการแพ็กเกจอื่นๆ ได้ในขณะที่ยังคงปฏิบัติตามกราฟการขึ้นต่อกันที่สร้างจากโมดูล Bazel
คุณสามารถกำหนดส่วนขยายโมดูลในไฟล์ .bzl ได้เช่นเดียวกับกฎของ repo โดยส่วนขยายจะไม่ได้รับการเรียกใช้โดยตรง แต่โมดูลแต่ละโมดูลจะระบุข้อมูลบางส่วนที่เรียกว่า แท็กเพื่อให้ส่วนขยายอ่าน 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 เพื่อนำ repo ที่ส่วนขยายสร้างขึ้นมาไว้ในขอบเขตของโมดูลปัจจุบัน
use_repo(maven, "maven")
repo ที่ส่วนขยายสร้างขึ้นเป็นส่วนหนึ่งของ API ของส่วนขยาย ในตัวอย่างนี้ ส่วนขยายโมดูล "maven" สัญญาว่าจะสร้าง repo ที่ชื่อว่า maven เมื่อมีการประกาศข้างต้น ส่วนขยายจะแก้ปัญหาระดับอย่างถูกต้อง เช่น @maven//:org_junit_junit เพื่อชี้ไปยัง repo ที่ส่วนขยาย "maven" สร้างขึ้น
คำจำกัดความของส่วนขยาย
คุณสามารถกำหนดส่วนขยายโมดูลได้ในลักษณะเดียวกับกฎของ repo โดยใช้ฟังก์ชัน
module_extension อย่างไรก็ตาม
แม้ว่ากฎของ repo จะมีแอตทริบิวต์หลายรายการ แต่ส่วนขยายโมดูลจะมี
tag_classes ซึ่งแต่ละรายการมีแอตทริบิวต์หลายรายการ
คลาสแท็กจะกำหนดสคีมาสำหรับแท็กที่ส่วนขยายนี้ใช้ ตัวอย่างเช่น ส่วนขยาย "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 ได้โดยใช้สคีมาแอตทริบิวต์ที่ระบุ
ฟังก์ชันการใช้งานของส่วนขยายโมดูลจะคล้ายกับฟังก์ชันการใช้งานของกฎของ repo
ยกเว้นว่าฟังก์ชันการใช้งานของส่วนขยายโมดูลจะได้รับออบเจ็กต์ module_ctx ซึ่งให้สิทธิ์เข้าถึงโมดูลทั้งหมดที่ใช้ส่วนขยายและแท็กที่เกี่ยวข้องทั้งหมด
จากนั้นฟังก์ชันการใช้งานจะเรียกใช้กฎของ repo เพื่อสร้าง repo
# @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 และ
ชื่อ maven@rules_jvm_external//:extension.bzl
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
การส่งออกส่วนขยายจากไฟล์ .bzl อื่นอีกครั้งจะทำให้ส่วนขยายมีข้อมูลระบุตัวตนใหม่ และหากมีการใช้ส่วนขยายทั้ง 2 เวอร์ชันในกราฟโมดูลแบบส่งผ่าน ระบบจะประเมินส่วนขยายทั้ง 2 เวอร์ชันแยกกัน และจะเห็นเฉพาะแท็กที่เชื่อมโยงกับข้อมูลระบุตัวตนนั้นๆ
ในฐานะผู้เขียนส่วนขยาย คุณควรตรวจสอบว่าผู้ใช้จะใช้ส่วนขยายโมดูลของคุณจากไฟล์ .bzl ไฟล์เดียวเท่านั้น
ชื่อและการมองเห็นของที่เก็บข้อมูล
repo ที่ส่วนขยายสร้างขึ้นจะมีชื่อ Canonical ในรูปแบบ module_repo_canonical_name~extension_name~repo_name สำหรับส่วนขยายที่โฮสต์อยู่ในโมดูลราก ระบบจะแทนที่ส่วน module_repo_canonical_name ด้วยสตริง _main โปรดทราบว่ารูปแบบชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ เนื่องจากรูปแบบนี้อาจมีการเปลี่ยนแปลงได้ทุกเมื่อ
นโยบายการตั้งชื่อนี้หมายความว่าส่วนขยายแต่ละรายการจะมี "เนมสเปซ repo" เป็นของตัวเอง ส่วนขยาย 2 รายการที่แตกต่างกันสามารถกำหนด repo ที่มีชื่อเดียวกันได้โดยไม่ต้องเสี่ยงต่อการเกิดการชนกัน นอกจากนี้ยังหมายความว่า repository_ctx.name จะรายงานชื่อ Canonical ของ repo ซึ่ง ไม่เหมือนกับชื่อที่ระบุไว้ในการเรียกใช้กฎของ repo
เมื่อพิจารณา repo ที่ส่วนขยายโมดูลสร้างขึ้นแล้ว จะมีกฎการมองเห็น repo หลายข้อดังนี้
- repo โมดูล Bazel สามารถดู repo ทั้งหมดที่นำมาใช้ในไฟล์
MODULE.bazelผ่านbazel_depและuse_repo - repo ที่ส่วนขยายโมดูลสร้างขึ้นสามารถดู repo ทั้งหมดที่โมดูลซึ่งโฮสต์ส่วนขยายมองเห็น รวมถึง repo อื่นๆ ทั้งหมดที่ส่วนขยายโมดูลเดียวกันสร้างขึ้น (โดยใช้ชื่อที่ระบุไว้ในการเรียกใช้กฎของ repo เป็นชื่อที่ปรากฏ)
- ซึ่งอาจทำให้เกิดความขัดแย้ง หาก repo โมดูลสามารถดู repo ที่มีชื่อที่ปรากฏ
fooและส่วนขยายสร้าง repo ที่มีชื่อที่ระบุfooแสดงว่า repo ทั้งหมดที่ส่วนขยายนั้นสร้างขึ้นfooจะอ้างอิงถึง repo แรก
- ซึ่งอาจทำให้เกิดความขัดแย้ง หาก repo โมดูลสามารถดู repo ที่มีชื่อที่ปรากฏ
แนวทางปฏิบัติแนะนำ
ส่วนนี้จะอธิบายแนวทางปฏิบัติแนะนำเมื่อเขียนส่วนขยายเพื่อให้ใช้งานง่าย บำรุงรักษาได้ และปรับให้เข้ากับการเปลี่ยนแปลงได้ดีเมื่อเวลาผ่านไป
ใส่ส่วนขยายแต่ละรายการไว้ในไฟล์แยกกัน
เมื่อส่วนขยายอยู่ในไฟล์ที่ต่างกัน ส่วนขยายหนึ่งจะโหลดที่เก็บข้อมูลที่ส่วนขยายอื่นสร้างขึ้นได้ แม้ว่าคุณจะไม่ได้ใช้ฟังก์ชันนี้ แต่ควรใส่ส่วนขยายไว้ในไฟล์แยกกันในกรณีที่คุณอาจต้องใช้ในภายหลัง ทั้งนี้เนื่องจากข้อมูลระบุตัวตนของส่วนขยายอิงตามไฟล์ ดังนั้นการย้ายส่วนขยายไปยังไฟล์อื่นในภายหลังจะเปลี่ยน API สาธารณะและเป็นการเปลี่ยนแปลงที่เข้ากันไม่ได้กับเวอร์ชันก่อนหน้าสำหรับผู้ใช้