Özel Fiiller Oluşturmak için Makroları Kullanma

Sorun bildir Kaynağı görüntüle Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bazel ile günlük etkileşim genellikle şu birkaç komut aracılığıyla gerçekleşir: build, test ve run. Ancak bazen bu özellikler sınırlı kalabilir. Örneğin, paketleri bir depoya göndermek, son kullanıcılar için doküman yayınlamak veya Kubernetes ile bir uygulama dağıtmak isteyebilirsiniz. Ancak Bazel'de publish veya deploy komutu yok. Bu işlemler nereye sığar?

bazel run komutu

Bazel'in hermetiklik, tekrarlanabilirlik ve artımlılık üzerine odaklanması nedeniyle build ve test komutları yukarıdaki görevler için yararlı değildir. Bu işlemler, sınırlı ağ erişimiyle bir korumalı alanda çalışabilir ve her bazel build ile yeniden çalıştırılacağı garanti edilmez.

Bunun yerine, yan etkileri olmasını istediğiniz görevler için bazel run kullanın. Bazel kullanıcıları, yürütülebilir dosyalar oluşturan kurallara alışkındır ve kural yazarları, bunu "özel fiillere" genişletmek için ortak bir dizi kalıbı takip edebilir.

Doğada: rules_k8s

Örneğin, Bazel için Kubernetes kurallarını (rules_k8s) ele alalım. Aşağıdaki hedefiniz olduğunu varsayalım:

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

k8s_object kuralı, staging hedefinde bazel build kullanıldığında standart bir Kubernetes YAML dosyası oluşturur. Ancak ek hedefler de k8s_object makrosu tarafından staging.apply ve :staging.delete gibi adlarla oluşturulur. Bu komutlar, söz konusu işlemleri gerçekleştirmek için derleme komut dosyaları oluşturur ve bazel run staging.apply ile yürütüldüğünde bazel k8s-apply veya bazel k8s-delete komutlarımız gibi davranır.

Başka bir örnek: ts_api_guardian_test

Bu kalıp, Angular projesinde de görülebilir. ts_api_guardian_test makrosu iki hedef oluşturur. Birincisi, oluşturulan bazı çıkışları "altın" bir dosyayla (yani beklenen çıkışı içeren bir dosya) karşılaştıran standart bir nodejs_test hedefidir. Bu, normal bir bazel test çağrısıyla oluşturulup çalıştırılabilir. angular-cli bölgesinde bazel test //etc/api:angular_devkit_core_api ile bu tür bir hedef çalıştırabilirsiniz.

Bu altın dosya, zaman içinde meşru nedenlerle güncellenmesi gerekebilir. Bunu manuel olarak güncellemek sıkıcı ve hataya açık bir işlem olduğundan bu makro, altın dosyayla karşılaştırmak yerine dosyayı güncelleyen bir nodejs_binary hedefi de sağlar. Aynı test komut dosyası, nasıl çağrıldığına bağlı olarak "doğrula" veya "kabul et" modunda çalışacak şekilde yazılabilir. Bu, daha önce öğrendiğinizle aynı kalıbı izler: Yerel bir bazel test-accept komutu yoktur ancak aynı etki bazel run //etc/api:angular_devkit_core_api.accept ile elde edilebilir.

Bu kalıp oldukça etkili olabilir ve onu tanımayı öğrendiğinizde oldukça yaygın olduğunu fark edersiniz.

Kendi kurallarınızı uyarlama

Bu kalıbın temelinde makrolar yer alır. Makrolar kurallar gibi kullanılır ancak birden fazla hedef oluşturabilirler. Genellikle, birincil derleme işlemini gerçekleştiren, belirtilen ada sahip bir hedef oluştururlar: Belki normal bir ikili dosya, bir Docker görüntüsü veya kaynak kodu arşivi oluşturur. Bu düzende, birincil hedefin çıktısına göre yan etkiler gerçekleştiren komut dosyaları oluşturmak için ek hedefler oluşturulur. Örneğin, ortaya çıkan ikili dosyayı yayınlama veya beklenen test çıktısını güncelleme gibi.

Bunu göstermek için, Sphinx ile web sitesi oluşturan hayali bir kuralı, kullanıcı hazır olduğunda yayınlamasına olanak tanıyan ek bir hedef oluşturmak üzere bir makroyla sarmalayın. Sphinx ile web sitesi oluşturmak için aşağıdaki mevcut kuralı göz önünde bulundurun:

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

Ardından, aşağıdaki gibi bir kuralı göz önünde bulundurun. Bu kural, çalıştırıldığında oluşturulan sayfaları yayınlayan bir komut dosyası oluşturur:

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

Son olarak, yukarıdaki iki kural için de birlikte hedefler oluşturmak üzere aşağıdaki sembolik makroyu (Bazel 8 veya daha yeni sürümlerde kullanılabilir) tanımlayın:

def _sphinx_site_impl(name, visibility, srcs, **kwargs):
    # This creates the primary target, producing the Sphinx-generated HTML. We
    # set `visibility = visibility` to make it visible to callers of the
    # macro.
    _sphinx_site(name = name, visibility = visibility, srcs = srcs, **kwargs)
    # This creates the secondary target, which produces a script for publishing
    # the site generated above. We don't want it to be visible to callers of
    # our macro, so we omit visibility for it.
    _sphinx_publisher(name = "%s.publish" % name, site = name, **kwargs)

sphinx_site = macro(
    implementation = _sphinx_site_impl,
    attrs = {"srcs": attr.label_list(allow_files = [".rst"])},
    # Inherit common attributes like tags and testonly
    inherit_attrs = "common",
)

Alternatif olarak, Bazel 8'den eski Bazel sürümlerini desteklemeniz gerekiyorsa bunun yerine eski bir makro tanımlayabilirsiniz:

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 dosyalarında, makroyu yalnızca birincil hedefi oluşturuyormuş gibi kullanın:

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

Bu örnekte, makro standart bir tek Bazel kuralıymış gibi bir "docs" hedefi oluşturulur. Kural oluşturulduğunda bazı yapılandırmalar oluşturur ve Sphinx'i çalıştırarak manuel incelemeye hazır bir HTML sitesi oluşturur. Ancak, siteyi yayınlamak için bir komut dosyası oluşturan ek bir "docs.publish" hedefi de oluşturulur. Birincil hedefin çıkışını kontrol ettikten sonra, bazel run :docs.publish komutunu kullanarak herkese açık tüketim için yayınlayabilirsiniz. Bu, hayali bir bazel publish komutuna benzer.

_sphinx_publisher kuralının nasıl uygulanacağı hemen anlaşılmayabilir. Genellikle bu tür işlemler başlatıcı kabuk komut dosyası yazar. Bu yöntemde genellikle ctx.actions.expand_template kullanılarak çok basit bir kabuk komut dosyası yazılır. Bu durumda, yayıncı ikili dosyası birincil hedefin çıktısının yoluyla çağrılır. Bu sayede yayıncı uygulaması genel kalabilir, _sphinx_site kuralı yalnızca HTML oluşturabilir ve ikisini birleştirmek için bu küçük komut dosyası yeterli olur.

rules_k8s'da .apply gerçekten de bunu yapar: expand_template apply.sh.tpl'a dayalı çok basit bir Bash komut dosyası yazar ve bu komut dosyası, birincil hedefin çıkışıyla kubectl'ı çalıştırır. Bu komut dosyası daha sonra bazel run :staging.apply ile oluşturulup çalıştırılabilir ve k8s_object hedefleri için etkili bir k8s-apply komutu sağlar.