Consulta configurável (cquery)

Informar um problema Mostrar fonte Por noite · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

cquery é uma variante do query que processa corretamente select() e opções de build efeitos no build gráfico.

Para isso, ele executa os resultados da análise do Bazel fase de transformação, que integra esses efeitos. query, por outro lado, executa os resultados de Fase de carregamento do Bazel antes da avaliação das opções.

Exemplo:

$ cat > tree/BUILD <<EOF
sh_library(
    name = "ash",
    deps = select({
        ":excelsior": [":manna-ash"],
        ":americana": [":white-ash"],
        "//conditions:default": [":common-ash"],
    }),
)
sh_library(name = "manna-ash")
sh_library(name = "white-ash")
sh_library(name = "common-ash")
config_setting(
    name = "excelsior",
    values = {"define": "species=excelsior"},
)
config_setting(
    name = "americana",
    values = {"define": "species=americana"},
)
EOF
# Traditional query: query doesn't know which select() branch you will choose,
# so it conservatively lists all of possible choices, including all used config_settings.
$ bazel query "deps(//tree:ash)" --noimplicit_deps
//tree:americana
//tree:ash
//tree:common-ash
//tree:excelsior
//tree:manna-ash
//tree:white-ash

# cquery: cquery lets you set build options at the command line and chooses
# the exact dependencies that implies (and also the config_setting targets).
$ bazel cquery "deps(//tree:ash)" --define species=excelsior --noimplicit_deps
//tree:ash (9f87702)
//tree:manna-ash (9f87702)
//tree:americana (9f87702)
//tree:excelsior (9f87702)

Cada resultado inclui um identificador exclusivo (9f87702) de a configuração com o qual o destino foi criado.

Como cquery é executado no gráfico de destino configurado. não há insight em artefatos, como ações de versão ou acesso a test_suite porque eles não são destinos configurados. Para o primeiro, consulte aquery.

Sintaxe básica

Uma chamada cquery simples tem esta aparência:

bazel cquery "function(//target)"

A expressão de consulta "function(//target)" consiste no seguinte:

  • function(...) é a função a ser executada no destino. cquery oferece suporte à maioria das funções de query, além de uma alguns novos.
  • //target é a expressão fornecida à função. Neste exemplo, é um alvo simples. Mas a linguagem de consulta também permite o aninhamento de funções. Veja exemplos no Guia de consulta.

cquery requer um destino para executar o carregamento e a análise. fases. A menos que especificado de outra forma, cquery analisa os destinos listados no expressão de consulta. Consulte --universe_scope. para consultar dependências de destinos de build de nível superior.

Configurações

A linha:

//tree:ash (9f87702)

significa que //tree:ash foi criado em uma configuração com o ID 9f87702. Para a maioria é um hash opaco dos valores de opção de build que definem o configuração do Terraform.

Para conferir o conteúdo completo da configuração, execute:

$ bazel config 9f87702

9f87702 é um prefixo do ID completo. Isso ocorre porque os IDs completos são Hashes SHA-256, que são longos e difíceis de acompanhar. cquery entende qualquer valor prefixo de um ID completo, semelhante a Hashes curtos do Git (em inglês). Para conferir os IDs completos, execute $ bazel config.

Avaliação do padrão de destino

//foo tem um significado diferente para cquery e query. Isso ocorre porque cquery avalia destinos configurados, e o gráfico de build pode ter vários versões configuradas do //foo.

Para cquery, um padrão de destino na expressão de consulta avalia a cada destino configurado com um rótulo que corresponda a esse padrão. A saída é determinista, mas cquery não garante a realização de pedidos além do contrato principal para ordenação de consultas.

Isso produz resultados mais sutis para expressões de consulta do que com query. Por exemplo, o exemplo a seguir pode produzir vários resultados:

# Analyzes //foo in the target configuration, but also analyzes
# //genrule_with_foo_as_tool which depends on an exec-configured
# //foo. So there are two configured target instances of //foo in
# the build graph.
$ bazel cquery //foo --universe_scope=//foo,//genrule_with_foo_as_tool
//foo (9f87702)
//foo (exec)

