จัดการการอ้างอิงภายนอกด้วย Bzlmod

Bzlmod คือชื่อรหัสของระบบทรัพยากร Dependency ภายนอกใหม่ที่เปิดตัวใน Bazel 5.0 โดยได้รับคําแนะนําเพื่อแก้ไขจุดที่เป็นปัญหาของระบบเก่าที่แก้ไขได้อย่างค่อยเป็นค่อยไป ดูรายละเอียดเพิ่มเติมได้ที่ส่วนคําชี้แจงปัญหาของเอกสารต้นฉบับ

ใน Bazel 5.0 Bzlmod จะไม่เปิดโดยค่าเริ่มต้น ต้องระบุธง --experimental_enable_bzlmod ต่อไปนี้เพื่อให้มีผล ตามที่ชื่อธงแนะนํานี้ ฟีเจอร์นี้ยังอยู่ระหว่างการทดสอบ API และลักษณะการทํางานอาจมีการเปลี่ยนแปลงจนกว่าฟีเจอร์จะเปิดตัวอย่างเป็นทางการ

โมดูล Bazel

ระบบอ้างอิงภายนอกของ WORKSPACE แบบเก่ามีศูนย์กลางอยู่ที่ที่เก็บ (หรือที่เก็บ) ที่สร้างผ่านกฎของที่เก็บ (หรือ กฎพื้นที่เก็บข้อมูล) แม้ว่าที่เก็บใหม่จะยังคงเป็นแนวคิดที่สําคัญในระบบใหม่ แต่โมดูลเป็นหน่วยหลักของทรัพยากร Dependency

โมดูลคือโปรเจ็กต์ Bazel ที่มีหลายเวอร์ชันได้ โดยแต่ละเวอร์ชันจะเผยแพร่ข้อมูลเมตาเกี่ยวกับโมดูลอื่นๆ ที่เกี่ยวข้อง ซึ่งคล้ายกับแนวคิดที่คุ้นเคยในระบบการจัดการการอ้างอิงอื่นๆ ได้แก่ อาร์ติแฟกต์ของ Maven, แพ็กเกจ npm, กล่องคาร์โก โมดูล Go, ล,

โมดูลเพียงระบุทรัพยากร Dependency โดยใช้คู่ name และ version แทนการใช้ URL ที่เฉพาะเจาะจงใน WORKSPACE จากนั้นระบบจะค้นหาทรัพยากร Dependency ในรีจิสทรีของ Bazel โดยค่าเริ่มต้นคือ Bazel Central Registry ในพื้นที่ทํางาน แต่ละโมดูลจะกลายเป็นที่เก็บ

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) ซึ่งต่างจากไฟล์ WORKSPACE คุณไม่จําเป็นต้องระบุทรัพยากร Dependency ของการรับส่งข้อมูล คุณควรระบุทรัพยากร Dependency ของโดยตรงแทน และไฟล์ MODULE.bazel ของทรัพยากร Dependency จะได้รับการประมวลผลเพื่อค้นหาทรัพยากร Dependency โดยอัตโนมัติ

ไฟล์ MODULE.bazel คล้ายกับไฟล์ BUILD เนื่องจากไม่รองรับรูปแบบการควบคุมรูปแบบ และห้ามไม่ให้มีคําสั่ง load การรองรับไฟล์คําสั่ง MODULE.bazel มีดังนี้

  • module เพื่อระบุข้อมูลเมตาเกี่ยวกับโมดูลปัจจุบัน รวมถึงชื่อ เวอร์ชัน และอื่นๆ
  • bazel_dep เพื่อระบุการขึ้นต่อกันโดยตรงกับโมดูล Bazel อื่นๆ
  • การลบล้าง ซึ่งใช้ได้กับโมดูลรูทเท่านั้น (กล่าวคือ ไม่ใช้โดยโมดูลที่กําลังใช้ทรัพยากร Dependency) เพื่อปรับแต่งลักษณะการทํางานของทรัพยากร Dependency เฉพาะหรือแบบเปลี่ยนผ่านดังต่อไปนี้
  • คําสั่งที่เกี่ยวข้องกับส่วนขยายโมดูล:

รูปแบบเวอร์ชัน

