Alat Migrasi Bzlmod

Untuk menyederhanakan proses yang sering kali rumit dalam berpindah dari WORKSPACE ke Bzlmod, sebaiknya gunakan skrip migrasi. Alat bantu ini mengotomatiskan banyak langkah yang terlibat dalam memigrasikan sistem pengelolaan dependensi eksternal Anda.

Catatan: Jika Anda ingin mencoba migrasi Bzlmod yang didukung AI, lihat Penyiapan Agen Migrasi Bzlmod.

Fungsi Inti

Fungsi utama skrip adalah:

  • Mengumpulkan informasi dependensi: Menganalisis file WORKSPACE project Anda untuk mengidentifikasi repositori eksternal yang digunakan oleh target build tertentu, menggunakan tanda experimental_repository_resolved_file Bazel untuk membuat file dependensi yang telah di-resolve yang berisi informasi ini.
  • Mengidentifikasi dependensi langsung: Menggunakan bazel query untuk menentukan repositori mana yang merupakan dependensi langsung untuk target yang ditentukan.
  • Bermigrasi ke Bzlmod: Menerjemahkan dependensi WORKSPACE yang relevan ke dalam padanannya di Bzlmod. Proses ini terdiri dari dua langkah:
    1. Perkenalkan semua dependensi langsung yang diidentifikasi ke file MODULE.bazel.
    2. Bangun target yang ditentukan dengan Bzlmod diaktifkan, lalu identifikasi dan perbaiki error yang dapat dikenali secara iteratif. Langkah ini diperlukan karena beberapa dependensi mungkin tidak ada di langkah pertama.
  • Membuat laporan migrasi: Membuat file migration_info.md yang mendokumentasikan proses migrasi. Laporan ini mencakup daftar dependensi langsung, deklarasi Bzlmod yang dihasilkan, dan langkah-langkah manual yang mungkin diperlukan untuk menyelesaikan migrasi.

Alat migrasi mendukung:

  • Dependensi yang tersedia di Bazel Central Registry
  • Aturan repositori kustom yang ditentukan pengguna
  • Dependensi pengelola paket
    • Maven
    • Go
    • Python

Catatan Penting:

  • Alat migrasi adalah utilitas upaya terbaik. Selalu periksa kembali rekomendasi yang diberikan untuk memastikan kebenarannya.
  • Gunakan alat migrasi dengan Bazel 7 (tidak didukung dengan Bazel 8).

Cara Menggunakan Alat Migrasi

Sebelum memulai:

  • Lakukan upgrade ke rilis Bazel 7 terbaru, yang memberikan dukungan yang andal untuk WORKSPACE dan Bzlmod.
  • Verifikasi bahwa perintah berikut berhasil dijalankan untuk target build utama project Anda:

    bazel build --nobuild --enable_workspace --noenable_bzlmod <targets>
    

Perintah untuk menjalankan skrip

Setelah prasyarat terpenuhi, jalankan perintah berikut untuk menggunakan alat migrasi:

# Clone the Bazel Central Registry repository
git clone https://github.com/bazelbuild/bazel-central-registry.git
cd bazel-central-registry

# Build the migration tool
bazel build //tools:migrate_to_bzlmod

# Create a convenient alias for the tool
alias migrate2bzlmod=$(realpath ./bazel-bin/tools/migrate_to_bzlmod)

# Navigate to your project's root directory and run the tool
cd 
migrate2bzlmod -t 

