diff --git a/kallithea/lib/diffs.py b/kallithea/lib/diffs.py --- a/kallithea/lib/diffs.py +++ b/kallithea/lib/diffs.py @@ -549,6 +549,19 @@ _hg_header_re = re.compile(br""" _header_next_check = re.compile(br'''(?!@)(?!literal )(?!delta )''') +_git_bs_escape_re = re.compile(r'\\(?:([^0-9])|([0-9]{3}))') + + +_git_bs_escape_dict = {'\\': '\\', '"': '"', 'r': '\r', 'n': '\n', 't': '\t'} + + +def _git_bs_unescape_m(m): + c = m.group(1) + if c is not None: + return _git_bs_escape_dict.get(c) or ('\\' + c) + return chr(int(m.group(2), 8)) + + def _get_header(vcs, diff_chunk): """ Parses a Git diff for a single file (header and chunks) and returns a tuple with: @@ -569,6 +582,11 @@ def _get_header(vcs, diff_chunk): if match is None: raise Exception('diff not recognized as valid %s diff: %r' % (vcs, safe_str(bytes(diff_chunk[:1000])))) meta_info = {k: None if v is None else safe_str(v) for k, v in match.groupdict().items()} + if vcs == 'git': + for k in ['a_path', 'b_path', 'a_file', 'b_file']: + v = meta_info.get(k) + if v: + meta_info[k] = _git_bs_escape_re.sub(_git_bs_unescape_m, v) rest = diff_chunk[match.end():] if rest: if _header_next_check.match(rest): diff --git a/kallithea/tests/models/test_diff_parsers.py b/kallithea/tests/models/test_diff_parsers.py --- a/kallithea/tests/models/test_diff_parsers.py +++ b/kallithea/tests/models/test_diff_parsers.py @@ -269,7 +269,7 @@ DIFF_FIXTURES = { 'ops': {RENAMED_FILENODE: 'file renamed from oh no to oh yes'}}), ], 'git_diff_quoting.diff': [ - (r'\"foo\"', # TODO: quotes should not be escaped + ('"foo"', 'added', {'added': 1, 'binary': False, @@ -281,19 +281,19 @@ DIFF_FIXTURES = { 'binary': False, 'deleted': 0, 'ops': {1: 'new file 100644'}}), - ("'foo'" r'\"foo\"', # TODO: quotes should not be escaped + ("'foo'" '"foo"', 'added', {'added': 1, 'binary': False, 'deleted': 0, 'ops': {1: 'new file 100644'}}), - (r'a\r\nb', # TODO: escaped + ('a\r\nb', # Note: will be parsed correctly, but other parts of Kallithea can't handle it 'added', {'added': 1, 'binary': False, 'deleted': 0, 'ops': {1: 'new file 100644'}}), - (r'foo\rfoo', # TODO: escaped + ('foo\rfoo', # Note: will be parsed correctly, but other parts of Kallithea can't handle it 'added', {'added': 0, 'binary': True, @@ -311,13 +311,13 @@ DIFF_FIXTURES = { 'binary': False, 'deleted': 0, 'ops': {1: 'new file 100644'}}), - (r'esc\033foo', # TODO: escaped + ('esc\033foo', # Note: will be parsed and handled correctly, but without good UI 'added', {'added': 0, 'binary': True, 'deleted': 0, 'ops': {1: 'new file 100644'}}), - (r'tab\tfoo', # TODO: escaped + ('tab\tfoo', # Note: will be parsed and handled correctly, but without good UI 'added', {'added': 0, 'binary': True,