Bzlmod की मदद से, डिपेंडेंसी मैनेज करें

Bzlmod बैजल 5.0 में पेश किए गए नए बाहरी डिपेंडेंसी सिस्टम का कोडनाम है. इसे पुराने सिस्टम के ऐसे कई दर्द बिंदुओं के लिए शुरू किया गया था जिनकी सुविधाएं धीरे-धीरे ठीक नहीं की जा सकतीं; ज़्यादा जानकारी के लिए, मूल डिज़ाइन दस्तावेज़ का समस्या स्टेटमेंट सेक्शन देखें.

Bazel 5.0 में, Bzlmod डिफ़ॉल्ट रूप से चालू नहीं होता. असर डालने के लिए --experimental_enable_bzlmod के बारे में बताने वाले फ़्लैग के बारे में बताना ज़रूरी है. जैसा कि फ़्लैग नाम से पता चलता है कि यह सुविधा अभी प्रयोग के तौर पर है; एपीआई की सुविधा और व्यवहार, आधिकारिक तौर पर लॉन्च होने तक बदल सकते हैं.

बेज़ेल मॉड्यूल

पुराना WORKSPACE-आधारित बाहरी डिपेंडेंसी सिस्टम, repositories (या repos) के आस-पास केंद्रित है, जो repository नियमों (या repo नियमों). हालांकि, नए सिस्टम में रेपोज़ अब भी एक अहम कॉन्सेप्ट हैं, लेकिन मॉड्यूल डिपेंडेंसी की मुख्य इकाइयां हैं.

मॉड्यूल एक बैजल प्रोजेक्ट है जिसमें कई वर्शन हो सकते हैं. हर वर्शन में ऐसे मॉड्यूल के बारे में मेटाडेटा प्रकाशित किया जाता है जिन पर वह निर्भर करता है. यह किसी दूसरे डिपेंडेंसी प्रबंधन सिस्टम में मौजूद सिद्धांतों के बारे में है: मेवन आर्टफ़ैक्ट, एनपीएम पैकेज, कार्गो क्रेट , एक Go मॉड्यूल वगैरह

मॉड्यूल WORKSPACE में मौजूद किसी खास यूआरएल के बजाय, name और version पेयर का इस्तेमाल करके, अपनी डिपेंडेंसी तय करता है. फिर डिपेंडेंसी 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 फ़ाइल के बगल में). WORKSPACE फ़ाइल के विपरीत, आपको अपनी ट्रांज़िट निर्भरताएं बताने की ज़रूरत नहीं है; इसके बजाय, आपको सिर्फ़ सीधे तौर पर डिपेंडेंसी तय करनी चाहिए. साथ ही, डिपेंडेंसी पर निर्भर रहने वाली MODULE.bazel फ़ाइलों को अपने-आप प्रोसेस किया जाता है.

MODULE.bazel फ़ाइल BUILD फ़ाइलों की तरह है, क्योंकि यह किसी भी तरह के कंट्रोल फ़्लो के साथ काम नहीं करती है; इसके अलावा, यह load स्टेटमेंट को भी अनुमति नहीं देता. ये निर्देश MODULE.bazel फ़ाइलों के साथ काम करते हैं:

  • module, मौजूदा मॉड्यूल का मेटाडेटा बताने के लिए जिसमें उसका नाम, वर्शन वगैरह शामिल हो;
  • bazel_dep, दूसरे Bazel मॉड्यूल पर सीधे तौर पर डिपेंडेंसी तय करने के लिए;
  • किसी खास डाइरेक्ट या ट्रांज़िट डिपेंडेंसी को पसंद के मुताबिक बनाने के लिए, सिर्फ़ रूट मॉड्यूल (यानी कि निर्भरता के तौर पर इस्तेमाल किए जा रहे मॉड्यूल) का इस्तेमाल नहीं किया जा सकता:
  • मॉड्यूल एक्सटेंशन से जुड़े निर्देश:

वर्शन का फ़ॉर्मैट

Bazel में अलग-अलग तरह के नेटवर्क और प्रोजेक्ट हैं, जिनमें अलग-अलग वर्शनिंग स्कीम का इस्तेमाल किया जाता है. अब तक सबसे लोकप्रिय SemVer है, लेकिन अलग-अलग स्कीम का इस्तेमाल करने वाले मुख्य प्रोजेक्ट भी हैं, जैसे कि Abseil, जिसके वर्शन तारीख-आधारित, उदाहरण के लिए 20210324.2).

