Ejemplos de protocolo de eventos de compilación

Informar un problema Ver fuente Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

La especificación completa del Build Event Protocol se puede encontrar en su definición de búfer de protocolo. Sin embargo, puede ser útil desarrollar cierta intuición antes de consultar la especificación.

Considera un espacio de trabajo de Bazel simple 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 ejecutes 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 elemento superior y secundario mencionada anteriormente. Ten en cuenta que, por brevedad, se omitieron algunos eventos de compilación y la mayoría de los campos.

bep-graph

Figura 1: Gráfico de BEP

Inicialmente, se publica un evento BuildStarted. El evento nos informa que se invocó la compilación a través del comando bazel test y anuncia 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 información sobre los destinos específicos a los que se expandió el patrón ...: //foo:foo_lib y //foo:foo_test. Para ello, declara dos eventos TargetConfigured como secundarios. Ten en cuenta que el evento TargetConfigured declara el evento Configuration como un evento secundario, aunque Configuration se haya publicado antes del evento TargetConfigured.

Además de la relación entre elementos superiores y secundarios, los eventos también pueden hacer referencia entre sí con 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 archivos no incorporan los nombres ni las rutas de acceso de los archivos en el evento. En cambio, contienen el identificador del evento de compilación de un evento NamedSetOfFiles, que luego contendrá los nombres y las rutas de acceso reales de los archivos. El evento NamedSetOfFiles permite que se informe un conjunto de archivos una sola vez y que se haga referencia a él en muchos destinos. Esta estructura es necesaria porque, de lo contrario, en algunos casos, el tamaño de salida del Build Event Protocol crecería de forma cuadrática con la cantidad de archivos. Es posible que un evento NamedSetOfFiles tampoco tenga todos sus archivos incorporados, sino que haga referencia a otros eventos 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, impresa 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 con 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 destino compilado.

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

Resultados de la relación de aspecto en la BEP

Las compilaciones normales evalúan las acciones asociadas con pares (target, configuration). Cuando compilas con aspectos habilitados, Bazel también evalúa los destinos asociados con las tuplas (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 los aspectos. Para cada par (target, configuration) con un aspecto aplicable, Bazel publica un evento TargetConfigured y TargetComplete adicionales que contienen 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 el 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 que produce un destino (o aspecto) determinado es un caso de uso común de BEP que se puede realizar de manera eficiente con cierta preparación. En esta sección, se analiza la estructura recursiva y compartida que ofrece el evento NamedSetOfFiles, que coincide con la estructura de un Depset de Starlark.

Los consumidores deben tener cuidado 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.

namedsetoffiles-bep-graph

Figura 2: Gráfico del BEP de NamedSetOfFiles.

Un evento NamedSetOfFiles siempre aparece en el flujo de BEP antes de un evento TargetComplete o NamedSetOfFiles que lo referencia. Esta es la relación inversa del evento "principal-secundario", en la que todos los eventos, excepto el primero, aparecen después de al menos un evento que los anuncia. Un evento NamedSetOfFiles se anuncia con un evento Progress sin semántica.

Dadas estas restricciones de orden y uso compartido, un consumidor típico debe almacenar en búfer todos los eventos de NamedSetOfFiles hasta que se agote la transmisión de BEP. En el siguiente flujo de eventos JSON y código de Python, se muestra cómo completar un mapa desde el destino o el aspecto hasta los artefactos compilados en el grupo de salida "predeterminado", y cómo procesar las salidas para un subconjunto de destinos 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)