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

Sorun bildir Kaynağı göster Nightly · 8.0 · 7.4 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel ile günlük etkileşim, temel olarak birkaç komutla gerçekleşir: build, test ve run. Ancak bazen bu seçenekler sınırlı gelebilir: Paketleri bir depoya göndermek, son kullanıcılar için dokümanlar yayınlamak veya Kubernetes ile uygulama dağıtmak isteyebilirsiniz. Ancak Bazel'de publish veya deploy komutu yoktur. Bu işlemler nerede kullanılır?

bazel run komutu

Bazel'in hermetiklik, yeniden üretilebilirlik ve artımlılığa odaklanması, build ve test komutlarının yukarıdaki görevler için yararlı olmadığı anlamına gelir. Bu işlemler, sınırlı ağ erişimi olan bir korumalı alanda çalışabilir ve her bazel build ile yeniden çalıştırılmaları garanti edilmez.

Bunun yerine, bazel run işlevini kullanın: İstediğiniz yan etkilerin olduğu görevler için idealdir. Bazel kullanıcıları, yürütülebilir dosyalar oluşturan kurallara alışkındır ve kural yazarları bunu "özel fiiller"e genişletmek için ortak bir kalıp grubunu takip edebilir.

Doğada: rules_k8s

Örneğin, Bazel için Kubernetes kurallarını içeren rules_k8s dosyasını ele alalım. Aşağıdaki hedefe sahip olduğunuzu 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, k8s_objectstaging.apply ve :staging.delete gibi adlara sahip makrolar tarafından da oluşturulur. Bu komutlar, bu işlemleri gerçekleştirmek için komut dosyaları oluşturur ve bazel run staging.apply ile çalıştırıldığında kendi 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. Bunlardan ilki, 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 derlenebilir ve çalıştırılabilir. angular-cli'te, bazel test //etc/api:angular_devkit_core_api ile böyle bir hedef çalıştırabilirsiniz.

Zaman içinde bu altın dosyanın meşru nedenlerle güncellenmesi gerekebilir. Bu dosyayı manuel olarak güncellemek zahmetli ve hatalara açık bir işlemdir. Bu nedenle, bu makroda altın dosyayla karşılaştırmak yerine dosyayı güncelleyen bir nodejs_binary hedefi de sağlanır. Aynı test komut dosyası, çağrılış şekline bağlı olarak "doğrula" veya "kabul et" modunda çalışacak şekilde yazılabilir. Bu, daha önce öğrendiğiniz kalıbı takip eder: Yerleşik 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 güçlü olabilir ve tanımayı öğrendikten sonra oldukça yaygın olduğunu göreceksiniz.

Kendi kurallarınızı uyarlama

Bu modelin merkezinde makrolar yer alır. Makrolar kurallar gibi kullanılır ancak birden fazla hedef oluşturabilir. Genellikle, birincil derleme işlemini gerçekleştiren, belirtilen ada sahip bir hedef oluştururlar: Normal bir ikili dosyayı, Docker görüntüsünü veya kaynak kodu arşivini derleyebilirler. Bu kalıpta, birincil hedefin çıktısına göre yan etkiler gerçekleştiren komut dosyaları oluşturmak için ek hedefler oluşturulur (ör. ortaya çıkan ikili dosyayı yayınlama veya beklenen test çıktısını güncelleme).

Bunu açıklamak için, Sphinx ile web sitesi oluşturan hayali bir kuralı, kullanıcının hazır olduğunda yayınlamasına olanak tanıyan ek bir hedef oluşturmak için 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 düşünün. 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 kuralların her ikisi için de hedefler oluşturmak üzere aşağıdaki makroyu tanımlayın:

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, tek bir Bazel kuralıymış gibi bir "docs" hedefi oluşturulur. Kurulduğunda kural bazı yapılandırmalar oluşturur ve manuel incelemeye hazır bir HTML sitesi oluşturmak için Sphinx'i çalıştırır. Ancak, siteyi yayınlamak için bir komut dosyası oluşturan ek bir "docs.publish" hedefi de oluşturulur. Birincil hedefin çıktısını kontrol ettikten sonra, hayali bir bazel publish komutu gibi herkese açık olarak yayınlamak için bazel run :docs.publish kullanabilirsiniz.

_sphinx_publisherKuralın uygulanmasının nasıl görüneceği hemen anlaşılmıyor. Bu tür işlemler genellikle bir başlatıcı kabuk komut dosyası yazar. Bu yöntem genellikle çok basit bir kabuk komut dosyası yazmak için ctx.actions.expand_template kullanılmasını içerir. Bu durumda, yayıncı ikilisini birincil hedefin çıkışına giden bir yola sahip olarak çağırabilirsiniz. Bu sayede yayıncı uygulaması genel kalabilir, _sphinx_site kuralı yalnızca HTML oluşturabilir ve bu ikisini birleştirmek için gereken tek şey bu küçük komut dosyasıdır.

rules_k8s'te .apply'un yaptığı tam olarak budur: expand_template apply.sh.tpl'e dayalı çok basit bir Bash komut dosyası yazar, bu komut dosyası da birincil hedefin çıktısıyla kubectl'i çalıştırır. Bu komut dosyası daha sonra bazel run :staging.apply ile derlenip çalıştırılabilir. Böylece k8s_object hedefleri için etkili bir k8s-apply komutu sağlanır.