Tệp Bazel Lockfile

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

Tính năng tệp khoá trong Bazel cho phép ghi lại các phiên bản hoặc phần phụ thuộc của thư viện phần mềm hoặc gói mà dự án yêu cầu. Để làm được như vậy, phương thức này lưu trữ kết quả của quá trình phân giải mô-đun và đánh giá tiện ích. Tệp khoá thúc đẩy các bản dựng có thể tái tạo, đảm bảo môi trường phát triển nhất quán. Ngoài ra, tính năng này còn giúp nâng cao hiệu suất của bản dựng bằng cách cho phép Bazel bỏ qua những phần trong quy trình phân giải không bị ảnh hưởng bởi những thay đổi trong các phần phụ thuộc của dự án. Hơn nữa, tệp khoá còn cải thiện độ ổn định bằng cách ngăn chặn những thay đổi không mong muốn hoặc có thể gây lỗi trong thư viện bên ngoài, nhờ đó làm giảm nguy cơ gây ra lỗi.

Tạo tệp Lockfile

Tệp khoá được tạo trong thư mục gốc của không gian làm việc có tên là MODULE.bazel.lock. Tệp này được tạo hoặc cập nhật trong quá trình xây dựng, cụ thể là sau khi đánh giá tiện ích và độ phân giải mô-đun. Quan trọng là API này chỉ bao gồm các phần phụ thuộc có trong lệnh gọi hiện tại của bản dựng.

Khi những thay đổi xảy ra trong dự án ảnh hưởng đến các phần phụ thuộc của dự án, tệp khoá sẽ tự động được cập nhật để phản ánh trạng thái mới. Điều này đảm bảo rằng tệp khoá vẫn tập trung vào tập hợp phần phụ thuộc cụ thể cần thiết cho bản dựng hiện tại, cung cấp bản trình bày chính xác các phần phụ thuộc đã được phân giải của dự án.

Sử dụng tệp Lockfile

Tệp khoá có thể được kiểm soát bằng cờ --lockfile_mode để tuỳ chỉnh hành vi của Bazel khi trạng thái dự án khác với tệp khoá. Các chế độ hiện có là:

  • update (Mặc định): Sử dụng thông tin có trong tệp khoá để bỏ qua việc tải các tệp sổ đăng ký đã biết xuống và tránh đánh giá lại các tiện ích có kết quả mới nhất. Nếu thiếu thông tin, thông tin đó sẽ được thêm vào tệp khoá. Ở chế độ này, Bazel cũng tránh làm mới thông tin có thể biến đổi (chẳng hạn như phiên bản được kéo) cho các phần phụ thuộc chưa thay đổi.
  • refresh: Giống như update, nhưng thông tin có thể thay đổi luôn được làm mới khi chuyển sang chế độ này và khoảng mỗi giờ khi ở chế độ này.
  • error: Giống như update, nhưng nếu bất kỳ thông tin nào bị thiếu hoặc đã lỗi thời, thì Baazel sẽ không hoạt động do lỗi. Chế độ này không bao giờ thay đổi tệp khoá hoặc thực hiện các yêu cầu mạng trong quá trình phân giải. Các tiện ích mô-đun tự đánh dấu là reproducible vẫn có thể thực hiện các yêu cầu mạng, nhưng dự kiến sẽ luôn cho ra kết quả tương tự.
  • off: Tệp khoá chưa được kiểm tra cũng như không cập nhật.

Lợi ích của Lockfile

Tệp khóa mang lại nhiều lợi ích và có thể được sử dụng theo nhiều cách khác nhau:

  • Bản dựng có thể tái tạo. Bằng cách ghi lại các phiên bản hoặc phần phụ thuộc cụ thể của thư viện phần mềm, tệp khoá đảm bảo rằng các bản dựng có thể tái tạo được trên nhiều môi trường và theo thời gian. Nhà phát triển có thể dựa vào kết quả nhất quán và dự đoán được khi xây dựng dự án.

  • Độ phân giải gia tăng nhanh. Tệp khoá cho phép Bazel tránh tải các tệp đăng ký đã được dùng trong bản dựng trước đó xuống. Điều này giúp cải thiện đáng kể hiệu quả của bản dựng, đặc biệt là trong các tình huống có thể tốn thời gian giải quyết.

  • Độ ổn định và giảm rủi ro. Tệp khoá giúp duy trì độ ổn định bằng cách ngăn chặn những thay đổi không mong muốn hoặc có thể gây lỗi trong thư viện bên ngoài. Bằng cách khoá các phần phụ thuộc với các phiên bản cụ thể, nguy cơ gây ra lỗi do các bản cập nhật không tương thích hoặc chưa được kiểm thử sẽ giảm.

