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 idl data of the diff in alphabetical order or by | |
8 diffing tags. | |
9 Usage: print_idl_diff.py diff_file.json order | |
10 diff.json: | |
11 Output of generate_idl_diff.py. A json file consists of a dictionary | |
12 expressing a diff between two defferent Chrome versions.The structure | |
13 of the dictionary is like below. | |
14 order: | |
15 Specify how to sort. Either by using diffing tags or in alphabetical ord er. | |
bashi
2015/09/25 06:40:58
nit: wrap line after 'alphabetical'.
shimadaa
2015/09/25 07:02:33
Done.
| |
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 input structure of generate_idl_diff.py and | |
31 that of print_diff.py is whether diffing tags are included or not. | |
32 The diffing tags are included in a parts that have a diff. | |
33 {'Interface': { | |
34 'diff_tag': 'deleted' | |
35 'ExtAttributes': [{'Name': '...' | |
36 'diff_tag': 'deleted'}, | |
37 ..., | |
38 ], | |
39 'Consts': [{'Type': '...', | |
40 'Name': '...', | |
41 'Value': '...' | |
42 'diff_tag': 'deleted'}, | |
43 ..., | |
44 ], | |
45 'Attributes': [{'Type': '...', | |
46 'Name': '...', | |
47 'ExtAttributes':[{'Name': '...'}, | |
48 ..., | |
49 ] | |
50 'diff_tag': 'deleted'}, | |
51 ..., | |
52 ], | |
53 'Operations': [{'Type': '...', | |
54 'Name': '...', | |
55 'ExtAttributes':[{'Name': '...'}, | |
56 ..., | |
57 ], | |
58 'Arguments': [{'Type': '...', | |
59 'Name': '...'}, | |
60 ..., | |
61 ] | |
62 'diff_tag': 'deleted'}, | |
63 ..., | |
64 ] | |
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 }, | |
96 ..., | |
97 } | |
98 """ | |
99 | |
100 | |
101 class Colorize(object): | |
102 """This class decorates text with colors and outputs it to sys.stdout. | |
103 TODO(shimadaa): This class doesn't work on Windows. Provides a way to suppre ss escape sequences. | |
bashi
2015/09/25 06:40:58
nit: wrap line after 'a way to'
shimadaa
2015/09/25 07:02:32
Done.
| |
104 """ | |
105 | |
106 BLACK = 30 | |
107 RED = 31 | |
108 GREEN = 32 | |
109 YELLOW = 33 | |
110 COLORS = (BLACK, RED, GREEN, YELLOW) | |
111 | |
112 def __init__(self, out): | |
113 self.out = out | |
114 | |
115 def reset_color(self): | |
116 """Reset text's color to default and output it to sys.stdout. | |
bashi
2015/09/25 06:40:58
nit: remove 'and output it to sys.stdout'.
shimadaa
2015/09/25 07:02:33
Done.
| |
117 """ | |
118 self.out.write('\033[0m') | |
119 | |
120 def change_color(self, color): | |
121 """Change text's color by specifing arguments and output it to sys.stdou t. | |
bashi
2015/09/25 06:40:58
nit: remove 'and output it to sys.stdout'.
shimadaa
2015/09/25 07:02:33
Done.
| |
122 Args: | |
123 color: A value that represents text's color. Mapping colors into values is below. | |
bashi
2015/09/25 06:40:58
how about:
color: A color to change. It should be
shimadaa
2015/09/25 07:02:32
Done.
| |
124 """ | |
125 if color in self.COLORS: | |
126 self.out.write('\033[' + str(color) + 'm') | |
127 else: | |
128 raise Exception('Unsupported color.') | |
129 | |
130 def writeln(self, string): | |
131 """Print text to use for line breaks. | |
132 """ | |
133 self.out.write(string + '\n') | |
134 | |
135 def write(self, string): | |
136 """Print text not to use for line breaks. | |
137 """ | |
138 self.out.write(string) | |
139 | |
140 | |
141 def sort_member_types(interface): | |
142 """Sort the members in the order of EXTATTRIBUTES_AND_MEMBER_TYPES. | |
143 Args: | |
144 interface: An "interface" object | |
145 Returns: | |
146 A sorted "interface" object | |
147 """ | |
148 sorted_interface = OrderedDict() | |
149 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: | |
150 sorted_interface[member_type] = interface.get(member_type) | |
151 sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) | |
152 return sorted_interface | |
153 | |
154 | |
155 def group_by_tag(interface_or_member_list): | |
156 """Group members of a given argument (an interface or a list of members) by tags. | |
bashi
2015/09/25 06:40:58
nit: wrap line after 'by'
shimadaa
2015/09/25 07:02:33
Done.
| |
157 Args: | |
158 interface_or_member_list: Interface name's list or "members" object's li st. | |
bashi
2015/09/25 06:40:58
nit: wrap line after "object's"
shimadaa
2015/09/25 07:02:33
Done.
| |
159 Returns: | |
160 removed: A list that consists of removed ones. | |
161 added: A list that consists of added ones. | |
162 unspecified: A list that consists of neither removed ones nor added ones . | |
bashi
2015/09/25 06:40:58
nit: wrap line after 'added'
shimadaa
2015/09/25 07:02:32
Done.
| |
163 """ | |
164 removed = [] | |
165 added = [] | |
166 unspecified = [] | |
167 for interface_or_member in interface_or_member_list: | |
168 if DIFF_TAG in interface_or_member: | |
169 if interface_or_member[DIFF_TAG] == DIFF_TAG_DELETED: | |
170 removed.append(interface_or_member) | |
171 elif interface_or_member[DIFF_TAG] == DIFF_TAG_ADDED: | |
172 added.append(interface_or_member) | |
173 else: | |
174 unspecified.append(interface_or_member) | |
175 return (removed, added, unspecified) | |
176 | |
177 | |
178 def sort_interface_names_by_tags(interfaces): | |
179 """Sort the order of interface names like below. | |
180 [a interface name of "interface" deleted whole | |
181 -> a interface name of "interface" added whole | |
182 -> a interface name of "interface" changed part] | |
183 Args: | |
184 interfaces: An "interface" objects. | |
185 Returns: | |
186 A list consists of interface names sorted | |
187 """ | |
188 interface_list = interfaces.values() | |
189 removed, added, unspecified = group_by_tag(interface_list) | |
190 removed = map(lambda interface: interface['Name'], removed) | |
191 added = map(lambda interface: interface['Name'], added) | |
192 unspecified = map(lambda interface: interface['Name'], unspecified) | |
193 sorted_interface_name = removed + added + unspecified | |
194 return (sorted_interface_name) | |
bashi
2015/09/25 06:40:58
nit: remove paresis.
shimadaa
2015/09/25 07:02:33
Done.
| |
195 | |
196 | |
197 def sort_members_by_tags(interface): | |
198 """Sort a "members" object by using diff_tag. | |
199 Args: | |
200 An "interface" object | |
201 Returns: | |
202 A sorted "interface" object | |
203 """ | |
204 sorted_interface = OrderedDict() | |
205 if DIFF_TAG in interface: | |
206 return interface | |
207 else: | |
bashi
2015/09/25 06:40:58
nit: You can remmove else clause.
if DIFF_TAG in
shimadaa
2015/09/25 07:02:33
Done.
| |
208 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: | |
209 member_list = interface[member_type] | |
210 removed, added, unspecified = group_by_tag(member_list) | |
211 sorted_interface[member_type] = removed + added + unspecified | |
212 return sorted_interface | |
213 | |
214 | |
215 def sort_diff_by_tags(interfaces): | |
216 """Sort an "interfaces" object expressing a diff by using diff_tag. | |
217 Args: | |
218 An "interfaces" object loaded by load_json_data(). | |
219 Returns: | |
220 A sorted "interfaces" object | |
221 """ | |
222 sorted_interfaces = OrderedDict() | |
223 sorted_interface_names = sort_interface_names_by_tags(interfaces) | |
224 for interface_name in sorted_interface_names: | |
225 interface = sort_members_by_tags(interfaces[interface_name]) | |
226 sorted_interfaces[interface_name] = sort_member_types(interface) | |
227 return sorted_interfaces | |
228 | |
229 | |
230 def sort_members_in_alphabetical_order(interface): | |
231 """Sort a "members" object in alphabetical order. | |
232 Args: | |
233 An "interface" object | |
234 Returns: | |
235 A sorted "interface" object | |
236 """ | |
237 sorted_interface = OrderedDict() | |
238 for member_type in EXTATTRIBUTES_AND_MEMBER_TYPES: | |
239 sorted_members = sorted(interface[member_type], key=lambda member: membe r['Name']) | |
bashi
2015/09/25 06:40:58
nit: wrap line after ','
shimadaa
2015/09/25 07:02:33
Done.
| |
240 sorted_interface[member_type] = sorted_members | |
241 return sorted_interface | |
242 | |
243 | |
244 def sort_diff_in_alphabetical_order(interfaces): | |
245 """Sort diff in alphabetical order. | |
246 Args: | |
247 An "interfaces" object. | |
248 Returns: | |
249 A sorted "interfaces" object in alphabetical order | |
250 """ | |
251 sorted_interfaces = OrderedDict() | |
252 for interface_name in sorted(interfaces.keys()): | |
253 interface = interfaces[interface_name] | |
254 sorted_interface = sort_members_in_alphabetical_order(interface) | |
255 sorted_interface[DIFF_TAG] = interface.get(DIFF_TAG) | |
256 sorted_interfaces[interface_name] = sorted_interface | |
257 return sorted_interfaces | |
258 | |
259 | |
260 def change_color_based_on_tag(member, out): | |
261 """Change color based on diff_tag and output prefix ('+' or '-') if |member| is added/deleted. | |
bashi
2015/09/25 06:40:58
nit: wrap line after |member|
shimadaa
2015/09/25 07:02:33
Done.
| |
262 Args: | |
263 member: A "member" object | |
264 """ | |
265 if DIFF_TAG in member: | |
266 if member[DIFF_TAG] == DIFF_TAG_DELETED: | |
267 out.change_color(Colorize.RED) | |
268 out.write('- ') | |
269 elif member[DIFF_TAG] == DIFF_TAG_ADDED: | |
270 out.change_color(Colorize.GREEN) | |
271 out.write('+ ') | |
272 else: | |
273 out.change_color(Colorize.BLACK) | |
274 out.write(' ') | |
275 | |
276 | |
277 def print_extattributes(extattributes, out): | |
278 """Print extattributes in an "interface" object. | |
279 Args: | |
280 A list included as a value of "member" object named "ExtAttributes" | |
281 """ | |
282 for extattribute in extattributes: | |
283 out.write(' ') | |
284 change_color_based_on_tag(extattribute, out) | |
285 out.writeln(extattribute['Name']) | |
286 | |
287 | |
288 def print_consts(consts, out): | |
289 """Print consts in an "interface" object. | |
290 Args: | |
291 A list included as a value of "member" object named "Consts" | |
292 """ | |
293 for const in consts: | |
294 out.write(' ') | |
295 change_color_based_on_tag(const, out) | |
296 out.write(const['Type']) | |
297 out.write(' ') | |
298 out.write(const['Name']) | |
299 out.write(' ') | |
300 out.writeln(const['Value']) | |
301 | |
302 | |
303 def print_items(items, callback, out): | |
bashi
2015/09/25 06:40:58
nit: Please add a comment to describe what this fu
shimadaa
2015/09/25 07:02:33
Done.
| |
304 count = 0 | |
305 for item in items: | |
306 callback(item) | |
307 count += 1 | |
308 if count < len(items): | |
309 out.write(', ') | |
310 | |
311 | |
312 def print_extattributes_of_member(extattributes, out): | |
313 """Print extattributes in a "member" object. | |
314 Args: | |
315 A list included as a value of "ExtAttributes" of "member" object | |
316 """ | |
317 def callback(extattribute): | |
318 out.write(extattribute['Name']) | |
319 | |
320 out.write('[') | |
321 print_items(extattributes, callback, out) | |
322 out.write(']') | |
323 | |
324 | |
325 def print_attributes(attributes, out): | |
326 """Print attributes in an "interface" object. | |
327 Args: | |
328 A list included as a value of "member" object named "Attributes" | |
329 """ | |
330 for attribute in attributes: | |
331 out.write(' ') | |
332 change_color_based_on_tag(attribute, out) | |
333 if attribute['ExtAttributes']: | |
334 print_extattributes_of_member(attribute['ExtAttributes'], out) | |
335 out.write(attribute['Type']) | |
336 out.write(' ') | |
337 out.writeln(attribute['Name']) | |
338 | |
339 | |
340 def print_arguments(arguments, out): | |
341 """Print arguments in a "members" object named "Operations". | |
342 Args: A list included as a value of "Arguments" of "member" object named | |
343 "Operations" | |
344 """ | |
345 def callback(argument): | |
346 out.write(argument['Name']) | |
347 | |
348 out.write('(') | |
349 print_items(arguments, callback, out) | |
350 out.writeln(')') | |
351 | |
352 | |
353 def print_operations(operations, out): | |
354 """Print operations in a "member" object. | |
355 Args: | |
356 A list included as a value of "member" object named "Operations" | |
357 """ | |
358 for operation in operations: | |
359 out.write(' ') | |
360 change_color_based_on_tag(operation, out) | |
361 if operation['ExtAttributes']: | |
362 print_extattributes_of_member(operation['ExtAttributes'], out) | |
363 out.write(operation['Type']) | |
364 out.write(' ') | |
365 if operation['Arguments']: | |
366 out.write(operation['Name']) | |
367 print_arguments(operation['Arguments'], out) | |
368 else: | |
369 out.writeln(operation['Name']) | |
370 | |
371 | |
372 def print_diff(diff, out): | |
373 """Print the diff on a shell. | |
374 Args: | |
375 A sorted diff | |
376 """ | |
377 for interface_name, interface in diff.iteritems(): | |
378 change_color_based_on_tag(interface, out) | |
379 out.change_color(Colorize.YELLOW) | |
380 out.write('[[') | |
381 out.write(interface_name) | |
382 out.writeln(']]') | |
383 out.reset_color() | |
384 for member_name, member in interface.iteritems(): | |
385 if member_name == 'ExtAttributes': | |
386 out.writeln('ExtAttributes') | |
387 print_extattributes(member, out) | |
388 elif member_name == 'Consts': | |
389 out.writeln(' Consts') | |
390 print_consts(member, out) | |
391 elif member_name == 'Attributes': | |
392 out.writeln(' Attributes') | |
393 print_attributes(member, out) | |
394 elif member_name == 'Operations': | |
395 out.writeln(' Operations') | |
396 print_operations(member, out) | |
397 out.reset_color() | |
398 | |
399 | |
400 def usage(): | |
bashi
2015/09/25 06:40:58
nit: Add a comment.
"""Show usage."""
shimadaa
2015/09/25 07:02:33
Done.
| |
401 sys.stdout.write('Usage: print_diff.py <diff_file.json> <TAG>/<ALPHABET>\n') | |
402 | |
403 | |
404 def main(argv): | |
405 if len(argv) != 2: | |
406 usage() | |
407 exit(1) | |
408 json_data = argv[0] | |
409 order = argv[1] | |
410 diff = load_json_file(json_data) | |
411 if order == 'TAG': | |
412 sort_func = sort_diff_by_tags | |
413 elif order == 'ALPHABET': | |
414 sort_func = sort_diff_in_alphabetical_order | |
415 else: | |
416 usage() | |
417 exit(1) | |
418 sorted_diff = sort_func(diff) | |
419 out = Colorize(sys.stdout) | |
420 print_diff(sorted_diff, out) | |
421 | |
422 | |
423 if __name__ == '__main__': | |
424 main(sys.argv[1:]) | |
OLD | NEW |