Index: bindings/scripts/print_idl_diff.py |
diff --git a/bindings/scripts/print_idl_diff.py b/bindings/scripts/print_idl_diff.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9a8deea5afa18c9330003a2ac6e97fce94a8019a |
--- /dev/null |
+++ b/bindings/scripts/print_idl_diff.py |
@@ -0,0 +1,433 @@ |
+#!/usr/bin/env python |
+# Copyright 2015 The Chromium Authors. All rights reserved. |
+# Use of this source code is governed by a BSD-style license that can be |
+# found in the LICENSE file. |
+ |
+"""Print a diff generated by generate_idl_diff.py. |
+Before printing, sort the diff in the alphabetical order or the order of |
+diffing tags. |
+Usage: print_idl_diff.py diff_file.json order |
+ diff.json: |
+ Output of generate_idl_diff.py. The json file contains a dictionary |
+ that represents a diff between two different Chromium versions. The |
+ structure of the dictionary is like below. |
+ order: |
+ Specify how to sort. Either by "ALPHABET" or "TAG". |
+""" |
+ |
+from collections import OrderedDict |
+import json |
+import sys |
+ |
+from generate_idl_diff import load_json_file |
+from generate_idl_diff import EXTATTRIBUTES_AND_MEMBER_TYPES |
+from generate_idl_diff import DIFF_TAG |
+from generate_idl_diff import DIFF_TAG_ADDED |
+from generate_idl_diff import DIFF_TAG_DELETED |
+ |
+ |
+"""Refer to the explanation of generate_idl_diff.py's input files. |
+The deffference between the input structure of generate_idl_diff.py and |
+that of print_diff.py is whether diffing tags are included or not. |
+ {'Interface': { |
+ 'diff_tag': 'deleted' |
+ 'ExtAttributes': [{'Name': '...' |
+ 'diff_tag': 'deleted'}, |
+ ..., |
+ ], |
+ 'Consts': [{'Type': '...', |
+ 'Name': '...', |
+ 'Value': '...' |
+ 'diff_tag': 'deleted'}, |
+ ..., |
+ ], |
+ 'Attributes': [{'Type': '...', |
+ 'Name': '...', |
+ 'ExtAttributes':[{'Name': '...'}, |
+ ..., |
+ ] |
+ 'diff_tag': 'deleted'}, |
+ ..., |
+ ], |
+ 'Operations': [{'Type': '...', |
+ 'Name': '...', |
+ 'ExtAttributes':[{'Name': '...'}, |
+ ..., |
+ ], |
+ 'Arguments': [{'Type': '...', |
+ 'Name': '...'}, |
+ ..., |
+ ] |
+ 'diff_tag': 'deleted'}, |
+ ..., |
+ ], |
+ 'Name': '...' |
+ }, |
+ { |
+ 'ExtAttributes': [{'Name': '...'}, |
+ ..., |
+ ], |
+ 'Consts': [{'Type': '...', |
+ 'Name': '...', |
+ 'Value': '...' |
+ 'diff_tag': 'added'}, |
+ ..., |
+ ], |
+ 'Attributes': [{'Type': '...', |
+ 'Name': '...', |
+ 'ExtAttributes':[{'Name': '...'}, |
+ ..., |
+ ]}, |
+ ..., |
+ ], |
+ 'Operations': [{'Type': '...', |
+ 'Name': '...', |
+ 'ExtAttributes':[{'Name': '...'}, |
+ ..., |
+ ], |
+ 'Arguments': [{'Type': '...', |
+ 'Name': '...'}, |
+ ..., |
+ ] |
+ 'diff_tag': 'deleted'}, |
+ ..., |
+ ], |
+ 'Name': '...' |
+ }, |
+ ..., |
+ } |
+""" |
+ |
+ |
+class Colorize(object): |
+ """This class outputs a colored text to sys.stdout. |
+ TODO(bashi): This class doesn't work on Windows. Provide a way to suppress |
+ escape sequences. |
+ """ |
+ |
+ BLACK = 30 |
+ RED = 31 |
+ GREEN = 32 |
+ YELLOW = 33 |
+ COLORS = (BLACK, RED, GREEN, YELLOW) |
+ |
+ def __init__(self, out): |
+ self.out = out |
+ |
+ def reset_color(self): |
+ """Reset text's color to default. |
+ """ |
+ self.out.write('\033[0m') |
+ |
+ def change_color(self, color): |
+ """Change text's color by specifing arguments. |
+ Args: |
+ color: A new color to change. It should be one of |COLORS|. |
+ """ |
+ if color in self.COLORS: |
+ self.out.write('\033[' + str(color) + 'm') |
+ else: |
+ raise Exception('Unsupported color.') |
+ |
+ def writeln(self, string): |
+ """Print text with a line-break. |
+ """ |
+ self.out.write(string + '\n') |
+ |
+ def write(self, string): |
+ """Print text without a line-break. |
+ """ |
+ self.out.write(string) |
+ |
+ |
+def sort_member_types(interface): |
+ """Sort the members in the order of EXTATTRIBUTES_AND_MEMBER_TYPES. |
+ Args: |
+ interface: An "interface" object |
+ Returns: |
+ A sorted "interface" object |
+ """ |
+ sorted_interface = OrderedDict() |
+ for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
+ sorted_interface[member_type] = interface.get(member_type) |
+ sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) |
+ return sorted_interface |
+ |
+ |
+def group_by_tag(interface_or_member_list): |
+ """Group members of |interface_or_member_list| by tags. |
+ Args: |
+ interface_or_member_list: A list of interface names or a list of "members" |
+ Returns: |
+ A tuple of (removed, added, unchanged) where |
+ removed: A list of removed members |
+ added: A list of added members |
+ unspecified: A list of other members |
+ """ |
+ removed = [] |
+ added = [] |
+ unspecified = [] |
+ for interface_or_member in interface_or_member_list: |
+ if DIFF_TAG in interface_or_member: |
+ if interface_or_member[DIFF_TAG] == DIFF_TAG_DELETED: |
+ removed.append(interface_or_member) |
+ elif interface_or_member[DIFF_TAG] == DIFF_TAG_ADDED: |
+ added.append(interface_or_member) |
+ else: |
+ unspecified.append(interface_or_member) |
+ return (removed, added, unspecified) |
+ |
+ |
+def sort_interface_names_by_tags(interfaces): |
+ """Sort interface names as follows. |
+ [names of deleted "interface"s |
+ -> names of added "interface"s |
+ -> names of other "interface"s] |
+ Args: |
+ interfaces: "interface" objects. |
+ Returns: |
+ A list of sorted interface names |
+ """ |
+ interface_list = interfaces.values() |
+ removed, added, unspecified = group_by_tag(interface_list) |
+ removed = map(lambda interface: interface['Name'], removed) |
+ added = map(lambda interface: interface['Name'], added) |
+ unspecified = map(lambda interface: interface['Name'], unspecified) |
+ sorted_interface_names = removed + added + unspecified |
+ return sorted_interface_names |
+ |
+ |
+def sort_members_by_tags(interface): |
+ """Sort members of a given interface in the order of diffing tags. |
+ Args: |
+ An "interface" object |
+ Returns: |
+ A sorted "interface" object |
+ """ |
+ sorted_interface = OrderedDict() |
+ if DIFF_TAG in interface: |
+ return interface |
+ for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
+ member_list = interface[member_type] |
+ removed, added, unspecified = group_by_tag(member_list) |
+ sorted_interface[member_type] = removed + added + unspecified |
+ return sorted_interface |
+ |
+ |
+def sort_diff_by_tags(interfaces): |
+ """Sort an "interfaces" object in the order of diffing tags. |
+ Args: |
+ An "interfaces" object loaded by load_json_data(). |
+ Returns: |
+ A sorted "interfaces" object |
+ """ |
+ sorted_interfaces = OrderedDict() |
+ sorted_interface_names = sort_interface_names_by_tags(interfaces) |
+ for interface_name in sorted_interface_names: |
+ interface = sort_members_by_tags(interfaces[interface_name]) |
+ sorted_interfaces[interface_name] = sort_member_types(interface) |
+ return sorted_interfaces |
+ |
+ |
+def sort_members_in_alphabetical_order(interface): |
+ """Sort a "members" object in the alphabetical order. |
+ Args: |
+ An "interface" object |
+ Returns: |
+ A sorted "interface" object |
+ """ |
+ sorted_interface = OrderedDict() |
+ for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: |
+ sorted_members = sorted(interface[member_type], |
+ key=lambda member: member['Name']) |
+ sorted_interface[member_type] = sorted_members |
+ return sorted_interface |
+ |
+ |
+def sort_diff_in_alphabetical_order(interfaces): |
+ """Sort an "interfaces" object in the alphabetical order. |
+ Args: |
+ An "interfaces" object. |
+ Returns: |
+ A sorted "interfaces" object |
+ """ |
+ sorted_interfaces = OrderedDict() |
+ for interface_name in sorted(interfaces.keys()): |
+ interface = interfaces[interface_name] |
+ sorted_interface = sort_members_in_alphabetical_order(interface) |
+ sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) |
+ sorted_interfaces[interface_name] = sorted_interface |
+ return sorted_interfaces |
+ |
+ |
+def print_member_with_color(member, out): |
+ """Print the "member" with a colored text. '+' is added to an added |
+ "member". '-' is added to a removed "member". |
+ Args: |
+ member: A "member" object |
+ """ |
+ if DIFF_TAG in member: |
+ if member[DIFF_TAG] == DIFF_TAG_DELETED: |
+ out.change_color(Colorize.RED) |
+ out.write('- ') |
+ elif member[DIFF_TAG] == DIFF_TAG_ADDED: |
+ out.change_color(Colorize.GREEN) |
+ out.write('+ ') |
+ else: |
+ out.change_color(Colorize.BLACK) |
+ out.write(' ') |
+ |
+ |
+def print_extattributes(extattributes, out): |
+ """Print extattributes in an "interface" object. |
+ Args: |
+ A list of "ExtAttributes" in the "interface" object |
+ """ |
+ for extattribute in extattributes: |
+ out.write(' ') |
+ print_member_with_color(extattribute, out) |
+ out.writeln(extattribute['Name']) |
+ |
+ |
+def print_consts(consts, out): |
+ """Print consts in an "interface" object. |
+ Args: |
+ A list of "Consts" of the "interface" object |
+ """ |
+ for const in consts: |
+ out.write(' ') |
+ print_member_with_color(const, out) |
+ out.write(str(const['Type'])) |
+ out.write(' ') |
+ out.write(const['Name']) |
+ out.write(' ') |
+ out.writeln(const['Value']) |
+ |
+ |
+def print_items(items, callback, out): |
+ """Calls |callback| for each item in |items|, printing commas between |
+ |callback| calls. |
+ Args: |
+ items: extattributes or arguments |
+ """ |
+ count = 0 |
+ for item in items: |
+ callback(item) |
+ count += 1 |
+ if count < len(items): |
+ out.write(', ') |
+ |
+ |
+def print_extattributes_in_member(extattributes, out): |
+ """Print extattributes in a "member" object. |
+ Args: |
+ A list of "ExtAttributes" in the "member" object |
+ """ |
+ def callback(extattribute): |
+ out.write(extattribute['Name']) |
+ |
+ out.write('[') |
+ print_items(extattributes, callback, out) |
+ out.write(']') |
+ |
+ |
+def print_attributes(attributes, out): |
+ """Print attributes in an "interface" object. |
+ Args: |
+ A list of "Attributes" in the "interface" object |
+ """ |
+ for attribute in attributes: |
+ out.write(' ') |
+ print_member_with_color(attribute, out) |
+ if attribute['ExtAttributes']: |
+ print_extattributes_in_member(attribute['ExtAttributes'], out) |
+ out.write(str(attribute['Type'])) |
+ out.write(' ') |
+ out.writeln(attribute['Name']) |
+ |
+ |
+def print_arguments(arguments, out): |
+ """Print arguments in a "members" object named "Operations". |
+ Args: A list of "Arguments" |
+ """ |
+ def callback(argument): |
+ out.write(argument['Name']) |
+ |
+ out.write('(') |
+ print_items(arguments, callback, out) |
+ out.writeln(')') |
+ |
+ |
+def print_operations(operations, out): |
+ """Print operations in a "member" object. |
+ Args: |
+ A list of "Operations" |
+ """ |
+ for operation in operations: |
+ out.write(' ') |
+ print_member_with_color(operation, out) |
+ if operation['ExtAttributes']: |
+ print_extattributes_in_member(operation['ExtAttributes'], out) |
+ out.write(str(operation['Type'])) |
+ out.write(' ') |
+ if operation['Arguments']: |
+ out.write(operation['Name']) |
+ print_arguments(operation['Arguments'], out) |
+ else: |
+ out.writeln(operation['Name']) |
+ |
+ |
+def print_diff(diff, out): |
+ """Print the diff on a shell. |
+ Args: |
+ A sorted diff |
+ """ |
+ for interface_name, interface in diff.iteritems(): |
+ print_member_with_color(interface, out) |
+ out.change_color(Colorize.YELLOW) |
+ out.write('[[') |
+ out.write(interface_name) |
+ out.writeln(']]') |
+ out.reset_color() |
+ for member_name, member in interface.iteritems(): |
+ if member_name == 'ExtAttributes': |
+ out.writeln('ExtAttributes') |
+ print_extattributes(member, out) |
+ elif member_name == 'Consts': |
+ out.writeln(' Consts') |
+ print_consts(member, out) |
+ elif member_name == 'Attributes': |
+ out.writeln(' Attributes') |
+ print_attributes(member, out) |
+ elif member_name == 'Operations': |
+ out.writeln(' Operations') |
+ print_operations(member, out) |
+ out.reset_color() |
+ |
+ |
+def print_usage(): |
+ """Show usage.""" |
+ sys.stdout.write('Usage: print_diff.py <diff_file.json> <"TAG"|"ALPHABET">\n') |
+ |
+ |
+def main(argv): |
+ if len(argv) != 2: |
+ print_usage() |
+ exit(1) |
+ json_data = argv[0] |
+ order = argv[1] |
+ diff = load_json_file(json_data) |
+ if order == 'TAG': |
+ sort_func = sort_diff_by_tags |
+ elif order == 'ALPHABET': |
+ sort_func = sort_diff_in_alphabetical_order |
+ else: |
+ print_usage() |
+ exit(1) |
+ sorted_diff = sort_func(diff) |
+ out = Colorize(sys.stdout) |
+ print_diff(sorted_diff, out) |
+ |
+ |
+if __name__ == '__main__': |
+ main(sys.argv[1:]) |