빌드 이벤트 프로토콜 예시

<ph type="x-smartling-placeholder"></ph> 문제 신고 소스 보기 1박 · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

빌드 이벤트 프로토콜의 전체 사양은 해당 프로토콜에서 확인할 수 있습니다. 버퍼 정의입니다. 하지만 사용 사례에 대한 직관을 쌓는 것이 한 번 더 검토하겠습니다

두 개의 빈 셸 스크립트로 구성된 간단한 Bazel 작업공간을 생각해 보세요. foo.sh, foo_test.sh, 다음 BUILD 파일

sh_library(
    name = "foo_lib",
    srcs = ["foo.sh"],
)

sh_test(
    name = "foo_test",
    srcs = ["foo_test.sh"],
    deps = [":foo_lib"],
)

이 프로젝트에서 bazel test ...를 실행하면 생성된 아래 그래프와 비슷합니다. 화살표는 부모와 자녀 관계를 맺고 있습니다. 일부 빌드 이벤트와 간결성을 위해 대부분의 필드가 생략되었습니다.

Bep-graph

그림 1. BEP 그래프.

처음에는 BuildStarted 이벤트가 게시됩니다. 이벤트를 통해 빌드가 bazel test 명령어를 통해 호출되고 하위 이벤트를 알립니다.

  • OptionsParsed
  • WorkspaceStatus
  • CommandLine
  • UnstructuredCommandLine
  • BuildMetadata
  • BuildFinished
  • PatternExpanded
  • Progress

처음 세 이벤트는 Bazel이 호출된 방식에 대한 정보를 제공합니다.

PatternExpanded 빌드 이벤트는 통계를 제공합니다. ... 패턴이 다음과 같이 확장되는 구체적인 타겟입니다. //foo:foo_lib//foo:foo_test. 이를 위해서는 TargetConfigured 이벤트를 하위 요소로 반환합니다. TargetConfigured 이벤트는 Configuration이더라도 Configuration 이벤트를 하위 이벤트로 선언합니다. TargetConfigured 이벤트 전에 게시되었습니다.

상위 및 하위 관계 외에도 이벤트는 서로를 참조할 수도 있습니다. 빌드 이벤트 식별자를 사용합니다 예를 들어 위의 그래프에서 TargetComplete 이벤트는 fileSetsNamedSetOfFiles 이벤트를 나타냄 필드를 확인합니다.

파일을 참조하는 빌드 이벤트는 일반적으로 파일을 삽입하지 않음 이벤트 이름 및 경로를 지정합니다. 대신 빌드 이벤트 식별자가 포함됩니다. NamedSetOfFiles 이벤트의 필드로, 실제 파일 이름과 학습합니다. NamedSetOfFiles 이벤트를 사용하면 파일 집합을 한 번 보고할 수 있습니다. 참조될 수 있습니다 이러한 구조가 필요한 이유는 경우에 따라 빌드 이벤트 프로토콜 출력 크기는 파일 수를 제어합니다. NamedSetOfFiles 이벤트에 일부 파일이 포함되어 있지 않을 수도 있습니다. 대신 NamedSetOfFiles 빌드 이벤트 식별자입니다

다음은 //foo:foo_libTargetComplete 이벤트 인스턴스입니다. 대상이며 프로토콜 버퍼의 JSON 표현으로 출력됩니다. 빌드 이벤트 식별자는 타겟을 불투명 문자열로 포함하며 다음을 참조합니다. Configuration 이벤트를 구성합니다. 이벤트가 실행되지 않습니다. 하위 이벤트를 알립니다. 이 페이로드에는 현재 IP 주소가 있는지에 대한 출력 파일 세트와 타겟의 종류를 빌드되었습니다.

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

BEP의 Aspect 결과

일반 빌드는 (target, configuration)와 관련된 작업을 평가합니다. 쌍. 가로세로를 사용 설정한 상태에서 빌드할 때 Bazel 사용 설정된 측면의 영향을 받는 각 타겟에 대해 (target, configuration, aspect) 삼중과 연결된 타겟을 추가로 평가합니다.

관점별 이벤트 유형입니다. 각 (target, configuration) 쌍마다 Bazel은 추가 TargetConfigured 및 관점을 적용한 결과가 포함된 TargetComplete 이벤트 있습니다. 예를 들어 //:foo_lib--aspects=aspects/myaspect.bzl%custom_aspect, 이 이벤트는 다음 위치에도 표시됩니다. 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"
      }]
    }]
  }
}

NamedSetOfFiles 사용 중

특정 타겟 (또는 관점)에 의해 생성된 아티팩트를 판단하는 것은 일반적인 일임 몇 가지 준비를 통해 효율적으로 수행할 수 있는 BEP 사용 사례 이 섹션 NamedSetOfFiles에서 제공하는 반복적 공유 구조 설명 이벤트를 수신합니다. 이 이벤트는 Starlark Depset의 구조와 일치합니다.

소비자는 처리 시 이차 알고리즘을 피하도록 주의해야 합니다. NamedSetOfFiles 이벤트로 인해 대규모 빌드에 수만 개의 순회 작업에 수억 개의 작업이 필요하며 2차 복잡도입니다.

namedsetoffiles-bep-graph

그림 2. NamedSetOfFiles BEP 그래프

NamedSetOfFiles 이벤트는 항상 BEP 스트림에 표시된 TargetComplete 또는 NamedSetOfFiles 이벤트를 반환합니다. 이것은 '상위-하위 요소'의 첫 번째 이벤트를 제외한 모든 이벤트가 하나 이상의 이벤트 후에 표시됩니다. NamedSetOfFiles 이벤트는 다음과 같습니다. 시맨틱이 없는 Progress 이벤트에 의해 공지됩니다.

이러한 순서 및 공유 제약 조건을 고려할 때 일반적인 소비자는 BEP 스트림이 소진될 때까지 이벤트가 NamedSetOfFiles개 남았습니다. 다음 JSON 이벤트 스트림 및 Python 코드를 사용하여 대상/대상: '기본값'의 빌드된 아티팩트 어떻게 해야 할까요? 빌드된 타겟/측면의 하위 집합에 대한 출력을 처리합니다.

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)