Chromium Code Reviews| 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 |