Bazel मॉड्यूल

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

Basel मॉड्यूल एक Bagel प्रोजेक्ट है. इसके कई वर्शन हो सकते हैं. इनमें से हर वर्शन, उस मॉड्यूल के बारे में मेटाडेटा पब्लिश करता है जिस पर वह निर्भर करता है. यह दूसरे डिपेंडेंसी मैनेजमेंट सिस्टम में, जाने-पहचाने कॉन्सेप्ट से मिलता-जुलता है. जैसे, Maven आर्टफ़ैक्ट, एनपीएम पैकेज, Go मॉड्यूल या कार्गो क्रेट.

मॉड्यूल के रेपो रूट में (WORKSPACE फ़ाइल के बगल में) एक 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")

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

डिफ़ॉल्ट रूप से, Bagel इस्तेमाल करने के लिए हर मॉड्यूल का एक वर्शन चुनता है. Baze, हर मॉड्यूल के लिए रेपो की जानकारी देता है. साथ ही, यह रजिस्ट्री से सलाह भी लेता है कि वह हर मॉड्यूल के लिए, रेपो की जानकारी कैसे देना चाहिए.

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

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

इस वजह से, Bzlmod SemVer खास निर्देश का ज़्यादा आसान वर्शन अपनाता है. इनमें ये अंतर शामिल हैं:

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

SemVer का कोई भी मान्य वर्शन, Basel मॉड्यूल का एक मान्य वर्शन है. इसके अलावा, दो SemVer वर्शन a और b, a < b की तुलना सिर्फ़ तब करते हैं, जब उनकी तुलना बेज़ल मॉड्यूल वर्शन के रूप में की जाती है और दोनों वर्शन एक ही होते हैं.

वर्शन चुनना

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

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

D के किस वर्शन का इस्तेमाल किया जाना चाहिए? इस सवाल का हल करने के लिए, Bzlmod ने Go मॉड्यूल सिस्टम में उपलब्ध कम से कम वर्शन चुनने की सुविधा (एमवीएस) एल्गोरिदम का इस्तेमाल किया है. MVS यह मानता है कि मॉड्यूल के सभी नए वर्शन, पुराने सिस्टम के साथ काम करते हैं. इसलिए, किसी भी डिपेंडेंट के हिसाब से तय किए गए सबसे नए वर्शन को चुनता है (हमारे उदाहरण में D 1.1). इसे "बहुत कम" कहा जाता है, क्योंकि D 1.1 सबसे पुराना वर्शन है जो हमारी ज़रूरी शर्तों को पूरा कर सकता है — भले ही, D 1.2 या इसके बाद का वर्शन मौजूद हो, लेकिन हम उन्हें नहीं चुनते. एमवीएस का इस्तेमाल करने से, वर्शन चुनने की ऐसी प्रोसेस बन जाती है जो हाई-फ़िडेलिटी और फिर से जनरेट की जा सकती है.

यांक किए गए वर्शन

अगर कुछ वर्शन से बचना चाहिए (जैसे कि सुरक्षा से जुड़े जोखिमों की स्थिति में), तो रजिस्ट्री उन्हें यान्क किया गया के तौर पर एलान कर सकती है. किसी मॉड्यूल के यैंक किए गए वर्शन को चुनते समय Baज़र एक गड़बड़ी दिखाता है. इस गड़बड़ी को ठीक करने के लिए, नए या बिना यैंक किए गए वर्शन पर अपग्रेड करें या यंक किए गए वर्शन को साफ़ तौर पर अनुमति देने के लिए --allow_yanked_versions फ़्लैग का इस्तेमाल करें.

कंपैटिबिलिटी लेवल

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

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

ओवरराइड

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

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

एक वर्शन में बदलाव

single_version_override कई मकसद पूरे करता है:

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

ये सभी एट्रिब्यूट ज़रूरी नहीं हैं. इन्हें एक-दूसरे के साथ मिलाया और मैच किया जा सकता है.

एक से ज़्यादा वर्शन ओवरराइड करने वाला वर्शन

रिज़ॉल्व किए गए डिपेंडेंसी ग्राफ़ में, एक ही मॉड्यूल के कई वर्शन को एक साथ दिखाने के लिए, multiple_version_override तय किया जा सकता है.

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

उदाहरण के लिए, अगर रिज़ॉल्यूशन से पहले डिपेंडेंसी ग्राफ़ में 1.1, 1.3, 1.5, 1.7, और 2.0 वर्शन मौजूद हैं और मेजर वर्शन, कंपैटबिलिटी लेवल है, तो:

  • एक से ज़्यादा वर्शन ओवरराइड करने से 1.3, 1.7, और 2.0 1.1 को 1.3 में अपग्रेड किया जा रहा है. साथ ही, 1.5 को 1.7 पर अपग्रेड किया जा रहा है और अन्य वर्शन में कोई बदलाव नहीं हुआ है.
  • एक से ज़्यादा वर्शन ओवरराइड करने से 1.5 और 2.0 में गड़बड़ी होती है, क्योंकि 1.7 पर अपग्रेड करने के लिए, काम करने के एक जैसे लेवल वाला कोई नया वर्शन नहीं है.
  • एक से ज़्यादा वर्शन ओवरराइड करने से 1.9 और 2.0 की गड़बड़ी होती है, क्योंकि समाधान से पहले, डिपेंडेंसी ग्राफ़ में 1.9 मौजूद नहीं होता.

इसके अलावा, उपयोगकर्ता registry एट्रिब्यूट का इस्तेमाल करके भी रजिस्ट्री को बदल सकते हैं. यह एक वर्शन में बदलाव की तरह ही होता है.

गैर-रजिस्ट्री बदलाव

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

Baज़ल, रजिस्ट्री के अलावा नीचे दिए गए बदलावों के साथ काम करते हैं:

डेटा स्टोर करने की जगहों के नाम और डिपार्टमेंट

मॉड्यूल का बैक अप लेने वाले रेपो का कैननिकल नाम module_name~version है (उदाहरण के लिए, bazel_skylib~1.0.3). गैर-रजिस्ट्री ओवरराइड वाले मॉड्यूल के लिए, version वाले हिस्से को स्ट्रिंग override से बदलें. ध्यान दें कि कैननिकल नाम का फ़ॉर्मैट कोई एपीआई नहीं है जिस पर आपको निर्भर रहना चाहिए. साथ ही, इसमें किसी भी समय बदलाव किया जा सकता है.

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

मॉड्यूल एक्सटेंशन किसी मॉड्यूल के दिखने वाले दायरे में अतिरिक्त डेटा स्टोर करने की सुविधा भी दे सकते हैं.