इस पेज पर, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम और उन्हें बनाने के पीछे की वजह बताई गई है. Bazel, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम है. टास्क पर आधारित बिल्ड सिस्टम, बिल्ड स्क्रिप्ट से बेहतर होते हैं. हालांकि, ये हर इंजीनियर को अपने टास्क तय करने की अनुमति देकर, उन्हें ज़्यादा पावर देते हैं.
आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम में, सिस्टम की ओर से तय किए गए कुछ ही टास्क होते हैं. इंजीनियर, इन्हें सीमित तरीके से कॉन्फ़िगर कर सकते हैं. इंजीनियर अब भी सिस्टम को बताते हैं कि क्या बनाना है. हालांकि, बिल्ड सिस्टम यह तय करता है कि उसे कैसे बनाना है. टास्क पर आधारित बिल्ड सिस्टम की तरह, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम (जैसे, Bazel) में भी बिल्डफ़ाइलें होती हैं. हालांकि, इन बिल्डफ़ाइलों का कॉन्टेंट अलग होता है. Bazel में बिल्डफ़ाइलें, ट्यूरिंग-कंप्लीट स्क्रिप्टिंग लैंग्वेज में ज़रूरी निर्देशों का सेट नहीं होती हैं. इनमें यह नहीं बताया जाता कि आउटपुट कैसे जनरेट करना है. इसके बजाय, ये एक एलान करने वाला मेनिफ़ेस्ट होती हैं. इसमें बिल्ड किए जाने वाले आर्टफ़ैक्ट का सेट, उनकी डिपेंडेंसी, और सीमित संख्या में ऐसे विकल्प शामिल होते हैं जिनसे यह तय होता है कि उन्हें कैसे बिल्ड किया जाए. कमांड लाइन पर bazel चलाने पर, इंजीनियर बिल्ड किए जाने वाले टारगेट का सेट तय करते हैं. इसे क्या कहा जाता है. वहीं, Bazel, कंपाइलेशन के चरणों को कॉन्फ़िगर करने, चलाने, और शेड्यूल करने की ज़िम्मेदारी लेता है. इसे कैसे कहा जाता है. अब बिल्ड सिस्टम के पास यह तय करने का पूरा कंट्रोल होता है कि कौनसे टूल कब चलाने हैं. इसलिए, यह ज़्यादा भरोसेमंद तरीके से काम कर सकता है. साथ ही, यह सही तरीके से काम करने की गारंटी भी देता है.
फ़ंक्शनल प्रोग्रामिंग के नज़रिए से
आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम और फ़ंक्शनल प्रोग्रामिंग के बीच समानताएं आसानी से देखी जा सकती हैं. पारंपरिक ज़रूरी प्रोग्रामिंग लैंग्वेज (जैसे, Java, C, और Python) में, एक के बाद एक स्टेटमेंट की सूची तय की जाती है. इसी तरह, टास्क पर आधारित बिल्ड सिस्टम में, प्रोग्रामर को चरणों की एक सीरीज़ तय करने की अनुमति मिलती है. इसके उलट, फ़ंक्शनल प्रोग्रामिंग लैंग्वेज (जैसे, Haskell और ML) को गणित के समीकरणों की सीरीज़ की तरह स्ट्रक्चर किया जाता है. फ़ंक्शनल लैंग्वेज में, प्रोग्रामर, कंपाइलर को यह बताता है कि कौनसी कंप्यूटेशन करनी है. हालांकि, वह यह तय नहीं करता कि कंप्यूटेशन कब और कैसे की जाएगी.
यह, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम में मेनिफ़ेस्ट का एलान करने और सिस्टम को यह तय करने की अनुमति देने से जुड़ा है कि बिल्ड कैसे करना है. फ़ंक्शनल प्रोग्रामिंग का इस्तेमाल करके, कई समस्याओं को आसानी से हल नहीं किया जा सकता. हालांकि, जिन समस्याओं को हल किया जा सकता है उनके लिए यह बहुत फ़ायदेमंद है. इस लैंग्वेज की मदद से, ऐसे प्रोग्राम को आसानी से पैरललाइज़ किया जा सकता है. साथ ही, यह उनके सही तरीके से काम करने की गारंटी भी देता है. ज़रूरी लैंग्वेज में ऐसा करना मुमकिन नहीं है. फ़ंक्शनल प्रोग्रामिंग का इस्तेमाल करके, उन समस्याओं को आसानी से हल किया जा सकता है जिनमें नियमों या फ़ंक्शन की सीरीज़ का इस्तेमाल करके, एक तरह के डेटा को दूसरी तरह के डेटा में बदलना होता है. बिल्ड सिस्टम भी ठीक ऐसा ही करता है. पूरा सिस्टम, असल में एक गणितीय फ़ंक्शन होता है. यह सोर्स फ़ाइलों (और कंपाइलर जैसे टूल) को इनपुट के तौर पर लेता है और बाइनरी को आउटपुट के तौर पर जनरेट करता है. इसलिए, बिल्ड सिस्टम को फ़ंक्शनल प्रोग्रामिंग के सिद्धांतों के आधार पर बनाना फ़ायदेमंद होता है.
आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम के बारे में जानकारी
Google का बिल्ड सिस्टम, Blaze, आर्टफ़ैक्ट पर आधारित पहला बिल्ड सिस्टम था. Bazel, Blaze का ओपन सोर्स वर्शन है.
Bazel में बिल्डफ़ाइल (आम तौर पर इसका नाम BUILD होता है) कुछ इस तरह दिखती है:
java_binary(
name = "MyBinary",
srcs = ["MyBinary.java"],
deps = [
":mylib",
],
)
java_library(
name = "mylib",
srcs = ["MyLibrary.java", "MyHelper.java"],
visibility = ["//java/com/example/myproduct:__subpackages__"],
deps = [
"//java/com/example/common",
"//java/com/example/myproduct/otherlib",
],
)
Bazel में, BUILD फ़ाइलें टारगेट तय करती हैं. यहां दो तरह के टारगेट दिए गए हैं: java_binary और java_library. हर टारगेट, एक आर्टफ़ैक्ट से जुड़ा होता है, जिसे सिस्टम बना सकता है. बाइनरी टारगेट, ऐसी बाइनरी जनरेट करते हैं जिन्हें सीधे तौर पर चलाया जा सकता है. वहीं, लाइब्रेरी टारगेट, ऐसी लाइब्रेरी जनरेट करते हैं जिनका इस्तेमाल बाइनरी या अन्य लाइब्रेरी कर सकती हैं. हर टारगेट में ये चीज़ें होती हैं:
name: कमांड लाइन और अन्य टारगेट पर, टारगेट को कैसे रेफ़र किया जाता हैsrcs: टारगेट के लिए आर्टफ़ैक्ट बनाने के लिए, कंपाइल की जाने वाली सोर्स फ़ाइलेंdeps: अन्य टारगेट जिन्हें इस टारगेट से पहले बिल्ड किया जाना चाहिए और इससे लिंक किया जाना चाहिए
डिपेंडेंसी, एक ही पैकेज में हो सकती हैं. जैसे, MyBinary की
डिपेंडेंसी :mylib पर है. इसके अलावा, ये एक ही सोर्स हाइरार्की में मौजूद किसी दूसरे पैकेज में भी हो सकती हैं.
जैसे, mylib की डिपेंडेंसी //java/com/example/common पर है.
टास्क पर आधारित बिल्ड सिस्टम की तरह, Bazel के कमांड-लाइन टूल का इस्तेमाल करके बिल्ड किए जाते हैं. MyBinary टारगेट को बिल्ड करने के लिए, bazel build :MyBinary चलाएं. साफ़ रिपॉज़िटरी में पहली बार यह कमांड डालने के बाद, Bazel:
- आर्टफ़ैक्ट के बीच डिपेंडेंसी का ग्राफ़ बनाने के लिए, वर्कस्पेस में मौजूद हर
BUILDफ़ाइल को पार्स करता है. - ग्राफ़ का इस्तेमाल करके,
MyBinaryकी ट्रांज़िटिव डिपेंडेंसी तय करता है. इसका मतलब है किMyBinaryजिस टारगेट पर निर्भर करता है और वे टारगेट जिस टारगेट पर निर्भर करते हैं, उन सभी को तय करता है. - इन सभी डिपेंडेंसी को क्रम से बिल्ड करता है. Bazel, उन सभी टारगेट को बिल्ड करके शुरू करता है जिनकी कोई अन्य डिपेंडेंसी नहीं होती. साथ ही, यह ट्रैक करता है कि हर टारगेट के लिए, किन डिपेंडेंसी को अब भी बिल्ड करना है. किसी टारगेट की सभी डिपेंडेंसी बिल्ड होने के बाद, Bazel उस टारगेट को बिल्ड करना शुरू करता है.
MyBinaryकी सभी ट्रांज़िटिव डिपेंडेंसी बिल्ड होने तक यह प्रोसेस जारी रहती है. MyBinaryको बिल्ड करके, एक फ़ाइनल एक्ज़ीक्यूटेबल बाइनरी जनरेट करता है. इसमें तीसरे चरण में बिल्ड की गई सभी डिपेंडेंसी लिंक होती हैं.
असल में, ऐसा लग सकता है कि यहां जो हो रहा है वह टास्क पर आधारित बिल्ड सिस्टम का इस्तेमाल करते समय होने वाली प्रोसेस से ज़्यादा अलग नहीं है. दरअसल, फ़ाइनल बाइनरी एक ही होती है. इसे जनरेट करने की प्रोसेस में, डिपेंडेंसी ढूंढने के लिए कई चरणों का विश्लेषण किया जाता है. इसके बाद, उन चरणों को क्रम से चलाया जाता है. हालांकि, इनमें अहम अंतर हैं. पहला अंतर तीसरे चरण में दिखता है. Bazel को पता है कि हर टारगेट सिर्फ़ एक Java लाइब्रेरी जनरेट करता है. इसलिए, उसे पता है कि उसे आर्बिट्ररी उपयोगकर्ता की ओर से तय की गई स्क्रिप्ट के बजाय, सिर्फ़ Java कंपाइलर चलाना है. इसलिए, उसे पता है कि इन चरणों को एक साथ चलाना सुरक्षित है. मल्टीकोर मशीन पर, टारगेट को एक-एक करके बिल्ड करने के मुकाबले, इससे परफ़ॉर्मेंस में काफ़ी सुधार हो सकता है. ऐसा सिर्फ़ इसलिए मुमकिन है, क्योंकि आर्टफ़ैक्ट पर आधारित अप्रोच में, बिल्ड सिस्टम अपनी एक्ज़ीक्यूशन रणनीति तय करता है. इससे, पैरललिज़्म के बारे में ज़्यादा भरोसेमंद तरीके से काम किया जा सकता है.
हालांकि, इसके फ़ायदे सिर्फ़ पैरललिज़्म तक ही सीमित नहीं हैं. इस अप्रोच का अगला फ़ायदा तब दिखता है, जब डेवलपर बिना कोई बदलाव किए, दूसरी बार bazel
build :MyBinary टाइप करता है. Bazel, एक सेकंड से भी कम समय में बंद हो जाता है और यह मैसेज दिखाता है कि टारगेट अप-टू-डेट है. ऐसा, फ़ंक्शनल प्रोग्रामिंग के उस पैराडाइम की वजह से मुमकिन है जिसके बारे में हमने पहले बात की थी. Bazel को पता है कि हर टारगेट, सिर्फ़ Java कंपाइलर चलाने का नतीजा है. साथ ही, उसे पता है कि Java कंपाइलर का आउटपुट सिर्फ़ उसके इनपुट पर निर्भर करता है. इसलिए, जब तक इनपुट में कोई बदलाव नहीं होता, तब तक आउटपुट को दोबारा इस्तेमाल किया जा सकता है.
यह विश्लेषण हर लेवल पर काम करता है. अगर MyBinary.java में बदलाव होता है, तो Bazel को पता होता है
कि MyBinary को दोबारा बिल्ड करना है, लेकिन mylib को दोबारा इस्तेमाल किया जा सकता है. अगर //java/com/example/common के लिए किसी सोर्स फ़ाइल में बदलाव होता है, तो Bazel को पता होता है कि उस लाइब्रेरी, mylib, और MyBinary को दोबारा बिल्ड करना है. हालांकि, //java/com/example/myproduct/otherlib को दोबारा इस्तेमाल किया जा सकता है.
Bazel को हर चरण में, इस्तेमाल किए जाने वाले टूल की प्रॉपर्टी के बारे में पता होता है. इसलिए, यह हर बार सिर्फ़ आर्टफ़ैक्ट के ज़रूरी सेट को दोबारा बिल्ड कर पाता है. साथ ही, यह गारंटी देता है कि यह पुराने बिल्ड जनरेट नहीं करेगा.
बिल्ड प्रोसेस को टास्क के बजाय आर्टफ़ैक्ट के हिसाब से फ़्रेम करना, थोड़ा मुश्किल है, लेकिन यह बहुत काम का है. प्रोग्रामर के लिए उपलब्ध फ़्लेक्सिबिलिटी को कम करके, बिल्ड सिस्टम को यह पता चल सकता है कि बिल्ड के हर चरण में क्या किया जा रहा है. यह इस जानकारी का इस्तेमाल करके, बिल्ड प्रोसेस को पैरललाइज़ करके और उनके आउटपुट को दोबारा इस्तेमाल करके, बिल्ड को ज़्यादा असरदार बना सकता है. हालांकि, यह सिर्फ़ पहला चरण है. पैरललिज़्म और दोबारा इस्तेमाल करने की इन सुविधाओं से, डिस्ट्रिब्यूटेड और ज़्यादा स्केलेबल बिल्ड सिस्टम बनाया जा सकता है.
Bazel की अन्य शानदार सुविधाएं
आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम, टास्क पर आधारित बिल्ड सिस्टम में मौजूद पैरललिज़्म और दोबारा इस्तेमाल करने से जुड़ी समस्याओं को हल करते हैं. हालांकि, कुछ समस्याएं अब भी बनी हुई हैं जिनके बारे में हमने पहले बात की थी. Bazel के पास इनमें से हर समस्या को हल करने के लिए, शानदार तरीके हैं. आगे बढ़ने से पहले, हमें इनके बारे में बात करनी चाहिए.
टूल को डिपेंडेंसी के तौर पर इस्तेमाल करना
हमें पहले एक समस्या आई थी कि बिल्ड, हमारे मशीन पर इंस्टॉल किए गए टूल पर निर्भर करते थे. साथ ही, अलग-अलग टूल वर्शन या लोकेशन की वजह से, सिस्टम में बिल्ड को दोबारा जनरेट करना मुश्किल हो सकता है. यह समस्या तब और भी मुश्किल हो जाती है, जब आपके प्रोजेक्ट में ऐसी लैंग्वेज का इस्तेमाल किया जाता है जिनके लिए अलग-अलग टूल की ज़रूरत होती है. यह इस बात पर निर्भर करता है कि उन्हें किस प्लैटफ़ॉर्म पर बिल्ड या कंपाइल किया जा रहा है. जैसे, Windows बनाम Linux. साथ ही, इन प्लैटफ़ॉर्म में से हर एक को एक ही काम करने के लिए, अलग-अलग टूल की ज़रूरत होती है.
Bazel, इस समस्या के पहले हिस्से को हल करने के लिए, टूल को हर टारगेट की डिपेंडेंसी के तौर पर इस्तेमाल करता है. वर्कस्पेस में मौजूद हर java_library, Java कंपाइलर पर निर्भर करती है. यह डिफ़ॉल्ट रूप से, जाने-माने कंपाइलर पर सेट होती है. जब भी Bazel, java_library को बिल्ड करता है, तो वह यह पक्का करता है कि तय किया गया कंपाइलर, किसी जानी-पहचानी लोकेशन पर उपलब्ध हो. किसी अन्य डिपेंडेंसी की तरह, अगर Java कंपाइलर में बदलाव होता है, तो उस पर निर्भर करने वाले हर आर्टफ़ैक्ट को दोबारा बिल्ड किया जाता है.
Bazel, बिल्ड कॉन्फ़िगरेशन सेट करके, प्लैटफ़ॉर्म इंडिपेंडेंस की समस्या के दूसरे हिस्से को हल करता है. टारगेट, सीधे तौर पर अपने टूल पर निर्भर करने के बजाय, कॉन्फ़िगरेशन के टाइप पर निर्भर करते हैं:
- होस्ट कॉन्फ़िगरेशन: बिल्ड के दौरान चलने वाले टूल को बिल्ड करना
- टारगेट कॉन्फ़िगरेशन: वह बाइनरी बिल्ड करना जिसका आपने अनुरोध किया था
बिल्ड सिस्टम को बढ़ाना
Bazel में, कई लोकप्रिय प्रोग्रामिंग लैंग्वेज के लिए टारगेट पहले से मौजूद होते हैं. हालांकि, इंजीनियर हमेशा ज़्यादा काम करना चाहेंगे. टास्क पर आधारित सिस्टम का एक फ़ायदा यह है कि इनमें किसी भी तरह की बिल्ड प्रोसेस को सपोर्ट करने की फ़्लेक्सिबिलिटी होती है. आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम में, इस फ़्लेक्सिबिलिटी को बनाए रखना बेहतर होगा. Bazel, कस्टम नियम जोड़कर, अपने सपोर्ट किए गए टारगेट टाइप को बढ़ाने की अनुमति देता है .
Bazel में कोई नियम तय करने के लिए, नियम का लेखक, उन इनपुट का एलान करता है जिनकी ज़रूरत नियम को होती है. ये इनपुट, BUILD फ़ाइल में पास किए गए एट्रिब्यूट के तौर पर होते हैं. साथ ही, वह उन आउटपुट के तय सेट का एलान करता है जो नियम जनरेट करता है. लेखक, उन कार्रवाइयों को भी तय करता है जो उस नियम से जनरेट होंगी. हर कार्रवाई, अपने इनपुट और आउटपुट का एलान करती है. साथ ही, कोई खास एक्ज़ीक्यूटेबल चलाती है या किसी फ़ाइल में कोई खास स्ट्रिंग लिखती है. इसे इसके इनपुट और आउटपुट के ज़रिए, अन्य कार्रवाइयों से जोड़ा जा सकता है. इसका मतलब है कि कार्रवाइयां, बिल्ड सिस्टम में कंपोज़ की जा सकने वाली सबसे निचले लेवल की यूनिट होती हैं. कोई कार्रवाई, अपनी तय की गई इनपुट और आउटपुट का इस्तेमाल करके, कुछ भी कर सकती है. Bazel, कार्रवाइयों को शेड्यूल करने और उनके नतीजों को कैश मेमोरी में सेव करने का काम करता है.
सिस्टम पूरी तरह से सुरक्षित नहीं है. ऐसा इसलिए, क्योंकि कार्रवाई के डेवलपर को अपनी कार्रवाई के हिस्से के तौर पर, गैर-डिटरमिनिस्टिक प्रोसेस शुरू करने से रोकने का कोई तरीका नहीं है. हालांकि, असल में ऐसा बहुत कम होता है. साथ ही, कार्रवाई के लेवल तक गलत इस्तेमाल की संभावनाओं को कम करने से, गड़बड़ियों की संभावना काफ़ी कम हो जाती है. कई सामान्य लैंग्वेज और टूल को सपोर्ट करने वाले नियम, ऑनलाइन आसानी से उपलब्ध हैं. ज़्यादातर प्रोजेक्ट के लिए, अपने नियम तय करने की ज़रूरत नहीं होगी. जिन प्रोजेक्ट के लिए नियम तय करने की ज़रूरत होगी, उनके लिए नियम की परिभाषाएं सिर्फ़ रिपॉज़िटरी में एक जगह तय करनी होंगी. इसका मतलब है कि ज़्यादातर इंजीनियर, उन नियमों का इस्तेमाल कर पाएंगे. उन्हें यह चिंता करने की ज़रूरत नहीं होगी कि उन्हें कैसे लागू किया गया है.
एनवायरमेंट को अलग करना
ऐसा लग सकता है कि कार्रवाइयों को भी अन्य सिस्टम में मौजूद टास्क की तरह ही समस्याएं आ सकती हैं. क्या ऐसी कार्रवाइयां लिखना अब भी मुमकिन नहीं है जो एक ही फ़ाइल में लिखती हैं और एक-दूसरे से टकराती हैं? असल में, Bazel, इन टकरावों को सैंडबॉक्सिंग का इस्तेमाल करके, रोक सकता है. सपोर्ट किए गए सिस्टम पर, हर कार्रवाई को फ़ाइल सिस्टम सैंडबॉक्स के ज़रिए, अन्य कार्रवाइयों से अलग किया जाता है. असल में, हर कार्रवाई, फ़ाइल सिस्टम का सिर्फ़ एक सीमित व्यू देख सकती है. इसमें वे इनपुट शामिल होते हैं जिनका एलान किया गया है और वे आउटपुट शामिल होते हैं जो जनरेट किए गए हैं. इसे Linux पर LXC जैसे सिस्टम लागू करते हैं. यह वही टेक्नोलॉजी है जिसका इस्तेमाल Docker में किया जाता है. इसका मतलब है कि कार्रवाइयों के बीच टकराव नहीं हो सकता, क्योंकि वे उन फ़ाइलों को नहीं पढ़ सकतीं जिनका एलान नहीं किया गया है. साथ ही, जिन फ़ाइलों को वे लिखती हैं, लेकिन उनका एलान नहीं करतीं वे कार्रवाई पूरी होने पर हटा दी जाती हैं. Bazel, नेटवर्क के ज़रिए कार्रवाइयों को कम्यूनिकेट करने से रोकने के लिए भी सैंडबॉक्स का इस्तेमाल करता है.
बाहरी डिपेंडेंसी को डिटरमिनिस्टिक बनाना
अब भी एक समस्या बाकी है. बिल्ड सिस्टम को अक्सर डिपेंडेंसी (चाहे वे टूल हों या लाइब्रेरी) को सीधे तौर पर बिल्ड करने के बजाय, बाहरी सोर्स से डाउनलोड करना पड़ता है. इसे उदाहरण में @com_google_common_guava_guava//jar डिपेंडेंसी के ज़रिए देखा जा सकता है. यह Maven से JAR फ़ाइल डाउनलोड करती है.
मौजूदा वर्कस्पेस के बाहर मौजूद फ़ाइलों पर निर्भर करना जोखिम भरा हो सकता है. इन फ़ाइलों में कभी भी बदलाव हो सकता है. इसलिए, बिल्ड सिस्टम को लगातार यह जांच करनी पड़ सकती है कि वे अप-टू-डेट हैं या नहीं. अगर वर्कस्पेस सोर्स कोड में बदलाव किए बिना, रिमोट फ़ाइल में बदलाव होता है, तो इससे ऐसे बिल्ड जनरेट हो सकते हैं जिन्हें दोबारा जनरेट नहीं किया जा सकता. ऐसा हो सकता है कि कोई बिल्ड एक दिन काम करे और अगले दिन किसी ऐसी डिपेंडेंसी में बदलाव की वजह से काम न करे जिस पर ध्यान नहीं दिया गया. आखिर में, बाहरी डिपेंडेंसी से सुरक्षा का बड़ा जोखिम हो सकता है, जब उसका मालिकाना हक किसी तीसरे पक्ष के पास हो. अगर कोई हमलावर, तीसरे पक्ष के सर्वर में घुसपैठ कर पाता है, तो वह डिपेंडेंसी फ़ाइल को अपने डिज़ाइन की किसी चीज़ से बदल सकता है. इससे, आपके बिल्ड एनवायरमेंट और उसके आउटपुट पर उसका पूरा कंट्रोल हो सकता है.
असल समस्या यह है कि हम चाहते हैं कि बिल्ड सिस्टम को इन फ़ाइलों के बारे में पता हो. इसके लिए, उन्हें सोर्स कंट्रोल में चेक इन करने की ज़रूरत न हो. डिपेंडेंसी को अपडेट करना एक सोच-समझकर लिया गया फ़ैसला होना चाहिए. हालांकि, यह फ़ैसला किसी एक जगह पर लिया जाना चाहिए. इसे अलग-अलग इंजीनियर या सिस्टम अपने-आप मैनेज नहीं करना चाहिए. ऐसा इसलिए, क्योंकि “लाइव ऐट हेड” मॉडल के साथ भी, हम चाहते हैं कि बिल्ड डिटरमिनिस्टिक हों. इसका मतलब है कि अगर आपने पिछले हफ़्ते का कोई कमिट चेक आउट किया है, तो आपको अपनी डिपेंडेंसी वैसे ही दिखनी चाहिए जैसी वे तब थीं, न कि जैसी वे अब हैं.
Bazel और कुछ अन्य बिल्ड सिस्टम, इस समस्या को हल करने के लिए, वर्कस्पेस के लिए मेनिफ़ेस्ट फ़ाइल की ज़रूरत होती है. इसमें वर्कस्पेस में मौजूद हर बाहरी डिपेंडेंसी के लिए क्रिप्टोग्राफ़िक हैश की सूची होती है. हैश, पूरी फ़ाइल को सोर्स कंट्रोल में चेक इन किए बिना, उसे यूनीक तरीके से दिखाने का एक तरीका है. जब भी किसी वर्कस्पेस से किसी नई बाहरी डिपेंडेंसी को रेफ़र किया जाता है, तो उस डिपेंडेंसी का हैश, मेनिफ़ेस्ट में मैन्युअल तरीके से या अपने-आप जुड़ जाता है. Bazel, बिल्ड चलाने पर, कैश मेमोरी में सेव की गई डिपेंडेंसी के असल हैश की तुलना, मेनिफ़ेस्ट में तय किए गए हैश से करता है. साथ ही, हैश में अंतर होने पर ही फ़ाइल को दोबारा डाउनलोड करता है.
अगर डाउनलोड किए गए आर्टफ़ैक्ट का हैश, मेनिफ़ेस्ट में तय किए गए हैश से अलग है, तो बिल्ड तब तक काम नहीं करेगा, जब तक मेनिफ़ेस्ट में हैश अपडेट नहीं किया जाता. यह अपने-आप किया जा सकता है. हालांकि, बिल्ड के नई डिपेंडेंसी को स्वीकार करने से पहले, उस बदलाव को मंज़ूरी मिलनी चाहिए और उसे सोर्स कंट्रोल में चेक इन किया जाना चाहिए. इसका मतलब है कि डिपेंडेंसी को कब अपडेट किया गया, इसकी जानकारी हमेशा मौजूद रहती है. साथ ही, वर्कस्पेस सोर्स में बदलाव किए बिना, बाहरी डिपेंडेंसी में बदलाव नहीं किया जा सकता. इसका मतलब यह भी है कि सोर्स कोड का पुराना वर्शन चेक आउट करने पर, बिल्ड में वही डिपेंडेंसी इस्तेमाल होंगी जो उस वर्शन को चेक इन करते समय इस्तेमाल हो रही थीं. अगर वे डिपेंडेंसी अब उपलब्ध नहीं हैं, तो बिल्ड काम नहीं करेगा.
ज़ाहिर है, अगर कोई रिमोट सर्वर उपलब्ध नहीं होता है या खराब डेटा दिखाता है, तो यह अब भी एक समस्या हो सकती है. अगर आपके पास उस डिपेंडेंसी की कोई दूसरी कॉपी उपलब्ध नहीं है, तो आपके सभी बिल्ड काम करना बंद कर सकते हैं. इस समस्या से बचने के लिए, हमारा सुझाव है कि किसी भी अहम प्रोजेक्ट के लिए, उसकी सभी डिपेंडेंसी को उन सर्वर या सेवाओं पर मिरर करें जिन पर आपको भरोसा है और जिनका कंट्रोल आपके पास है. ऐसा न करने पर, आपको अपने बिल्ड सिस्टम की उपलब्धता के लिए हमेशा किसी तीसरे पक्ष पर निर्भर रहना होगा. भले ही, चेक-इन किए गए हैश, उसकी सुरक्षा की गारंटी देते हों.