การใช้มาโครเพื่อสร้างคำกริยาที่กำหนดเอง

รายงานปัญหา ดูแหล่งที่มา ตอนกลางคืน · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

การโต้ตอบแบบวันต่อวันกับ Bazel จะเกิดขึ้นผ่านคำสั่ง 2-3 อย่างหลักๆ ดังนี้ build, test และ run แต่ในบางครั้ง อาจมีข้อจำกัดต่อไปนี้: ต้องการพุชแพ็กเกจไปยังที่เก็บ เผยแพร่เอกสารสำหรับผู้ใช้ปลายทาง หรือ ทำให้แอปพลิเคชันใช้งานได้ด้วย Kubernetes แต่ Bazel ไม่มี publish หรือ คำสั่ง deploy – การดำเนินการเหล่านี้เหมาะกับตำแหน่งใด

คำสั่งเรียกใช้ Bazel

การมุ่งเน้นของ Bazel ในด้านความต่อเนื่อง การทำซ้ำ และส่วนเพิ่มหมายถึง คำสั่ง build และ test ไม่มีประโยชน์ต่องานด้านบน การดำเนินการเหล่านี้ อาจทำงานในแซนด์บ็อกซ์โดยมีการจำกัดการเข้าถึงเครือข่าย และไม่รับประกันว่า ให้เรียกใช้ทุก bazel build อีกครั้ง

แต่ให้อาศัย bazel run แทน ซึ่งเป็นภาระงานที่ต้องการมี ของ Google ผู้ใช้ Bazel คุ้นเคยกับกฎที่สร้างไฟล์ที่เรียกใช้งานได้ และ ผู้เขียนกฎสามารถทำตามชุดรูปแบบทั่วไปเพื่อขยาย "คำกริยาที่กำหนดเอง"

ป่าเถื่อน: rules_k8s

ตัวอย่างเช่น ลองพิจารณา rules_k8s กฎ Kubernetes สำหรับ Bazel สมมติว่าคุณมีเป้าหมายต่อไปนี้

# BUILD file in //application/k8s
k8s_object(
    name = "staging",
    kind = "deployment",
    cluster = "testing",
    template = "deployment.yaml",
)

กฎ k8s_object จะสร้าง ไฟล์ Kubernetes YAML มาตรฐานเมื่อใช้ bazel build ใน staging เป้าหมาย อย่างไรก็ตาม เป้าหมายเพิ่มเติมก็สร้างขึ้นโดย k8s_object เช่นกัน ที่มีชื่ออย่างเช่น staging.apply และ :staging.delete บิลด์เหล่านี้ สคริปต์เพื่อดำเนินการดังกล่าว และเมื่อเรียกใช้ด้วย bazel run staging.apply สคริปต์เหล่านี้จะทำงานเหมือนคำสั่ง bazel k8s-apply หรือ bazel k8s-delete ของเราเอง

อีกตัวอย่างหนึ่ง: ts_api_guardian_test

รูปแบบนี้สามารถดูในโปรเจ็กต์ Angular ได้ด้วย มาโคร ts_api_guardian_test จะสร้างเป้าหมาย 2 อย่าง รายการแรกคือเป้าหมาย nodejs_test มาตรฐานซึ่งเปรียบเทียบ เอาต์พุตบางส่วนที่สร้างขึ้นสำหรับ "ทอง" (ซึ่งก็คือ ไฟล์ที่มีองค์ประกอบ เอาต์พุตที่คาดหวัง) ซึ่งสร้างและเรียกใช้ได้ด้วยการเรียกใช้ bazel test ปกติ ใน angular-cli คุณสามารถเรียกใช้ประเภท เป้าหมาย ด้วย bazel test //etc/api:angular_devkit_core_api

เมื่อเวลาผ่านไป คุณอาจต้องอัปเดตไฟล์ทองคำนี้ด้วยเหตุผลที่เหมาะสม การอัปเดตด้วยตนเองนี้น่าเบื่อและเกิดข้อผิดพลาดได้ง่าย ดังนั้นมาโครนี้ยังมี เป้าหมาย nodejs_binary ที่อัปเดตไฟล์ทองคำแทนการเปรียบเทียบ แข่งกับสิ่งนั้น สามารถเขียนสคริปต์การทดสอบเดียวกันเพื่อทำงานใน "ยืนยัน" ได้อย่างมีประสิทธิภาพ หรือ "ยอมรับ" ตามวิธีที่ระบบเรียกใช้ ซึ่งจะเป็นไปตามรูปแบบเดียวกัน ที่คุณได้เรียนรู้แล้ว ไม่มีคำสั่ง bazel test-accept แบบเนทีฟ แต่ และจะให้ผลลัพธ์แบบเดียวกัน bazel run //etc/api:angular_devkit_core_api.accept

รูปแบบนี้อาจใช้ได้ผลดีมาก และกลายเป็นรูปแบบที่พบได้บ่อยเมื่อคุณ เรียนรู้ที่จะจดจำ

การปรับกฎของคุณเอง

