कस्टम क्रिया बनाने के लिए मैक्रो का उपयोग करना

समस्या की शिकायत करें सोर्स देखें

Baज़ल के साथ हर दिन होने वाला इंटरैक्शन, मुख्य रूप से कुछ कमांड के ज़रिए होता है: build, test, और run. हालांकि, कभी-कभी इन अनुरोधों की संख्या सीमित हो सकती है: हो सकता है कि आप पैकेज को डेटा स्टोर करने की जगह में पुश करना चाहें, असली उपयोगकर्ताओं के लिए दस्तावेज़ पब्लिश करना चाहें या Kubernetes पर एक ऐप्लिकेशन डिप्लॉय करना चाहें. हालांकि, Basel के पास publish या deploy का निर्देश नहीं है – ये कार्रवाइयां कहां की जा सकती हैं?

बेज़ल रन कमांड

बेज़ल हरमैटिटी, रीप्रॉड्यूसिबिलिटी, और बढ़ोतरी पर ध्यान देने का मतलब है कि build और test निर्देश ऊपर दिए गए कामों के लिए मददगार नहीं हैं. ये कार्रवाइयां सीमित नेटवर्क ऐक्सेस वाले सैंडबॉक्स में चल सकती हैं. इसके हर bazel build पर फिर से चलने की कोई गारंटी नहीं है.

इसके बजाय, bazel run का इस्तेमाल करें: उन टास्क के लिए मेहनत का घोड़ा, जिनका असर आपको जानना है. बेज़ल के उपयोगकर्ता उन नियमों के आदी हैं जो एक्ज़ीक्यूटेबल बनाते हैं और नियम लिखने वाले लोग, पैटर्न के एक सामान्य सेट का पालन करके इसे "कस्टम क्रियाओं" तक बढ़ा सकते हैं.

जंगल में: नियम_k8s

उदाहरण के लिए, Basel के लिए, Kubernetes नियम rules_k8s पर विचार करें. मान लें कि आपके पास यह टारगेट है:

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

जब staging टारगेट पर bazel build का इस्तेमाल किया जाता है, तो k8s_object नियम एक स्टैंडर्ड Kubernetes YAML फ़ाइल बनाता है. हालांकि, staging.apply और :staging.delete जैसे नामों वाला k8s_object मैक्रो भी अतिरिक्त टारगेट बनाता है. ये कार्रवाइयां करने के लिए, ये स्क्रिप्ट बनाती हैं. इन्हें bazel run staging.apply के साथ इस्तेमाल करने पर, ये हमारे अपने bazel k8s-apply या bazel k8s-delete निर्देशों की तरह काम करते हैं.

एक और उदाहरण: ts_api_Guardian_test

इस पैटर्न को Angular प्रोजेक्ट में भी देखा जा सकता है. ts_api_guardian_test मैक्रो दो टारगेट बनाता है. पहला स्टैंडर्ड 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_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,
)

आखिर में, ऊपर दिए गए दोनों नियमों को एक साथ टारगेट करने के लिए, नीचे दिया गया मैक्रो तय करें:

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"],
)

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

यह तुरंत पता नहीं चल पा रहा है कि _sphinx_publisher नियम को लागू करने का क्या तरीका हो सकता है. अक्सर, इस तरह की कार्रवाइयां, लॉन्चर शेल स्क्रिप्ट लिखती हैं. आम तौर पर, इस तरीके में एक बहुत आसान शेल स्क्रिप्ट लिखने के लिए ctx.actions.expand_template का इस्तेमाल किया जाता है. इस मामले में, पब्लिशर बाइनरी को प्राइमरी टारगेट के आउटपुट के पाथ के साथ शुरू किया जाता है. इस तरह, पब्लिशर का तरीका सामान्य रह सकता है और _sphinx_site नियम सिर्फ़ एचटीएमएल बना सकता है. साथ ही, इन दोनों को एक साथ मिलाने के लिए, सिर्फ़ यह छोटी स्क्रिप्ट ज़रूरी है.

rules_k8s में, .apply यही काम करता है: expand_template apply.sh.tpl के आधार पर, एक बहुत आसान बैश स्क्रिप्ट लिखता है. यह kubectl, मुख्य टारगेट के आउटपुट के साथ चलती है. इसके बाद, इस स्क्रिप्ट को bazel run :staging.apply की मदद से बनाया और चलाया जा सकता है. इसमें k8s_object टारगेट के लिए k8s-apply कमांड दिया जा सकता है.