La especificación completa del protocolo de eventos de compilación se puede encontrar en la definición del búfer de protocolo. Sin embargo, podría ser útil crear algo de intuición antes de mirar la especificación.
Considera un lugar de trabajo simple de Bazel que consta de dos secuencias de comandos de shell vacías foo.sh
y foo_test.sh
, y el siguiente archivo BUILD
:
sh_library(
name = "foo_lib",
srcs = ["foo.sh"],
)
sh_test(
name = "foo_test",
srcs = ["foo_test.sh"],
deps = [":foo_lib"],
)
Cuando ejecutas bazel test ...
en este proyecto, el gráfico de compilación de los eventos de compilación generados se parecerá al siguiente. Las flechas indican la relación de superior y secundario antes mencionada. Ten en cuenta que algunos eventos de compilación y la mayoría de los campos se omitieron para abreviar.
Figura 1: Gráfico de BEP.
Inicialmente, se publica un evento BuildStarted
. El evento nos informa que la
compilación se invocó a través del comando bazel test
y anuncia los eventos secundarios:
OptionsParsed
WorkspaceStatus
CommandLine
UnstructuredCommandLine
BuildMetadata
BuildFinished
PatternExpanded
Progress
Los primeros tres eventos proporcionan información sobre cómo se invocó Bazel.
El evento de compilación PatternExpanded
proporciona estadísticas
sobre qué objetivos específicos se expandió el patrón ...
a
//foo:foo_lib
y //foo:foo_test
. Para ello, declara dos eventos TargetConfigured
como elementos secundarios. Ten en cuenta que el evento TargetConfigured
declara el evento Configuration
como un evento secundario, a pesar de que Configuration
se publicó antes que el evento TargetConfigured
.
Además de la relación de superior y secundario, los eventos también pueden referirse entre sí
mediante sus identificadores de eventos de compilación. Por ejemplo, en el gráfico anterior, el evento TargetComplete
hace referencia al evento NamedSetOfFiles
en su campo fileSets
.
Por lo general, los eventos de compilación que hacen referencia a los archivos no incorporan los nombres de los archivos ni las rutas de acceso en el evento. En cambio, contienen el identificador de evento de compilación de un evento NamedSetOfFiles
, que contendrá los nombres de archivo y las rutas de acceso reales. El evento NamedSetOfFiles
permite que se informe un conjunto de archivos una vez y que
muchos objetivos lo hagan referencia a ellos. Esta estructura es necesaria porque, de lo contrario, en algunos casos, el tamaño de los resultados del Protocolo de eventos de compilación aumentaría de forma cuadrática con la cantidad de archivos. También es posible que un evento NamedSetOfFiles
no tenga todos sus archivos incorporados. En su lugar, haga referencia a otros eventos de NamedSetOfFiles
a través de sus identificadores de eventos de compilación.
A continuación, se muestra una instancia del evento TargetComplete
para el destino //foo:foo_lib
del gráfico anterior, impreso en la representación JSON del búfer de protocolo.
El identificador de evento de compilación contiene el destino como una cadena opaca y hace referencia al evento Configuration
mediante su identificador de evento de compilación. El evento no anuncia ningún evento secundario. La carga útil contiene información sobre si el destino se compiló correctamente, el conjunto de archivos de salida y el tipo de compilación de destino.
{
"id": {
"targetCompleted": {
"label": "//foo:foo_lib",
"configuration": {
"id": "544e39a7f0abdb3efdd29d675a48bc6a"
}
}
},
"completed": {
"success": true,
"outputGroup": [{
"name": "default",
"fileSets": [{
"id": "0"
}]
}],
"targetKind": "sh_library rule"
}
}
Resultados de aspecto en BEP
Las compilaciones comunes evalúan las acciones asociadas con pares (target, configuration)
. Cuando compilas con los aspectos habilitados, Bazel
también evalúa los objetivos asociados con triples de (target, configuration,
aspect)
para cada destino afectado por un aspecto habilitado determinado.
Los resultados de la evaluación de los aspectos están disponibles en BEP a pesar de la ausencia de tipos de eventos específicos de un aspecto. Para cada par (target, configuration)
con un
aspecto aplicable, Bazel publica un evento TargetConfigured
y
TargetComplete
adicional que contiene el resultado de aplicar el aspecto al
destino. Por ejemplo, si //:foo_lib
se compila con --aspects=aspects/myaspect.bzl%custom_aspect
, este evento también aparecerá en la 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"
}]
}]
}
}
Consumo de NamedSetOfFiles
Determinar los artefactos producidos por un objetivo (o aspecto) determinado es un caso de uso común de BeP que se puede realizar de manera eficiente con un poco de preparación. En esta sección, se analiza la estructura compartida y recursiva que ofrece el evento NamedSetOfFiles
, que coincide con la estructura de un Depset de Starlark.
Los consumidores deben asegurarse de evitar los algoritmos cuadráticos cuando procesan eventos NamedSetOfFiles
, ya que las compilaciones grandes pueden contener decenas de miles de estos eventos, lo que requiere cientos de millones de operaciones en un recorrido con complejidad cuadrática.
Figura 2: Gráfico de BEP de NamedSetOfFiles
.
Un evento NamedSetOfFiles
siempre aparece en la transmisión de BEP antes de un evento TargetComplete
o NamedSetOfFiles
que haga referencia a él. Esto es lo contrario a la relación de evento "principal-secundario", en la que todos los eventos aparecen después de al menos un evento que lo anuncia, excepto el primero. Un evento Progress
anuncia un evento NamedSetOfFiles
sin semántica.
Debido a estas restricciones de orden y uso compartido, un consumidor típico debe almacenar en búfer todos los eventos NamedSetOfFiles
hasta que se agote la transmisión de BEP. La siguiente transmisión de eventos JSON y el código de Python demuestran cómo propagar un mapa de destino o aspecto a artefactos compilados en el grupo de salida "predeterminado" y cómo procesar los resultados para un subconjunto de objetivos o aspectos compilados:
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)