Migra de Maven a Bazel

Informa un problema Ver código fuente

En esta página, se describe cómo migrar de Maven a Bazel, incluidos los requisitos previos y los pasos de instalación. Describe las diferencias entre Maven y Bazel, y proporciona un ejemplo de migración mediante el proyecto de Guava.

Cuando migras de cualquier herramienta de compilación a Bazel, es mejor tener ambas herramientas de compilación en ejecución en paralelo hasta que hayas migrado por completo el equipo de desarrollo, el sistema de CI y cualquier otro sistema relevante. Puedes ejecutar Maven y Bazel en el mismo repositorio.

Antes de comenzar

  • Instala Bazel si aún no está instalado.
  • Si eres nuevo en Bazel, consulta el instructivo Introducción a Bazel: compila Java antes de comenzar la migración. En el instructivo, se explican los conceptos, la estructura y la sintaxis de las etiquetas de Bazel.

Diferencias entre Maven y Bazel

  • Maven usa archivos pom.xml de nivel superior. Bazel admite varios archivos de compilación y varios destinos por archivo BUILD, lo que permite compilaciones que son más incrementales que las de Maven.
  • Maven se encarga de los pasos del proceso de implementación. Bazel no automatiza la implementación.
  • Bazel te permite expresar dependencias entre idiomas.
  • A medida que agregas secciones nuevas al proyecto, es posible que, con Bazel, debas agregar archivos BUILD nuevos. Se recomienda agregar un archivo BUILD a cada paquete de Java nuevo.

Migra de Maven a Bazel

En los siguientes pasos, se describe cómo migrar tu proyecto a Bazel:

  1. Cree el archivo WORKSPACE
  2. Cómo crear un archivo BUILD
  3. Crear más archivos de BUILD
  4. Compila con Bazel

Los siguientes ejemplos provienen de una migración del proyecto Guava de Maven a Bazel. El proyecto de Guava que se usó es el lanzamiento v31.1. En los ejemplos que usan Guava, no se explica cada paso de la migración, pero sí se muestran los archivos y el contenido que se generan o agregan de forma manual para la migración.

$ git clone https://github.com/google/guava.git && cd guava
$ git checkout v31.1

1. Cree el archivo WORKSPACE

Crea un archivo llamado WORKSPACE en la raíz de tu proyecto. Si tu proyecto no tiene dependencias externas, el archivo del lugar de trabajo puede estar vacío.

Si tu proyecto depende de archivos o paquetes que no están en uno de los directorios del proyecto, especifica estas dependencias externas en el archivo del lugar de trabajo. A fin de automatizar la lista de dependencias externas para el archivo del espacio de trabajo, usa rules_jvm_external. Para obtener instrucciones sobre cómo usar este conjunto de reglas, consulta el archivo README.

Ejemplo de proyecto de Guava: dependencias externas

Puedes enumerar las dependencias externas del proyecto de Guava con el conjunto de reglas rules_jvm_external.

Agrega el siguiente fragmento al archivo WORKSPACE:

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

RULES_JVM_EXTERNAL_TAG = "4.3"
RULES_JVM_EXTERNAL_SHA = "6274687f6fc5783b589f56a2f1ed60de3ce1f99bc4e8f9edef3de43bdf7c6e74"

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

