Tiện ích mô-đun cho phép người dùng mở rộng hệ thống mô-đun bằng cách đọc dữ liệu đầu vào từ các mô-đun trên biểu đồ phần phụ thuộc, thực hiện logic cần thiết để phân giải phần phụ thuộc và cuối cùng là tạo repo bằng cách gọi các quy tắc repo. Các tiện ích này có các khả năng tương tự như quy tắc repo, cho phép chúng thực hiện thao tác I/O tệp, gửi yêu cầu mạng, v.v. Ngoài ra, chúng cho phép Bazel tương tác với các hệ thống quản lý gói khác trong khi vẫn tuân thủ biểu đồ phần phụ thuộc được tạo từ các mô-đun Bazel.
Bạn có thể xác định các phần mở rộng của mô-đun trong các tệp .bzl
, giống như quy tắc kho lưu trữ. Đó là
không được gọi trực tiếp; thay vào đó, mỗi mô-đun chỉ định các phần dữ liệu được gọi là thẻ
để tiện ích đọc. Bazel chạy quá trình phân giải mô-đun trước khi đánh giá bất kỳ
tiện ích. Tiện ích này đọc tất cả thẻ thuộc về nó trên toàn bộ
biểu đồ phần phụ thuộc.
Mức sử dụng tiện ích
Các tiện ích được lưu trữ trong chính các mô-đun Bazel. Để sử dụng tiện ích trong một
mô-đun, trước tiên hãy thêm bazel_dep
trên mô-đun lưu trữ tiện ích, sau đó
gọi hàm tích hợp use_extension
để đưa nó vào phạm vi. Hãy xem ví dụ sau: một đoạn trích từ
Tệp MODULE.bazel
để sử dụng "maven" tiện ích mở rộng được xác định trong
rules_jvm_external
mô-đun:
bazel_dep(name = "rules_jvm_external", version = "4.5")
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
Thao tác này liên kết giá trị trả về của use_extension
với một biến, cho phép
người dùng sử dụng cú pháp dấu chấm để chỉ định thẻ cho tiện ích. Các thẻ phải tuân thủ
giản đồ được xác định bởi các lớp thẻ tương ứng được chỉ định trong
định nghĩa phần mở rộng. Ví dụ: chỉ định một số
Thẻ maven.install
và maven.artifact
:
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"])
Sử dụng lệnh use_repo
để khôi phục kho lưu trữ
do tiện ích tạo ra trong phạm vi của mô-đun hiện tại.
use_repo(maven, "maven")
Các kho lưu trữ do tiện ích tạo ra sẽ là một phần của API của tiện ích đó. Trong ví dụ này, phương thức
"maven" tiện ích mô-đun hứa hẹn sẽ tạo một kho lưu trữ có tên là maven
. Với
khai báo ở trên, tiện ích này sẽ giải quyết đúng cách các nhãn như
@maven//:org_junit_junit
để trỏ đến kho lưu trữ do "maven" tạo ra
tiện ích.
Định nghĩa phần mở rộng
Bạn có thể xác định tiện ích mô-đun tương tự như quy tắc kho lưu trữ, bằng cách sử dụng
Hàm module_extension
. Tuy nhiên,
trong khi quy tắc repo có một số thuộc tính, thì tiện ích mô-đun có
tag_class
es, mỗi thuộc tính có một số
. Các lớp thẻ xác định giản đồ cho thẻ mà tiện ích này sử dụng. Để
ví dụ: "maven" tiện ích mở rộng ở trên có thể được xác định như sau:
# @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},
)
Những thông tin khai báo này cho thấy rằng các thẻ maven.install
và maven.artifact
có thể
được chỉ định bằng giản đồ thuộc tính đã chỉ định.
Chức năng triển khai của phần mở rộng mô-đun cũng tương tự như các tiện ích của kho lưu trữ
ngoại trừ việc chúng nhận được đối tượng module_ctx
,
Tuỳ chọn này cấp quyền truy cập vào tất cả các mô-đun sử dụng tiện ích và tất cả các thẻ liên quan.
Sau đó, hàm triển khai này sẽ gọi các quy tắc kho lưu trữ để tạo kho lưu trữ.
# @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)
Thông tin nhận dạng của tiện ích
Các đuôi mô-đun được xác định theo tên và tệp .bzl
xuất hiện
trong cuộc gọi đến use_extension
. Trong ví dụ sau, tiện ích maven
được xác định bởi tệp .bzl
@rules_jvm_external//:extension.bzl
và
tên maven
:
maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
Việc xuất lại một tiện ích từ một tệp .bzl
khác sẽ cung cấp cho tiện ích đó một danh tính mới
và nếu cả hai phiên bản của phần mở rộng đều được sử dụng trong đồ thị mô-đun bắc cầu,
thì chúng sẽ được đánh giá riêng và sẽ chỉ nhìn thấy các thẻ được liên kết
với danh tính cụ thể đó.
Là tác giả của tiện ích, bạn phải đảm bảo rằng người dùng sẽ chỉ sử dụng
đuôi mô-đun từ một tệp .bzl
duy nhất.
Tên và chế độ hiển thị kho lưu trữ
Các kho lưu trữ do tiện ích tạo ra có tên chuẩn ở dạng module_repo_canonical_name~extension_name~repo_name
. Đối với tiện ích được lưu trữ trong
mô-đun gốc, phần module_repo_canonical_name
là
được thay thế bằng chuỗi _main
. Lưu ý rằng định dạng tên chuẩn không phải là
API mà bạn nên phụ thuộc. API này có thể thay đổi bất cứ lúc nào.
Chính sách đặt tên này có nghĩa là mỗi tiện ích đều có "không gian tên kho lưu trữ" riêng; hai
mỗi tiện ích có thể xác định một repo có cùng tên mà không gây rủi ro
bất kỳ xung đột nào. Điều này cũng có nghĩa là repository_ctx.name
báo cáo tên chính tắc
của repo, không giống với tên được chỉ định trong quy tắc repo
.
Xem xét các kho lưu trữ do các tiện ích mô-đun tạo ra, có một số quy tắc chế độ hiển thị repo:
- Kho lưu trữ mô-đun Bazel có thể xem tất cả các kho lưu trữ được giới thiệu trong tệp
MODULE.bazel
quabazel_dep
vàuse_repo
. - Một kho lưu trữ do tiện ích mô-đun tạo ra có thể xem tất cả các kho lưu trữ hiển thị với
mô-đun lưu trữ tiện ích, cùng với tất cả các kho lưu trữ khác do
cùng một tiện ích mô-đun (sử dụng các tên được chỉ định trong các lệnh gọi quy tắc repo dưới dạng
tên rõ ràng của chúng).
- Điều này có thể dẫn đến xung đột. Nếu kho lưu trữ mô-đun có thể thấy một kho lưu trữ có
tên rõ ràng
foo
, đồng thời tiện ích này tạo ra một kho lưu trữ có tên được chỉ địnhfoo
, thì cho tất cả các kho lưu trữ do tiện ích đó tạo rafoo
đề cập đến phương thức cũ.
- Điều này có thể dẫn đến xung đột. Nếu kho lưu trữ mô-đun có thể thấy một kho lưu trữ có
tên rõ ràng
Các phương pháp hay nhất
Phần này mô tả các phương pháp hay nhất khi viết phần mở rộng để chúng dễ sử dụng, dễ bảo trì và thích ứng tốt với những thay đổi theo thời gian.
Đặt mỗi tiện ích vào một tệp riêng
Khi tiện ích nằm trong một tệp khác, tiện ích sẽ cho phép một tiện ích tải kho lưu trữ được tạo bởi tiện ích khác. Ngay cả khi bạn không sử dụng chức năng của thiết bị, tốt nhất bạn nên đặt chúng vào các tệp riêng phòng khi cần sau. Điều này là do danh tính của tiện ích dựa trên tệp của tiện ích đó, nên việc di chuyển tiện ích mở rộng này thành một tệp khác, sau đó thay đổi API công khai của bạn và là một phiên bản ngược thay đổi không tương thích cho người dùng của bạn.
Chỉ định hệ điều hành và cấu trúc
Nếu tiện ích của bạn dựa vào hệ điều hành hoặc loại cấu trúc của hệ điều hành,
hãy nhớ nêu rõ điều này trong định nghĩa tiện ích bằng cách sử dụng os_dependent
và arch_dependent
thuộc tính boolean Điều này đảm bảo rằng Bazel nhận ra
cần được đánh giá lại xem có thay đổi nào đối với một trong hai chỉ số đó hay không.
Chỉ mô-đun gốc mới ảnh hưởng trực tiếp đến tên kho lưu trữ
Hãy nhớ rằng khi một tiện ích tạo kho lưu trữ, các kho lưu trữ đó sẽ được tạo trong
không gian tên của tiện ích. Điều này có nghĩa là có thể xảy ra xung đột nếu
các mô-đun sử dụng cùng một phần mở rộng và kết thúc bằng việc tạo ra một kho lưu trữ có cùng một phần
. Tệp này thường thể hiện dưới dạng tag_class
của tiện ích mô-đun có name
đối số được truyền dưới dạng giá trị name
của quy tắc kho lưu trữ.
Ví dụ: giả sử mô-đun gốc là A
phụ thuộc vào mô-đun B
. Cả hai mô-đun
phụ thuộc vào mô-đun mylang
. Nếu cả A
và B
đều gọi
mylang.toolchain(name="foo")
, cả hai sẽ cố gắng tạo một kho lưu trữ có tên
foo
trong mô-đun mylang
nên sẽ xảy ra lỗi.
Để tránh điều này, hãy xoá khả năng thiết lập tên kho lưu trữ trực tiếp, hoặc chỉ cho phép mô-đun gốc làm như vậy. Bạn có thể cho phép mô-đun gốc này vì không có gì phụ thuộc vào nó, nên không phải lo lắng về một mô-đun khác tạo ra tên xung đột.