Skip to content

Commit d4834b5

Browse files
committed
Add hash-object support to Git class and update CLI parser logic
- Implemented `hash_object` method in the `Git` class with optional write functionality. - Updated CLI parser to include `hash-object` command with `-w` flag support. - Enhanced `create_blob` to conditionally write object files. - Added unit tests for `hash_object` and updated parser tests accordingly. - Refactored `change_to_tmp_dir` fixture to return the temporary directory path.
1 parent 68e03a3 commit d4834b5

5 files changed

Lines changed: 52 additions & 11 deletions

File tree

app/main.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ def main():
1111
return git.init_repo()
1212
case "cat-file":
1313
return git.cat_file(args.hash, pretty_print=args.pretty_print)
14+
case "hash-object":
15+
return git.hash_object(args.path, write=args.write)
1416
case _:
1517
raise RuntimeError(f"Unknown command #{args.command}")
1618

app/models/git.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
__all__ = ["Git"]
66

7+
from app.utils import create_blob
8+
79
NULL_BYTE = b"\x00"
810

911

@@ -30,3 +32,9 @@ def cat_file(cls, hash_: str, *, pretty_print: bool = False):
3032
if pretty_print:
3133
sys.stdout.write(body.decode())
3234
return Blob(header=header, body=body)
35+
36+
@classmethod
37+
def hash_object(cls, path: pathlib.Path, *, write: bool = False):
38+
with path.open("r") as f:
39+
hash_value = create_blob(f.read(), write=write)
40+
return hash_value

app/utils.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ def get_parser():
1818
cat_file_parser.add_argument(
1919
"hash",
2020
)
21+
22+
# hash_object
23+
hash_object_parser = subparsers.add_parser("hash-object")
24+
hash_object_parser.add_argument("path", type=pathlib.Path)
25+
hash_object_parser.add_argument("-w", "--write", action="store_true")
2126
return parser
2227

2328

24-
def create_blob(content: str) -> str:
29+
def create_blob(content: str, *, write: bool = True) -> str:
2530
# Format the blob object
2631
blob = f"blob {len(content)}\0{content}"
2732
# Convert to bytes
@@ -35,13 +40,11 @@ def create_blob(content: str) -> str:
3540
hash_object = hashlib.sha1(blob_bytes)
3641
hash_value = hash_object.hexdigest()
3742

38-
# Create directory structure
39-
path = pathlib.Path(".git/objects", hash_value[:2])
40-
path.mkdir(exist_ok=True)
43+
if write:
44+
# Create directory structure
45+
path = pathlib.Path(".git/objects", hash_value[:2])
46+
path.mkdir(exist_ok=True)
4147

42-
with (path / hash_value[2:]).open("wb") as f:
43-
f.write(compressed)
44-
# Write the compressed blob
45-
# with open(path / hash_value[2:], 'wb') as f:
46-
# f.write(compressed)
48+
with (path / hash_value[2:]).open("wb") as f:
49+
f.write(compressed)
4750
return hash_value

tests/test_git.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
from app.main import Git
77
from app.utils import create_blob
88

9+
910
@pytest.fixture
1011
def change_to_tmp_dir(tmp_path):
1112
with contextlib.chdir(tmp_path):
12-
yield
13+
yield tmp_path
1314

1415

1516
class TestGit:
@@ -29,6 +30,20 @@ def test_cat_file(self, change_to_tmp_dir):
2930
assert blob.header == f"blob {len(blob.body)}".encode()
3031
assert blob.body == b"some content"
3132

32-
def test_hash_object(self, change_to_tmp_dir):
33+
@pytest.mark.parametrize("write", [True, False])
34+
@pytest.mark.parametrize(
35+
"content, expected_hash_value",
36+
[("hello world\n", "3b18e512dba79e4c8300dd08aeb37f8e728b8dad")],
37+
)
38+
def test_hash_object(self, change_to_tmp_dir, content, expected_hash_value, write):
3339
git = Git()
3440
git.init_repo()
41+
tmp_file = change_to_tmp_dir / "file.txt"
42+
tmp_file.write_text(content)
43+
hash_value = git.hash_object(tmp_file, write=write)
44+
assert hash_value == expected_hash_value
45+
assert len(hash_value) == 40
46+
expected_path = (
47+
change_to_tmp_dir / ".git/objects" / hash_value[:2] / hash_value[2:]
48+
)
49+
assert expected_path.exists() == write

tests/test_utils.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import pathlib
12
from argparse import Namespace
23

34
import pytest
@@ -17,6 +18,18 @@
1718
["cat-file", "-p", "some_hash"],
1819
Namespace(command="cat-file", hash="some_hash", pretty_print=True),
1920
),
21+
(
22+
["hash-object", "some_file.txt"],
23+
Namespace(
24+
command="hash-object", path=pathlib.Path("some_file.txt"), write=False
25+
),
26+
),
27+
(
28+
["hash-object", "-w", "some_file.txt"],
29+
Namespace(
30+
command="hash-object", path=pathlib.Path("some_file.txt"), write=True
31+
),
32+
),
2033
],
2134
)
2235
def test_parser(params, expected):

0 commit comments

Comments
 (0)