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

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

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

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

एक्सटेंशन, Bazel मॉड्यूल में ही होस्ट किए जाते हैं. किसी मॉड्यूल में एक्सटेंशन का इस्तेमाल करने के लिए, सबसे पहले उस मॉड्यूल में bazel_dep जोड़ें जो एक्सटेंशन को होस्ट करता है. इसके बाद, उसे स्कोप में लाने के लिए, use_extension बिल्ट-इन फ़ंक्शन को कॉल करें. यहां एक उदाहरण दिया गया है. यह MODULE.bazel फ़ाइल का एक स्निपेट है. यह rules_jvm_external मॉड्यूल में तय किए गए "maven" एक्सटेंशन का इस्तेमाल करने के लिए है:

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//:org_junit_junit जैसे लेबल को सही तरीके से हल करता है, ताकि वे "maven" एक्सटेंशन से जनरेट की गई रिपॉज़िटरी की ओर इशारा करें.

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

` 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 का मतलब पहली रिपॉज़िटरी होगा.

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

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

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

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