Arquivo de bloqueio do Bazel

Informar um problema Acessar código-fonte

O recurso de bloqueio de arquivo do Bazel permite a gravação de versões ou dependências específicas de bibliotecas de software ou pacotes exigidos por um projeto. Para isso, ele armazena o resultado da resolução do módulo e da avaliação da extensão. O lockfile promove builds reproduzíveis, garantindo ambientes de desenvolvimento consistentes. Além disso, ela melhora a eficiência do build, permitindo que o Bazel pule o processo de resolução quando não houver mudanças nas dependências do projeto. Além disso, o lockfile melhora a estabilidade, evitando atualizações inesperadas ou alterações interruptivas em bibliotecas externas, reduzindo o risco de introduzir bugs.

Geração de arquivo de bloqueio

O arquivo de bloqueio é gerado na raiz do espaço de trabalho com o nome MODULE.bazel.lock. Ele é criado ou atualizado durante o processo de build, especificamente após a resolução do módulo e a avaliação da extensão. O arquivo de bloqueio captura o estado atual do projeto, incluindo o arquivo MÓDULO, sinalizações, substituições e outras informações relevantes. É importante ressaltar que isso inclui apenas dependências incluídas na invocação atual do build.

Quando ocorrem alterações no projeto que afetam as dependências, o arquivo de bloqueio é atualizado automaticamente para refletir o novo estado. Isso garante que o arquivo de bloqueio permaneça focado no conjunto específico de dependências necessárias para o build atual, fornecendo uma representação precisa das dependências resolvidas do projeto.

Uso do arquivo de bloqueio

O lockfile pode ser controlado pela flag --lockfile_mode para personalizar o comportamento do Bazel quando o estado do projeto é diferente do lockfile. Os modos disponíveis são:

  • update (padrão): se o estado do projeto corresponder ao arquivo de bloqueio, o resultado da resolução será imediatamente retornado do arquivo de bloqueio. Caso contrário, a resolução é executada e o arquivo de bloqueio é atualizado para refletir o estado atual.
  • error: se o estado do projeto corresponder ao arquivo de bloqueio, o resultado da resolução será retornado do arquivo de bloqueio. Caso contrário, o Bazel gera um erro indicando as variações entre o projeto e o arquivo de bloqueio. Esse modo é particularmente útil quando você quer garantir que as dependências do projeto permaneçam inalteradas e que todas as diferenças sejam tratadas como erros.
  • off: o arquivo de bloqueio não é verificado.

Benefícios do Lockfile

O lockfile oferece vários benefícios e pode ser usado de várias maneiras:

  • Builds reproduzíveis. Ao capturar as versões ou dependências específicas de bibliotecas de software, o arquivo de bloqueio garante que as versões sejam reproduzíveis em diferentes ambientes e ao longo do tempo. Os desenvolvedores podem confiar em resultados consistentes e previsíveis ao criar seus projetos.

  • Pular resolução eficiente. O arquivo de bloqueio permite que o Bazel pule o processo de resolução se não houver mudanças nas dependências do projeto desde a última compilação. Isso melhora significativamente a eficiência do build, especialmente em cenários em que a resolução pode ser demorada.

  • Estabilidade e redução de riscos. O lockfile ajuda a manter a estabilidade, evitando atualizações inesperadas ou alterações interruptivas em bibliotecas externas. Ao bloquear as dependências a versões específicas, o risco de introduzir bugs devido a atualizações incompatíveis ou não testadas é reduzido.

Conteúdo do arquivo de bloqueio

O arquivo de bloqueio contém todas as informações necessárias para determinar se o estado do projeto foi alterado. Também inclui o resultado da criação do projeto no estado atual. O arquivo de bloqueio consiste em duas partes principais:

  1. Entradas da resolução do módulo, como moduleFileHash, flags e localOverrideHashes, além da saída da resolução, que é moduleDepGraph.
  2. Para cada extensão de módulo, o arquivo de bloqueio inclui entradas que o afetam, representadas por transitiveDigest, e a saída da execução dessa extensão, chamada de generatedRepoSpecs.