บาเซลมีระบบนิเวศที่หลากหลายและโครงการต่างๆ ใช้รูปแบบการกําหนดเวอร์ชันที่หลากหลาย รายการที่ได้รับความนิยมมากที่สุดจนถึงตอนนี้คือ SemVer แต่ก็ยังมีโครงการที่โดดเด่นที่ใช้สคีมที่แตกต่างกัน เช่น Abseil ซึ่งมีเวอร์ชัน อ้างอิงวันที่ เช่น 20210324.2)

ด้วยเหตุนี้ Bzlmod จึงนําข้อมูลจําเพาะของ SemVer มาใช้ในบรรยากาศผ่อนคลายมากขึ้น โดยเฉพาะอย่างยิ่งที่อนุญาตให้เกิดลําดับตัวเลขในส่วน "เผยแพร่" ของเวอร์ชัน (แทนที่จะเท่ากับ 3 ตามที่ SemVer กําหนด: MAJOR.MINOR.PATCH) นอกจากนี้ ความหมายของคําว่าเวอร์ชันใหญ่ ผู้เยาว์ และแพตช์ไม่ได้บังคับใช้ด้วย (อย่างไรก็ตาม โปรดอ่านระดับความเข้ากันได้เพื่อดูรายละเอียดเกี่ยวกับวิธีที่เราใช้ความเข้ากันได้แบบย้อนหลัง) ระบบจะไม่แก้ไขส่วนอื่นๆ ของข้อมูลจําเพาะ SemVer เช่น ขีดกลางของเวอร์ชันที่เผยแพร่

ความละเอียดของเวอร์ชัน

ปัญหาด้านการใช้เพชรเป็นหลักคือพื้นที่ที่มีการจัดการโดยใช้ทรัพยากร Dependency สมมติว่าคุณมีกราฟทรัพยากรต่อไปนี้

       A 1.0
      /     \
   B 1.0    C 1.1
     |        |
   D 1.0    D 1.1

ควรใช้ D เวอร์ชันใด ในการแก้ปัญหานี้ Bzlmod ใช้อัลกอริทึมการเลือกเวอร์ชันมินิมอล (MVS) ที่ใช้ในระบบโมดูล Go MVS จะถือว่าโมดูลเวอร์ชันใหม่ทั้งหมดเข้ากันได้หลัง จึงจะเลือกเวอร์ชันสูงสุดที่ระบุตามโมดูลใดก็ได้ (D 1.1 ในตัวอย่างของเรา) เราเรียกการดําเนินการนี้ว่า "มินิมอล" เนื่องจากมีเวอร์ชัน 1.1 สําหรับเวอร์ชันมินิมัล ซึ่งเป็นไปตามข้อกําหนด แม้เราจะไม่มี D 1.2 ขึ้นไปก็ตาม ซึ่งข้อดีเพิ่มเติมคือการเลือกเวอร์ชันเป็นความแม่นยําสูงและทําซ้ํา

ความละเอียดของเวอร์ชันจะดําเนินการภายในเครื่องของคุณ ไม่ใช่โดยรีจิสทรี

ระดับความเข้ากันได้

โปรดทราบว่าสมมติฐานที่ MVS ทําได้เกี่ยวกับความเข้ากันได้แบบย้อนหลังนั้นทําได้เพราะใช้โมดูลโมดูลที่ทํางานร่วมกันแบบย้อนหลังไม่เหมือนกัน ในแง่ของ SemVer หมายความว่า A 1.x และ A 2.x จะถือว่าเป็นโมดูลที่แตกต่างกัน และสามารถอยู่ร่วมกับกราฟทรัพยากร Dependency ได้ ซึ่งจะส่งผลให้เกิดข้อเท็จจริงที่ว่าเวอร์ชันหลักจะได้รับการเข้ารหัสในเส้นทางแพ็กเกจใน Go จึงไม่มีเวลาคอมไพล์หรือเวลาเชื่อมโยง

สําหรับ Bazel เราไม่รับประกันดังกล่าว ด้วยเหตุนี้ เราจึงจําเป็นต้องมีวิธีแสดงถึงหมายเลข "เวอร์ชันหลัก" เพื่อตรวจหาเวอร์ชันที่เข้ากันไม่ได้แบบย้อนหลัง หมายเลขนี้เรียกว่าระดับความเข้ากันได้ ซึ่งจะระบุโดยโมดูลแต่ละเวอร์ชันในคําสั่ง module() เมื่อมีข้อมูลนี้อยู่ในมือ ก็อาจเกิดข้อผิดพลาดได้ เมื่อตรวจพบว่ามีโมดูลเดียวกันที่มีระดับความเข้ากันได้ที่แตกต่างกันในกราฟการอ้างอิงที่แก้ไขแล้ว

ชื่อที่เก็บ

ใน Bazel ทรัพยากร Dependency ภายนอกทั้งหมดจะมีชื่อที่เก็บ ในบางครั้งการใช้ทรัพยากร 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)
  • ชื่อที่เก็บในเครื่อง: ชื่อที่เก็บที่จะใช้ในไฟล์ BUILD และ .bzl ภายในที่เก็บ ทรัพยากร Dependency เดียวกันอาจมีชื่อท้องถิ่นต่างกันสําหรับที่เก็บที่ต่างกัน
    โดยพิจารณาจากสิ่งต่อไปนี้

    • สําหรับที่เก็บโมดูล Bazel: module_name โดยค่าเริ่มต้น หรือชื่อที่ระบุโดยแอตทริบิวต์ repo_name ใน bazel_dep
    • สําหรับที่เก็บส่วนขยายโมดูล: ชื่อที่เก็บซึ่งแนะนําผ่าน use_repo

ที่เก็บทั้งหมดจะมีพจนานุกรมการแมปที่เก็บของทรัพยากร Dependency โดยตรงเป็นแผนที่จากชื่อที่เก็บในเครื่องไปยังชื่อที่เก็บ Canonical เราใช้การแมปที่เก็บเพื่อแก้ไขชื่อที่เก็บเมื่อสร้างป้ายกํากับ โปรดทราบว่าไม่มีการขัดแย้งกันของชื่อที่เก็บ Canonical และการค้นพบชื่อที่เก็บในเครื่องโดยการแยกวิเคราะห์ไฟล์ MODULE.bazel ก็จะช่วยให้จับและแก้ปัญหาความขัดแย้งได้อย่างง่ายดายโดยไม่ส่งผลต่อ ทรัพยากร Dependency อื่นๆ

ความเข้มงวดลดลง

รูปแบบตามข้อกําหนดทรัพยากร Dependency ใหม่ช่วยให้เราตรวจสอบที่เข้มงวดขึ้นได้ โดยเฉพาะอย่างยิ่ง เรากําหนดให้โมดูลใช้ที่เก็บที่สร้างขึ้นจากทรัพยากร Dependency โดยตรงได้เท่านั้น วิธีนี้ช่วยป้องกันไม่ให้เกิดข้อขัดข้องที่เสียหายโดยไม่ได้ตั้งใจและแก้ไขข้อบกพร่องได้ยากเมื่อบางสิ่งในกราฟอ้างอิงมีการเปลี่ยนแปลง

จริงจังกับการติดตั้งใช้งานอย่างเข้มงวดตามการแมปที่เก็บ โดยทั่วไปการแมปที่เก็บสําหรับที่เก็บแต่ละรายการมีทรัพยากร Dependency โดยตรงทั้งหมดและที่เก็บอื่นๆ จะไม่ปรากฏ ระบบจะกําหนดทรัพยากร Dependency ที่มองเห็นได้ของที่เก็บแต่ละรายการดังนี้

  • ที่เก็บโมดูลของ Bazel จะดูที่เก็บทั้งหมดที่แนะนําในไฟล์ MODULE.bazel ได้ผ่านทาง bazel_dep และ use_repo
  • ที่เก็บของส่วนขยายโมดูลจะดูทรัพยากร Dependency ทั้งหมดของโมดูลที่มีส่วนขยายนั้นได้ รวมถึงที่เก็บอื่นๆ ทั้งหมดที่สร้างขึ้นโดยส่วนขยายโมดูลเดียวกัน

รีจิสทรี