Se você quiser declarar precisamente qual instância consultar, use a função config.

Consulte o padrão de destino de query documentação para mais informações sobre padrões de destino.

Funções

Do conjunto de funções compatível com query, cquery oferece suporte a todos allrdeps, buildfiles, rbuildfiles, siblings, tests e visible.

cquery também introduz estas novas funções:

config

expr ::= config(expr, word)

O operador config tenta encontrar o destino configurado para o rótulo indicado pelo primeiro argumento e a configuração especificada pelo segundo argumento.

Os valores válidos para o segundo argumento são null ou um hash de configuração personalizada. Os hashes podem ser recuperados de $ bazel config ou da saída de um cquery anterior.

Exemplos:

$ bazel cquery "config(//bar, 3732cc8)" --universe_scope=//foo
$ bazel cquery "deps(//foo)"
//bar (exec)
//baz (exec)

$ bazel cquery "config(//baz, 3732cc8)"

Se nem todos os resultados do primeiro argumento puderem ser encontrados no arquivo do servidor, apenas aquelas que podem ser encontradas são retornadas. Se não houver resultados não for encontrada na configuração especificada, a consulta falhará.

Opções

Opções de build

cquery é executado em uma versão regular do Bazel e, portanto, herda o conjunto de opções disponíveis durante uma compilação.

Como usar as opções do cquery

--universe_scope (lista separada por vírgulas)

Muitas vezes, as dependências dos destinos configurados passam transições, o que faz com que sua configuração seja diferente do seu dependente. Esta sinalização permite que você consulte um destino como se ele fosse criado como uma dependência ou um objeto transitivo dependência de outro destino. Exemplo:

# x/BUILD
genrule(
     name = "my_gen",
     srcs = ["x.in"],
     outs = ["x.cc"],
     cmd = "$(locations :tool) $< >$@",
     tools = [":tool"],
)
cc_binary(
    name = "tool",
    srcs = ["tool.cpp"],
)

As regras gerais configuram as ferramentas na configuração exec Portanto, as consultas a seguir produziriam as seguintes saídas:

Consulta Destino criado Saída
bazel cquery "//x:tool" //x:tool //x:tool(targetconfig)
bazel cquery "//x:tool" --universe_scope=&quot;//x:my_gen&quot; //x:my_gen //x:tool(execconfig)

Se essa flag for definida, o conteúdo dela será criado. Se não estiver definido, todos os destinos mencionados na expressão de consulta são construídos. O fechamento transitivo da os destinos criados são usados como o universo da consulta. De qualquer forma, os alvos ser construídos devem ser construídos no nível superior (isto é, compatível com sistemas de ). cquery retorna resultados no fechamento transitivo desses metas de nível superior.

