Exemplos de protocolo de evento de build

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

A especificação completa do Build Event Protocol pode ser encontrada no respectivo protocolo a definição do buffer. No entanto, pode ser útil criar uma intuição antes de olhar a especificação.

Considere um espaço de trabalho simples do Bazel composto por dois scripts de shell vazios foo.sh e foo_test.sh e o seguinte arquivo BUILD:

sh_library(
    name = "foo_lib",
    srcs = ["foo.sh"],
)

sh_test(
    name = "foo_test",
    srcs = ["foo_test.sh"],
    deps = [":foo_lib"],
)

Ao executar bazel test ... nesse projeto, o gráfico de build do eventos de build serão parecidos com o gráfico abaixo. As setas indicam o que já mencionamos. Alguns eventos de build e a maioria dos campos foram omitidos para concisão.

gráfico bep

Figura 1. Gráfico BEP.

Inicialmente, um evento BuildStarted é publicado. O evento informa que a build foi invocado pelo comando bazel test e anuncia eventos filhos:

  • OptionsParsed
  • WorkspaceStatus
  • CommandLine
  • UnstructuredCommandLine
  • BuildMetadata
  • BuildFinished
  • PatternExpanded
  • Progress

Os três primeiros eventos fornecem informações sobre como o Bazel foi invocado.

O evento de build PatternExpanded fornece insights em quais destinos específicos o padrão ... se expandiu: //foo:foo_lib e //foo:foo_test. Ele faz isso declarando dois TargetConfigured como filhos. O evento TargetConfigured declara o evento Configuration como um evento filho, mesmo que Configuration foi postado antes do evento TargetConfigured.

Além da relação pai e filho, os eventos também podem se referir entre si usando identificadores de eventos de build. Por exemplo, no gráfico acima, O evento TargetComplete refere-se ao evento NamedSetOfFiles na fileSets .

Eventos de build que se referem a arquivos geralmente não o incorporam nomes e caminhos no evento. Em vez disso, elas contêm o identificador de evento de build de um evento NamedSetOfFiles, que conterá os nomes reais dos arquivos e caminhos de rede. O evento NamedSetOfFiles permite que um conjunto de arquivos seja informado uma vez e referida por muitos alvos. Essa estrutura é necessária porque, caso contrário, em alguns casos, o tamanho da saída do Protocolo de evento de criação aumentaria o número de arquivos. Também é possível que um evento NamedSetOfFiles não tenha todos os arquivos incorporados, mas se referem a outros eventos NamedSetOfFiles por meio do identificadores de evento de build.

Veja abaixo uma instância do evento TargetComplete para o //foo:foo_lib do gráfico acima, impresso na representação JSON do buffer de protocolo. O identificador de eventos de build contém o destino como uma string opaca e se refere ao o evento Configuration usando o identificador de evento de build. O evento não anunciar eventos filhos. O payload contém informações sobre se o o destino foi criado, o conjunto de arquivos de saída e o tipo de construído.

{
  "id": {
    "targetCompleted": {
      "label": "//foo:foo_lib",
      "configuration": {
        "id": "544e39a7f0abdb3efdd29d675a48bc6a"
      }
    }
  },
  "completed": {
    "success": true,
    "outputGroup": [{
      "name": "default",
      "fileSets": [{
        "id": "0"
      }]
    }],
    "targetKind": "sh_library rule"
  }
}

Resultados do Aspect em BEP

Os builds comuns avaliam ações associadas ao (target, configuration) pares. Quando você cria com aspects ativados, o Bazel além de avaliar os destinos associados a três valores de (target, configuration, aspect) para cada destino afetado por um determinado aspecto ativado.

Os resultados da avaliação dos aspectos estão disponíveis no BEP, apesar da ausência de tipos de eventos de aspectos específicos. Para cada par de (target, configuration) com um aplicável, o Bazel publica um TargetConfigured e evento TargetComplete que mostra o resultado da aplicação do aspecto ao alvo. Por exemplo, se //:foo_lib for criado com --aspects=aspects/myaspect.bzl%custom_aspect, este evento também apareceria em o BEP:

{
  "id": {
    "targetCompleted": {
      "label": "//foo:foo_lib",
      "configuration": {
        "id": "544e39a7f0abdb3efdd29d675a48bc6a"
      },
      "aspect": "aspects/myaspect.bzl%custom_aspect"
    }
  },
  "completed": {
    "success": true,
    "outputGroup": [{
      "name": "default",
      "fileSets": [{
        "id": "1"
      }]
    }]
  }
}

Consumindo NamedSetOfFiles

Determinar os artefatos produzidos por um determinado alvo (ou aspecto) é um processo comum Caso de uso do BEP que pode ser feito de forma eficiente com alguma preparação. Esta seção aborda a estrutura compartilhada recursiva oferecida pelo NamedSetOfFiles que corresponde à estrutura de um Depset do Starlark.

Os consumidores precisam ter cuidado para evitar algoritmos quadráticos durante o processamento Eventos NamedSetOfFiles, porque builds grandes podem conter dezenas de milhares de exigindo centenas de milhões de operações em uma travessia com complexidade quadrática.

namedsetoffiles-bep-graph

Figura 2. Gráfico de BEP NamedSetOfFiles.

Um evento NamedSetOfFiles sempre aparece no fluxo BEP antes de um TargetComplete ou NamedSetOfFiles que faz referência a ele. Esta é a inverso de "pai-filho" relação do evento, em que todos, exceto o primeiro, aparece depois de ser anunciado por pelo menos um evento. Um evento NamedSetOfFiles é anunciado por um evento Progress sem semântica.

Com essas restrições de pedidos e compartilhamento, um consumidor típico precisa armazenar NamedSetOfFiles eventos até o fluxo do BEP terminar. O JSON a seguir O fluxo de eventos e o código Python demonstram como preencher um mapa destino/aspecto a artefatos criados na classe "default" grupo de saída e como Processe as saídas para um subconjunto de destinos/aspectos criados:

named_sets = {}  # type: dict[str, NamedSetOfFiles]
outputs = {}     # type: dict[str, dict[str, set[str]]]

for event in stream:
  kind = event.id.WhichOneof("id")
  if kind == "named_set":
    named_sets[event.id.named_set.id] = event.named_set_of_files
  elif kind == "target_completed":
    tc = event.id.target_completed
    target_id = (tc.label, tc.configuration.id, tc.aspect)
    outputs[target_id] = {}
    for group in event.completed.output_group:
      outputs[target_id][group.name] = {fs.id for fs in group.file_sets}

for result_id in relevant_subset(outputs.keys()):
  visit = outputs[result_id].get("default", [])
  seen_sets = set(visit)
  while visit:
    set_name = visit.pop()
    s = named_sets[set_name]
    for f in s.files:
      process_file(result_id, f)
    for fs in s.file_sets:
      if fs.id not in seen_sets:
        visit.add(fs.id)
        seen_sets.add(fs.id)