OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright 2015 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """Print a diff generated by generate_idl_diff.py. |
| 7 Before printing, sort the diff in the alphabetical order or the order of |
| 8 diffing tags. |
| 9 Usage: print_idl_diff.py diff_file.json order |
| 10 diff.json: |
| 11 Output of generate_idl_diff.py. The json file contains a dictionary |
| 12 that represents a diff between two different Chromium versions. The |
| 13 structure of the dictionary is like below. |
| 14 order: |
| 15 Specify how to sort. Either by "ALPHABET" or "TAG". |
| 16 """ |
| 17 |
| 18 from collections import OrderedDict |
| 19 import json |
| 20 import sys |
| 21 |
| 22 from generate_idl_diff import load_json_file |
| 23 from generate_idl_diff import EXTATTRIBUTES_AND_MEMBER_TYPES |
| 24 from generate_idl_diff import DIFF_TAG |
| 25 from generate_idl_diff import DIFF_TAG_ADDED |
| 26 from generate_idl_diff import DIFF_TAG_DELETED |
| 27 |
| 28 |
| 29 """Refer to the explanation of generate_idl_diff.py's input files. |
| 30 The deffference between the input structure of generate_idl_diff.py and |
| 31 that of print_diff.py is whether diffing tags are included or not. |
| 32 {'Interface': { |
| 33 'diff_tag': 'deleted' |
| 34 'ExtAttributes': [{'Name': '...' |
| 35 'diff_tag': 'deleted'}, |
| 36 ..., |
| 37 ], |
| 38 'Consts': [{'Type': '...', |
| 39 'Name': '...', |
| 40 'Value': '...' |
| 41 'diff_tag': 'deleted'}, |
| 42 ..., |
| 43 ], |
| 44 'Attributes': [{'Type': '...', |
| 45 'Name': '...', |
| 46 'ExtAttributes':[{'Name': '...'}, |
| 47 ..., |
| 48 ] |
| 49 'diff_tag': 'deleted'}, |
| 50 ..., |
| 51 ], |
| 52 'Operations': [{'Type': '...', |
| 53 'Name': '...', |
| 54 'ExtAttributes':[{'Name': '...'}, |
| 55 ..., |
| 56 ], |
| 57 'Arguments': [{'Type': '...', |
| 58 'Name': '...'}, |
| 59 ..., |
| 60 ] |
| 61 'diff_tag': 'deleted'}, |
| 62 ..., |
| 63 ], |
| 64 'Name': '...' |
| 65 }, |
| 66 { |
| 67 'ExtAttributes': [{'Name': '...'}, |
| 68 ..., |
| 69 ], |
| 70 'Consts': [{'Type': '...', |
| 71 'Name': '...', |
| 72 'Value': '...' |
| 73 'diff_tag': 'added'}, |
| 74 ..., |
| 75 ], |
| 76 'Attributes': [{'Type': '...', |
| 77 'Name': '...', |
| 78 'ExtAttributes':[{'Name': '...'}, |
| 79 ..., |
| 80 ]}, |
| 81 ..., |
| 82 ], |
| 83 'Operations': [{'Type': '...', |
| 84 'Name': '...', |
| 85 'ExtAttributes':[{'Name': '...'}, |
| 86 ..., |
| 87 ], |
| 88 'Arguments': [{'Type': '...', |
| 89 'Name': '...'}, |
| 90 ..., |
| 91 ] |
| 92 'diff_tag': 'deleted'}, |
| 93 ..., |
| 94 ], |
| 95 'Name': '...' |
| 96 }, |
| 97 ..., |
| 98 } |
| 99 """ |
| 100 |
| 101 |
| 102 class Colorize(object): |
| 103 """This class outputs a colored text to sys.stdout. |
| 104 TODO(bashi): This class doesn't work on Windows. Provide a way to suppress |
| 105 escape sequences. |
| 106 """ |
| 107 |
| 108 BLACK = 30 |
| 109 RED = 31 |
| 110 GREEN = 32 |
| 111 YELLOW = 33 |
| 112 COLORS = (BLACK, RED, GREEN, YELLOW) |
| 113 |
| 114 def __init__(self, out): |
| 115 self.out = out |
| 116 |
| 117 def reset_color(self): |
| 118 """Reset text's color to default. |
| 119 """ |
| 120 self.out.write('\033[0m') |
| 121 |
| 122 def change_color(self, color): |
| 123 """Change text's color by specifing arguments. |
| 124 Args: |
| 125 color: A new color to change. It should be one of |COLORS|. |
| 126 """ |
| 127 if color in self.COLORS: |
| 128 self.out.write('\033[' + str(color) + 'm') |
| 129 else: |
| 130 raise Exception('Unsupported color.') |
| 131 |
| 132 def writeln(self, string): |
| 133 """Print text with a line-break. |
| 134 """ |
| 135 self.out.write(string + '\n') |
| 136 |
| 137 def write(self, string): |
| 138 """Print text without a line-break. |
| 139 """ |
| 140 self.out.write(string) |
| 141 |
| 142 |
| 143 def sort_member_types(interface): |
| 144 """Sort the members in the order of EXTATTRIBUTES_AND_MEMBER_TYPES. |
| 145 Args: |
| 146 interface: An "interface" object |
| 147 Returns: |
| 148 A sorted "interface" object |
| 149 """ |
| 150 sorted_interface = OrderedDict() |
| 151 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
| 152 sorted_interface[member_type] = interface.get(member_type) |
| 153 sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) |
| 154 return sorted_interface |
| 155 |
| 156 |
| 157 def group_by_tag(interface_or_member_list): |
| 158 """Group members of |interface_or_member_list| by tags. |
| 159 Args: |
| 160 interface_or_member_list: A list of interface names or a list of "member
s" |
| 161 Returns: |
| 162 A tuple of (removed, added, unchanged) where |
| 163 removed: A list of removed members |
| 164 added: A list of added members |
| 165 unspecified: A list of other members |
| 166 """ |
| 167 removed = [] |
| 168 added = [] |
| 169 unspecified = [] |
| 170 for interface_or_member in interface_or_member_list: |
| 171 if DIFF_TAG in interface_or_member: |
| 172 if interface_or_member[DIFF_TAG] == DIFF_TAG_DELETED: |
| 173 removed.append(interface_or_member) |
| 174 elif interface_or_member[DIFF_TAG] == DIFF_TAG_ADDED: |
| 175 added.append(interface_or_member) |
| 176 else: |
| 177 unspecified.append(interface_or_member) |
| 178 return (removed, added, unspecified) |
| 179 |
| 180 |
| 181 def sort_interface_names_by_tags(interfaces): |
| 182 """Sort interface names as follows. |
| 183 [names of deleted "interface"s |
| 184 -> names of added "interface"s |
| 185 -> names of other "interface"s] |
| 186 Args: |
| 187 interfaces: "interface" objects. |
| 188 Returns: |
| 189 A list of sorted interface names |
| 190 """ |
| 191 interface_list = interfaces.values() |
| 192 removed, added, unspecified = group_by_tag(interface_list) |
| 193 removed = map(lambda interface: interface['Name'], removed) |
| 194 added = map(lambda interface: interface['Name'], added) |
| 195 unspecified = map(lambda interface: interface['Name'], unspecified) |
| 196 sorted_interface_names = removed + added + unspecified |
| 197 return sorted_interface_names |
| 198 |
| 199 |
| 200 def sort_members_by_tags(interface): |
| 201 """Sort members of a given interface in the order of diffing tags. |
| 202 Args: |
| 203 An "interface" object |
| 204 Returns: |
| 205 A sorted "interface" object |
| 206 """ |
| 207 sorted_interface = OrderedDict() |
| 208 if DIFF_TAG in interface: |
| 209 return interface |
| 210 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
| 211 member_list = interface[member_type] |
| 212 removed, added, unspecified = group_by_tag(member_list) |
| 213 sorted_interface[member_type] = removed + added + unspecified |
| 214 return sorted_interface |
| 215 |
| 216 |
| 217 def sort_diff_by_tags(interfaces): |
| 218 """Sort an "interfaces" object in the order of diffing tags. |
| 219 Args: |
| 220 An "interfaces" object loaded by load_json_data(). |
| 221 Returns: |
| 222 A sorted "interfaces" object |
| 223 """ |
| 224 sorted_interfaces = OrderedDict() |
| 225 sorted_interface_names = sort_interface_names_by_tags(interfaces) |
| 226 for interface_name in sorted_interface_names: |
| 227 interface = sort_members_by_tags(interfaces[interface_name]) |
| 228 sorted_interfaces[interface_name] = sort_member_types(interface) |
| 229 return sorted_interfaces |
| 230 |
| 231 |
| 232 def sort_members_in_alphabetical_order(interface): |
| 233 """Sort a "members" object in the alphabetical order. |
| 234 Args: |
| 235 An "interface" object |
| 236 Returns: |
| 237 A sorted "interface" object |
| 238 """ |
| 239 sorted_interface = OrderedDict() |
| 240 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
| 241 sorted_members = sorted(interface[member_type], |
| 242 key=lambda member: member['Name']) |
| 243 sorted_interface[member_type] = sorted_members |
| 244 return sorted_interface |
| 245 |
| 246 |
| 247 def sort_diff_in_alphabetical_order(interfaces): |
| 248 """Sort an "interfaces" object in the alphabetical order. |
| 249 Args: |
| 250 An "interfaces" object. |
| 251 Returns: |
| 252 A sorted "interfaces" object |
| 253 """ |
| 254 sorted_interfaces = OrderedDict() |
| 255 for interface_name in sorted(interfaces.keys()): |
| 256 interface = interfaces[interface_name] |
| 257 sorted_interface = sort_members_in_alphabetical_order(interface) |
| 258 sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) |
| 259 sorted_interfaces[interface_name] = sorted_interface |
| 260 return sorted_interfaces |
| 261 |
| 262 |
| 263 def print_member_with_color(member, out): |
| 264 """Print the "member" with a colored text. '+' is added to an added |
| 265 "member". '-' is added to a removed "member". |
| 266 Args: |
| 267 member: A "member" object |
| 268 """ |
| 269 if DIFF_TAG in member: |
| 270 if member[DIFF_TAG] == DIFF_TAG_DELETED: |
| 271 out.change_color(Colorize.RED) |
| 272 out.write('- ') |
| 273 elif member[DIFF_TAG] == DIFF_TAG_ADDED: |
| 274 out.change_color(Colorize.GREEN) |
| 275 out.write('+ ') |
| 276 else: |
| 277 out.change_color(Colorize.BLACK) |
| 278 out.write(' ') |
| 279 |
| 280 |
| 281 def print_extattributes(extattributes, out): |
| 282 """Print extattributes in an "interface" object. |
| 283 Args: |
| 284 A list of "ExtAttributes" in the "interface" object |
| 285 """ |
| 286 for extattribute in extattributes: |
| 287 out.write(' ') |
| 288 print_member_with_color(extattribute, out) |
| 289 out.writeln(extattribute['Name']) |
| 290 |
| 291 |
| 292 def print_consts(consts, out): |
| 293 """Print consts in an "interface" object. |
| 294 Args: |
| 295 A list of "Consts" of the "interface" object |
| 296 """ |
| 297 for const in consts: |
| 298 out.write(' ') |
| 299 print_member_with_color(const, out) |
| 300 out.write(str(const['Type'])) |
| 301 out.write(' ') |
| 302 out.write(const['Name']) |
| 303 out.write(' ') |
| 304 out.writeln(const['Value']) |
| 305 |
| 306 |
| 307 def print_items(items, callback, out): |
| 308 """Calls |callback| for each item in |items|, printing commas between |
| 309 |callback| calls. |
| 310 Args: |
| 311 items: extattributes or arguments |
| 312 """ |
| 313 count = 0 |
| 314 for item in items: |
| 315 callback(item) |
| 316 count += 1 |
| 317 if count < len(items): |
| 318 out.write(', ') |
| 319 |
| 320 |
| 321 def print_extattributes_in_member(extattributes, out): |
| 322 """Print extattributes in a "member" object. |
| 323 Args: |
| 324 A list of "ExtAttributes" in the "member" object |
| 325 """ |
| 326 def callback(extattribute): |
| 327 out.write(extattribute['Name']) |
| 328 |
| 329 out.write('[') |
| 330 print_items(extattributes, callback, out) |
| 331 out.write(']') |
| 332 |
| 333 |
| 334 def print_attributes(attributes, out): |
| 335 """Print attributes in an "interface" object. |
| 336 Args: |
| 337 A list of "Attributes" in the "interface" object |
| 338 """ |
| 339 for attribute in attributes: |
| 340 out.write(' ') |
| 341 print_member_with_color(attribute, out) |
| 342 if attribute['ExtAttributes']: |
| 343 print_extattributes_in_member(attribute['ExtAttributes'], out) |
| 344 out.write(str(attribute['Type'])) |
| 345 out.write(' ') |
| 346 out.writeln(attribute['Name']) |
| 347 |
| 348 |
| 349 def print_arguments(arguments, out): |
| 350 """Print arguments in a "members" object named "Operations". |
| 351 Args: A list of "Arguments" |
| 352 """ |
| 353 def callback(argument): |
| 354 out.write(argument['Name']) |
| 355 |
| 356 out.write('(') |
| 357 print_items(arguments, callback, out) |
| 358 out.writeln(')') |
| 359 |
| 360 |
| 361 def print_operations(operations, out): |
| 362 """Print operations in a "member" object. |
| 363 Args: |
| 364 A list of "Operations" |
| 365 """ |
| 366 for operation in operations: |
| 367 out.write(' ') |
| 368 print_member_with_color(operation, out) |
| 369 if operation['ExtAttributes']: |
| 370 print_extattributes_in_member(operation['ExtAttributes'], out) |
| 371 out.write(str(operation['Type'])) |
| 372 out.write(' ') |
| 373 if operation['Arguments']: |
| 374 out.write(operation['Name']) |
| 375 print_arguments(operation['Arguments'], out) |
| 376 else: |
| 377 out.writeln(operation['Name']) |
| 378 |
| 379 |
| 380 def print_diff(diff, out): |
| 381 """Print the diff on a shell. |
| 382 Args: |
| 383 A sorted diff |
| 384 """ |
| 385 for interface_name, interface in diff.iteritems(): |
| 386 print_member_with_color(interface, out) |
| 387 out.change_color(Colorize.YELLOW) |
| 388 out.write('[[') |
| 389 out.write(interface_name) |
| 390 out.writeln(']]') |
| 391 out.reset_color() |
| 392 for member_name, member in interface.iteritems(): |
| 393 if member_name == 'ExtAttributes': |
| 394 out.writeln('ExtAttributes') |
| 395 print_extattributes(member, out) |
| 396 elif member_name == 'Consts': |
| 397 out.writeln(' Consts') |
| 398 print_consts(member, out) |
| 399 elif member_name == 'Attributes': |
| 400 out.writeln(' Attributes') |
| 401 print_attributes(member, out) |
| 402 elif member_name == 'Operations': |
| 403 out.writeln(' Operations') |
| 404 print_operations(member, out) |
| 405 out.reset_color() |
| 406 |
| 407 |
| 408 def print_usage(): |
| 409 """Show usage.""" |
| 410 sys.stdout.write('Usage: print_diff.py <diff_file.json> <"TAG"|"ALPHABET">\n
') |
| 411 |
| 412 |
| 413 def main(argv): |
| 414 if len(argv) != 2: |
| 415 print_usage() |
| 416 exit(1) |
| 417 json_data = argv[0] |
| 418 order = argv[1] |
| 419 diff = load_json_file(json_data) |
| 420 if order == 'TAG': |
| 421 sort_func = sort_diff_by_tags |
| 422 elif order == 'ALPHABET': |
| 423 sort_func = sort_diff_in_alphabetical_order |
| 424 else: |
| 425 print_usage() |
| 426 exit(1) |
| 427 sorted_diff = sort_func(diff) |
| 428 out = Colorize(sys.stdout) |
| 429 print_diff(sorted_diff, out) |
| 430 |
| 431 |
| 432 if __name__ == '__main__': |
| 433 main(sys.argv[1:]) |
OLD | NEW |