Modül uzantıları

Sorun bildir Kaynağı göster

Modül uzantıları, kullanıcıların bağımlılık grafiğindeki modüllerden giriş verilerini okuyarak, bağımlılıkları çözmek için gerekli mantığı uygulayarak ve son olarak depo kurallarını çağırarak depo oluşturarak modül sistemini genişletmelerini sağlar. Bu uzantılar, depo kurallarına benzer özellikler içerir. Bu özellikler dosya G/Ç'sini gerçekleştirmelerini, ağ istekleri göndermelerini ve benzeri işlemleri gerçekleştirmelerini sağlar. Diğer olanaklarının yanı sıra Bazel'ın diğer paket yönetimi sistemleriyle etkileşimde bulunmasına olanak tanırken Bazel modüllerinden oluşturulan bağımlılık grafiğine de riayet eder.

Kod deposu kurallarında olduğu gibi, .bzl dosyalarında modül uzantılarını tanımlayabilirsiniz. Bunlar doğrudan çağrılmaz. Her modül, uzantıların okunması için etiket adı verilen veri parçalarını belirtir. Bazel, uzantıları değerlendirmeden önce modül çözünürlüğü çalıştırır. Uzantı, bağımlılık grafiğinin tamamında kendisine ait tüm etiketleri okur.

Uzantı kullanımı

Uzantılar Bazel modüllerinde barındırılır. Bir modül içinde uzantı kullanmak için öncelikle uzantıyı barındıran modüle bir bazel_dep ekleyin. Daha sonra, uzantıyı kapsama almak için use_extension yerleşik işlevini çağırın. Şu örneği inceleyin: rules_jvm_external modülünde tanımlanan "maven" uzantısını kullanmak için MODULE.bazel dosyasından alınan bir snippet:

bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

Bu işlem, use_extension döndürülen değerini bir değişkene bağlar. Böylece kullanıcı, uzantı etiketlerini belirtmek için nokta söz dizimini kullanabilir. Etiketler, uzantı tanımında belirtilen karşılık gelen etiket sınıfları tarafından tanımlanan şemaya uygun olmalıdır. Bazı maven.install ve maven.artifact etiketlerini belirten bir örnek:

maven.install(artifacts = ["org.junit:junit:4.13.2"])
maven.artifact(group = "com.google.guava",
               artifact = "guava",
               version = "27.0-jre",
               exclusions = ["com.google.j2objc:j2objc-annotations"])

Uzantı tarafından oluşturulan depoları mevcut modülün kapsamına almak için use_repo yönergesini kullanın.

use_repo(maven, "maven")

Bir uzantı tarafından oluşturulan depolar, ilgili API'nin bir parçasıdır. Bu örnekte "maven" modülü uzantısı, maven adlı bir depo oluşturmayı taahhüt eder. Yukarıdaki beyanla uzantı, "maven" uzantısı tarafından oluşturulan depoya işaret etmek için @maven//:org_junit_junit gibi etiketleri doğru şekilde çözer.

Uzantı tanımı

module_extension işlevini kullanarak modül uzantılarını depo kurallarına benzer şekilde tanımlayabilirsiniz. Bununla birlikte, depo kurallarının birkaç özelliği vardır. Modül uzantılarında ise her biri belirli özelliklere sahip tag_class öğeleri bulunur. Etiket sınıfları, bu uzantı tarafından kullanılan etiketler için şemaları tanımlar. Örneğin, yukarıdaki "maven" uzantısı şu şekilde tanımlanabilir:

# @rules_jvm_external//:extensions.bzl

_install = tag_class(attrs = {"artifacts": attr.string_list(), ...})
_artifact = tag_class(attrs = {"group": attr.string(), "artifact": attr.string(), ...})
maven = module_extension(
  implementation = _maven_impl,
  tag_classes = {"install": _install, "artifact": _artifact},
)

Bu bildirimler, maven.install ve maven.artifact etiketlerinin belirtilen özellik şeması kullanılarak belirtilebileceğini gösterir.

Modül uzantılarının uygulama işlevi, depoların kurallarına benzerdir. Tek fark, uzantıyı ve ilgili tüm etiketleri kullanan tüm modüllere erişim izni veren bir module_ctx nesnesi almalarıdır. Ardından uygulama işlevi, depo oluşturmak için depo kurallarını çağırır.

# @rules_jvm_external//:extensions.bzl

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")  # a repo rule
def _maven_impl(ctx):
  # This is a fake implementation for demonstration purposes only

  # collect artifacts from across the dependency graph
  artifacts = []
  for mod in ctx.modules:
    for install in mod.tags.install:
      artifacts += install.artifacts
    artifacts += [_to_artifact(artifact) for artifact in mod.tags.artifact]

  # call out to the coursier CLI tool to resolve dependencies
  output = ctx.execute(["coursier", "resolve", artifacts])
  repo_attrs = _process_coursier_output(output)

  # call repo rules to generate repos
  for attrs in repo_attrs:
    http_file(**attrs)
  _generate_hub_repo(name = "maven", repo_attrs)

Uzantı kimliği