File yang dihasilkan oleh skrip ini

  • MODULE.bazel - File manifes pusat untuk Bzlmod, yang mendeklarasikan metadata project dan dependensi langsungnya pada modul Bazel lainnya.
  • migration_info.md - File yang memberikan petunjuk langkah demi langkah tentang cara menjalankan alat migrasi, yang dirancang untuk membantu penyelesaian proses migrasi secara manual, jika perlu.
  • resolved_deps.py - Berisi daftar lengkap dependensi eksternal project, yang dihasilkan dengan menganalisis file WORKSPACE project, yang berfungsi sebagai referensi selama transisi.
  • query_direct_deps - Berisi informasi yang relevan dengan migrasi terkait target yang digunakan, yang diperoleh dengan memanggil Bazel dengan --output=build pada file WORKSPACE project. File ini terutama digunakan oleh skrip migrasi.
  • extension_for_XXX - File yang berisi definisi ekstensi modul. Alat migrasi membuat file ini untuk dependensi yang bukan modul Bazel standar, tetapi dapat dikelola menggunakan ekstensi modul Bzlmod.

Tanda

Flag yang tersedia dalam skrip migrasi ini adalah:

  • --t/--target: Target yang akan dimigrasikan. Flag ini dapat diulang, dan targetnya diakumulasikan.
  • --i/--initial: Menghapus file MODULE.bazel, resolved_deps.py, migration_info.md dan memulai dari awal - Mendeteksi dependensi langsung, memperkenalkannya di MODULE.bazel, dan menjalankan kembali pembuatan dependensi yang telah di-resolve.

Pembersihan pascamigrasi

  • Hapus migration_info.md, resolved_deps.py, dan query_direct_deps.
  • Hapus komentar dari file MODULE.bazel yang digunakan untuk migrasi, seperti # -- bazel_dep definitions -- #.

Contoh Migrasi

Untuk melihat cara kerja skrip migrasi, pertimbangkan skenario berikut saat dependensi Python, Maven, dan Go dideklarasikan dalam file WORKSPACE.

Klik di sini untuk melihat file WORKSPACE

workspace(name="example")

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load(":my_custom_macro.bzl", "my_custom_macro")

http_archive(
    name = "rules_cc",
    sha256 = "b8b918a85f9144c01f6cfe0f45e4f2838c7413961a8ff23bc0c6cdf8bb07a3b6",
    strip_prefix = "rules_cc-0.1.5",
    urls = ["https://github.com/bazelbuild/rules_cc/releases/download/0.1.5/rules_cc-0.1.5.tar.gz"],
)

# Module dependency
# -------------------
http_archive(
    name = "rules_shell",
    sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
    strip_prefix = "rules_shell-0.4.0",
    url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)

# Repo rule
# -------------------
http_archive(
    name = "com_github_cockroachdb_cockroach",
    sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
    strip_prefix = "cockroach-22.1.6",
    url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)

# Module extension
# -------------------
# Macro which invokes repository_rule
my_custom_macro(
    name = "my_custom_repo",
)

# Go dependencies
# -------------------
http_archive(
    name = "io_bazel_rules_go",
    integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
    ],
)

http_archive(
    name = "bazel_gazelle",
    integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()

go_repository(
    name = "org_golang_x_net",
    importpath = "golang.org/x/net",
    sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
    version = "v0.0.0-20190311183353-d8887717615a",
    build_file_proto_mode = "disable",
    build_naming_convention = "import",
)

# Python dependencies
# -------------------
http_archive(
    name = "rules_python",
    integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
    strip_prefix = "rules_python-1.4.0",
    url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()

load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
   name = "my_python_deps",
   requirements_lock = "@example//:requirements_lock.txt",
)

load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()

load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
    name = "python_3_11",
    python_version = "3.11",
)

# Maven dependencies
# __________________

RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    name = "px_deps",
    artifacts = [
        "org.antlr:antlr4:4.11.1",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

Selain itu, untuk mendemonstrasikan penggunaan ekstensi modul, makro kustom dipanggil dari WORKSPACE dan ditentukan di my_custom_macro.bzl.

Klik di sini untuk melihat file my_custom_macro.bzl

"""Repo rule and macro used for testing"""

def _test_repo_rule_impl(repository_ctx):
    repository_ctx.file(
        "BUILD",
        content = """
genrule(
    name = "foo",
    outs = ["rule_name.out"],
    cmd = "touch $@",
    visibility = ["//visibility:public"],
)
"""
    )

_test_repo_rule = repository_rule(
    implementation = _test_repo_rule_impl,
)

def my_custom_macro(name):
    _test_repo_rule(name = name)

Tujuan akhirnya adalah memiliki file MODULE.bazel dan menghapus file WORKSPACE, tanpa memengaruhi pengalaman pengguna.

Langkah pertama adalah mengikuti Cara Menggunakan Alat Migrasi, yang sebagian besar memeriksa versi bazel (harus Bazel 7) dan menambahkan alias ke skrip migrasi.

Kemudian, menjalankan migrate2bzlmod -t=//... akan menghasilkan:

  bazel 7.6.1

  Generating ./resolved_deps.py file - It might take a while...

  RESOLVED: rules_java has been introduced as a Bazel module.
  RESOLVED: bazel_gazelle has been introduced as a Bazel module.
  RESOLVED: io_bazel_rules_go has been introduced as a Bazel module.
  RESOLVED: rules_python has been introduced as a Bazel module.
  IMPORTANT: 3.11 is used as a default python version. If you need a different version, please change it manually and then rerun the migration tool.
  RESOLVED: my_python_deps has been introduced as python extension.
  RESOLVED: org_golang_x_net has been introduced as go extension.
  RESOLVED: rules_jvm_external has been introduced as a Bazel module.
  RESOLVED: org.antlr has been introduced as maven extension.
  RESOLVED: rules_shell has been introduced as a Bazel module.

  Congratulations! All external repositories needed for building //... are available with Bzlmod!
  IMPORTANT: Fix potential build time issues by running the following command:
      bazel build --enable_bzlmod --noenable_workspace //...

  IMPORTANT: For details about the migration process, check `migration_info.md` file.

yang memberikan informasi penting berikut:

  • Membuat file ./resolved_deps.py, yang berisi info tentang semua repositori eksternal yang dideklarasikan dan dimuat menggunakan file WORKSPACE Anda.
  • Kata kunci RESOLVED menjelaskan semua dependensi yang diselesaikan oleh alat dan ditambahkan ke file MODULE.bazel.
  • Kata kunci IMPORTANT menjelaskan informasi penting yang layak untuk dipelajari.
  • Semua dependensi telah diselesaikan dalam contoh ini, setidaknya dengan flag --nobuild.
  • Penting untuk menjalankan build lengkap (perintah yang ditentukan) dan memperbaiki error potensial secara manual (misalnya, toolchain tidak terdaftar dengan benar).
  • File migration_info.md berisi detail tentang migrasi. Lihat detailnya di bagian ini.

Transformasi

Bagian ini mengilustrasikan migrasi kode dari file WORKSPACE ke MODULE.bazel.

WORKSPACE - Bazel Module

http_archive(
    name = "rules_shell",
    sha256 = "3e114424a5c7e4fd43e0133cc6ecdfe54e45ae8affa14fadd839f29901424043",
    strip_prefix = "rules_shell-0.4.0",
    url = "https://github.com/bazelbuild/rules_shell/releases/download/v0.4.0/rules_shell-v0.4.0.tar.gz",
)

MODULE.bazel - Modul Bazel

bazel_dep(name = "rules_shell", version = "0.6.1")

WORKSPACE - Go Extension

http_archive(
    name = "io_bazel_rules_go",
    integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip",
    ],
)
http_archive(
    name = "bazel_gazelle",
    integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

go_rules_dependencies()
go_register_toolchains(version = "1.23.1")
gazelle_dependencies()

go_repository(
    name = "org_golang_x_net",
    importpath = "golang.org/x/net",
    sum = "h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=",
    version = "v0.0.0-20190311183353-d8887717615a",
    build_file_proto_mode = "disable",
    build_naming_convention = "import",
)

MODULE.bazel - Ekstensi Go

go_deps = use_extension("@bazel_gazelle//:extensions.bzl", "go_deps")
go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk")

go_deps.from_file(go_mod = "//:go.mod")
use_repo(go_deps, "org_golang_x_net")
go_sdk.from_file(go_mod = "//:go.mod")

go_deps.gazelle_override(
    path = "golang.org/x/net",
    directives = [
        "gazelle:proto disable",
         "gazelle:go_naming_convention import",
    ],
)

WORKSPACE - Python Extension

http_archive(
    name = "rules_python",
    integrity = "sha256-qDdnnxOC8mlowe5vg5x9r5B5qlMSgGmh8oFd7KpjcwQ=",
    strip_prefix = "rules_python-1.4.0",
    url = "https://github.com/bazelbuild/rules_python/releases/download/1.4.0/rules_python-1.4.0.tar.gz",
)

load("@rules_python//python:repositories.bzl", "py_repositories")
py_repositories()

load("@rules_python//python:pip.bzl", "pip_parse")
pip_parse(
   name = "my_python_deps",
   requirements_lock = "@example//:requirements_lock.txt",
)

load("@my_python_deps//:requirements.bzl", "install_deps")
install_deps()

load("@rules_python//python:repositories.bzl", "python_register_toolchains")
python_register_toolchains(
    name = "python_3_11",
    python_version = "3.11",
)

MODULE.bazel - Ekstensi Python

pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
pip.parse(
    hub_name = "my_python_deps",
    python_version = "3.11",
    requirements_lock = "//:requirements_lock.txt",
)
use_repo(pip, "my_python_deps")

python = use_extension("@rules_python//python/extensions:python.bzl", "python")
python.defaults(python_version = "3.11")
python.toolchain(python_version = "3.11")

WORKSPACE - Maven Extension

RULES_JVM_EXTERNAL_TAG = "4.5"
RULES_JVM_EXTERNAL_SHA = "b17d7388feb9bfa7f2fa09031b32707df529f26c91ab9e5d909eb1676badd9a6"

http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

load("@rules_jvm_external//:repositories.bzl", "rules_jvm_external_deps")
rules_jvm_external_deps()
load("@rules_jvm_external//:setup.bzl", "rules_jvm_external_setup")
rules_jvm_external_setup()

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    name = "px_deps",
    artifacts = [
        "org.antlr:antlr4:4.11.1",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

MODULE.bazel - Ekstensi Maven

bazel_dep(name = "rules_jvm_external", version = "6.8")

maven = use_extension("@rules_jvm_external//:extensions.bzl", "maven")
use_repo(maven, "px_deps")

maven.artifact(
    name = "px_deps",
    group = "org.antlr",
    artifact = "antlr4",
    version = "4.11.1"
)

WORKSPACE - Repo rule

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "com_github_cockroachdb_cockroach",
    sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
    strip_prefix = "cockroach-22.1.6",
    url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
)

MODULE.bazel - Aturan repo

http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
  name = "com_github_cockroachdb_cockroach",
  url = "https://github.com/cockroachdb/cockroach/archive/v22.1.6.tar.gz",
  sha256 = "6c3568ef244ce6b874694eeeecb83ed4f5d5dff6cf037c952ecde76828a6c502",
  strip_prefix = "cockroach-22.1.6",
)