Bzlmod ค้นพบทรัพยากร Dependency โดยการขอข้อมูลจากรีจิสทรี Bazel รีจิสทรี Bazel เป็นเพียงฐานข้อมูลของโมดูล Bazel รีจิสทรีรองรับเพียงประเภทเดียวคือรีจิสทรีดัชนีซึ่งเป็นไดเรกทอรีในเครื่องหรือเซิร์ฟเวอร์ HTTP แบบคงที่ตามรูปแบบที่เจาะจง เรามีแผนที่จะเพิ่มการสนับสนุนสําหรับรีจิสทรีโมดูลเดียว ซึ่งเป็นเพียงที่เก็บ Git ที่มีแหล่งที่มาและประวัติของโปรเจ็กต์

รีจิสทรีรีจิสทรี

รีจิสทรีดัชนีคือไดเรกทอรีในเครื่องหรือเซิร์ฟเวอร์ HTTP แบบคงที่ ที่มีข้อมูลเกี่ยวกับรายการโมดูล ซึ่งรวมถึงหน้าแรก ผู้ดูแล ไฟล์ MODULE.bazel ของแต่ละเวอร์ชัน และวิธีดึงข้อมูลของแต่ละรายการ version ที่สําคัญคือไม่ต้องแสดงไฟล์ที่เก็บถาวรของแหล่งที่มาเอง

รีจิสทรีดัชนีต้องอยู่ในรูปแบบด้านล่าง

  • /bazel_registry.json: ไฟล์ JSON ที่มีข้อมูลเมตาสําหรับรีจิสทรี ปัจจุบันมีเพียงคีย์เดียวคือ mirrors ซึ่งระบุรายการมิเรอร์ที่จะใช้สําหรับที่เก็บถาวรของต้นทาง
  • /modules: ไดเรกทอรีที่มีไดเรกทอรีย่อยสําหรับแต่ละโมดูลในรีจิสทรีนี้
  • /modules/$MODULE: ไดเรกทอรีที่มีไดเรกทอรีย่อยสําหรับแต่ละโมดูลของโมดูลนี้ และไฟล์ต่อไปนี้
    • metadata.json: ไฟล์ JSON ที่มีข้อมูลเกี่ยวกับโมดูลโดยมีช่องต่อไปนี้
      • homepage: URL หน้าแรกของโครงการ
      • maintainers: รายการออบเจ็กต์ JSON แต่ละรายการที่สอดคล้องกับข้อมูลของผู้ดูแลโมดูลในรีจิสทรี โปรดทราบว่าชื่อนี้ไม่จําเป็นต้องเหมือนกับ author ของโครงการ
      • versions: รายการเวอร์ชันของโมดูลทั้งหมดที่จะพบในรีจิสทรีนี้
      • yanked_versions: รายการเวอร์ชันนี้ของโมดูลนี้ ขณะนี้ยังไม่มีการดําเนินการ แต่ครีเอเตอร์จะข้ามเวอร์ชันที่มีอักขระหยาบหรือทําให้เกิดข้อผิดพลาดได้ในอนาคต
  • /modules/$MODULE/$VERSION: ไดเรกทอรีที่มีไฟล์ต่อไปนี้
    • MODULE.bazel: ไฟล์ MODULE.bazel ของเวอร์ชันโมดูลนี้
    • source.json: ไฟล์ JSON ที่มีข้อมูลเกี่ยวกับวิธีดึงข้อมูลแหล่งที่มาของเวอร์ชันโมดูลนี้ โดยมีช่องต่อไปนี้
      • url: URL ของที่เก็บถาวรต้นทาง
      • integrity: ผลรวมตรวจสอบความสมบูรณ์ของทรัพยากร
      • strip_prefix: คํานําหน้าของแถบที่จะตัดเมื่อแยก ที่เก็บถาวรของแหล่งที่มา
      • patches: รายการสตริง โดยแต่ละชื่อจะตั้งชื่อไฟล์แพตช์เพื่อใช้กับที่เก็บถาวรที่แยกไว้ ไฟล์แพตช์อยู่ภายใต้ไดเรกทอรี /modules/$MODULE/$VERSION/patches
      • patch_strip: เหมือนกับอาร์กิวเมนต์ --strip ของแพตช์ Unix
    • patches/: ไดเรกทอรีที่ไม่บังคับซึ่งมีไฟล์แพตช์

รีจิสทรี Bazel Central

