blob: 71934c29ab11f09ba4b51f6db6f1cb405230e339 [file] [log] [blame]
#!/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 sys
from webkitpy.bindings.generate_idl_diff import load_json_file
from webkitpy.bindings.generate_idl_diff import EXTATTRIBUTES_AND_MEMBER_TYPES
from webkitpy.bindings.generate_idl_diff import DIFF_TAG
from webkitpy.bindings.generate_idl_diff import DIFF_TAG_ADDED
from webkitpy.bindings.generate_idl_diff import DIFF_TAG_DELETED
# pylint: disable=W0105
"""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)
# pylint: disable=W0110
removed = map(lambda interface: interface['Name'], removed)
# pylint: disable=W0110
added = map(lambda interface: interface['Name'], added)
# pylint: disable=W0110
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:])