มาโครคือหัวใจของรูปแบบนี้ มาโครใช้ในลักษณะ แต่สามารถสร้างเป้าหมายหลายรายการได้ โดยทั่วไปพวกเขาจะสร้าง เป้าหมายด้วยชื่อที่ระบุซึ่งดำเนินการบิลด์หลัก: บางที โมเดลจะสร้างไบนารีปกติ อิมเมจ Docker หรือซอร์สโค้ดที่เก็บถาวร ใน รูปแบบนี้ เป้าหมายเพิ่มเติมจะถูกสร้างขึ้นเพื่อสร้างสคริปต์ที่ทำงานด้าน ตามผลลัพธ์ของเป้าหมายหลัก เช่น การเผยแพร่ ผลลัพธ์ไบนารีที่เป็นผลลัพธ์ หรืออัปเดตเอาต์พุตทดสอบที่คาดไว้

เพื่อให้เห็นภาพชัดขึ้น ให้รวมกฎจินตภาพที่สร้างเว็บไซต์ที่มี Sphinx กับมาโครเพื่อสร้าง เป้าหมายที่อนุญาตให้ผู้ใช้เผยแพร่เมื่อพร้อม ลองพิจารณาวิธีต่อไปนี้ กฎที่มีอยู่สำหรับการสร้างเว็บไซต์ที่มี Sphinx มีดังนี้

_sphinx_site = rule(
     implementation = _sphinx_impl,
     attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
)

ถัดไป ให้พิจารณากฎดังตัวอย่างต่อไปนี้ ซึ่งจะสร้างสคริปต์ที่เมื่อเรียกใช้ เผยแพร่หน้าเว็บที่สร้างขึ้น

_sphinx_publisher = rule(
    implementation = _publish_impl,
    attrs = {
        "site": attr.label(),
        "_publisher": attr.label(
            default = "//internal/sphinx:publisher",
            executable = True,
        ),
    },
    executable = True,
)

สุดท้าย ให้กำหนดมาโครต่อไปนี้เพื่อสร้างเป้าหมายสำหรับทั้ง 2 อย่างข้างต้น เข้าด้วยกัน

def sphinx_site(name, srcs = [], **kwargs):
    # This creates the primary target, producing the Sphinx-generated HTML.
    _sphinx_site(name = name, srcs = srcs, **kwargs)
    # This creates the secondary target, which produces a script for publishing
    # the site generated above.
    _sphinx_publisher(name = "%s.publish" % name, site = name, **kwargs)

ในไฟล์ BUILD ให้ใช้มาโครเหมือนกับว่าสร้างเฉพาะมาโครหลัก เป้าหมาย:

sphinx_site(
    name = "docs",
    srcs = ["index.md", "providers.md"],
)

ในตัวอย่างนี้ "เอกสาร" สร้างเป้าหมายขึ้นมา เช่นเดียวกับที่ว่ามาโคร กฎมาตรฐานข้อเดียวของ Bazel เมื่อสร้าง กฎจะสร้างการกำหนดค่าบางอย่าง และเรียกใช้ Sphinx เพื่อสร้างเว็บไซต์ HTML ที่พร้อมสำหรับการตรวจสอบด้วยตนเอง อย่างไรก็ตาม "docs.publish" เพิ่มเติม ก็จะสร้างสคริปต์ กำลังเผยแพร่ไซต์ เมื่อคุณตรวจสอบเอาต์พุตของเป้าหมายหลักแล้ว คุณจะสามารถทำสิ่งต่อไปนี้ ใช้ bazel run :docs.publish เพื่อเผยแพร่สำหรับสาธารณะ เช่นเดียวกับ คำสั่ง bazel publish ในจินตนาการ

เรายังไม่ทราบโดยทันทีว่าการใช้ _sphinx_publisher เป็นไปอย่างไร อาจมีหน้าตาของกฎ การดำเนินการเช่นนี้มักจะเขียนสคริปต์เชลล์ Launcher โดยทั่วไป วิธีการนี้รวมถึงการใช้ ctx.actions.expand_template ในการเขียนสคริปต์เชลล์แบบง่ายมาก ซึ่งในกรณีนี้จะเรียกใช้ไบนารีของผู้เผยแพร่โฆษณา ที่มีเส้นทางไปยังเอาต์พุตของเป้าหมายหลัก วิธีนี้ช่วยให้ผู้เผยแพร่โฆษณา การใช้งานยังคงเป็นแบบทั่วไป กฎ _sphinx_site จะทำได้เพียง HTML และสคริปต์ขนาดเล็กนี้ก็เป็นแค่สิ่งที่จำเป็นในการรวมทั้งสอง

ใน rules_k8s นี่คือสิ่งที่ .apply ทำจริงๆ: expand_template เขียนสคริปต์ Bash แบบง่ายๆ จาก apply.sh.tpl, ซึ่งเรียกใช้ kubectl พร้อมเอาต์พุตของเป้าหมายหลัก สคริปต์นี้สามารถ จะสร้างและเรียกใช้ด้วย bazel run :staging.apply อย่างมีประสิทธิภาพ คำสั่ง k8s-apply สำหรับเป้าหมาย k8s_object