Bazel Central Registry (BCR) เป็นรีจิสทรีดัชนีที่ registry.bazel.build เนื้อหาของที่เก็บได้รับการสํารองข้อมูลโดยที่เก็บ GitHub bazelbuild/bazel-central-registry

BCR ได้รับการดูแลโดยชุมชน Bazel ผู้ร่วมให้ข้อมูลสามารถส่งคําขอดึงข้อมูลได้ ดูนโยบายและกระบวนการลงทะเบียนของ Central Registry

นอกเหนือจากการปฏิบัติตามรูปแบบรีจิสทรีดัชนีตามปกติแล้ว BCR ยังจําเป็นต้องใช้ไฟล์ presubmit.yml สําหรับโมดูลแต่ละเวอร์ชัน (/modules/$MODULE/$VERSION/presubmit.yml) ไฟล์นี้จะระบุเป้าหมายบิลด์และการทดสอบที่สําคัญ 2-3 เป้าหมายที่ใช้เพื่อตรวจสอบความถูกต้องของเวอร์ชันของโมดูลนี้ได้ และใช้โดยไปป์ไลน์ CI ของ BCR เพื่อการทํางานร่วมกันระหว่างโมดูลใน BCR ของ Google Play

การเลือกรีจิสทรี

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

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

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

ส่วนขยายโมดูลจะกําหนดไว้ในไฟล์ .bzl เช่นเดียวกับกฎที่เก็บหรือมาโคร 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 etcล etc เป็นโมดูล Bazel คุณอาจคิดว่าโมดูลแต่ละรายการเป็นไฟล์ MODULE.bazel แต่ละโมดูลจะระบุแท็กสําหรับส่วนขยายโมดูลได้บางส่วน โค้ดบางรายการระบุสําหรับส่วนขยาย "maven" และบางรายการระบุสําหรับ "gogo" เมื่อสรุปทรัพยากร Dependency นี้เสร็จสมบูรณ์แล้ว (เช่น จริงๆ แล้ว B 1.2 อาจมี bazel_dep ใน D 1.3 แต่อัปเกรดเป็น D 1.4 แล้วเนื่องจาก C) ส่วนขยาย "maven" ทํางานและจะอ่านแท็ก maven.* ทั้งหมดโดยใช้ข้อมูลภายในนั้นเพื่อตัดสินใจว่าจะสร้างที่เก็บใด ในทํานองเดียวกัน สําหรับส่วนขยาย "gogo"

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

ส่วนขยายจะโฮสต์อยู่ในโมดูล 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 เพื่อประกาศ การดําเนินการนี้เป็นไปตามเงื่อนไขความเข้มงวดที่เคร่งครัด และหลีกเลี่ยงความขัดแย้งกับชื่อที่เก็บในเครื่อง

use_repo(
    maven,
    "org_junit_junit",
    guava="com_google_guava_guava",
)

ที่เก็บที่สร้างขึ้นโดยส่วนขยายเป็นส่วนหนึ่งของ API ดังนั้นจากแท็กที่ระบุ คุณควรทราบว่าส่วนขยาย "maven" จะสร้างที่เก็บที่ชื่อว่า "org_junit_junit" และรายการหนึ่งชื่อ "com_google_guava_guava" เมื่อใช้ use_repo คุณจะเปลี่ยนชื่อในขอบเขตของโมดูลได้ เช่น "guava" ที่นี่

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

ส่วนขยายโมดูลมีการกําหนดคล้ายกับกฎที่เก็บ โดยใช้ฟังก์ชัน module_extension ทั้ง 2 อย่างมีฟังก์ชันการใช้งาน แม้ว่ากฎพื้นที่เก็บข้อมูลจะมีแอตทริบิวต์หลายรายการ แต่ส่วนขยายโมดูลก็มี tag_class จํานวนหนึ่งซึ่งแต่ละรายการมีแอตทริบิวต์ คลาสแท็กจะกําหนดสคีมาสําหรับแท็กที่ส่วนขยายนี้ใช้ ตัวอย่างของส่วนขยาย "ผู้สร้าง" สมมติข้างต้นมีดังนี้

# @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 และแท็กที่เกี่ยวข้องทั้งหมด ฟังก์ชันการใช้งานควรเรียกใช้กฎที่เก็บเพื่อสร้างที่เก็บ

# @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