WORKSPACE - Module extension

load(":my_custom_macro.bzl", "my_custom_macro")

my_custom_macro(
    name = "my_custom_repo",
)

MODULE.bazel - Ekstensi modul

extension_for_my_custom_macro = use_extension("//:extension_for_my_custom_macro.bzl", "extension_for_my_custom_macro")
use_repo(extension_for_my_custom_macro, "my_custom_repo")

extension_for_my_custom_macro.bzl

load("//:my_custom_macro.bzl", "my_custom_macro")

def _extension_for_my_custom_macro_impl(ctx):
  my_custom_macro(
    name = "my_custom_repo",
  )

extension_for_my_custom_macro = module_extension(implementation = _extension_for_my_custom_macro_impl)

Tips untuk proses debug

Bagian ini memberikan perintah dan informasi yang berguna untuk membantu men-debug masalah yang mungkin muncul selama migrasi Bzlmod.

Tips berguna

  • Mengganti versi - Tidak jarang terjadi bahwa mengupgrade versi dependensi menyebabkan masalah. Bzlmod dapat mengubah versi dependensi karena algoritma MVS. Untuk menggunakan versi yang sama atau serupa seperti di RUANG KERJA, ganti dengan single_version_override. Perhatikan bahwa ini berguna untuk men-debug perbedaan antara WORKSPACE dan Bzlmod, tetapi Anda tidak boleh mengandalkan fitur ini dalam jangka panjang.

    single_version_override(module_name = "{dep_name}", version = "{version}")

  • Gunakan perintah bazel mod.

    • Periksa versi repo tertentu dengan perintah show_repo. Contoh:

      bazel mod show_repo @rules_python

    • Periksa informasi tentang ekstensi modul dengan perintah show_extension. Contoh:

      bazel mod show_extension @rules_python//python/extensions:pip.bzl%pip

  • Gunakan mode vendor untuk membuat salinan lokal repo saat Anda ingin memantau atau mengontrol sumber repo. Contoh:

    bazel vendor --enable_bzlmod --vendor_dir=vendor_src --repo=@protobuf

