xref: /aosp_15_r20/external/mesa3d/bin/ci/update_traces_checksum.py (revision 6104692788411f58d303aa86923a9ff6ecaded22)
1#!/usr/bin/env python3
2# Copyright © 2022 Collabora Ltd.
3# Authors:
4#   David Heidelberg <[email protected]>
5#
6# For the dependencies, see the requirements.txt
7# SPDX-License-Identifier: MIT
8
9"""
10Helper script to update traces checksums
11"""
12
13import argparse
14import bz2
15import glob
16import re
17import json
18import sys
19from ruamel.yaml import YAML
20
21import gitlab
22from colorama import Fore, Style
23from gitlab_common import get_gitlab_project, read_token, wait_for_pipeline, get_gitlab_pipeline_from_url
24
25
26DESCRIPTION_FILE = "export PIGLIT_REPLAY_DESCRIPTION_FILE=.*/install/(.*)$"
27DEVICE_NAME = "export PIGLIT_REPLAY_DEVICE_NAME='(.*)'$"
28
29
30def gather_results(
31    project,
32    pipeline,
33) -> None:
34    """Gather results"""
35
36    target_jobs_regex = re.compile(".*-traces([:].*)?$")
37
38    for job in pipeline.jobs.list(all=True, sort="desc"):
39        if target_jobs_regex.match(job.name) and job.status == "failed":
40            cur_job = project.jobs.get(job.id)
41            # get variables
42            print(f"��  {job.name}...")
43            log: list[str] = cur_job.trace().decode("unicode_escape", "ignore").splitlines()
44            filename: str = ''
45            dev_name: str = ''
46            for logline in log:
47                desc_file = re.search(DESCRIPTION_FILE, logline)
48                device_name = re.search(DEVICE_NAME, logline)
49                if desc_file:
50                    filename = desc_file.group(1)
51                if device_name:
52                    dev_name = device_name.group(1)
53
54            if not filename or not dev_name:
55                print(Fore.RED + "Couldn't find device name or YML file in the logs!" + Style.RESET_ALL)
56                return
57
58            print(f"�� Found {dev_name} and file {filename}")
59
60            # find filename in Mesa source
61            traces_file = glob.glob('./**/' + filename, recursive=True)
62            # write into it
63            with open(traces_file[0], 'r', encoding='utf-8') as target_file:
64                yaml = YAML()
65                yaml.compact(seq_seq=False, seq_map=False)
66                yaml.version = 1,2
67                yaml.width = 2048  # do not break the text fields
68                yaml.default_flow_style = None
69                target = yaml.load(target_file)
70
71                # parse artifact
72                results_json_bz2 = cur_job.artifact("results/results.json.bz2")
73                results_json = bz2.decompress(results_json_bz2).decode("utf-8", errors="replace")
74                results = json.loads(results_json)
75
76                for _, value in results["tests"].items():
77                    if (
78                        not value['images'] or
79                        not value['images'][0] or
80                        "image_desc" not in value['images'][0]
81                    ):
82                        continue
83
84                    trace: str = value['images'][0]['image_desc']
85                    checksum: str = value['images'][0]['checksum_render']
86
87                    if not checksum:
88                        print(Fore.RED + f"{dev_name}: {trace}: checksum is missing! Crash?" + Style.RESET_ALL)
89                        continue
90
91                    if checksum == "error":
92                        print(Fore.RED + f"{dev_name}: {trace}: crashed" + Style.RESET_ALL)
93                        continue
94
95                    if target['traces'][trace][dev_name].get('checksum') == checksum:
96                        continue
97
98                    if "label" in target['traces'][trace][dev_name]:
99                        print(f'{dev_name}: {trace}: please verify that label {Fore.BLUE}{target["traces"][trace][dev_name]["label"]}{Style.RESET_ALL} is still valid')
100
101                    print(Fore.GREEN + f'{dev_name}: {trace}: checksum updated' + Style.RESET_ALL)
102                    target['traces'][trace][dev_name]['checksum'] = checksum
103
104            with open(traces_file[0], 'w', encoding='utf-8') as target_file:
105                yaml.dump(target, target_file)
106
107
108
109def parse_args() -> None:
110    """Parse args"""
111    parser = argparse.ArgumentParser(
112        description="Tool to generate patch from checksums ",
113        epilog="Example: update_traces_checksum.py --rev $(git rev-parse HEAD) "
114    )
115    parser.add_argument(
116        "--rev", metavar="revision", help="repository git revision",
117    )
118    parser.add_argument(
119        "--token",
120        metavar="token",
121        help="force GitLab token, otherwise it's read from ~/.config/gitlab-token",
122    )
123    parser.add_argument(
124        "--pipeline-url",
125        metavar="pipeline_url",
126        help="specify a pipeline url",
127    )
128    return parser.parse_args()
129
130
131if __name__ == "__main__":
132    try:
133        args = parse_args()
134
135        token = read_token(args.token)
136
137        gl = gitlab.Gitlab(url="https://gitlab.freedesktop.org", private_token=token)
138
139        cur_project = get_gitlab_project(gl, "mesa")
140
141        if args.pipeline_url:
142            pipe, cur_project = get_gitlab_pipeline_from_url(gl, args.pipeline_url)
143            REV = pipe.sha
144        else:
145            if not args.rev:
146                print('error: the following arguments are required: --rev')
147                sys.exit(1)
148            print(f"Revision: {args.rev}")
149            (pipe, cur_project) = wait_for_pipeline([cur_project], args.rev)
150        print(f"Pipeline: {pipe.web_url}")
151        gather_results(cur_project, pipe)
152
153        sys.exit()
154    except KeyboardInterrupt:
155        sys.exit(1)
156