| # Copyright 2023 The Pigweed Authors |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| # use this file except in compliance with the License. You may obtain a copy of |
| # the License at |
| # |
| # https://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| # License for the specific language governing permissions and limitations under |
| # the License. |
| """Merge multiple profraws together using llvm-profdata.""" |
| |
| import argparse |
| import enum |
| import json |
| import logging |
| import subprocess |
| import sys |
| from pathlib import Path |
| from typing import Any |
| |
| _LOG = logging.getLogger(__name__) |
| |
| |
| class FailureMode(enum.Enum): |
| ANY = 'any' |
| ALL = 'all' |
| |
| def __str__(self): |
| return self.value |
| |
| |
| def _parse_args() -> dict[str, Any]: |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument( |
| '--llvm-profdata-path', |
| type=Path, |
| required=True, |
| help='Path to the llvm-profdata binary to use for merging.', |
| ) |
| parser.add_argument( |
| '--test-metadata-path', |
| type=Path, |
| required=True, |
| help='Path to the *.test_metadata.json file that describes all of the ' |
| 'tests being used to generate a coverage report.', |
| ) |
| parser.add_argument( |
| '--profdata-path', |
| type=Path, |
| required=True, |
| help='Path for the output merged profdata file to use with generating a' |
| ' coverage report for the tests described in --test-metadata.', |
| ) |
| parser.add_argument( |
| '--depfile-path', |
| type=Path, |
| required=True, |
| help='Path for the output depfile to convey the extra input ' |
| 'requirements from parsing --test-metadata.', |
| ) |
| parser.add_argument( |
| '--failure-mode', |
| type=FailureMode, |
| choices=list(FailureMode), |
| required=False, |
| default=FailureMode.ANY, |
| help='Sets the llvm-profdata --failure-mode option.', |
| ) |
| return vars(parser.parse_args()) |
| |
| |
| def merge_profraws( |
| llvm_profdata_path: Path, |
| test_metadata_path: Path, |
| profdata_path: Path, |
| depfile_path: Path, |
| failure_mode: FailureMode, |
| ) -> int: |
| """Merge multiple profraws together using llvm-profdata.""" |
| |
| # Open the test_metadata_path, parse it to JSON, and extract out the |
| # profraws. |
| test_metadata = json.loads(test_metadata_path.read_text()) |
| profraw_paths = [ |
| str(obj['path']) |
| for obj in test_metadata |
| if 'type' in obj and obj['type'] == 'profraw' |
| ] |
| |
| # Generate merged profdata. |
| command = [ |
| str(llvm_profdata_path), |
| 'merge', |
| '--sparse', |
| '--failure-mode', |
| str(failure_mode), |
| '-o', |
| str(profdata_path), |
| ] + profraw_paths |
| |
| _LOG.info('') |
| _LOG.info(' '.join(command)) |
| _LOG.info('') |
| |
| output = subprocess.run(command) |
| if output.returncode != 0: |
| return output.returncode |
| |
| # Generate the depfile that describes the dependency on the profraws used to |
| # create profdata_path. |
| depfile_path.write_text( |
| ''.join( |
| [ |
| str(profdata_path), |
| ': \\\n', |
| *[str(path) + ' \\\n' for path in profraw_paths], |
| ] |
| ) |
| ) |
| |
| return 0 |
| |
| |
| def main() -> int: |
| return merge_profraws(**_parse_args()) |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |