Tệp Bazel Lockfile

Báo cáo vấn đề Xem nguồn Hằng đêm · 7.3 · 7.2 · 7.1 · 7 · 6,5

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. Nó đạt được điều này bằng cách lưu trữ kết quả của độ phân giải và tiện ích mở rộng mô-đun đánh giá. Tệp Lockfile thúc đẩy các bản dựng có thể tái tạo, đảm bảo tính nhất quán môi trường phát triển riêng biệt. Ngoài ra, tính năng này còn nâng cao hiệu quả của bản dựng bằng cách cho phép Bazel để bỏ qua những phần không bị ảnh hưởng của các thay đổi trong quy trình giải quyết 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 các thay đổi không mong muốn hoặc có thể gây lỗi trong thư viện bên ngoài, do đó 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 với tên MODULE.bazel.lock. Mã này được tạo hoặc cập nhật trong quá trình xây dựng, đặc biệt là sau khi đánh giá độ phân giải và tiện ích của mô-đun. Quan trọng là chỉ bao gồm các phần phụ thuộc có trong lệnh gọi hiện tại của phương thức bản dựng.

Khi các 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ậ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, cung cấp bản trình bày chính xác về dự án đã được giải quyết phần phụ thuộc.

Sử dụng tệp Lockfile

Tệp khoá có thể được kiểm soát bằng cờ này --lockfile_mode đến 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 đăng ký đã biết xuống cũng như tránh việc đánh giá lại tiện ích kết quả của họ vẫn được cập nhật. Nếu thiếu thông tin, đượ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ể thay đổi, chẳng hạn như các 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 có thông tin nào bị thiếu hoặc đã lỗi thời, Bazel sẽ không thành công và có lỗi. Chế độ này không bao giờ thay đổi tệp khoá hoặc thực hiện yêu cầu mạng trong quá trình phân giải. Tiện ích mô-đun được đánh dấu vì 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ả giống nhau.
  • 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 các 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 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ễ dự đoán 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 xuống tệp đăng ký đã được sử dụng trong bản dựng trước. Đ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 trường hợp việc giải quyết vấn đề có thể tốn thời gian.

  • Độ ổn định và giảm rủi ro. Tệp Lockfile giúp duy trì sự ổn định bằng cách ngăn chặn các thay đổi không mong muốn hoặc có thể gây lỗi trong thư viện bên ngoài. Theo khoá các phần phụ thuộc thành các phiên bản cụ thể, dẫn đến nguy cơ gây ra lỗi do số lượng bản cập nhật không tương thích hoặc chưa được kiểm thử đã bị 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. Báo cáo này cũng bao gồm kết quả của quá trình 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, như 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 tất cả các tệp trong truy cập vào sổ đăng ký từ xa trong quá trình phân giải mô-đun. Vì độ phân giải thuật toán có tính xác định hoàn toàn khi được cung cấp cùng một đầu vào và tất cả điều khiển từ xa dữ liệu đầu vào được băm, điều này đảm bảo kết quả giải quyết có thể tái tạo đầy đủ trong khi tránh việc sao chép quá nhiều thông tin từ xa trong tệp khoá. 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ô-đun, nhưng sổ đăng ký có mức độ ưu tiên thấp hơn đã làm (xem mục "not found" (không tìm thấy) trong ví dụ). Thông tin vốn có khả năng thay đổi này có thể được cập nhật qua bazel mod deps --lockfile_mode=refresh.

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

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

Phần selectedYankedVersions chứa các phiên bản được kéo của các mô-đun được chọn theo độ phân giải mô-đun. Vì việc này thường dẫn đến lỗi khi cố gắng tạo, phần này sẽ chỉ trống khi các phiên bản được kéo được cho phép rõ rà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 trích dẫn vốn có thể thay đổi và do đó không thể tham chiếu bằng hàm băm. Thông tin này có thể được cập nhật 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 sử 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 tiện ích không được sử dụng trên biểu đồ phần phụ thuộc, thì phần này sẽ bị xoá khỏi moduleExtensions bản đồ.