load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
    artifacts = [
        "com.google.code.findbugs:jsr305:3.0.2",
        "com.google.errorprone:error_prone_annotations:2.11.0",
        "com.google.j2objc:j2objc-annotations:1.3",
        "org.codehaus.mojo:animal-sniffer-annotations:1.20",
        "org.checkerframework:checker-qual:3.12.0",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

2. Crear un archivo BUILD

Ahora que definiste las dependencias externas y el lugar de trabajo (si corresponde), debes crear archivos BUILD para describir cómo se debe compilar el proyecto. A diferencia de Maven con su único archivo pom.xml, Bazel puede usar muchos archivos BUILD para compilar un proyecto. Estos archivos especifican varios destinos de compilación, que permiten que Bazel produzca compilaciones incrementales.

Agrega archivos BUILD en etapas. Comienza por agregar un archivo BUILD en la raíz de tu proyecto y usarlo para realizar una compilación inicial con Bazel. Luego, puedes definir mejor tu compilación agregando más archivos BUILD con orientaciones más detalladas.

  1. En el mismo directorio que el archivo WORKSPACE, crea un archivo de texto y asígnale el nombre BUILD.

  2. En este archivo BUILD, usa la regla adecuada para crear un destino y compilar tu proyecto. A continuación, se incluyen algunas sugerencias:

    • Usa la regla apropiada:

      • Para compilar proyectos con un solo módulo de Maven, usa la regla java_library de la siguiente manera:

        java_library(
            name = "everything",
            srcs = glob(["src/main/java/**/*.java"]),
            resources = glob(["src/main/resources/**"]),
            deps = ["//:all-external-targets"],
        )
        
      • Para compilar proyectos con varios módulos de Maven, usa la regla java_library de la siguiente manera:

        java_library(
            name = "everything",
            srcs = glob([
                "Module1/src/main/java/**/*.java",
                "Module2/src/main/java/**/*.java",
                ...
            ]),
            resources = glob([
                "Module1/src/main/resources/**",
                "Module2/src/main/resources/**",
                ...
            ]),
            deps = ["//:all-external-targets"],
        )
        
      • Para compilar objetos binarios, usa la regla java_binary:

        java_binary(
            name = "everything",
            srcs = glob(["src/main/java/**/*.java"]),
            resources = glob(["src/main/resources/**"]),
            deps = ["//:all-external-targets"],
            main_class = "com.example.Main"
        )
        
    • Especifica los atributos:

      • name: Asigne un nombre significativo al objetivo. En los ejemplos anteriores, el objetivo se denomina “todo”.
      • srcs: usa globbing para enumerar todos los archivos .java en tu proyecto.
      • resources: Usa globalización para enumerar todos los recursos de tu proyecto.
      • deps: Debes determinar qué dependencias externas necesita tu proyecto. Por ejemplo, si generaste una lista de dependencias externas con la herramienta generate_workspace, las dependencias para java_library son las bibliotecas enumeradas en la macro generated_java_libraries.
    • Mira el siguiente ejemplo de este archivo BUILD de nivel superior de la migración del proyecto de Guava.

  3. Ahora que tienes un archivo BUILD en la raíz de tu proyecto, compílalo para asegurarte de que funcione. En la línea de comandos, desde el directorio del lugar de trabajo, usa bazel build //:everything para compilar el proyecto con Bazel.

    El proyecto ahora se compiló correctamente con Bazel. Deberás agregar más archivos BUILD para permitir compilaciones incrementales del proyecto.

Ejemplo de proyecto de Guava: comienza con un archivo BUILD.

Cuando se migra el proyecto de Guava a Bazel, inicialmente se usa un archivo BUILD para compilar todo el proyecto. A continuación, se muestra el contenido de este archivo BUILD inicial en el directorio de espacio de trabajo:

java_library(
    name = "everything",
    srcs = glob([
        "guava/src/**/*.java",
        "futures/failureaccess/src/**/*.java",
    ]),
    deps = [
        "@maven//:com_google_code_findbugs_jsr305",
        "@maven//:com_google_errorprone_error_prone_annotations",
        "@maven//:com_google_j2objc_j2objc_annotations",
        "@maven//:org_checkerframework_checker_qual",
        "@maven//:org_codehaus_mojo_animal_sniffer_annotations",
    ],
)

3. Crear más archivos BUILD (opcional)

Bazel funciona con una sola BUILD file, como viste después de completar la primera compilación. Debes considerar dividir la compilación en fragmentos más pequeños si agregas más archivos BUILD con objetivos detallados.

Varios archivos BUILD con varios destinos le darán a la compilación un mayor nivel de detalle, lo que permitirá:

  • aumentó las compilaciones incrementales del proyecto,
  • Incrementó la ejecución paralela de la compilación.
  • un mejor mantenimiento de la compilación para usuarios futuros
  • control sobre la visibilidad de los objetivos entre paquetes, lo que puede evitar problemas como las bibliotecas que contienen detalles de implementación que se filtran a API públicas.

Sugerencias para agregar más archivos BUILD:

  • Puedes comenzar por agregar un archivo BUILD a cada paquete de Java. Comienza con los paquetes de Java que tienen la menor cantidad de dependencias y avanza hasta los paquetes con la mayor cantidad de dependencias.
  • A medida que agregas archivos BUILD y especificas objetivos, agrega estos destinos nuevos a las secciones deps de los destinos que dependen de ellos. Ten en cuenta que la función glob() no cruza los límites del paquete, por lo que la cantidad de paquetes aumenta los archivos que coinciden con glob().
  • Cada vez que agregues un archivo BUILD a un directorio main, asegúrate de agregar un archivo BUILD al directorio test correspondiente.
  • Asegúrese de limitar correctamente la visibilidad entre paquetes.
  • Para simplificar los errores de solución de problemas en la configuración de los archivos BUILD, asegúrate de que el proyecto continúe compilando con Bazel a medida que agregas cada archivo de compilación. Ejecuta bazel build //... para asegurarte de que aún se compilen todos tus destinos.

4. Compila mediante Bazel

Compilaste con Bazel a medida que agregaste archivos BUILD para validar la configuración de la compilación.

Cuando tengas archivos BUILD en el nivel de detalle deseado, puedes usar Bazel para producir todas tus compilaciones.