इस वजह से, Bzlmod SemVer की खास बातों का ज़्यादा सुविधाजनक वर्शन अपनाता है. खास तौर पर, वर्शन के "रिलीज़" वाले हिस्से में अंकों की संख्या के क्रम की अनुमति देता है (SemVer के तय किए गए तीन के बजाय: MAJOR.MINOR.PATCH). इसके अलावा, बड़े, नाबालिग, और पैच वर्शन के सिमैंटिक, ज़बरदस्ती नहीं दिखाए जाते. (हालांकि, हम पुराने सिस्टम के साथ काम करने की सुविधा को कैसे दिखाते हैं, इस बारे में ज़्यादा जानकारी के लिए साथ काम करने का लेवल देखें.) SemVer स्पेसिफ़िकेशन के दूसरे हिस्सों में बदलाव नहीं किए गए हैं, जैसे कि किसी हाइफ़न से पहले वाले वर्शन का संकेत देना.

वर्शन रिज़ॉल्यूशन

वर्शन तय करने वाले डिपेंडेंसी को प्रबंधित करने के लिए, हीरे की डिपेंडेंसी से जुड़ी समस्या होती है. मान लें कि आपके पास नीचे दिए गए डिपेंडेंसी ग्राफ़ हैं:

       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 या इससे नया वर्शन मौजूद हो, हम उन्हें नहीं चुनते हैं. इससे पता चलता है कि वर्शन चुनने का विकल्प ज़्यादा भरोसेमंद है और फिर से बनाया जा सकता है.

वर्शन रिज़ॉल्यूशन आपकी मशीन पर स्थानीय तौर पर दिखाया जाता है, न कि रजिस्ट्री.

इनके साथ काम करने की सुविधा

ध्यान दें कि एमवीएस के लिए पुराने सिस्टम के साथ काम करने की सुविधा का अनुमान लगाना संभव है, क्योंकि यह पुराने मॉड्यूल के उन वर्शन को अलग मॉड्यूल मानता है जिनकी ज़रूरत नहीं है. SemVer के संदर्भ में, इसका मतलब है कि 1.x और A 2.x अलग-अलग मॉड्यूल माने जाते हैं और हल किए गए डिपेंडेंसी ग्राफ़ में एक साथ हो सकते हैं. इस वजह से, इस बात का ध्यान रखा जाता है कि प्रमुख वर्शन को Go Go पैकेज पैकेज में एन्कोड किया गया है. इसलिए, कंपाइल-टाइम या लिंक करने के समय के बीच कोई अंतर नहीं है.

बैजल में, ऐसी गारंटी नहीं है. इस तरह "पिछले वर्शन" की संख्या बताने के लिए हमें ऐसे तरीके का इस्तेमाल करना होगा जिससे पीछे वाले वर्शन का पता लगाया जा सके. इस संख्या को कम्पैटबिलटी लेवल कहा जाता है और इसे हर मॉड्यूल के module() निर्देश में बताया जाता है. इस जानकारी के साथ, जब हमें यह पता चलता है कि समाधान किए गए निर्भरता ग्राफ़ में अलग-अलग संगतता लेवल वाले एक ही मॉड्यूल के वर्शन मौजूद हैं.

डेटा स्टोर करने की जगह के नाम

बैजल में, हर बाहरी डिपेंडेंसी का एक 'डेटा स्टोर करने की जगह' नाम होता है. कभी-कभी, डिपेंडेंसी का इस्तेमाल अलग-अलग डेटा स्टोर करने की जगहों के नामों के ज़रिए भी किया जा सकता है (उदाहरण के लिए, @io_bazel_skylib और @bazel_skylib, दोनों का मतलब है बज़ेल स्काइलिब) या एक ही डेटा स्टोर करने की जगह का नाम अलग-अलग प्रोजेक्ट में अलग-अलग डिपेंडेंसी के लिए इस्तेमाल किया जा सकता है.