Modül uzantıları, use_extension çağrısında görünen .bzl dosyası ve adla tanımlanır. Aşağıdaki örnekte maven uzantısı, .bzl dosyası @rules_jvm_external//:extension.bzl ve maven adıyla tanımlanır:

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")

Bir uzantıyı farklı bir .bzl dosyasından yeniden dışa aktarmak, uzantıya yeni bir kimlik verir ve geçişli modül grafiğinde uzantının her iki sürümü de kullanılıyorsa bunlar ayrı olarak değerlendirilir ve yalnızca bu kimlikle ilişkilendirilen etiketleri görür.

Uzantı yazarı olarak, kullanıcıların modül uzantınızı sadece tek bir .bzl dosyasından kullanacaklarından emin olmalısınız.

Kod deposu adları ve görünürlük

Uzantılar tarafından oluşturulan kod depoları, module_repo_canonical_name~extension_name~repo_name biçiminde standart adlara sahiptir. Kök modülde barındırılan uzantılarda module_repo_canonical_name bölümü, _main dizesiyle değiştirilir. Standart ad biçiminin güvenmeniz gereken bir API olmadığını ve her an değişebileceğini unutmayın.

Bu adlandırma politikası, her uzantının kendi "depo ad alanına" sahip olduğu anlamına gelir. İki farklı uzantı, çakışma riski olmadan aynı ada sahip bir depo tanımlayabilir. Bu aynı zamanda repository_ctx.name hizmetinin, deponun standart adını bildirdiği anlamına gelir. Bu ad, depo kuralı çağrısında belirtilen adla aynı değildir.

Modül uzantıları tarafından oluşturulan depolar dikkate alındığında, birkaç depo görünürlüğü kuralı vardır:

  • Bazel modülü deposu, bazel_dep ve use_repo aracılığıyla MODULE.bazel dosyasında sunulan tüm depoları görebilir.
  • Modül uzantısı tarafından oluşturulan bir depo, uzantıyı barındıran modüle görünür olan tüm depoları ve aynı modül uzantısı tarafından oluşturulan diğer tüm depoları görebilir (depo kuralı çağrılarında belirtilen adlar, görünen adları olarak kullanılır).
    • Bu durum, çakışmaya neden olabilir. Modül deposu görünen adı foo olan bir depo görebiliyorsa ve uzantı, belirtilen adı foo olan bir depo oluşturuyorsa bu uzantı tarafından oluşturulan tüm kod depoları için foo, eski kod deposunu ifade eder.

En iyi uygulamalar

Bu bölümde, uzantıların kullanılması, bakımı kolay ve zaman içindeki değişikliklere iyi uyum sağlaması için uzantı yazmayla ilgili en iyi uygulamalar açıklanmaktadır.

Her uzantıyı ayrı bir dosyaya yerleştirin

Uzantılar farklı dosyalarda olduğunda, bir uzantının başka bir uzantı tarafından oluşturulan depoları yüklemesine olanak tanır. Bu işlevi kullanmıyor olsanız bile, daha sonra ihtiyacınız olması ihtimaline karşı bunları ayrı dosyalara yerleştirmek en iyisidir. Bunun nedeni, uzantının kimliğinin dosyaya dayalı olmasıdır. Dolayısıyla, uzantıyı daha sonra başka bir dosyaya taşımak genel API'nizi değiştirir ve kullanıcılarınız için geriye dönük olarak uyumsuz bir değişiklik olur.

İşletim sistemini ve mimariyi belirleme

Uzantınız işletim sistemini veya mimari türünü temel alıyorsa bunu uzantı tanımında os_dependent ve arch_dependent boole özelliklerini kullanarak belirttiğinizden emin olun. Bu sayede, ikisinden birinde değişiklik olduğunda Bazel'in yeniden değerlendirme ihtiyacını anlamasını sağlar.

Kod deposu adlarını doğrudan yalnızca kök modül etkilemelidir

Bir uzantı depo oluşturduğunda bunların, uzantının ad alanı içinde oluşturulduğunu unutmayın. Bu durum, farklı modüllerin aynı uzantıyı kullanması ve sonuçta aynı ada sahip bir depo oluşturulması durumunda çakışmaların meydana gelebileceği anlamına gelir. Bu durum genellikle modül uzantısının tag_class öğesinin, depo kuralının name değeri olarak aktarılan bir name bağımsız değişkenine sahip olması olarak görünür.

Örneğin, A kök modülünün B modülüne bağlı olduğunu varsayalım. Her iki modül de mylang modülüne bağlıdır. Hem A hem de B mylang.toolchain(name="foo") çağrısı yaparsa her ikisi de mylang modülü içinde foo adlı bir depo oluşturmayı dener ve bir hata oluşur.

Bunu önlemek için doğrudan kod deposu adını ayarlama özelliğini kaldırın veya yalnızca kök modülün yapmasına izin verin. Kök modüle hiçbir şey bağımlı olmayacağından izin verebilirsiniz. Böylece çakışan bir ad oluşturacak başka bir modülün endişelenmesi gerekmez.