Quy tắc kho lưu trữ

Báo cáo sự cố Xem nguồn

Trang này trình bày cách xác định các quy tắc kho lưu trữ và cung cấp các ví dụ để biết thêm thông tin chi tiết.

Kho lưu trữ bên ngoài là một cây thư mục, chứa các tệp nguồn có thể sử dụng được trong bản dựng Bazel. Hệ thống này được tạo theo yêu cầu bằng cách chạy quy tắc kho lưu trữ tương ứng. Repo có thể được xác định theo nhiều cách, nhưng cuối cùng, mỗi kho lưu trữ được xác định bằng cách gọi quy tắc kho lưu trữ, giống như các mục tiêu bản dựng được xác định bằng cách gọi quy tắc bản dựng. Bạn có thể dùng các tệp này để phụ thuộc vào các thư viện bên thứ ba (chẳng hạn như các thư viện đóng gói Maven) cũng như để tạo các tệp BUILD dành riêng cho máy chủ lưu trữ mà Bazel đang chạy.

Định nghĩa quy tắc kho lưu trữ

Trong tệp .bzl, hãy dùng hàm repository_rule để xác định quy tắc kho lưu trữ mới và lưu trữ quy tắc đó trong biến toàn cục. Sau khi xác định quy tắc kho lưu trữ, hệ thống có thể gọi quy tắc này dưới dạng một hàm để xác định kho lưu trữ. Lệnh gọi này thường được thực hiện từ bên trong hàm triển khai tiện ích mô-đun.

Hai thành phần chính của định nghĩa quy tắc kho lưu trữ là giản đồ thuộc tính và hàm triển khai. Giản đồ thuộc tính xác định tên và loại thuộc tính được chuyển đến lệnh gọi quy tắc kho lưu trữ và hàm triển khai sẽ được chạy khi cần tìm nạp kho lưu trữ.

Thuộc tính

Thuộc tính là các đối số được chuyển đến lệnh gọi quy tắc kho lưu trữ. Giản đồ của các thuộc tính được quy tắc kho lưu trữ chấp nhận được chỉ định bằng cách sử dụng đối số attrs khi quy tắc kho lưu trữ được xác định bằng lệnh gọi đến repository_rule. Ví dụ về việc xác định các thuộc tính urlsha256 dưới dạng chuỗi:

http_archive = repository_rule(
    implementation=_impl,
    local=True,
    attrs={
        "url": attr.string(mandatory=True)
        "sha256": attr.string(mandatory=True)
    }
)

Để truy cập vào một thuộc tính trong hàm triển khai, hãy sử dụng repository_ctx.attr.<attribute_name>:

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

Mọi repository_rule đều có thuộc tính được xác định ngầm name. Đây là một thuộc tính chuỗi hoạt động có phần kỳ diệu: khi được chỉ định làm dữ liệu đầu vào cho lệnh gọi quy tắc kho lưu trữ, hệ thống sẽ lấy một tên kho lưu trữ rõ ràng; nhưng khi được đọc từ hàm triển khai của quy tắc kho lưu trữ bằng repository_ctx.attr.name, thuộc tính này sẽ trả về tên kho lưu trữ chính tắc.

Hàm triển khai

Mỗi quy tắc kho lưu trữ yêu cầu hàm implementation. Thành phần này chứa logic thực tế của quy tắc và được thực thi nghiêm ngặt trong Giai đoạn tải.

Hàm có đúng một tham số đầu vào là repository_ctx. Hàm trả về None để biểu thị rằng quy tắc có thể tạo lại nhờ các tham số đã chỉ định hoặc một lệnh với tập hợp các tham số cho quy tắc đó sẽ biến quy tắc đó thành một quy tắc có thể mô phỏng tạo cùng một kho lưu trữ. Ví dụ: đối với một quy tắc theo dõi kho lưu trữ git, tức là trả về một giá trị nhận dạng cam kết cụ thể thay vì một nhánh nổi đã được chỉ định ban đầu.

Bạn có thể dùng tham số đầu vào repository_ctx để truy cập vào các giá trị thuộc tính và các hàm không ẩn (tìm tệp nhị phân, thực thi tệp nhị phân, tạo tệp trong kho lưu trữ hoặc tải tệp xuống từ Internet). Hãy xem tài liệu về API để biết thêm thông tin liên quan. Ví dụ:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

Khi nào hàm triển khai được thực thi?

Hàm triển khai quy tắc kho lưu trữ được thực thi khi Bazel cần một mục tiêu từ kho lưu trữ đó, chẳng hạn như khi một mục tiêu khác (trong một kho lưu trữ khác) phụ thuộc vào mục tiêu đó hoặc nếu mục tiêu được đề cập trên dòng lệnh. Sau đó, hàm triển khai dự kiến sẽ tạo kho lưu trữ trong hệ thống tệp. Quá trình này được gọi là "tìm nạp" kho lưu trữ.