Pembuatan Laporan Migrasi

File ini diperbarui dengan setiap menjalankan skrip migrasi atau dibuat dari awal jika ini adalah proses pertama atau jika tanda --i digunakan. Laporan ini berisi:

  • Perintah untuk pengujian lokal.
  • Daftar dependensi langsung (setidaknya yang digunakan langsung dalam project).
  • Untuk setiap dependensi, menu drop-down untuk memeriksa tempat deklarasi repositori dalam file WORKSPACE, yang sangat berguna untuk proses pen-debug-an. Anda dapat melihatnya sebagai:

    > Click here to see where and how the repo was declared in the WORKSPACE
    file
  • Untuk setiap dependensi, cara penerapannya dalam file MODULE.bazel. Dari Contoh Migrasi sebelumnya, akan terlihat seperti:

    1. Dependensi modul Bazel - Migration of rules_python

      Found perfect name match in BCR: rules_python
      Found partially name matches in BCR: rules_python_gazelle_plugin
      
      It has been introduced as a Bazel module:
          `bazel_dep(name = "rules_python", version = "1.6.1")`
      • Skrip akan otomatis menggunakan perfect name match jika menemukannya. Jika terjadi error, Anda dapat memeriksa ulang apakah nama telah ditambahkan dengan benar.
    2. Ekstensi Python - Migration of my_python_deps

      pip.parse(
          hub_name = "my_python_deps",
          requirements_lock = "//:requirements_lock.txt",
          python_version = "3.11",
      )
      use_repo(pip, "my_python_deps")
    3. Ekstensi Maven - Migration of org.antlr (px_deps):

      maven.artifact(
          name = "px_deps",
          group = "org.antlr",
          artifact = "antlr4",
          version = "4.11.1"
      )
    4. Ekstensi Go - Migration of org_golang_x_net

      go_deps.from_file(go_mod = "//:go.mod")
      go_sdk.from_file(go_mod = "//:go.mod")
      
      go_deps.gazelle_override(
          path = "golang.org/x/net",
          directives = [
              "gazelle:proto disable",
              "gazelle:go_naming_convention import",
          ],
      )
      • Library ini telah diperkenalkan sebagai modul go dengan bantuan go.mod. Jika go.mod dan go.sum tidak tersedia, modul go akan ditambahkan langsung ke file MODULE.bazel.
      • gazelle_override digunakan untuk menambahkan direktif tertentu.

Masukan

Jika Anda ingin berkontribusi, lakukan dengan membuat Masalah atau PR di bazel-central-registry.