Skip to content

Commit 4f85afa

Browse files
committed
Refactor ls_tree to use _parse_tree_content for cleaner tree content parsing
- Introduced `_parse_tree_content` method to modularize tree object parsing using regex. - Updated `ls_tree` to leverage `_parse_tree_content`, improving readability and maintainability. - Adjusted `--name-only` logic to decode and display file names correctly.
1 parent 08870cf commit 4f85afa

1 file changed

Lines changed: 19 additions & 23 deletions

File tree

app/models/git.py

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import binascii
22
import hashlib
33
import pathlib
4+
import re
45
import sys
56
import zlib
67
from enum import StrEnum, auto
78

89
__all__ = ["Git"]
910

1011
from os import PathLike
11-
12+
from typing import Iterator
1213

1314
NULL_BYTE = b"\x00"
1415

@@ -139,6 +140,21 @@ def create_tree(
139140
self.save_file(tree_hash, tree_store)
140141
return tree_hash
141142

143+
@staticmethod
144+
def _parse_tree_content(content: bytes) -> Iterator[dict[str, bytes]]:
145+
pattern = re.compile(
146+
rb"""
147+
(?P<mode>\d+)
148+
\s
149+
(?P<file_name>[^\x00]+)
150+
\x00
151+
(?P<raw_hash>.{20})
152+
""",
153+
re.VERBOSE,
154+
)
155+
for match in pattern.finditer(content):
156+
yield match.groupdict()
157+
142158
def ls_tree(self, hash_value: str, *, name_only: bool = False):
143159
object_path = self.objects_folder / hash_value[:2] / hash_value[2:]
144160
with object_path.open("rb") as f:
@@ -149,28 +165,8 @@ def ls_tree(self, hash_value: str, *, name_only: bool = False):
149165
if not header.startswith(b"tree "):
150166
raise ValueError(f"Not a tree object: {header}")
151167
# 3. Parse entries
152-
entries = []
153-
pos = 0
154-
while pos < len(content):
155-
# Find the null byte that separates entry info from hash
156-
null_pos = content.index(b"\0", pos)
157-
158-
# Parse entry text (contains mode, type, and name)
159-
entry_text = content[pos:null_pos].decode()
160-
mode, name = entry_text.split(" ")
161-
162-
# Extract 20-byte hash and convert to hex
163-
hash_start = null_pos + 1
164-
hash_end = hash_start + 20 # SHA-1 hash is 20 bytes
165-
hash_bytes = content[hash_start:hash_end]
166-
hash_hex = binascii.hexlify(hash_bytes).decode()
167-
168-
# Add entry to list
169-
entries.append({"mode": mode, "name": name, "hash": hash_hex})
170-
171-
# Move to next entry
172-
pos = hash_end
168+
entries = list(self._parse_tree_content(content))
173169
if name_only:
174170
for entry in entries:
175-
print(entry["name"])
171+
print(entry["file_name"].decode())
176172
return entries

0 commit comments

Comments
 (0)