Mesmo que seja possível criar todos os destinos em uma expressão de consulta na parte superior pode ser vantajoso não fazer isso. Por exemplo, definir explicitamente --universe_scope pode impedir a criação de destinos várias vezes em configurações que não são importantes para você. Também pode ajudar a especificar qual versão de configuração de um desejado que você está procurando (já que isso não é possível no momento para especificar isso de outra maneira). Defina essa flag se a expressão de consulta for mais complexa que deps(//foo).

--implicit_deps (booleano, padrão=verdadeiro)

Definir esta sinalização como falsa filtra todos os resultados que não foram definidos explicitamente no do arquivo BUILD e, em vez disso, é definido pelo Bazel em outro lugar. Isso inclui filtros resolvidos de última geração.

--tool_deps (booleano, padrão=verdadeiro)

Definir esse flag como "false" filtra todos os destinos configurados para os quais caminho do destino consultado até eles cruzam uma transição entre o destino e a configuração configurações que não sejam de destino. Se o destino consultado estiver na configuração de destino, a definição de --notool_deps retorna apenas destinos que também estão na configuração de destino. Se o cliente o destino está em uma configuração que não é de destino. Definir --notool_deps retornará apenas também em configurações que não são de segmentação. Essa configuração geralmente não afeta a filtragem de conjuntos de ferramentas resolvidos.

--include_aspects (booleano, padrão=verdadeiro)

Inclui as dependências adicionadas por aspects.

Se essa sinalização estiver desativada, cquery somepath(X, Y) e cquery deps(X) | grep 'Y' omite Y se X só depender dele por um aspecto.

Formatos de saída

Por padrão, a saída do cquery resulta em uma lista ordenada por dependência de pares de rótulo e configuração. Há também outras opções para expor os resultados.

Transições

--transitions=lite
--transitions=full

Transições de configuração são usados para criar destinos abaixo dos destinos de nível superior em diferentes do que os destinos de nível superior.

Por exemplo, um alvo pode impor uma transição à configuração "exec" em todos dependências no atributo tools. Elas são conhecidas como atributos transições. As regras também podem impor transições nas próprias configurações, conhecidas como transições de classe de regra. Esse formato de saída gera informações sobre essas transições, como o tipo e o efeito que elas têm na criação .

Esse formato de saída é acionado pela sinalização --transitions, que, por padrão, é Defina como NONE. Ele pode ser definido no modo FULL ou LITE. FULL de saídas do modo informações sobre transições de classes de regras e de atributos, incluindo uma a diferença detalhada entre as opções antes e depois da transição. Modo LITE gera as mesmas informações sem a diferença de opções.

Saída de mensagem de protocolo

--output=proto

Essa opção faz com que os alvos resultantes sejam impressos em um protocolo binário forma de buffer. A definição do buffer de protocolo pode ser encontrada em src/main/protobuf/analysis_v2.proto.

CqueryResult é a mensagem de nível superior que contém os resultados da cquery. Ela tem uma lista de ConfiguredTarget mensagens e uma lista de Configuration mensagens. Cada ConfiguredTarget tem uma configuration_id com valor igual a ao do campo id da mensagem Configuration correspondente.

--[no]proto:include_configurations

Por padrão, os resultados do cquery retornam informações de configuração como parte de cada destino configurado. Se você quiser omitir essas informações e receber a saída proto formatado exatamente como a saída proto da consulta, defina essa flag como falsa.

Consulte a documentação de saída .proto da consulta. para mais opções relacionadas a saídas de protótipos.

Saída de gráfico

--output=graph

Essa opção gera a saída como um arquivo .dot compatível com Graphviz. Consulte query documentação de saída do gráfico (em inglês) para mais detalhes. cquery também oferece suporte a --graph:node_limit e --graph:factored

Saída de arquivos

--output=files

Essa opção exibe uma lista dos arquivos de saída produzidos por cada destino correspondido pela consulta semelhante à lista exibida no final de uma bazel build invocação. A saída contém apenas os arquivos divulgados no arquivo grupos de saída, conforme determinado flag --output_groups. Ela inclui arquivos de origem.

Todos os caminhos emitidos por esse formato de saída são relativos ao execroot, que pode ser obtido via bazel info execution_root. Se o link simbólico de conveniência bazel-out existir, os caminhos para arquivos no repositório principal também resolvem em relação ao espaço de trabalho diretório.

Como definir o formato de saída usando o Starlark

--output=starlark

Esse formato de saída chama um Starlark para cada destino configurado no resultado da consulta e exibe o valor retornados pela chamada. A sinalização --starlark:file especifica o local de um Arquivo Starlark que define uma função chamada format com um único parâmetro. target Essa função é chamada para cada objeto Target no resultado da consulta. Como alternativa, por conveniência, você pode especificar apenas os corpo de uma função declarada como def format(target): return expr usando o sinalização --starlark:expr.

"cquery" Dialeto Starlark

O ambiente cquery Starlark é diferente de um arquivo BUILD ou .bzl. Inclui Starlark completo constantes e funções integradas, além de outras específicas de cquery descritas abaixo, mas não (por exemplo) glob, native ou rule, e não oferece suporte a instruções de carregamento.

build_options(target)

build_options(target) retorna um mapa com chaves que são identificadores de opção de build. Consulte Configurações) e cujos valores são os valores de Starlark. Opções de criação com valores que não são legais do Starlark valores são omitidos deste mapa.

