Ejemplos de protocolo de eventos de compilación

Informar un problema Ver fuente Noche /}1}

La especificación completa del protocolo de eventos de compilación se puede encontrar en su definición de búfer de protocolo. Sin embargo, podría ser útil desarrollar un poco de 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 se ejecuta bazel test ... en este proyecto, el gráfico de compilación de los eventos de compilación generados se parecerá al siguiente gráfico. Las flechas indican la relación principal y secundaria antes mencionada. Ten en cuenta que algunos eventos de compilación y la mayoría de los campos se omitieron para mayor brevedad.

gráfico-bep

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 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 a qué objetivos específicos 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 superior y secundaria, 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.

Los eventos de compilación que hacen referencia a archivos no suelen incorporar los nombres de archivos ni las rutas de acceso en el evento. En su lugar, contienen el identificador del evento de compilación de un evento NamedSetOfFiles, que luego contendrá los nombres de archivo y las rutas de acceso reales. El evento NamedSetOfFiles permite que un conjunto de archivos se informe una vez y que varios destinos hagan referencia a este. Esta estructura es necesaria porque, de lo contrario, en algunos casos, el tamaño de salida del protocolo de eventos de compilación aumentaría de forma cuadrática con la cantidad de archivos. Además, es posible que un evento NamedSetOfFiles no 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, impreso en la representación JSON del búfer de protocolo. El identificador del evento de compilación contiene el objetivo 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ó de forma correcta, el conjunto de archivos de salida y el tipo de destino que se compiló.

{
  "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 acciones asociadas con pares (target, configuration). Cuando compilas con los aspectos habilitados, Bazel evalúa de forma adicional los destinos asociados con los triples (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 aspectos. Para cada par (target, configuration) con un aspecto aplicable, Bazel publica un evento adicional TargetConfigured y TargetComplete que llevan 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

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

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

con nombresetoffiles-bep-graph

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 hace referencia a él. Esto es lo contrario a la relación de evento "principal-secundario", en la que todos aparecen, excepto el primero, después de que al menos un evento lo anuncie. Un evento NamedSetOfFiles se anuncia mediante 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. En la siguiente transmisión de eventos JSON y el código de Python, se demuestra cómo propagar un mapa desde un objetivo o aspecto hasta los 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)