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.
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. Talvez 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 evento de aspecto específico. 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.
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 de 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
Processar 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)