Bzlmod में, डेटा स्टोर करने की जगहें Bazel मॉड्यूल और मॉड्यूल एक्सटेंशन से जनरेट हो सकती हैं. डेटा स्टोर करने की जगह के टकराव की समस्या को हल करने के लिए, हम नए सिस्टम में डेटा स्टोर करने की मैपिंग की प्रक्रिया को अपना रहे हैं. यहां दो महत्वपूर्ण सिद्धांत दिए गए हैं:

  • कैननिकल डेटा स्टोर करने की जगह का नाम: हर डेटा स्टोर करने की जगह के लिए दुनिया भर में इस्तेमाल किया जाने वाला डेटा स्टोर करने की जगह. इस डायरेक्ट्री का नाम, डेटा स्टोर करने की जगह होता है.
    इसे इस तरह बनाया गया है (चेतावनी: कैननिकल नाम का फ़ॉर्मैट ऐसा एपीआई नहीं है जिस पर आपको निर्भर होना चाहिए. इसमें किसी भी समय बदलाव किया जा सकता है):

    • 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 फ़ाइलों में रेपो में इस्तेमाल किया जाता है. अलग-अलग डेटा स्टोर करने के लिए एक ही डिपेंडेंसी के अलग-अलग स्थानीय नाम हो सकते हैं.
    इसे इस तरह तय किया गया है:

    • बेज़ेल मॉड्यूल रिपॉज़िट के लिए: डिफ़ॉल्ट रूप से module_name या bazel_dep में repo_name एट्रिब्यूट के ज़रिए बताया गया नाम.
    • मॉड्यूल एक्सटेंशन डेटा ट्रांसफ़र के लिए: डेटा स्टोर करने की जगह का नाम use_repo के ज़रिए पेश किया गया.

हर रिपॉज़िटरी (डेटा स्टोर करने की जगह) में सीधे तौर पर डिपेंडेंसी होती है. यह स्थानीय रिपॉज़िटरी (डेटा स्टोर करने की जगह) के नाम से कैननिकल डेटा स्टोर के नाम तक का एक मैप होता है. हम लेबल बनाते समय डेटा स्टोर करने की जगह का समाधान करने के लिए, डेटा संग्रह की मैपिंग का इस्तेमाल करते हैं. ध्यान दें कि कैननिकल डेटा स्टोर करने की जगह के नामों में कोई टकराव नहीं है और MODULE.bazel फ़ाइल को पार्स करके, स्थानीय डेटा संग्रह की जगहों के नामों का इस्तेमाल किया जा सकता है. इसलिए, टकरावों को प्रभावित किए बिना दूसरी डिपेंडेंसी

सख्त गिरावट

नए डिपेंडेंसी से जुड़े खास निर्देश फ़ॉर्मैट से हम सख्ती से जांच कर पाते हैं. खास तौर पर, अब हम यह लागू करते हैं कि मॉड्यूल सिर्फ़ उसी तरह के रिपोज़िट का इस्तेमाल कर सकता है जो उसे सीधे तौर पर निर्भर करता है. इससे, कुछ समय के लिए होने वाले डिपेंडेंसी ग्राफ़ में कुछ बदलाव होने पर, गलती से और डीबग करने में मुश्किल का सामना करने में मदद मिलती है.

डिपोज़िटरी मैपिंग के आधार पर सख्त डिप्स लागू की जाती है. दरअसल, हर डेटा स्टोर करने की जगह के लिए डेटा स्टोर करने की मैपिंग में सभी डिपेंडेंसी होती है. यह किसी दूसरी रिपॉज़िटरी (डेटा स्टोर करने की जगह) को नहीं देखा जाता. हर डेटा स्टोर करने की जगह के हिसाब से डिपेंडेंसी इस तरह तय की जाती हैं:

  • बैजल मॉड्यूल रेपो MODULE.bazel फ़ाइल में पेश किए गए सभी मान bazel_dep और use_repo के ज़रिए देख सकते हैं.
  • मॉड्यूल एक्सटेंशन रेपो, एक्सटेंशन देने वाले मॉड्यूल की दिखाई देने वाली सभी निर्भरताएं देख सकता है. साथ ही, एक ही मॉड्यूल एक्सटेंशन से जनरेट किए गए दूसरे सभी रिपोज़िटरी भी देख सकते हैं.

रजिस्ट्री

Bzlmod ने, बेज़ेल से अपनी जानकारी का इस्तेमाल करके अपनी जानकारी का अनुरोध करके, डिपेंडेंसी का पता लगाया. बेज़ेल रजिस्ट्री, बेज़ेल मॉड्यूल का सिर्फ़ एक डेटाबेस है. इंडेक्स रजिस्ट्री सिर्फ़ रजिस्ट्री के लिए काम करती है. यह कोई खास फ़ॉर्मैट इस्तेमाल करने वाली स्थानीय डायरेक्ट्री या स्टैटिक एचटीटीपी सर्वर होता है. आने वाले समय में, हम सिंगल-मॉड्यूल रजिस्ट्री के लिए सहायता जोड़ने की योजना बना रहे हैं. ये बस, किसी प्रोजेक्ट के स्रोत और इतिहास वाली रिपोर्ट के संग्रह होते हैं.

इंडेक्स रजिस्ट्री