Se o destino for um arquivo de entrada, build_options(target) retornará None, porque o arquivo de entrada têm configuração nula.

provedores(destino)

providers(target) retorna um mapa com chaves que são nomes de provedores (por exemplo, "DefaultInfo") e cujos valores são os valores de Starlark. Provedores cujos valores não são valores de Starlark legais são omitidos deste mapa.

Exemplos

Mostre uma lista separada por espaços dos nomes de base de todos os arquivos produzidos por //foo:

  bazel cquery //foo --output=starlark \
    --starlark:expr="' '.join([f.basename for f in target.files.to_list()])"

Mostre uma lista separada por espaços dos caminhos de todos os arquivos produzidos por destinos rule em //bar e os respectivos subpacotes:

  bazel cquery 'kind(rule, //bar/...)' --output=starlark \
    --starlark:expr="' '.join([f.path for f in target.files.to_list()])"

Mostra uma lista das mnemônicas de todas as ações registradas pelo //foo.

  bazel cquery //foo --output=starlark \
    --starlark:expr="[a.mnemonic for a in target.actions]"

Mostre uma lista de saídas de compilação registradas por um //baz cc_library.

  bazel cquery //baz --output=starlark \
    --starlark:expr="[f.path for f in target.output_groups.compilation_outputs.to_list()]"

Mostre o valor da opção de linha de comando --javacopt ao criar //foo.

  bazel cquery //foo --output=starlark \
    --starlark:expr="build_options(target)['//command_line_option:javacopt']"

Imprima o rótulo de cada destino com exatamente uma saída. Este exemplo usa Funções do Starlark definidas em um arquivo.

  $ cat example.cquery

  def has_one_output(target):
    return len(target.files.to_list()) == 1

  def format(target):
    if has_one_output(target):
      return target.label
    else:
      return ""

  $ bazel cquery //baz --output=starlark --starlark:file=example.cquery

Mostre o rótulo de cada destino que é estritamente Python 3. Este exemplo usa Funções do Starlark definidas em um arquivo.

  $ cat example.cquery

  def format(target):
    p = providers(target)
    py_info = p.get("PyInfo")
    if py_info and py_info.has_py3_only_sources:
      return target.label
    else:
      return ""

  $ bazel cquery //baz --output=starlark --starlark:file=example.cquery

Extraia um valor de um provedor definido pelo usuário.

  $ cat some_package/my_rule.bzl

  MyRuleInfo = provider(fields={"color": "the name of a color"})

  def _my_rule_impl(ctx):
      ...
      return [MyRuleInfo(color="red")]

  my_rule = rule(
      implementation = _my_rule_impl,
      attrs = {...},
  )

  $ cat example.cquery

  def format(target):
    p = providers(target)
    my_rule_info = p.get("//some_package:my_rule.bzl%MyRuleInfo'")
    if my_rule_info:
      return my_rule_info.color
    return ""

  $ bazel cquery //baz --output=starlark --starlark:file=example.cquery

cquery x query

cquery e query se complementam e se destacam em a diferentes nichos. Considere o seguinte e decida qual é a melhor para você:

  • cquery segue ramificações específicas do select() para e modelar o gráfico exato que você criar. query não sabe qual ramificação escolhida pelo build, então aproximadamente inclui todas as ramificações.
  • A precisão de cquery exige a criação de mais gráficos do que O query sim. Especificamente, cquery avalia alvos configurados enquanto somente query avalia destinos. Isso leva mais tempo e usa mais memória.
  • Interpretação de cquery para a linguagem de consulta apresenta ambiguidade que query evita. Por exemplo: se "//foo" existir em duas configurações, qual delas cquery "deps(//foo)" deve usar? A função config pode ajudar com isso.
  • Como uma ferramenta mais recente, o cquery não oferece suporte para determinados usos casos de uso diferentes. Consulte Problemas conhecidos para mais detalhes.

