OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 | |
3 # Copyright 2014 Google Inc. | |
4 # | |
5 # Use of this source code is governed by a BSD-style license that can be | |
jcgregorio
2014/01/03 16:46:20
Needs a longer description of what this script doe
hal.canary
2014/01/03 21:06:15
Done.
| |
6 # found in the LICENSE file. | |
7 | |
8 | |
9 import optparse | |
10 import os | |
11 import random | |
12 import re | |
13 import subprocess | |
14 import shutil | |
15 import sys | |
16 import tempfile | |
17 | |
18 | |
19 GIT = 'git' # Assume git is in your path. Change this otherwise. | |
borenet
2014/01/03 18:15:48
On the bots (and anywhere with depot_tools in the
hal.canary
2014/01/03 21:06:15
I've made it an option.
| |
20 | |
21 | |
22 def find_hash_from_revision(revision, search_depth): | |
23 ''' | |
jcgregorio
2014/01/03 16:46:20
"""Finds the hash associated with a revision.
Sea
hal.canary
2014/01/03 21:06:15
Done.
| |
24 Searches through the last N commits to find out the hash that is | |
25 associated with the revision number. | |
26 ''' | |
borenet
2014/01/03 18:15:48
Please update your docstrings to follow this forma
hal.canary
2014/01/03 21:06:15
Done.
| |
27 SKIA_URL = 'https://skia.googlesource.com/skia.git' | |
borenet
2014/01/03 18:15:48
This can go outside, at the module level. There's
hal.canary
2014/01/03 23:58:48
Let's figure out our use-case for modifying the ur
| |
28 temp_dir = tempfile.mkdtemp(prefix='git_skia_tmp_') | |
29 devnull = open(os.devnull, "w") | |
borenet
2014/01/03 18:15:48
Is this just to avoid seeing output from the subpr
hal.canary
2014/01/03 21:06:15
That's why they introduced subprocess.DEVNULL!
| |
30 try: | |
31 if 0 != subprocess.call([ | |
32 GIT, 'clone', '--depth=%d' % search_depth, '--single-branch', | |
33 SKIA_URL, temp_dir], stdout=devnull, stderr=devnull): | |
34 raise Exception("Failed to grab a copy of Skia.") | |
borenet
2014/01/03 18:15:48
Why not use subprocess.check_call, which will rais
hal.canary
2014/01/03 21:06:15
Done.
| |
35 for i in xrange(search_depth): | |
36 commit = 'origin/master~%d' % i | |
37 proc = subprocess.Popen([ | |
38 GIT, 'log', '-n', '1', '--format=format:%B', commit], | |
39 cwd=temp_dir, stdout=subprocess.PIPE, | |
40 stderr=devnull) | |
41 revision_format = 'http://skia.googlecode.com/svn/trunk@%d' | |
42 revision_regex = re.compile(revision_format % revision) | |
43 for line in proc.stdout: | |
borenet
2014/01/03 18:15:48
I think it's a good idea to use proc.wait() before
hal.canary
2014/01/03 21:06:15
In theory,the output could be very long, but in pr
| |
44 if revision_regex.search(line) is not None: | |
45 proc.stdout.close() | |
46 return subprocess.check_output([ | |
47 GIT, 'log', '-n', '1', '--format=format:%H', | |
48 commit], cwd=temp_dir).strip() | |
49 finally: | |
50 shutil.rmtree(temp_dir) | |
51 devnull.close() | |
52 raise Exception('Failed to find revision.') | |
53 | |
54 | |
55 def checkout_master(): | |
56 ''' | |
57 Stashes current changes if necessary, checkout master, pulls from | |
58 origin, and returns hash of current revision, plus arguments to be | |
59 passed to restore_repository to reture to original state. | |
borenet
2014/01/03 18:15:48
sp: "return"?
hal.canary
2014/01/03 21:06:15
Done.
| |
60 ''' | |
61 # Assumes the current directory is a git repository and master is | |
62 # tracking an upstream branch. | |
63 stash = (0 != len(subprocess.check_output([GIT, 'diff', '--shortstat']))) | |
64 if stash: | |
65 subprocess.check_call([GIT, 'stash', 'save']) | |
borenet
2014/01/03 18:15:48
Since this is (mostly) going to be run by bots, I
hal.canary
2014/01/03 21:06:15
This may be run by anyone who wants to force a DEP
| |
66 old_branch = subprocess.check_output([GIT, 'symbolic-ref', '--short', | |
67 'HEAD']).strip() | |
borenet
2014/01/03 18:15:48
nit: indent
| |
68 if old_branch != 'master': | |
69 subprocess.check_call([GIT, 'checkout', 'master']) | |
70 subprocess.check_call([GIT, 'pull']) | |
71 master_hash = subprocess.check_output([GIT, 'show-ref', 'HEAD', '--hash']) | |
72 return master_hash.strip(), (old_branch, stash) | |
borenet
2014/01/03 18:15:48
I think it's a little confusing to return a tuple
hal.canary
2014/01/03 21:06:15
I've refactored.
| |
73 | |
74 | |
75 def restore_repository(restore): | |
borenet
2014/01/03 18:15:48
Please add docstrings for this and the other funct
hal.canary
2014/01/03 21:06:15
Done.
| |
76 (old_branch, stash) = restore | |
borenet
2014/01/03 18:15:48
Why not take old_branch and stash as parameters to
hal.canary
2014/01/03 23:58:48
(refactored away)
| |
77 if old_branch != 'master': | |
78 subprocess.check_call([GIT, 'checkout', old_branch]) | |
79 if stash: | |
80 subprocess.check_call([GIT, 'stash', 'pop']) | |
81 | |
82 | |
83 def change_skia_deps(revision, hashval, depspath): | |
84 temp_file = tempfile.NamedTemporaryFile(delete=False, | |
85 prefix='skia_DEPS_ROLL_tmp_') | |
borenet
2014/01/03 18:15:48
nit: indent
| |
86 try: | |
87 deps_regex_rev = re.compile('"skia_revision": "[0-9]*",') | |
88 deps_regex_hash = re.compile('"skia_hash": "[0-9a-f]*",') | |
89 | |
90 deps_regex_rev_repl = '"skia_revision": "{}",'.format(revision) | |
91 deps_regex_hash_repl = '"skia_hash": "{}",'.format(hashval) | |
borenet
2014/01/03 18:15:48
Same comment about the format strings as before...
hal.canary
2014/01/03 21:06:15
I missed those. Done.
| |
92 | |
93 with open(depspath, 'r') as f: | |
94 for line in f: | |
95 line = deps_regex_rev.sub(deps_regex_rev_repl, line) | |
96 line = deps_regex_hash.sub(deps_regex_hash_repl, line) | |
97 temp_file.write(line) | |
borenet
2014/01/03 18:15:48
Optional: You can entirely avoid using a temporary
| |
98 finally: | |
99 temp_file.close() | |
100 shutil.move(temp_file.name, depspath) | |
101 | |
102 | |
103 def git_branch_add_commit_cl_upload(file_list, message): | |
104 old_branch = subprocess.check_output([GIT, 'symbolic-ref', '--short', | |
105 'HEAD']).strip() | |
borenet
2014/01/03 18:15:48
nit: indent
| |
106 branch_name = 'tmp_%d' % random.randrange(1<<16) | |
borenet
2014/01/03 18:15:48
A timestamp would work well here. Alternatively,
hal.canary
2014/01/03 21:06:15
Done.
| |
107 subprocess.check_call([GIT, 'checkout', '-b', branch_name]) | |
108 args = [GIT, 'add'] | |
109 args.extend(file_list) | |
borenet
2014/01/03 18:15:48
Since we're on a clean branch, it's probably okay
hal.canary
2014/01/03 21:06:15
Done.
hal.canary
2014/01/03 23:58:48
Well, that broke the git submodules in some weird
| |
110 subprocess.check_call(args) | |
111 subprocess.check_call([GIT, 'commit', '-m', message]) | |
112 subprocess.check_call([GIT, 'cl', 'upload']) | |
113 issue = subprocess.check_output([GIT, 'cl', 'issue']).strip() | |
114 subprocess.check_call([GIT, 'checkout', old_branch]) | |
115 subprocess.check_call([GIT, 'branch', '-D', branch_name]) | |
116 return issue | |
117 | |
118 | |
119 def add_whitespace_change(file_name): | |
120 with open(file_name, 'a') as o: | |
121 o.write('\n') | |
122 | |
123 | |
124 def roll_deps(revision, hashval, chromium_dir): | |
125 os.chdir(chromium_dir) | |
126 | |
127 master_hash, restore = checkout_master() | |
128 message = 'roll skia DEPS to %d' % revision | |
129 change_skia_deps(revision, hashval, 'DEPS') | |
130 deps_issue = git_branch_add_commit_cl_upload(['DEPS'], message) | |
131 | |
132 message = 'whitespace change %s' % master_hash[:8] # Unique name | |
133 add_whitespace_change('whitespace.txt') | |
134 whitespace_issue = git_branch_add_commit_cl_upload(['whitespace.txt'], | |
135 message) | |
borenet
2014/01/03 18:15:48
nit: indent
| |
136 restore_repository(restore) | |
137 print '\n' | |
138 print 'DEPS roll:\n %s\n' % deps_issue | |
139 print 'Whitespace change:\n %s\n' % whitespace_issue | |
140 | |
141 | |
142 def find_hash_and_roll_deps(revision, chromium_dir, search_depth): | |
143 hashval = find_hash_from_revision(revision, search_depth) | |
144 if hashval is None: | |
145 raise Exception('failed to find revision') | |
146 | |
147 print 'revision=@%d hash=%s\n' % (revision, hashval) | |
148 | |
149 roll_deps(revision, hashval, chromium_dir) | |
150 | |
151 | |
152 def main(args): | |
153 usage = 'Usage: %prog -c CHROMIUM_PATH -r REVISION' | |
154 | |
155 # Anyone using this script on a regular basis should set this | |
156 # environment variable. | |
157 chromium_repo_path_env = os.environ['CHROMIUM_REPO_PATH'] if ( | |
jcgregorio
2014/01/03 16:46:20
Use:
chromium_repo_path_env = os.environ.get('C
hal.canary
2014/01/03 21:06:15
Done.
| |
158 'CHROMIUM_REPO_PATH' in os.environ) else None | |
borenet
2014/01/03 18:15:48
Python supports defaults in dict retrieval:
chromi
hal.canary
2014/01/03 21:06:15
Done.
| |
159 | |
160 option_parser = optparse.OptionParser(usage=usage) | |
161 option_parser.add_option( | |
162 '-c', '--chromium_path', help='Path to Chromium Git repository.', | |
163 default=chromium_repo_path_env) | |
164 option_parser.add_option( | |
165 '-r', '--revision', help='The Skia revision number', type="int") | |
166 option_parser.add_option( | |
167 '', '--search_depth', help='How far back to look for the revision', | |
168 type="int", default=100) | |
169 options = option_parser.parse_args(args)[0] | |
170 | |
171 if (not options.revision and not options.chromium_path): | |
172 option_parser.error('Must specify revision and chromium_path.') | |
173 if (not options.revision): | |
174 option_parser.error('Must specify revision.') | |
175 if (not options.chromium_path): | |
176 option_parser.error('Must specify chromium_path.') | |
177 | |
178 find_hash_and_roll_deps(options.revision, options.chromium_path, | |
179 options.search_depth) | |
borenet
2014/01/03 18:15:48
nit: indent
hal.canary
2014/01/03 21:06:15
Done.
| |
180 | |
181 | |
182 if __name__ == '__main__': | |
183 main(sys.argv[1:]) | |
184 | |
OLD | NEW |