टास्क-आधारित बिल्ड सिस्टम

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

टास्क पर आधारित बिल्ड सिस्टम को समझना

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

इस उदाहरण को चींटी मैन्युअल:

<project name="MyProject" default="dist" basedir=".">
   <description>
     simple example build file
   </description>
   <!-- set global properties for this build -->
   <property name="src" location="src"/>
   <property name="build" location="build"/>
   <property name="dist" location="dist"/>

   <target name="init">
     <!-- Create the time stamp -->
     <tstamp/>
     <!-- Create the build directory structure used by compile -->
     <mkdir dir="${build}"/>
   </target>
   <target name="compile" depends="init"
       description="compile the source">
     <!-- Compile the Java code from ${src} into ${build} -->
     <javac srcdir="${src}" destdir="${build}"/>
   </target>
   <target name="dist" depends="compile"
       description="generate the distribution">
     <!-- Create the distribution directory -->
     <mkdir dir="${dist}/lib"/>
     <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
     <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
   </target>
   <target name="clean"
       description="clean up">
     <!-- Delete the ${build} and ${dist} directory trees -->
     <delete dir="${build}"/>
     <delete dir="${dist}"/>
   </target>
</project>

बिल्ड फ़ाइल को एक्सएमएल में लिखा गया है और यह बिल्ड के बारे में कुछ आसान मेटाडेटा के बारे में बताता है के साथ-साथ टास्क की सूची (एक्सएमएल में <target> टैग). (चींटी ने किसी टास्क को दिखाने के लिए target किया जाता है और यह निर्देश देने के लिए task शब्द का इस्तेमाल करता है कमांड.) हर टास्क, चींटी की ओर से तय किए गए निर्देशों की एक सूची चलाता है, इनमें डायरेक्ट्री बनाना और मिटाना, javac चलाना, और तो हम एक JAR फ़ाइल बनाते हैं. निर्देशों के इस सेट को उपयोगकर्ता के दिए गए निर्देशों की मदद से बढ़ाया जा सकता है किसी भी तरह के लॉजिक को कवर करने के लिए प्लग-इन का इस्तेमाल किया जा सकता है. हर टास्क, उसके लिए टास्क तय कर सकता है का इस्तेमाल डिपेंडेंसी एट्रिब्यूट की मदद से किया जाता है. ये डिपेंडेंसी एक असाइकलिक ग्राफ़ बनाती हैं, जैसा कि इमेज 1 में दिखाया गया है.

डिपेंडेंसी दिखाने वाला एक्रिलिक ग्राफ़

चित्र 1. डिपेंडेंसी दिखाने वाला एक साइक्लिक ग्राफ़

उपयोगकर्ता, Ant के कमांड-लाइन टूल को टास्क देकर, बिल्ड अंजाम देते हैं. उदाहरण के लिए, जब कोई उपयोगकर्ता ant dist टाइप करता है, तो Ant यह तरीका अपनाता है:

  1. मौजूदा डायरेक्ट्री में, build.xml नाम की फ़ाइल लोड करता है और इसे पार्स करता है: चित्र 1 में दिखाई गई ग्राफ़ संरचना बनाएं.
  2. कमांड लाइन पर दिया गया dist नाम का टास्क खोजता है और को पता चलता है कि यह compile नाम के टास्क पर निर्भर है.
  3. compile नाम वाला टास्क खोजता है और उसे पता चलता है कि यह इस पर निर्भर करता है init नाम का टास्क.
  4. init नाम वाला टास्क खोजता है और उसे पता चलता है कि उसमें कोई डिपेंडेंसी नहीं है.
  5. init टास्क में बताए गए निर्देशों को एक्ज़ीक्यूट करता है.
  6. compile टास्क में बताए गए निर्देशों को लागू करता है, बशर्ते वे सभी निर्देश दिए गए हों टास्क की डिपेंडेंसी लागू हो गई हैं.
  7. dist टास्क में बताए गए निर्देशों को लागू करता है, बशर्ते वे सभी निर्देश दिए गए हों टास्क की डिपेंडेंसी लागू हो गई हैं.

आखिर में, dist टास्क को चलाते समय Ant ने जो कोड लागू किया वह उसके बराबर होता है को नीचे दी गई शेल स्क्रिप्ट में अपडेट करें:

./createTimestamp.sh
mkdir build/
javac src/* -d build/
mkdir -p dist/lib/
jar cf dist/lib/MyProject-$(date --iso-8601).jar build/*

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

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

टास्क पर आधारित बिल्ड सिस्टम के बारे में गलत जानकारी

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

बिल्ड के चरणों को साथ-साथ चलाने में परेशानी

कई कोर वाले मॉडर्न डेवलपमेंट वर्कस्टेशन काफ़ी दमदार होते हैं साथ ही, बिल्ड के कई चरणों को एक साथ लागू करने की सुविधा मिलती है. हालांकि, टास्क पर आधारित सिस्टम अक्सर टास्क को साथ में करने में असमर्थ होते हैं, भले ही ऐसा लगता हो कि उन्हें ऐसा हो सकता है. मान लीजिए कि टास्क A, टास्क B और C पर निर्भर है. क्योंकि टास्क B और C एक-दूसरे पर निर्भर नहीं रहतीं, क्या उन्हें एक साथ चलाना सुरक्षित है सिस्टम कितनी जल्दी टास्क A पर जा सकता है? शायद, अगर उन्होंने किसी चीज़ को छुआ नहीं संसाधन भी हो सकते हैं. लेकिन शायद नहीं—शायद और ट्रैक करने के लिए दोनों एक ही फ़ाइल का इस्तेमाल करते हैं दोनों स्थितियों और उन्हें एक साथ चलाने से विवाद पैदा होता है. कोई नहीं जिससे सिस्टम को पता चल जाता है, तो या तो उसे इन विवादों का जोखिम उठाना पड़ता है (बिल बनाने में बहुत कम, लेकिन बहुत मुश्किल से डीबग करने में मुश्किल होती है) या फिर किसी एक प्रोसेस में पूरे बिल्ड को किसी एक थ्रेड पर चलने से रोकें. इससे एक बेहतरीन डेवलपर मशीन की बहुत बर्बादी हो सकती है और यह पूरी तरह से बिल्ड को एक से ज़्यादा मशीनों में डिस्ट्रिब्यूट करने की संभावना को रोकता है.

इंक्रीमेंटल बिल्ड करने में परेशानी

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

स्क्रिप्ट के रखरखाव और उन्हें डीबग करने में परेशानी

आखिर में, टास्क-आधारित बिल्ड सिस्टम से लगाई गई बिल्ड स्क्रिप्ट अक्सर सिर्फ़ काम करना मुश्किल हो. आम तौर पर, इन कामों की ज़्यादा जांच-पड़ताल नहीं की जाती है, लेकिन स्क्रिप्ट बनाएं सिस्टम की तरह ही कोड होते हैं. साथ ही, इन गड़बड़ियों को आसानी से छिपाया जा सकता है. यहां उन गड़बड़ियों के कुछ उदाहरण दिए गए हैं जो Google News पर टास्क पर आधारित बिल्ड सिस्टम:

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

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

इस तरीके से ब्लेज़ जैसे आर्टफ़ैक्ट-आधारित बिल्ड सिस्टम बनाने में मदद मिली और बेज़ल.