Modul Bazel adalah project Bazel yang dapat memiliki beberapa versi, yang masing-masing memublikasikan metadata tentang modul lain yang menjadi dependensinya. Hal ini analog dengan konsep yang sudah dikenal dalam sistem pengelolaan dependensi lainnya, seperti artefak Maven, paket npm, modul Go, atau peti Cargo.
Modul harus memiliki file MODULE.bazel
di root repo-nya (di samping
file WORKSPACE
). File ini adalah manifes modul yang mendeklarasikan nama,
versi, daftar dependensi langsung, dan informasi lainnya. Untuk contoh
dasar:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
Untuk melakukan resolusi modul, Bazel memulai dengan membaca file
MODULE.bazel
modul root, lalu berulang kali meminta file MODULE.bazel
dependensi
apa pun dari registry Bazel hingga
menemukan seluruh grafik dependensi.
Secara default, Bazel kemudian memilih satu versi dari setiap modul untuk digunakan. Bazel merepresentasikan setiap modul dengan repo, dan berkonsultasi dengan registry lagi untuk mempelajari cara menentukan setiap repo.
Format versi
Bazel memiliki ekosistem yang beragam dan proyek menggunakan berbagai skema pembuatan versi. Yang paling populer sejauh ini adalah SemVer, tetapi ada juga project terkemuka yang menggunakan skema berbeda seperti Abseil, yang versinya berbasis tanggal, misalnya 20210324.2
).
Karena alasan ini, Bzlmod menggunakan versi spesifikasi SemVer yang lebih santai. Perbedaannya meliputi:
- SemVer menetapkan bahwa bagian "rilis" dari versi harus terdiri dari 3
segmen:
MAJOR.MINOR.PATCH
. Di Bazel, persyaratan ini dilonggarkan sehingga sejumlah segmen diizinkan. - Dalam SemVer, setiap segmen di bagian "rilis" hanya boleh berupa angka. Di Bazel, ini dilonggarkan untuk mengizinkan huruf, dan semantik perbandingan cocok dengan "ID" di bagian "prarilis".
- Selain itu, semantik peningkatan versi besar, minor, dan patch tidak diterapkan. Namun, lihat tingkat kompatibilitas untuk mengetahui detail tentang cara kami menunjukkan kompatibilitas mundur.
Semua versi SemVer yang valid adalah versi modul Bazel yang valid. Selain itu, dua
versi SemVer a
dan b
membandingkan a < b
jika dan hanya jika metode tersebut sama saat
dibandingkan sebagai versi modul Bazel.
Pemilihan versi
Pertimbangkan masalah dependensi diamond, yang merupakan topik utama dalam ruang pengelolaan dependensi berversi. Misalkan Anda memiliki grafik dependensi:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
Versi D
mana yang harus digunakan? Untuk menyelesaikan pertanyaan ini, Bzlmod menggunakan algoritme Pemilihan Versi Minimal (MVS) yang diperkenalkan di sistem modul Go. MVS mengasumsikan bahwa semua
versi baru modul kompatibel dengan versi lama, sehingga memilih versi tertinggi
yang ditentukan oleh dependensi mana pun (D 1.1
dalam contoh kami). Ini disebut "minimal"
karena D 1.1
adalah versi paling awal yang dapat memenuhi persyaratan kita —
meskipun ada D 1.2
atau yang lebih baru, kita tidak akan memilihnya. Menggunakan MVS akan membuat
proses pemilihan versi yang fidelity tinggi dan dapat direproduksi.
Versi Yanked
Registry dapat mendeklarasikan versi tertentu sebagai dicabut jika harus dihindari (misalnya karena kerentanan keamanan). Bazel akan menampilkan error saat memilih
versi modul yang ditarik. Untuk memperbaiki error ini, upgrade ke versi yang lebih baru
yang tidak ditautkan, atau gunakan flag
--allow_yanked_versions
untuk secara eksplisit mengizinkan versi yang ditarik.
Tingkat kompatibilitas
Di Go, asumsi MVS tentang kompatibilitas mundur berfungsi karena memperlakukan
versi modul yang tidak kompatibel dengan versi sebelumnya sebagai modul terpisah. Dalam hal
SemVer, hal ini berarti A 1.x
dan A 2.x
dianggap sebagai modul yang berbeda, dan dapat
berdampingan dalam grafik dependensi yang di-resolve. Hal ini dimungkinkan dengan
mengenkode versi utama di jalur paket di Go, sehingga tidak ada
konflik waktu kompilasi atau waktu penautan.
Namun, Bazel tidak dapat memberikan jaminan tersebut, sehingga Bazel memerlukan nomor "versi utama"
untuk mendeteksi versi yang tidak kompatibel dengan versi lama. Nomor ini disebut
tingkat kompatibilitas, dan ditentukan oleh setiap versi modul dalam
perintah module()
. Dengan informasi ini, Bazel dapat menampilkan error saat
mendeteksi adanya versi modul yang sama dengan tingkat kompatibilitas berbeda
dalam grafik dependensi yang di-resolve.
Mengganti
Tentukan penggantian dalam file MODULE.bazel
untuk mengubah perilaku resolusi modul
Bazel. Hanya penggantian modul root yang akan berlaku; jika modul
digunakan sebagai dependensi, penggantiannya akan diabaikan.
Setiap penggantian ditetapkan untuk nama modul tertentu, sehingga memengaruhi semua versinya dalam grafik dependensi. Meskipun hanya penggantian modul root yang berlaku, penggantian tersebut dapat juga untuk dependensi transitif yang tidak diandalkan secara langsung oleh modul root.
Penggantian versi tunggal
single_version_override
mendukung beberapa tujuan:
- Dengan atribut
version
, Anda dapat menyematkan dependensi ke versi tertentu, terlepas dari versi dependensi mana yang diminta dalam grafik dependensi. - Dengan atribut
registry
, Anda dapat memaksa dependensi ini agar berasal dari registry tertentu, bukan mengikuti proses pemilihan registry normal. - Dengan atribut
patch*
, Anda dapat menentukan sekumpulan patch yang akan diterapkan ke modul yang didownload.
Semua atribut ini bersifat opsional dan dapat digabungkan serta dicocokkan satu sama lain.
Penggantian beberapa versi
multiple_version_override
dapat ditentukan untuk memungkinkan beberapa versi modul yang sama berdampingan dalam
grafik dependensi yang diselesaikan.
Anda dapat menentukan daftar eksplisit versi yang diizinkan untuk modul, yang semuanya harus ada dalam grafik dependensi sebelum resolusi — harus ada beberapa dependensi transitif yang bergantung pada setiap versi yang diizinkan. Setelah resolusi, hanya versi modul yang diizinkan yang tetap ada, sedangkan Bazel mengupgrade versi modul lainnya ke versi terdekat yang lebih tinggi yang diizinkan pada tingkat kompatibilitas yang sama. Jika tidak ada versi lebih tinggi yang diizinkan pada tingkat kompatibilitas yang sama, Bazel akan menampilkan error.
Misalnya, jika versi 1.1
, 1.3
, 1.5
, 1.7
, dan 2.0
ada dalam
grafik dependensi sebelum resolusi, dan versi utamanya adalah tingkat
kompatibilitas:
- Penggantian beberapa versi yang memungkinkan
1.3
,1.7
, dan2.0
menyebabkan1.1
diupgrade ke1.3
,1.5
diupgrade ke1.7
, dan versi lainnya tetap sama. - Penggantian beberapa versi yang memungkinkan
1.5
dan2.0
menghasilkan error, karena1.7
tidak memiliki versi yang lebih tinggi pada tingkat kompatibilitas yang sama untuk diupgrade. - Penggantian multi-versi yang memungkinkan
1.9
dan2.0
menghasilkan error, karena1.9
tidak ada dalam grafik dependensi sebelum resolusi.
Selain itu, pengguna juga dapat mengganti registry menggunakan atribut registry
, seperti penggantian versi tunggal.
Penggantian non-registry
Penggantian non-registry sepenuhnya menghapus modul dari resolusi versi. Bazel
tidak meminta file MODULE.bazel
ini dari registry, melainkan dari
repo itu sendiri.
Bazel mendukung penggantian non-registry berikut:
Nama repositori dan dependensi ketat
Nama kanonis repo yang mendukung modul adalah module_name~version
(misalnya, bazel_skylib~1.0.3
). Untuk modul dengan penggantian non-registry, ganti bagian version
dengan string override
. Perhatikan bahwa format nama kanonis bukan API yang harus Anda andalkan dan dapat berubah kapan saja.
Nama jelas repo yang mendukung
modul ke dependensi langsungnya secara default disetel ke nama modulnya, kecuali jika
atribut repo_name
dari perintah bazel_dep
menyatakan sebaliknya. Perlu diperhatikan bahwa ini berarti modul hanya dapat menemukan dependensi
langsungnya. Hal ini membantu mencegah kerusakan yang tidak disengaja akibat perubahan
dependensi transitif.
Ekstensi modul juga dapat memasukkan repositori tambahan ke dalam cakupan modul yang terlihat.