Confira um exemplo que demonstra a estrutura do arquivo de bloqueio e as explicações de cada seção:

{
  "lockFileVersion": 1,
  "moduleFileHash": "b0f47b98a67ee15f9.......8dff8721c66b721e370",
  "flags": {
    "cmdRegistries": [
      "https://bcr.bazel.build/"
    ],
    "cmdModuleOverrides": {},
    "allowedYankedVersions": [],
    "envVarAllowedYankedVersions": "",
    "ignoreDevDependency": false,
    "directDependenciesMode": "WARNING",
    "compatibilityMode": "ERROR"
  },
  "localOverrideHashes": {
    "bazel_tools": "b5ae1fa37632140aff8.......15c6fe84a1231d6af9"
  },
  "moduleDepGraph": {
    "<root>": {
      "name": "",
      "version": "",
      "executionPlatformsToRegister": [],
      "toolchainsToRegister": [],
      "extensionUsages": [
        {
          "extensionBzlFile": "extension.bzl",
          "extensionName": "lockfile_ext"
        }
      ],
      ...
    }
  },
  "moduleExtensions": {
    "//:extension.bzl%lockfile_ext": {
      "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
      "generatedRepoSpecs": {
        "hello": {
          "bzlFile": "@@//:extension.bzl",
          ...
        }
      }
    }
  }
}

Hash de arquivo do módulo

O moduleFileHash representa o hash do conteúdo do arquivo MODULE.bazel. Se houver alguma alteração nesse arquivo, o valor de hash será diferente.

Sinalizações

O objeto Flags armazena todas as sinalizações que podem afetar o resultado da resolução.

Hashes de substituição local

Se o módulo raiz incluir local_path_overrides, esta seção armazenará o hash do arquivo MODULE.bazel no repositório local. Permite rastrear alterações nessa dependência.

Gráfico de dependências do módulo

O moduleDepGraph representa o resultado do processo de resolução usando as entradas mencionadas acima. Ele forma o gráfico de dependências de todos os módulos necessários para executar o projeto.

Extensões do módulo

A seção moduleExtensions é um mapa que inclui apenas as extensões usadas na invocação atual ou invocadas anteriormente, excluindo aquelas que não são mais utilizadas. Em outras palavras, se uma extensão não estiver mais sendo usada no gráfico de dependência, ela será removida do mapa moduleExtensions.

Cada entrada neste mapa corresponde a uma extensão usada e é identificada pelo arquivo e nome que a contém. O valor correspondente de cada entrada contém as informações relevantes associadas a essa extensão:

  1. transitiveDigest: o resumo da implementação da extensão e os arquivos .bzl transitivos dela.
  2. O generatedRepoSpecs é o resultado da execução dessa extensão com a entrada atual.

Outro fator que pode afetar os resultados da extensão são os usos. Embora não sejam armazenados no arquivo de bloqueio, os usos são considerados ao comparar o estado atual da extensão com o que está no arquivo de bloqueio.

Práticas recomendadas

Para maximizar os benefícios do recurso de bloqueio de arquivo, considere as seguintes práticas recomendadas:

  • Atualize regularmente o arquivo de bloqueio para refletir as alterações nas dependências ou na configuração do projeto. Isso garante que os builds subsequentes sejam baseados no conjunto de dependências mais atualizado e preciso.

  • Inclua o arquivo de bloqueio no controle de versões para facilitar a colaboração e garantir que todos os membros da equipe tenham acesso ao mesmo arquivo de bloqueio, promovendo ambientes de desenvolvimento consistentes em todo o projeto.

Seguindo essas práticas recomendadas, você pode utilizar efetivamente o recurso de lockfile no Bazel, levando a fluxos de trabalho de desenvolvimento de software mais eficientes, confiáveis e colaborativos.