Bzlmod คือชื่อรหัสของระบบการอ้างอิงภายนอกใหม่ ซึ่งเปิดตัวใน Bazel 5.0 เราได้เปิดตัวระบบนี้เพื่อแก้ปัญหาหลายประการของระบบเดิม ซึ่งไม่สามารถแก้ไขได้ทีละน้อย ดูรายละเอียดเพิ่มเติมได้ที่ส่วนคำชี้แจงปัญหาของเอกสารการออกแบบต้นฉบับ
ใน Bazel 5.0 ระบบจะไม่ได้เปิด Bzlmod ไว้โดยค่าเริ่มต้น คุณต้องระบุแฟล็ก
--experimental_enable_bzlmod
เพื่อให้การดำเนินการต่อไปนี้มีผล
ดังที่ชื่อฟีเจอร์ระบุไว้ ฟีเจอร์นี้ยังอยู่ในขั้นทดลอง
API และลักษณะการทำงานอาจเปลี่ยนแปลงไปจนกว่าฟีเจอร์จะเปิดตัวอย่างเป็นทางการ
หากต้องการย้ายข้อมูลโปรเจ็กต์ไปยัง Bzlmod ให้ทำตามคำแนะนำในการย้ายข้อมูล Bzlmod นอกจากนี้ คุณยังดูตัวอย่างการใช้งาน Bzlmod ได้ในที่เก็บตัวอย่าง
โมดูล Bazel
ระบบการอ้างอิงภายนอกแบบเดิมที่อิงตาม WORKSPACE
จะเน้นที่ที่เก็บข้อมูล (หรือ repo) ซึ่งสร้างขึ้นผ่านกฎของที่เก็บข้อมูล (หรือกฎของ repo)
แม้ว่ารีโปจะยังคงเป็นแนวคิดที่สำคัญในระบบใหม่ แต่โมดูลคือ
หน่วยหลักของ Dependency
โดยพื้นฐานแล้ว โมดูลคือโปรเจ็กต์ Bazel ที่มีได้หลายเวอร์ชัน ซึ่งแต่ละเวอร์ชัน จะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่ขึ้นอยู่กับโมดูลนั้น ซึ่งคล้ายกับแนวคิดที่คุ้นเคยในระบบการจัดการทรัพยากร Dependency อื่นๆ เช่น Artifact ของ Maven, Package ของ npm, Crate ของ Cargo, Module ของ Go เป็นต้น
โมดูลเพียงแค่ระบุการขึ้นต่อกันโดยใช้คู่ name
และ version
แทนที่จะใช้ URL ที่เฉพาะเจาะจงใน WORKSPACE
จากนั้นระบบจะค้นหาการขึ้นต่อกันในรีจิสทรี Bazel โดยค่าเริ่มต้นคือรีจิสทรีกลางของ Bazel ในพื้นที่ทำงาน โมดูลแต่ละรายการจะเปลี่ยนเป็นที่เก็บ
MODULE.bazel
โมดูลทุกเวอร์ชันจะมีไฟล์ MODULE.bazel
ที่ประกาศการอ้างอิงและข้อมูลเมตาอื่นๆ ตัวอย่างพื้นฐานมีดังนี้
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 transitive เหมือนกับไฟล์ WORKSPACE
แต่คุณควรกำหนดเฉพาะทรัพยากร Dependency direct และระบบจะประมวลผลไฟล์ MODULE.bazel
ของทรัพยากร Dependency เพื่อค้นหาทรัพยากร Dependency transitive โดยอัตโนมัติ
ไฟล์ MODULE.bazel
คล้ายกับไฟล์ BUILD
เนื่องจากไม่รองรับรูปแบบการควบคุมโฟลว์ใดๆ และยังห้ามใช้คำสั่ง load
อีกด้วย ไฟล์ที่คำสั่ง
MODULE.bazel
รองรับมีดังนี้
module
เพื่อระบุข้อมูลเมตา เกี่ยวกับโมดูลปัจจุบัน รวมถึงชื่อ เวอร์ชัน และอื่นๆbazel_dep
เพื่อระบุการอ้างอิงโดยตรง ในโมดูล 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 ดังนี้
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
ควรใช้ D เวอร์ชันใด Bzlmod ใช้ การเลือกเวอร์ชันขั้นต่ำ (MVS) ซึ่งเป็นอัลกอริทึมที่เปิดตัวในระบบโมดูล Go เพื่อตอบคำถามนี้ MVS จะถือว่าโมดูลเวอร์ชันใหม่ทั้งหมด เข้ากันได้กับเวอร์ชันก่อนหน้า จึงเลือกเวอร์ชันสูงสุด ที่ระบุโดยการขึ้นต่อกัน (D 1.1 ในตัวอย่างของเรา) เราเรียกเวอร์ชันนี้ว่า "ขั้นต่ำ" เนื่องจาก D 1.1 ในที่นี้เป็นเวอร์ชันขั้นต่ำที่ตรงตามข้อกำหนดของเรา แม้ว่าจะมี D 1.2 หรือเวอร์ชันที่ใหม่กว่า แต่เราก็จะไม่เลือก ซึ่งมีข้อดีเพิ่มเติมคือ การเลือกเวอร์ชันจะมีความเที่ยงตรงสูงและทำซ้ำได้
การแก้ไขเวอร์ชันจะดำเนินการในเครื่องของคุณ ไม่ใช่โดยรีจิสทรี
ระดับความเข้ากันได้
โปรดทราบว่าสมมติฐานของ MVS เกี่ยวกับการเข้ากันได้แบบย้อนหลังนั้นเป็นไปได้เนื่องจาก ถือว่าโมดูลเวอร์ชันที่เข้ากันไม่ได้แบบย้อนหลังเป็นโมดูลแยกต่างหาก ในแง่ของ SemVer นั่นหมายความว่า A 1.x และ A 2.x ถือเป็นโมดูลที่แตกต่างกัน และสามารถอยู่ร่วมกันในกราฟการอ้างอิงที่แก้ไขแล้ว ซึ่งเป็นไปได้เนื่องจากมีการเข้ารหัสเวอร์ชันหลักในเส้นทางแพ็กเกจใน Go จึงไม่มีความขัดแย้งในเวลาคอมไพล์หรือเวลาลิงก์
ใน Bazel เราไม่มีการรับประกันดังกล่าว ดังนั้นเราจึงต้องมีวิธีระบุหมายเลข "เวอร์ชันหลัก" เพื่อตรวจหาเวอร์ชันที่เข้ากันไม่ได้แบบย้อนหลัง หมายเลขนี้เรียกว่าระดับความเข้ากันได้ และจะระบุโดยแต่ละเวอร์ชันของโมดูลในคำสั่ง module()
เมื่อมีข้อมูลนี้ เราจะแสดงข้อผิดพลาด
เมื่อตรวจพบว่ามีโมดูลเวอร์ชันเดียวกันที่มีระดับความเข้ากันได้แตกต่างกัน
อยู่ในกราฟการอ้างอิงที่แก้ไขแล้ว
ชื่อที่เก็บ
ใน Bazel การขึ้นต่อกันภายนอกทุกรายการจะมีชื่อที่เก็บ บางครั้งอาจมีการใช้ทรัพยากร Dependency เดียวกันผ่านชื่อที่เก็บที่แตกต่างกัน (เช่น ทั้ง @io_bazel_skylib
และ @bazel_skylib
หมายถึง Bazel skylib) หรืออาจมีการใช้ชื่อที่เก็บเดียวกันสำหรับทรัพยากร Dependency ที่แตกต่างกันในโปรเจ็กต์ต่างๆ
ใน Bzlmod โมดูล Bazel และส่วนขยายโมดูลจะสร้างที่เก็บได้ เราจึงนำกลไกการแมปที่เก็บมาใช้ในระบบใหม่เพื่อแก้ไขชื่อที่เก็บที่ขัดแย้งกัน แนวคิดสำคัญ 2 ประการมีดังนี้
ชื่อที่เก็บ Canonical: ชื่อที่เก็บที่ไม่ซ้ำกับชื่ออื่นใดทั่วโลกสำหรับที่เก็บแต่ละรายการ นี่จะเป็นชื่อไดเรกทอรีที่ที่เก็บอยู่
โดยมีโครงสร้างดังนี้ (คำเตือน: รูปแบบชื่อ Canonical ไม่ใช่ API ที่คุณควรใช้ เนื่องจากอาจมีการเปลี่ยนแปลงได้ทุกเมื่อ)- สำหรับที่เก็บโมดูล Bazel:
module_name~version
(ตัวอย่าง@bazel_skylib~1.0.3
) - สำหรับที่เก็บส่วนขยายโมดูล
module_name~version~extension_name~repo_name
(ตัวอย่าง@rules_cc~0.0.1~cc_configure~local_config_cc
)
- สำหรับที่เก็บโมดูล Bazel:
ชื่อที่เก็บที่ปรากฏ: ชื่อที่เก็บที่จะใช้ในไฟล์
BUILD
และ.bzl
ภายในที่เก็บ การขึ้นต่อกันเดียวกันอาจมีชื่อที่ปรากฏแตกต่างกันในที่เก็บต่างๆ
โดยมีวิธีพิจารณาดังนี้
ที่เก็บทุกแห่งมีพจนานุกรมการแมปที่เก็บของทรัพยากร Dependency โดยตรง
ซึ่งเป็นการแมปจากชื่อที่เก็บที่เห็นไปยังชื่อที่เก็บ Canonical
เราใช้การแมปที่เก็บเพื่อแก้ไขชื่อที่เก็บเมื่อสร้างป้ายกำกับ
โปรดทราบว่าไม่มีความขัดแย้งของชื่อที่เก็บที่แน่นอน และสามารถค้นพบการใช้งานชื่อที่เก็บที่ชัดเจนได้โดยการแยกวิเคราะห์ไฟล์ MODULE.bazel
ดังนั้นจึงสามารถตรวจหาและแก้ไขความขัดแย้งได้อย่างง่ายดายโดยไม่ส่งผลกระทบต่อการขึ้นต่อกันอื่นๆ
การขึ้นต่อกันอย่างเข้มงวด
รูปแบบการระบุการขึ้นต่อกันแบบใหม่ช่วยให้เราตรวจสอบได้เข้มงวดมากขึ้น โดยเฉพาะอย่างยิ่ง ตอนนี้เราบังคับใช้ว่าโมดูลจะใช้ได้เฉพาะรีโปที่สร้างจากการขึ้นต่อกันโดยตรงของโมดูล ซึ่งจะช่วยป้องกันการหยุดทำงานโดยไม่ตั้งใจและแก้ไขข้อบกพร่องได้ยาก เมื่อมีการเปลี่ยนแปลงบางอย่างในกราฟการอ้างอิงแบบทรานซิทีฟ
เราใช้ Strict Deps โดยอิงตามการแมปที่เก็บ โดยพื้นฐานแล้ว การแมปที่เก็บสำหรับแต่ละที่เก็บจะมีการอ้างอิงโดยตรงทั้งหมดของที่เก็บนั้น ส่วนที่เก็บอื่นๆ จะไม่ปรากฏ ระบบจะกำหนดทรัพยากร Dependency ที่มองเห็นได้สำหรับที่เก็บแต่ละแห่งดังนี้
- ที่เก็บโมดูล Bazel จะเห็นที่เก็บทั้งหมดที่ระบุไว้ในไฟล์
MODULE.bazel
ผ่านbazel_dep
และuse_repo
- ที่เก็บส่วนขยายโมดูลจะเห็นการขึ้นต่อกันที่มองเห็นได้ทั้งหมดของโมดูลที่ ให้ส่วนขยาย รวมถึงที่เก็บอื่นๆ ทั้งหมดที่สร้างโดยส่วนขยายโมดูลเดียวกัน
รีจิสทรี
Bzlmod จะค้นหาการขึ้นต่อกันโดยการขอข้อมูลจากรีจิสทรีของ Bazel รีจิสทรี Bazel เป็นเพียงฐานข้อมูลของโมดูล Bazel รูปแบบรีจิสทรีเดียวที่ระบบรองรับคือรีจิสทรีดัชนี ซึ่งเป็น ไดเรกทอรีในเครื่องหรือเซิร์ฟเวอร์ HTTP แบบคงที่ที่ใช้รูปแบบที่เฉพาะเจาะจง ในอนาคต เราวางแผนที่จะเพิ่มการรองรับรีจิสทรีแบบโมดูลเดียว ซึ่งเป็นเพียง ที่เก็บ 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
: ผลรวมตรวจสอบ ความสมบูรณ์ของทรัพยากรย่อย ของไฟล์เก็บถาวรstrip_prefix
: คำนำหน้าไดเรกทอรีที่จะนำออกเมื่อแตกไฟล์ ที่มาpatches
: รายการสตริง ซึ่งแต่ละสตริงจะตั้งชื่อไฟล์แพตช์ที่จะ ใช้กับที่เก็บถาวรที่แยกออกมา ไฟล์แพตช์จะอยู่ในไดเรกทอรี/modules/$MODULE/$VERSION/patches
patch_strip
: เหมือนกับอาร์กิวเมนต์--strip
ของแพตช์ Unix
- คุณเปลี่ยนประเภทเพื่อใช้เส้นทางในเครื่องได้โดยใช้ฟิลด์ต่อไปนี้
type
:local_path
path
: เส้นทางในเครื่องไปยังที่เก็บ โดยคำนวณดังนี้- หากเส้นทางเป็นเส้นทางแบบสัมบูรณ์ ระบบจะใช้เส้นทางดังกล่าวตามที่เป็นอยู่
- หากเส้นทางเป็นเส้นทางแบบสัมพัทธ์และ
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 เนื้อหาของเอกสารนี้
ได้รับการสนับสนุนโดยที่เก็บ GitHub
bazelbuild/bazel-central-registry
ชุมชน Bazel เป็นผู้ดูแล BCR และยินดีรับผู้มีส่วนร่วมที่ต้องการส่งคำขอ Pull ดู นโยบายและขั้นตอนของรีจิสทรีกลางของ Bazel
นอกเหนือจากการทำตามรูปแบบของรีจิสทรีดัชนีปกติแล้ว BCR ยังกำหนดให้มี
presubmit.yml
สำหรับแต่ละเวอร์ชันของโมดูล
(/modules/$MODULE/$VERSION/presubmit.yml
) ไฟล์นี้จะระบุเป้าหมายการสร้างและการทดสอบที่จำเป็นบางอย่าง ซึ่งสามารถใช้เพื่อตรวจสอบความถูกต้องของเวอร์ชันโมดูลนี้ และไปป์ไลน์ CI ของ BCR จะใช้ไฟล์นี้เพื่อให้มั่นใจถึงการทำงานร่วมกันระหว่างโมดูลใน BCR
การเลือกรีจิสทรี
คุณใช้แฟล็ก Bazel ที่ทำซ้ำได้ --registry
เพื่อระบุรายการรีจิสทรีที่จะขอโมดูลได้ จึงตั้งค่าโปรเจ็กต์ให้ดึงข้อมูลทรัพยากร Dependency จากรีจิสทรีของบุคคลที่สามหรือรีจิสทรีภายในได้ รีจิสทรีที่อยู่ก่อนหน้าจะมี
ลำดับความสำคัญสูงกว่า คุณสามารถใส่รายการ--registry
แฟล็กในไฟล์
.bazelrc
ของโปรเจ็กต์เพื่อความสะดวก
ส่วนขยายโมดูล
ส่วนขยายโมดูลช่วยให้คุณขยายระบบโมดูลได้โดยการอ่านข้อมูลอินพุต
จากโมดูลในกราฟการขึ้นต่อกัน การใช้ตรรกะที่จำเป็นเพื่อแก้ไข
การขึ้นต่อกัน และสุดท้ายคือการสร้าง repo โดยการเรียกใช้กฎของ repo โดยมีฟังก์ชันคล้ายกับมาโคร WORKSPACE
ในปัจจุบัน แต่เหมาะกับโลกของโมดูลและการอ้างอิงแบบทรานซิทีฟมากกว่า
ส่วนขยายโมดูลจะกำหนดในไฟล์ .bzl
เช่นเดียวกับกฎของ repo หรือมาโคร WORKSPACE
โดยจะไม่ได้เรียกใช้โดยตรง แต่แต่ละโมดูลจะระบุชิ้นส่วนของข้อมูลที่เรียกว่าแท็กเพื่อให้ส่วนขยายอ่านได้ จากนั้นหลังจากที่การระบุเวอร์ชันของโมดูลเสร็จสิ้นแล้ว ระบบจะเรียกใช้ส่วนขยายของโมดูล ส่วนขยายแต่ละรายการจะทำงาน
ครั้งเดียวหลังจากที่โมดูลได้รับการแก้ไข (ยังคงก่อนที่จะมีการสร้างจริง) และ
จะอ่านแท็กทั้งหมดที่เป็นของส่วนขยายนั้นในกราฟการขึ้นต่อกันทั้งหมด
[ 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) ]
ในกราฟการขึ้นต่อกันตัวอย่างด้านบน A 1.1
และ B 1.2
เป็นโมดูล Bazel
คุณสามารถคิดว่าแต่ละโมดูลเป็นไฟล์ MODULE.bazel
แต่ละโมดูลสามารถระบุแท็กบางรายการ
สำหรับการขยายโมดูลได้ โดยแท็กบางรายการจะระบุไว้สำหรับการขยาย "maven"
และแท็กบางรายการจะระบุไว้สำหรับ "cargo" เมื่อกราฟการขึ้นต่อกันนี้เสร็จสมบูรณ์ (เช่น 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")
หากส่วนขยายสร้างที่เก็บที่คุณต้องการใช้ในโมดูล ให้ใช้คำสั่ง use_repo
เพื่อประกาศที่เก็บเหล่านั้น เพื่อตอบสนองเงื่อนไข deps ที่เข้มงวดและหลีกเลี่ยงชื่อที่เก็บในเครื่อง
ที่ขัดแย้งกัน
use_repo(
maven,
"org_junit_junit",
guava="com_google_guava_guava",
)
ที่เก็บที่สร้างโดยส่วนขยายเป็นส่วนหนึ่งของ API ดังนั้นจากแท็กที่คุณระบุ คุณควรทราบว่าส่วนขยาย "maven" จะสร้างที่เก็บที่ชื่อ "org_junit_junit" และที่เก็บที่ชื่อ "com_google_guava_guava" เมื่อใช้
use_repo
คุณจะเปลี่ยนชื่อได้ในขอบเขตของโมดูล เช่น เปลี่ยนเป็น
"guava" ในที่นี้
คำจำกัดความของส่วนขยาย
ส่วนขยายโมดูลจะกำหนดในลักษณะเดียวกับกฎของ repo โดยใช้ฟังก์ชัน module_extension
ทั้งคู่มีฟังก์ชันการใช้งาน แต่ในขณะที่กฎ repo มีแอตทริบิวต์หลายรายการ
ส่วนขยายโมดูลมีtag_class
หลายรายการ ซึ่งแต่ละรายการมีแอตทริบิวต์หลายรายการ
คลาสแท็กจะกำหนดสคีมาสำหรับแท็กที่ส่วนขยายนี้ใช้ ต่อจากตัวอย่างส่วนขยาย "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]
ในตัวอย่างข้างต้น เราจะดูโมดูลทั้งหมดในกราฟการขึ้นต่อกัน
(ctx.modules
) ซึ่งแต่ละโมดูลเป็นออบเจ็กต์
bazel_module
ที่ฟิลด์ tags
แสดงแท็ก maven.*
ทั้งหมดในโมดูล จากนั้นเราจะเรียกใช้ยูทิลิตี CLI
Coursier เพื่อติดต่อ Maven และทำการแก้ไข สุดท้าย เราใช้ผลลัพธ์
ความละเอียดเพื่อสร้างที่เก็บจำนวนหนึ่งโดยใช้กฎที่เก็บ maven_single_jar
สมมติ