Bazel लॉकफ़ाइल

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

लॉकफ़ाइल जनरेट करना

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

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

लॉकफ़ाइल का इस्तेमाल करना

लॉकफ़ाइल को फ़्लैग --lockfile_mode से कंट्रोल किया जा सकता है. इससे, प्रोजेक्ट की स्थिति, लॉकफ़ाइल से अलग होने पर, Bazel के व्यवहार को पसंद के मुताबिक बनाया जा सकता है. ये मोड उपलब्ध हैं:

  • update (डिफ़ॉल्ट): जानी-मानी रजिस्ट्री फ़ाइलों के डाउनलोड को स्किप करने और उन एक्सटेंशन का फिर से आकलन न करने के लिए, लॉकफ़ाइल में मौजूद जानकारी का इस्तेमाल करें जिनके नतीजे अब भी अप-टू-डेट हैं. अगर जानकारी मौजूद नहीं है, तो उसे लॉकफ़ाइल में जोड़ा जाएगा. इस मोड में, Bazel, उन डिपेंडेंसी के लिए, बदली जा सकने वाली जानकारी को रीफ़्रेश नहीं करता जिनमें कोई बदलाव नहीं हुआ है. जैसे, हटाए गए वर्शन.
  • refresh: यह मोड, update मोड की तरह ही काम करता है. हालांकि, इस मोड पर स्विच करने पर, बदली जा सकने वाली जानकारी हमेशा रीफ़्रेश होती है. साथ ही, इस मोड में हर घंटे में एक बार रीफ़्रेश होती है.
  • error: यह मोड, update मोड की तरह ही काम करता है. हालांकि, अगर कोई जानकारी मौजूद नहीं है या पुरानी हो गई है, तो Bazel, गड़बड़ी के साथ फ़ेल हो जाएगा. इस मोड में, रिज़ॉल्यूशन के दौरान, लॉकफ़ाइल में कोई बदलाव नहीं होता या नेटवर्क के अनुरोध नहीं किए जाते. मॉड्यूल एक्सटेंशन, जिन्हें reproducible के तौर पर मार्क किया गया है वे अब भी नेटवर्क के अनुरोध कर सकते हैं. हालांकि, उनसे हमेशा एक ही नतीजा मिलने की उम्मीद की जाती है.
  • off: इस मोड में, लॉकफ़ाइल की जांच नहीं की जाती और न ही उसे अपडेट किया जाता है.

लॉकफ़ाइल के फ़ायदे

लॉकफ़ाइल के कई फ़ायदे हैं और इसका इस्तेमाल कई तरीकों से किया जा सकता है:

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

  • इंक्रीमेंटल रिज़ॉल्यूशन तेज़ी से किए जा सकते हैं. लॉकफ़ाइल की मदद से, Bazel, उन रजिस्ट्री फ़ाइलों को डाउनलोड नहीं करता जिनका इस्तेमाल पहले किसी बिल्ड में किया जा चुका है. इससे, बिल्ड की क्षमता काफ़ी बेहतर होती है. खास तौर पर, उन स्थितियों में जहां रिज़ॉल्यूशन में ज़्यादा समय लग सकता है.

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

लॉकफ़ाइल का कॉन्टेंट

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

  1. मॉड्यूल रिज़ॉल्यूशन के लिए इनपुट के तौर पर इस्तेमाल की जाने वाली सभी रिमोट फ़ाइलों के हैश.
  2. हर मॉड्यूल एक्सटेंशन के लिए, लॉकफ़ाइल में वे इनपुट शामिल होते हैं जिन पर इसका असर पड़ता है, इन्हें bzlTransitiveDigest, usagesDigest और अन्य फ़ील्ड के तौर पर दिखाया जाता है. साथ ही, उस एक्सटेंशन को चलाने का आउटपुट भी शामिल होता है. इसे generatedRepoSpecs कहा जाता है

यहां एक उदाहरण दिया गया है, जिसमें लॉकफ़ाइल का स्ट्रक्चर दिखाया गया है. साथ ही, हर सेक्शन के बारे में जानकारी दी गई है:

{
  "lockFileVersion": 10,
  "registryFileHashes": {
    "https://bcr.bazel.build/bazel_registry.json": "8a28e4af...5d5b3497",
    "https://bcr.bazel.build/modules/foo/1.0/MODULE.bazel": "7cd0312e...5c96ace2",
    "https://bcr.bazel.build/modules/foo/2.0/MODULE.bazel": "70390338... 9fc57589",
    "https://bcr.bazel.build/modules/foo/2.0/source.json": "7e3a9adf...170d94ad",
    "https://registry.mycorp.com/modules/foo/1.0/MODULE.bazel": "not found",
    ...
  },
  "selectedYankedVersions": {
    "foo@2.0": "Yanked for demo purposes"
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "general": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "bzlTransitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

रजिस्ट्री फ़ाइल के हैश

registryFileHashes सेक्शन में, मॉड्यूल रिज़ॉल्यूशन के दौरान ऐक्सेस की गई रिमोट रजिस्ट्रियों की सभी फ़ाइलों के हैश शामिल होते हैं. रिज़ॉल्यूशन का एल्गोरिदम, एक जैसे इनपुट दिए जाने पर पूरी तरह से तय होता है. साथ ही, सभी रिमोट इनपुट के हैश किए जाते हैं. इससे, रिज़ॉल्यूशन का नतीजा पूरी तरह से एक जैसा होता है. साथ ही, लॉकफ़ाइल में रिमोट जानकारी की ज़रूरत से ज़्यादा डुप्लीकेट कॉपी नहीं बनती. ध्यान दें कि इसमें यह भी रिकॉर्ड किया जाता है कि किसी खास रजिस्ट्री में कोई मॉड्यूल मौजूद नहीं था, लेकिन कम प्राथमिकता वाली रजिस्ट्री में मौजूद था. उदाहरण के लिए, "नहीं मिला" एंट्री देखें. बदली जा सकने वाली इस जानकारी को bazel mod deps --lockfile_mode=refresh की मदद से अपडेट किया जा सकता है.

Bazel, लॉकफ़ाइल से मिले हैश का इस्तेमाल करके, डाउनलोड करने से पहले, रिपॉज़िटरी कैश में रजिस्ट्री फ़ाइलें ढूंढता है. इससे, बाद के रिज़ॉल्यूशन की प्रोसेस तेज़ हो जाती है.

हटाए गए चुने गए वर्शन

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

यह फ़ील्ड ज़रूरी है, क्योंकि मॉड्यूल फ़ाइलों के मुकाबले, हटाए गए वर्शन की जानकारी बदली जा सकती है. इसलिए, इसे हैश से रेफ़र नहीं किया जा सकता. इस जानकारी को bazel mod deps --lockfile_mode=refresh की मदद से अपडेट किया जा सकता है.

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

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

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

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

  1. bzlTransitiveDigest, एक्सटेंशन के लागू करने और उसके ज़रिए ट्रांज़िटिव तरीके से लोड की गई .bzl फ़ाइलों का डाइजेस्ट होता है.
  2. usagesDigest, डिपेंडेंसी ग्राफ़ में एक्सटेंशन के इस्तेमाल का डाइजेस्ट होता है. इसमें सभी टैग शामिल होते हैं.
  3. अन्य फ़ील्ड के बारे में जानकारी नहीं दी गई है. ये फ़ील्ड, एक्सटेंशन के अन्य इनपुट को ट्रैक करते हैं. जैसे, उन फ़ाइलों या डायरेक्ट्री का कॉन्टेंट जिन्हें वह पढ़ता है या उन एनवायरमेंट वैरिएबल का इस्तेमाल करता है.
  4. generatedRepoSpecs, मौजूदा इनपुट के साथ एक्सटेंशन से बनाई गई रिपॉज़िटरी को एनकोड करते हैं.
  5. ज़रूरी नहीं कि moduleExtensionMetadata फ़ील्ड में, एक्सटेंशन से दिया गया मेटाडेटा शामिल हो. जैसे, बनाई गई कुछ रिपॉज़िटरी को रूट मॉड्यूल से use_repo के ज़रिए इंपोर्ट किया जाना चाहिए या नहीं. इस जानकारी से, bazel mod tidy कमांड काम करता है.

मॉड्यूल एक्सटेंशन, लॉकफ़ाइल में शामिल न होने का विकल्प चुन सकते हैं. इसके लिए, reproducible = True के साथ, वापस आने वाले मेटाडेटा को सेट करें. ऐसा करने पर, वे वादा करते हैं कि एक जैसे इनपुट दिए जाने पर, वे हमेशा एक जैसी रिपॉज़िटरी बनाएंगे.

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

लॉकफ़ाइल की सुविधा के फ़ायदों को बढ़ाने के लिए, यहां दिए गए सबसे सही तरीकों को अपनाएं:

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

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

  • Bazel चलाने के लिए, bazelisk का इस्तेमाल करें. साथ ही, वर्शन कंट्रोल में a .bazelversion फ़ाइल शामिल करें. इसमें, लॉकफ़ाइल के हिसाब से Bazel का वर्शन तय किया जाता है. Bazel, आपके बिल्ड की डिपेंडेंसी है. इसलिए, लॉकफ़ाइल, Bazel के वर्शन के हिसाब से होती है. साथ ही, यह Bazel के उन रिलीज़ के बीच भी बदल जाएगी जो पुराने वर्शन के साथ काम करते हैं. bazelisk का इस्तेमाल करने से यह पक्का होता है कि सभी डेवलपर, Bazel के ऐसे वर्शन का इस्तेमाल कर रहे हैं जो लॉकफ़ाइल से मेल खाता हो.

इन सबसे सही तरीकों को अपनाकर, Bazel में लॉकफ़ाइल की सुविधा का असरदार तरीके से इस्तेमाल किया जा सकता है. इससे, सॉफ़्टवेयर डेवलपमेंट के वर्कफ़्लो ज़्यादा असरदार, भरोसेमंद, और साथ मिलकर काम करने वाले बन सकते हैं.