इंडेक्स रजिस्ट्री एक लोकल डायरेक्ट्री या स्टैटिक एचटीटीपी सर्वर होता है. इसमें मॉड्यूल की सूची के बारे में जानकारी होती है. इसमें होम पेज, रखरखाव करने वाले, हर वर्शन की MODULE.bazel फ़ाइल, और हर स्रोत के स्रोत को फ़ेच करने का तरीका शामिल होता है वर्शन से अलग होता है. खास तौर से, स्रोत संग्रह को खुद दिखाने की ज़रूरत नहीं होती.

इंडेक्स रजिस्ट्री को नीचे दिए गए फ़ॉर्मैट का पालन करना चाहिए:

  • /bazel_registry.json: ऐसी JSON फ़ाइल जिसमें रजिस्ट्री का मेटाडेटा होता है. फ़िलहाल, इसमें सिर्फ़ एक कुंजी है, mirrors, जो स्रोत के संग्रह के लिए मिरर करने वाली सूची देती है.
  • /modules: इस रजिस्ट्री के हर मॉड्यूल के लिए सबडायरेक्ट्री वाली एक डायरेक्ट्री.
  • /modules/$MODULE: इस डायरेक्ट्री के हर वर्शन के लिए एक सबडायरेक्ट्री वाली डायरेक्ट्री के साथ-साथ यह फ़ाइल भी मौजूद है:
    • metadata.json: एक JSON फ़ाइल जिसमें मॉड्यूल के बारे में जानकारी होती है, जिसमें ये फ़ील्ड शामिल हैं:
      • homepage: प्रोजेक्ट के होम पेज का यूआरएल.
      • maintainers: JSON ऑब्जेक्ट की एक सूची, जिनमें से हर एक रजिस्ट्री में मॉड्यूल के रखरखाव वाले की जानकारी से मेल खाती है. ध्यान दें, यह ज़रूरी नहीं है कि यह प्रोजेक्ट के लेखक ही हों.
      • versions: इस रजिस्ट्री में मिलने वाले इस मॉड्यूल के सभी वर्शन की सूची.
      • yanked_versions: इस मॉड्यूल के क्रम में रखे गए वर्शन की सूची. फ़िलहाल, यह 'नहीं' के तौर पर काम कर रहा है. हालांकि, आने वाले समय में, जल्दी अपलोड होने वाले वर्शन को छोड़ दिया जाएगा या उसमें गड़बड़ी पैदा होगी.
  • /modules/$MODULE/$VERSION: इस फ़ाइल वाली डायरेक्ट्री:
    • MODULE.bazel: इस मॉड्यूल वर्शन की MODULE.bazel फ़ाइल.
    • source.json: एक JSON फ़ाइल, जिसमें इस मॉड्यूल वर्शन के स्रोत को लाने के तरीके की जानकारी दी गई है, जिसमें ये फ़ील्ड शामिल हैं:
      • url: स्रोत संग्रह का यूआरएल.
      • integrity: सबसंसाधन इंटेग्रिटी संग्रह का चेकसम.
      • strip_prefix: स्रोत संग्रह को निकालते समय निकाला जाने वाला निर्देशिका उपसर्ग.
      • patches: स्ट्रिंग की एक सूची, जिनमें से हर एक एक्सट्रैक्ट की गई फ़ाइल को नाम देती है और एक्सट्रैक्ट किए गए संग्रह पर लागू करती है. पैच फ़ाइलें /modules/$MODULE/$VERSION/patches निर्देशिका में शामिल होती हैं.
      • patch_strip: यूनिक्स पैच के --strip तर्क के समान है.
    • patches/: एक वैकल्पिक डायरेक्ट्री जिसमें पैच फ़ाइलें हैं.

बैजल सेंट्रल रजिस्ट्री

Bazel Central Registry (BCR) एक इंडेक्स रजिस्ट्री है, जो registry.bazel.build पर स्थित है. इसके कॉन्टेंट का बैक अप GitHub रिपो bazelbuild/bazel-central-registry पर लेता है.

बीसीआर की देखरेख बाज़ेल समुदाय करता है; पुल के अनुरोध सबमिट करने के लिए, योगदान देने वालों का स्वागत है. Bazel Central Registry की नीतियां और प्रक्रियाएं देखें.

सामान्य इंडेक्स रजिस्ट्री के फ़ॉर्मैट को फ़ॉलो करने के अलावा, बीसीआर के लिए हर मॉड्यूल वर्शन के लिए presubmit.yml फ़ाइल ज़रूरी है (/modules/$MODULE/$VERSION/presubmit.yml). इस फ़ाइल में कुछ ज़रूरी बिल्ड और टेस्ट टारगेट दिए गए हैं, जिनका इस्तेमाल करके इस मॉड्यूल के वर्शन की वैधता की जांच की जा सकती है. इसका इस्तेमाल बीसीआर की सीआई पाइपलाइन करता है, ताकि बीसीआर में मौजूद मॉड्यूल के बीच इंटरऑपरेबिलिटी (दूसरे सिस्टम के साथ काम करना) पक्का किया जा सके चुनें.

