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şletmesine olanak tanır. Bu uzantılar, depo kurallarına benzer özelliklere sahiptir. Bu özellikler, dosya G/Ç işlemlerini gerçekleştirmelerine, ağ istekleri göndermelerine vb. olanak tanır. Diğerlerinin yanı sıra, Bazel'in Bazel modüllerinden oluşturulan bağımlılık grafiğine saygı duyarken diğer paket yönetim sistemleriyle etkileşim kurmasına olanak tanır.
Depo kuralları gibi .bzl
dosyalarında modül uzantılarını tanımlayabilirsiniz. Doğrudan çağrılmazlar. Bunun yerine, her modül, uzantıların okuması için etiket adı verilen veri parçalarını belirtir. Bazel, uzantıları değerlendirmeden önce modül çözümlemesini ç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 uzantıyı modülde kullanmak için önce uzantıyı barındıran modüle bir bazel_dep
ekleyin, ardından kapsama almak için use_extension
yerleşik işlevini çağırın. Aşağıdaki örneği inceleyin. Bu örnekte, rules_jvm_external
modülünde tanımlanan "maven" uzantısını kullanmak için bir MODULE.bazel
dosyasından bir snippet alınmıştır:
bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
Bu, use_extension
değerini bir değişkene bağlar. Böylece kullanıcı, uzantı için etiketleri belirtmek üzere nokta söz dizimini kullanabilir. Etiketler, uzantı tanımında belirtilen ilgili etiket sınıfları tarafından tanımlanan şemaya uymalı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ı geçerli 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, uzantının API'sinin bir parçasıdır. Bu örnekte, "maven" modül uzantısı maven
adlı bir depo oluşturmayı vaat etmektedir. Yukarıdaki beyanla uzantı, @maven//:org_junit_junit
gibi etiketleri "maven" uzantısı tarafından oluşturulan depoyu işaret edecek şekilde doğru şekilde çözer.
Uzantı tanımı
Modül uzantılarını, module_extension
işlevini kullanarak depo kurallarına benzer şekilde tanımlayabilirsiniz. Ancak depo kurallarının bir dizi özelliği olsa da modül uzantılarının her biri bir dizi tag_class
içerir. 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 beyanlar, maven.install
ve maven.artifact
etiketlerinin belirtilen özellik şeması kullanılarak belirtilebileceğini gösterir.
Modül uzantılarının uygulama işlevi, depo kurallarının işlevlerine benzer. Tek fark, uzantıyı kullanan tüm modüllere ve ilgili tüm etiketlere 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 ad ve .bzl
dosyasıyla tanımlanır. Aşağıdaki örnekte, maven
uzantısı .bzl
dosyası @rules_jvm_external//:extension.bzl
ve ad maven
ile tanımlanmıştır:
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
Bir uzantıyı farklı bir .bzl
dosyasından yeniden dışa aktardığınızda uzantıya yeni bir kimlik verilir. Uzantıların her iki sürümü de geçişli modül grafiğinde kullanılırsa ayrı ayrı değerlendirilir ve yalnızca söz konusu kimlikle ilişkili etiketleri görür.
Uzantı yazarı olarak, kullanıcıların modül uzantınızı yalnızca tek bir .bzl
dosyasından kullanacağından emin olmanız gerekir.
Depo adları ve görünürlük
Uzantılar tarafından oluşturulan depoların standart adları module_repo_canonical_name+extension_name+repo_name
şeklindedir. Kanonik ad biçiminin, güvenebileceğiniz bir API olmadığını ve herhangi bir zamanda değiştirilebileceğini unutmayın.
Bu adlandırma politikası, her uzantının kendi "repo ad alanının" olduğu anlamına gelir. İki farklı uzantı, herhangi bir çakışma riski olmadan aynı ada sahip bir depo tanımlayabilir. Ayrıca repository_ctx.name
, deponun standart adını raporlar. Bu ad, depo kural çağrısında belirtilen adla aynı değildir.
Modül uzantıları tarafından oluşturulan depolar göz önüne alındığında, birkaç depo görünürlüğü kuralı vardır:
- Bazel modül deposu,
bazel_dep
veuse_repo
aracılığıylaMODULE.bazel
dosyasında tanıtılan tüm depoları görebilir. - Bir modül uzantısı tarafından oluşturulan bir depo, uzantıyı barındıran modül tarafından görülebilen tüm depoları ve aynı zamanda aynı modül uzantısı tarafından oluşturulan diğer tüm depoları görebilir (repo kural çağrılarında belirtilen adları görünür adları olarak kullanır).
- Bu durum, çakışmaya neden olabilir. Modül deposu
foo
görünen adına sahip bir depo görebiliyorsa ve uzantı,foo
adlı bir depo oluşturuyorsa bu uzantı tarafından oluşturulan tüm depolar içinfoo
, önceki depoyu ifade eder.
- Bu durum, çakışmaya neden olabilir. Modül deposu
- Benzer şekilde, bir modül uzantısının uygulama işlevinde, uzantı tarafından oluşturulan depolar, oluşturuldukları sıraya bakılmaksızın, özelliklerdeki görünen adlarıyla birbirlerine referans verebilir.
- Modül tarafından görülebilen bir depoyla çakışma olması durumunda, depo kuralı özelliklerine iletilen etiketler, aynı ada sahip uzantı tarafından oluşturulan depo yerine modül tarafından görülebilen depoya atıfta bulunmaları için
Label
çağrısına sarmalanabilir.
- Modül tarafından görülebilen bir depoyla çakışma olması durumunda, depo kuralı özelliklerine iletilen etiketler, aynı ada sahip uzantı tarafından oluşturulan depo yerine modül tarafından görülebilen depoya atıfta bulunmaları için
Modül uzantısı depolarını geçersiz kılma ve bunlara kod ekleme
Kök modül, modül uzantısı depolarını geçersiz kılmak veya eklemek için override_repo
ve inject_repo
kullanabilir.
Örnek: rules_java
'nin java_tools
öğesini tedarikçi firma tarafından sağlanan bir kopyayla değiştirme
# MODULE.bazel
local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository")
local_repository(
name = "my_java_tools",
path = "vendor/java_tools",
)
bazel_dep(name = "rules_java", version = "7.11.1")
java_toolchains = use_extension("@rules_java//java:extension.bzl", "toolchains")
override_repo(java_toolchains, remote_java_tools = "my_java_tools")
Örnek: Bir Go bağımlılığını, sistem zlib yerine @zlib
'e bağımlı olacak şekilde düzeltme
# MODULE.bazel
bazel_dep(name = "gazelle", version = "0.38.0")
bazel_dep(name = "zlib", version = "1.3.1.bcr.3")
go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
go_deps.module_override(
patches = [
"//patches:my_module_zlib.patch",
],
path = "example.com/my_module",
)
use_repo(go_deps, ...)
inject_repo(go_deps, "zlib")
# patches/my_module_zlib.patch
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -1,6 +1,6 @@
go_binary(
name = "my_module",
importpath = "example.com/my_module",
srcs = ["my_module.go"],
- copts = ["-lz"],
+ cdeps = ["@zlib"],
)
En iyi uygulamalar
Bu bölümde, uzantıların kullanımı kolay, bakımı yapılabilir ve zaman içindeki değişikliklere iyi uyum sağlayacak şekilde yazılmasıyla 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 izin verilir. Bu işlevi kullanmasanız bile, daha sonra ihtiyaç duyabileceğiniz için bunları ayrı dosyalara koymanız önerilir. Bunun nedeni, uzantının kimliğinin dosyasına bağlı olmasıdır. Bu nedenle, uzantıyı daha sonra başka bir dosyaya taşımak herkese açık API'nizi değiştirir ve kullanıcılarınız için geriye dönük olarak uyumlu olmayan bir değişikliktir.
Tekrarlanabilirliği belirtin
Uzantı, aynı girişler (uzantı etiketleri, okuduğu dosyalar vb.) verildiğinde her zaman aynı depoları tanımlıyorsa ve özellikle de sağlama toplamıyla korunmayan indirme işlemlerini kullanmıyorsa reproducible = True
ile extension_metadata
döndürmeyi düşünebilirsiniz. Bu sayede Bazel, kilit dosyasına yazarken bu uzantıyı atlayabilir.
İşletim sistemini ve mimariyi belirtin
Uzantılarınız işletim sistemine veya mimari türüne bağlıysa os_dependent
ve arch_dependent
Boole özelliklerini kullanarak bunu uzantı tanımında belirtmeyi unutmayın. Bu sayede Bazel, bunlardan birinde değişiklik olması durumunda yeniden değerlendirme yapılması gerektiğini bilir.
Barındırıcıya olan bu tür bir bağımlılık, bu uzantının kilit dosyası girişinin korunmasını zorlaştırdığından, mümkünse uzantıyı yeniden üretilebilir olarak işaretleyebilirsiniz.
Yalnızca kök modül, depo adlarını doğrudan etkilemelidir.
Bir uzantı depolama alanı oluşturduğunda bu depolama alanlarının uzantının ad alanında oluşturulduğunu unutmayın. Bu, farklı modüller aynı uzantıyı kullanıp aynı ada sahip bir depo oluşturması durumunda çakışmalar olabileceği anlamına gelir. Bu durum genellikle bir modül uzantısının tag_class
, depo kuralı name
değeri olarak iletilen bir name
bağımsız değişkenine sahip olması şeklinde ortaya çıkar.
Örneğin, A
adlı kök modülü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")
işlevini çağırırsa her ikisi de mylang
modülü içinde foo
adlı bir depo oluşturmaya çalışır ve bir hata meydana gelir.
Bunu önlemek için depo adını doğrudan ayarlama özelliğini kaldırın veya yalnızca kök modülün bunu yapmasına izin verin. Kök modülün bu özelliğe sahip olmasında sakınca yoktur çünkü hiçbir şey ona bağlı değildir. Bu nedenle, başka bir modülün çakışan bir ad oluşturması konusunda endişelenmenize gerek yoktur.