Bazel में लॉकफ़ाइल की सुविधा की मदद से, किसी प्रोजेक्ट के लिए ज़रूरी सॉफ़्टवेयर लाइब्रेरी या पैकेज के खास वर्शन या डिपेंडेंसी रिकॉर्ड की जा सकती हैं. यह सुविधा, मॉड्यूल रिज़ॉल्यूशन और एक्सटेंशन के आकलन के नतीजों को सेव करके, ऐसा करती है. लॉकफ़ाइल की मदद से, एक जैसे बिल्ड तैयार किए जा सकते हैं. इससे, डेवलपमेंट के एनवायरमेंट में एकरूपता बनी रहती है. इसके अलावा, लॉकफ़ाइल की मदद से, बिल्ड की क्षमता बढ़ती है. ऐसा इसलिए, क्योंकि Bazel, रिज़ॉल्यूशन की प्रोसेस के उन हिस्सों को छोड़ सकता है जिन पर प्रोजेक्ट की डिपेंडेंसी में हुए बदलावों का असर नहीं पड़ता. साथ ही, लॉकफ़ाइल की मदद से, स्थिरता बेहतर होती है. ऐसा इसलिए, क्योंकि यह बाहरी लाइब्रेरी में अचानक होने वाले अपडेट या बड़े बदलावों को रोकती है. इससे, गड़बड़ियां होने का खतरा कम हो जाता है.
लॉकफ़ाइल जनरेट करना
लॉकफ़ाइल, वर्कस्पेस के रूट में MODULE.bazel.lock नाम से जनरेट होती है. यह बिल्ड की प्रोसेस के दौरान बनाई या अपडेट की जाती है. खास तौर पर, मॉड्यूल रिज़ॉल्यूशन और एक्सटेंशन के आकलन के बाद. अहम बात यह है कि इसमें सिर्फ़ वे डिपेंडेंसी शामिल होती हैं जो बिल्ड के मौजूदा इनवोकेशन में शामिल हैं.
जब प्रोजेक्ट में ऐसे बदलाव होते हैं जिनसे उसकी डिपेंडेंसी पर असर पड़ता है, तो लॉकफ़ाइल अपने-आप अपडेट हो जाती है, ताकि नई स्थिति दिख सके. इससे यह पक्का होता है कि लॉकफ़ाइल, मौजूदा बिल्ड के लिए ज़रूरी डिपेंडेंसी के खास सेट पर फ़ोकस रहे. साथ ही, प्रोजेक्ट की हल की गई डिपेंडेंसी की सटीक जानकारी मिलती रहे.
लॉकफ़ाइल का इस्तेमाल करना
लॉकफ़ाइल को फ़्लैग
--lockfile_mode से
कंट्रोल किया जा सकता है. इससे, प्रोजेक्ट की स्थिति, लॉकफ़ाइल से अलग होने पर, Bazel के व्यवहार को
पसंद के मुताबिक बनाया जा सकता है. उपलब्ध मोड ये हैं:
update(डिफ़ॉल्ट): लॉकफ़ाइल में मौजूद जानकारी का इस्तेमाल करके, जाने-पहचाने रजिस्ट्री फ़ाइलों के डाउनलोड को छोड़ें. साथ ही, उन एक्सटेंशन का फिर से आकलन न करें जिनके नतीजे अब भी अप-टू-डेट हैं. अगर कोई जानकारी मौजूद नहीं है, तो उसे लॉकफ़ाइल में जोड़ दिया जाएगा. इस मोड में, Bazel, उन डिपेंडेंसी के लिए, बदली जा सकने वाली जानकारी को रीफ़्रेश नहीं करता जिनमें कोई बदलाव नहीं हुआ है. जैसे, हटाए गए वर्शन.refresh: यह मोड,updateमोड की तरह ही काम करता है. हालांकि, इस मोड पर स्विच करने पर, बदली जा सकने वाली जानकारी हमेशा रीफ़्रेश होती है. साथ ही, इस मोड में हर घंटे में एक बार रीफ़्रेश होती है.error: यह मोड,updateमोड की तरह ही काम करता है. हालांकि, अगर कोई जानकारी मौजूद नहीं है या पुरानी हो गई है, तो Bazel, गड़बड़ी के साथ फ़ेल हो जाएगा. यह मोड, रिज़ॉल्यूशन के दौरान, लॉकफ़ाइल में कभी भी बदलाव नहीं करता या नेटवर्क के अनुरोध नहीं करता. मॉड्यूल एक्सटेंशन, जिन्हेंreproducibleके तौर पर मार्क किया गया है वे अब भी नेटवर्क के अनुरोध कर सकते हैं. हालांकि, उनसे हमेशा एक जैसा नतीजा मिलने की उम्मीद की जाती है.off: इस मोड में, लॉकफ़ाइल की जांच नहीं की जाती और न ही उसे अपडेट किया जाता है.
लॉकफ़ाइल के फ़ायदे
लॉकफ़ाइल के कई फ़ायदे हैं और इसका इस्तेमाल कई तरीकों से किया जा सकता है:
एक जैसे बिल्ड तैयार करना. सॉफ़्टवेयर लाइब्रेरी के खास वर्शन या डिपेंडेंसी को कैप्चर करके, लॉकफ़ाइल यह पक्का करती है कि अलग-अलग एनवायरमेंट में और समय के साथ, एक जैसे बिल्ड तैयार किए जा सकें. डेवलपर, अपने प्रोजेक्ट को बनाते समय, एक जैसे और अनुमान के मुताबिक नतीजे पा सकते हैं.
इंक्रीमेंटल रिज़ॉल्यूशन तेज़ी से करना. लॉकफ़ाइल की मदद से, Bazel, उन रजिस्ट्री फ़ाइलों को डाउनलोड नहीं करता जिनका इस्तेमाल पहले किसी बिल्ड में किया जा चुका है. इससे, बिल्ड की क्षमता काफ़ी बेहतर होती है. खास तौर पर, उन स्थितियों में जहां रिज़ॉल्यूशन में ज़्यादा समय लग सकता है.
स्थिरता बनाए रखना और जोखिम कम करना. लॉकफ़ाइल की मदद से, स्थिरता बनाए रखने में मदद मिलती है. ऐसा इसलिए, क्योंकि यह बाहरी लाइब्रेरी में अचानक होने वाले अपडेट या बड़े बदलावों को रोकती है. डिपेंडेंसी को खास वर्शन पर लॉक करके, असंगत या बिना जांच किए गए अपडेट की वजह से गड़बड़ियां होने का खतरा कम हो जाता है.
लॉकफ़ाइल का कॉन्टेंट
लॉकफ़ाइल में, यह तय करने के लिए सभी ज़रूरी जानकारी होती है कि प्रोजेक्ट की स्थिति में बदलाव हुआ है या नहीं. इसमें, मौजूदा स्थिति में प्रोजेक्ट बनाने का नतीजा भी शामिल होता है. लॉकफ़ाइल के दो मुख्य हिस्से होते हैं:
- मॉड्यूल रिज़ॉल्यूशन के लिए इनपुट के तौर पर इस्तेमाल की जाने वाली सभी रिमोट फ़ाइलों के हैश.
- हर मॉड्यूल एक्सटेंशन के लिए, लॉकफ़ाइल में वे इनपुट शामिल होते हैं जिनसे उस पर असर पड़ता है,
इन्हें
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 मैप से हटा दिया जाता है.
अगर कोई एक्सटेंशन, ऑपरेटिंग सिस्टम या आर्किटेक्चर टाइप से अलग है, तो इस सेक्शन में सिर्फ़ एक "सामान्य" एंट्री दिखती है. इसके अलावा, इसमें कई एंट्री शामिल होती हैं. इनके नाम, ओएस, आर्किटेक्चर या दोनों के हिसाब से रखे जाते हैं. हर एंट्री, उन खास चीज़ों पर एक्सटेंशन का आकलन करने के नतीजे से जुड़ी होती है.
एक्सटेंशन मैप में मौजूद हर एंट्री, इस्तेमाल किए गए एक्सटेंशन से जुड़ी होती है. इसकी पहचान, इसमें शामिल फ़ाइल और नाम से होती है. हर एंट्री की वैल्यू में, उस एक्सटेंशन से जुड़ी काम की जानकारी शामिल होती है:
bzlTransitiveDigest, एक्सटेंशन के लागू करने और उसके ज़रिए ट्रांज़िटिव तरीके से लोड की गई .bzl फ़ाइलों का डाइजेस्ट होता है.usagesDigest, डिपेंडेंसी ग्राफ़ में एक्सटेंशन के इस्तेमाल का डाइजेस्ट होता है. इसमें सभी टैग शामिल होते हैं.- अन्य फ़ील्ड, जिनके बारे में जानकारी नहीं दी गई है. ये फ़ील्ड, एक्सटेंशन के अन्य इनपुट को ट्रैक करते हैं. जैसे, उन फ़ाइलों या डायरेक्ट्री का कॉन्टेंट जिन्हें वह पढ़ता है या उन एनवायरमेंट वैरिएबल का इस्तेमाल करता है.
generatedRepoSpecs, मौजूदा इनपुट के साथ एक्सटेंशन से बनाई गई रिपॉज़िटरी को एनकोड करता है.- ज़रूरी नहीं कि
moduleExtensionMetadataफ़ील्ड में, एक्सटेंशन से दिया गया मेटाडेटा शामिल हो. जैसे, एक्सटेंशन से बनाई गई कुछ रिपॉज़िटरी को रूट मॉड्यूल सेuse_repoके ज़रिए इंपोर्ट किया जाना चाहिए या नहीं. इस जानकारी से,bazel mod tidyकमांड काम करती है.
मॉड्यूल एक्सटेंशन, लॉकफ़ाइल में शामिल न होने का विकल्प चुन सकते हैं. इसके लिए, reproducible = True के साथ, वापस आने वाले मेटाडेटा को सेट करें. ऐसा करके, वे वादा करते हैं कि एक जैसे इनपुट दिए जाने पर, वे हमेशा एक जैसी रिपॉज़िटरी बनाएंगे.
सबसे सही तरीके
लॉकफ़ाइल की सुविधा के फ़ायदों को ज़्यादा से ज़्यादा पाने के लिए, यहां दिए गए सबसे सही तरीकों को अपनाएं:
प्रोजेक्ट की डिपेंडेंसी या कॉन्फ़िगरेशन में हुए बदलावों को दिखाने के लिए, लॉकफ़ाइल को समय-समय पर अपडेट करें. इससे यह पक्का होता है कि बाद के बिल्ड, डिपेंडेंसी के सबसे अप-टू-डेट और सटीक सेट पर आधारित हों. सभी एक्सटेंशन को एक साथ लॉक करने के लिए,
bazel mod deps --lockfile_mode=updateचलाएं.वर्शन कंट्रोल में लॉकफ़ाइल शामिल करें, ताकि साथ मिलकर काम किया जा सके. साथ ही, यह पक्का करें कि टीम के सभी सदस्यों के पास एक ही लॉकफ़ाइल का ऐक्सेस हो. इससे, प्रोजेक्ट में डेवलपमेंट के एनवायरमेंट में एकरूपता बनी रहती है.
Bazel को चलाने के लिए,
bazeliskका इस्तेमाल करें. साथ ही, वर्शन कंट्रोल में.bazelversionफ़ाइल शामिल करें. इसमें, लॉकफ़ाइल के वर्शन के हिसाब से Bazel का वर्शन तय किया जाता है. Bazel, आपके बिल्ड की डिपेंडेंसी है. इसलिए, लॉकफ़ाइल, Bazel के वर्शन के हिसाब से होती है. साथ ही, यह Bazel के उन रिलीज़ के बीच भी बदल जाएगी जो एक-दूसरे के साथ काम करते हैं.bazeliskका इस्तेमाल करने से यह पक्का होता है कि सभी डेवलपर, Bazel के ऐसे वर्शन का इस्तेमाल कर रहे हैं जो लॉकफ़ाइल से मेल खाता हो.
इन सबसे सही तरीकों को अपनाकर, Bazel में लॉकफ़ाइल की सुविधा का असरदार तरीके से इस्तेमाल किया जा सकता है. इससे, सॉफ़्टवेयर डेवलपमेंट के वर्कफ़्लो ज़्यादा असरदार, भरोसेमंद, और साथ मिलकर काम करने वाले बन सकते हैं.
मर्ज करने से जुड़ी समस्याएं
लॉकफ़ाइल का फ़ॉर्मैट, मर्ज करने से जुड़ी समस्याओं को कम करने के लिए डिज़ाइन किया गया है. हालांकि, ये समस्याएं अब भी हो सकती हैं.
अपने-आप हल होना
Bazel, git के लिए कस्टम मर्ज ड्राइवर उपलब्ध कराता है. इससे, इन समस्याओं को अपने-आप हल करने में मदद मिलती है.
ड्राइवर सेट अप करने के लिए, अपने git रिपॉज़िटरी के रूट में मौजूद .gitattributes फ़ाइल में यह लाइन जोड़ें:
# A custom merge driver for the Bazel lockfile.
# https://bazel.build/external/lockfile#automatic-resolution
MODULE.bazel.lock merge=bazel-lockfile-merge
इसके बाद, ड्राइवर का इस्तेमाल करने वाले हर डेवलपर को इसे एक बार रजिस्टर करना होगा. इसके लिए, यह तरीका अपनाएं:
- jq (1.5 या उससे नया वर्शन) इंस्टॉल करें.
- ये कमांड चलाएं:
jq_script=$(curl https://raw.githubusercontent.com/bazelbuild/bazel/master/scripts/bazel-lockfile-merge.jq)
printf '%s\n' "${jq_script}" | less # to optionally inspect the jq script
git config --global merge.bazel-lockfile-merge.name "Merge driver for the Bazel lockfile (MODULE.bazel.lock)"
git config --global merge.bazel-lockfile-merge.driver "jq -s '${jq_script}' -- %O %A %B > %A.jq_tmp && mv %A.jq_tmp %A"
मैन्युअल तरीके से हल करना
registryFileHashes और selectedYankedVersions फ़ील्ड में, मर्ज करने से जुड़ी सामान्य समस्याओं को सुरक्षित तरीके से हल किया जा सकता है. इसके लिए, समस्या के दोनों हिस्सों की सभी एंट्री को सेव रखें.
मर्ज करने से जुड़ी अन्य समस्याओं को मैन्युअल तरीके से हल नहीं किया जाना चाहिए. इसके बजाय:
- लॉकफ़ाइल की पिछली स्थिति को वापस लाएं
git reset MODULE.bazel.lock && git checkout MODULE.bazel.lockकी मदद से. MODULE.bazelफ़ाइल में मौजूद किसी भी समस्या को हल करें.- लॉकफ़ाइल को अपडेट करने के लिए,
bazel mod depsचलाएं.