रजिस्ट्री चुनना

बार-बार इस्तेमाल होने वाले बैजल फ़्लैग --registry का इस्तेमाल करके, रजिस्ट्री की सूची के बारे में बताया जा सकता है. इससे, मॉड्यूल का अनुरोध किया जा सकता है. इससे आप किसी तीसरे पक्ष या इंटरनल रजिस्ट्री से डिपेंडेंसी फ़ेच करने के लिए, अपना प्रोजेक्ट सेट अप कर सकते हैं. पहले के रजिस्ट्री लोगों को अहमियत देते थे. सुविधा के लिए, आप अपने प्रोजेक्ट की .bazelrc फ़ाइल में, --registry फ़्लैग की सूची डाल सकते हैं.

मॉड्यूल एक्सटेंशन

मॉड्यूल एक्सटेंशन की मदद से आप डिपेंडेंसी ग्राफ़ में मौजूद मॉड्यूल के इनपुट डेटा को पढ़ कर, मॉड्यूल पर निर्भर कर सकते हैं. साथ ही, डिपेंडेंसी को ठीक करने के लिए ज़रूरी तर्क परफ़ॉर्म कर सकते हैं और आखिर में रेपो नियमों को कॉल करके डेटा संग्रह कर सकते हैं. वे आज के WORKSPACE मैक्रो की तरह काम करते हैं, लेकिन वे मॉड्यूल और ट्रांज़िट पर निर्भर लोगों के लिए ज़्यादा अनुकूल हैं.

मॉड्यूल एक्सटेंशन .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 वगैरह, Bazel मॉड्यूल हैं. आप इनमें से हर एक को MODULE.bazel फ़ाइल मान सकते हैं. हर मॉड्यूल, मॉड्यूल एक्सटेंशन के लिए कुछ टैग तय कर सकता है; यहां कुछ "Maven" एक्सटेंशन के लिए तय किए गए हैं और कुछ "कार्गो" के लिए दिए गए हैं. जब इस डिपेंडेंसी ग्राफ़ को तय किया जाता है (उदाहरण के लिए, हो सकता है कि B 1.2 में D 1.3 पर असल में bazel_dep हो, लेकिन C की वजह से उसे D 1.4 में अपग्रेड किया गया हो), एक्सटेंशन "maven" चलाया जाता है और यह तय करने के लिए कि कौनसी रिपोज़िट बनाने हैं, यह सभीmaven.* टैग को पढ़ने का काम करता है. इसी तरह "कार्गो" एक्सटेंशन के लिए.

एक्सटेंशन का इस्तेमाल

एक्सटेंशन खुद ही 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",
)

किसी एक्सटेंशन से जनरेट किए गए रीपोज़, उसके एपीआई का हिस्सा हैं. इसलिए, आपने जो टैग दिए हैं, उनके बारे में आपको पता होना चाहिए कि "maven" एक्सटेंशन "org_junit_junit" नाम की रेपो बनाने जा रहा है, और "com_google_guava_guava" ". use_repo के साथ, आप अपने मॉड्यूल के दायरे में उनका नाम बदल सकते हैं, जैसे कि यहां "guava".

एक्सटेंशन की परिभाषा

मॉड्यूल एक्सटेंशन उसी तरह से नियम बनाए गए हैं जिस तरह से नियम module_extension फ़ंक्शन का इस्तेमाल करते हैं. दोनों में लागू करने का फ़ंक्शन होता है; हालांकि, रेपो नियमों में कई एट्रिब्यूट हैं, लेकिन मॉड्यूल एक्सटेंशन में कई 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 ऑब्जेक्ट मिलता है, जो डिपेंडेंसी ग्राफ़ और सभी उपयुक्त टैग का ऐक्सेस देता है. इसके बाद, लागू करने की सुविधा को रिपोज़िट जनरेट करने के लिए रेपो नियमों को कॉल करना चाहिए:

# @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.* टैग दिखाता है. इसके बाद, हम सीएलआई की उपयोगिता का इस्तेमाल करके, मेवन से संपर्क करने और उससे जुड़ी समस्या हल करने के लिए काम शुरू करते हैं. आखिर में, हम काल्पनिक maven_single_jar मानने के नियम का इस्तेमाल करके कई रिज़ॉल्यूशन बनाने के लिए रिज़ॉल्यूशन के नतीजे का इस्तेमाल करते हैं.