| Index: third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
|
| diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
|
| index dc790442463defccbd0b90f9f4ab79a8fd9d93aa..ab21b9da8fe44165f74b7c703f487db75931087f 100644
|
| --- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
|
| +++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
|
| @@ -28,23 +28,19 @@
|
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
| import datetime
|
| +import logging
|
| import re
|
|
|
| -from webkitpy.common.checkout.scm.scm import SCM
|
| from webkitpy.common.memoized import memoized
|
| from webkitpy.common.system.executive import Executive, ScriptError
|
| +from webkitpy.common.system.filesystem import FileSystem
|
|
|
| +_log = logging.getLogger(__name__)
|
|
|
| -class AmbiguousCommitError(Exception):
|
|
|
| - def __init__(self, num_local_commits, has_working_directory_changes):
|
| - Exception.__init__(self, "Found %s local commits and the working directory is %s" % (
|
| - num_local_commits, ["clean", "not clean"][has_working_directory_changes]))
|
| - self.num_local_commits = num_local_commits
|
| - self.has_working_directory_changes = has_working_directory_changes
|
| -
|
| -
|
| -class Git(SCM):
|
| +class Git(object):
|
| + # Unless otherwise specified, methods are expected to return paths relative
|
| + # to self.checkout_root.
|
|
|
| # Git doesn't appear to document error codes, but seems to return
|
| # 1 or 128, mostly.
|
| @@ -52,15 +48,33 @@ class Git(SCM):
|
|
|
| executable_name = 'git'
|
|
|
| - def __init__(self, cwd, **kwargs):
|
| - SCM.__init__(self, cwd, **kwargs)
|
| -
|
| - def _run_git(self, command_args, **kwargs):
|
| + def __init__(self, cwd, executive=None, filesystem=None):
|
| + self.cwd = cwd
|
| + self._executive = executive or Executive()
|
| + self._filesystem = filesystem or FileSystem()
|
| + self.checkout_root = self.find_checkout_root(self.cwd)
|
| +
|
| + def _run_git(self,
|
| + command_args,
|
| + cwd=None,
|
| + input=None, # pylint: disable=redefined-builtin
|
| + timeout_seconds=None,
|
| + decode_output=True,
|
| + return_exit_code=False):
|
| full_command_args = [self.executable_name] + command_args
|
| - full_kwargs = kwargs
|
| - if 'cwd' not in full_kwargs:
|
| - full_kwargs['cwd'] = self.checkout_root
|
| - return self._run(full_command_args, **full_kwargs)
|
| + cwd = cwd or self.checkout_root
|
| + return self._executive.run_command(
|
| + full_command_args,
|
| + cwd=cwd,
|
| + input=input,
|
| + timeout_seconds=timeout_seconds,
|
| + return_exit_code=return_exit_code,
|
| + decode_output=decode_output)
|
| +
|
| + # SCM always returns repository relative path, but sometimes we need
|
| + # absolute paths to pass to rm, etc.
|
| + def absolute_path(self, repository_relative_path):
|
| + return self._filesystem.join(self.checkout_root, repository_relative_path)
|
|
|
| @classmethod
|
| def in_working_directory(cls, path, executive=None):
|
| @@ -130,21 +144,13 @@ class Git(SCM):
|
| unstaged_changes[path] = line[1]
|
| return unstaged_changes
|
|
|
| - def status_command(self):
|
| - # git status returns non-zero when there are changes, so we use git diff name --name-status HEAD instead.
|
| - # No file contents printed, thus utf-8 autodecoding in self.run is fine.
|
| - return [self.executable_name, "diff", "--name-status", "--no-renames", "HEAD"]
|
| -
|
| - def _status_regexp(self, expected_types):
|
| - return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types
|
| -
|
| def add_all(self, pathspec=None):
|
| command = ['add', '--all']
|
| if pathspec:
|
| command.append(pathspec)
|
| return self._run_git(command)
|
|
|
| - def add_list(self, paths, return_exit_code=False, recurse=True):
|
| + def add_list(self, paths, return_exit_code=False):
|
| return self._run_git(["add"] + paths, return_exit_code=return_exit_code)
|
|
|
| def delete_list(self, paths):
|
| @@ -208,11 +214,28 @@ class Git(SCM):
|
| # Added (A), Copied (C), Deleted (D), Modified (M), Renamed (R)
|
| return self._run_status_and_extract_filenames(status_command, self._status_regexp("ADM"))
|
|
|
| - def _added_files(self):
|
| + def added_files(self):
|
| return self._run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
|
|
|
| - def _deleted_files(self):
|
| - return self._run_status_and_extract_filenames(self.status_command(), self._status_regexp("D"))
|
| + def _run_status_and_extract_filenames(self, status_command, status_regexp):
|
| + filenames = []
|
| + # We run with cwd=self.checkout_root so that returned-paths are root-relative.
|
| + for line in self._run_git(status_command, cwd=self.checkout_root).splitlines():
|
| + match = re.search(status_regexp, line)
|
| + if not match:
|
| + continue
|
| + # status = match.group('status')
|
| + filename = match.group('filename')
|
| + filenames.append(filename)
|
| + return filenames
|
| +
|
| + def status_command(self):
|
| + # git status returns non-zero when there are changes, so we use git diff name --name-status HEAD instead.
|
| + # No file contents printed, thus utf-8 autodecoding in self.run is fine.
|
| + return ["diff", "--name-status", "--no-renames", "HEAD"]
|
| +
|
| + def _status_regexp(self, expected_types):
|
| + return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types
|
|
|
| @staticmethod
|
| def supports_local_commits():
|
| @@ -233,6 +256,7 @@ class Git(SCM):
|
| return int(match.group('commit_position'))
|
|
|
| def commit_position(self, path):
|
| + """Returns the latest chromium commit position found in the checkout."""
|
| git_log = self.most_recent_log_matching('Cr-Commit-Position:', path)
|
| return self._commit_position_from_git_log(git_log)
|
|
|
| @@ -260,21 +284,33 @@ class Git(SCM):
|
| Patch files are effectively binary since they may contain
|
| files of multiple different encodings.
|
| """
|
| + order = self._patch_order()
|
| + command = [
|
| + 'diff',
|
| + '--binary',
|
| + '--no-color',
|
| + "--no-ext-diff",
|
| + "--full-index",
|
| + "--no-renames",
|
| + "--src-prefix=a/",
|
| + "--dst-prefix=b/",
|
| +
|
| + ]
|
| + if order:
|
| + command.append(order)
|
| + command += [self._merge_base(git_commit), "--"]
|
| + if changed_files:
|
| + command += changed_files
|
| + return self._run_git(command, decode_output=False, cwd=self.checkout_root)
|
|
|
| + def _patch_order(self):
|
| # Put code changes at the top of the patch and layout tests
|
| # at the bottom, this makes for easier reviewing.
|
| config_path = self._filesystem.dirname(self._filesystem.path_to_module('webkitpy.common.config'))
|
| order_file = self._filesystem.join(config_path, 'orderfile')
|
| - order = ""
|
| if self._filesystem.exists(order_file):
|
| - order = "-O%s" % order_file
|
| -
|
| - command = [self.executable_name, 'diff', '--binary', '--no-color', "--no-ext-diff",
|
| - "--full-index", "--no-renames", "--src-prefix=a/", "--dst-prefix=b/",
|
| - order, self._merge_base(git_commit), "--"]
|
| - if changed_files:
|
| - command += changed_files
|
| - return self._run(command, decode_output=False, cwd=self.checkout_root)
|
| + return "-O%s" % order_file
|
| + return ""
|
|
|
| @memoized
|
| def commit_position_from_git_commit(self, git_commit):
|
| @@ -312,9 +348,6 @@ class Git(SCM):
|
| command = ['commit', '--all', '-F', '-']
|
| self._run_git(command, input=message)
|
|
|
| - # These methods are git specific and are meant to provide support for the Git oriented workflow
|
| - # that Blink is moving towards, hence there are no equivalent methods in the SVN class.
|
| -
|
| def pull(self, timeout_seconds=None):
|
| self._run_git(['pull'], timeout_seconds=timeout_seconds)
|
|
|
| @@ -324,7 +357,7 @@ class Git(SCM):
|
| def git_commits_since(self, commit):
|
| return self._run_git(['log', commit + '..master', '--format=%H', '--reverse']).split()
|
|
|
| - def git_commit_detail(self, commit, format=None):
|
| + def git_commit_detail(self, commit, format=None): # pylint: disable=redefined-builtin
|
| args = ['log', '-1', commit]
|
| if format:
|
| args.append('--format=' + format)
|
|
|