Nội dung tệp khoá

Tệp khoá chứa tất cả thông tin cần thiết để xác định xem trạng thái dự án đã thay đổi hay chưa. Nó cũng bao gồm kết quả của việc xây dựng dự án ở trạng thái hiện tại. Tệp khoá bao gồm hai phần chính:

  1. Hàm băm của tất cả tệp từ xa là dữ liệu đầu vào để phân giải mô-đun.
  2. Đối với mỗi tiện ích mô-đun, tệp khoá bao gồm các dữ liệu đầu vào ảnh hưởng đến tiện ích đó, được biểu thị bằng bzlTransitiveDigest, usagesDigest và các trường khác, cũng như kết quả khi chạy tiện ích đó, được gọi là generatedRepoSpecs

Dưới đây là ví dụ minh hoạ cấu trúc của tệp khoá, cùng với nội dung giải thích cho từng phần:

{
  "lockFileVersion": 10,
  "registryFileHashes": {
    "https://bcr.bazel.build/bazel_registry.json": "8a28e4af...5d5b3497",
    "https://bcr.bazel.build/modules/foo/1.0/MODULE.bazel": "7cd0312e...5c96ace2",
    "https://bcr.bazel.build/modules/foo/2.0/MODULE.bazel": "70390338... 9fc57589",
    "https://bcr.bazel.build/modules/foo/2.0/source.json": "7e3a9adf...170d94ad",
    "https://registry.mycorp.com/modules/foo/1.0/MODULE.bazel": "not found",
    ...
  },
  "selectedYankedVersions": {
    "foo@2.0": "Yanked for demo purposes"
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "general": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "bzlTransitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "bzlTransitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "usagesDigest": "aLmqbvowmHkkBPve05y....yDNGN7oh7r3QIZTZs=",
        ...,
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

Hàm băm tệp đăng ký

Phần registryFileHashes chứa hàm băm của mọi tệp từ sổ đăng ký từ xa được truy cập trong quá trình phân giải mô-đun. Vì thuật toán độ phân giải mang tính quyết định hoàn toàn khi đưa ra cùng một dữ liệu đầu vào và tất cả các dữ liệu đầu vào từ xa đều được băm, nên điều này đảm bảo kết quả phân giải có thể tái tạo đầy đủ, đồng thời tránh việc sao chép quá nhiều thông tin từ xa trong tệp khoá. Xin lưu ý rằng thao tác này cũng yêu cầu ghi lại khi một sổ đăng ký cụ thể không chứa một mô-đun nhất định, nhưng sổ đăng ký có mức độ ưu tiên thấp hơn thì lại chứa (xem mục "không tìm thấy" trong ví dụ). Bạn có thể cập nhật thông tin vốn có thể thay đổi này thông qua bazel mod deps --lockfile_mode=refresh.

Bazel sử dụng các hàm băm từ tệp khoá để tra cứu các tệp đăng ký trong bộ nhớ đệm của kho lưu trữ trước khi tải xuống, nhờ đó tăng tốc độ phân giải tiếp theo.

Các phiên bản Yanked đã chọn

Phần selectedYankedVersions chứa phiên bản được trích dẫn của các mô-đun được chọn theo độ phân giải của mô-đun. Vì điều này thường dẫn đến lỗi khi cố gắng xây dựng, nên phần này chỉ có nội dung không trống khi các phiên bản được trích xuất được cho phép một cách rõ ràng thông qua --allow_yanked_versions hoặc BZLMOD_ALLOW_YANKED_VERSIONS.

Trường này là cần thiết vì so với các tệp mô-đun, thông tin phiên bản được kéo vốn có khả năng thay đổi và do đó không thể tham chiếu bằng hàm băm. Bạn có thể cập nhật thông tin này qua bazel mod deps --lockfile_mode=refresh.

Tiện ích mô-đun

Mục moduleExtensions là một bản đồ chỉ bao gồm các tiện ích được dùng trong lệnh gọi hiện tại hoặc đã được gọi trước đó, đồng thời loại trừ mọi tiện ích không còn được sử dụng. Nói cách khác, nếu một tiện ích hiện không được dùng nữa trên biểu đồ phần phụ thuộc, thì tiện ích đó sẽ bị xoá khỏi bản đồ moduleExtensions.

Nếu một tiện ích độc lập với loại hệ điều hành hoặc cấu trúc, thì phần này chỉ có một mục nhập "chung". Nếu không, nhiều mục nhập sẽ được đưa vào, đặt tên theo hệ điều hành, cấu trúc hoặc cả hai, trong đó mỗi mục tương ứng với kết quả đánh giá tiện ích dựa trên những thông tin cụ thể đó.

Mỗi mục trong bản đồ tiện ích tương ứng với một tiện ích đã sử dụng và được xác định bằng tệp và tên chứa tiện ích đó. Giá trị tương ứng của mỗi mục nhập chứa thông tin liên quan đến tiện ích đó:

  1. bzlTransitiveDigest là chuỗi đại diện trong quá trình triển khai tiện ích và các tệp .bzl được tải bắc cầu.
  2. usagesDigest là chuỗi đại diện sử dụng tiện ích trong biểu đồ phần phụ thuộc, bao gồm tất cả các thẻ.
  3. Các trường không xác định khác giúp theo dõi dữ liệu đầu vào khác vào tiện ích, chẳng hạn như nội dung của các tệp hoặc thư mục mà tiện ích đọc hoặc các biến môi trường mà tiện ích sử dụng.
  4. generatedRepoSpecs mã hoá những kho lưu trữ do tiện ích tạo bằng dữ liệu đầu vào hiện tại.
  5. Trường moduleExtensionMetadata không bắt buộc chứa siêu dữ liệu do tiện ích cung cấp, chẳng hạn như mô-đun gốc có nên nhập một số kho lưu trữ nhất định mà tiện ích tạo ra qua use_repo hay không. Thông tin này hỗ trợ lệnh bazel mod tidy.

Các tiện ích mô-đun có thể chọn không đưa vào tệp khoá bằng cách đặt siêu dữ liệu trả về bằng reproducible = True. Bằng cách làm như vậy, họ hứa hẹn rằng họ sẽ luôn tạo cùng một kho lưu trữ khi được cung cấp cùng một dữ liệu đầu vào.

Những phương pháp hay nhất

Để tối đa hoá lợi ích của tính năng tệp khoá, hãy cân nhắc các phương pháp hay nhất sau đây:

  • Thường xuyên cập nhật tệp khoá để phản ánh những thay đổi trong các phần phụ thuộc hoặc cấu hình của dự án. Điều này đảm bảo rằng các bản dựng tiếp theo sẽ dựa trên tập hợp phần phụ thuộc mới nhất và chính xác nhất. Để khoá tất cả tiện ích cùng một lúc, hãy chạy bazel mod deps --lockfile_mode=update.

  • Đưa tệp khoá vào chế độ quản lý phiên bản để hỗ trợ việc cộng tác và đảm bảo rằng tất cả thành viên trong nhóm đều có quyền truy cập vào cùng một tệp khoá, giúp thúc đẩy các môi trường phát triển nhất quán trên toàn dự án.

  • Sử dụng bazelisk để chạy Bazel và đưa tệp .bazelversion vào quy trình quản lý phiên bản để chỉ định phiên bản Bazel tương ứng với tệp khoá. Vì bản thân Bazel là một phần phụ thuộc của bản dựng, nên tệp khoá dành riêng cho phiên bản Bazel và sẽ thay đổi ngay cả giữa các bản phát hành Bazel tương thích ngược. Việc sử dụng bazelisk đảm bảo rằng tất cả các nhà phát triển đều đang sử dụng phiên bản Bazel khớp với tệp khoá.

Bằng cách làm theo các phương pháp hay nhất này, bạn có thể sử dụng hiệu quả tính năng tệp khoá trong Bazel, từ đó mang đến quy trình phát triển phần mềm cộng tác, đáng tin cậy và hiệu quả hơn.