Como migrar do Maven para o Bazel

Informar um problema Acessar a origem

Nesta página, descrevemos como migrar do Maven para o Bazel, incluindo os pré-requisitos e as etapas de instalação. Ele descreve as diferenças entre o Maven e o Bazel e fornece um exemplo de migração usando o projeto Guava.

Ao migrar de qualquer ferramenta de build para o Bazel, é melhor que as duas ferramentas de build sejam executadas em paralelo até que você tenha migrado totalmente sua equipe de desenvolvimento, o sistema de CI e outros sistemas relevantes. É possível executar o Maven e o Bazel no mesmo repositório.

Antes de começar

  • Instale o Bazel se ele ainda não estiver instalado.
  • Se você não conhece o Bazel, leia o tutorial Introdução ao Bazel: Build Java antes de começar a migração. Neste tutorial, explicamos os conceitos, a estrutura e a sintaxe de rótulos do Bazel.

Diferenças entre o Maven e o Bazel

  • O Maven usa arquivos pom.xml de nível superior. Ele é compatível com vários arquivos de build e vários destinos por arquivo BUILD, permitindo builds mais incrementais que os do Maven.
  • O Maven assume o controle das etapas do processo de implantação. O Bazel não automatiza a implantação.
  • O Bazel permite expressar dependências entre linguagens.
  • À medida que você adiciona novas seções ao projeto, talvez seja necessário adicionar novos arquivos BUILD no Bazel. A prática recomendada é adicionar um arquivo BUILD a cada novo pacote Java.

Migrar do Maven para o Bazel

As etapas abaixo descrevem como migrar seu projeto para o Bazel:

  1. Criar o arquivo do ESPAÇO DE TRABALHO
  2. Criar um arquivo BUILD
  3. Criar mais arquivos BUILD
  4. Criar usando o Bazel

Os exemplos abaixo vêm de uma migração do projeto Guava do Maven para o Bazel. O projeto Guava usado está na versão v31.1. Os exemplos que usam Guava não explicam cada etapa da migração, mas mostram os arquivos e conteúdos que são gerados ou adicionados manualmente para a migração.

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

1. Criar o arquivo do ESPAÇO DE TRABALHO

Crie um arquivo chamado WORKSPACE na raiz do projeto. Se o projeto não tiver dependências externas, o arquivo do espaço de trabalho poderá estar vazio.

Se o projeto depender de arquivos ou pacotes que não estão em um dos diretórios do projeto, especifique essas dependências externas no arquivo do espaço de trabalho. Para automatizar a listagem de dependências externas do arquivo do espaço de trabalho, use rules_jvm_external. Para instruções sobre como usar esse conjunto de regras, consulte o README (em inglês).

Exemplo de projeto Guava: dependências externas

É possível listar as dependências externas do projeto Guava com o conjunto de regras rules_jvm_external.

Adicione o seguinte snippet ao arquivo 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. Criar um arquivo BUILD

Agora que você tem o espaço de trabalho definido e as dependências externas (se aplicáveis) listadas, é necessário criar arquivos BUILD para descrever como o projeto precisa ser criado. Ao contrário do Maven, com o único arquivo pom.xml, o Bazel pode usar muitos arquivos BUILD para criar um projeto. Esses arquivos especificam vários destinos de compilação, o que permite que o Bazel produza builds incrementais.

Adicione BUILD arquivos em etapas. Comece adicionando um arquivo BUILD na raiz do projeto e usando-o para fazer um build inicial com o Bazel. Em seguida, você refina seu build adicionando mais arquivos BUILD com destinos mais granulares.

  1. No mesmo diretório do arquivo WORKSPACE, crie um arquivo de texto e nomeie-o como BUILD.

  2. Neste arquivo BUILD, use a regra apropriada para criar um destino para criar seu projeto. Veja algumas dicas:

    • Use a regra apropriada:

      • Para criar projetos com um único módulo do Maven, use a regra java_library desta maneira:

        java_library(
            name = "everything",
            srcs = glob(["src/main/java/**/*.java"]),
            resources = glob(["src/main/resources/**"]),
            deps = ["//:all-external-targets"],
        )
        
      • Para criar projetos com vários módulos Maven, use a regra java_library desta maneira:

        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 criar binários, use a regra 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"
        )
        
    • Especifique os atributos:

      • name: dê um nome significativo ao destino. Nos exemplos acima, o destino é chamado de "tudo".
      • srcs: use globbing para listar todos os arquivos .java no projeto.
      • resources: use globbing para listar todos os recursos no projeto.
      • deps: é necessário determinar de quais dependências externas seu projeto precisa. Por exemplo, se você gerou uma lista de dependências externas usando a ferramenta generate_workspace, as dependências de java_library serão as bibliotecas listadas na macro generated_java_libraries.
    • Confira o exemplo abaixo desse arquivo BUILD de nível superior da migração do projeto Guava.

  3. Agora que você tem um arquivo BUILD na raiz do seu projeto, crie seu projeto para garantir que ele funcione. Na linha de comando, no diretório do espaço de trabalho, use bazel build //:everything para criar o projeto com o Bazel.

    O projeto foi criado com o Bazel. Será necessário adicionar mais arquivos BUILD para permitir builds incrementais do projeto.

Exemplo de projeto Guava: comece com um arquivo BUILD

Ao migrar o projeto Guava para o Bazel, inicialmente um arquivo BUILD é usado para criar o projeto inteiro. Confira o conteúdo do arquivo BUILD inicial no diretório do espaço de trabalho:

java_library(
    name = "everything",
    srcs = glob([
        "guava/src/**/*.java",
        "futures/failureaccess/src/**/*.java",
    ]),
    javacopts = ["-XepDisableAllChecks"],
    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. Criar mais arquivos BUILD (opcional)

O Bazel funciona com apenas um BUILD file, como você viu depois de concluir a primeira versão. Considere dividir o build em partes menores adicionando mais arquivos BUILD com destinos granulares.

Vários arquivos BUILD com vários destinos fornecerão maior granularidade ao build, permitindo:

  • de aumento dos builds incrementais do projeto,
  • mais execução paralela da compilação,
  • melhor manutenção do build para futuros usuários e
  • controle sobre a visibilidade dos destinos entre os pacotes, o que pode evitar problemas como bibliotecas com detalhes de implementação vazando para APIs públicas.

Dicas para adicionar mais arquivos BUILD:

  • Comece adicionando um arquivo BUILD a cada pacote Java. Comece com pacotes Java que têm menos dependências e siga até os pacotes com mais dependências.
  • À medida que você adiciona arquivos BUILD e especifica destinos, adicione esses novos destinos às seções deps de destinos que dependem deles. Observe que a função glob() não ultrapassa os limites do pacote. Portanto, à medida que o número de pacotes aumenta, os arquivos correspondentes por glob() vão diminuir.
  • Sempre que você adicionar um arquivo BUILD a um diretório main, inclua um arquivo BUILD no diretório test correspondente.
  • Limite a visibilidade entre os pacotes.
  • Para simplificar a solução de problemas na configuração de arquivos BUILD, verifique se o projeto continua sendo criado com o Bazel à medida que você adiciona cada arquivo de build. Execute bazel build //... para garantir que todos os destinos ainda sejam criados.

4. Criar usando o Bazel

Você está compilando usando o Bazel ao adicionar arquivos BUILD para validar a configuração do build.

Quando você tem arquivos BUILD com a granularidade desejada, pode usar o Bazel para produzir todos os builds.