Bzlmod คือชื่อรหัสของระบบทรัพยากร Dependency ภายนอกใหม่ ที่เปิดตัวใน Bazel 5.0 ซึ่งเปิดตัวมาเพื่อแก้ปัญหาหลายประการของระบบเก่าที่แก้ไขแบบค่อยๆ เป็นค่อยๆ ไปได้ยาก โปรดดูรายละเอียดเพิ่มเติมในส่วนคำอธิบายปัญหาของเอกสารการออกแบบเดิม
ใน Bazel 5.0 ระบบจะไม่ได้เปิด Bzlmod ไว้โดยค่าเริ่มต้น คุณต้องระบุแฟล็ก --experimental_enable_bzlmod เพื่อให้การตั้งค่าต่อไปนี้มีผล ฟีเจอร์นี้ยังอยู่ในขั้น ทดลอง ในปัจจุบัน โดย
API และลักษณะการทำงานอาจเปลี่ยนแปลงไปจนกว่าฟีเจอร์จะเปิดตัวอย่างเป็นทางการ
หากต้องการย้ายข้อมูลโปรเจ็กต์ไปยัง Bzlmod ให้ทำตามคำแนะนำในการย้ายข้อมูล Bzlmod นอกจากนี้ คุณยังดูตัวอย่างการใช้งาน Bzlmod ได้ในที่เก็บตัวอย่าง
โมดูล Bazel
ระบบทรัพยากร Dependency ภายนอกแบบเก่าที่อิงตาม WORKSPACE จะเน้นที่ ที่เก็บ (หรือ repo) ซึ่งสร้างขึ้นผ่าน กฎของที่เก็บ (หรือ กฎของ repo)
แม้ว่า repo จะยังคงเป็นแนวคิดที่สำคัญในระบบใหม่ แต่ โมดูล คือหน่วยทรัพยากร Dependency หลัก
โมดูล เป็นโปรเจ็กต์ Bazel ที่มีหลายเวอร์ชัน โดยแต่ละเวอร์ชันจะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่โมดูลนั้นๆ ขึ้นอยู่ด้วย ซึ่งคล้ายกับแนวคิดที่คุ้นเคยในระบบการจัดการทรัพยากร Dependency อื่นๆ เช่น _อาร์ติแฟกต์_ ของ Maven, _แพ็กเกจ_ ของ npm, _เครต_ ของ Cargo, _โมดูล_ ของ Go เป็นต้น
โมดูลจะระบุทรัพยากร Dependency โดยใช้คู่ name และ version แทน URL ที่เฉพาะเจาะจงใน WORKSPACE จากนั้นระบบจะค้นหาทรัพยากร Dependency ใน
รีจิสทรี Bazel ซึ่งเป็น
รีจิสทรีกลางของ Bazel โดยค่าเริ่มต้น ในพื้นที่ทำงาน โมดูลแต่ละรายการจะเปลี่ยนเป็น repo
MODULE.bazel
โมดูลทุกเวอร์ชันจะมีไฟล์ MODULE.bazel ที่ประกาศทรัพยากร Dependency และข้อมูลเมตาอื่นๆ ตัวอย่างเบื้องต้นมีดังนี้
module(
name = "my-module",
version = "1.0",
)
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
ไฟล์ MODULE.bazel ควรอยู่ในรูทของไดเรกทอรีพื้นที่ทำงาน (ข้างไฟล์ WORKSPACE) คุณไม่จำเป็นต้องระบุทรัพยากร Dependency แบบทรานซิทีฟ เหมือนกับไฟล์ WORKSPACE แต่ควรรระบุเฉพาะทรัพยากร Dependency โดยตรง และระบบจะประมวลผลไฟล์ MODULE.bazel ของทรัพยากร Dependency เพื่อค้นหาทรัพยากร Dependency แบบทรานซิทีฟโดยอัตโนมัติ
ไฟล์ MODULE.bazel คล้ายกับไฟล์ BUILD เนื่องจากไม่รองรับการควบคุมโฟลว์ทุกรูปแบบ และยังไม่อนุญาตให้ใช้คำสั่ง load ด้วย คำสั่งที่ไฟล์ MODULE.bazel รองรับมีดังนี้
moduleสำหรับระบุข้อมูลเมตาเกี่ยวกับโมดูลปัจจุบัน รวมถึงชื่อ เวอร์ชัน และอื่นๆbazel_depสำหรับระบุทรัพยากร Dependency โดยตรงในโมดูล Bazel อื่นๆ- การลบล้าง ซึ่งใช้ได้เฉพาะโมดูลรูท (นั่นคือ โมดูลที่ไม่ได้ใช้เป็นทรัพยากร Dependency) เพื่อปรับแต่งลักษณะการทำงานของทรัพยากร Dependency โดยตรงหรือแบบทรานซิทีฟบางอย่าง ได้แก่
- คำสั่งที่เกี่ยวข้องกับส่วนขยายโมดูล:
รูปแบบเวอร์ชัน
Bazel มีระบบนิเวศที่หลากหลายและโปรเจ็กต์ต่างๆ ใช้รูปแบบการกำหนดเวอร์ชันที่แตกต่างกัน รูปแบบที่ได้รับความนิยมมากที่สุดคือ SemVer แต่ก็มีโปรเจ็กต์ที่โดดเด่นซึ่งใช้รูปแบบอื่นด้วย เช่น Abseil ที่เวอร์ชันอิงตามวันที่ เช่น 20210324.2)
ด้วยเหตุนี้ Bzlmod จึงใช้ข้อกำหนดเวอร์ชัน SemVer ที่ยืดหยุ่นมากขึ้น โดยมีข้อแตกต่างดังนี้
- SemVer กำหนดว่าส่วน "รีลีส" ของเวอร์ชันต้องประกอบด้วย 3 ส่วน ได้แก่
MAJOR.MINOR.PATCHใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้สามารถใช้ส่วนต่างๆ ได้ตามต้องการ - ใน SemVer ส่วนต่างๆ ในส่วน "รีลีส" ต้องเป็นตัวเลขเท่านั้น ใน Bazel ข้อกำหนดนี้จะยืดหยุ่นมากขึ้นเพื่อให้สามารถใช้ตัวอักษรได้ด้วย และความหมายของการเปรียบเทียบจะตรงกับ "ตัวระบุ" ในส่วน "พรีรีลีส"
- นอกจากนี้ ระบบยังไม่ได้บังคับใช้ความหมายของการเพิ่มเวอร์ชันหลัก เวอร์ชันย่อย และเวอร์ชันแพตช์ (อย่างไรก็ตาม โปรดดู ระดับความเข้ากันได้ สำหรับ รายละเอียดเกี่ยวกับวิธีที่เรากำหนดความเข้ากันได้แบบย้อนหลัง)
เวอร์ชัน SemVer ที่ถูกต้องจะเป็นเวอร์ชันโมดูล Bazel ที่ถูกต้อง นอกจากนี้ เวอร์ชัน SemVer 2 เวอร์ชัน ได้แก่ a และ b จะเปรียบเทียบ a < b ก็ต่อเมื่อเป็นจริงเมื่อเปรียบเทียบเป็นเวอร์ชันโมดูล Bazel
การแก้ปัญหาเวอร์ชัน
ปัญหาทรัพยากร Dependency แบบไดมอนด์เป็นปัญหาหลักในพื้นที่การจัดการทรัพยากร Dependency ที่กำหนดเวอร์ชัน สมมติว่าคุณมีกราฟทรัพยากร Dependency ต่อไปนี้
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
ควรใช้ D เวอร์ชันใด Bzlmod ใช้ การเลือกเวอร์ชันต่ำสุด (MVS) ซึ่งเป็นอัลกอริทึมที่เปิดตัวในระบบโมดูล Go เพื่อแก้ปัญหานี้ MVS สันนิษฐานว่าโมดูลเวอร์ชันใหม่ทั้งหมดมีความเข้ากันได้แบบย้อนหลัง จึงเลือกเวอร์ชันสูงสุดที่ระบุโดยทรัพยากร Dependency (D 1.1 ในตัวอย่างของเรา) อัลกอริทึมนี้เรียกว่า "ต่ำสุด" เนื่องจาก D 1.1 ในที่นี้เป็นเวอร์ชัน ต่ำสุด ที่ตรงตามข้อกำหนดของเรา แม้ว่าจะมี D 1.2 หรือใหม่กว่า แต่เราก็จะไม่เลือกเวอร์ชันเหล่านั้น ซึ่งมีข้อดีเพิ่มเติมคือการเลือกเวอร์ชันมีความ แม่นยำสูง และ ทำซ้ำได้
ระบบจะทำการแก้ปัญหาเวอร์ชันในเครื่องของคุณ ไม่ใช่รีจิสทรี
ระดับความเข้ากันได้
โปรดทราบว่าข้อสันนิษฐานของ MVS เกี่ยวกับความเข้ากันได้แบบย้อนหลังเป็นไปได้เนื่องจากระบบจะถือว่าโมดูลเวอร์ชันที่ไม่เข้ากันแบบย้อนหลังเป็นโมดูลแยกต่างหาก ในแง่ของ SemVer หมายความว่า A 1.x และ A 2.x ถือเป็นโมดูลที่แตกต่างกัน และสามารถอยู่ร่วมกันในกราฟทรัพยากร Dependency ที่แก้ปัญหาแล้ว ซึ่งเป็นไปได้เนื่องจากมีการเข้ารหัสเวอร์ชันหลักในเส้นทางแพ็กเกจใน Go จึงไม่มีความขัดแย้งในเวลาคอมไพล์หรือเวลาลิงก์
ใน Bazel เราไม่มีการรับประกันดังกล่าว ดังนั้นเราจึงต้องมีวิธีระบุหมายเลข "เวอร์ชันหลัก" เพื่อตรวจหาเวอร์ชันที่ไม่เข้ากันแบบย้อนหลัง หมายเลขนี้
เรียกว่า ระดับความเข้ากันได้ และโมดูลแต่ละเวอร์ชันจะระบุไว้ใน
คำสั่ง module() เมื่อมีข้อมูลนี้ เราจะแสดงข้อผิดพลาดเมื่อตรวจพบว่ามีโมดูลเวอร์ชันเดียวกันที่มีระดับความเข้ากันได้ต่างกันอยู่ในกราฟทรัพยากร Dependency ที่แก้ปัญหาแล้ว
ชื่อที่เก็บ
ใน Bazel ทรัพยากร Dependency ภายนอกทุกรายการจะมีชื่อที่เก็บ บางครั้งอาจมีการใช้
ทรัพยากร Dependency เดียวกันผ่านชื่อที่เก็บที่ต่างกัน (เช่น ทั้ง
@io_bazel_skylib และ @bazel_skylib หมายถึง
Bazel skylib) หรืออาจมีการใช้ชื่อที่เก็บเดียวกันสำหรับ
ชื่อที่เก็บที่ต่างกันในโปรเจ็กต์ต่างๆ
ใน Bzlmod โมดูล Bazel และ ส่วนขยายโมดูลสามารถสร้างที่เก็บได้ เราใช้กลไกการแมปที่เก็บ ในระบบใหม่ เพื่อแก้ปัญหาความขัดแย้งของชื่อที่เก็บ แนวคิดสำคัญ 2 ประการมีดังนี้
ชื่อที่เก็บ Canonical: ชื่อที่เก็บที่ไม่ซ้ำกันทั่วโลกสำหรับ ที่เก็บแต่ละแห่ง ชื่อนี้จะเป็นชื่อไดเรกทอรีที่ที่เก็บอยู่
ชื่อนี้สร้างขึ้นดังนี้ (คำเตือน: รูปแบบชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ เนื่องจากอาจมีการเปลี่ยนแปลงได้ทุกเมื่อ)- สำหรับ repo โมดูล Bazel:
module_name~version
(ตัวอย่าง.@bazel_skylib~1.0.3) - สำหรับ repo ส่วนขยายโมดูล:
module_name~version~extension_name~repo_name
(ตัวอย่าง.@rules_cc~0.0.1~cc_configure~local_config_cc)
- สำหรับ repo โมดูล Bazel:
ชื่อที่เก็บที่ปรากฏ: ชื่อที่เก็บที่จะใช้ในไฟล์
BUILDและ.bzlภายใน repo ทรัพยากร Dependency เดียวกันอาจมีชื่อที่ปรากฏต่างกันใน repo ต่างๆ
ชื่อนี้กำหนดดังนี้
ที่เก็บทุกแห่งจะมีพจนานุกรมการแมปที่เก็บของทรัพยากร Dependency โดยตรง ซึ่งเป็นการแมปจากชื่อที่เก็บที่ปรากฏไปยังชื่อที่เก็บ Canonical
เราใช้การแมปที่เก็บเพื่อแก้ปัญหาชื่อที่เก็บเมื่อสร้างป้ายกำกับ โปรดทราบว่าไม่มีความขัดแย้งของชื่อที่เก็บ Canonical และสามารถค้นพบการใช้งานชื่อที่เก็บที่ปรากฏได้โดยการแยกวิเคราะห์ไฟล์ MODULE.bazel จึงสามารถตรวจพบและแก้ปัญหาความขัดแย้งได้อย่างง่ายดายโดยไม่ส่งผลกระทบต่อทรัพยากร Dependency อื่นๆ
ทรัพยากร Dependency ที่เข้มงวด
รูปแบบการระบุทรัพยากร Dependency ใหม่ช่วยให้เราทำการตรวจสอบที่เข้มงวดมากขึ้นได้ โดยเฉพาะอย่างยิ่ง ตอนนี้เราบังคับใช้ว่าโมดูลจะใช้ได้เฉพาะ repo ที่สร้างจากทรัพยากร Dependency โดยตรงเท่านั้น ซึ่งจะช่วยป้องกันการหยุดทำงานโดยไม่ตั้งใจและแก้ปัญหาได้ยากเมื่อมีการเปลี่ยนแปลงบางอย่างในกราฟทรัพยากร Dependency แบบทรานซิทีฟ
เราได้ใช้การแมปที่เก็บเพื่อสร้างทรัพยากร Dependency ที่เข้มงวด โดยพื้นฐานแล้ว การแมปที่เก็บสำหรับ repo แต่ละแห่งจะมี ทรัพยากร Dependency โดยตรง ทั้งหมด และที่เก็บอื่นๆ จะไม่ปรากฏ ระบบจะกำหนดทรัพยากร Dependency ที่ปรากฏสำหรับที่เก็บแต่ละแห่งดังนี้
- repo โมดูล Bazel จะเห็น repo ทั้งหมดที่เปิดตัวในไฟล์
MODULE.bazelผ่านbazel_depและuse_repo - repo ส่วนขยายโมดูลจะเห็นทรัพยากร Dependency ที่ปรากฏทั้งหมดของโมดูลที่ให้ส่วนขยาย รวมถึง repo อื่นๆ ทั้งหมดที่สร้างโดยส่วนขยายโมดูลเดียวกัน
รีจิสทรี
Bzlmod จะค้นหาทรัพยากร Dependency โดยขอข้อมูลจาก รีจิสทรี Bazel รีจิสทรี Bazel เป็นเพียงฐานข้อมูลของโมดูล Bazel รูปแบบรีจิสทรีที่รองรับมีเพียง _รีจิสทรีดัชนี_ ซึ่งเป็น ไดเรกทอรีในเครื่องหรือเซิร์ฟเวอร์ HTTP แบบคงที่ที่ใช้รูปแบบเฉพาะ ใน อนาคต เราวางแผนที่จะเพิ่มการรองรับ รีจิสทรีโมดูลเดียว ซึ่งเป็นเพียง repo Git ที่มีซอร์สโค้ดและประวัติของโปรเจ็กต์
รีจิสทรีดัชนี
รีจิสทรีดัชนีเป็นไดเรกทอรีในเครื่องหรือเซิร์ฟเวอร์ HTTP แบบคงที่ที่มีข้อมูลเกี่ยวกับรายการโมดูล ซึ่งรวมถึงหน้าแรก ผู้ดูแล ไฟล์ MODULE.bazel ของแต่ละเวอร์ชัน และวิธีดึงข้อมูลซอร์สโค้ดของแต่ละเวอร์ชัน โปรดทราบว่ารีจิสทรี ไม่จำเป็นต้อง ให้บริการไฟล์เก็บถาวรของซอร์สโค้ดเอง
รีจิสทรีดัชนีต้องเป็นไปตามรูปแบบด้านล่าง
/bazel_registry.json: ไฟล์ JSON ที่มีข้อมูลเมตาสำหรับรีจิสทรี เช่นmirrorsซึ่งระบุรายการมิเรอร์ที่จะใช้สำหรับไฟล์เก็บถาวรของซอร์สโค้ดmodule_base_pathซึ่งระบุเส้นทางฐานสำหรับโมดูลที่มีประเภทlocal_repositoryในไฟล์source.json
/modules: ไดเรกทอรีที่มีไดเรกทอรีย่อยสำหรับโมดูลแต่ละรายการในรีจิสทรีนี้/modules/$MODULE: ไดเรกทอรีที่มีไดเรกทอรีย่อยสำหรับโมดูลเวอร์ชันนี้แต่ละเวอร์ชัน รวมถึงไฟล์ต่อไปนี้metadata.json: ไฟล์ JSON ที่มีข้อมูลเกี่ยวกับโมดูล โดยมีฟิลด์ต่อไปนี้homepage: URL ของหน้าแรกของโปรเจ็กต์maintainers: รายการออบเจ็กต์ JSON ซึ่งแต่ละรายการสอดคล้องกับข้อมูลของผู้ดูแลโมดูล ในรีจิสทรี โปรดทราบว่าข้อมูลนี้ไม่จำเป็นต้องเหมือนกับ ผู้เขียน โปรเจ็กต์versions: รายการโมดูลเวอร์ชันทั้งหมดที่จะพบในรีจิสทรีนี้yanked_versions: รายการโมดูลเวอร์ชันที่ ยกเลิก ปัจจุบันการดำเนินการนี้ไม่มีผล แต่ในอนาคตระบบจะข้ามเวอร์ชันที่ยกเลิกหรือแสดงข้อผิดพลาด
/modules/$MODULE/$VERSION: ไดเรกทอรีที่มีไฟล์ต่อไปนี้MODULE.bazel: ไฟล์MODULE.bazelของโมดูลเวอร์ชันนี้source.json: ไฟล์ JSON ที่มีข้อมูลเกี่ยวกับวิธีดึงข้อมูลซอร์สโค้ดของโมดูลเวอร์ชันนี้- ประเภทเริ่มต้นคือ "archive" ที่มีฟิลด์ต่อไปนี้
url: URL ของไฟล์เก็บถาวรของซอร์สโค้ดintegrity: ผลรวมตรวจสอบ Subresource Integrity ของไฟล์เก็บถาวรstrip_prefix: คำนำหน้าไดเรกทอรีที่จะนำออกเมื่อแยกไฟล์เก็บถาวรของซอร์สโค้ดpatches: รายการสตริง ซึ่งแต่ละรายการจะตั้งชื่อไฟล์แพตช์ที่จะใช้กับไฟล์เก็บถาวรที่แยกออกมา ไฟล์แพตช์จะอยู่ในไดเรกทอรี/modules/$MODULE/$VERSION/patchespatch_strip: เหมือนกับอาร์กิวเมนต์--stripของแพตช์ Unix
- คุณสามารถเปลี่ยนประเภทเพื่อใช้เส้นทางในเครื่องที่มีฟิลด์ต่อไปนี้ได้
type:local_pathpath: เส้นทางในเครื่องไปยัง repo ซึ่งคำนวณได้ดังนี้- หากเส้นทางเป็นเส้นทางสัมบูรณ์ ระบบจะใช้เส้นทางนั้น
- หากเส้นทางเป็นเส้นทางสัมพัทธ์และ
module_base_pathเป็นเส้นทางสัมบูรณ์ ระบบจะแก้ปัญหาเส้นทางเป็น<module_base_path>/<path> - หากทั้งเส้นทางและ
module_base_pathเป็นเส้นทางสัมพัทธ์ ระบบจะแก้ปัญหาเส้นทางเป็น<registry_path>/<module_base_path>/<path>รีจิสทรีต้องโฮสต์ในเครื่องและใช้โดย--registry=file://<registry_path>ไม่เช่นนั้น Bazel จะแสดงข้อผิดพลาด
- ประเภทเริ่มต้นคือ "archive" ที่มีฟิลด์ต่อไปนี้
patches/: ไดเรกทอรีที่ไม่บังคับซึ่งมีไฟล์แพตช์ โดยจะใช้ก็ต่อเมื่อsource.jsonมีประเภท "archive"
รีจิสทรีกลางของ Bazel
รีจิสทรีกลางของ Bazel (BCR) เป็นรีจิสทรีดัชนีที่อยู่ใน
bcr.bazel.build เนื้อหาของรีจิสทรีนี้ได้รับการสนับสนุนโดย repo GitHub
bazelbuild/bazel-central-registry
ชุมชน Bazel เป็นผู้ดูแล BCR และยินดีรับผู้มีส่วนร่วมส่งคำขอแบบดึง โปรดดู นโยบายและขั้นตอนของรีจิสทรีกลางของ Bazel
นอกเหนือจากการใช้รูปแบบรีจิสทรีดัชนีปกติแล้ว BCR ยังกำหนดให้มี ไฟล์ presubmit.yml สำหรับโมดูลเวอร์ชันแต่ละเวอร์ชัน (/modules/$MODULE/$VERSION/presubmit.yml) ไฟล์นี้จะระบุเป้าหมายการสร้างและการทดสอบที่สำคัญบางอย่างที่ใช้เพื่อตรวจสอบความถูกต้องของโมดูลเวอร์ชันนี้ และไปป์ไลน์ CI ของ BCR จะใช้ไฟล์นี้เพื่อให้มั่นใจว่าโมดูลใน BCR ทำงานร่วมกันได้
การเลือกรีจิสทรี
คุณสามารถใช้แฟล็ก Bazel --registry ที่ทำซ้ำได้เพื่อระบุรายการรีจิสทรีที่จะขอโมดูลได้ คุณจึงตั้งค่าโปรเจ็กต์ให้ดึงข้อมูลทรัพยากร Dependency จากรีจิสทรีของบุคคลที่สามหรือรีจิสทรีภายในได้ รีจิสทรีก่อนหน้าจะมีลำดับความสำคัญสูงกว่า คุณสามารถใส่รายการแฟล็ก --registry ในไฟล์ .bazelrc ของโปรเจ็กต์เพื่อความสะดวก
ส่วนขยายโมดูล
ส่วนขยายโมดูลช่วยให้คุณขยายระบบโมดูลได้โดยการอ่านข้อมูลอินพุตจากโมดูลในกราฟทรัพยากร Dependency ทำตรรกะที่จำเป็นเพื่อแก้ปัญหาทรัพยากร Dependency และสร้าง repo ในท้ายที่สุดโดยการเรียกใช้กฎของ repo ส่วนขยายโมดูลมีฟังก์ชันคล้ายกับมาโคร WORKSPACE ในปัจจุบัน แต่เหมาะกับโลกของโมดูลและทรัพยากร Dependency แบบทรานซิทีฟมากกว่า
ส่วนขยายโมดูลกำหนดไว้ในไฟล์ .bzl เช่นเดียวกับกฎของ repo หรือมาโคร WORKSPACE โดยจะไม่ได้เรียกใช้โดยตรง แต่โมดูลแต่ละรายการจะระบุข้อมูลที่เรียกว่า แท็ก เพื่อให้ส่วนขยายอ่านได้ จากนั้นระบบจะเรียกใช้ส่วนขยายโมดูลหลังจากที่แก้ปัญหาโมดูลเวอร์ชันแล้ว ส่วนขยายแต่ละรายการจะทำงาน 1 ครั้งหลังจากการแก้ปัญหาโมดูล (ก่อนที่จะมีการสร้างจริง) และจะอ่านแท็กทั้งหมดที่เป็นของส่วนขยายนั้นๆ ในกราฟทรัพยากร Dependency ทั้งหมดได้
[ A 1.1 ]
[ * maven.dep(X 2.1) ]
[ * maven.pom(...) ]
/ \
bazel_dep / \ bazel_dep
/ \
[ B 1.2 ] [ C 1.0 ]
[ * maven.dep(X 1.2) ] [ * maven.dep(X 2.1) ]
[ * maven.dep(Y 1.3) ] [ * cargo.dep(P 1.1) ]
\ /
bazel_dep \ / bazel_dep
\ /
[ D 1.4 ]
[ * maven.dep(Z 1.4) ]
[ * cargo.dep(Q 1.1) ]
ในกราฟทรัพยากร Dependency ตัวอย่างด้านบน A 1.1 และ B 1.2 เป็นโมดูล Bazel คุณสามารถคิดว่าแต่ละโมดูลเป็นไฟล์ MODULE.bazel โมดูลแต่ละรายการสามารถระบุแท็กบางรายการสำหรับส่วนขยายโมดูลได้ โดยในที่นี้มีการระบุแท็กบางรายการสำหรับส่วนขยาย "maven" และบางรายการสำหรับ "cargo" เมื่อกราฟทรัพยากร Dependency นี้เสร็จสมบูรณ์ (เช่น B 1.2 อาจมี bazel_dep ใน D 1.3 แต่ได้รับการอัปเกรดเป็น D 1.4 เนื่องจาก C) ระบบจะเรียกใช้ส่วนขยาย "maven" และส่วนขยายนี้จะอ่านแท็ก maven.* ทั้งหมด โดยใช้ข้อมูลในแท็กเพื่อตัดสินใจว่าจะสร้าง repo ใด
เช่นเดียวกับส่วนขยาย "cargo"
การใช้งานส่วนขยาย
ส่วนขยายโฮสต์อยู่ในโมดูล Bazel เอง ดังนั้นหากต้องการใช้ส่วนขยายใน
โมดูล คุณต้องเพิ่ม bazel_dep ในโมดูลนั้นก่อน แล้วจึงเรียกใช้
ฟังก์ชันในตัว use_extension เพื่อนำส่วนขยายนั้นมาใช้ ดูตัวอย่างต่อไปนี้ ซึ่งเป็นข้อมูลโค้ดจากไฟล์ MODULE.bazel เพื่อใช้ส่วนขยาย "maven" สมมติที่กำหนดไว้ในโมดูล rules_jvm_external
bazel_dep(name = "rules_jvm_external", version = "1.0")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
หลังจากนำส่วนขยายมาใช้แล้ว คุณจะใช้ไวยากรณ์แบบจุดเพื่อระบุแท็กสำหรับส่วนขยายได้ โปรดทราบว่าแท็กต้องเป็นไปตามสคีมาที่กำหนดโดย
คลาสแท็กที่เกี่ยวข้อง (ดูคำจำกัดความของส่วนขยาย
ด้านล่าง) ตัวอย่างต่อไปนี้แสดงการระบุแท็ก maven.dep และ maven.pom บางรายการ
maven.dep(coord="org.junit:junit:3.0")
maven.dep(coord="com.google.guava:guava:1.2")
maven.pom(pom_xml="//:pom.xml")
หากส่วนขยายสร้าง repo ที่คุณต้องการใช้ในโมดูล ให้ใช้คำสั่ง
use_repo เพื่อประกาศ
repo เหล่านั้น ทั้งนี้เพื่อให้เป็นไปตามเงื่อนไขทรัพยากร Dependency ที่เข้มงวดและหลีกเลี่ยงความขัดแย้งของชื่อ repo ในเครื่อง
use_repo(
maven,
"org_junit_junit",
guava="com_google_guava_guava",
)
repo ที่สร้างโดยส่วนขยายเป็นส่วนหนึ่งของ API ของส่วนขยาย ดังนั้นจากแท็กที่คุณระบุ คุณควรทราบว่าส่วนขยาย "maven" จะสร้าง repo ที่ชื่อ "org_junit_junit" และ repo ที่ชื่อ "com_google_guava_guava" คุณสามารถเปลี่ยนชื่อ repo เหล่านั้นในขอบเขตของโมดูลได้โดยใช้ use_repo เช่น เปลี่ยนเป็น "guava" ในที่นี้
คำจำกัดความของส่วนขยาย
ส่วนขยายโมดูลกำหนดไว้คล้ายกับกฎของ repo โดยใช้ฟังก์ชัน
module_extension
ทั้งสองอย่างมีฟังก์ชันการใช้งาน แต่กฎของ repo มี
แอตทริบิวต์หลายรายการ ส่วนขยายโมดูลมี
tag_classesหลายรายการ ซึ่งแต่ละรายการมี
แอตทริบิวต์หลายรายการ คลาสแท็กกำหนดสคีมาสำหรับแท็กที่ส่วนขยายนี้ใช้ ดูตัวอย่างส่วนขยาย "maven" สมมติข้างต้นต่อ
# @rules_jvm_external//:extensions.bzl
maven_dep = tag_class(attrs = {"coord": attr.string()})
maven_pom = tag_class(attrs = {"pom_xml": attr.label()})
maven = module_extension(
implementation=_maven_impl,
tag_classes={"dep": maven_dep, "pom": maven_pom},
)
การประกาศเหล่านี้แสดงให้เห็นอย่างชัดเจนว่าสามารถระบุแท็ก maven.dep และ maven.pom ได้โดยใช้สคีมาแอตทริบิวต์ที่กำหนดไว้ข้างต้น
ฟังก์ชันการใช้งานคล้ายกับมาโคร WORKSPACE ยกเว้นว่าฟังก์ชันนี้จะได้รับออบเจ็กต์ module_ctx ซึ่งให้สิทธิ์เข้าถึงกราฟทรัพยากร Dependency และแท็กที่เกี่ยวข้องทั้งหมด จากนั้นฟังก์ชันการใช้งานควรเรียกใช้กฎของ repo เพื่อสร้าง repo
# @rules_jvm_external//:extensions.bzl
load("//:repo_rules.bzl", "maven_single_jar")
def _maven_impl(ctx):
coords = []
for mod in ctx.modules:
coords += [dep.coord for dep in mod.tags.dep]
output = ctx.execute(["coursier", "resolve", coords]) # hypothetical call
repo_attrs = process_coursier(output)
[maven_single_jar(**attrs) for attrs in repo_attrs]
ในตัวอย่างข้างต้น เราจะดูโมดูลทั้งหมดในกราฟทรัพยากร Dependency
(ctx.modules) ซึ่งแต่ละโมดูลเป็น
bazel_module ออบเจ็กต์ที่ฟิลด์ tags แสดง
แท็ก maven.* ทั้งหมดในโมดูล จากนั้นเราจะเรียกใช้ยูทิลิตี CLI Coursier เพื่อติดต่อ Maven และทำการแก้ปัญหา สุดท้าย เราใช้ผลการแก้ปัญหาเพื่อสร้าง repo หลายรายการโดยใช้กฎของ repo maven_single_jar สมมติ