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

Sorun bildir Kaynağı göster

Bazel ile günlük etkileşim genellikle birkaç komut aracılığıyla gerçekleşir: build, test ve run. Ancak bazen bu olanaklar sizi sınırlı hale getirebilir: Paketleri bir depoya aktarmak, son kullanıcılar için belge yayınlamak veya Kubernetes ile bir uygulama dağıtmak isteyebilirsiniz. Ancak Bazel'ın bir publish veya deploy komutu yok. Bu işlemler nerede geçerli?

Bazel çalıştırma komutu

Bazel'in hermetiklik, yeniden oluşturulabilirlik ve artımlılık konularına odaklanması, build ve test komutlarının yukarıdaki görevler için faydalı olmadığı anlamına geliyor. Bu işlemler, sınırlı ağ erişimine sahip bir korumalı alanda çalıştırılabilir ve her bazel build ile tekrar çalıştırılacağı garanti edilmez.

Bunun yerine, yan etkileri istediğiniz görevlerin gerçekleştireceği bazel run aracını kullanın. Bazel kullanıcıları yürütülebilir dosyalar oluşturan kurallara alışkındır. Kural yazarları, bunu "özel fiilleri" kapsayacak şekilde genişletmek için ortak bir kalıp kümesini izleyebilir.

Doğada: rules_k8s

Örneğin, Bazel için Kubernetes kuralları olan rules_k8s'i 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",
)

staging hedefinde bazel build kullanıldığında k8s_object kuralı, standart bir Kubernetes YAML dosyası oluşturur. Bununla birlikte, ek hedefler k8s_object makrosu tarafından staging.apply ve :staging.delete gibi adlarla oluşturulur. Bunlar, bu işlemleri gerçekleştirmek için komut dosyaları oluşturur ve bazel run staging.apply ile yürütüldüğünde bunlar, 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. Birincisi, oluşturulan bazı çıktıları "golden" dosyası (yani beklenen çıkışı içeren bir dosya) ile karşılaştıran standart bir nodejs_test hedefidir. Bu özellik normal bazel test çağrısıyla oluşturulup çalıştırılabilir. angular-cli ürününde bazel test //etc/api:angular_devkit_core_api ile böyle bir hedef çalıştırabilirsiniz.

Zaman içinde, bu altın dosyanın geçerli nedenlerle güncellenmesi gerekebilir. Bu dosyayı manuel olarak güncellemek yorucu ve hataya açıktır. Bu nedenle bu makro, aynı zamanda altın dosyasını karşılaştırmak yerine güncelleyen bir nodejs_binary hedefi de sağlar. Etkin olarak, çağrılma şekline bağlı olarak aynı test komut dosyası "doğrulama" veya "kabul etme" modunda çalışacak şekilde yazılabilir. Bu, daha önce öğrendiğiniz şablonun aynısıdır: Yerel bir bazel test-accept komutu yoktur ancak bazel run //etc/api:angular_devkit_core_api.accept ile aynı etki elde edilebilir.

Bu kalıp oldukça güçlü olabilir ve bu modeli tanımayı öğrendiğinizde oldukça yaygın hale gelir.

Kendi kurallarınızı uyarlama

Makrolar bu kalıbın temelinde yer alır. Makrolar, kurallar gibi kullanılır ancak birkaç hedef oluşturabilir. Genellikle birincil derleme işlemini gerçekleştiren, belirtilen ada sahip bir hedef oluştururlar. Belki normal bir ikili program, Docker görüntüsü veya kaynak kodu arşivi oluşturur. Bu kalıpta, birincil hedefin çıktısına bağlı olarak yan etkiler gerçekleştiren komut dosyaları oluşturmak için ek hedefler oluşturulur (sonuçta ortaya çıkan ikili dosyayı yayınlama veya beklenen test çıkışını güncelleme gibi).

Bunu göstermek için, Sfenks içeren bir web sitesi oluşturan sanal bir kuralı, kullanıcının hazır olduğunda yayınlamasına olanak tanıyan ek bir hedef oluşturmak üzere makroyla sarmalayın. Sfenks ile web sitesi oluşturmak için şu mevcut kuralı düşünün:

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

Ardından, çalıştırıldığında oluşturulan sayfaları yayınlayan bir komut dosyası oluşturan aşağıdaki gibi bir kural düşünün:

_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 birlikte 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 birincil hedefi oluşturur gibi kullanın:

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

Bu örnekte, makro standart, tek bir Bazel kuralı olduğu gibi, bir "dokümanlar" hedefi oluşturulur. Kural oluşturulduğunda, bir yapılandırma oluşturur ve manuel inceleme için hazır bir HTML sitesi oluşturmak üzere Sfenks'i çalıştırır. Bununla birlikte, 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 tıpkı sanal bir bazel publish komutu gibi bazel run :docs.publish kullanarak bunu herkese açık kullanım için yayınlayabilirsiniz.

_sphinx_publisher kuralının nasıl uygulandığı hemen belli olmaz. Genellikle, bu tür işlemler bir başlatıcı kabuk komut dosyası yazar. Bu yöntemde genellikle çok basit bir kabuk komut dosyası yazmak için ctx.actions.expand_template kullanılır. Bu durumda, yayıncı ikili programı birincil hedefin çıkışına giden bir yolla çağrılır. Böylece, yayıncı uygulaması genel kalabilir, _sphinx_site kuralı yalnızca HTML üretebilir ve ikisini bir araya getirmek için gereken tek şey bu küçük komut dosyasıdır.

rules_k8s ürününde .apply tam olarak bu işlemi gerçekleştirir: expand_template, birincil hedefin çıkışıyla kubectl çalıştıran apply.sh.tpl tabanlı çok basit bir Bash komut dosyası yazar. Daha sonra bu komut dosyası bazel run :staging.apply ile derlenip çalıştırılabilir ve k8s_object hedefleri için etkili bir şekilde k8s-apply komutu sağlar.