आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम

इस पेज पर, आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम और उन्हें बनाने के पीछे की वजह बताई गई है. 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:

  1. आर्टफ़ैक्ट के बीच डिपेंडेंसी का ग्राफ़ बनाने के लिए, वर्कस्पेस में मौजूद हर BUILD फ़ाइल को पार्स करता है.
  2. ग्राफ़ का इस्तेमाल करके, MyBinary की ट्रांज़िटिव डिपेंडेंसी तय करता है. इसका मतलब है कि हर वह टारगेट जिस पर MyBinary निर्भर करता है और हर वह टारगेट जिस पर वे टारगेट निर्भर करते हैं.
  3. इनमें से हर डिपेंडेंसी को क्रम से बिल्ड करता है. Bazel, उन टारगेट को बिल्ड करके शुरू करता है जिनकी कोई अन्य डिपेंडेंसी नहीं होती. साथ ही, यह ट्रैक करता है कि हर टारगेट के लिए, किन डिपेंडेंसी को अब भी बिल्ड करना है. किसी टारगेट की सभी डिपेंडेंसी बिल्ड होने के बाद, Bazel उस टारगेट को बिल्ड करना शुरू कर देता है. MyBinary की सभी ट्रांज़िटिव डिपेंडेंसी बिल्ड होने तक यह प्रोसेस जारी रहती है.
  4. 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, बिल्ड चलाने पर, कैश की गई डिपेंडेंसी के असल हैश की तुलना, मेनिफ़ेस्ट में तय किए गए हैश से करता है. साथ ही, हैश में अंतर होने पर ही फ़ाइल को दोबारा डाउनलोड करता है.

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

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