Ejemplos de protocolos de eventos de compilación

Informa un problema Ver código fuente

La especificación completa del protocolo de evento de compilación se encuentra en la definición del búfer de protocolo. Sin embargo, puede ser útil desarrollar una intuición antes de ver 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 ejecutes bazel test ... en este proyecto, el grafo de compilación de los eventos de compilación generados se parecerá al siguiente gráfico. Las flechas indican la relación superior y secundaria ya mencionada. Ten en cuenta que se omitieron algunos eventos de compilación y la mayoría de los campos para abreviar.

gráfico bip

Figura 1: Gráfico de BEP.

Inicialmente, se publica un evento BuildStarted. El evento nos informa que la compilación se invocó mediante el 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 estadísticas sobre en qué objetivos específicos se expandió el patrón ... a //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 secundario, a pesar de que Configuration se haya publicado antes del evento TargetConfigured.

Además de la relación principal y secundaria, los eventos también pueden referirse unos a otros 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 archivos no incorporan los nombres de archivo ni las rutas de acceso en el evento. En su lugar, contienen el identificador de evento de compilación de un evento NamedSetOfFiles, que, a su vez, contendrá los nombres de archivo y las rutas de acceso reales. El evento NamedSetOfFiles permite que un conjunto de archivos se denuncia una vez y muchos hacen referencia a él. Esta estructura es necesaria porque, de lo contrario, en algunos casos, el tamaño de salida del protocolo de evento de compilación crecería de manera 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 objetivo //foo:foo_lib del gráfico anterior, que se imprime en la representación JSON del búfer de protocolo. El identificador del evento de compilación contiene el destino como una string 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 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 aspectos en BEP

Las compilaciones comunes evalúan las acciones asociadas con los pares (target, configuration). Cuando compilas con aspectos habilitados, Bazel también evalúa los destinos asociados con los triples de (target, configuration, aspect), para cada destino afectado por un aspecto habilitado determinado.

Los resultados de la evaluación de aspectos están disponibles en BEP, a pesar de la ausencia de tipos de eventos específicos de un aspecto. Por cada par (target, configuration) con un aspecto aplicable, Bazel publica un evento TargetConfigured y TargetComplete adicional que lleva el resultado de la aplicación del aspecto al destino. Por ejemplo, si //:foo_lib se compila con --aspects=aspects/myaspect.bzl%custom_aspect, este evento también aparece 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"
      }]
    }]
  }
}

Consume NamedSetOfFiles

Determinar los artefactos producidos por un objetivo (o aspecto) determinado es un caso de uso de BeP común que se puede hacer de manera eficiente con algo de preparación. En esta sección, se analiza la estructura recurrente y compartida que ofrece el evento NamedSetOfFiles, que coincide con la estructura de Depset de Starlark.

Los consumidores deben tener cuidado para evitar los algoritmos cuadráticos al procesar eventos NamedSetOfFiles, ya que las compilaciones grandes pueden contener decenas de miles de estos eventos y requerir cientos de millones de operaciones en un recorrido con complejidad cuadrática.

namesetoffiles-bep-graph

Figura 2: Gráfico de BEP de NamedSetOfFiles.

Un evento NamedSetOfFiles siempre aparece en la transmisión BEP antes de un evento TargetComplete o NamedSetOfFiles que hace referencia a él. Esta es la inversa de la relación de evento "superior-secundario", en la que todas, excepto la primera, aparecen después de que al menos un evento lo anuncia. Un evento NamedSetOfFiles es anunciado por 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 NamedSetOfFiles hasta que se agote la transmisión de BEP. El siguiente flujo 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 de 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)