Trái ngược với các mục tiêu thông thường, kho lưu trữ không nhất thiết phải tìm nạp lại khi có thay đổi nào đó sẽ khiến kho lưu trữ khác đi. Nguyên nhân là do có những thứ mà Bazel không thể phát hiện được các thay đổi hoặc sẽ gây ra quá nhiều chi phí cho mỗi bản dựng (ví dụ: những thứ được tìm nạp từ mạng). Do đó, kho lưu trữ chỉ được tìm nạp lại nếu một trong những điều sau thay đổi:

  • Các thuộc tính được chuyển đến lệnh gọi quy tắc kho lưu trữ.
  • Mã Starlark bao gồm việc triển khai quy tắc kho lưu trữ.
  • Giá trị của mọi biến môi trường được truyền đến phương thức getenv() của repository_ctx hoặc được khai báo bằng thuộc tính environ của repository_rule. Giá trị của các biến môi trường này có thể được cố định trong dòng lệnh bằng cờ --repo_env.
  • Nội dung của mọi tệp được truyền đến read(), execute() và các phương thức tương tự của repository_ctx được một nhãn tham chiếu (ví dụ: //mypkg:label.txt chứ không phải mypkg/label.txt)
  • Khi bazel fetch --force được thực thi.

Có 2 tham số của repository_rule kiểm soát thời điểm tìm nạp lại kho lưu trữ:

  • Nếu cờ configure được thiết lập, kho lưu trữ chỉ được tìm nạp lại trên bazel fetch khi tham số --configure được truyền vào kho lưu trữ đó (nếu thuộc tính không được đặt, lệnh này sẽ không gây ra việc tìm nạp lại)
  • Nếu bạn đặt cờ local, thì ngoài các trường hợp trên, kho lưu trữ cũng được tìm nạp lại khi máy chủ Bazel khởi động lại.

Khởi động lại hàm triển khai

Bạn có thể khởi động lại hàm triển khai trong khi kho lưu trữ đang được tìm nạp nếu một phần phụ thuộc mà kho lưu trữ yêu cầu bị thiếu. Trong trường hợp đó, quá trình thực thi hàm triển khai sẽ dừng lại, phần phụ thuộc bị thiếu sẽ được giải quyết và hàm sẽ được thực thi lại sau khi phần phụ thuộc đã được giải quyết. Để tránh việc khởi động lại không cần thiết (tốn kém, vì quyền truy cập mạng có thể phải lặp lại), đối số nhãn sẽ được tìm nạp trước, miễn là tất cả đối số nhãn đều có thể được phân giải thành tệp hiện có. Xin lưu ý rằng việc phân giải một đường dẫn từ một chuỗi hoặc một nhãn chỉ được tạo trong quá trình thực thi hàm vẫn có thể gây ra việc khởi động lại.

Buộc tìm nạp lại các kho lưu trữ bên ngoài

Đôi khi, một kho lưu trữ bên ngoài có thể trở nên lỗi thời mà không có bất kỳ thay đổi nào đối với định nghĩa hoặc các phần phụ thuộc của kho lưu trữ đó. Ví dụ: một kho lưu trữ tìm nạp các nguồn có thể tuân theo một nhánh cụ thể của kho lưu trữ bên thứ ba, và các thay đổi mới có sẵn trên nhánh đó. Trong trường hợp này, bạn có thể yêu cầu bazel tìm nạp lại vô điều kiện tất cả các kho lưu trữ bên ngoài bằng cách gọi bazel fetch --force --all.

Hơn nữa, một số quy tắc kho lưu trữ kiểm tra máy cục bộ và có thể trở nên lỗi thời nếu máy cục bộ được nâng cấp. Tại đây, bạn có thể yêu cầu Bazel chỉ tìm nạp lại các kho lưu trữ bên ngoài đó, trong đó định nghĩa repository_rule có bộ thuộc tính configure được đặt, hãy sử dụng bazel fetch --all --configure.

Ví dụ

  • Chuỗi công cụ định cấu hình tự động C++: chuỗi này sử dụng quy tắc kho lưu trữ để tự động tạo các tệp cấu hình C++ cho Bazel bằng cách tìm trình biên dịch C++ cục bộ, môi trường và cờ mà trình biên dịch C++ hỗ trợ.

  • Kho lưu trữ Go sử dụng một số repository_rule để xác định danh sách các phần phụ thuộc cần thiết để sử dụng quy tắc Go.

  • rules_jvm_external sẽ tạo một kho lưu trữ bên ngoài có tên là @maven theo mặc định. Kho lưu trữ này tạo mục tiêu bản dựng cho mọi cấu phần phần mềm Maven trong cây phần phụ thuộc bắc cầu.