@@ -203,9 +203,57 @@ def send_want_request(self):
203203 with urlopen (request ) as response :
204204 data = response .read ()
205205
206- if data .startswith (b"0008NAK\n " ):
207- return data [8 :]
208- return data
206+ return self ._extract_pack_data (data )
207+
208+ @staticmethod
209+ def _extract_pack_data (data : bytes ) -> bytes :
210+ """Extract pack data from sideband-encoded response."""
211+ offset = 0
212+ pack_data = b""
213+
214+ while offset < len (data ):
215+ # Read 4-byte hex length
216+ pkt_len_hex = data [offset :offset + 4 ]
217+ if len (pkt_len_hex ) < 4 :
218+ break
219+
220+ # Check if this looks like a hex length or raw PACK data
221+ try :
222+ pkt_len = int (pkt_len_hex , 16 )
223+ except ValueError :
224+ # Not hex - might be raw PACK data (no sideband)
225+ if data [offset :offset + 4 ] == b"PACK" :
226+ return data [offset :]
227+ break
228+
229+ if pkt_len == 0 : # flush packet
230+ offset += 4
231+ break # end of response
232+
233+ # Get packet content (excluding length prefix)
234+ pkt_content = data [offset + 4 :offset + pkt_len ]
235+ offset += pkt_len
236+
237+ # Check for NAK/ACK lines
238+ if pkt_content .startswith (b"NAK" ):
239+ continue
240+ if pkt_content .startswith (b"ACK" ):
241+ continue
242+
243+ # Check for sideband channel byte
244+ if len (pkt_content ) > 0 :
245+ channel = pkt_content [0 ]
246+ if channel == 1 : # pack data channel
247+ pack_data += pkt_content [1 :]
248+ elif channel == 2 : # progress channel
249+ continue
250+ elif channel == 3 : # error channel
251+ raise RuntimeError (f"Server error: { pkt_content [1 :].decode ()} " )
252+ elif pkt_content .startswith (b"PACK" ):
253+ # No sideband, raw pack data starting in this packet
254+ return pkt_content
255+
256+ return pack_data
209257
210258 def parse_pack_header (self , data : bytes ) -> PackHeader :
211259 """Parse pack file header, return (version, num_objects)."""
@@ -375,29 +423,3 @@ def checkout(self, tree_sha: str, objects: dict[str, PackObject], dest: Path):
375423 elif obj .type == OBJ_TREE :
376424 path .mkdir (exist_ok = True )
377425 self .checkout (sha1 , objects , path )
378-
379-
380- if __name__ == "__main__" :
381- work_dir = Path ("/tmp/test-clone" )
382- git_dir = work_dir / ".git"
383- git_dir .mkdir (parents = True , exist_ok = True )
384-
385- with GitClone (DEFAULT_URL ) as clone :
386- pack_data = clone .send_want_request ()
387- pack_header = clone .parse_pack_header (pack_data )
388- objects = clone .parse_pack_objects (pack_data , pack_header .num_objects )
389- stored = clone .store_objects (objects , git_dir )
390-
391- # Find HEAD commit and checkout
392- head_sha = clone .refs ["HEAD" ].sha1
393- commit_obj = stored [head_sha ]
394- commit_info = clone .parse_commit (commit_obj .data )
395- tree_sha = commit_info ["tree" ]
396-
397- clone .checkout (tree_sha , stored , work_dir )
398-
399- print (f"Cloned to { work_dir } " )
400- print (f"Files:" )
401- for f in work_dir .iterdir ():
402- if f .name != ".git" :
403- print (f" { f .name } " )
0 commit comments