Nếu một tiện ích độc lập với loại hệ điều hành hoặc loại cấu trúc, phần này chỉ có một "chung" duy nhất mục nhập. Nếu không, nhiều các mục nhập được bao gồm, được đặ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á phần mở rộng dựa trên những thông tin cụ thể đó.

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

  1. bzlTransitiveDigest là thông báo 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 cho việc 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 theo dõi các dữ liệu đầu vào khác vào tiện ích, chẳng hạn như nội dung của tệp hoặc thư mục mà công cụ đọc hoặc môi trường các biến mà nó sử dụng.
  4. generatedRepoSpecs mã hoá các kho lưu trữ do với đầ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 chẳng hạn như các kho lưu trữ nhất định mà nó đã tạo được mô-đun gốc nhập qua use_repo. 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 trả về siêu dữ liệu bằng reproducible = True. Bằng cách làm như vậy, họ cam kết rằng chúng 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.

Các 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 những điều tốt nhất sau đây thực tiễn:

  • 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 của dự án hoặc . Điều này giúp đảm bảo rằng các bản dựng tiếp theo được dựa trên được cập nhật và chính xác về các phần phụ thuộc. Cách khoá mọi tiện ích chạy bazel mod deps --lockfile_mode=update cùng một lúc.

  • Đưa tệp khoá vào trình quản lý phiên bản để tạo điều kiện 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á, môi trường phát triển nhất quán trong suốt dự án.

  • Sử dụng bazelisk để chạy Bazel và đưa vào Tệp .bazelversion trong phần quản lý phiên bản chỉ định phiên bản Bazel tương ứng với tệp khoá. Bởi vì bản thân Bazel là phần phụ thuộc của bản dựng của bạn, tệp lockfile dành riêng cho phiên bản Bazel và sẽ thay đổi ngay cả giữa tương thích ngược Bản phát hành của Bazel. Việc sử dụng bazelisk giúp đảm bảo rằng tất cả nhà phát triển đang sử dụng một 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 tệp khoá một cách hiệu quả trong Bazel, mang lại hiệu quả, đáng tin cậy và cộng tác hơn quy trình phát triển phần mềm.

Xung đột hợp nhất

Định dạng tệp khoá được thiết kế để giảm thiểu xung đột hợp nhất, nhưng chúng vẫn có thể xảy ra.

Độ phân giải tự động

Bazel cung cấp một trình điều khiển git Merge để giúp tự động giải quyết những xung đột này.

Thiết lập trình điều khiển bằng cách thêm dòng này vào tệp .gitattributes trong thư mục gốc của kho lưu trữ git của bạn:

# A custom merge driver for the Bazel lockfile.
# https://bazel.build/external/lockfile#automatic-resolution
MODULE.bazel.lock merge=bazel-lockfile-merge

Sau đó, mỗi nhà phát triển muốn sử dụng trình điều khiển phải đăng ký trình điều khiển một lần trước bằng cách làm theo các bước sau:

  1. Cài đặt jq (1.5 trở lên).
  2. Chạy các lệnh sau:
jq_script=$(curl https://raw.githubusercontent.com/bazelbuild/bazel/master/scripts/bazel-lockfile-merge.jq)
printf '%s\n' "${jq_script}" | less # to optionally inspect the jq script
git config --global merge.bazel-lockfile-merge.name   "Merge driver for the Bazel lockfile (MODULE.bazel.lock)"
git config --global merge.bazel-lockfile-merge.driver "jq -s '${jq_script}' -- %O %A %B > %A.jq_tmp && mv %A.jq_tmp %A"

Độ phân giải thủ công

Các xung đột hợp nhất đơn giản trong registryFileHashesselectedYankedVersions có thể được giải quyết an toàn bằng cách giữ lại tất cả các mục nhập từ cả hai phía của xung đột.

Các loại xung đột hợp nhất khác không được giải quyết theo cách thủ công. Thay vào đó:

  1. Khôi phục trạng thái trước đó của tệp khoá thông qua git reset MODULE.bazel.lock && git checkout MODULE.bazel.lock.
  2. Giải quyết mọi xung đột trong tệp MODULE.bazel.
  3. Chạy bazel mod deps để cập nhật tệp khoá.