Skip to content

Commit 80361a5

Browse files
committed
Complete ls_tree implementation and add chdir utility
- Finalized `ls_tree` method in the `Git` class to parse and list tree objects with detailed entry data. - Introduced `chdir` context manager to handle temporary directory changes. - Updated `write_tree` to include `tree` type in tree entries.
1 parent 782f29e commit 80361a5

2 files changed

Lines changed: 42 additions & 7 deletions

File tree

app/models/git.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
from os import PathLike
1010
from typing import Protocol
1111

12+
from app.utils import chdir
13+
1214
NULL_BYTE = b"\x00"
1315

1416

@@ -78,12 +80,6 @@ def hash_object(
7880
sys.stdout.write(hash_value)
7981
return hash_value
8082

81-
def ls_tree(self, hash_value: str, *, name_only: bool = False):
82-
path = self.objects_folder / hash_value[:2] / hash_value[2:]
83-
with path.open("rb") as f:
84-
data = zlib.decompress(f.read())
85-
raise NotImplementedError
86-
8783
def write_tree(self, directory=".") -> str:
8884
entries = []
8985
dir_path = pathlib.Path(directory)
@@ -105,7 +101,9 @@ def write_tree(self, directory=".") -> str:
105101
hash_value = self.write_tree(entry)
106102
# Convert hex string to binary
107103
hash_binary = binascii.unhexlify(hash_value)
108-
entries.append(f"{mode} {entry.name}".encode() + b"\0" + hash_binary)
104+
entries.append(
105+
f"{mode} tree {entry.name}".encode() + b"\0" + hash_binary
106+
)
109107

110108
# Combine all entries into a single tree object
111109
tree_content = b"".join(entries)
@@ -116,3 +114,28 @@ def write_tree(self, directory=".") -> str:
116114
tree_hash = self.create_hash(tree_store)
117115
self.save_file(tree_hash, tree_store)
118116
return tree_hash
117+
118+
def ls_tree(self, hash_value: str, *, name_only: bool = False):
119+
# Read and decompress the tree object
120+
entries = []
121+
122+
dir_name = self.objects_folder / hash_value[:2]
123+
with chdir(dir_name):
124+
file_name = pathlib.Path(hash_value[2:])
125+
with file_name.open("rb") as f:
126+
data = zlib.decompress(f.read())
127+
128+
header, _, tree_data = data.partition(NULL_BYTE)
129+
kind, data_len = header.decode().split()
130+
entry_data, _, raw_hash = tree_data.partition(NULL_BYTE)
131+
mode, entry_kind, name = entry_data.split()
132+
hash_value = binascii.hexlify(raw_hash).decode()
133+
134+
entry = {
135+
"mode": mode.decode(),
136+
"type": entry_kind.decode(),
137+
"name": name.decode(),
138+
"hash": hash_value,
139+
}
140+
entries.append(entry)
141+
return entry

app/utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import contextlib
2+
import os
13
import pathlib
24
from argparse import ArgumentParser
35

@@ -29,3 +31,13 @@ def get_parser():
2931
ls_tree_parser.add_argument("hash_value")
3032

3133
return parser
34+
35+
36+
@contextlib.contextmanager
37+
def chdir(path):
38+
old_path = os.getcwd()
39+
os.chdir(path)
40+
try:
41+
yield
42+
finally:
43+
os.chdir(old_path)

0 commit comments

Comments
 (0)