Chromium Code Reviews| Index: tools/roll_deps.py |
| diff --git a/tools/roll_deps.py b/tools/roll_deps.py |
| index 42b917415c6bca83c3ff628f2916c52bd9d8ce62..d1970b0f5c3ac7b40f6e932ca0239543589b0453 100755 |
| --- a/tools/roll_deps.py |
| +++ b/tools/roll_deps.py |
| @@ -26,7 +26,6 @@ import os |
| import re |
| import shutil |
| import subprocess |
| -from subprocess import check_call |
| import sys |
| import tempfile |
| @@ -55,7 +54,8 @@ class DepsRollConfig(object): |
| options = DepsRollConfig.GetOptionParser() |
| # pylint: disable=I0011,E1103 |
| self.verbose = options.verbose |
| - self.save_branches = options.save_branches |
| + self.vsp = VerboseSubprocess(self.verbose) |
|
borenet
2014/01/08 19:20:21
This could be named something more descriptive; ev
hal.canary
2014/01/08 19:59:35
That sounds like a terrible namespace collision.
borenet
2014/01/08 20:06:17
Not if you're using it with self.subprocess.* or c
|
| + self.save_branches = not options.delete_branches |
| self.search_depth = options.search_depth |
| self.chromium_path = options.chromium_path |
| self.git = options.git_path |
| @@ -110,6 +110,10 @@ class DepsRollConfig(object): |
| option_parser.add_option( |
| '-r', '--revision', type='int', default=None, |
| help='The Skia SVN revision number, defaults to top of tree.') |
| + option_parser.add_option( |
| + '-g', '--git_hash', default=None, |
| + help='A partial Skia Git hash. If set, overrides "--revision".') |
| + |
| # Anyone using this script on a regular basis should set the |
| # SKIA_GIT_CHECKOUT_PATH environment variable. |
| option_parser.add_option( |
| @@ -125,8 +129,8 @@ class DepsRollConfig(object): |
| '', '--git_path', help='Git executable, defaults to "git".', |
| default='git') |
| option_parser.add_option( |
| - '', '--save_branches', help='Save the temporary branches', |
| - action='store_true', dest='save_branches', default=False) |
| + '', '--delete_branches', help='Delete the temporary branches', |
| + action='store_true', dest='delete_branches', default=False) |
| option_parser.add_option( |
| '', '--verbose', help='Do not suppress the output from `git cl`.', |
| action='store_true', dest='verbose', default=False) |
| @@ -167,23 +171,124 @@ class DepsRollError(Exception): |
| pass |
| -def strip_output(*args, **kwargs): |
| - """Wrap subprocess.check_output and str.strip(). |
| +class VerboseSubprocess(object): |
| + """Call subprocess methods, but print out command before executing. |
| - Pass the given arguments into subprocess.check_output() and return |
| - the results, after stripping any excess whitespace. |
| + Attributes: |
| + verbose: (boolean) should we print out the command or not. If |
| + not, this is the same as calling the subprocess method |
| + quiet: (boolean) suppress stdout on check_call and call. |
| + prefix: (string) When verbose, what to print before each command. |
| + """ |
| - Args: |
| - *args: to be passed to subprocess.check_output() |
| - **kwargs: to be passed to subprocess.check_output() |
| + def __init__(self, verbose): |
| + self.verbose = verbose |
| + self.quiet = not verbose |
| + self.prefix = '~~$ ' |
| - Returns: |
| - The output of the process as a string without leading or |
| - trailing whitespace. |
| - Raises: |
| - OSError or subprocess.CalledProcessError: raised by check_output. |
| - """ |
| - return str(subprocess.check_output(*args, **kwargs)).strip() |
| + @staticmethod |
| + def _fix(string): |
| + """Quote and escape a string if necessary.""" |
| + if ' ' in string or '\n' in string: |
| + string = '"%s"' % string.replace('\n', '\\n') |
| + return string |
| + |
| + @staticmethod |
| + def print_subprocess_args(prefix, *args, **kwargs): |
| + """Print out args in a human-readable manner.""" |
| + if 'cwd' in kwargs: |
| + print '%scd %s' % (prefix, kwargs['cwd']) |
| + print prefix + ' '.join(VerboseSubprocess._fix(arg) for arg in args[0]) |
| + if 'cwd' in kwargs: |
| + print '%scd -' % prefix |
| + |
| + def check_call(self, *args, **kwargs): |
| + """Wrapper for subprocess.check_call(). |
| + |
| + Args: |
| + *args: to be passed to subprocess.check_call() |
| + **kwargs: to be passed to subprocess.check_call() |
| + Returns: |
| + Whatever subprocess.check_call() returns. |
| + Raises: |
| + OSError or subprocess.CalledProcessError: raised by check_call. |
| + """ |
| + if self.verbose: |
| + self.print_subprocess_args(self.prefix, *args, **kwargs) |
| + if self.quiet: |
| + with open(os.devnull, 'w') as devnull: |
| + return subprocess.check_call(*args, stdout=devnull, **kwargs) |
| + else: |
| + return subprocess.check_call(*args, **kwargs) |
| + |
| + def call(self, *args, **kwargs): |
| + """Wrapper for subprocess.check(). |
| + |
| + Args: |
| + *args: to be passed to subprocess.check_call() |
| + **kwargs: to be passed to subprocess.check_call() |
| + Returns: |
| + Whatever subprocess.call() returns. |
| + Raises: |
| + OSError or subprocess.CalledProcessError: raised by call. |
| + """ |
| + if self.verbose: |
| + self.print_subprocess_args(self.prefix, *args, **kwargs) |
| + if self.quiet: |
| + with open(os.devnull, 'w') as devnull: |
| + return subprocess.call(*args, stdout=devnull, **kwargs) |
| + else: |
| + return subprocess.call(*args, **kwargs) |
| + |
| + def check_output(self, *args, **kwargs): |
| + """Wrapper for subprocess.check_output(). |
| + |
| + Args: |
| + *args: to be passed to subprocess.check_output() |
| + **kwargs: to be passed to subprocess.check_output() |
| + Returns: |
| + Whatever subprocess.check_output() returns. |
| + Raises: |
| + OSError or subprocess.CalledProcessError: raised by check_output. |
| + """ |
| + if self.verbose: |
| + self.print_subprocess_args(self.prefix, *args, **kwargs) |
| + return subprocess.check_output(*args, **kwargs) |
| + |
| + def strip_output(self, *args, **kwargs): |
| + """Wrap subprocess.check_output and str.strip(). |
| + |
| + Pass the given arguments into subprocess.check_output() and return |
| + the results, after stripping any excess whitespace. |
| + |
| + Args: |
| + *args: to be passed to subprocess.check_output() |
| + **kwargs: to be passed to subprocess.check_output() |
| + |
| + Returns: |
| + The output of the process as a string without leading or |
| + trailing whitespace. |
| + Raises: |
| + OSError or subprocess.CalledProcessError: raised by check_output. |
| + """ |
| + if self.verbose: |
| + self.print_subprocess_args(self.prefix, *args, **kwargs) |
| + return str(subprocess.check_output(*args, **kwargs)).strip() |
| + |
| + def popen(self, *args, **kwargs): |
| + """Wrapper for subprocess.Popen(). |
| + |
| + Args: |
| + *args: to be passed to subprocess.Popen() |
| + **kwargs: to be passed to subprocess.Popen() |
| + Returns: |
| + The output of subprocess.Popen() |
| + Raises: |
| + OSError or subprocess.CalledProcessError: raised by Popen. |
| + """ |
| + if self.verbose: |
| + self.print_subprocess_args(self.prefix, *args, **kwargs) |
| + return subprocess.Popen(*args, **kwargs) |
| def create_temp_skia_clone(config, depth): |
| @@ -200,7 +305,7 @@ def create_temp_skia_clone(config, depth): |
| git = config.git |
| skia_dir = tempfile.mkdtemp(prefix='git_skia_tmp_') |
| try: |
| - check_call( |
| + config.vsp.check_call( |
| [git, 'clone', '-q', '--depth=%d' % depth, |
| '--single-branch', config.skia_url, skia_dir]) |
| return skia_dir |
| @@ -209,7 +314,21 @@ def create_temp_skia_clone(config, depth): |
| raise error |
| -def find_revision_and_hash(config, revision): |
| +def get_svn_revision(config, commit): |
| + """Works in both git and git-svn. returns a string.""" |
| + svn_format = ( |
| + '(git-svn-id: [^@ ]+@|SVN changes up to revision )' |
| + '(?P<return>[0-9]+)') |
|
borenet
2014/01/08 19:27:40
Unfortunately, we need to add another case:
"LKGR
hal.canary
2014/01/08 19:59:35
Done.
borenet
2014/01/08 20:06:17
Thanks.
|
| + svn_revision = ReSearch.search_within_output( |
| + config.verbose, svn_format, None, |
| + [config.git, 'log', '-n', '1', '--format=format:%B', commit]) |
| + if not svn_revision: |
| + raise DepsRollError( |
| + 'Revision number missing from Chromium origin/master.') |
| + return int(svn_revision) |
| + |
| + |
| +def revision_and_hash(config, revision): |
| """Finds revision number and git hash of origin/master in the Skia tree. |
| Args: |
| @@ -220,7 +339,7 @@ def find_revision_and_hash(config, revision): |
| Returns: |
| A tuple (revision, hash) |
| revision: (int) SVN revision number. |
| - hash: (string) full Git commit hash. |
| + git_hash: (string) full Git commit hash. |
| Raises: |
| roll_deps.DepsRollError: if the revision can't be found. |
| @@ -228,44 +347,185 @@ def find_revision_and_hash(config, revision): |
| subprocess.CalledProcessError: git returned unexpected status. |
| """ |
| git = config.git |
| - use_temp = False |
| - skia_dir = None |
| depth = 1 if (revision is None) else config.search_depth |
| - try: |
| - if config.skia_git_checkout_path: |
| - skia_dir = config.skia_git_checkout_path |
| - ## Update origin/master if needed. |
| - check_call([git, 'fetch', '-q', 'origin'], cwd=skia_dir) |
| - else: |
| - skia_dir = create_temp_skia_clone(config, depth) |
| - assert skia_dir |
| - use_temp = True |
| - |
| + with SkiaGitCheckout(config, depth): |
| if revision is None: |
| - message = subprocess.check_output( |
| - [git, 'log', '-n', '1', '--format=format:%B', |
| - 'origin/master'], cwd=skia_dir) |
| - svn_format = ( |
| - 'git-svn-id: http://skia.googlecode.com/svn/trunk@([0-9]+) ') |
| - search = re.search(svn_format, message) |
| - if not search: |
| - raise DepsRollError( |
| - 'Revision number missing from origin/master.') |
| - revision = int(search.group(1)) |
| - git_hash = strip_output( |
| - [git, 'show-ref', 'origin/master', '--hash'], cwd=skia_dir) |
| + revision = get_svn_revision(config, 'origin/master') |
| + git_hash = config.vsp.strip_output( |
| + [git, 'show-ref', 'origin/master', '--hash']) |
| else: |
| revision_regex = config.revision_format % revision |
| - git_hash = strip_output( |
| - [git, 'log', '--grep', revision_regex, '--format=format:%H', |
| - 'origin/master'], cwd=skia_dir) |
| - |
| + git_hash = config.vsp.strip_output( |
| + [git, 'log', '--grep', revision_regex, |
| + '--format=format:%H', 'origin/master']) |
| if revision < 0 or not git_hash: |
| raise DepsRollError('Git hash can not be found.') |
| return revision, git_hash |
| - finally: |
| - if use_temp: |
| - shutil.rmtree(skia_dir) |
| + |
| + |
| +def revision_and_hash_from_partial(config, partial_hash): |
| + """Returns the SVN revision number and full git hash. |
| + |
| + Args: |
| + config: (roll_deps.DepsRollConfig) object containing options. |
| + partial_hash: (string) Partial git commit hash. |
| + |
| + Returns: |
| + A tuple (revision, hash) |
| + revision: (int) SVN revision number. |
| + git_hash: (string) full Git commit hash. |
| + |
| + Raises: |
| + roll_deps.DepsRollError: if the revision can't be found. |
| + OSError: failed to execute git or git-cl. |
| + subprocess.CalledProcessError: git returned unexpected status. |
| + """ |
| + with SkiaGitCheckout(config, config.search_depth): |
| + git_hash = config.vsp.strip_output( |
| + ['git', 'log', '--format=format:%H', '-n1', partial_hash]) |
| + if not git_hash: |
| + raise DepsRollError('Partial Git hash can not be found.') |
| + revision = get_svn_revision(config, git_hash) |
| + return revision, git_hash |
| + |
| + |
| +class SkiaGitCheckout(object): |
| + """Class to create a temporary skia git checkout, if necessary. |
| + """ |
| + # pylint: disable=I0011,R0903 |
| + |
| + def __init__(self, config, depth): |
| + self._config = config |
| + self._depth = depth |
| + self._use_temp = None |
| + self._original_cwd = None |
| + |
| + def __enter__(self): |
| + config = self._config |
| + git = config.git |
| + skia_dir = None |
| + self._original_cwd = os.getcwd() |
| + if config.skia_git_checkout_path: |
| + skia_dir = config.skia_git_checkout_path |
| + ## Update origin/master if needed. |
| + if self._config.verbose: |
| + print '~~$', 'cd', skia_dir |
| + os.chdir(skia_dir) |
| + config.vsp.check_call([git, 'fetch', '-q', 'origin']) |
| + self._use_temp = None |
| + else: |
| + skia_dir = tempfile.mkdtemp(prefix='git_skia_tmp_') |
| + self._use_temp = skia_dir |
| + try: |
| + os.chdir(skia_dir) |
| + config.vsp.check_call( |
| + [git, 'clone', '-q', '--depth=%d' % self._depth, |
| + '--single-branch', config.skia_url, '.']) |
| + except (OSError, subprocess.CalledProcessError) as error: |
| + shutil.rmtree(skia_dir) |
| + raise error |
| + |
| + finally: |
| + shutil.rmtree(skia_dir) |
|
borenet
2014/01/08 19:20:21
I'm confused - won't this delete our checkout befo
hal.canary
2014/01/08 19:59:35
Done.
|
| + |
| + def __exit__(self, etype, value, traceback): |
| + os.chdir(self._original_cwd) |
| + if self._use_temp: |
| + shutil.rmtree(self._use_temp) |
| + if self._config.verbose: |
| + print '~~$', 'cd', self._original_cwd |
|
borenet
2014/01/08 19:20:21
Please put this before os.chdir so that we get the
hal.canary
2014/01/08 19:59:35
Done.
|
| + |
| + |
| +class ChangeDir(object): |
| + """Use with a with-statement to temporarily change directories.""" |
| + # pylint: disable=I0011,R0903 |
| + |
| + def __init__(self, directory, verbose=False): |
| + self._directory = directory |
| + self._verbose = verbose |
| + |
| + def __enter__(self): |
| + if self._verbose: |
| + print '~~$ cd %s' % self._directory |
| + cwd = os.getcwd() |
| + os.chdir(self._directory) |
| + self._directory = cwd |
| + |
| + def __exit__(self, etype, value, traceback): |
| + if self._verbose: |
| + print '~~$ cd %s' % self._directory |
| + os.chdir(self._directory) |
| + |
| + |
| +class ReSearch(object): |
|
borenet
2014/01/08 19:20:21
Now that you've split this into a class with only
hal.canary
2014/01/08 19:59:35
As soon as someone else needs it, we can do that.
|
| + """A collection of static methods for regexing things.""" |
| + |
| + @staticmethod |
| + def search_within_stream(input_stream, pattern, default=None): |
| + """Search for regular expression in a file-like object. |
| + |
| + Opens a file for reading and searches line by line for a match to |
| + the regex and returns the parenthesized group named return for the |
| + first match. Does not search across newlines. |
| + |
| + For example: |
| + pattern = '^root(:[^:]*){4}:(?P<return>[^:]*)' |
| + with open('/etc/passwd', 'r') as stream: |
| + return search_within_file(stream, pattern) |
| + should return root's home directory (/root on my system). |
| + |
| + Args: |
| + input_stream: file-like object to be read |
| + pattern: (string) to be passed to re.compile |
| + default: what to return if no match |
| + |
| + Returns: |
| + A string or whatever default is |
| + """ |
| + pattern_object = re.compile(pattern) |
| + for line in input_stream: |
| + match = pattern_object.search(line) |
| + if match: |
| + return match.group('return') |
| + return default |
| + |
| + @staticmethod |
| + def search_within_string(input_string, pattern, default=None): |
| + """Search for regular expression in a string. |
| + |
| + Args: |
| + input_string: (string) to be searched |
| + pattern: (string) to be passed to re.compile |
| + default: what to return if no match |
| + |
| + Returns: |
| + A string or whatever default is |
| + """ |
| + match = re.search(pattern, input_string) |
| + return match.group('return') if match else default |
| + |
| + @staticmethod |
| + def search_within_output(verbose, pattern, default, *args, **kwargs): |
| + """Search for regular expression in a process output. |
| + |
| + Does not search across newlines. |
| + |
| + Args: |
| + verbose: (boolean) shoule we call |
| + VerboseSubprocess.print_subprocess_args? |
| + pattern: (string) to be passed to re.compile |
| + default: what to return if no match |
| + *args: to be passed to subprocess.Popen() |
| + **kwargs: to be passed to subprocess.Popen() |
| + |
| + Returns: |
| + A string or whatever default is |
| + """ |
| + if verbose: |
| + VerboseSubprocess.print_subprocess_args( |
| + '~~$ ', *args, **kwargs) |
| + proc = subprocess.Popen(*args, stdout=subprocess.PIPE, **kwargs) |
| + return ReSearch.search_within_stream(proc.stdout, pattern, default) |
| class GitBranchCLUpload(object): |
| @@ -302,7 +562,6 @@ class GitBranchCLUpload(object): |
| self._stash = None |
| self._original_branch = None |
| self._config = config |
| - self._svn_info = None |
| self.issue = None |
| def stage_for_commit(self, *paths): |
| @@ -315,88 +574,76 @@ class GitBranchCLUpload(object): |
| def __enter__(self): |
| git = self._config.git |
| + vsp = self._config.vsp |
| def branch_exists(branch): |
| """Return true iff branch exists.""" |
| - return 0 == subprocess.call( |
| - [git, 'show-ref', '--quiet', branch]) |
| + return 0 == vsp.call([git, 'show-ref', '--quiet', branch]) |
| def has_diff(): |
| """Return true iff repository has uncommited changes.""" |
| - return bool(subprocess.call([git, 'diff', '--quiet', 'HEAD'])) |
| + return bool(vsp.call([git, 'diff', '--quiet', 'HEAD'])) |
| + |
| self._stash = has_diff() |
| if self._stash: |
| - check_call([git, 'stash', 'save']) |
| + subprocess.check_call([git, 'stash', 'save']) |
|
borenet
2014/01/08 19:20:21
Why not use your wrapper?
hal.canary
2014/01/08 19:59:35
Done.
|
| try: |
| - self._original_branch = strip_output( |
| + self._original_branch = vsp.strip_output( |
| [git, 'symbolic-ref', '--short', 'HEAD']) |
| except (subprocess.CalledProcessError,): |
| - self._original_branch = strip_output( |
| + self._original_branch = vsp.strip_output( |
| [git, 'rev-parse', 'HEAD']) |
| if not self._branch_name: |
| self._branch_name = self._config.default_branch_name |
| if branch_exists(self._branch_name): |
| - check_call([git, 'checkout', '-q', 'master']) |
| - check_call([git, 'branch', '-q', '-D', self._branch_name]) |
| - |
| - check_call( |
| - [git, 'checkout', '-q', '-b', |
| - self._branch_name, 'origin/master']) |
| + vsp.check_call([git, 'checkout', '-q', 'master']) |
| + vsp.check_call([git, 'branch', '-q', '-D', self._branch_name]) |
| - svn_info = subprocess.check_output(['git', 'svn', 'info']) |
| - svn_info_search = re.search(r'Last Changed Rev: ([0-9]+)\W', svn_info) |
| - assert svn_info_search |
| - self._svn_info = svn_info_search.group(1) |
| + vsp.check_call( |
| + [git, 'checkout', '-q', '-b', self._branch_name, 'origin/master']) |
| def __exit__(self, etype, value, traceback): |
| # pylint: disable=I0011,R0912 |
| git = self._config.git |
| - def quiet_check_call(*args, **kwargs): |
| - """Call check_call, but pipe output to devnull.""" |
| - with open(os.devnull, 'w') as devnull: |
| - check_call(*args, stdout=devnull, **kwargs) |
| + vsp = self._config.vsp |
| + svn_info = str(get_svn_revision(self._config, 'HEAD')) |
| for filename in self._file_list: |
| assert os.path.exists(filename) |
| - check_call([git, 'add', filename]) |
| - check_call([git, 'commit', '-q', '-m', self._message]) |
| + vsp.check_call([git, 'add', filename]) |
| + vsp.check_call([git, 'commit', '-q', '-m', self._message]) |
| git_cl = [git, 'cl', 'upload', '-f', '--cc=skia-team@google.com', |
| '--bypass-hooks', '--bypass-watchlists'] |
| - git_try = [git, 'cl', 'try', '--revision', self._svn_info] |
| + git_try = [git, 'cl', 'try', '--revision', svn_info] |
| git_try.extend([arg for bot in self._config.cl_bot_list |
| for arg in ('-b', bot)]) |
| if self._config.skip_cl_upload: |
| - print ' '.join(git_cl) |
| + print 'You should call:' |
| + print ' cd %s' % os.getcwd() |
| + VerboseSubprocess.print_subprocess_args( |
| + ' ', [git, 'checkout', self._branch_name]) |
| + VerboseSubprocess.print_subprocess_args(' ', git_cl) |
| if self._config.cl_bot_list: |
| - print ' '.join(git_try) |
| + VerboseSubprocess.print_subprocess_args(' ', git_try) |
| self.issue = '' |
| else: |
| - if self._config.verbose: |
| - check_call(git_cl) |
| - else: |
| - quiet_check_call(git_cl) |
| - self.issue = strip_output([git, 'cl', 'issue']) |
| + vsp.check_call(git_cl) |
| + self.issue = vsp.strip_output([git, 'cl', 'issue']) |
| if self._config.cl_bot_list: |
| - if self._config.verbose: |
| - check_call(git_try) |
| - else: |
| - quiet_check_call(git_try) |
| + vsp.check_call(git_try) |
| # deal with the aftermath of failed executions of this script. |
| if self._config.default_branch_name == self._original_branch: |
| self._original_branch = 'master' |
| - check_call([git, 'checkout', '-q', self._original_branch]) |
| + vsp.check_call([git, 'checkout', '-q', self._original_branch]) |
| if self._config.default_branch_name == self._branch_name: |
| - check_call([git, 'branch', '-q', '-D', self._branch_name]) |
| + vsp.check_call([git, 'branch', '-q', '-D', self._branch_name]) |
| if self._stash: |
| - check_call([git, 'stash', 'pop']) |
| + vsp.check_call([git, 'stash', 'pop']) |
| def change_skia_deps(revision, git_hash, depspath): |
| @@ -428,18 +675,6 @@ def change_skia_deps(revision, git_hash, depspath): |
| shutil.move(temp_file.name, depspath) |
| -def branch_name(message): |
| - """Return the first line of a commit message to be used as a branch name. |
| - |
| - Args: |
| - message: (string) |
| - |
| - Returns: |
| - A string derived from message suitable for a branch name. |
| - """ |
| - return message.lstrip().split('\n')[0].rstrip().replace(' ', '_') |
| - |
| - |
| def roll_deps(config, revision, git_hash): |
| """Upload changed DEPS and a whitespace change. |
| @@ -457,18 +692,29 @@ def roll_deps(config, revision, git_hash): |
| OSError: failed to execute git or git-cl. |
| subprocess.CalledProcessError: git returned unexpected status. |
| """ |
| + |
| git = config.git |
| - cwd = os.getcwd() |
| - os.chdir(config.chromium_path) |
| - try: |
| - check_call([git, 'fetch', '-q', 'origin']) |
| - master_hash = strip_output( |
| + with ChangeDir(config.chromium_path, config.verbose): |
| + config.vsp.check_call([git, 'fetch', '-q', 'origin']) |
| + |
| + old_revision = ReSearch.search_within_output( |
| + config.verbose, '"skia_revision": "(?P<return>[0-9]+)",', None, |
| + [git, 'show', 'origin/master:DEPS']) |
| + assert old_revision |
| + if revision == int(old_revision): |
| + print 'DEPS is up to date!' |
| + return None |
| + |
| + master_hash = config.vsp.strip_output( |
| [git, 'show-ref', 'origin/master', '--hash']) |
| + branch = None |
| + |
| # master_hash[8] gives each whitespace CL a unique name. |
| message = ('whitespace change %s\n\nThis CL was created by' |
| ' Skia\'s roll_deps.py script.\n') % master_hash[:8] |
| - branch = branch_name(message) if config.save_branches else None |
| + if config.save_branches: |
| + branch = 'control_%s' % master_hash[:8] |
| codereview = GitBranchCLUpload(config, message, branch) |
| with codereview: |
| @@ -478,15 +724,17 @@ def roll_deps(config, revision, git_hash): |
| whitespace_cl = codereview.issue |
| if branch: |
| whitespace_cl = '%s\n branch: %s' % (whitespace_cl, branch) |
| - control_url_match = re.search('https?://[^) ]+', codereview.issue) |
| - if control_url_match: |
| - message = ('roll skia DEPS to %d\n\nThis CL was created by' |
| - ' Skia\'s roll_deps.py script.\n\ncontrol: %s' |
| - % (revision, control_url_match.group(0))) |
| - else: |
| - message = ('roll skia DEPS to %d\n\nThis CL was created by' |
| - ' Skia\'s roll_deps.py script.') % revision |
| - branch = branch_name(message) if config.save_branches else None |
| + |
| + control_url = ReSearch.search_within_string( |
| + codereview.issue, '(?P<return>https?://[^) ]+)', '?') |
| + |
| + if config.save_branches: |
| + branch = 'roll_%d_%s' % (revision, master_hash[:8]) |
| + message = ( |
| + 'roll skia DEPS to %d\n\nold revision:%s\n' |
| + 'new revision:%d\nThis CL was created by' |
| + ' Skia\'s roll_deps.py script.\n\ncontrol: %s' |
| + % (revision, old_revision, revision, control_url)) |
| codereview = GitBranchCLUpload(config, message, branch) |
| with codereview: |
| change_skia_deps(revision, git_hash, 'DEPS') |
| @@ -496,11 +744,9 @@ def roll_deps(config, revision, git_hash): |
| deps_cl = '%s\n branch: %s' % (deps_cl, branch) |
| return deps_cl, whitespace_cl |
| - finally: |
| - os.chdir(cwd) |
| -def find_hash_and_roll_deps(config, revision): |
| +def find_hash_and_roll_deps(config, revision, partial_hash): |
| """Call find_hash_from_revision() and roll_deps(). |
| The calls to git will be verbose on standard output. After a |
| @@ -511,20 +757,29 @@ def find_hash_and_roll_deps(config, revision): |
| config: (roll_deps.DepsRollConfig) object containing options. |
| revision: (int or None) the Skia SVN revision number or None |
| to use the tip of the tree. |
| + partial_hash: (string) a partial pure-git Skia commit hash. |
| + If set, revision is ignored. |
|
borenet
2014/01/08 19:20:21
This and revision should default to None so that o
hal.canary
2014/01/08 19:59:35
Done.
|
| Raises: |
| roll_deps.DepsRollError: if the revision can't be found. |
| OSError: failed to execute git or git-cl. |
| subprocess.CalledProcessError: git returned unexpected status. |
| """ |
| - revision, git_hash = find_revision_and_hash(config, revision) |
| + |
| + if partial_hash: |
| + revision, git_hash = revision_and_hash_from_partial( |
| + config, partial_hash) |
| + else: |
| + revision, git_hash = revision_and_hash(config, revision) |
| print 'revision=%r\nhash=%r\n' % (revision, git_hash) |
| - deps_issue, whitespace_issue = roll_deps(config, revision, git_hash) |
| + roll = roll_deps(config, revision, git_hash) |
| - print 'DEPS roll:\n %s\n' % deps_issue |
| - print 'Whitespace change:\n %s\n' % whitespace_issue |
| + if roll: |
| + deps_issue, whitespace_issue = roll |
| + print 'DEPS roll:\n %s\n' % deps_issue |
| + print 'Whitespace change:\n %s\n' % whitespace_issue |
| def main(args): |
| @@ -544,7 +799,7 @@ def main(args): |
| option_parser.error('Invalid git executable.') |
| config = DepsRollConfig(options) |
| - find_hash_and_roll_deps(config, options.revision) |
| + find_hash_and_roll_deps(config, options.revision, options.git_hash) |
| if __name__ == '__main__': |