Archivo de bloqueo de Bazel

Informar un problema Ver fuente

La función de archivo de bloqueo en Bazel permite la grabación de versiones o dependencias específicas de bibliotecas de software o paquetes que requiere un proyecto. Se logra almacenando el resultado de la resolución del módulo y la evaluación de la extensión. El archivo de bloqueo promueve compilaciones reproducibles, lo que garantiza entornos de desarrollo coherentes. Además, mejora la eficiencia de compilación, ya que permite que Bazel omita el proceso de resolución cuando no hay cambios en las dependencias del proyecto. Además, el archivo de bloqueo mejora la estabilidad evitando actualizaciones inesperadas o cambios rotundos en bibliotecas externas, lo que reduce el riesgo de introducir errores.

Generación de archivos de bloqueo

El archivo de bloqueo se genera bajo la raíz del lugar de trabajo con el nombre MODULE.bazel.lock. Se crea o actualiza durante el proceso de compilación, en especial después de la resolución del módulo y la evaluación de la extensión. El archivo bloqueado captura el estado actual del proyecto, incluido el archivo MÓDULO, las marcas, las anulaciones y otra información relevante. Es importante destacar que solo incluye dependencias que se incluyen en la invocación actual de la compilación.

Cuando se producen cambios en el proyecto que afectan sus dependencias, el archivo de bloqueo se actualiza automáticamente para reflejar el estado nuevo. Esto garantiza que el archivo de bloqueo permanezca enfocado en el conjunto específico de dependencias necesarias para la compilación actual, lo que proporciona una representación precisa de las dependencias resueltas del proyecto.

Uso del archivo bloqueado

El archivo de bloqueo se puede controlar con la marca --lockfile_mode para personalizar el comportamiento de Bazel cuando el estado del proyecto difiere del archivo de bloqueo. Los modos disponibles son los siguientes:

  • update (predeterminado): Si el estado del proyecto coincide con el archivo de bloqueo, el resultado de la resolución se muestra de inmediato desde el archivo de bloqueo. De lo contrario, se ejecuta la resolución, y el archivo de bloqueo se actualiza para reflejar el estado actual.
  • error: Si el estado del proyecto coincide con el archivo de bloqueo, se muestra el resultado de la resolución desde el archivo. De lo contrario, Bazel arroja un error que indica las variaciones entre el proyecto y el archivo de bloqueo. Este modo es particularmente útil cuando quieres asegurarte de que las dependencias de tu proyecto no se modifiquen y de que las diferencias se traten como errores.
  • off: El archivo de bloqueo no está marcado.

Beneficios del archivo bloqueado

El archivo bloqueado ofrece varios beneficios y se puede utilizar de varias maneras:

  • Compilaciones reproducibles. Mediante la captura de las versiones o dependencias específicas de las bibliotecas de software, el archivo de bloqueo garantiza que las compilaciones se puedan reproducir en diferentes entornos y con el tiempo. Los desarrolladores pueden confiar en resultados coherentes y predecibles cuando compilan sus proyectos.

  • Omisión de resolución eficiente El archivo de bloqueo permite que Bazel omita el proceso de resolución si no hay cambios en las dependencias del proyecto desde la última compilación. Esto mejora considerablemente la eficiencia de compilación, especialmente en situaciones en las que la resolución puede llevar mucho tiempo.

  • Estabilidad y reducción de riesgos. El archivo de bloqueo ayuda a mantener la estabilidad, ya que evita actualizaciones inesperadas o cambios rotundos en bibliotecas externas. Cuando bloqueas las dependencias en versiones específicas, se reduce el riesgo de introducir errores debido a actualizaciones incompatibles o no probadas.

Contenido del archivo bloqueado

El archivo de bloqueo contiene toda la información necesaria para determinar si cambió el estado del proyecto. También incluye el resultado de la construcción del proyecto en el estado actual. El archivo de bloqueo consta de dos partes principales:

  1. Las entradas de la resolución del módulo, como moduleFileHash, flags y localOverrideHashes, así como el resultado de la resolución, que es moduleDepGraph
  2. Para cada extensión de módulo, el archivo de bloqueo incluye entradas que lo afectan, representadas por transitiveDigest, y el resultado de la ejecución de esa extensión, conocida como generatedRepoSpecs.

