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
,_test
,_unittest
,Test
याTests
को टारगेट करता है _lib
या_library
जैसे बेमतलब के सफ़िक्स इस्तेमाल न करें. हालांकि, अगर_library
टारगेट और उससे जुड़े_binary
के बीच टकराव से बचने के लिए ऐसा करना ज़रूरी हो, तो किया जा सकता है- प्रोटो से जुड़े टारगेट के लिए:
proto_library
टारगेट के नाम_proto
से खत्म होने चाहिए- भाषा के हिसाब से
*_proto_library
के नियम, मूल प्रोटो से मेल खाने चाहिए. हालांकि,*_proto_library
को भाषा के हिसाब से सफ़िक्स से बदलें. जैसे:cc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
_proto
किसको दिखे
विज़िबिलिटी को जितना हो सके उतना सीमित किया जाना चाहिए. हालांकि, टेस्ट और रिवर्स डिपेंडेंसी के ज़रिए ऐक्सेस करने की अनुमति दी जानी चाहिए. ज़रूरत के हिसाब से __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
फ़ाइलें छोटी हो जाती हैं.