| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -733,12 +733,17 @@ def _handle_diff_line(lines_bytes: bytes, repo: "Repo", index: DiffIndex["Diff"] | |||
| 733 | 733 | # Discard everything before the first colon, and the colon itself. | |
| 734 | 734 | _, _, lines = lines.partition(":") | |
| 735 | 735 | ||
| 736 | - for line in lines.split("\x00:"): | ||
| 737 | - if not line: | ||
| 736 | + # Each record is a metadata field starting with a colon, followed by one path, | ||
| 737 | + # or two for copies and renames, each terminated by NUL. A path may itself | ||
| 738 | + # start with a colon or contain a line feed, so read the fields in order | ||
| 739 | + # instead of splitting at colons. | ||
| 740 | + fields = iter(lines.rstrip("\n").split("\x00")) | ||
| 741 | + for meta in fields: | ||
| 742 | + if not meta: | ||
| 738 | 743 | # The line data is empty, skip. | |
| 739 | 744 | continue | |
| 740 | - meta, _, path = line.partition("\x00") | ||
| 741 | - path = path.rstrip("\x00") | ||
| 745 | + if meta.startswith(":"): | ||
| 746 | + meta = meta[1:] | ||
| 742 | 747 | a_blob_id: Optional[str] | |
| 743 | 748 | b_blob_id: Optional[str] | |
| 744 | 749 | old_mode, new_mode, a_blob_id, b_blob_id, _change_type = meta.split(None, 4) | |
@@ -748,7 +753,7 @@ def _handle_diff_line(lines_bytes: bytes, repo: "Repo", index: DiffIndex["Diff"] | |||
| 748 | 753 | change_type: Lit_change_type = cast(Lit_change_type, _change_type[0]) | |
| 749 | 754 | score_str = "".join(_change_type[1:]) | |
| 750 | 755 | score = int(score_str) if score_str.isdigit() else None | |
| 751 | - path = path.strip("\n") | ||
| 756 | + path = next(fields, "") | ||
| 752 | 757 | a_path = path.encode(defenc) | |
| 753 | 758 | b_path = path.encode(defenc) | |
| 754 | 759 | deleted_file = False | |
@@ -767,13 +772,9 @@ def _handle_diff_line(lines_bytes: bytes, repo: "Repo", index: DiffIndex["Diff"] | |||
| 767 | 772 | new_file = True | |
| 768 | 773 | elif change_type == "C": | |
| 769 | 774 | copied_file = True | |
| 770 | - a_path_str, b_path_str = path.split("\x00", 1) | ||
| 771 | - a_path = a_path_str.encode(defenc) | ||
| 772 | - b_path = b_path_str.encode(defenc) | ||
| 775 | + b_path = next(fields, "").encode(defenc) | ||
| 773 | 776 | elif change_type == "R": | |
| 774 | - a_path_str, b_path_str = path.split("\x00", 1) | ||
| 775 | - a_path = a_path_str.encode(defenc) | ||
| 776 | - b_path = b_path_str.encode(defenc) | ||
| 777 | + b_path = next(fields, "").encode(defenc) | ||
| 777 | 778 | rename_from, rename_to = a_path, b_path | |
| 778 | 779 | elif change_type == "T": | |
| 779 | 780 | # Nothing to do. | |
@@ -817,17 +818,17 @@ def _index_from_raw_format(cls, repo: "Repo", proc: "Popen") -> "DiffIndex[Diff] | |||
| 817 | 818 | # :100644 100644 687099101... 37c5e30c8... M .gitignore | |
| 818 | 819 | ||
| 819 | 820 | index: "DiffIndex" = DiffIndex() | |
| 821 | + text_list: List[bytes] = [] | ||
| 820 | 822 | stderr_list: List[bytes] = [] | |
| 821 | 823 | ||
| 822 | 824 | def finalize_process_with_stderr(proc: Union["Popen", "Git.AutoInterrupt"]) -> None: | |
| 823 | 825 | finalize_process(proc, stderr=b"".join(stderr_list)) | |
| 824 | 826 | ||
| 827 | + # Output is read line by line, but paths may contain line feeds, so parse | ||
| 828 | + # the records only once all of it has been read. | ||
| 825 | 829 | handle_process_output( | |
| 826 | - proc, | ||
| 827 | - lambda byt: cls._handle_diff_line(byt, repo, index), | ||
| 828 | - stderr_list.append, | ||
| 829 | - finalize_process_with_stderr, | ||
| 830 | - decode_streams=False, | ||
| 830 | + proc, text_list.append, stderr_list.append, finalize_process_with_stderr, decode_streams=False | ||
| 831 | 831 | ) | |
| 832 | + cls._handle_diff_line(b"".join(text_list), repo, index) | ||
| 832 | 833 | ||
| 833 | 834 | return index | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -4,6 +4,7 @@ | |||
| 4 | 4 | # 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/ | |
| 5 | 5 | ||
| 6 | 6 | import gc | |
| 7 | + from io import BytesIO | ||
| 7 | 8 | import os.path as osp | |
| 8 | 9 | import shutil | |
| 9 | 10 | import sys | |
@@ -12,10 +13,13 @@ | |||
| 12 | 13 | import ddt | |
| 13 | 14 | import pytest | |
| 14 | 15 | ||
| 15 | - from git import NULL_TREE, Diff, DiffIndex, Diffable, GitCommandError, Repo, Submodule | ||
| 16 | + from gitdb.base import IStream | ||
| 17 | + | ||
| 18 | + from git import NULL_TREE, Blob, Diff, DiffIndex, Diffable, GitCommandError, Repo, Submodule | ||
| 16 | 19 | from git.cmd import Git | |
| 17 | 20 | from git.diff import decode_path | |
| 18 | 21 | from git.exc import UnsafeOptionError | |
| 22 | + from git.index.typ import BaseIndexEntry | ||
| 19 | 23 | ||
| 20 | 24 | from test.lib import StringProcessAdapter, TestBase, fixture, with_rw_directory | |
| 21 | 25 | ||
@@ -253,6 +257,19 @@ def test_diff_file_with_colon(self): | |||
| 253 | 257 | Diff._handle_diff_line(output, None, res) | |
| 254 | 258 | self.assertEqual(len(res), 3) | |
| 255 | 259 | ||
| 260 | + @with_rw_directory | ||
| 261 | + def test_diff_raw_paths_with_colon_or_line_feed(self, rw_dir): | ||
| 262 | + repo = Repo.init(rw_dir) | ||
| 263 | + binsha = repo.odb.store(IStream(Blob.type, 1, BytesIO(b"x"))).binsha | ||
| 264 | + fake_meta = ":100644 100644 %s %s M" % ("1" * 40, "2" * 40) | ||
| 265 | + paths = [":planted", "docs/a\n" + fake_meta, "docs/b", "setup.py"] | ||
| 266 | + repo.index.add([BaseIndexEntry((0o100644, binsha, 0, path)) for path in paths]) | ||
| 267 | + commit = repo.index.commit("paths") | ||
| 268 | + | ||
| 269 | + diffs = commit.diff(NULL_TREE) | ||
| 270 | + self.assertEqual([d.b_path for d in diffs], sorted(paths)) | ||
| 271 | + self.assertEqual({d.change_type for d in diffs}, {"A"}) | ||
| 272 | + | ||
| 256 | 273 | def test_empty_diff(self): | |
| 257 | 274 | res = [] | |
| 258 | 275 | Diff._handle_diff_line(b"", None, res) | |
| Back | FazBrowse Home | New Git URL |
0 commit comments