การจัดรูปแบบไฟล์ 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();' > $@",
)
การตั้งชื่อเป้าหมาย
ชื่อเป้าหมายควรสื่อความหมาย หากเป้าหมายมีไฟล์ต้นทางไฟล์เดียว โดยทั่วไปเป้าหมายควรมีชื่อที่มาจากแหล่งที่มานั้น (เช่น cc_library
สำหรับ chat.cc
อาจตั้งชื่อว่า chat
หรือ java_library
สำหรับ DirectMessage.java
อาจตั้งชื่อว่า direct_message
)
เป้าหมายที่มีชื่อเดียวกันสำหรับแพ็กเกจ (เป้าหมายที่มีชื่อเดียวกับไดเรกทอรีที่บรรจุ) ควรให้ฟังก์ชันการทำงานตามที่อธิบายโดยชื่อไดเรกทอรี หากไม่มีเป้าหมายดังกล่าว อย่าสร้างเป้าหมายที่มีชื่อเดียวกัน
โปรดใช้ชื่อย่อเมื่ออ้างอิงถึงเป้าหมายที่มีชื่อเดียวกัน (//x
แทน //x:x
) หากคุณอยู่ในแพ็กเกจเดียวกัน ให้ใช้การอ้างอิงภายใน (:x
แทน //x
)
หลีกเลี่ยงการใช้ชื่อเป้าหมายที่ "สงวนไว้" ซึ่งมีความหมายพิเศษ ซึ่งรวมถึง all
, __pkg__
และ __subpackages__
ชื่อเหล่านี้มีความหมายเชิงอรรถศาสตร์พิเศษและอาจทำให้เกิดความสับสนและลักษณะการทำงานที่ไม่คาดคิดเมื่อนำมาใช้
หากไม่มีแบบแผนของทีมที่แพร่หลาย ต่อไปนี้คือคําแนะนําที่ไม่ผูกมัดซึ่งใช้กันอย่างกว้างขวางใน Google
- โดยทั่วไป ให้ใช้ "snake_case"
- สําหรับ
java_library
ที่มีsrc
1 ตัว หมายความว่าใช้ชื่อที่ไม่ใช่ชื่อไฟล์ที่ไม่มีนามสกุล - สำหรับกฎ
*_binary
และ*_test
ของ Java ให้ใช้"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 ให้ทําดังนี้
- เป้าหมาย
proto_library
ควรมีชื่อที่ลงท้ายด้วย_proto
- กฎ
*_proto_library
สำหรับภาษาที่เฉพาะเจาะจงควรตรงกับ proto พื้นฐาน แต่แทนที่_proto
ด้วยส่วนต่อท้ายที่เฉพาะเจาะจงตามภาษา เช่นcc_proto_library
:_cc_proto
java_proto_library
:_java_proto
java_lite_proto_library
:_java_proto_lite
- เป้าหมาย
ระดับการแชร์
คุณควรกำหนดขอบเขตระดับการเข้าถึงให้แคบที่สุดเท่าที่จะเป็นไปได้ ขณะเดียวกันก็ยังคงอนุญาตให้การทดสอบและความสัมพันธ์ย้อนกลับเข้าถึงได้ ใช้ __pkg__
และ __subpackages__
ตามเหมาะสม
หลีกเลี่ยงการตั้งค่าแพ็กเกจ default_visibility
เป็น //visibility:public
//visibility:public
ควรตั้งค่าแยกต่างหากสําหรับเป้าหมายใน API สาธารณะของโปรเจ็กต์เท่านั้น ไลบรารีเหล่านี้อาจเป็นไลบรารีที่ออกแบบมาเพื่อให้โปรเจ็กต์ภายนอกใช้ หรือไบนารีที่กระบวนการบิลด์ของโปรเจ็กต์ภายนอกอาจใช้
การอ้างอิง
Dependency ควรจํากัดไว้เฉพาะ Dependency โดยตรง (Dependency ที่แหล่งที่มาที่ระบุไว้ในกฎจําเป็นต้องใช้) อย่าแสดงรายการ Dependency แบบทรานซิทีฟ
คุณควรระบุแพ็กเกจที่ต้องใช้ภายในไว้ก่อนและอ้างอิงด้วยวิธีที่เข้ากันได้กับส่วนการอ้างอิงเป้าหมายในแพ็กเกจปัจจุบันด้านบน (ไม่ใช่ตามชื่อแพ็กเกจแบบสัมบูรณ์)
โปรดระบุรายการพึ่งพาโดยตรงเป็นรายการเดียว การวางข้อกำหนด "ทั่วไป" ของเป้าหมายหลายรายการไว้ในตัวแปรจะลดความสามารถในการบำรุงรักษา ทำให้เครื่องมือเปลี่ยนข้อกำหนดของเป้าหมายไม่ได้ และอาจนำไปสู่ข้อกำหนดที่ไม่ได้ใช้
Globs
ระบุ "ไม่มีเป้าหมาย" ด้วย []
อย่าใช้นิพจน์ทั่วไปที่ตรงกับรายการใดๆ เลย เนื่องจากมีแนวโน้มที่จะเกิดข้อผิดพลาดและไม่ค่อยชัดเจนเท่ากับรายการว่าง
เกิดซ้ำ
อย่าใช้นิพจน์ทั่วไปแบบย้อนกลับเพื่อจับคู่ไฟล์ต้นฉบับ (เช่น
glob(["**/*.java"])
)
รูปแบบทั่วไปแบบเรียกซ้ำทำให้การหาเหตุผลของไฟล์ BUILD
ทำได้ยาก เนื่องจากจะข้ามไดเรกทอรีย่อยที่มีไฟล์ BUILD
โดยทั่วไปแล้ว รูปแบบทั่วไปแบบเรียกซ้ำจะมีประสิทธิภาพน้อยกว่าการมีไฟล์ BUILD
1 ไฟล์ต่อไดเรกทอรีที่มีการกำหนดกราฟความเกี่ยวข้องไว้ระหว่างกัน เนื่องจากวิธีนี้ช่วยให้แคชระยะไกลและการทำงานแบบขนานมีประสิทธิภาพมากขึ้น
แนวทางปฏิบัติแนะนำคือให้เขียนไฟล์ BUILD
ในแต่ละไดเรกทอรีและกำหนดกราฟความเกี่ยวข้องระหว่างไฟล์
ไม่ใช้การเรียกซ้ำ
โดยทั่วไประบบจะยอมรับรูปแบบทั่วไปแบบไม่ซ้ำ
การประชุมอื่นๆ
ใช้อักษรตัวพิมพ์ใหญ่และขีดล่างเพื่อประกาศค่าคงที่ (เช่น
GLOBAL_CONSTANT
) ใช้อักษรตัวพิมพ์เล็กและขีดล่างเพื่อประกาศตัวแปร (เช่นmy_variable
)ไม่ควรแบ่งป้ายกำกับ แม้ว่าจะมีความยาวเกิน 79 อักขระก็ตาม ป้ายกำกับควรเป็นสตริงตัวอักษรล้วนทุกครั้งที่เป็นไปได้ Rationale: ช่วยให้ค้นหาและแทนที่ได้ง่าย และยังช่วยปรับปรุงการอ่านออกเสียงด้วย
ค่าของแอตทริบิวต์ชื่อควรเป็นสตริงคงที่ตามตัวอักษร (ยกเว้นในมาโคร) Rationale: เครื่องมือภายนอกใช้แอตทริบิวต์ชื่อเพื่ออ้างอิงกฎ ผู้ใช้ต้องค้นหากฎได้โดยไม่ต้องตีความโค้ด
เมื่อตั้งค่าแอตทริบิวต์ประเภทบูลีน ให้ใช้ค่าบูลีน ไม่ใช่ค่าจำนวนเต็ม กฎยังคงแปลงจำนวนเต็มเป็นบูลีนตามที่จำเป็นเนื่องจากเหตุผลเดิม แต่เราไม่แนะนําให้ทำเช่นนั้น Rationale:
flaky = 1
อาจทำให้เข้าใจผิดว่าหมายความว่า "แยกกลุ่มเป้าหมายนี้ออกโดยเรียกใช้อีกครั้ง 1 ครั้ง"flaky = True
พูดอย่างตรงไปตรงมาว่า "การทดสอบนี้ทำงานไม่เสถียร"
ความแตกต่างกับคู่มือสไตล์ Python
แม้ว่าความเข้ากันได้กับคู่มือสไตล์ Python จะเป็นเป้าหมาย แต่ก็มีความแตกต่างอยู่บ้าง ดังนี้
ไม่มีขีดจำกัดความยาวบรรทัดอย่างเข้มงวด ความคิดเห็นและสตริงที่ยาวมักจะมีการแยกออกเป็น 79 คอลัมน์ แต่ก็ไม่บังคับ ไม่ควรบังคับใช้ในการตรวจสอบโค้ดหรือสคริปต์ก่อนส่ง Rationale: ป้ายกำกับอาจมีความยาวเกินขีดจำกัดนี้ เป็นเรื่องปกติที่เครื่องมือจะสร้างหรือแก้ไขไฟล์
BUILD
ซึ่งไม่เหมาะกับขีดจำกัดความยาวบรรทัดไม่รองรับการต่อสตริงโดยนัย ใช้โอเปอเรเตอร์
+
Rationale: ไฟล์BUILD
มีรายการสตริงจำนวนมาก คุณอาจลืมใส่คอมมา ซึ่งจะทำให้ได้ผลลัพธ์ที่แตกต่างออกไปโดยสิ้นเชิง ซึ่งทำให้เกิดข้อบกพร่องมากมายในอดีต ดูการสนทนานี้ด้วยใช้เว้นวรรครอบเครื่องหมาย
=
สำหรับอาร์กิวเมนต์คีย์เวิร์ดในกฎ Rationale: อาร์กิวเมนต์ที่มีชื่อมีการใช้งานบ่อยกว่าใน Python มากและจะอยู่บรรทัดแยกต่างหากเสมอ การเว้นวรรคช่วยให้อ่านง่ายขึ้น รูปแบบนี้มีมานานแล้ว และการปรับแต่งไฟล์BUILD
ที่มีอยู่ทั้งหมดนั้นไม่คุ้มค่าโดยค่าเริ่มต้น ให้ใช้เครื่องหมายคำพูดคู่สำหรับสตริง Rationale: ไม่ได้ระบุไว้ในคู่มือสไตล์ Python แต่แนะนำให้ใช้รูปแบบที่สอดคล้องกัน เราจึงตัดสินใจใช้เฉพาะสตริงที่มีเครื่องหมายคำพูดคู่ หลายภาษาใช้เครื่องหมายคำพูดแบบคู่สำหรับสตริงตัวอักษร
ใช้บรรทัดว่าง 1 บรรทัดระหว่างคําจํากัดความระดับบนสุด 2 รายการ Rationale: โครงสร้างของไฟล์
BUILD
ไม่เหมือนไฟล์ Python ทั่วไป มีเฉพาะคำสั่งระดับบนสุด การใช้บรรทัดว่างเดี่ยวจะทำให้ไฟล์BUILD
สั้นลง