OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 # Copyright (c) 2014 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 | |
7 """Find and display recent changes in the given GM.""" | |
epoger
2014/04/01 17:39:02
Please paste your example run command line within
borenet
2014/04/01 18:11:38
Done.
| |
8 | |
9 | |
10 import argparse | |
11 import json | |
12 import os | |
13 import re | |
14 import subprocess | |
15 import sys | |
16 | |
17 | |
18 def _get_hash_and_last_change(gm_name, filepath): | |
19 """Find the current hash for the given GM and the last-changed revision. | |
20 | |
21 This function runs "svn blame", which is slow. | |
22 | |
23 Args: | |
24 gm_name: string; name of the GM in question. | |
25 filepath: string: path to the actual-results.json file. | |
epoger
2014/04/01 17:39:02
maybe semicolon after "string" just to be consiste
borenet
2014/04/01 18:11:38
Whoops. Done.
| |
26 Returns: | |
27 tuple of the form (last_changed_rev, hash), where last_changed_rev is an | |
28 int and hash is a string, or (None, None) if the file does not exist, the | |
29 GM is not found in the file, or some other problem occurs. | |
30 """ | |
31 if not os.path.isfile(filepath): | |
32 # If the file doesn't exist, we may have synced to before it was created. | |
33 return (None, None) | |
34 output = subprocess.check_output(['svn', 'blame', '--force', filepath]) | |
35 pattern = (r'^\s+\d+\s+.+\s+"%s.png" : {\s*\n\s+\d+\s+.+\s+"allowed-digests" ' | |
36 ': \[\s*\n\s+(\d+)\s+.+\s+\[ "bitmap-64bitMD5",\s+\n*(\d+)') | |
borenet
2014/04/01 13:49:57
This isn't quite right, since it will only find ch
epoger
2014/04/01 17:39:02
That's not a problem; see https://code.google.com/
borenet
2014/04/01 18:11:38
Agreed. I guess another way to do it would be to
| |
37 match = re.search(pattern % gm_name, output, re.MULTILINE) | |
38 if match: | |
39 try: | |
40 return (int(match.groups()[0]), match.groups()[1]) | |
41 except Exception: | |
42 # If there are any problems with the above (incorrect number of matches, | |
43 # inability to parse an integer), just return None. | |
44 return (None, None) | |
45 return (None, None) | |
46 | |
47 | |
48 def find_changes(builder_name, gm_name, autogen_path): | |
49 """Find and return recent changes in the given GM. | |
50 | |
51 This function runs "svn blame" and "svn update" numerous times and is | |
52 therefore very slow. | |
53 | |
54 Args: | |
55 builder_name: string; name of the builder. | |
56 gm_name: string; name of the GM. | |
57 autogen_path: string; path to skia-autogen checkout. | |
58 Yields: | |
59 tuples of the form: (autogen_revision, hash) | |
60 """ | |
61 actuals_path = os.path.join(autogen_path, builder_name, 'actual-results.json') | |
62 | |
63 # Capture the initial state of the skia-autogen checkout so that we can return | |
64 # to the same state later. | |
65 orig_rev = subprocess.check_output(['svnversion', '.'], | |
66 cwd=autogen_path).rstrip() | |
67 | |
68 try: | |
69 last_change_rev, hash = _get_hash_and_last_change(gm_name, actuals_path) | |
70 while last_change_rev: | |
71 yield (str(last_change_rev), hash) | |
72 # Sync to the revision just *before* the last change | |
73 subprocess.check_call(['svn', 'update', '-r', str(last_change_rev - 1)], | |
74 cwd=autogen_path, | |
75 stdout=subprocess.PIPE, | |
76 stderr=subprocess.PIPE) | |
77 last_change_rev, hash = _get_hash_and_last_change(gm_name, actuals_path) | |
78 finally: | |
79 # Return the repository to its initial state. | |
80 subprocess.check_call(['svn', 'update', '-r', orig_rev], | |
81 cwd=autogen_path, | |
82 stdout=subprocess.PIPE, | |
83 stderr=subprocess.PIPE) | |
84 | |
85 | |
86 def main(): | |
87 """Find and display recent changes in the given GM.""" | |
88 parser = argparse.ArgumentParser(description=sys.modules[__name__].__doc__) | |
89 parser.add_argument('builder_name', help='Name of the builder.') | |
90 parser.add_argument('gm_name', help='Name of the GM.') | |
91 parser.add_argument('--autogen-path', default=os.curdir, | |
92 help=('Path to a skia-autogen checkout. This checkout ' | |
93 'will be modified but the script will attempt to ' | |
94 'restore it to its original state. Default: ' | |
95 '"%(default)s"')) | |
96 args = parser.parse_args() | |
97 | |
98 print 'Rev\tHash' | |
99 for change in find_changes(args.builder_name, args.gm_name, | |
100 args.autogen_path): | |
101 print '\t'.join(change) | |
102 | |
103 | |
104 if __name__ == '__main__': | |
105 sys.exit(main()) | |
epoger
2014/04/01 17:39:02
Does this mean main() should return an int? Becau
borenet
2014/04/01 18:11:38
This is a convention I've seen in a number of plac
epoger
2014/04/01 18:18:55
I would buy that.
| |
OLD | NEW |