Un módulo de Bazel es un proyecto de Bazel que puede tener varias versiones, cada una de las cuales que publica metadatos sobre otros módulos de los que depende. Este es análogo a los conceptos conocidos en otros sistemas de gestión de dependencias, como un Artefacto de Maven, un paquete de npm, un módulo de Go o un contenedor de Cargo
Un módulo debe tener un archivo MODULE.bazel
en su raíz de repositorio (junto al
WORKSPACE
). Este archivo es el manifiesto del módulo, que declara su nombre
la versión, la lista de dependencias directas y otra información. Para obtener una
ejemplo:
module(name = "my-module", version = "1.0")
bazel_dep(name = "rules_cc", version = "0.0.1")
bazel_dep(name = "protobuf", version = "3.19.0")
Consulta la lista completa de directivas disponibles en archivos MODULE.bazel
.
Para llevar a cabo la resolución del módulo, Bazel comienza por leer el archivo
MODULE.bazel
y, luego, solicita repetidamente el nombre de cualquier dependencia
MODULE.bazel
de un registro de Bazel hasta que
descubre todo el gráfico de la dependencia.
De forma predeterminada, Bazel selecciona una versión de cada módulo. usar. Bazel representa cada módulo con un repositorio y consulta el registro. de nuevo para aprender a definir cada repositorio.
Formato de la versión
Bazel tiene un ecosistema diverso y los proyectos usan varios esquemas de control de versiones. El
el más popular por mucho es SemVer, pero hay
también destaca proyectos con diferentes esquemas,
Abseil, cuyo
se basan en fechas, por ejemplo, 20210324.2
).
Por este motivo, Bzlmod adopta una versión más relajada de la especificación de SemVer. El Estas son algunas de las diferencias:
- SemVer prescribe que la "liberación" parte de la versión debe constar de 3
segmentos:
MAJOR.MINOR.PATCH
. En Bazel, este requisito se flexibiliza, por lo que que se permite cualquier cantidad de segmentos. - En SemVer, cada uno de los segmentos del “lanzamiento” debe contener solo dígitos. En Bazel, esto se flexibiliza para permitir letras también, y la comparación la semántica coinciden con los “identificadores” en la sección “Versión preliminar” de una parte del proyecto.
- Además, la semántica de los aumentos mayores, secundarios y de versiones de parche son sin aplicar de manera forzosa. Sin embargo, consulta el nivel de compatibilidad para detalles sobre cómo denotamos la retrocompatibilidad.
Cualquier versión válida de SemVer es una versión válida del módulo de Bazel. Además, dos
Las versiones a
y b
de SemVer comparan a < b
si y solo si se cumple lo mismo cuando
se comparan con versiones de módulos de Bazel.
Selección de versión
Considera el problema de la dependencia de diamante, un elemento básico en la dependencia con control de versiones de una organización. Supongamos que tienes el gráfico de dependencias:
A 1.0
/ \
B 1.0 C 1.1
| |
D 1.0 D 1.1
¿Qué versión de D
se debería usar? Para resolver esta pregunta, Bzlmod usa la
Selección de versión mínima
(MVS) en el sistema de módulos de Go. MVS asume que todos los datos
de un módulo son retrocompatibles, por lo que elige la versión más alta
especificado por cualquier dependiente (D 1.1
en nuestro ejemplo). Se llama “mínimo”
porque D 1.1
es la primera versión que podría satisfacer nuestros requisitos:
incluso si existen D 1.2
o una versión posterior, no las seleccionamos. Con MVS, se crea un
que es de alta fidelidad y reproducible.
Versiones ya compartidas
El registro puede declarar que ciertas versiones son retiradas si deben evitarse.
(por ejemplo, para las vulnerabilidades de seguridad). Bazel muestra un error cuando se selecciona un
de un módulo. Para corregir este error, actualiza a una versión más reciente
versión no editada ni usar la
--allow_yanked_versions
marca para permitir explícitamente la versión ya realizada.
Nivel de compatibilidad
En Go, la suposición de MVS sobre la retrocompatibilidad funciona porque trata
versiones incompatibles con versiones anteriores de un módulo como un módulo independiente. En términos de
SemVer, lo que significa que A 1.x
y A 2.x
se consideran módulos distintos y pueden
coexistir en el gráfico de dependencias resuelto. A su vez, esto es posible gracias a
a la versión principal en la ruta del paquete en Go, por lo que
conflictos de tiempo de compilación
o de vinculación.
Sin embargo, Bazel no puede proporcionar esas garantías, por lo que necesita la "versión principal".
para detectar versiones incompatibles con versiones anteriores. Este número se llama
el nivel de compatibilidad y se especifica mediante la versión de cada módulo en su
directiva module()
. Con esta información, Bazel puede arrojar un error cuando
detecta las versiones del mismo módulo con diferentes niveles de compatibilidad
existen en el gráfico de dependencias resuelto.
Anula
Especifica anulaciones en el archivo MODULE.bazel
para alterar el comportamiento de Bazel
resolución del módulo. Solo tienen efecto las anulaciones del módulo raíz; si se trata de un módulo
como dependencia, se ignoran sus anulaciones.
Cada anulación se especifica para un nombre de módulo determinado, lo que afecta a en el gráfico de dependencias. Aunque solo las anulaciones del módulo raíz toman pueden ser para dependencias transitivas que el módulo raíz no dependen directamente.
Anulación de versión única
La single_version_override
tiene varios propósitos:
- Con el atributo
version
, puedes fijar una dependencia a un elemento independientemente de las versiones de la dependencia que se soliciten en el gráfico de dependencias. - Con el atributo
registry
, puedes forzar esta dependencia para que provenga de un en lugar de seguir el registro normal de selección. - Con los atributos
patch*
, puedes especificar un conjunto de parches para aplicar a el módulo descargado.
Todos estos atributos son opcionales y se pueden combinar entre sí.
Anulación de varias versiones
Un objeto multiple_version_override
se puede especificar para permitir que múltiples versiones del mismo módulo coexistan en la
gráfico de dependencia resuelto.
Puedes especificar una lista explícita de versiones permitidas para el módulo, que deben deben estar presentes en el gráfico de la dependencia antes de la resolución; debe existir alguna dependencia transitiva según cada versión permitida. Después del del módulo, solo quedan las versiones permitidas, mientras que Bazel actualiza otras versiones del módulo a la versión más cercana permitida y con nivel de compatibilidad. Si no hay una versión posterior permitida con la misma compatibilidad existente, Bazel arroja un error.
Por ejemplo, si las versiones 1.1
, 1.3
, 1.5
, 1.7
y 2.0
existen en el
gráfico de dependencias antes de la resolución y la versión principal es la de compatibilidad
nivel:
- Una anulación de varias versiones que permite
1.3
,1.7
y2.0
da como resultado Se actualizará1.1
a1.3
,1.5
se actualizará a1.7
, y otras versiones restantes que sean iguales. - Una anulación de varias versiones que permite
1.5
y2.0
da como resultado un error, como1.7
no tiene una versión posterior con el mismo nivel de compatibilidad para actualizar. - Una anulación de varias versiones que permite
1.9
y2.0
da como resultado un error, como1.9
no está presente en el gráfico de dependencia antes de la resolución.
Además, los usuarios pueden anular el registro con el registry
.
de manera similar a las anulaciones de una sola versión.
Anulaciones que no son de registro
Las anulaciones que no son de registro quitan un módulo por completo de la resolución de la versión. Bazel
no solicita estos archivos MODULE.bazel
de un registro, sino de
el repo en sí.
Bazel admite las siguientes anulaciones que no son de registro:
Define repositorios que no representen módulos de Bazel
Con bazel_dep
, puedes definir repositorios que representen a otros módulos de Bazel.
A veces, es necesario definir un repositorio que no represente un Bazel.
module; por ejemplo, uno que contenga un archivo JSON sin formato para que se lea como datos.
En este caso, podrías usar el método use_repo_rule
directiva para definir directamente un repositorio
invocando una regla de repositorio. Este repo solo será visible para el módulo al que
definidos.
En niveles más profundos, esto se implementa usando el mismo mecanismo que el módulo , que te permite definir repositorios con más y flexibilidad.
Nombres de repositorios y dependencias estrictas
El nombre aparente de un repositorio que respalda un
módulo a sus dependientes directos es el nombre predeterminado del nombre de módulo, a menos que el
Atributo repo_name
de bazel_dep
directiva dice lo contrario. Ten en cuenta que esto significa que un módulo solo puede encontrar su
dependencias. Esto ayuda a evitar fallas accidentales debido a cambios en
las dependencias transitivas.
El nombre canónico de un repositorio que respalda un
módulo es module_name~version
(por ejemplo, bazel_skylib~1.0.3
) o module_name~
(por ejemplo, bazel_features~
), dependiendo de si hay
varias versiones del módulo en todo el gráfico de la dependencia (consulta
multiple_version_override
).
Ten en cuenta que el formato de nombre canónico no es una API en la que debas confiar.
está sujeto a cambios en cualquier momento. En lugar de codificar el nombre canónico,
usa una forma admitida para obtenerla directamente de Bazel:
* En los archivos BUILD y .bzl
, usa
Label.repo_name
en una instancia Label
Se crea a partir de una cadena de etiqueta proporcionada por el nombre aparente del repositorio, p.ej.,
Label("@bazel_skylib").repo_name
* Cuando busques archivos runfiles, usa
$(rlocationpath ...)
o una de las bibliotecas de archivos de ejecución
@bazel_tools//tools/{bash,cpp,java}/runfiles
o, para un conjunto de reglas rules_foo
,
en @rules_foo//foo/runfiles
.
* Cuando interactúes con Bazel desde una herramienta externa, como un IDE o un lenguaje
usa el comando bazel mod dump_repo_mapping
para obtener la asignación
nombres aparentes a nombres canónicos de un conjunto determinado de repositorios.
Las extensiones de módulos también pueden incluir repositorios adicionales. dentro del alcance visible de un módulo.