2016-11-30 06:21:53 +01:00
|
|
|
"""Wrapper around git command-line tools."""
|
2019-07-12 08:46:20 +02:00
|
|
|
from __future__ import (absolute_import, division, print_function)
|
|
|
|
__metaclass__ = type
|
2016-11-30 06:21:53 +01:00
|
|
|
|
2019-08-29 20:02:11 +02:00
|
|
|
import re
|
|
|
|
|
2019-08-06 23:43:29 +02:00
|
|
|
from . import types as t
|
2019-06-27 21:00:26 +02:00
|
|
|
|
2019-08-06 23:43:29 +02:00
|
|
|
from .util import (
|
2017-03-15 19:10:50 +01:00
|
|
|
SubprocessError,
|
2019-08-30 21:03:39 +02:00
|
|
|
display,
|
2019-06-27 21:00:26 +02:00
|
|
|
raw_command,
|
2019-08-30 21:03:39 +02:00
|
|
|
to_text,
|
2016-11-30 06:21:53 +01:00
|
|
|
)
|
|
|
|
|
|
|
|
|
2019-07-12 22:17:20 +02:00
|
|
|
class Git:
|
2016-11-30 06:21:53 +01:00
|
|
|
"""Wrapper around git command-line tools."""
|
2019-07-10 02:31:04 +02:00
|
|
|
def __init__(self, root=None): # type: (t.Optional[str]) -> None
|
2016-11-30 06:21:53 +01:00
|
|
|
self.git = 'git'
|
2019-06-27 21:00:26 +02:00
|
|
|
self.root = root
|
2016-11-30 06:21:53 +01:00
|
|
|
|
2018-01-17 15:33:33 +01:00
|
|
|
def get_diff(self, args, git_options=None):
|
2017-03-15 20:17:42 +01:00
|
|
|
"""
|
|
|
|
:type args: list[str]
|
2018-08-28 04:02:35 +02:00
|
|
|
:type git_options: list[str] | None
|
2017-03-15 20:17:42 +01:00
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
|
|
|
cmd = ['diff'] + args
|
2018-01-17 15:33:33 +01:00
|
|
|
if git_options is None:
|
|
|
|
git_options = ['-c', 'core.quotePath=']
|
|
|
|
return self.run_git_split(git_options + cmd, '\n', str_errors='replace')
|
2017-03-15 20:17:42 +01:00
|
|
|
|
2016-11-30 06:21:53 +01:00
|
|
|
def get_diff_names(self, args):
|
|
|
|
"""
|
|
|
|
:type args: list[str]
|
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
|
|
|
cmd = ['diff', '--name-only', '--no-renames', '-z'] + args
|
|
|
|
return self.run_git_split(cmd, '\0')
|
|
|
|
|
2019-08-29 20:02:11 +02:00
|
|
|
def get_submodule_paths(self): # type: () -> t.List[str]
|
|
|
|
"""Return a list of submodule paths recursively."""
|
2019-08-30 01:31:38 +02:00
|
|
|
cmd = ['submodule', 'status', '--recursive', '.']
|
2019-08-29 20:02:11 +02:00
|
|
|
output = self.run_git_split(cmd, '\n')
|
|
|
|
submodule_paths = [re.search(r'^.[0-9a-f]+ (?P<path>[^ ]+)', line).group('path') for line in output]
|
|
|
|
return submodule_paths
|
|
|
|
|
2016-11-30 06:21:53 +01:00
|
|
|
def get_file_names(self, args):
|
|
|
|
"""
|
|
|
|
:type args: list[str]
|
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
|
|
|
cmd = ['ls-files', '-z'] + args
|
|
|
|
return self.run_git_split(cmd, '\0')
|
|
|
|
|
|
|
|
def get_branches(self):
|
|
|
|
"""
|
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
|
|
|
cmd = ['for-each-ref', 'refs/heads/', '--format', '%(refname:strip=2)']
|
|
|
|
return self.run_git_split(cmd)
|
|
|
|
|
|
|
|
def get_branch(self):
|
|
|
|
"""
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
cmd = ['symbolic-ref', '--short', 'HEAD']
|
|
|
|
return self.run_git(cmd).strip()
|
|
|
|
|
2018-11-14 20:30:48 +01:00
|
|
|
def get_rev_list(self, commits=None, max_count=None):
|
|
|
|
"""
|
|
|
|
:type commits: list[str] | None
|
|
|
|
:type max_count: int | None
|
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
|
|
|
cmd = ['rev-list']
|
|
|
|
|
|
|
|
if commits:
|
|
|
|
cmd += commits
|
|
|
|
else:
|
|
|
|
cmd += ['HEAD']
|
|
|
|
|
|
|
|
if max_count:
|
|
|
|
cmd += ['--max-count', '%s' % max_count]
|
|
|
|
|
|
|
|
return self.run_git_split(cmd)
|
|
|
|
|
2016-11-30 06:21:53 +01:00
|
|
|
def get_branch_fork_point(self, branch):
|
|
|
|
"""
|
|
|
|
:type branch: str
|
|
|
|
:rtype: str
|
|
|
|
"""
|
|
|
|
cmd = ['merge-base', '--fork-point', branch]
|
|
|
|
return self.run_git(cmd).strip()
|
|
|
|
|
2017-03-15 19:10:50 +01:00
|
|
|
def is_valid_ref(self, ref):
|
|
|
|
"""
|
|
|
|
:type ref: str
|
|
|
|
:rtype: bool
|
|
|
|
"""
|
|
|
|
cmd = ['show', ref]
|
|
|
|
try:
|
2017-07-28 03:26:23 +02:00
|
|
|
self.run_git(cmd, str_errors='replace')
|
2017-03-15 19:10:50 +01:00
|
|
|
return True
|
|
|
|
except SubprocessError:
|
|
|
|
return False
|
|
|
|
|
2017-07-28 03:15:56 +02:00
|
|
|
def run_git_split(self, cmd, separator=None, str_errors='strict'):
|
2016-11-30 06:21:53 +01:00
|
|
|
"""
|
|
|
|
:type cmd: list[str]
|
2017-07-29 01:17:56 +02:00
|
|
|
:type separator: str | None
|
|
|
|
:type str_errors: str
|
2016-11-30 06:21:53 +01:00
|
|
|
:rtype: list[str]
|
|
|
|
"""
|
2017-07-28 03:15:56 +02:00
|
|
|
output = self.run_git(cmd, str_errors=str_errors).strip(separator)
|
2016-11-30 06:21:53 +01:00
|
|
|
|
2017-05-03 17:19:44 +02:00
|
|
|
if not output:
|
2016-11-30 06:21:53 +01:00
|
|
|
return []
|
|
|
|
|
|
|
|
return output.split(separator)
|
|
|
|
|
2017-07-28 03:15:56 +02:00
|
|
|
def run_git(self, cmd, str_errors='strict'):
|
2016-11-30 06:21:53 +01:00
|
|
|
"""
|
|
|
|
:type cmd: list[str]
|
2017-07-29 01:17:56 +02:00
|
|
|
:type str_errors: str
|
2016-11-30 06:21:53 +01:00
|
|
|
:rtype: str
|
|
|
|
"""
|
2019-08-30 21:03:39 +02:00
|
|
|
try:
|
|
|
|
return raw_command([self.git] + cmd, cwd=self.root, capture=True, str_errors=str_errors)[0]
|
|
|
|
except SubprocessError as spe:
|
|
|
|
display.warning(to_text(spe.message))
|
|
|
|
return spe.stdout
|