Index: tools/roll_deps.py |
diff --git a/tools/roll_deps.py b/tools/roll_deps.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..10051cf9c95e3f845cd1e35ccbdc9a9b8e9b1f32 |
--- /dev/null |
+++ b/tools/roll_deps.py |
@@ -0,0 +1,184 @@ |
+#!/usr/bin/python |
+ |
+# Copyright 2014 Google Inc. |
+# |
+# 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.
|
+# found in the LICENSE file. |
+ |
+ |
+import optparse |
+import os |
+import random |
+import re |
+import subprocess |
+import shutil |
+import sys |
+import tempfile |
+ |
+ |
+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.
|
+ |
+ |
+def find_hash_from_revision(revision, search_depth): |
+ ''' |
jcgregorio
2014/01/03 16:46:20
"""Finds the hash associated with a revision.
Sea
hal.canary
2014/01/03 21:06:15
Done.
|
+ Searches through the last N commits to find out the hash that is |
+ associated with the revision number. |
+ ''' |
borenet
2014/01/03 18:15:48
Please update your docstrings to follow this forma
hal.canary
2014/01/03 21:06:15
Done.
|
+ 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
|
+ temp_dir = tempfile.mkdtemp(prefix='git_skia_tmp_') |
+ 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!
|
+ try: |
+ if 0 != subprocess.call([ |
+ GIT, 'clone', '--depth=%d' % search_depth, '--single-branch', |
+ SKIA_URL, temp_dir], stdout=devnull, stderr=devnull): |
+ 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.
|
+ for i in xrange(search_depth): |
+ commit = 'origin/master~%d' % i |
+ proc = subprocess.Popen([ |
+ GIT, 'log', '-n', '1', '--format=format:%B', commit], |
+ cwd=temp_dir, stdout=subprocess.PIPE, |
+ stderr=devnull) |
+ revision_format = 'http://skia.googlecode.com/svn/trunk@%d' |
+ revision_regex = re.compile(revision_format % revision) |
+ 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
|
+ if revision_regex.search(line) is not None: |
+ proc.stdout.close() |
+ return subprocess.check_output([ |
+ GIT, 'log', '-n', '1', '--format=format:%H', |
+ commit], cwd=temp_dir).strip() |
+ finally: |
+ shutil.rmtree(temp_dir) |
+ devnull.close() |
+ raise Exception('Failed to find revision.') |
+ |
+ |
+def checkout_master(): |
+ ''' |
+ Stashes current changes if necessary, checkout master, pulls from |
+ origin, and returns hash of current revision, plus arguments to be |
+ 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.
|
+ ''' |
+ # Assumes the current directory is a git repository and master is |
+ # tracking an upstream branch. |
+ stash = (0 != len(subprocess.check_output([GIT, 'diff', '--shortstat']))) |
+ if stash: |
+ 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
|
+ old_branch = subprocess.check_output([GIT, 'symbolic-ref', '--short', |
+ 'HEAD']).strip() |
borenet
2014/01/03 18:15:48
nit: indent
|
+ if old_branch != 'master': |
+ subprocess.check_call([GIT, 'checkout', 'master']) |
+ subprocess.check_call([GIT, 'pull']) |
+ master_hash = subprocess.check_output([GIT, 'show-ref', 'HEAD', '--hash']) |
+ 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.
|
+ |
+ |
+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.
|
+ (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)
|
+ if old_branch != 'master': |
+ subprocess.check_call([GIT, 'checkout', old_branch]) |
+ if stash: |
+ subprocess.check_call([GIT, 'stash', 'pop']) |
+ |
+ |
+def change_skia_deps(revision, hashval, depspath): |
+ temp_file = tempfile.NamedTemporaryFile(delete=False, |
+ prefix='skia_DEPS_ROLL_tmp_') |
borenet
2014/01/03 18:15:48
nit: indent
|
+ try: |
+ deps_regex_rev = re.compile('"skia_revision": "[0-9]*",') |
+ deps_regex_hash = re.compile('"skia_hash": "[0-9a-f]*",') |
+ |
+ deps_regex_rev_repl = '"skia_revision": "{}",'.format(revision) |
+ 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.
|
+ |
+ with open(depspath, 'r') as f: |
+ for line in f: |
+ line = deps_regex_rev.sub(deps_regex_rev_repl, line) |
+ line = deps_regex_hash.sub(deps_regex_hash_repl, line) |
+ temp_file.write(line) |
borenet
2014/01/03 18:15:48
Optional: You can entirely avoid using a temporary
|
+ finally: |
+ temp_file.close() |
+ shutil.move(temp_file.name, depspath) |
+ |
+ |
+def git_branch_add_commit_cl_upload(file_list, message): |
+ old_branch = subprocess.check_output([GIT, 'symbolic-ref', '--short', |
+ 'HEAD']).strip() |
borenet
2014/01/03 18:15:48
nit: indent
|
+ 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.
|
+ subprocess.check_call([GIT, 'checkout', '-b', branch_name]) |
+ args = [GIT, 'add'] |
+ 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
|
+ subprocess.check_call(args) |
+ subprocess.check_call([GIT, 'commit', '-m', message]) |
+ subprocess.check_call([GIT, 'cl', 'upload']) |
+ issue = subprocess.check_output([GIT, 'cl', 'issue']).strip() |
+ subprocess.check_call([GIT, 'checkout', old_branch]) |
+ subprocess.check_call([GIT, 'branch', '-D', branch_name]) |
+ return issue |
+ |
+ |
+def add_whitespace_change(file_name): |
+ with open(file_name, 'a') as o: |
+ o.write('\n') |
+ |
+ |
+def roll_deps(revision, hashval, chromium_dir): |
+ os.chdir(chromium_dir) |
+ |
+ master_hash, restore = checkout_master() |
+ message = 'roll skia DEPS to %d' % revision |
+ change_skia_deps(revision, hashval, 'DEPS') |
+ deps_issue = git_branch_add_commit_cl_upload(['DEPS'], message) |
+ |
+ message = 'whitespace change %s' % master_hash[:8] # Unique name |
+ add_whitespace_change('whitespace.txt') |
+ whitespace_issue = git_branch_add_commit_cl_upload(['whitespace.txt'], |
+ message) |
borenet
2014/01/03 18:15:48
nit: indent
|
+ restore_repository(restore) |
+ print '\n' |
+ print 'DEPS roll:\n %s\n' % deps_issue |
+ print 'Whitespace change:\n %s\n' % whitespace_issue |
+ |
+ |
+def find_hash_and_roll_deps(revision, chromium_dir, search_depth): |
+ hashval = find_hash_from_revision(revision, search_depth) |
+ if hashval is None: |
+ raise Exception('failed to find revision') |
+ |
+ print 'revision=@%d hash=%s\n' % (revision, hashval) |
+ |
+ roll_deps(revision, hashval, chromium_dir) |
+ |
+ |
+def main(args): |
+ usage = 'Usage: %prog -c CHROMIUM_PATH -r REVISION' |
+ |
+ # Anyone using this script on a regular basis should set this |
+ # environment variable. |
+ 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.
|
+ '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.
|
+ |
+ option_parser = optparse.OptionParser(usage=usage) |
+ option_parser.add_option( |
+ '-c', '--chromium_path', help='Path to Chromium Git repository.', |
+ default=chromium_repo_path_env) |
+ option_parser.add_option( |
+ '-r', '--revision', help='The Skia revision number', type="int") |
+ option_parser.add_option( |
+ '', '--search_depth', help='How far back to look for the revision', |
+ type="int", default=100) |
+ options = option_parser.parse_args(args)[0] |
+ |
+ if (not options.revision and not options.chromium_path): |
+ option_parser.error('Must specify revision and chromium_path.') |
+ if (not options.revision): |
+ option_parser.error('Must specify revision.') |
+ if (not options.chromium_path): |
+ option_parser.error('Must specify chromium_path.') |
+ |
+ find_hash_and_roll_deps(options.revision, options.chromium_path, |
+ options.search_depth) |
borenet
2014/01/03 18:15:48
nit: indent
hal.canary
2014/01/03 21:06:15
Done.
|
+ |
+ |
+if __name__ == '__main__': |
+ main(sys.argv[1:]) |
+ |