En esta página, se explica cómo crear reglas de repositorio y se proporcionan ejemplos para obtener más detalles.
Un repositorio externo es una regla que solo se puede usar
en el archivo WORKSPACE y que permite una operación no hermética en la fase de carga
de Bazel. Cada regla de repositorio externo crea su propio espacio de trabajo, con sus
propios BUILD archivos y artefactos. 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.
Creación de reglas de repositorio
En un archivo .bzl, usa la
repository_rule para crear una regla de
repositorio nueva y almacenarla en una variable global.
Se puede usar una regla de repositorio personalizada como una regla de repositorio nativa. Tiene un atributo name obligatorio y se puede hacer referencia a cada destino presente en sus archivos de compilación
como @<name>//package:target donde <name> es el valor del
atributo name.
La regla se carga cuando la compilas de forma explícita o si es una dependencia de
la compilación. En este caso, Bazel ejecutará su función implementation. Esta
función describe cómo crear el repositorio, su contenido y los archivos BUILD.
Atributos
Los atributos son argumentos de reglas que se pasan como un diccionario al argumento de regla attrs.
Los atributos y sus tipos se definen y se enumeran cuando defines una
regla de repositorio. Un ejemplo que define los atributos url y sha256 como
cadenas:
local_repository = repository_rule(
implementation=_impl,
local=True,
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 atributos definidos de forma implícita (al igual que las reglas de compilación
). Los dos atributos implícitos son name (al igual que para las reglas de compilación) y
repo_mapping. Se puede acceder al nombre de una regla de repositorio con
repository_ctx.name. El significado de repo_mapping es el mismo que para las
reglas de repositorio nativas
local_repository
y
new_local_repository.
Si un nombre de atributo comienza con _, es privado y los usuarios no pueden configurarlo.
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 devuelve None para indicar que la regla es reproducible con los parámetros especificados o un diccionario con un conjunto de parámetros para esa regla que la convertirían en una regla reproducible que genera el mismo repositorio. Por ejemplo, para una regla que hace un seguimiento de un repositorio de Git, esto significaría devolver un identificador de confirmación específico en lugar de una rama flotante que se especificó originalmente.
El parámetro de entrada repository_ctx se puede usar para acceder a valores de atributos y funciones no herméticas (buscar un objeto binario, ejecutar un objeto binario, crear un archivo en el repositorio o descargar un archivo de Internet). Consulta la biblioteca 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 un 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. Luego, se espera que la función de implementación cree el repositorio en el sistema de archivos. Esto se denomina "recuperación" del repositorio.
A diferencia de los destinos normales, los repositorios no se vuelven a recuperar necesariamente cuando cambia algo que haría que el repositorio sea diferente. Esto se debe a que hay elementos para los que Bazel no puede detectar cambios o que causarían una sobrecarga excesiva 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 elementos:
- Los parámetros que se pasan a la declaración del repositorio en el archivo
WORKSPACE. - El código de Starlark que comprende la implementación del repositorio.
- El valor de cualquier variable de entorno declarada con el
environatributo de larepository_rule. Los valores de estas variables de entorno se pueden conectar de forma directa en la línea de comandos con la--action_envmarca (pero esta marca invalidará cada acción de la compilación). - El contenido de cualquier archivo que se pase a los métodos
read(),execute()y similares derepository_ctxal que se hace referencia con una etiqueta (por ejemplo,//mypkg:label.txt, pero nomypkg/label.txt) - Cuando se ejecuta
bazel sync.
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 enbazel synccuando se le pasa el parámetro--configure(si el atributo no está configurado, este comando no provocará una recuperación). Si se configura la marca
local, además de los casos anteriores, el repositorio también se vuelve a recuperar cuando se reinicia el servidor de Bazel o cuando cambia cualquier archivo que afecte la declaración del repositorio (p. ej., el archivoWORKSPACEo un archivo que carga), independientemente de si los cambios provocaron un cambio en la declaración del repositorio o en su código.En estos casos, no se vuelven a recuperar los repositorios no locales. Esto se debe a que se supone que estos repositorios se comunican con la red o son costosos.
Cómo reiniciar la función de implementación
La función de implementación se puede reiniciar mientras se recupera un repositorio si falta una dependencia que solicita. En ese caso, se detendrá la ejecución de la función de implementación, se resolverá la dependencia faltante y se volverá a ejecutar la función después de que se resuelva la dependencia. Para evitar reinicios innecesarios (que son costosos, ya que tal vez se deba repetir el acceso a la red), se recuperan previamente los argumentos de etiquetas, 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 cadena o una etiqueta que se creó solo durante la ejecución de la función aún podría causar un reinicio.
Cómo forzar la recuperación de repositorios externos
A veces, un repositorio externo puede quedar obsoleto sin que se modifique su
definición o sus dependencias. Por ejemplo, un repositorio que recupera fuentes puede
seguir una rama en particular de un repositorio de terceros, y hay confirmaciones nuevas están
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 sync.
Además, algunas reglas inspeccionan la máquina local y podrían quedar obsoletas si esta se actualizó. Aquí puedes pedirle a Bazel que solo vuelva a recuperar los repositorios externos en los que la definición de repository_rule tenga establecido el atributo configure, mediante bazel sync --configure.
Ejemplos
Cadena de herramientas de C++ configurada automáticamente: Usa una regla de repositorio para crear automáticamente los archivos de configuración de C++ para Bazel buscando el compilador local de C++, el entorno y las marcas que admite el compilador de C++.
Los repositorios de Go usan varias reglas
repository_rulepara definir la lista de dependencias necesarias para usar las reglas de Go.rules_jvm_external crea un repositorio externo llamado
@mavende forma predeterminada que genera destinos de compilación para cada artefacto de Maven en el árbol de dependencias transitivas.