Reglas del repositorio

Informar un problema Ver fuente Noche /}1}

En esta página, se explica cómo definir las reglas del repositorio y se proporcionan ejemplos para obtener más detalles.

Un repositorio externo es un árbol de directorios que contiene archivos de origen que se pueden usar en una compilación de Bazel, que se genera a pedido mediante la ejecución de la regla de repositorio correspondiente. Los repositorios se pueden definir de muchas maneras, pero, en última instancia, cada repositorio se define invocando una regla de repositorio, del mismo modo que los objetivos de compilación se definen a través de la invocación de reglas de compilación. Se pueden usar para depender de bibliotecas de terceros (como bibliotecas empaquetadas de Maven), pero también para generar archivos BUILD específicos del host en el que se ejecuta Bazel.

Definición de la regla del repositorio

En un archivo .bzl, usa la función repository_rule para definir una regla de repositorio nueva y almacénala en una variable global. Una vez que se define una regla de repositorio, se puede invocar como una función para definir repositorios. Por lo general, esta invocación se realiza desde dentro de una función de implementación de extensión de módulo.

Los dos componentes principales de una definición de reglas de repositorio son su esquema de atributos y la función de implementación. El esquema de atributos determina los nombres y tipos de atributos que se pasan a una invocación de regla de repositorio, y la función de implementación se ejecuta cuando se debe recuperar el repositorio.

Atributos

Los atributos son argumentos que se pasan a la invocación de la regla del repositorio. El esquema de los atributos que acepta una regla de repositorio se especifica con el argumento attrs cuando la regla de repositorio se define con una llamada a repository_rule. Ejemplo de cómo definir los atributos url y sha256 como strings:

http_archive = repository_rule(
    implementation=_impl,
    attrs={
        "url": attr.string(mandatory=True)
        "sha256": attr.string(mandatory=True)
    }
)

Para acceder a un atributo dentro de la función de implementación, usa repository_ctx.attr.<attribute_name>:

def _impl(repository_ctx):
    url = repository_ctx.attr.url
    checksum = repository_ctx.attr.sha256

Todos los repository_rule tienen el atributo name definido de forma implícita. Este es un atributo de cadena que se comporta de forma mágica: cuando se especifica como una entrada a la invocación de una regla de repositorio, toma un nombre de repositorio aparente. Sin embargo, cuando se lee desde la función de implementación de la regla del repositorio con repository_ctx.attr.name, muestra el nombre del repositorio canónico.

Función de implementación

Cada regla de repositorio requiere una función implementation. Contiene la lógica real de la regla y se ejecuta estrictamente en la fase de carga.

La función tiene exactamente un parámetro de entrada, repository_ctx. La función muestra None para indicar que la regla se puede reproducir según los parámetros especificados o un diccionario con un conjunto de parámetros para esa regla que convertiría esa regla en una reproducible que genera el mismo repositorio. Por ejemplo, para una regla que realiza un seguimiento de un repositorio de Git, esto implicaría mostrar un identificador de confirmación específico en lugar de una rama flotante que se especificó en un principio.

El parámetro de entrada repository_ctx se puede usar para acceder a valores de atributos y a funciones no herméticas (encontrar un objeto binario, ejecutarlo, crear un archivo en el repositorio o descargar un archivo de Internet). Consulta los documentos de la API para obtener más contexto. Ejemplo:

def _impl(repository_ctx):
  repository_ctx.symlink(repository_ctx.attr.path, "")

local_repository = repository_rule(
    implementation=_impl,
    ...)

¿Cuándo se ejecuta la función de implementación?

La función de implementación de una regla de repositorio se ejecuta cuando Bazel necesita un destino de ese repositorio, por ejemplo, cuando otro destino (en otro repositorio) depende de él o si se menciona en la línea de comandos. Se espera que la función de implementación cree el repositorio en el sistema de archivos. Esto se llama "recuperar" el repo.

A diferencia de los objetivos normales, los repositorios no siempre se vuelven a recuperar cuando hay un cambio que podría hacer que el repositorio sea diferente. Esto se debe a que hay aspectos en los que Bazel no puede detectar cambios o generaría demasiada sobrecarga en cada compilación (por ejemplo, elementos que se recuperan de la red). Por lo tanto, los repositorios se vuelven a recuperar solo si cambia uno de los siguientes cambios:

  • Los atributos que se pasan a la invocación de la regla del repositorio.
  • El código de Starlark, que consta de la implementación de la regla del repositorio.
  • Es el valor de cualquier variable de entorno pasada al método getenv() de repository_ctx o declarada con el atributo environ de repository_rule. Los valores de estas variables de entorno se pueden conectar por cable en la línea de comandos con la marca --repo_env.
  • El contenido de cualquier archivo que se pasa a read(), execute() y métodos similares de repository_ctx, al que hace referencia una etiqueta (por ejemplo, //mypkg:label.txt, pero no mypkg/label.txt)
  • Cuando se ejecuta bazel fetch --force

Hay dos parámetros de repository_rule que controlan cuándo se vuelven a recuperar los repositorios:

  • Si se configura la marca configure, el repositorio solo se vuelve a recuperar el bazel fetch cuando se le pasa el parámetro --configure (si no se establece el atributo, este comando no volverá a recuperar).
  • Si se establece la marca local, además de los casos anteriores, el repositorio también se vuelve a recuperar cuando se reinicia el servidor de Bazel.

Reinicia la función de implementación

Si falta una dependencia que solicita, la función de implementación se puede reiniciar mientras se recupera un repositorio. En ese caso, se detendrá la ejecución de la función de implementación, se resolverá la dependencia faltante y la función se volverá a ejecutar después de que se haya resuelto la dependencia. Para evitar reinicios innecesarios (que son costosos, ya que es posible que haya que repetir el acceso a la red), los argumentos de etiqueta se cargan previamente, siempre que todos los argumentos de etiquetas se puedan resolver en un archivo existente. Ten en cuenta que resolver una ruta de acceso a partir de una string o una etiqueta que se construyó solo durante la ejecución de la función podría causar un reinicio.

Fuerza la recuperación de repositorios externos

A veces, un repositorio externo puede quedar desactualizado sin ningún cambio en su definición o dependencias. Por ejemplo, un repositorio que recupera fuentes podría seguir una rama específica de un repositorio de terceros, y hay nuevas confirmaciones disponibles en esa rama. En este caso, puedes pedirle a Bazel que vuelva a recuperar todos los repositorios externos de forma incondicional llamando a bazel fetch --force --all.

Además, algunas reglas del repositorio inspeccionan la máquina local y podrían quedar desactualizadas si esta se actualiza. Aquí puedes pedirle a Bazel que solo vuelva a recuperar esos repositorios externos en los que la definición repository_rule tenga configurado el atributo configure. Usa bazel fetch --all --configure.

Ejemplos

  • Cadena de herramientas configurada automáticamente de C++: Usa una regla de repositorio para crear automáticamente los archivos de configuración de C++ para Bazel buscando el compilador C++ local, el entorno y las marcas que admite el compilador C++.

  • Los repositorios de Go usan varios repository_rule a fin de definir la lista de dependencias necesarias para usar las reglas de Go.

  • De forma predeterminada, rules_jvm_external crea un repositorio externo llamado @maven que genera destinos de compilación para cada artefacto de Maven en el árbol de dependencias transitivo.