1# Copyright 2022 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Transforms a JSON list of paths using -ffile-prefix-map style rules.""" 15 16import argparse 17import json 18from typing import Iterator, TextIO 19 20# Note: This should be list[tuple[str, str]], but using string.split() 21# produces tuple[Any,...], so this permits that typing for convenience. 22PrefixMaps = list[tuple] 23 24 25def _parse_args() -> argparse.Namespace: 26 """Parses and returns the command line arguments.""" 27 28 parser = argparse.ArgumentParser(description=__doc__) 29 parser.add_argument( 30 'in_json', 31 type=argparse.FileType('r'), 32 help='The JSON file containing a list of file names ' 33 'that the prefix map operations should be applied to', 34 ) 35 parser.add_argument( 36 '--prefix-map-json', 37 type=argparse.FileType('r'), 38 required=True, 39 help=( 40 'JSON file containing an array of prefix map transformations to ' 41 'apply to the strings before tokenizing. These string literal ' 42 'transformations are of the form "from=to". All strings with the ' 43 'prefix `from` will have the prefix replaced with `to`. ' 44 'Transformations are applied in the order they are listed in the ' 45 'JSON file.' 46 ), 47 ) 48 49 parser.add_argument( 50 '--output', 51 type=argparse.FileType('w'), 52 help='File path to write transformed paths to.', 53 ) 54 return parser.parse_args() 55 56 57def remap_paths(paths: list[str], prefix_maps: PrefixMaps) -> Iterator[str]: 58 for path in paths: 59 for from_prefix, to_prefix in prefix_maps: 60 if path.startswith(from_prefix): 61 path = path.replace(from_prefix, to_prefix, 1) 62 break # Only the first -ffile-prefix-map option applies. 63 yield path 64 65 66def remap_json_paths( 67 in_json: TextIO, output: TextIO, prefix_map_json: TextIO 68) -> None: 69 paths = json.load(in_json) 70 prefix_maps: PrefixMaps = [ 71 tuple(m.split('=', maxsplit=1)) for m in json.load(prefix_map_json) 72 ] 73 74 json.dump(list(remap_paths(paths, prefix_maps)), output) 75 76 77if __name__ == '__main__': 78 remap_json_paths(**vars(_parse_args())) 79