Skip to content

Commit a4034fd

Browse files
codexByron
authored andcommitted
feat(gix): read object headers with native lookup
Use GixPython's header lookup for `Git.get_object_header` and ODB metadata. Preserve the existing object-ID, kind and size tuple, missing-object behavior, and CLI diagnostics for unsupported storage or revision syntax. Keep the persistent-process lifecycle regressions explicitly exercising the CLI fallback. The staged version passes Ruff and Python syntax checks. Its SHA-1/SHA-256 native smoke and focused pytest selection pass: 10 passed in 4.34s.
1 parent 00a4808 commit a4034fd

3 files changed

Lines changed: 40 additions & 0 deletions

File tree

‎git/_backend.py‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from importlib import import_module
1010
import logging
1111
import os
12+
import re
1213
from threading import Lock
1314
from typing import Any, Callable, Dict, List, Sequence, Tuple
1415

@@ -84,6 +85,39 @@ def _repository(command: Any, env: Dict[str, Any], *, query_config: bool = False
8485
return repo
8586

8687

88+
def _oid(repo: Any, ref: Any) -> Any:
89+
ref = safe_decode(ref) if isinstance(ref, bytes) else str(ref)
90+
if re.fullmatch(r"[a-fA-F0-9]{40}|[a-fA-F0-9]{64}", ref):
91+
return gix.ObjectId(ref)
92+
if ref.startswith(":/") or "^{/" in ref or "-dirty" in ref or re.search(r"-\d+-g[0-9a-fA-F]+", ref):
93+
raise _Unsupported("revision grammar differences (GIX-17)")
94+
if not hasattr(repo, "rev_parse_single"):
95+
raise _Unsupported("revision feature disabled")
96+
return repo.rev_parse_single(ref)
97+
98+
99+
def object_data(command: Any, ref: bytes) -> Any:
100+
"""Use native object reads without changing the public cat-file interface."""
101+
if gix is None:
102+
return NotImplemented
103+
method = "get_object_header"
104+
command._require_version()
105+
try:
106+
repo = _repository(command, {})
107+
oid = _oid(repo, ref)
108+
header = repo.try_find_header(oid)
109+
if header is None:
110+
raise ValueError("SHA %s could not be resolved" % oid)
111+
result: Tuple[Any, ...] = (str(oid), header.kind(), header.size())
112+
except _Unsupported as exc:
113+
return _fallback(method, str(exc))
114+
except gix.Error as exc:
115+
_logger.debug("%s native read: %s", method, exc)
116+
return _fallback(method, "native read diagnostics")
117+
record(method, "native")
118+
return result
119+
120+
87121
_HANDLERS: Dict[str, Callable[[Any, List[str], Dict[str, Any]], bytes]] = {}
88122

89123

‎git/cmd.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,6 +2062,9 @@ def get_object_header(self, ref: Union[str, bytes]) -> Tuple[str, str, int]:
20622062
(hexsha, type_string, size_as_int)
20632063
"""
20642064
request = self._prepare_ref(ref)
2065+
native = _backend.object_data(self, request[:-1])
2066+
if native is not NotImplemented:
2067+
return native
20652068
cmd = self._get_persistent_cmd("cat_file_header", "cat_file", batch_check=True, Z=True)
20662069
return self.__get_object_header(cmd, request)
20672070

‎test/test_submodule.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ def test_submodule_rejects_checkout_and_gitmodules_symlinks(movable_submodule, t
590590

591591
def test_add_closes_checkout_processes(movable_submodule, monkeypatch):
592592
"""Adding a submodule must not leave a child process holding its checkout open."""
593+
# Native reads have no persistent process; keep exercising the CLI fallback.
594+
monkeypatch.setattr(git._backend, "object_data", lambda *args, **kwargs: NotImplemented)
593595
sm = movable_submodule
594596
checkout = Path(sm.repo.working_tree_dir, "new")
595597
execute = Git.execute
@@ -620,6 +622,7 @@ def capture_process(self, command, *args, **kwargs):
620622

621623
@pytest.mark.parametrize("operation", ["update", "error", "recursive", "keep-going"])
622624
def test_update_closes_checkout_processes_retained_by_logging(movable_submodule, monkeypatch, caplog, operation):
625+
monkeypatch.setattr(git._backend, "object_data", lambda *args, **kwargs: NotImplemented)
623626
sm = movable_submodule
624627
recursive = operation in ("recursive", "keep-going")
625628
with sm.module() as module:

0 commit comments

Comments
 (0)