मॉड्यूल एक्सटेंशन की मदद से लोग, डिपेंडेंसी ग्राफ़ में मॉड्यूल से इनपुट डेटा को पढ़कर, डिपेंडेंसी हल करने के लिए ज़रूरी लॉजिक परफ़ॉर्म करके, और रेपो नियमों को कॉल करके रेपो बनाते हुए, मॉड्यूल सिस्टम को बढ़ा सकते हैं. इन एक्सटेंशन में रेपो नियमों से मिलती-जुलती सुविधाएं होती हैं. इनसे उन्हें फ़ाइल I/O चलाने, नेटवर्क के अनुरोध भेजने वगैरह में मदद मिलती है. दूसरी बातों के साथ-साथ, वे Basel मॉड्यूल से बनाए गए डिपेंडेंसी ग्राफ़ का भी ध्यान रखते हुए दूसरे पैकेज मैनेजमेंट सिस्टम के साथ इंटरैक्ट करने में मदद करते हैं.
रेपो नियमों की तरह ही, .bzl
फ़ाइलों में मॉड्यूल एक्सटेंशन तय किए जा सकते हैं. इन्हें सीधे तौर पर ट्रिगर नहीं किया जाता है. इसके बजाय, हर मॉड्यूल में एक्सटेंशन के पढ़ने के लिए, टैग कहे जाने वाले डेटा के अलग-अलग हिस्सों के बारे में बताया जाता है. किसी भी एक्सटेंशन का आकलन करने से पहले, Basel मॉड्यूल रिज़ॉल्यूशन को रन करता है. एक्सटेंशन, इससे जुड़े सभी टैग को पूरे डिपेंडेंसी ग्राफ़ में पढ़ता है.
एक्सटेंशन का इस्तेमाल
एक्सटेंशन, Basel मॉड्यूल में खुद होस्ट किए जाते हैं. किसी मॉड्यूल में किसी एक्सटेंशन का इस्तेमाल करने के लिए, सबसे पहले उस मॉड्यूल पर bazel_dep
जोड़ें जो एक्सटेंशन को होस्ट करता है. इसके बाद, उसे स्कोप में लाने के लिए, use_extension
पहले से मौजूद फ़ंक्शन को कॉल करें. इस उदाहरण पर विचार करें — rules_jvm_external
मॉड्यूल में तय किए गए "मेवेन" एक्सटेंशन का इस्तेमाल करने के लिए, MODULE.bazel
फ़ाइल से एक स्निपेट:
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
डायरेक्टिव का इस्तेमाल करें.
use_repo(maven, "maven")
किसी एक्सटेंशन के ज़रिए जनरेट किए गए डेटा स्टोर करने की जगह, इसके एपीआई का हिस्सा होती है. इस उदाहरण में,
"मेवन" मॉड्यूल एक्सटेंशन, maven
नाम का एक रेपो जनरेट करने का वादा करता है. ऊपर दी गई जानकारी के मुताबिक, एक्सटेंशन @maven//:org_junit_junit
जैसे लेबल को सही तरीके से रिज़ॉल्व करता है, ताकि "मेवन" एक्सटेंशन से जनरेट हुए रेपो को दिखाया जा सके.
एक्सटेंशन की परिभाषा
module_extension
फ़ंक्शन का इस्तेमाल करके, रेपो नियमों की तरह ही मॉड्यूल एक्सटेंशन तय किए जा सकते हैं. हालांकि, रेपो नियमों में कई एट्रिब्यूट होते हैं, लेकिन मॉड्यूल एक्सटेंशन में tag_class
होते हैं. हर एक एट्रिब्यूट में कई एट्रिब्यूट होते हैं. टैग क्लास, इस एक्सटेंशन में इस्तेमाल किए जाने वाले टैग के लिए स्कीमा तय करती हैं. उदाहरण के लिए, ऊपर दिया गया "मैवेन" एक्सटेंशन इस तरह से परिभाषित किया जा सकता है:
# @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
टैग को, दिए गए एट्रिब्यूट स्कीमा का इस्तेमाल करके तय किया जा सकता है.
मॉड्यूल एक्सटेंशन को लागू करने का फ़ंक्शन, रेपो नियमों की तरह ही होता है. हालांकि, इसमें सिर्फ़ module_ctx
ऑब्जेक्ट मिलता है, जो एक्सटेंशन और ज़रूरी टैग का इस्तेमाल करने वाले सभी मॉड्यूल को ऐक्सेस करने की अनुमति देता है.
इसके बाद, लागू करने वाला फ़ंक्शन, रेपो जनरेट करने के लिए रेपो नियमों को कॉल करता है.
# @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)
एक्सटेंशन आइडेंटिटी
मॉड्यूल एक्सटेंशन की पहचान, use_extension
को किए गए कॉल में मौजूद नाम और .bzl
फ़ाइल से की जाती है. यहां दिए गए उदाहरण में, एक्सटेंशन maven
की पहचान .bzl
फ़ाइल @rules_jvm_external//:extension.bzl
और नाम maven
से की गई है:
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
किसी दूसरी .bzl
फ़ाइल से किसी एक्सटेंशन को दोबारा एक्सपोर्ट करने पर, उसे एक नई पहचान मिलती है. साथ ही, अगर एक्सटेंशन के दोनों वर्शन को ट्रांज़िटिव मॉड्यूल ग्राफ़ में इस्तेमाल किया जाता है, तो उनका अलग-अलग आकलन किया जाएगा और आपको सिर्फ़ उस पहचान से जुड़े टैग दिखेंगे.
एक्सटेंशन लेखक के तौर पर, आपको यह पक्का करना चाहिए कि उपयोगकर्ता सिर्फ़ एक .bzl
फ़ाइल से आपके मॉड्यूल एक्सटेंशन का इस्तेमाल करें.
डेटा स्टोर करने की जगहों के नाम और उनके दिखने की सेटिंग
एक्सटेंशन के ज़रिए जनरेट किए गए डेटा संग्रह में module_repo_canonical_name~extension_name~repo_name
के तौर पर कैननिकल नाम होते हैं. रूट मॉड्यूल में होस्ट किए गए एक्सटेंशन के लिए, module_repo_canonical_name
वाला हिस्सा _main
स्ट्रिंग से बदल दिया जाता है. ध्यान दें कि कैननिकल नाम का फ़ॉर्मैट वह एपीआई नहीं है जिस पर आपको निर्भर रहना चाहिए. इसमें किसी भी समय बदलाव हो सकता है.
नाम रखने की इस नीति का मतलब है कि हर एक्सटेंशन का अपना "रेपो नेमस्पेस" होता है; दो
अलग-अलग एक्सटेंशन, बिना किसी झगड़े के एक जैसे नाम से रेपो तय कर सकते हैं. इसका मतलब यह भी है कि repository_ctx.name
, रेपो का कैननिकल नाम रिपोर्ट करता है, जो रेपो नियम कॉल में दिए गए नाम से मेल नहीं है.
मॉड्यूल एक्सटेंशन से जनरेट किए गए रिपो को ध्यान में रखते हुए, रेपो को देखने के कई नियम हैं:
- बेज़ल मॉड्यूल रेपो,
bazel_dep
औरuse_repo
के ज़रिए, अपनीMODULE.bazel
फ़ाइल में उपलब्ध सभी रेपो देख सकता है. - मॉड्यूल एक्सटेंशन से जनरेट किए गए रेपो में, एक्सटेंशन को होस्ट करने वाले मॉड्यूल को दिखने वाले सभी रिपो दिख सकते हैं. साथ ही, एक ही मॉड्यूल एक्सटेंशन से जनरेट हुए अन्य सभी रिपो दिख सकते हैं (रेपो नियम में बताए गए नामों का इस्तेमाल करके, ये अपने नाम के तौर पर दिखते हैं).
- इसकी वजह से विवाद हो सकता है. अगर मॉड्यूल रेपो को साफ़ तौर पर
foo
नाम वाला रेपो दिख सकता है और एक्सटेंशन बताए गए नामfoo
वाला एक रेपो जनरेट करता है, तो उस एक्सटेंशन से जनरेट होने वाले सभी रिपो के लिएfoo
, पिछले रिपो को दिखाता है.
- इसकी वजह से विवाद हो सकता है. अगर मॉड्यूल रेपो को साफ़ तौर पर
सबसे सही तरीके
इस सेक्शन में एक्सटेंशन लिखने के सबसे सही तरीकों के बारे में बताया गया है, ताकि उन्हें इस्तेमाल करना, मैनेज करना आसान हो, और वे समय के साथ होने वाले बदलावों के हिसाब से खुद को ढाल सकें.
हर एक्सटेंशन को एक अलग फ़ाइल में रखें
जब एक्सटेंशन किसी अलग फ़ाइल में होते हैं, तो यह एक एक्सटेंशन को दूसरे एक्सटेंशन से जनरेट की गई डेटा स्टोर करने की जगहों को लोड करने देता है. भले ही, आपने इस फ़ंक्शन का इस्तेमाल न किया हो, फिर भी बेहतर होगा कि बाद में ज़रूरत पड़ने पर इन्हें अलग-अलग फ़ाइलों में रखें. ऐसा इसलिए होता है क्योंकि एक्सटेंशन की पहचान उसकी फ़ाइल पर आधारित होती है, इसलिए इस एक्सटेंशन को बाद में किसी अन्य फ़ाइल में ले जाने से आपका सार्वजनिक API बदल जाता है और यह आपके उपयोगकर्ताओं के लिए पुराने सिस्टम के साथ काम न करने वाला बदलाव होता है.
ऑपरेटिंग सिस्टम और आर्किटेक्चर की जानकारी दें
अगर आपका एक्सटेंशन, ऑपरेटिंग सिस्टम या उसके आर्किटेक्चर टाइप पर निर्भर है, तो एक्सटेंशन की परिभाषा में os_dependent
और arch_dependent
बूलियन एट्रिब्यूट का इस्तेमाल करके, इसकी जानकारी ज़रूर दें. इससे यह पक्का होता है कि अगर Ba ज़रिए, दोनों में से किसी में भी बदलाव होता है,
तो फिर से जांच करने की ज़रूरत है.
डेटा स्टोर करने की जगह के नामों पर, सिर्फ़ रूट मॉड्यूल का सीधे तौर पर असर होना चाहिए
याद रखें कि जब कोई एक्सटेंशन डेटा स्टोर करने की जगहें बनाता है, तो वे एक्सटेंशन के नेमस्पेस में बनाए जाते हैं. इसका मतलब है कि अगर अलग-अलग मॉड्यूल एक ही एक्सटेंशन का इस्तेमाल करते हैं और इसी नाम से डेटा स्टोर करने की जगह बना लेते हैं, तो टकराव हो सकते हैं. यह अक्सर मॉड्यूल एक्सटेंशन के tag_class
के तौर पर दिखता है, जिसमें एक name
तर्क होता है, जिसे रिपॉज़िटरी नियम की name
वैल्यू के तौर पर पास किया जाता है.
उदाहरण के लिए, मान लें कि रूट मॉड्यूल, A
, B
मॉड्यूल पर निर्भर करता है. दोनों मॉड्यूल,
मॉड्यूल पर निर्भर करते हैंmylang
. अगर A
और B
, दोनों mylang.toolchain(name="foo")
को कॉल करते हैं, तो वे दोनों mylang
मॉड्यूल में foo
नाम का डेटा स्टोर करने की जगह बनाने की कोशिश करेंगे. इसके बाद, कोई गड़बड़ी होगी.
इससे बचने के लिए, या तो डेटा स्टोर करने की जगह का नाम सीधे सेट करने की सुविधा हटाएं या सिर्फ़ रूट मॉड्यूल को ऐसा करने की अनुमति दें. रूट मॉड्यूल की इस क्षमता को अनुमति देना ठीक है, क्योंकि इस पर कुछ भी निर्भर नहीं होगा, इसलिए इसे किसी दूसरे मॉड्यूल के बारे में चिंता करने की ज़रूरत नहीं है जो एक विरोधी नाम बना रहा हो.