Esta página é o manual de referência para a Linguagem de consulta do Bazel usada quando você usa bazel query
para analisar dependências de versão. Ela também descreve os formatos de saída compatíveis com bazel query
.
Para casos de uso práticos, consulte as Instruções de consulta do Bazel.
Referência de consulta adicional
Além do query
, que é executado no gráfico de destino da fase pós-carregamento, o Bazel inclui a consulta do gráfico de ações e a consulta configurável.
Consulta do gráfico de ação
A consulta do gráfico de ações (aquery
) opera no gráfico de destino configurado pós-análise e expõe informações sobre Ações, Artefatos e os relacionamentos deles. aquery
é útil quando você tem interesse nas propriedades das ações/artefatos gerados do gráfico de destino configurado.
Por exemplo, os comandos reais são executados e as entradas, saídas e elementos mnemônicos.
Para mais detalhes, consulte a referência do Aquery.
Consulta configurável
A consulta tradicional do Bazel é executada no gráfico de destino da fase pós-carregamento e, portanto, não tem um conceito de configurações e conceitos relacionados. Além disso, ele não resolve corretamente declarações de seleção e, em vez disso, retorna todas as resoluções possíveis de seleções. No entanto, o ambiente de consulta configurável cquery
lida corretamente com as configurações, mas não fornece todas as funcionalidades dessa consulta original.
Para mais detalhes, veja a referência de consulta.
Exemplos
Como as pessoas usam o bazel query
? Veja alguns exemplos:
Por que a árvore //foo
depende de //bar/baz
?
Mostrar um caminho:
somepath(foo/..., //bar/baz:all)
Quais bibliotecas C++ dependem de todos os testes foo
que o destino foo_bin
não tem?
kind("cc_library", deps(kind(".*test rule", foo/...)) except deps(//foo:foo_bin))
Tokens: a sintaxe lexical
As expressões na linguagem de consulta são compostas dos seguintes tokens:
Palavras-chave, como
let
. Palavras-chave são as palavras reservadas do idioma, e cada uma delas é descrita abaixo. O conjunto completo de palavras-chave é:Palavras, como "
foo/...
", ".*test rule
" ou "//bar/baz:all
". Se uma sequência de caracteres estiver entre aspas (começa e termina com aspas simples "ou" e termina com aspas duplas"), ela será uma palavra. Se uma sequência de caracteres não for entre aspas, ainda poderá ser analisada como uma palavra. Palavras sem aspas são sequências de caracteres extraídos dos caracteres alfabéticos A-Za-z, numerais de 0 a 9 e caracteres especiais*/@.-_:$~[]
(asterisco, barra invertida, a, ponto, hífen, sublinhado, dois pontos, cifrão, til, colchete esquerdo, colchete direito). No entanto, as palavras sem aspas podem começar com um hífen-
ou um asterisco*
, mesmo que os [nomes de destino][(/concepts/labels#target-names) relativos comecem com esses caracteres.As palavras sem aspas também podem não incluir os caracteres de adição
+
ou de=
, mesmo que esses caracteres sejam permitidos em nomes de destino. Ao escrever o código que gera expressões de consulta, os nomes de destino precisam estar entre aspas.A cotação é necessária ao escrever scripts que constroem expressões de consulta do Bazel a partir de valores fornecidos pelo usuário.
//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.
Essa cota é complementar a qualquer que possa ser exigida pelo shell, como:
bazel query ' "//foo:bar=wiz" ' # single-quotes for shell, double-quotes for Bazel.
Palavras-chave e operadores, quando entre aspas, são tratados como palavras comuns. Por exemplo,
some
é uma palavra-chave, mas "alguns" é uma palavra. Tantofoo
quanto "foo" são palavras.No entanto, tenha cuidado ao usar aspas simples ou duplas em nomes de destino. Ao citar um ou mais nomes de destino, use apenas um tipo de aspas (todas as aspas simples ou duplas).
Veja a seguir exemplos da string de consulta 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
Escolhemos essa sintaxe para que as aspas não sejam necessárias na maioria dos casos. O exemplo (incomum) de
".*test rule"
precisa de aspas: ele começa com um ponto final e contém um espaço. A citação de"cc_library"
é desnecessária, mas inofensiva.Pontuação, como parênteses
()
, período.
e vírgula,
. As palavras que contêm pontuação (exceto as exceções listadas acima) precisam estar entre aspas.
Os caracteres de espaço em branco fora de uma palavra entre aspas são ignorados.
Conceitos da linguagem de consulta do Bazel
A linguagem de consulta do Bazel é uma linguagem de expressões. Cada expressão é avaliada como um conjunto parcialmente ordenado de destinos ou, de maneira equivalente, a um gráfico (DAG) de destinos. Esse é o único tipo de dados.
Set e gráfico referem-se ao mesmo tipo de dados, mas enfatizam aspectos diferentes dele, por exemplo:
- Definido: a ordem parcial dos destinos não é interessante.
- Gráfico: a ordem parcial das segmentações é significativa.
Ciclos no gráfico de dependência
Os gráficos de dependência de compilação devem ser acíclicos.
Os algoritmos usados pela linguagem de consulta se destinam ao uso em gráficos acíclicos, mas são robustos em relação a ciclos. Os detalhes de como os bicicletas são tratados não são especificados e não devem ser usados.
Dependências implícitas
Além de criar dependências definidas explicitamente em arquivos BUILD
, o Bazel adiciona dependências implícitas às regras. Por exemplo, cada regra Java depende implicitamente do JavaBuilder. As dependências implícitas são estabelecidas usando atributos que começam com $
e não podem ser modificadas em arquivos BUILD
.
Por padrão, bazel query
considera dependências implícitas ao computar o resultado da consulta. Esse comportamento pode ser alterado com a opção --[no]implicit_deps
. Como a consulta não considera as configurações, os possíveis conjuntos de ferramentas nunca são considerados.
Som
As expressões da linguagem de consulta do Bazel operam no gráfico de dependência de compilação, que é definido implicitamente por todas as declarações de regra em todos os arquivos BUILD
. É importante entender que esse gráfico é um pouco abstrato e não constitui uma descrição completa de como executar todas as etapas de uma versão. Para realizar uma criação, é necessária uma configuração. Consulte a seção configurações do Guia do usuário para mais detalhes.
O resultado da avaliação de uma expressão na linguagem de consulta do Bazel é verdadeiro para todas as configurações, o que significa que pode ser uma aproximação conservadora e não exatamente precisa. Se você usar a ferramenta de consulta para calcular o conjunto de todos os arquivos de origem necessários durante uma criação, ela poderá informar mais do que realmente é necessário. Por exemplo, a ferramenta de consulta incluirá todos os arquivos necessários para oferecer suporte à tradução de mensagens, mesmo que você não pretenda usar esse recurso na versão.
Preservação da ordem do gráfico
As operações preservam as restrições de ordenação
herdadas das subexpressões. Você pode pensar nisso
como "a lei da preservação da ordem parcial". Considere um exemplo: se você emitir uma consulta para determinar o fechamento transitivo de dependências de um destino específico, o conjunto resultante será ordenado de acordo com o gráfico de dependência. Se você filtrar esse conjunto para incluir apenas os destinos do tipo file
, a mesma relação organizativa de ordenação parcial será mantida entre cada par de destinos no subconjunto resultante, mesmo que nenhum desses pares esteja diretamente conectado no gráfico original.
Não há bordas de arquivo de arquivo no gráfico de dependência de compilação.
No entanto, enquanto todos os operadores preservam a ordem, algumas operações, como as operações set, não introduzem nenhuma restrição de ordem própria. Considere esta expressão:
deps(x) union y
A ordem do conjunto final de resultados preserva todas as restrições de ordem das subexpressões, ou seja, todas as dependências transitivas de x
são ordenadas corretamente em relação umas às outras. No entanto, a consulta não garante nada sobre
a ordem dos destinos em y
, nem sobre a
ordem dos destinos em deps(x)
em relação aos em
y
(exceto para os destinos em
y
que também estão em deps(x)
).
Os operadores que introduzem restrições de ordem incluem: allpaths
, deps
, rdeps
, somepath
e os caracteres curinga do padrão de destino package:*
, dir/...
etc.
Consulta do Sky
O Sky Query é um modo de consulta que opera em um escopo universal especificado.
Funções especiais disponíveis apenas no SkyQuery
O modo de consulta do Sky tem as funções de consulta adicionais allrdeps
e rbuildfiles
. Essas funções operam em todo o escopo universal (por isso, não fazem sentido para a consulta normal).
Como especificar um escopo universal
O modo de consulta do Sky é ativado transmitindo as duas sinalizações a seguir: (--universe_scope
ou --infer_universe_scope
) e --order_output=no
.
--universe_scope=<target_pattern1>,...,<target_patternN>
instrui a consulta a pré-carregar o fechamento transitivo do padrão de destino especificado pelos padrões de destino, que podem ser tanto aditivos quanto subtrativos. Todas as consultas são avaliadas nesse "escopo". Em particular,
os operadores allrdeps
e
rbuildfiles
só retornam resultados desse escopo.
--infer_universe_scope
diz ao Bazel para inferir um valor para --universe_scope
a partir da expressão de consulta. Esse valor inferido é a lista de padrões de destino exclusivos na expressão da consulta, mas pode não ser isso que você quer. Por exemplo:
bazel query --infer_universe_scope --order_output=no "allrdeps(//my:target)"
A lista de padrões de destino exclusivos nessa expressão de consulta é ["//my:target"]
. Portanto, o Bazel trata isso da mesma forma que a invocação:
bazel query --universe_scope=//my:target --order_output=no "allrdeps(//my:target)"
Mas o resultado dessa consulta com --universe_scope
é apenas //my:target
. Nenhuma das dependências inversas de //my:target
está no universo, por construção. Por outro lado, considere o seguinte:
bazel query --infer_universe_scope --order_output=no "tests(//a/... + b/...) intersect allrdeps(siblings(rbuildfiles(my/starlark/file.bzl)))"
Esta é uma invocação de consulta significativa que tenta computar os destinos de teste na expansão de tests
dos destinos em alguns diretórios que dependem temporariamente de destinos em que a definição usa um determinado arquivo .bzl
. Aqui, --infer_universe_scope
é uma conveniência, especialmente no caso em que a escolha de --universe_scope
exigiria que você analisasse a expressão de consulta por conta própria.
Portanto, para expressões de consulta que usam operadores com escopo universal, como
allrdeps
e
rbuildfiles
, use
--infer_universe_scope
apenas se o comportamento desejado.
O Sky Query tem algumas vantagens e desvantagens em comparação com a consulta padrão. A principal desvantagem é que ele não pode ordenar a saída de acordo com a ordem do gráfico e, portanto, determinados formatos de saída são proibidos. As vantagens são que ele fornece dois operadores (allrdeps
e rbuildfiles
) que não estão disponíveis na consulta padrão.
Além disso, a consulta do Sky faz o trabalho introspectivando o gráfico do Skyframe, em vez de criar um novo gráfico, que é o que a implementação padrão faz. Há algumas circunstâncias em que ele é mais rápido e usa menos memória.
Expressões: sintaxe e semântica da gramática
Esta é a gramática da linguagem de consulta do Bazel, expressa na notação 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 ... ')'
As seções a seguir descrevem cada uma das produções dessa gramática em ordem.
Padrões de segmentação
expr ::= word
De maneira sintática, um padrão de destino é apenas uma palavra. Ele é interpretado como um conjunto (não ordenado) de destinos. O padrão de destino mais simples é um rótulo, que identifica um único destino (arquivo ou regra). Por exemplo, o padrão de destino //foo:bar
é avaliado como um conjunto que contém um elemento, o destino, a regra bar
.
Os padrões de destino generalizam os rótulos para incluir caracteres curinga em pacotes e destinos. Por exemplo, foo/...:all
(ou apenas foo/...
) é um padrão de destino
que avalia um conjunto que contém todas as regras em cada pacote abaixo
do diretório foo
. bar/baz:all
é um padrão de destino que avalia
um conjunto contendo todas as regras no pacote bar/baz
, mas não nos
subpacotes.
Da mesma forma, foo/...:*
é um padrão de destino que avalia um conjunto contendo todos os destinos (regras e arquivos) em cada pacote de maneira recursiva abaixo do diretório foo
. bar/baz:*
avalia como um conjunto que contém todos os destinos no pacote bar/baz
, mas não nos subpacotes.
Como o caractere curinga :*
corresponde a arquivos e regras, ele costuma ser mais útil do que :all
para consultas. Por outro lado, o caractere curinga :all
, implícito em padrões de destino como foo/...
, costuma ser mais útil para builds.
Os padrões de destino bazel query
funcionam da mesma forma que os destinos de criação bazel build
. Para mais detalhes, consulte Padrões de destino ou digite bazel help target-syntax
.
Os padrões de destino podem ser avaliados como um conjunto singleton (no caso de um rótulo), como um conjunto que contém muitos elementos (como no caso de foo/...
, que tem milhares de elementos) ou como um conjunto vazio, se o padrão de destino não corresponder a nenhum destino.
Todos os nós no resultado de uma expressão de padrão de destino são ordenados corretamente em relação uns aos outros de acordo com a relação de dependência. Portanto, o resultado de
foo:*
não é apenas o conjunto de destinos no pacote foo
, ele também é o
gráfico sobre esses destinos. Nenhuma garantia é feita sobre a ordem relativa dos nós de resultado em relação a outros nós. Para mais detalhes, consulte a seção ordem do gráfico.
Variáveis
expr ::= let name = expr1 in expr2
| $name
A linguagem de consulta do Bazel permite definições e referências a variáveis. O resultado da avaliação de uma expressão let
é igual ao de expr2, com todas as ocorrências sem custo financeiro da variável name substituídas pelo valor de expr1.
Por exemplo, let v = foo/... in allpaths($v, //common) intersect $v
é equivalente a allpaths(foo/...,//common) intersect foo/...
.
Uma ocorrência de uma referência de variável name
diferente de uma expressão de inclusão let name = ...
é um erro. Em outras palavras, as expressões de consulta de nível superior não podem ter variáveis livres.
Nas produções gramaticais acima, name
é como word, mas com a restrição adicional de ser um identificador legal na linguagem de programação C. As referências à variável devem ser precedidas pelo caractere "$".
Cada expressão let
define apenas uma variável, mas você pode aninhá-las.
Os padrões de destino e as referências de variáveis consistem em apenas um único token, uma palavra, criando uma ambiguidade sintática. No entanto, não há ambiguidade semântica, porque o subconjunto de palavras que são nomes de variáveis legais é separado do subconjunto de palavras que são padrões de segmentação legal.
Tecnicamente falando, as expressões let
não aumentam a expressividade da linguagem de consulta: qualquer consulta expressável na linguagem também pode ser expressa sem elas. No entanto, elas melhoram a concisão de muitas consultas e também podem levar a uma avaliação de consulta mais eficiente.
Expressões entre parênteses
expr ::= (expr)
Parênteses associam subexpressões para forçar uma ordem de avaliação. Uma expressão entre parênteses avalia o valor do argumento.
Operações algébricas de conjuntos: interseção, união, diferença definida
expr ::= expr intersect expr
| expr ^ expr
| expr union expr
| expr + expr
| expr except expr
| expr - expr
Esses três operadores calculam as operações de conjunto habituais sobre os argumentos.
Cada operador tem duas formas, uma nominal, como intersect
, e uma simbólica, como ^
. Ambas as formas são equivalentes. As formas simbólicas são mais rápidas de digitar. Para maior clareza, o restante desta página usa as formas nominais.
Por exemplo:
foo/... except foo/bar/...
avalia o conjunto de segmentações que correspondem a foo/...
, mas não a foo/bar/...
.
É possível escrever a mesma consulta:
foo/... - foo/bar/...
As operações intersect
(^
) e union
(+
) são comutativas (simétricas), e except
(-
) é assimétrica. O analisador considera os três operadores como
associativos à esquerda e de igual precedência. Portanto, é recomendável usar parênteses. Por exemplo, as duas primeiras expressões são equivalentes, mas a terceira não é:
x intersect y union z
(x intersect y) union z
x intersect (y union z)
Ler destinos de uma fonte externa: set
expr ::= set(word *)
O operador set(a b c ...)
calcula a união de um conjunto de zero ou mais padrões de destino, separados por espaço em branco (sem vírgulas).
Em conjunto com o recurso $(...)
do shell Bourne, set()
oferece os meios de salvar os resultados de uma consulta em um arquivo de texto regular, manipulando esse arquivo de texto usando outros programas (como ferramentas de shell padrão do UNIX) e, em seguida, apresentando o resultado na ferramenta de consulta como um valor para processamento adicional. Por exemplo:
bazel query deps(//my:target) --output=label | grep ... | sed ... | awk ... > foo
bazel query "kind(cc_binary, set($(<foo)))"
No próximo exemplo,kind(cc_library, deps(//some_dir/foo:main, 5))
é computado filtrando os valores maxrank
usando um programa awk
.
bazel query 'deps(//some_dir/foo:main)' --output maxrank | awk '($1 < 5) { print $2;} ' > foo
bazel query "kind(cc_library, set($(<foo)))"
Nestes exemplos, $(<foo)
é uma forma abreviada de $(cat foo)
, mas também é possível usar comandos de shell diferentes de cat
, como o comando awk
anterior.
Funções
expr ::= word '(' int | word | expr ... ')'
A linguagem de consulta define várias funções. O nome da função determina o número e o tipo de argumentos necessários. As seguintes funções estão disponíveis:
allpaths
attr
buildfiles
rbuildfiles
deps
filter
kind
labels
loadfiles
rdeps
allrdeps
same_pkg_direct_rdeps
siblings
some
somepath
tests
visible
Fechamento transitivo de dependências: dependências
expr ::= deps(expr)
| deps(expr, depth)
O operador deps(x)
é avaliado como o gráfico formado pelo fechamento transitivo de dependências do conjunto de argumentos x. Por exemplo, o valor de deps(//foo)
é o gráfico de dependência com raiz no único nó foo
, incluindo todas as dependências. O valor de deps(foo/...)
são os gráficos de dependência cujas raízes são todas as regras em cada pacote abaixo do diretório foo
. Nesse contexto,
"dependências" significa apenas destinos de regras e arquivos. Portanto, os arquivos BUILD
e
Starlark necessários para criar esses destinos não estão incluídos aqui. Para isso, use o operador buildfiles
.
O gráfico resultante é ordenado de acordo com a relação de dependência. Para mais detalhes, consulte a seção sobre ordem de gráfico.
O operador deps
aceita um segundo argumento opcional, que é um literal inteiro que especifica um limite superior na profundidade da pesquisa. Portanto, deps(foo:*, 0)
retorna todos os destinos no pacote foo
, enquanto deps(foo:*, 1)
inclui os pré-requisitos diretos de qualquer destino no pacote foo
, e deps(foo:*, 2)
inclui os nós diretamente acessíveis a partir dos nós em deps(foo:*, 1)
e assim por diante. Esses números correspondem às classificações mostradas no formato de saída minrank
.
Se o parâmetro depth for omitido, a pesquisa será ilimitada: ela computa o fechamento transitivo reflexivo dos pré-requisitos.
Fechamento transitivo de dependências reversas: rdeps
expr ::= rdeps(expr, expr)
| rdeps(expr, expr, depth)
O operador rdeps(u, x)
é avaliado como as dependências reversas do conjunto de argumentos x no fechamento transitivo do conjunto universal u.
O gráfico resultante é ordenado de acordo com a relação de dependência. Consulte a seção sobre ordem de gráfico para mais detalhes.
O operador rdeps
aceita um terceiro argumento opcional, que é um literal inteiro que especifica um limite superior na profundidade da pesquisa. O gráfico resultante inclui apenas nós a uma distância da profundidade especificada de qualquer nó no conjunto de argumentos. Portanto, rdeps(//foo, //common, 1)
é avaliado para todos os nós no fechamento transitivo de //foo
que dependem diretamente de //common
. Esses números correspondem às classificações mostradas no formato de saída minrank
. Se o parâmetro depth for omitido, a pesquisa será ilimitada.
Fechamento transitivo de todas as dependências reversas: allrdeps
expr ::= allrdeps(expr)
| allrdeps(expr, depth)
O operador allrdeps
se comporta da mesma forma que o operador rdeps
, mas o "conjunto universal" é aquele que a sinalização --universe_scope
avalia, em vez de ser especificado separadamente. Assim, se --universe_scope=//foo/...
foi transmitido, allrdeps(//bar)
é equivalente a rdeps(//foo/..., //bar)
.
Dependências reversas diretas no mesmo pacote: same_pkg_direct_rdeps
expr ::= same_pkg_direct_rdeps(expr)
O operador same_pkg_direct_rdeps(x)
é avaliado como o conjunto completo de destinos
que estão no mesmo pacote que um destino no conjunto de argumentos e que dependem diretamente dele.
Como lidar com o pacote de um destino: irmãos
expr ::= siblings(expr)
O operador siblings(x)
avalia o conjunto completo de destinos que estão no mesmo pacote que um destino no conjunto de argumentos.
Escolha arbitrária: algumas
expr ::= some(expr)
| some(expr, count )
O operador some(x, k)
seleciona no máximo k destinos arbitrariamente a partir do conjunto de argumentos x e avalia como um conjunto que contém apenas esses destinos. O parâmetro k é opcional. Se ausente, o resultado será um conjunto singleton contendo apenas um destino selecionado arbitrariamente. Se o tamanho do conjunto de argumentos x for menor que k, todo o conjunto de argumentos x será retornado.
Por exemplo, a expressão some(//foo:main union //bar:baz)
é avaliada como um conjunto de singleton que contém //foo:main
ou //bar:baz
, mas qual não está definido. A expressão some(//foo:main union //bar:baz, 2)
ou
some(//foo:main union //bar:baz, 3)
retorna //foo:main
e
//bar:baz
.
Se o argumento for um singleton, some
calculará a função de identidade: some(//foo:main)
é equivalente a //foo:main
.
Caso o conjunto de argumentos especificado esteja vazio, ocorrerá um erro, como na expressão some(//foo:main intersect //bar:baz)
.
Operadores de caminho: somepath, allpaths
expr ::= somepath(expr, expr)
| allpaths(expr, expr)
Os operadores somepath(S, E)
e allpaths(S, E)
calculam caminhos entre dois conjuntos de destinos. Ambas as consultas aceitam dois argumentos, um S definido de pontos de partida e um conjunto de E de pontos finais. somepath
retorna o gráfico de nós em algum caminho arbitrário de um destino em S para um destino em E. allpaths
retorna o gráfico de nós em todos os caminhos de qualquer destino em S para qualquer destino em E.
Os gráficos resultantes são ordenados de acordo com a relação de dependência. Consulte a seção sobre ordem do gráfico para mais detalhes.
somepath(S1 + S2, E) , um resultado possível. |
somepath(S1 + S2, E) , outro resultado possível. |
allpaths(S1 + S2, E) |
Filtragem de tipo de segmentação: tipo
expr ::= kind(word, expr)
O operador kind(pattern, input)
aplica um filtro a um conjunto de destinos e descarta aqueles que não são do tipo esperado. O parâmetro pattern especifica o tipo de segmentação a ser correspondido.
Por exemplo, os tipos dos quatro destinos definidos pelo arquivo BUILD
(para o pacote p
) mostrados abaixo são ilustrados na tabela:
Código | Objetivo | Tipo |
---|---|---|
genrule( name = "a", srcs = ["a.in"], outs = ["a.out"], cmd = "...", ) |
//p:a |
regra geral |
//p:a.in |
arquivo de origem | |
//p:a.out |
arquivo gerado | |
//p:BUILD |
arquivo de origem |
Assim, kind("cc_.* rule", foo/...)
avalia o conjunto de todos os destinos de regras cc_library
, cc_binary
etc. abaixo de foo
, e kind("source file", deps(//foo))
avalia o conjunto de todos os arquivos de origem no fechamento transitivo de dependências do destino //foo
.
A cota do argumento pattern geralmente é necessária
porque, sem ela, muitas expressões regulares, como source
file
e .*_test
, não são consideradas palavras pelo analisador.
Ao fazer a correspondência para package group
, os destinos que terminam em :all
podem não produzir resultados. Em vez disso, use :all-targets
.
Filtragem de nome de destino: filter
expr ::= filter(word, expr)
O operador filter(pattern, input)
aplica um filtro a um conjunto de destinos e descarta os destinos cujos rótulos (na forma absoluta) não correspondem ao padrão. Ele é avaliado como um subconjunto da entrada.
O primeiro argumento, pattern é uma palavra que contém uma expressão regular sobre os nomes de destino. Uma expressão filter
é avaliada como o conjunto que contém todos os destinos x, de modo que x seja membro do conjunto input e o rótulo (na forma absoluta, como //foo:bar
) de x contenha uma correspondência (não ancorada) para a expressão regular pattern. Como todos os nomes de destino começam com //
, ele pode ser usado como uma alternativa à âncora de expressão regular ^
.
Esse operador geralmente fornece uma alternativa muito mais rápida e robusta para o operador intersect
. Por exemplo, para ver todas as dependências bar
do destino //foo:foo
, é possível avaliar
deps(//foo) intersect //bar/...
No entanto, essa instrução exigirá a análise de todos os arquivos BUILD
na árvore bar
, o que será lento e propenso a erros em arquivos BUILD
irrelevantes. Uma alternativa seria:
filter(//bar, deps(//foo))
que primeiro calcula o conjunto de dependências //foo
e, em seguida, filtra apenas os destinos que correspondem ao padrão fornecido. Em outras palavras, os destinos com nomes contendo //bar
como uma substring.
Outro uso comum do operador filter(pattern,
expr)
é filtrar arquivos específicos por nome ou extensão. Por exemplo:
filter("\.cc$", deps(//foo))
fornecerá uma lista de todos os arquivos .cc
usados para criar //foo
.
Filtragem de atributos de regra: attr
expr ::= attr(word, word, expr)
O operador attr(name, pattern, input)
aplica um filtro a um conjunto de metas e descarta as que não são regras, as que não têm o atributo name definido ou as regras em que o valor do atributo não corresponde à expressão regular pattern fornecida. Ele avalia um subconjunto da entrada.
O primeiro argumento, name é o nome do atributo de regra que deve corresponder ao padrão de expressão regular fornecido. O segundo argumento, pattern, é uma expressão regular acima dos valores do atributo. Uma expressão attr
é avaliada como o conjunto que contém todos os destinos x, de modo que x seja um membro do conjunto input, seja uma regra com o atributo definido name e o valor do atributo contenha uma correspondência (não ancorada) para a expressão regular pattern. Se name for um atributo opcional e a regra não o especificar explicitamente, o valor do atributo padrão será usado para comparação. Por exemplo:
attr(linkshared, 0, deps(//foo))
selecionará todas as dependências //foo
com permissão para ter um
atributo "linkshared" (como uma regra cc_binary
) e defini-lo
explicitamente definido como 0 ou não defini-lo, mas o valor padrão é 0 (como para
regras cc_binary
).
Os atributos de tipo de lista (como srcs
, data
etc.) são convertidos em strings no formato [value<sub>1</sub>, ..., value<sub>n</sub>]
, começando com um colchete [
, terminando com um colchete ]
e usando ",
" (vírgula, espaço) para delimitar vários valores.
Os rótulos são convertidos em strings usando a forma absoluta do rótulo. Por exemplo, um atributo deps=[":foo",
"//otherpkg:bar", "wiz"]
seria convertido na string [//thispkg:foo, //otherpkg:bar, //thispkg:wiz]
.
Os colchetes estão sempre presentes. Portanto, a lista vazia usaria o valor de string []
para fins de correspondência. Por exemplo:
attr("srcs", "\[\]", deps(//foo))
selecionará todas as regras entre as dependências //foo
que tenham um
atributo srcs
vazio, enquanto
attr("data", ".{3,}", deps(//foo))
selecionará todas as regras entre as dependências //foo
que especificam pelo menos um valor no atributo data
(cada rótulo tem pelo menos três caracteres devido a //
e :
).
Para selecionar todas as regras entre dependências de //foo
com um value
específico em um
atributo de tipo de lista, use
attr("tags", "[\[ ]value[,\]]", deps(//foo))
Isso funciona porque o caractere antes de value
será [
ou um espaço, e o caractere depois de value
será uma vírgula ou ]
.
Filtragem de visibilidade de regras: visível
expr ::= visible(expr, expr)
O operador visible(predicate, input)
aplica um filtro a um conjunto de destinos e descarta os destinos sem a visibilidade necessária.
O primeiro argumento, predicate, é um conjunto de destinos para o qual todos os destinos na saída precisam estar visíveis. Uma expressão visible é avaliada como o conjunto que contém todos os destinos x, de modo que x seja um membro do conjunto input e, para todos os destinos y em predicate, x esteja visível para y. Por exemplo:
visible(//foo, //bar:*)
selecionará todos os destinos no pacote //bar
de que //foo
pode depender sem violar as restrições de visibilidade.
Avaliação de atributos de regra do tipo label: labels
expr ::= labels(word, expr)
O operador labels(attr_name, inputs)
retorna o conjunto de metas especificado no atributo attr_name do tipo "rótulo" ou "lista de rótulo" em alguma regra no conjunto inputs.
Por exemplo, labels(srcs, //foo)
retorna o conjunto de
destinos que aparecem no atributo srcs
da
regra //foo
. Se houver várias regras com atributos srcs
no conjunto inputs, a união de srcs
será retornada.
Expandir e filtrar test_suites: testes
expr ::= tests(expr)
O operador tests(x)
retorna o conjunto de todas as regras de teste
no conjunto x, expandindo as regras test_suite
para
o conjunto de testes individuais aos quais elas se referem e aplicando a filtragem por
tag
e size
.
Por padrão, a avaliação da consulta
ignora todos os destinos que não são de teste em todas as regras test_suite
. Isso pode ser
alterado para erros com a opção --strict_test_suite
.
Por exemplo, a consulta kind(test, foo:*)
lista todas as regras *_test
e test_suite
no pacote foo
. Todos os resultados são (por definição) membros do pacote foo
. Por outro lado, a consulta tests(foo:*)
retornará todos os testes individuais que serão executados por bazel test
foo:*
. Isso pode incluir testes pertencentes a outros pacotes, que são referenciados direta ou indiretamente por meio de regras test_suite
.
Arquivos de definição de pacote: buildfiles
expr ::= buildfiles(expr)
O operador buildfiles(x)
retorna o conjunto
de arquivos que define os pacotes de cada destino no
conjunto x. Em outras palavras, para cada pacote, o arquivo BUILD
,
além de arquivos .bzl que ele referencia via load
. Observe que isso
também retorna os arquivos BUILD
dos pacotes que contêm esses
arquivos load
.
Esse operador normalmente é usado para determinar quais arquivos ou
pacotes são necessários para criar um destino especificado, geralmente em conjunto com
a opção --output package
abaixo. Por exemplo:
bazel query 'buildfiles(deps(//foo))' --output package
retorna o conjunto de todos os pacotes dos quais //foo
depende transitivamente.
Arquivos de definição de pacote: rbuildfiles
expr ::= rbuildfiles(word, ...)
O operador rbuildfiles
usa uma lista separada por vírgulas de fragmentos de caminho e retorna
o conjunto de arquivos BUILD
que dependem temporariamente desses fragmentos de caminho. Por exemplo, se //foo
for um pacote, rbuildfiles(foo/BUILD)
retornará o destino //foo:BUILD
. Se o arquivo foo/BUILD
tiver
load('//bar:file.bzl'...
, rbuildfiles(bar/file.bzl)
retornará
o destino //foo:BUILD
, bem como os destinos de qualquer outro arquivo BUILD
que
carregue //bar:file.bzl
O escopo do operador --universe_scope
. Os arquivos que não correspondem diretamente a arquivos BUILD
e .bzl
não afetam os resultados. Por exemplo, os arquivos de origem (como foo.cc
) são ignorados,
mesmo que sejam explicitamente mencionados no arquivo BUILD
. No entanto, links simbólicos são respeitados. Portanto, se foo/BUILD
for um link simbólico para bar/BUILD
, rbuildfiles(bar/BUILD)
incluirá //foo:BUILD
nos resultados.
O operador rbuildfiles
é quase moralmente o inverso do operador buildfiles
. No entanto, essa inversão moral tem mais força em uma direção: as saídas de rbuildfiles
são como as entradas de buildfiles
. A primeira conterá apenas destinos de arquivo BUILD
em pacotes, e a segunda poderá conter esses destinos. Na outra direção, a correspondência é mais fraca. As
saídas do operador buildfiles
são destinos correspondentes a todos os pacotes e .bzl
arquivos necessários para uma determinada entrada. No entanto, as entradas do operador rbuildfiles
não são esses destinos, mas os fragmentos de caminho que correspondem a esses destinos.
Arquivos de definição de pacote: loadfiles
expr ::= loadfiles(expr)
O operador loadfiles(x)
retorna o conjunto de
arquivos Starlark necessários para carregar os pacotes de cada destino no
conjunto x. Em outras palavras, para cada pacote, ele retorna os arquivos .bzl que são referenciados nos arquivos BUILD
.
Formatos de saída
bazel query
gera um gráfico.
Especifique o conteúdo, o formato e a ordem em que bazel query
apresenta esse gráfico por meio da opção de linha de comando --output
.
Ao executar com o Sky Query, somente formatos de saída compatíveis com resultados não ordenados são permitidos. Especificamente, os formatos de saída graph
, minrank
e maxrank
são proibidos.
Alguns dos formatos de saída aceitam opções adicionais. O nome de cada opção de saída é prefixado com o formato de saída ao qual se aplica. Portanto, --graph:factored
se aplica somente quando --output=graph
está sendo usado. Não tem efeito se um formato de saída diferente de graph
for usado. Da mesma forma, --xml:line_numbers
se aplica somente quando --output=xml
está sendo usado.
Na ordem dos resultados
Embora as expressões de consulta sempre sigam a "lei de conservação da ordem do gráfico", a apresentação dos resultados pode ser feita de maneira ordenada ou não. Isso não influencia os destinos no conjunto de resultados ou como a consulta é calculada. Ele afeta apenas a maneira como os resultados são impressos em stdout. Além disso, os nós equivalentes na ordem de dependência podem ou não estar em ordem alfabética.
A sinalização --order_output
pode ser usada para controlar esse comportamento.
A sinalização --[no]order_results
tem um subconjunto da funcionalidade da sinalização --order_output
e está obsoleta.
O valor padrão dessa sinalização é auto
, que mostra os resultados em ordem
lexicográfica. No entanto, quando somepath(a,b)
for usado, os resultados serão impressos em
ordem deps
.
Quando essa sinalização for no
e --output
for build
, label
, label_kind
, location
, package
, proto
ou xml
, as saídas serão impressas em ordem arbitrária. Essa costuma ser a opção mais rápida. No entanto, não há suporte para quando --output
é graph
, minrank
ou maxrank
: com esses formatos, o Bazel sempre imprime resultados ordenados pela ordem ou classificação da dependência.
Quando essa sinalização é deps
, o Bazel exibe os resultados em uma ordem topológica, ou seja, dependências. No entanto, os nós não ordenados pela ordem de dependência (porque não há caminho de um para o outro) podem ser impressos em qualquer ordem.
Quando essa sinalização é full
, o Bazel imprime nós em uma ordem totalmente determinística (total).
Primeiro, todos os nós são classificados em ordem alfabética. Em seguida, cada nó da lista é usado como o início de uma
pesquisa de profundidade pós-ordem, em que as bordas enviadas para os nós não visitados são transferidas em
ordem alfabética dos sucessores. Por fim, os nodes são impressos no sentido inverso da ordem em que foram visitados.
A impressão de nós nessa ordem pode ser mais lenta. Portanto, use-a somente quando o determinismo for importante.
Imprime o formulário de origem dos destinos conforme eles aparecem no BUILD
--output build
Com essa opção, a representação de cada destino é como se fosse escrita à mão na linguagem BUILD. Todas as variáveis e chamadas de função (como glob, macros) são expandidas, o que é útil para ver o efeito das macros do Starlark. Além disso, cada regra efetiva informa um valor generator_name
e/ou generator_function
, fornecendo o nome da macro que foi avaliada para produzir a regra efetiva.
Embora a saída use a mesma sintaxe dos arquivos BUILD
, não é garantido que ela produzirá um arquivo BUILD
válido.
Imprimir o marcador de cada destino
--output label
Com essa opção, o conjunto de nomes (ou rótulos) de cada destino no gráfico resultante é impresso, um rótulo por linha, em ordem topológica (a menos que --noorder_results
seja especificado, consulte as observações sobre a ordem dos resultados).
Uma ordem topológica é aquela em que um nó do gráfico aparece antes de todos os sucessores. É claro que há muitas ordens topológicas possíveis de um gráfico. A pós-ordem inversa é apenas uma, e a escolhida não é especificada.
Ao imprimir a saída de uma consulta somepath
, a ordem em que os nós são impressos é a ordem do caminho.
Advertência: em alguns casos específicos, pode haver dois destinos distintos com o mesmo rótulo. Por exemplo, uma regra sh_binary
e seu único arquivo srcs
(implícito) podem ser chamados de foo.sh
. Se o resultado de uma consulta contiver esses dois destinos, a saída (no formato label
) parecerá conter uma cópia. Ao usar o formato label_kind
(veja abaixo), a distinção fica clara: os dois destinos têm o mesmo nome, mas um deles tem o tipo sh_binary rule
e o outro tipo source file
.
Imprimir o rótulo e o tipo de cada destino
--output label_kind
Como label
, esse formato de saída imprime os rótulos de
cada destino no gráfico resultante, em ordem topológica, mas também
antecede o rótulo pelo tipo do destino.
Imprimir o marcador de cada segmento, em ordem de classificação
--output minrank --output maxrank
Assim como label
, os formatos de saída minrank
e maxrank
imprimem os rótulos de cada destino no gráfico resultante, mas em vez de aparecer em ordem topológica, eles aparecem na ordem de classificação, precedidos pelo número da classificação. Elas não são afetadas pela sinalização --[no]order_results
de ordenação de resultados (consulte as observações sobre a ordem dos resultados).
Há duas variantes desse formato: minrank
classifica
cada nó pelo comprimento do caminho mais curto de um nó raiz para ele.
Os nós "raiz" (aqueles que não têm bordas recebidas) são de classificação 0, seus sucessores são de classificação 1 etc. (como sempre, as bordas apontam de um destino para seus pré-requisitos: os destinos de que depende).
maxrank
classifica cada nó pelo tamanho do caminho mais longo de um nó raiz para ele. Novamente, "raízes" têm classificação 0, todos os outros nós têm uma classificação maior que a classificação máxima de todos os antecessores.
Todos os nós em um ciclo são considerados da mesma classificação. A maioria dos gráficos é acíclica, mas os ciclos ocorrem simplesmente porque os arquivos BUILD
contêm ciclos com erro.
Esses formatos de saída são úteis para descobrir a profundidade de um gráfico. Se usado para o resultado de uma consulta deps(x)
, rdeps(x)
ou allpaths
, o número de classificação é igual ao comprimento do caminho mais curto (com minrank
) ou mais longo (com maxrank
) de x
para um nó nessa classificação. maxrank
pode ser usado para determinar a
sequência mais longa de etapas de versão necessárias para criar um destino.
Por exemplo, o gráfico à esquerda produz as saídas à direita quando --output minrank
e --output maxrank
são especificados, 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 |
Imprimir o local de cada destino
--output location
Como label_kind
, essa opção imprime para cada destino no resultado, o tipo e o rótulo do destino, mas é prefixado por uma string que descreve a localização do destino, como um nome de arquivo e um número de linha. O formato é semelhante à saída de grep
. Assim, as ferramentas que podem analisar o segundo (como Emacs ou vi) também podem usar a saída da consulta para percorrer uma série de correspondências, permitindo que a ferramenta de consulta do Bazel seja usada como um "grep" para arquivos BUILD com reconhecimento de gráfico de dependência.
As informações de local variam de acordo com o tipo de segmentação (consulte o operador kind). Para regras, o local da declaração da regra dentro do arquivo BUILD
é impresso.
Para arquivos de origem, o local da linha 1 do arquivo real é impresso. Para um arquivo gerado, o local da regra que o gera é impresso. A ferramenta de consulta não tem informações suficientes para encontrar o local real do arquivo gerado e, em qualquer caso, ela pode não existir se uma versão ainda não tiver sido executada.
Imprimir o conjunto de pacotes
--output package
Essa opção imprime o nome de todos os pacotes a que algum destino no conjunto de resultados pertence. Os nomes são impressos em ordem lexicográfica, excluindo os duplicados. Formalmente, isso é uma projeção a partir do conjunto de rótulos (pacote, destino) para os pacotes.
Os pacotes em repositórios externos são formatados como @repo//foo/bar
, enquanto os pacotes no repositório principal são formatados como foo/bar
.
Em conjunto com a consulta deps(...)
, essa opção de saída pode ser usada para encontrar o conjunto de pacotes que precisam ser verificados para criar um determinado conjunto de destinos.
Exibir um gráfico do resultado
--output graph
Essa opção faz com que o resultado da consulta seja impresso como um gráfico direcionado no formato popular AT&T GraphViz. Normalmente, o resultado é salvo em um arquivo, como .png
ou .svg
.
Se o programa dot
não estiver instalado na estação de trabalho, instale-o usando o comando sudo apt-get install graphviz
. Consulte a seção de exemplo abaixo para ver uma amostra de invocação.
Esse formato de saída é particularmente útil para consultas allpaths
, deps
ou rdeps
, em que o resultado inclui um conjunto de caminhos que não podem ser facilmente visualizados quando renderizados em um formato linear, como com --output label
.
Por padrão, o gráfico é renderizado em uma forma considerada. Ou seja, nós topologicamente equivalentes são mesclados em um único nó com vários rótulos. Isso torna o gráfico mais compacto e legível, porque os gráficos de resultados típicos contêm padrões altamente repetitivos. Por exemplo, uma regra java_library
pode depender de centenas de arquivos de origem Java, todos gerados pelo mesmo genrule
. No gráfico fatorado, todos esses arquivos são representados por um único nó. Esse comportamento pode ser desativado
com a opção --nograph:factored
.
--graph:node_limit n
A opção especifica o comprimento máximo da string de rótulo para um nó de gráfico na saída. Rótulos mais longos serão truncados. -1 desativa o truncamento. Devido à forma fatorada na qual os gráficos geralmente são impressos, os rótulos dos nós podem ser muito longos. O GraphViz não pode processar rótulos com mais de 1.024 caracteres, que é o valor padrão dessa opção. Essa opção não tem efeito a menos que
--output=graph
esteja sendo usado.
--[no]graph:factored
Por padrão, os gráficos são exibidos em forma fatorada, conforme explicado acima.
Quando --nograph:factored
é especificado, os gráficos são impressos sem fatoração. Isso torna a visualização usando o GraphViz impraticável, mas o formato mais simples pode facilitar o processamento por outras ferramentas (como o grep). Essa opção não tem efeito,
a menos que --output=graph
esteja sendo usado.
XML
--output xml
Essa opção faz com que os destinos resultantes sejam impressos em um formato XML. A saída começa com um cabeçalho XML como este
<?xml version="1.0" encoding="UTF-8"?>
<query version="2">
e continua com um elemento XML para cada destino no gráfico de resultados, em ordem topológica (a menos que resultados não ordenados sejam solicitados), e termina com um caractere
</query>
Entradas simples são emitidas para destinos do tipo file
:
<source-file name='//foo:foo_main.cc' .../>
<generated-file name='//foo:libfoo.so' .../>
Porém, para regras, o XML é estruturado e contém definições de todos
os atributos da regra, incluindo aqueles cujo valor não foi especificado
explicitamente no arquivo BUILD
da regra.
Além disso, o resultado inclui elementos rule-input
e
rule-output
para que a topologia do
gráfico de dependência possa ser reconstruída sem que você saiba que, por exemplo, os elementos do atributo srcs
são
dependências futuras (pré-requisitos) e o conteúdo do
atributo outs
são dependências retroativas (consumidores).
Os elementos rule-input
de dependências implícitas serão suprimidos se --noimplicit_deps
for especificado.
<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 um destino contém um atributo name
,
cujo valor é o rótulo do destino, e
um atributo location
, cujo valor é o local do destino,
conforme impresso pelo --output location
.
--[no]xml:line_numbers
Por padrão, os locais exibidos na saída XML contêm números de linha.
Quando --noxml:line_numbers
é especificado, os números de linha não são impressos.
--[no]xml:default_values
Por padrão, a saída XML não inclui o atributo de regra cujo valor é o valor padrão para esse tipo de atributo (por exemplo, se ele não foi especificado no arquivo BUILD
ou se o valor padrão foi fornecido explicitamente). Essa opção faz com que esses valores de atributo sejam
incluídos na saída XML.
Expressões regulares
As expressões regulares na linguagem de consulta usam a biblioteca regex de Java. Portanto, é possível usar a sintaxe completa para java.util.regex.Pattern
.
Como fazer consultas com repositórios externos
Se a versão depender de regras de repositórios externos (definidas no arquivo WORKSPACE), os resultados da consulta incluirão essas dependências. Por
exemplo, se //foo:bar
depender de //external:some-lib
e //external:some-lib
estiver vinculado a @other-repo//baz:lib
, bazel query 'deps(//foo:bar)'
listará @other-repo//baz:lib
e
//external:some-lib
como dependências.
Os próprios repositórios externos não são dependências de uma versão. Ou seja, no exemplo acima, //external:other-repo
não é uma dependência. No entanto, ele pode ser consultado como um membro do pacote //external
. Por exemplo:
# 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