Problemas conhecidos

Todos os destinos que cquery "cria" precisam ter a mesma configuração.

Antes de avaliar as consultas, cquery aciona um build de apenas antes do ponto em que as ações de build seriam executadas. O alvo “construções” são selecionados por padrão entre todos os rótulos que aparecem na consulta expressão (que pode ser substituído com --universe_scope). Esses precisam ter a mesma configuração.

Embora geralmente compartilhem o "alvo" de nível superior configuração, regras podem alterar a própria configuração transições de borda de entrada. É aqui que o cquery fica aquém.

Alternativa: se possível, defina --universe_scope como uma opção mais rigorosa. do projeto. Exemplo:

# This command attempts to build the transitive closures of both //foo and
# //bar. //bar uses an incoming edge transition to change its --cpu flag.
$ bazel cquery 'somepath(//foo, //bar)'
ERROR: Error doing post analysis query: Top-level targets //foo and //bar
have different configurations (top-level targets with different
configurations is not supported)

# This command only builds the transitive closure of //foo, under which
# //bar should exist in the correct configuration.
$ bazel cquery 'somepath(//foo, //bar)' --universe_scope=//foo

Não há suporte para o --output=xml.

Saída não determinista.

O cquery não exclui permanentemente os dados do gráfico de build automaticamente comandos anteriores e, portanto, está propenso a coletar resultados de consultas. Por exemplo, genquery realiza uma transição "exec" em o atributo tools, ou seja, configura as ferramentas na configuração exec.

Você pode ver os efeitos duradouros dessa transição abaixo.

$ cat > foo/BUILD <<<EOF
genrule(
    name = "my_gen",
    srcs = ["x.in"],
    outs = ["x.cc"],
    cmd = "$(locations :tool) $< >$@",
    tools = [":tool"],
)
cc_library(
    name = "tool",
)
EOF

    $ bazel cquery "//foo:tool"
tool(target_config)

    $ bazel cquery "deps(//foo:my_gen)"
my_gen (target_config)
tool (exec_config)
...

    $ bazel cquery "//foo:tool"
tool(exec_config)

Alternativa: altere qualquer opção de inicialização para forçar uma nova análise dos destinos configurados. Por exemplo, adicione --test_arg=&lt;whatever&gt; ao comando de build.

Solução de problemas

Padrões de destino recursivos (/...)

Se você encontrar:

$ bazel cquery --universe_scope=//foo:app "somepath(//foo:app, //foo/...)"
ERROR: Error doing post analysis query: Evaluation failed: Unable to load package '[foo]'
because package is not in scope. Check that all target patterns in query expression are within the
--universe_scope of this query.

isso sugere incorretamente que o pacote //foo não está no escopo, mesmo que --universe_scope=//foo:app a inclui. Isso se deve a limitações de design cquery: Como solução alternativa, inclua //foo/... explicitamente no universo escopo:

$ bazel cquery --universe_scope=//foo:app,//foo/... "somepath(//foo:app, //foo/...)"

Se isso não funcionar, por exemplo, porque alguns destinos em //foo/... não podem com as flags de build escolhidas), desencapsular o padrão manualmente na pacotes constituintes com uma consulta de pré-processamento:

# Replace "//foo/..." with a subshell query call (not cquery!) outputting each package, piped into
# a sed call converting "<pkg>" to "//<pkg>:*", piped into a "+"-delimited line merge.
# Output looks like "//foo:*+//foo/bar:*+//foo/baz".
#
$  bazel cquery --universe_scope=//foo:app "somepath(//foo:app, $(bazel query //foo/...
--output=package | sed -e 's/^/\/\//' -e 's/$/:*/' | paste -sd "+" -))"