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

समस्या की शिकायत करें स्रोत देखें

मॉड्यूल एक्सटेंशन, उपयोगकर्ताओं को डिपेंडेंसी ग्राफ़ में मॉड्यूल से इनपुट डेटा पढ़कर, डिपेंडेंसी के लिए ज़रूरी लॉजिक इस्तेमाल करके, और आखिर में रिपो नियमों को कॉल करके रिपॉज़िट बनाने की सुविधा देते हैं. इन एक्सटेंशन में रेपो नियमों जैसी क्षमताएं होती हैं, जो उन्हें फ़ाइल I/O करने, नेटवर्क के अनुरोध भेजने वगैरह में सक्षम बनाती हैं. इसके अलावा, वे Bazel को दूसरे पैकेज मैनेजमेंट सिस्टम से इंटरैक्ट करने की अनुमति देते हैं. साथ ही, वह Bazel मॉड्यूल से बने डिपेंडेंसी ग्राफ़ का भी ध्यान रखते हैं.

रेपो नियमों की तरह ही, .bzl फ़ाइलों में मॉड्यूल एक्सटेंशन तय किए जा सकते हैं. इन्हें सीधे तौर पर शुरू नहीं किया जाता. इसके बजाय, हर मॉड्यूल टैग नाम के डेटा के बारे में बताता है, ताकि एक्सटेंशन को पढ़ा जा सके. Bazel किसी भी एक्सटेंशन का आकलन करने से पहले, मॉड्यूल रिज़ॉल्यूशन को चलाता है. यह एक्सटेंशन, डिपेंडेंसी के पूरे ग्राफ़ में अपने सभी टैग को पढ़ता है.

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

एक्सटेंशन, Bazel मॉड्यूल में खुद होस्ट किए जाते हैं. किसी मॉड्यूल में एक्सटेंशन का इस्तेमाल करने के लिए, सबसे पहले एक्सटेंशन को होस्ट करने वाले मॉड्यूल पर bazel_dep जोड़ें. इसके बाद, उसे स्कोप में लाने के लिए, use_extension बिल्ट-इन फ़ंक्शन को कॉल करें. नीचे दिए गए उदाहरण पर विचार करें — rules_jvm_external मॉड्यूल में बताए गए "maven" एक्सटेंशन का इस्तेमाल करने के लिए, 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 नाम के रेपो जनरेट करने का वादा करता है. ऊपर दी गई जानकारी के साथ, एक्सटेंशन "maven" एक्सटेंशन से जनरेट किए गए रेपो को पॉइंट करने के लिए, @maven//:org_junit_junit जैसे लेबल को सही तरीके से रिज़ॉल्व करता है.

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

module_extension फ़ंक्शन का इस्तेमाल करके, रिपो नियमों की तरह मॉड्यूल एक्सटेंशन तय किए जा सकते हैं. हालांकि, रीपो के नियमों में कई एट्रिब्यूट होते हैं, लेकिन मॉड्यूल एक्सटेंशन में tag_classes होते हैं. इनमें से हर एक में कई एट्रिब्यूट होते हैं. टैग क्लास, इस एक्सटेंशन में इस्तेमाल किए गए टैग के लिए स्कीमा तय करती हैं. उदाहरण के लिए, ऊपर दिए गए "maven" एक्सटेंशन को इस तरह से परिभाषित किया जा सकता है:

# @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 मॉड्यूल रेपो, अपनी MODULE.bazel फ़ाइल में पेश किए गए सभी रिपो देख सकता है bazel_dep और use_repo की मदद से.
  • किसी मॉड्यूल एक्सटेंशन से जनरेट किया गया रेपो, एक्सटेंशन को होस्ट करने वाले मॉड्यूल पर दिखने वाले सभी रिपो देख सकता है, साथ ही उसी मॉड्यूल एक्सटेंशन से जनरेट किए गए दूसरे सभी रिपो देख सकता है (रीपो नियम कॉल में बताए गए नामों का इस्तेमाल करके उनके साफ़ तौर पर दिखने वाले नामों का इस्तेमाल करके).
    • इसकी वजह से, समय पर विवाद हो सकता है. अगर मॉड्यूल रेपो, साफ़ तौर पर दिखने वाले नाम foo के साथ डेटा स्टोर करने की जगह देख सकता है और एक्सटेंशन तय किए गए नाम foo से डेटा रेपो जनरेट करता है, तो उस एक्सटेंशन से जनरेट किए गए सभी रिपो के लिए foo का मतलब पुराने नाम से है.

सबसे सही तरीके

इस सेक्शन में एक्सटेंशन लिखने के सबसे सही तरीके बताए गए हैं. इससे इन्हें इस्तेमाल करने, मैनेज करने, और समय के साथ होने वाले बदलावों के हिसाब से ढलने में आसानी होगी.

हर एक्सटेंशन को अलग फ़ाइल में रखें

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

ऑपरेटिंग सिस्टम और आर्किटेक्चर की जानकारी दें

अगर आपका एक्सटेंशन, ऑपरेटिंग सिस्टम या उसके आर्किटेक्चर पर निर्भर करता है, तो "os_dependent" और "arch_exact" बूलियन एट्रिब्यूट का इस्तेमाल करके, एक्सटेंशन की परिभाषा में इसकी जानकारी ज़रूर दें. इससे यह पक्का होता है कि अगर उनमें से किसी में भी बदलाव होता है, तो Bazel को फिर से आकलन करने की ज़रूरत होगी.