Este es un ejemplo que muestra la estructura del archivo de bloqueo, junto con explicaciones para cada sección:

{
  "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": {
      "general": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    },
    "//:extension.bzl%lockfile_ext2": {
      "os:macos": {
        "transitiveDigest": "oWDzxG/aLnyY6Ubrfy....+Jp6maQvEPxn0pBM=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      },
      "os:linux": {
        "transitiveDigest": "eWDzxG/aLsyY3Ubrto....+Jp4maQvEPxn0pLK=",
        "generatedRepoSpecs": {
          "hello": {
            "bzlFile": "@@//:extension.bzl",
            ...
          }
        }
      }
    }
  }
}

Hash del archivo de módulo

El moduleFileHash representa el hash del contenido del archivo MODULE.bazel. Si se produce algún cambio en este archivo, el valor de hash difiere.

Marcas

El objeto Flags almacena todas las marcas que pueden afectar el resultado de la resolución.

Hashes de anulación locales

Si el módulo raíz incluye local_path_overrides, esta sección almacena el hash del archivo MODULE.bazel en el repositorio local. Permite hacer un seguimiento de los cambios de esta dependencia.

Gráfico de dependencia de módulos

moduleDepGraph representa el resultado del proceso de resolución con las entradas mencionadas anteriormente. Forma el gráfico de dependencias de todos los módulos necesarios para ejecutar el proyecto.

Extensiones de módulo

La sección moduleExtensions es un mapa que incluye solo las extensiones que se usaron en la invocación actual o que se invocaron anteriormente, y excluye las extensiones que ya no se usan. En otras palabras, si una extensión ya no se usa en el gráfico de dependencia, se quita del mapa moduleExtensions.

Si una extensión es independiente del sistema operativo o del tipo de arquitectura, esta sección presenta solo una entrada "general". De lo contrario, se incluyen varias entradas, con el nombre del SO, la arquitectura o ambos, y cada una corresponde al resultado de la evaluación de la extensión en esos detalles.

Cada entrada en el mapa de extensiones corresponde a una extensión usada y se identifica por el archivo y el nombre que la contiene. El valor correspondiente de cada entrada contiene la información relevante asociada con esa extensión:

  1. El transitiveDigest es el resumen de la implementación de la extensión y sus archivos .bzl transitivos.
  2. El generatedRepoSpecs es el resultado de ejecutar esa extensión con la entrada actual.

Un factor adicional que puede afectar los resultados de la extensión son sus usos. Aunque no se almacenan en el archivo bloqueado, los usos se tienen en cuenta cuando se compara el estado actual de la extensión con el del archivo de bloqueo.

Prácticas recomendadas

Para maximizar los beneficios de la función de bloqueo de archivo, ten en cuenta las siguientes prácticas recomendadas:

  • Actualiza con regularidad el archivo de bloqueo para reflejar los cambios en las dependencias o la configuración del proyecto. Esto garantiza que las compilaciones posteriores se basen en el conjunto de dependencias más actualizado y preciso.

  • Incluye el archivo bloqueado en el control de versión para facilitar la colaboración y garantizar que todos los miembros del equipo tengan acceso al mismo archivo de bloqueo, lo que promueve entornos de desarrollo coherentes en todo el proyecto.

  • Usa bazelisk para ejecutar Bazel y, luego, incluye un archivo .bazelversion en el control de versión que especifique la versión de Bazel correspondiente al archivo de bloqueo. Debido a que Bazel en sí es una dependencia de tu compilación, el archivo de bloqueo es específico de la versión de Bazel y cambia incluso entre versiones de Bazel compatibles con versiones anteriores. El uso de bazelisk garantiza que todos los desarrolladores usen una versión de Bazel que coincida con el archivo de bloqueo.

Si sigues estas prácticas recomendadas, puedes usar de manera eficaz la función de archivo de bloqueo en Bazel, lo que generará flujos de trabajo de desarrollo de software más eficientes, confiables y colaborativos.