Esta página es el manual de referencia del Lenguaje de consulta de Bazel que se usa
cuando usas bazel query
para analizar las dependencias de compilación. También se describen los formatos de salida que admite bazel query
.
Para ver casos de uso prácticos, consulta el Instructivo de consulta de Bazel.
Referencia adicional de consulta
Además de query
, que se ejecuta en el gráfico de destino de la fase posterior a la carga, Bazel incluye la consulta de gráfico de acciones y la consulta configurable.
Consulta de grafo de acción
La consulta del gráfico de acciones (aquery
) opera en el gráfico de destino configurado después del análisis y expone información sobre las acciones, los artefactos y sus relaciones. aquery
es útil cuando te interesan las propiedades de las acciones o artefactos generados a partir del gráfico de destino configurado.
Por ejemplo, los comandos reales que se ejecutan y sus entradas, salidas y mnemotecnias.
Para obtener más detalles, consulta la referencia de aquery.
Consulta configurable
La consulta tradicional de Bazel se ejecuta en el gráfico de destino de la fase posterior a la carga y, por lo tanto, no tiene el concepto de configuraciones ni sus conceptos relacionados. En particular,
no resuelve correctamente las sentencias de selección
y, en su lugar, muestra todas las resoluciones posibles de las selecciones. Sin embargo, el entorno de consulta configurable, cquery
, controla correctamente las configuraciones, pero no proporciona todas las funciones de esta consulta original.
Para obtener más detalles, consulta la referencia de cquery.
Ejemplos
¿Cómo usan bazel query
las personas? Estos son algunos ejemplos típicos:
¿Por qué el árbol //foo
depende de //bar/baz
?
Mostrar una ruta:
somepath(foo/..., //bar/baz:all)
¿De qué bibliotecas C++ dependen todas las pruebas foo
del objetivo foo_bin
?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
Tokens: La sintaxis léxica
Las expresiones en el lenguaje de consulta se componen de los siguientes marcadores:
Palabras clave, como
let
. Las palabras clave son las palabras reservadas del lenguaje y cada una de ellas se describe a continuación. El conjunto completo de palabras clave es:Palabras, como "
foo/...
", ".*test rule
" o "//bar/baz:all
". Si una secuencia de caracteres está entre comillas (comienza y termina con una comilla simple ' o comienza y termina con una comilla doble "), es una palabra. Si una secuencia de caracteres no está entre comillas, es posible que se analice como una palabra. Las palabras sin comillas son secuencias de caracteres extraídos de los caracteres del alfabeto A-Za-z, los números del 0 al 9 y los caracteres especiales*/@.-_:$~[]
(asterisco, barra, arroba, punto, guion, guion bajo, dos puntos, signo de dólar, virgulilla, corchete izquierdo y corchete derecho). Sin embargo, las palabras sin comillas no pueden comenzar con un guion-
ni un asterisco*
, aunque los nombres de destino relativos pueden comenzar con esos caracteres.Las palabras sin comillas tampoco pueden incluir los caracteres signo más
+
o signo igual=
, aunque esos caracteres se permiten en los nombres de destino. Cuando escribas código que genere expresiones de consulta, los nombres de destino deben ir entre comillas.Es necesario usar comillas cuando se escriben secuencias de comandos que construyen expresiones de consulta de Bazel a partir de valores proporcionados por el usuario.
//foo:bar+wiz # WRONG: scanned as //foo:bar + wiz. //foo:bar=wiz # WRONG: scanned as //foo:bar = wiz. "//foo:bar+wiz" # OK. "//foo:bar=wiz" # OK.
Ten en cuenta que estas comillas se suman a las que pueda requerir tu shell, como las siguientes:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
Las palabras clave y los operadores, cuando están entrecomillados, se tratan como palabras comunes. Por ejemplo,
some
es una palabra clave, pero "some" es una palabra.foo
y “foo” son palabras.Sin embargo, ten cuidado cuando uses comillas simples o dobles en los nombres de los objetivos. Cuando cites uno o más nombres de destino, usa solo un tipo de comillas (todas simples o todas dobles).
Los siguientes son ejemplos de cómo será la cadena de consulta de Java:
'a"'a' # WRONG: Error message: unclosed quotation. "a'"a" # WRONG: Error message: unclosed quotation. '"a" + 'a'' # WRONG: Error message: unexpected token 'a' after query expression '"a" + ' "'a' + "a"" # WRONG: Error message: unexpected token 'a' after query expression ''a' + ' "a'a" # OK. 'a"a' # OK. '"a" + "a"' # OK "'a' + 'a'" # OK
Elegimos esta sintaxis para que no se necesiten comillas en la mayoría de los casos. El ejemplo (inusual) de
".*test rule"
necesita comillas: comienza con un punto y contiene un espacio. No es necesario, pero no es dañino, citar"cc_library"
.Puntuación, como paréntesis
()
, punto.
y coma,
. Las palabras que contengan signos de puntuación (aparte de las excepciones enumeradas anteriormente) deben ir entre comillas.
Se ignoran los caracteres de espacio en blanco fuera de una palabra entre comillas.
Conceptos del lenguaje de consulta de Bazel
El lenguaje de consulta de Bazel es un lenguaje de expresiones. Cada expresión se evalúa como un conjunto parcialmente ordenado de objetivos o, de manera equivalente, un gráfico (DAG) de objetivos. Este es el único tipo de datos.
El conjunto y el gráfico se refieren al mismo tipo de datos, pero enfatizan diferentes aspectos, por ejemplo:
- Establecer: El orden parcial de los objetivos no es interesante.
- Gráfico: El orden parcial de los objetivos es significativo.
Ciclos en el gráfico de dependencias
Los gráficos de dependencias de compilación deben ser acíclicos.
Los algoritmos que usa el lenguaje de consulta están diseñados para su uso en grafos acíclicos, pero son sólidos respecto de los ciclos. No se especifican los detalles de cómo se tratan los ciclos y no se debe confiar en ellos.
Dependencias implícitas
Además de las dependencias de compilación definidas de forma explícita en los archivos BUILD
, Bazel agrega dependencias implícitas adicionales a las reglas. Por ejemplo, cada regla de Java depende implícitamente de JavaBuilder. Las dependencias implícitas se establecen mediante atributos que comienzan con $
y no se pueden anular en archivos BUILD
.
Según la configuración predeterminada, bazel query
tiene en cuenta dependencias implícitas cuando se calcula el resultado de la consulta. Este comportamiento se puede cambiar con la opción --[no]implicit_deps
. Ten en cuenta que, como la consulta no tiene en cuenta las configuraciones, nunca se consideran las posibles cadenas de herramientas.
Solidez
Las expresiones del lenguaje de consulta de Bazel operan en el gráfico de dependencias de compilación, que es el gráfico que definen implícitamente todas las declaraciones de reglas en todos los archivos BUILD
. Es importante comprender que este gráfico es un poco abstracto y no constituye una descripción completa de cómo realizar todos los pasos de una compilación. Para realizar una compilación, también se requiere una configuración. Consulta la sección configurations de la Guía del usuario para obtener más detalles.
El resultado de evaluar una expresión en el lenguaje de consulta de Bazel es verdadero para todas las configuraciones, lo que significa que puede ser una sobreestimación conservadora y no ser del todo precisa. Si usas la herramienta de consulta para calcular el conjunto de todos los archivos de origen necesarios durante una compilación, es posible que se informe más de lo que realmente es necesario porque, por ejemplo, la herramienta de consulta incluirá todos los archivos necesarios para admitir la traducción de mensajes, aunque no tengas la intención de usar esa función en tu compilación.
Sobre la preservación del orden del gráfico
Las operaciones conservan las restricciones de ordenamiento heredadas de sus subexpresiones. Puedes pensar en esto como “la ley de conservación del orden parcial”. Considera un ejemplo: si emites una consulta para determinar el cierre transitivo de las dependencias de un objetivo en particular, el conjunto resultante se ordena según el grafo de dependencias. Si filtras ese conjunto para que incluya solo los destinos de la categoría file
, se mantiene la misma relación de orden parcial transitiva entre cada par de objetivos en el subconjunto resultante, aunque ninguno de estos pares esté conectado directamente en el gráfico original.
(No hay bordes de archivo de archivo en el gráfico de dependencia de compilación).
Sin embargo, si bien todos los operadores preservan el orden, algunas operaciones, como las operaciones de conjunto, no introducen ninguna restricción de orden propia. Considera esta expresión:
deps(x) union y
Se garantiza que el orden del conjunto de resultados final conserve todas las restricciones de orden de sus subexpresiones, es decir, que todas las dependencias transitivas de x
estén ordenadas correctamente entre sí. Sin embargo, la consulta no garantiza nada sobre el orden de los objetivos en y
ni sobre el orden de los objetivos en deps(x)
en relación con los de y
(excepto por aquellos objetivos en y
que también están en deps(x)
).
Entre los operadores que introducen restricciones de orden, se incluyen los siguientes: allpaths
, deps
, rdeps
, somepath
y los comodines de patrones de destino package:*
, dir/...
, etcétera.
Búsqueda de cielo
Sky Query es un modo de consulta que opera sobre un alcance universal especificado.
Funciones especiales disponibles solo en SkyQuery
El modo de consulta de Sky tiene las funciones de consulta adicionales allrdeps
y rbuildfiles
. Estas funciones operan en todo el
alcance del universo (por lo que no tienen sentido para la consulta normal).
Especifica un alcance de universo
Para activar el modo de consulta de Sky, pasa las siguientes dos marcas: (--universe_scope
o --infer_universe_scope
) y --order_output=no
.
--universe_scope=<target_pattern1>,...,<target_patternN>
le indica a la consulta que cargue previamente la clausura transitiva del patrón de destino especificado por los patrones de destino, que pueden ser aditivos y sustractivos. Luego, todas las consultas se evalúan en este "alcance". En particular, los operadores allrdeps
y rbuildfiles
solo muestran resultados de este alcance.
--infer_universe_scope
le dice a Bazel que infiera un valor para --universe_scope
a partir de la expresión de consulta. Este valor inferido es la lista de patrones de destino únicos en la expresión de consulta, pero es posible que no sea lo que deseas. Por ejemplo:
bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"
La lista de patrones de destino únicos en esta expresión de consulta es ["//my:target"]
, por lo que Bazel lo trata de la misma manera que la invocación:
bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"
Sin embargo, el resultado de esa consulta con --universe_scope
es solo //my:target
; ninguna de las dependencias inversas de //my:target
está en el universo, por construcción. Por otro lado, ten en cuenta lo siguiente:
bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"
Esta es una invocación de consulta significativa que intenta calcular los destinos de prueba en la expansión tests
de los destinos en algunos directorios que dependen de forma transitiva de destinos cuya definición usa un archivo .bzl
determinado. Aquí, --infer_universe_scope
es una conveniencia, en especial en el caso en que la elección de --universe_scope
requeriría que analices la expresión de consulta por tu cuenta.
Por lo tanto, para las expresiones de consulta que usan operadores centrados en el universo, como allrdeps
y rbuildfiles
, asegúrate de usar --infer_universe_scope
solo si su comportamiento es lo que deseas.
Sky Query tiene algunas ventajas y desventajas en comparación con la consulta predeterminada. La principal desventaja es que no puede ordenar su salida según el orden del gráfico y, por lo tanto, se prohíben ciertos formatos de salida. Sus ventajas son que proporciona dos operadores (allrdeps
y rbuildfiles
) que no están disponibles en la consulta predeterminada.
Además, Sky Query hace su trabajo mediante la introspección del gráfico de Skyframe, en lugar de crear un gráfico nuevo, que es lo que hace la implementación predeterminada. Por lo tanto, hay algunas circunstancias en las que es más rápido y usa menos memoria.
Expresiones: Sintaxis y semántica de la gramática
Esta es la gramática del lenguaje de consulta de Bazel, expresada en notación EBNF:
expr ::= word
| let name = expr in expr
| (expr)
| expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
| set(word *)
| word '(' int | word | expr ... ')'
En las siguientes secciones, se describe cada una de las producciones de esta gramática en orden.
Patrones de segmentación
expr ::= word
Sintácticamente, un patrón de objetivo es solo una palabra. Se interpreta como un conjunto (no ordenado) de objetivos. El patrón de destino más simple es una etiqueta, que identifica un solo destino (archivo o regla). Por ejemplo, el patrón de destino //foo:bar
se evalúa como un conjunto que contiene un elemento, el objetivo, la regla bar
.
Los patrones de destino generalizan las etiquetas para incluir comodines en paquetes y objetivos. Por ejemplo, foo/...:all
(o solo foo/...
) es un patrón objetivo
que se evalúa como un conjunto que contiene todas las reglas en cada paquete de forma recursiva
debajo del directorio foo
. bar/baz:all
es un patrón objetivo que se evalúa
como un conjunto que contiene todas las reglas del paquete bar/baz
, pero no sus
subpaquetes.
De manera similar, foo/...:*
es un patrón de destino que se evalúa como un conjunto que contiene todos los objetivos (archivos de reglas y) en cada paquete de forma recursiva debajo del directorio foo
. bar/baz:*
se evalúa como un conjunto que contiene todos los destinos del paquete bar/baz
, pero no sus subpaquetes.
Debido a que el comodín :*
coincide con archivos y reglas, a menudo es más útil que :all
para las consultas. Por el contrario, el comodín :all
(implícito en patrones de destino como foo/...
) suele ser más útil para las compilaciones.
Los patrones de destino bazel query
funcionan de la misma manera que los destinos de compilación bazel build
. Para obtener más información, consulta Patrones de destino o escribe bazel help target-syntax
.
Los patrones de destino pueden evaluarse como un conjunto singleton (en el caso de una etiqueta), un conjunto que contiene muchos elementos (como en el caso de foo/...
, que tiene miles de elementos) o un conjunto vacío, si el patrón de destino no coincide con ningún objetivo.
Todos los nodos en el resultado de una expresión de patrón de destino se ordenan correctamente en relación con los demás según la relación de dependencia. Por lo tanto, el resultado de foo:*
no es solo el conjunto de destinos en el paquete foo
, sino también el gráfico sobre esos destinos. (No se hacen garantías sobre el orden relativo de los nodos de resultados en relación con otros nodos). Para obtener más detalles, consulta la sección Orden del gráfico.
Variables
expr ::= let name = expr1 in expr2
| $name
El lenguaje de consulta de Bazel permite definiciones de variables y referencias a ellas. El resultado de la evaluación de una expresión let
es el mismo que el de expr2, con todos los casos gratuitos de la variable name reemplazados por el valor de expr1.
Por ejemplo, let v = foo/... in allpaths($v, //common) intersect $v
es equivalente a allpaths(foo/...,//common) intersect foo/...
.
Una ocurrencia de una referencia de variable name
que no sea en una expresión let name = ...
envolvente es un error. En otras palabras, las expresiones de consulta de nivel superior no pueden tener variables libres.
En las producciones gramaticales anteriores, name
es como word, pero con la restricción adicional de que es un identificador legal en el lenguaje de programación C. Las referencias a la variable deben anteponerse con el carácter "$".
Cada expresión let
define solo una variable, pero puedes anidarlas.
Tanto los patrones de destino como las referencias de variables consisten en un solo token, una palabra, lo que crea una ambigüedad sintáctica. Sin embargo, no hay ambigüedad semántica, ya que el subconjunto de palabras que son nombres de variables legales no se superpone con el subconjunto de palabras que son patrones de destino legales.
Técnicamente hablando, las expresiones let
no aumentan la expresividad del lenguaje de consulta: cualquier consulta que se pueda expresar en el lenguaje también se puede expresar sin ellas. Sin embargo, mejoran la concisión de muchas consultas y también pueden generar una evaluación de consultas más eficiente.
Expresiones entre paréntesis
expr ::= (expr)
Los paréntesis asocian subexpresiones para forzar un orden de evaluación. Una expresión entre paréntesis se evalúa como el valor de su argumento.
Operaciones algebraicas de conjuntos: intersección, unión y diferencia de conjuntos
expr ::= expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
Estos tres operadores calculan las operaciones de conjunto habituales sobre sus argumentos.
Cada operador tiene dos formas: una nominal, como intersect
, y una simbólica, como ^
. Ambas formas son equivalentes; las formas simbólicas son más rápidas de escribir. (Para mayor claridad, en el resto de esta página se usan las formas nominales).
Por ejemplo:
foo/... except foo/bar/...
Se evalúa como el conjunto de objetivos que coinciden con foo/...
, pero no con foo/bar/...
.
Puedes escribir la misma consulta de la siguiente manera:
foo/... - foo/bar/...
Las operaciones intersect
(^
) y union
(+
) son conmutativas (simétricas); except
(-
) es asimétrica. El analizador trata a los tres operadores como asociativos a la izquierda y de igual precedencia, por lo que es posible que quieras paréntesis. Por
ejemplo, las dos primeras de estas expresiones son equivalentes, pero la tercera no:
x intersect y union z
(x intersect y) union z
x intersect (y union z)
Leer destinos de una fuente externa: establecer
expr ::= set(word *)
El operador set(a b c ...)
calcula la unión de un conjunto de cero o más patrones de destino, separados por espacios en blanco (sin comas).
En conjunto con la función $(...)
de la shell de Bourne, set()
proporciona un medio para guardar los resultados de una consulta en un archivo de texto normal, manipular ese archivo de texto con otros programas (como las herramientas de shell estándar de UNIX) y, luego, volver a ingresar el resultado en la herramienta de consultas como un valor para continuar con el procesamiento. Por ejemplo:
bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"
En el siguiente ejemplo,se calcula kind(cc_library, deps(//some_dir/foo:main, 5))
filtrando los valores de maxrank
con un programa awk
.
bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"
En estos ejemplos, $(<foo)
es un atajo para $(cat foo)
, pero también se pueden usar comandos de shell distintos de cat
, como el comando awk
anterior.
Funciones
expr ::= word '(' int | word | expr ... ')'
El lenguaje de consulta define varias funciones. El nombre de la función determina la cantidad y el tipo de argumentos que requiere. Las siguientes funciones están disponibles:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
Cierre transitivo de dependencias: deps
expr ::= deps(expr)
| deps(expr, depth)
El operador deps(x)
se evalúa como el grafo formado por la clausura transitiva de las dependencias de su conjunto de argumentos x. Por ejemplo, el valor de deps(//foo)
es el gráfico de dependencia que tiene su raíz en el nodo único foo
, incluidas todas sus dependencias. El valor de deps(foo/...)
son los gráficos de dependencias cuyas raíces son todas las reglas de cada paquete debajo del directorio foo
. En este contexto,
"dependencias" significa solo objetivos de reglas y archivos, por lo tanto, los archivos BUILD
y
Starlark necesarios para crear estos objetivos no se incluyen aquí. Para ello, debes usar el operador buildfiles
.
El gráfico resultante se ordena según la relación de dependencia. Para obtener más detalles, consulta la sección sobre el orden de los gráficos.
El operador deps
acepta un segundo argumento opcional, que es un número entero literal que especifica un límite superior en la profundidad de la búsqueda. Por lo tanto, deps(foo:*, 0)
muestra todos los destinos del paquete foo
, mientras que deps(foo:*, 1)
incluye además los requisitos previos directos de cualquier destino del paquete foo
, y deps(foo:*, 2)
incluye además los nodos a los que se puede acceder directamente desde los nodos de deps(foo:*, 1)
, y así sucesivamente. (Estos números corresponden a las clasificaciones que se muestran en el formato de salida minrank
).
Si se omite el parámetro depth, la búsqueda no tiene límites: calcula el cierre transitivo reflexivo de los requisitos previos.
Cierre transitivo de dependencias inversas: rdeps
expr ::= rdeps(expr, expr)
| rdeps(expr, expr, depth)
El operador rdeps(u, x)
se evalúa como las dependencias inversas del conjunto de argumentos x dentro del cierre transitivo del conjunto de universo u.
El gráfico resultante se ordena según la relación de dependencia. Consulta la sección sobre el orden del gráfico para obtener más detalles.
El operador rdeps
acepta un tercer argumento opcional, que es un número entero literal que especifica un límite superior en la profundidad de la búsqueda. El grafo resultante solo incluye nodos ubicados dentro de una distancia de la profundidad especificada de cualquier nodo del conjunto de argumentos. Por lo tanto, rdeps(//foo, //common, 1)
se evalúa en todos los nodos
de la clausura transitiva de //foo
que dependen directamente de //common
. (Estos números corresponden a las clasificaciones que se muestran en el formato de salida de minrank
). Si se omite el parámetro depth, la búsqueda no tiene límites.
Cierre transitivo de todas las dependencias inversas: allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
El operador allrdeps
se comporta de la misma manera que el operador rdeps
, excepto que el "conjunto de universo" es cualquier valor al que se evalúe la marca --universe_scope
, en lugar de especificarse por separado. Por lo tanto, si se pasó --universe_scope=//foo/...
, allrdeps(//bar)
es equivalente a rdeps(//foo/..., //bar)
.
Dependencias inversas directas en el mismo paquete: same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
El operador same_pkg_direct_rdeps(x)
evalúa el conjunto completo de destinos que se encuentran en el mismo paquete que uno del conjunto de argumentos y que dependen directamente de él.
Cómo lidiar con el paquete de un destino: hermanos
expr ::= siblings(expr)
El operador siblings(x)
evalúa el conjunto completo de destinos que se encuentran en el mismo paquete que un destino del conjunto de argumentos.
Elección arbitraria: algunos
expr ::= some(expr)
| some(expr, count )
El operador some(x, k)
selecciona, de forma arbitraria, como máximo k objetivos de su conjunto de argumentos x y se evalúa como un conjunto que contiene solo esos objetivos. El parámetro k es opcional. Si falta, el resultado será un conjunto singleton que contiene solo un objetivo seleccionado de forma arbitraria. Si el tamaño del conjunto de argumentos x es menor que k, se mostrará todo el conjunto de argumentos x.
Por ejemplo, la expresión some(//foo:main union //bar:baz)
se evalúa como un conjunto singleton que contiene //foo:main
o //bar:baz
, aunque no está definido. La expresión some(//foo:main union //bar:baz, 2)
o some(//foo:main union //bar:baz, 3)
muestra //foo:main
y //bar:baz
.
Si el argumento es un singleton, some
calcula la función de identidad: some(//foo:main)
equivale a //foo:main
.
Se produce un error si el conjunto de argumentos especificado está vacío, como en la expresión some(//foo:main intersect //bar:baz)
.
Operadores de ruta de acceso: somepath, allpaths
expr ::= somepath(expr, expr)
| allpaths(expr, expr)
Los operadores somepath(S, E)
y allpaths(S, E)
calculan las rutas entre dos conjuntos de objetivos. Ambas consultas aceptan dos argumentos: un conjunto S de puntos de partida y un conjunto E de puntos finales. somepath
muestra el gráfico de nodos en alguna ruta de acceso arbitraria de un destino en S a un destino en E. allpaths
muestra el gráfico de nodos en todas las rutas de acceso de cualquier destino en S a cualquier destino en E.
Los gráficos resultantes se ordenan según la relación de dependencia. Consulta la sección sobre el orden del gráfico para obtener más detalles.
Filtrado de tipos de objetivos: similares
expr ::= kind(word, expr)
El operador kind(pattern, input)
aplica un filtro a un conjunto de destinos y descarta aquellos que no son del tipo esperado. El parámetro pattern especifica qué tipo de objetivo debe coincidir.
Por ejemplo, los tipos de los cuatro destinos definidos por el archivo BUILD
(para el paquete p
) que se muestran a continuación se ilustran en la tabla:
Código | Objetivo | Tipo |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
Regla genrule |
//p:a.in |
archivo fuente | |
//p:a.out |
archivo generado | |
//p:BUILD |
archivo fuente |
Por lo tanto, kind("cc_.* rule", foo/...)
se evalúa como el conjunto de todos los objetivos de reglas cc_library
, cc_binary
, etc., debajo de foo
, y kind("source file", deps(//foo))
se evalúa como el conjunto de todos los archivos fuente en el cierre transitivo de dependencias del objetivo //foo
.
A menudo, se requieren las comillas del argumento pattern porque sin él, el analizador no considera palabras regulares a muchas expresiones regulares, como source
file
y .*_test
.
Cuando se realiza la coincidencia para package group
, es posible que los objetivos que terminan en :all
no generen ningún resultado. Utiliza :all-targets
en lugar de esta función.
Filtrado de nombres de objetivos: filtro
expr ::= filter(word, expr)
El operador filter(pattern, input)
aplica un filtro a un conjunto de objetivos y descarta los objetivos cuyas etiquetas (en forma absoluta) no coinciden con el patrón. Se evalúa como un subconjunto de su entrada.
El primer argumento, pattern, es una palabra que contiene una expresión regular sobre los nombres de destino. Una expresión filter
se evalúa como el conjunto que contiene todos los destinos x, de modo que x sea un miembro del conjunto input y la etiqueta (en forma absoluta, como //foo:bar
) de x contenga una coincidencia (sin anclaje) para la expresión regular pattern. Dado que todos los nombres de destino comienzan con //
, se puede usar como alternativa al ancla de expresión regular ^
.
Este operador suele proporcionar una alternativa mucho más rápida y sólida al operador intersect
. Por ejemplo, para ver todas las dependencias bar
del destino //foo:foo
, se podría evaluar
deps(//foo) intersect //bar/...
Sin embargo, esta sentencia requerirá el análisis de todos los archivos BUILD
en el árbol bar
, lo que será lento y propenso a errores en archivos BUILD
irrelevantes. Una alternativa sería la siguiente:
filter(//bar, deps(//foo))
Esto primero calcularía el conjunto de dependencias //foo
y, luego, filtraría solo los objetivos que coincidan con el patrón proporcionado; es decir, objetivos con nombres que contengan //bar
como substring.
Otro uso común del operador filter(pattern,
expr)
es filtrar archivos específicos por su nombre o extensión. Por ejemplo:
filter("\.cc$", deps(//foo))
proporcionará una lista de todos los archivos .cc
que se usaron para compilar //foo
.
Filtrado de atributos de la regla: attr
expr ::= attr(word, word, expr)
El operador attr(name, pattern, input)
aplica un filtro a un conjunto de objetivos y descarta los objetivos que no son reglas, los objetivos de reglas que no tienen definido el atributo name o los objetivos de reglas en los que el valor del atributo no coincide con la expresión regular pattern proporcionada. Evalúa un subconjunto de su entrada.
El primer argumento, name, es el nombre del atributo de la regla que debe coincidir con el patrón de expresión regular proporcionado. El segundo argumento, pattern, es una expresión regular sobre los valores del atributo. Una expresión attr
se evalúa como el conjunto que contiene todos los objetivos x, de modo que x sea un miembro del conjunto input, sea una regla con el atributo definido name y el valor del atributo contenga una coincidencia (sin anclaje) para la expresión regular pattern. Si name es un atributo opcional y la regla no lo especifica de forma explícita, se usará el valor predeterminado del atributo para la comparación. Por ejemplo:
attr(linkshared, 0, deps(//foo))
Seleccionará todas las dependencias de //foo
que pueden tener un atributo linkshared (como la regla cc_binary
) y lo establecerán explícitamente en 0 o no lo establecerán en absoluto, pero el valor predeterminado es 0 (como en el caso de las reglas cc_binary
).
Los atributos de tipo de lista (como srcs
, data
, etc.) se convierten en strings con el formato [value<sub>1</sub>, ..., value<sub>n</sub>]
, que comienzan con un corchete [
, terminan con un corchete ]
y usan ",
" (coma, espacio) para delimitar varios valores.
Las etiquetas se convierten en cadenas con el formato absoluto de la etiqueta. Por ejemplo, un atributo deps=[":foo",
"//otherpkg:bar", "wiz"]
se convertiría en la cadena [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
.
Los corchetes siempre están presentes, por lo que la lista vacía usaría el valor de cadena []
para la coincidencia. Por ejemplo:
attr("srcs", "\[\]", deps(//foo))
seleccionará todas las reglas entre las dependencias de //foo
que tengan un atributo srcs
vacío, mientras que
attr("data", ".{3,}", deps(//foo))
seleccionará todas las reglas de las dependencias //foo
que especifiquen al menos un valor en el atributo data
(cada etiqueta tiene al menos 3 caracteres debido a //
y :
).
Para seleccionar todas las reglas entre las dependencias de //foo
con un value
en particular en un atributo de tipo de lista, usa
attr("tags", "[\[ ]value[,\]]", deps(//foo))
Esto funciona porque el carácter antes de value
será [
o un espacio, y el carácter después de value
será una coma o ]
.
Filtrado de visibilidad de la regla: visible
expr ::= visible(expr, expr)
El operador visible(predicate, input)
aplica un filtro a un conjunto de destinos y descarta los destinos sin la visibilidad requerida.
El primer argumento, predicate, es un conjunto de destinos a los que deben ser visibles todos los destinos en el resultado. Una expresión visible se evalúa como el conjunto que contiene todos los destinos x, de modo que x sea un miembro del conjunto input y, para todos los destinos y en predicate, x sea visible para y. Por ejemplo:
visible(//foo, //bar:*)
seleccionará todos los objetivos del paquete //bar
en los que //foo
puede depender sin infringir las restricciones de visibilidad.
Evaluación de los atributos de regla de tipo etiqueta: etiquetas
expr ::= labels(word, expr)
El operador labels(attr_name, inputs)
muestra el conjunto de objetivos especificados en el atributo attr_name de tipo "etiqueta" o "lista de etiquetas" en alguna regla del conjunto inputs.
Por ejemplo, labels(srcs, //foo)
muestra el conjunto de objetivos que aparecen en el atributo srcs
de la regla //foo
. Si hay varias reglas con atributos srcs
en el conjunto inputs, se muestra la unión de sus srcs
.
Expande y filtra test_suites: tests
expr ::= tests(expr)
El operador tests(x)
muestra el conjunto de todas las reglas de prueba en el conjunto x, expande cualquier regla test_suite
al conjunto de pruebas individuales al que hacen referencia y aplica el filtrado por tag
y size
.
De forma predeterminada, la evaluación de consultas ignora los objetivos que no son de prueba en todas las reglas test_suite
. Esto se puede cambiar a errores con la opción --strict_test_suite
.
Por ejemplo, la consulta kind(test, foo:*)
enumera todas las reglas *_test
y test_suite
en el paquete foo
. Todos los resultados son (por
definición) miembros del paquete foo
. Por el contrario,
la consulta tests(foo:*)
mostrará todas las
pruebas individuales que ejecutaría bazel test
foo:*
: esto puede incluir pruebas que pertenezcan a otros paquetes
a las que se haga referencia directa o indirectamente
mediante reglas test_suite
.
Archivos de definición de paquetes: buildfiles
expr ::= buildfiles(expr)
El operador buildfiles(x)
muestra el conjunto de archivos que definen los paquetes de cada destino en el conjunto x. En otras palabras, para cada paquete, su archivo BUILD
, además de cualquier archivo .bzl al que haga referencia a través de load
. Ten en cuenta que esto también muestra los archivos BUILD
de los paquetes que contienen estos archivos load
.
Por lo general, este operador se usa cuando se determina qué archivos o paquetes son necesarios para compilar un destino especificado, a menudo junto con la opción --output package
(más abajo). Por ejemplo:
bazel query 'buildfiles(deps(//foo))' --output package
Muestra el conjunto de todos los paquetes de los que //foo
depende transitivamente.
Archivos de definición de paquetes: rbuildfiles
expr ::= rbuildfiles(word, ...)
El operador rbuildfiles
toma una lista separada por comas de fragmentos de ruta de acceso y muestra el conjunto de archivos BUILD
que dependen transitivamente de esos fragmentos de ruta de acceso. Por ejemplo, si //foo
es un paquete, rbuildfiles(foo/BUILD)
mostrará el destino //foo:BUILD
. Si el archivo foo/BUILD
contiene load('//bar:file.bzl'...
, rbuildfiles(bar/file.bzl)
mostrará el destino //foo:BUILD
, así como los destinos de cualquier otro archivo BUILD
que cargue //bar:file.bzl
.
El alcance del operador --universe_scope
. Los archivos que no corresponden directamente a los archivos BUILD
y .bzl
no afectan los resultados. Por ejemplo, los archivos de origen (como foo.cc
) se ignoran, incluso si se mencionan de forma explícita en el archivo BUILD
. Sin embargo, se respetan los symlinks, de modo que si foo/BUILD
es un symlink a bar/BUILD
, rbuildfiles(bar/BUILD)
incluirá //foo:BUILD
en sus resultados.
El operador rbuildfiles
es casi moralmente el inverso del operador buildfiles
. Sin embargo, esta inversión moral se mantiene con más fuerza en una dirección: los resultados de rbuildfiles
son como las entradas de buildfiles
; el primero solo contendrá destinos de archivos BUILD
en paquetes, y el segundo puede contener esos destinos. En la otra dirección, la correspondencia es más débil. Los resultados del operador buildfiles
son objetivos que corresponden a todos los paquetes y .Los archivos bzl
que necesita una entrada determinada Sin embargo, las entradas del operador rbuildfiles
no son esos destinos, sino los fragmentos de ruta que corresponden a esos destinos.
Archivos de definición de paquetes: loadfiles
expr ::= loadfiles(expr)
El operador loadfiles(x)
muestra el conjunto de archivos de Starlark necesarios para cargar los paquetes de cada destino en el conjunto x. En otras palabras, para cada paquete, muestra los archivos .bzl a los que se hace referencia desde sus archivos BUILD
.
Formatos de salida
bazel query
genera un gráfico.
Especificas el contenido, el formato y el orden con los que bazel query
presenta este gráfico a través de la opción de línea de comandos --output
.
Cuando se ejecuta con Sky Query, solo se permiten los formatos de salida que son compatibles con la salida desordenada. En específico, se prohíben los formatos de salida graph
, minrank
y maxrank
.
Algunos de los formatos de salida aceptan opciones adicionales. El nombre de cada opción de salida tiene el prefijo del formato de salida al que se aplica, por lo que --graph:factored
solo se aplica cuando se usa --output=graph
; no tiene efecto si se usa un formato de salida distinto de graph
. Del mismo modo, --xml:line_numbers
solo se aplica cuando se usa --output=xml
.
Sobre el orden de los resultados
Aunque las expresiones de consulta siempre siguen la "ley de la conservación del orden del gráfico", la presentación de los resultados se puede hacer de forma ordenada o desordenada. Esto no influye en los objetivos del conjunto de resultados ni en la forma en que se calcula la consulta. Solo afecta la forma en que se imprimen los resultados en stdout. Además, los nodos que son equivalentes en el orden de dependencia pueden estar ordenados alfabéticamente o no.
Se puede usar la marca --order_output
para controlar este comportamiento.
(La marca --[no]order_results
tiene un subconjunto de la funcionalidad de la marca --order_output
y dejó de estar disponible).
El valor predeterminado de esta marca es auto
, que imprime los resultados en orden alfabético. Sin embargo, cuando se usa somepath(a,b)
, los resultados se imprimen en orden deps
.
Cuando esta marca es no
y --output
es uno de los siguientes valores: build
, label
, label_kind
, location
, package
, proto
o xml
, los resultados se imprimirán en orden arbitrario. Por lo general, esta es la opción más rápida. Sin embargo, no se admite cuando
--output
es uno de graph
, minrank
o
maxrank
: con estos formatos, Bazel siempre imprime resultados ordenados por el orden o clasificación de dependencia.
Cuando esta marca es deps
, Bazel imprime los resultados en un orden topológico, es decir,
primero las dependencias. Sin embargo, los nodos que no están ordenados por el orden de dependencia (porque no hay una ruta de acceso de uno a otro) se pueden imprimir en cualquier orden.
Cuando esta marca es full
, Bazel imprime nodos en un orden completamente determinista (total).
Primero, todos los nodos se ordenan alfabéticamente. Luego, cada nodo de la lista se usa como el inicio de una búsqueda en profundidad posorden en la que se recorren los bordes salientes a los nodos no visitados en orden alfabético de los nodos sucesores. Por último, los nodos se imprimen en el revés del orden en que se visitaron.
La impresión de nodos en este orden puede ser más lenta, por lo que se debe usar solo cuando el determinismo sea importante.
Imprime el formulario de origen de los destinos como aparecerían en BUILD
--output build
Con esta opción, la representación de cada objetivo es como si se hubiera escrito a mano en el lenguaje BUILD. Todas las variables y llamadas a función (como glob, macros) se expanden, lo que es útil para ver el efecto de las macros de Starlark. Además, cada regla efectiva informa un valor generator_name
o generator_function
, que indica el nombre de la macro que se evaluó para generar la regla efectiva.
Aunque el resultado usa la misma sintaxis que los archivos BUILD
, no se garantiza que se genere un archivo BUILD
válido.
Imprime la etiqueta de cada objetivo
--output label
Con esta opción, se imprime el conjunto de nombres (o etiquetas) de cada objetivo en el gráfico resultante, una etiqueta por línea, en orden topológico (a menos que se especifique --noorder_results
, consulta las notas sobre el orden de los resultados).
(un ordenamiento topológico es aquel en el que un nodo del grafo aparece antes que todos sus sucesores). Por supuesto, hay muchos ordenamientos topológicos posibles de un gráfico (el orden pospostre inverso es solo uno); no se especifica cuál se elige.
Cuando se imprime el resultado de una consulta somepath
, el orden en el que se imprimen los nodos es el orden de la ruta.
Advertencia: En algunos casos excepcionales, puede haber dos destinos distintos con la misma etiqueta; por ejemplo, una regla sh_binary
y su único archivo srcs
(implícito) pueden llamarse foo.sh
. Si el resultado de una consulta contiene ambos objetivos, el resultado (en formato label
) parecerá contener un duplicado. Cuando usas el formato label_kind
(consulta a continuación), la distinción es clara: los dos destinos tienen el mismo nombre, pero uno tiene el tipo sh_binary rule
y el otro tipo source file
.
Imprime la etiqueta y el tipo de cada objetivo
--output label_kind
Al igual que label
, este formato de salida imprime las etiquetas de cada destino en el gráfico resultante, en orden topológico, pero, además, precede a la etiqueta con el tipo del destino.
Cómo imprimir objetivos en formato de búfer de protocolo
--output proto
Imprime el resultado de la consulta como un búfer de protocolo QueryResult
.
Cómo imprimir objetivos en formato de búfer de protocolo de longitud delimitada
--output streamed_proto
Imprime un flujo de búferes de protocolo Target
delimitado por longitud. Esto es útil para (i) evitar las limitaciones de tamaño de los búferes de protocolo cuando hay demasiados destinos para caber en un solo QueryResult
o (ii) para iniciar el procesamiento mientras Bazel aún está generando resultados.
Cómo imprimir destinos en formato proto de texto
--output textproto
Al igual que --output proto
, imprime el búfer de protocolo QueryResult
, pero en formato de texto.
Imprime destinos en formato ndjson
--output streamed_jsonproto
Similar a --output streamed_proto
, imprime un flujo de búferes de protocolo Target
, pero en formato ndjson.
Imprime la etiqueta de cada objetivo, en orden de clasificación
--output minrank --output maxrank
Al igual que label
, los formatos de salida minrank
y maxrank
imprimen las etiquetas de cada objetivo en el gráfico resultante, pero en lugar de aparecer en orden topológico, aparecen en orden de clasificación, precedidos por su número de clasificación. Estos no se ven afectados por la marca --[no]order_results
de orden de resultados (consulta las notas sobre el orden de los resultados).
Existen dos variantes de este formato: minrank
clasifica cada nodo según la longitud de la ruta más corta desde un nodo raíz hasta él.
Los nodos “raíz” (aquellos que no tienen aristas entrantes) son de rango 0, sus sucesores son de rango 1, etcétera. (Como siempre, las aristas apuntan de un objetivo a sus requisitos previos: los objetivos de los que depende).
maxrank
clasifica cada nodo según la longitud de la ruta más larga desde un nodo raíz hasta él. Una vez más, las “raíces” tienen el rango 0, y todos los demás
nudos tienen un rango que es uno mayor que el rango máximo de todos
sus predecesores.
Todos los nodos de un ciclo se consideran de igual rango. (La mayoría de los grafos son acíclicos, pero los ciclos ocurren simplemente porque los archivos BUILD
contienen ciclos erróneos).
Estos formatos de salida son útiles para descubrir qué tan profundo es un gráfico. Si se usan para el resultado de una consulta deps(x)
, rdeps(x)
o allpaths
, el número de clasificación es igual a la longitud de la ruta más corta (con minrank
) o más larga (con maxrank
) de x
a un nodo en esa clasificación. maxrank
se puede usar para determinar la secuencia más larga de pasos de compilación necesarios para compilar un destino.
Por ejemplo, el gráfico de la izquierda genera los resultados de la derecha cuando se especifican --output minrank
y --output maxrank
, respectivamente.
minrank 0 //c:c 1 //b:b 1 //a:a 2 //b:b.cc 2 //a:a.cc |
maxrank 0 //c:c 1 //b:b 2 //a:a 2 //b:b.cc 3 //a:a.cc |
Imprime la ubicación de cada objetivo
--output location
Al igual que label_kind
, esta opción imprime, para cada objetivo en el resultado, el tipo y la etiqueta del objetivo, pero se le antepone una cadena que describe la ubicación de ese objetivo, como un nombre de archivo y un número de línea. El formato se parece al resultado de grep
. Por lo tanto, las herramientas que pueden analizar estos últimos (como Emacs
o vi) también pueden usar el resultado de la consulta para revisar una serie de
coincidencias, lo que permite que la herramienta de consultas de Bazel se use como
un “grep para archivos BUILD” con reconocimiento de gráficos de dependencia.
La información de ubicación varía según el tipo de objetivo (consulta el operador kind). En el caso de las reglas, se imprime la ubicación de la declaración de la regla dentro del archivo BUILD
.
En el caso de los archivos fuente, se imprime la ubicación de la línea 1 del archivo real. En el caso de un archivo generado, se muestra la ubicación de la regla que lo genera. (La herramienta de consultas no tiene suficiente información para encontrar la ubicación real del archivo generado y, en cualquier caso, es posible que no exista si aún no se realizó una compilación).
Cómo imprimir el conjunto de paquetes
--output package
Esta opción imprime el nombre de todos los paquetes a los que pertenece un objetivo del conjunto de resultados. Los nombres se imprimen en orden alfabético y se excluyen los duplicados. De forma formal, esta es una proyección del conjunto de etiquetas (paquete, destino) a los paquetes.
Los paquetes de los repositorios externos tienen el formato @repo//foo/bar
, mientras que los paquetes del repositorio principal tienen el formato foo/bar
.
Junto con la consulta deps(...)
, esta opción de salida se puede usar para encontrar el conjunto de paquetes que se deben comprobar para compilar un conjunto determinado de destinos.
Cómo mostrar un gráfico del resultado
--output graph
Esta opción hace que el resultado de la consulta se imprima como un gráfico dirigido en el popular formato AT&T GraphViz. Por lo general, el resultado se guarda en un archivo, como .png
o .svg
.
(Si el programa dot
no está instalado en tu estación de trabajo, puedes instalarlo con el comando sudo apt-get install graphviz
). Consulta la sección de ejemplo a continuación para ver una invocación de muestra.
Este formato de salida es particularmente útil para las consultas allpaths
, deps
o rdeps
, en las que el resultado incluye un conjunto de rutas que no se pueden visualizar fácilmente cuando se renderizan de forma lineal, como con --output label
.
De forma predeterminada, el gráfico se renderiza en un formato factorizado. Es decir, los nodos topológicamente equivalentes se combinan en un solo nodo con varias etiquetas. Esto hace que el gráfico sea más compacto y legible, ya que los gráficos de resultados típicos contienen patrones muy repetitivos. Por ejemplo, una regla java_library
puede depender de cientos de archivos de origen de Java generados por el mismo genrule
. En el gráfico factorizado, todos estos archivos están representados por un solo nodo. Este comportamiento se puede inhabilitar con la opción --nograph:factored
.
--graph:node_limit n
La opción especifica la longitud máxima de la cadena de etiqueta para un nodo de gráfico en el resultado. Las etiquetas más largas se truncarán. -1 inhabilita la truncación. Debido al formato factorizado en el que se imprimen los grafos, las etiquetas de los nodos pueden ser muy largas. GraphViz no puede controlar etiquetas que superen los 1,024 caracteres, que es el valor predeterminado de esta opción. Esta opción no tiene efecto, a menos que se use --output=graph
.
--[no]graph:factored
De forma predeterminada, los gráficos se muestran en formato factorizado, como se explicó anteriormente.
Cuando se especifica --nograph:factored
, los gráficos se imprimen sin factorización. Esto hace que la visualización con GraphViz no sea práctica, pero el formato más simple puede facilitar el procesamiento de otras herramientas (como grep). Esta opción no tiene ningún efecto
a menos que se use --output=graph
.
XML
--output xml
Esta opción hace que los destinos resultantes se impriman en un formato XML. El resultado comienza con un encabezado XML como este:
<?xml version="1.0" encoding="UTF-8"?>
<query version="2">
Luego, continúa con un elemento XML para cada objetivo en el gráfico de resultados, en orden topológico (a menos que se soliciten resultados desordenados) y termina con una solicitud
</query>
Se emiten entradas simples para los destinos del tipo file
:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
Sin embargo, en el caso de las reglas, el XML está estructurado y contiene definiciones de todos los atributos de la regla, incluidos aquellos cuyo valor no se especificó de forma explícita en el archivo BUILD
de la regla.
Además, el resultado incluye elementos rule-input
y rule-output
para que se pueda reconstruir la topología del grafo de dependencias sin tener que saber que, por ejemplo, los elementos del atributo srcs
son dependencias hacia adelante (requisitos previos) y el contenido del atributo outs
son dependencias hacia atrás (consumidores).
Los elementos rule-input
para las dependencias implícitas se suprimen si se especifica --noimplicit_deps
.
<rule class='cc_binary rule' name='//foo:foo' ...>
<list name='srcs'>
<label value='//foo:foo_main.cc'/>
<label value='//foo:bar.cc'/>
...
</list>
<list name='deps'>
<label value='//common:common'/>
<label value='//collections:collections'/>
...
</list>
<list name='data'>
...
</list>
<int name='linkstatic' value='0'/>
<int name='linkshared' value='0'/>
<list name='licenses'/>
<list name='distribs'>
<distribution value="INTERNAL" />
</list>
<rule-input name="//common:common" />
<rule-input name="//collections:collections" />
<rule-input name="//foo:foo_main.cc" />
<rule-input name="//foo:bar.cc" />
...
</rule>
Cada elemento XML de un destino contiene un atributo name
, cuyo valor es la etiqueta del destino, y un atributo location
, cuyo valor es la ubicación del destino tal como la imprime --output location
.
--[no]xml:line_numbers
De forma predeterminada, las ubicaciones que se muestran en el resultado del archivo XML incluyen números de línea.
Cuando se especifica --noxml:line_numbers
, no se imprimen los números de línea.
--[no]xml:default_values
De forma predeterminada, el resultado XML no incluye el atributo de regla cuyo valor es el valor predeterminado para ese tipo de atributo (por ejemplo, si no se especificó en el archivo BUILD
o si el valor predeterminado se proporcionó de forma explícita). Esta opción hace que esos valores de atributos se incluyan en el resultado XML.
Expresiones regulares
Las expresiones regulares en el lenguaje de consulta usan la biblioteca de expresiones regulares de Java, por lo que puedes usar la sintaxis completa para java.util.regex.Pattern
.
Cómo consultar con repositorios externos
Si la compilación depende de reglas de repositorios externos (definidas en el archivo WORKSPACE), los resultados de la consulta incluirán estas dependencias. Por
ejemplo, si //foo:bar
depende de //external:some-lib
y //external:some-lib
está vinculado a @other-repo//baz:lib
, entonces
bazel query 'deps(//foo:bar)'
mostrará @other-repo//baz:lib
y
//external:some-lib
como dependencias.
Los repositorios externos no son dependencias de una compilación. Es decir, en
el ejemplo anterior, //external:other-repo
no es una dependencia. Sin embargo, se puede consultar como miembro del paquete //external
, por ejemplo:
# Querying over all members of //external returns the repository.
bazel query 'kind(http_archive, //external:*)'
//external:other-repo
# ...but the repository is not a dependency.
bazel query 'kind(http_archive, deps(//foo:bar))'
INFO: Empty results