1#!/usr/bin/env python3 2# Copyright 2015 gRPC authors. 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16# produces cleaner build.yaml files 17 18import collections 19import os 20import sys 21 22import yaml 23 24TEST = os.environ.get("TEST", "false") == "true" 25 26_TOP_LEVEL_KEYS = [ 27 "settings", 28 "proto_deps", 29 "filegroups", 30 "libs", 31 "targets", 32 "vspackages", 33] 34_ELEM_KEYS = [ 35 "name", 36 "gtest", 37 "cpu_cost", 38 "flaky", 39 "build", 40 "run", 41 "language", 42 "plugin_option", 43 "public_headers", 44 "headers", 45 "src", 46 "deps", 47] 48 49 50def repr_ordered_dict(dumper, odict): 51 return dumper.represent_mapping( 52 "tag:yaml.org,2002:map", list(odict.items()) 53 ) 54 55 56yaml.add_representer(collections.OrderedDict, repr_ordered_dict) 57 58 59def _rebuild_as_ordered_dict(indict, special_keys): 60 outdict = collections.OrderedDict() 61 for key in sorted(indict.keys()): 62 if "#" in key: 63 outdict[key] = indict[key] 64 for key in special_keys: 65 if key in indict: 66 outdict[key] = indict[key] 67 for key in sorted(indict.keys()): 68 if key in special_keys: 69 continue 70 if "#" in key: 71 continue 72 outdict[key] = indict[key] 73 return outdict 74 75 76def _clean_elem(indict): 77 for name in ["public_headers", "headers", "src"]: 78 if name not in indict: 79 continue 80 inlist = indict[name] 81 protos = list(x for x in inlist if os.path.splitext(x)[1] == ".proto") 82 others = set(x for x in inlist if x not in protos) 83 indict[name] = protos + sorted(others) 84 return _rebuild_as_ordered_dict(indict, _ELEM_KEYS) 85 86 87def cleaned_build_yaml_dict_as_string(indict): 88 """Takes dictionary which represents yaml file and returns the cleaned-up yaml string""" 89 js = _rebuild_as_ordered_dict(indict, _TOP_LEVEL_KEYS) 90 for grp in ["filegroups", "libs", "targets"]: 91 if grp not in js: 92 continue 93 js[grp] = sorted( 94 [_clean_elem(x) for x in js[grp]], 95 key=lambda x: (x.get("language", "_"), x["name"]), 96 ) 97 output = yaml.dump(js, indent=2, width=80, default_flow_style=False) 98 # massage out trailing whitespace 99 lines = [] 100 for line in output.splitlines(): 101 lines.append(line.rstrip() + "\n") 102 output = "".join(lines) 103 return output 104 105 106if __name__ == "__main__": 107 for filename in sys.argv[1:]: 108 with open(filename) as f: 109 js = yaml.safe_load(f) 110 output = cleaned_build_yaml_dict_as_string(js) 111 if TEST: 112 with open(filename) as f: 113 if not f.read() == output: 114 raise Exception( 115 "Looks like build-cleaner.py has not been run for file" 116 ' "%s"?' % filename 117 ) 118 else: 119 with open(filename, "w") as f: 120 f.write(output) 121