Skip to content

Commit 5ff52cc

Browse files
authored
Merge pull request #2209 from caroescm/fix-index-add-chmod
index: write blobs via git hash-object, not gitdb's odb.store
2 parents 9729ed3 + 93677a0 commit 5ff52cc

3 files changed

Lines changed: 41 additions & 3 deletions

File tree

git/db.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,14 @@
55

66
__all__ = ["GitCmdObjectDB", "GitDB"]
77

8-
from gitdb.base import OInfo, OStream
8+
from subprocess import PIPE
9+
10+
from gitdb.base import IStream, OInfo, OStream
911
from gitdb.db import GitDB, LooseObjectDB
1012
from gitdb.exc import BadObject
13+
from gitdb.fun import stream_copy
1114

15+
from git.compat import force_text
1216
from git.util import bin_to_hex, hex_to_bin
1317
from git.exc import GitCommandError
1418

@@ -46,6 +50,25 @@ def stream(self, binsha: bytes) -> OStream:
4650
hexsha, typename, size, stream = self._git.stream_object_data(bin_to_hex(binsha))
4751
return OStream(hex_to_bin(hexsha), typename, size, stream)
4852

53+
def store(self, istream: IStream) -> IStream:
54+
"""Store an object using git itself."""
55+
if istream.binsha is not None or self.ostream() is not None:
56+
return super().store(istream)
57+
58+
proc = self._git.hash_object(
59+
"-t", force_text(istream.type), "-w", "--stdin", "--literally", as_process=True, istream=PIPE
60+
)
61+
assert proc.stdin is not None
62+
try:
63+
stream_copy(istream.read, proc.stdin.write, istream.size, self.stream_chunk_size)
64+
finally:
65+
proc.stdin.close()
66+
assert proc.stdout is not None
67+
hexsha = proc.stdout.read().strip()
68+
proc.wait()
69+
istream.binsha = hex_to_bin(hexsha)
70+
return istream
71+
4972
# { Interface
5073

5174
def partial_to_complete_sha_hex(self, partial_hexsha: str) -> bytes:

test/test_db.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,30 @@
33
# This module is part of GitPython and is released under the
44
# 3-Clause BSD License: https://opensource.org/license/bsd-3-clause/
55

6+
from io import BytesIO
67
import os.path as osp
8+
from unittest import mock
9+
10+
from gitdb import IStream
11+
from gitdb.db import LooseObjectDB
12+
from gitdb.typ import str_blob_type
713

814
from git.db import GitCmdObjectDB
915
from git.exc import BadObject
1016
from git.util import bin_to_hex
1117

12-
from test.lib import TestBase
18+
from test.lib import TestBase, with_rw_repo
1319

1420

1521
class TestDB(TestBase):
22+
@with_rw_repo("HEAD")
23+
def test_store_uses_hash_object(self, rw_repo):
24+
data = b"hello world"
25+
with mock.patch.object(LooseObjectDB, "store", side_effect=AssertionError("unexpected loose-object write")):
26+
istream = rw_repo.odb.store(IStream(str_blob_type, len(data), BytesIO(data)))
27+
28+
assert rw_repo.odb.stream(istream.binsha).read() == data
29+
1630
def test_base(self):
1731
gdb = GitCmdObjectDB(osp.join(self.rorepo.git_dir, "objects"), self.rorepo.git)
1832

test/test_refs.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
from git.exc import UnsafeOptionError
2727
from git.objects.tag import TagObject
2828
import git.refs as refs
29-
from git.util import Actor
29+
from git.util import Actor, rmtree
3030

3131
from test.lib import TestBase, requires_symlinks, with_rw_repo, PathLikeMock
3232

@@ -43,6 +43,7 @@ def _repo_with_initial_commit(self, base_dir):
4343
yield repo
4444
finally:
4545
repo.git.clear_cache()
46+
rmtree(repo_dir)
4647

4748
def test_from_path(self):
4849
# Should be able to create any reference directly.

0 commit comments

Comments
 (0)