BUILD फ़ाइल फ़ॉर्मैट करने का तरीका, Go के तरीके जैसा ही है. इसमें एक स्टैंडर्ड टूल, फ़ॉर्मैट से जुड़ी ज़्यादातर समस्याओं को ठीक करता है.
Buildifier एक ऐसा टूल है जो सोर्स कोड को पार्स करता है और उसे स्टैंडर्ड स्टाइल में दिखाता है. इसलिए, हर BUILD फ़ाइल को एक ही तरीके से अपने-आप फ़ॉर्मैट किया जाता है. इससे कोड की समीक्षा के दौरान, फ़ॉर्मैटिंग से जुड़ी कोई समस्या नहीं आती. इससे टूल के लिए, BUILD फ़ाइलों को समझना, उनमें बदलाव करना, और उन्हें जनरेट करना भी आसान हो जाता है.
BUILD फ़ाइल का फ़ॉर्मैट, buildifier के आउटपुट से मेल खाना चाहिए.
फ़ॉर्मैटिंग का उदाहरण
# Test code implementing the Foo controller.
package(default_testonly = True)
py_test(
name = "foo_test",
srcs = glob(["*.py"]),
data = [
"//data/production/foo:startfoo",
"//foo",
"//third_party/java/jdk:jdk-k8",
],
flaky = True,
deps = [
":check_bar_lib",
":foo_data_check",
":pick_foo_port",
"//pyglib",
"//testing/pybase",
],
)
फ़ाइल स्ट्रक्चर
सुझाव: इस क्रम का इस्तेमाल करें. हर एलिमेंट को शामिल करना ज़रूरी नहीं है:
पैकेज की जानकारी (टिप्पणी)
load()के सभी स्टेटमेंटpackage()फ़ंक्शन.नियमों और मैक्रो को कॉल करना
Buildifier, किसी एलिमेंट से जुड़ी टिप्पणी और स्टैंडअलोन टिप्पणी के बीच अंतर करता है. अगर कोई टिप्पणी किसी खास एलिमेंट से जुड़ी नहीं है, तो उसके बाद एक खाली लाइन का इस्तेमाल करें. अपने-आप होने वाले बदलावों के लिए, इन दोनों के बीच अंतर करना ज़रूरी है. उदाहरण के लिए, किसी नियम को मिटाते समय किसी टिप्पणी को बनाए रखने या हटाने के लिए, इन दोनों के बीच अंतर करना ज़रूरी है.
# Standalone comment (such as to make a section in a file)
# Comment for the cc_library below
cc_library(name = "cc")
मौजूदा पैकेज में मौजूद टारगेट के रेफ़रंस
फ़ाइलों को पैकेज डायरेक्ट्री के हिसाब से उनके पाथ से रेफ़र किया जाना चाहिए. इसके लिए, अप-रेफ़रंस (जैसे, ..) का इस्तेमाल नहीं किया जाना चाहिए. जनरेट की गई फ़ाइलों के नाम के आगे ":" प्रीफ़िक्स होना चाहिए, ताकि यह पता चल सके कि वे सोर्स नहीं हैं. सोर्स फ़ाइलों के नाम की शुरुआत : से नहीं होनी चाहिए. नियमों के पहले : होना चाहिए. उदाहरण के लिए, मान लें कि x.cc एक सोर्स फ़ाइल है:
cc_library(
name = "lib",
srcs = ["x.cc"],
hdrs = [":gen_header"],
)
genrule(
name = "gen_header",
srcs = [],
outs = ["x.h"],
cmd = "echo 'int x();' > $@",
)
टारगेट का नामकरण
टारगेट के नाम, कम शब्दों में ज़्यादा जानकारी देने वाले होने चाहिए. अगर किसी टारगेट में एक सोर्स फ़ाइल है, तो टारगेट का नाम आम तौर पर उस सोर्स से लिया जाना चाहिए. उदाहरण के लिए, chat.cc के लिए cc_library का नाम chat रखा जा सकता है या DirectMessage.java के लिए java_library का नाम direct_message रखा जा सकता है.
किसी पैकेज के लिए, उसी नाम का टारगेट (जिस टारगेट का नाम, पैकेज वाली डायरेक्ट्री के नाम से मिलता-जुलता हो) को डायरेक्ट्री के नाम से बताई गई सुविधा देनी चाहिए. अगर ऐसा कोई टारगेट मौजूद नहीं है, तो उसी नाम का टारगेट न बनाएं.
एक ही नाम वाले टारगेट (//x के बजाय //x:x) का रेफ़रंस देते समय, छोटे नाम का इस्तेमाल करें. अगर आप एक ही पैकेज में हैं, तो लोकल रेफ़रंस (:x के बजाय //x) का इस्तेमाल करें.
"आरक्षित" टारगेट के नामों का इस्तेमाल न करें, क्योंकि इनका खास मतलब होता है. इनमें all, __pkg__, और __subpackages__ शामिल हैं. इन नामों के खास मायने होते हैं. इनका इस्तेमाल करने पर, भ्रम पैदा हो सकता है और अनचाहे नतीजे मिल सकते हैं.
टीम के मौजूदा नियमों के न होने पर, यहां कुछ ऐसी सलाह दी गई हैं जिनका पालन करना ज़रूरी नहीं है. हालांकि, Google में इनका इस्तेमाल बड़े पैमाने पर किया जाता है:
- आम तौर पर, "snake_case" का इस्तेमाल करें
- एक
srcवालेjava_libraryके लिए, इसका मतलब है कि फ़ाइल के नाम का इस्तेमाल न करना. हालांकि, इसमें एक्सटेंशन शामिल नहीं है - Java
*_binaryऔर*_testनियमों के लिए, "Upper CamelCase" का इस्तेमाल करें. इससे टारगेट किए गए नाम का मिलान,srcमें से किसी एक से किया जा सकता है.java_testके लिए, इससेtest_classएट्रिब्यूट को टारगेट के नाम से अनुमानित किया जा सकता है.
- एक
- अगर किसी टारगेट के एक से ज़्यादा वैरिएंट हैं, तो उन्हें अलग-अलग दिखाने के लिए, सफ़िक्स जोड़ें. जैसे,
:foo_dev,:foo_prodया:bar_x86,:bar_x64) _test,_unittest,TestयाTestsकी मदद से,_testसफ़िक्स को टारगेट करना_libया_libraryजैसे बेमतलब के सफ़िक्स का इस्तेमाल न करें. हालांकि, अगर_libraryटारगेट और उससे जुड़े_binaryके बीच टकराव से बचने के लिए ऐसा करना ज़रूरी हो, तो किया जा सकता है- प्रोटो से जुड़े टारगेट के लिए:
proto_libraryटारगेट के नाम_protoसे खत्म होने चाहिए- भाषा के हिसाब से
*_proto_libraryके नियम, मूल प्रोटो से मेल खाने चाहिए. हालांकि,_protoकी जगह भाषा के हिसाब से सफ़िक्स का इस्तेमाल करना चाहिए. जैसे:cc_proto_library:_cc_protojava_proto_library:_java_protojava_lite_proto_library:_java_proto_lite
किसको दिखे
विज़िबिलिटी को जितना हो सके उतना सीमित रखना चाहिए. हालांकि, टेस्ट और रिवर्स डिपेंडेंसी के लिए ऐक्सेस की अनुमति देनी चाहिए. ज़रूरत के हिसाब से __pkg__ और __subpackages__ का इस्तेमाल करें.
default_visibility पैकेज को //visibility:public पर सेट न करें.
//visibility:public को सिर्फ़ प्रोजेक्ट के सार्वजनिक एपीआई में मौजूद टारगेट के लिए अलग-अलग सेट किया जाना चाहिए. ये ऐसी लाइब्रेरी हो सकती हैं जिन्हें बाहरी प्रोजेक्ट या बाइनरी पर निर्भर रहने के लिए डिज़ाइन किया गया है. साथ ही, इनका इस्तेमाल बाहरी प्रोजेक्ट की बिल्ड प्रोसेस में किया जा सकता है.
डिपेंडेंसी
डिपेंडेंसी सिर्फ़ डायरेक्ट डिपेंडेंसी तक सीमित होनी चाहिए. डायरेक्ट डिपेंडेंसी का मतलब है कि नियम में शामिल सोर्स के लिए ज़रूरी डिपेंडेंसी. ट्रांज़िटिव डिपेंडेंसी की सूची न बनाएं.
पैकेज-लोकल डिपेंडेंसी को सबसे पहले लिस्ट किया जाना चाहिए. साथ ही, उन्हें ऊपर दिए गए मौजूदा पैकेज में टारगेट के रेफ़रंस सेक्शन के साथ काम करने वाले तरीके से रेफ़र किया जाना चाहिए. इसके लिए, उनके पूरे पैकेज के नाम का इस्तेमाल नहीं किया जाना चाहिए.
डिपेंडेंसी को सीधे तौर पर एक ही सूची के तौर पर दिखाएं. कई टारगेट की "सामान्य" डिपेंडेंसी को एक वैरिएबल में डालने से, उन्हें मैनेज करना मुश्किल हो जाता है. साथ ही, टूल के लिए किसी टारगेट की डिपेंडेंसी को बदलना नामुमकिन हो जाता है. इससे ऐसी डिपेंडेंसी भी बन सकती हैं जिनका इस्तेमाल नहीं किया जाता.
Globs
[] की मदद से, "कोई टारगेट नहीं" बताएं. ऐसे ग्लोब का इस्तेमाल न करें जो किसी भी फ़ाइल से मेल न खाता हो: इसमें गड़बड़ी होने की संभावना ज़्यादा होती है और यह खाली सूची से कम साफ़ तौर पर दिखता है.
बार-बार होने वाला
सोर्स फ़ाइलों को मैच करने के लिए, रिकर्सिव ग्लोब का इस्तेमाल न करें. उदाहरण के लिए,
glob(["**/*.java"]).
रिकर्सिव ग्लोब की वजह से, BUILD फ़ाइलों के बारे में तर्क देना मुश्किल हो जाता है, क्योंकि ये BUILD फ़ाइलों वाली सबडायरेक्ट्री को छोड़ देते हैं.
आम तौर पर, रिकर्सिव ग्लोब, हर डायरेक्ट्री के लिए BUILD फ़ाइल से कम असरदार होते हैं. इन फ़ाइलों के बीच डिपेंडेंसी ग्राफ़ तय किया जाता है. इससे रिमोट कैशिंग और पैरललिज़्म को बेहतर तरीके से इस्तेमाल किया जा सकता है.
हर डायरेक्ट्री में BUILD फ़ाइल बनाना और उनके बीच डिपेंडेंसी ग्राफ़ तय करना एक अच्छा तरीका है.
नॉन-रिकर्सिव
आम तौर पर, नॉन-रिकर्सिव ग्लोब स्वीकार किए जाते हैं.
अन्य कन्वेंशन
कॉन्स्टेंट (जैसे,
GLOBAL_CONSTANT) को तय करने के लिए, अंग्रेज़ी के बड़े अक्षरों और अंडरस्कोर का इस्तेमाल करें. वैरिएबल (जैसे,my_variable) को तय करने के लिए, अंग्रेज़ी के छोटे अक्षरों और अंडरस्कोर का इस्तेमाल करें.लेबल को कभी भी अलग-अलग नहीं किया जाना चाहिए, भले ही उनमें 79 से ज़्यादा वर्ण हों. जहां तक हो सके, लेबल स्ट्रिंग लिटरल होने चाहिए. वजह: इससे ढूंढने और बदलने की प्रोसेस आसान हो जाती है. इससे पढ़ने में आसानी होती है.
name एट्रिब्यूट की वैल्यू, लिटरल कॉन्स्टेंट स्ट्रिंग होनी चाहिए. हालांकि, मैक्रो में ऐसा नहीं है. वजह: बाहरी टूल, किसी नियम को रेफ़र करने के लिए, नाम एट्रिब्यूट का इस्तेमाल करते हैं. उन्हें कोड को समझे बिना नियमों का पता लगाना होता है.
बूलियन टाइप के एट्रिब्यूट सेट करते समय, पूर्णांक वैल्यू के बजाय बूलियन वैल्यू का इस्तेमाल करें. लेगसी सिस्टम की वजह से, नियमों में अब भी ज़रूरत के मुताबिक पूर्णांकों को बूलियन में बदला जाता है. हालांकि, ऐसा न करने का सुझाव दिया जाता है. वजह:
flaky = 1को गलत तरीके से पढ़ा जा सकता है. ऐसा लग सकता है कि इसमें कहा गया है कि "इस टारगेट को एक बार फिर से चलाकर, इसमें मौजूद गड़बड़ी को ठीक करें".flaky = Trueमें साफ़ तौर पर बताया गया है कि "यह टेस्ट फ़्लेकी है".
Python स्टाइल गाइड के साथ अंतर
हालांकि, Python स्टाइल गाइड के साथ काम करना एक लक्ष्य है, लेकिन इसमें कुछ अंतर हैं:
लाइन की लंबाई की कोई तय सीमा नहीं है. लंबी टिप्पणियों और लंबी स्ट्रिंग को अक्सर 79 कॉलम में बांटा जाता है. हालांकि, ऐसा करना ज़रूरी नहीं है. इसे कोड की समीक्षा या सबमिट करने से पहले की स्क्रिप्ट में लागू नहीं किया जाना चाहिए. वजह: लेबल लंबे हो सकते हैं और इस सीमा से ज़्यादा हो सकते हैं. आम तौर पर,
BUILDफ़ाइलों को टूल जनरेट करते हैं या उनमें बदलाव करते हैं. इसलिए, लाइन की लंबाई की सीमा तय करना सही नहीं है.स्ट्रिंग को अपने-आप जोड़ने की सुविधा काम नहीं करती.
+ऑपरेटर का इस्तेमाल करें. वजह:BUILDफ़ाइलों में स्ट्रिंग की कई सूचियां शामिल हैं. कॉमा लगाना भूलना आम बात है. इससे नतीजे पूरी तरह से अलग हो जाते हैं. इस वजह से, पिछले समय में कई गड़बड़ियां हुई हैं. यह बातचीत भी देखें.नियमों में कीवर्ड के तर्कों के लिए,
=चिह्न के आस-पास स्पेस का इस्तेमाल करें. वजह: नाम वाले आर्ग्युमेंट, Python की तुलना में ज़्यादा बार इस्तेमाल किए जाते हैं. साथ ही, ये हमेशा अलग लाइन में होते हैं. स्पेस का इस्तेमाल करने से, कॉन्टेंट को आसानी से पढ़ा जा सकता है. यह तरीका लंबे समय से इस्तेमाल किया जा रहा है. इसलिए, सभी मौजूदाBUILDफ़ाइलों में बदलाव करने की ज़रूरत नहीं है.डिफ़ॉल्ट रूप से, स्ट्रिंग के लिए डबल कोटेशन मार्क का इस्तेमाल करें. वजह: Python की स्टाइल गाइड में इसके बारे में नहीं बताया गया है. हालांकि, इसमें एक जैसा फ़ॉर्मैट इस्तेमाल करने का सुझाव दिया गया है. इसलिए, हमने सिर्फ़ डबल कोट वाली स्ट्रिंग का इस्तेमाल करने का फ़ैसला किया है. कई भाषाओं में, स्ट्रिंग लिटरल के लिए डबल कोट का इस्तेमाल किया जाता है.
टॉप-लेवल की दो परिभाषाओं के बीच एक खाली लाइन का इस्तेमाल करें. वजह:
BUILDफ़ाइल का स्ट्रक्चर, सामान्य Python फ़ाइल जैसा नहीं होता. इसमें सिर्फ़ टॉप-लेवल स्टेटमेंट होते हैं. एक खाली लाइन का इस्तेमाल करने से,BUILDफ़ाइलें छोटी हो जाती हैं.