Changeset 3cae0be3e824…
Parent b0f69d1c8f96…
by
Changes to 3 files · Browse files at 3cae0be3e824 Showing diff from parent b0f69d1c8f96 Diff from another changeset...
@@ -7,6 +7,9 @@ * Repo.do_commit has a new argument 'merge_heads'. (Jelmer Vernooij)
* New ``Repo.clone`` method. (Jelmer Vernooij, #725369)
+
+ * ``GitClient.send_pack`` now supports the 'side-band-64k' capability.
+ (Jelmer Vernooij)
CHANGES
|
|
|
@@ -32,6 +32,7 @@ UpdateRefsError,
)
from dulwich.protocol import (
+ PktLineParser,
Protocol,
TCP_GIT_PORT,
ZERO_SHA,
@@ -52,8 +53,8 @@ """Check if a file descriptor is readable."""
return len(select.select([fileno], [], [], 0)[0]) > 0
-COMMON_CAPABILITIES = ['ofs-delta']
-FETCH_CAPABILITIES = ['multi_ack', 'side-band-64k'] + COMMON_CAPABILITIES
+COMMON_CAPABILITIES = ['ofs-delta', 'side-band-64k']
+FETCH_CAPABILITIES = ['multi_ack'] + COMMON_CAPABILITIES
SEND_CAPABILITIES = ['report-status'] + COMMON_CAPABILITIES
@@ -117,7 +118,7 @@
# TODO(durin42): this doesn't correctly degrade if the server doesn't
# support some capabilities. This should work properly with servers
-# that don't support side-band-64k and multi_ack.
+# that don't support multi_ack.
class GitClient(object):
"""Git smart server client.
@@ -163,19 +164,14 @@ refs[ref] = sha
return refs, server_capabilities
- def _parse_status_report(self, proto):
- report_status_parser = ReportStatusParser()
- for pkt in proto.read_pkt_seq():
- report_status_parser.handle_packet(pkt)
- report_status_parser.check()
-
- # TODO(durin42): add side-band-64k capability support here and advertise it
- def send_pack(self, path, determine_wants, generate_pack_contents):
+ def send_pack(self, path, determine_wants, generate_pack_contents,
+ progress=None):
"""Upload a pack to a remote repository.
:param path: Repository path
:param generate_pack_contents: Function that can return a sequence of the
shas of the objects to upload.
+ :param progress: Optional callback called with progress updates
:raises SendPackError: if server rejects the pack data
:raises UpdateRefsError: if the server supports report-status
@@ -183,8 +179,9 @@ """
proto, unused_can_read = self._connect('receive-pack', path)
old_refs, server_capabilities = self._read_refs(proto)
+ negotiated_capabilities = list(self._send_capabilities)
if 'report-status' not in server_capabilities:
- self._send_capabilities.remove('report-status')
+ negotiated_capabilities.remove('report-status')
new_refs = determine_wants(old_refs)
if not new_refs:
proto.write_pkt_line(None)
@@ -202,7 +199,7 @@ else:
proto.write_pkt_line(
'%s %s %s\0%s' % (old_sha1, new_sha1, refname,
- ' '.join(self._send_capabilities)))
+ ' '.join(negotiated_capabilities)))
sent_capabilities = True
if new_sha1 not in have and new_sha1 != ZERO_SHA:
want.append(new_sha1)
@@ -211,9 +208,22 @@ return new_refs
objects = generate_pack_contents(have, want)
entries, sha = write_pack_objects(proto.write_file(), objects)
-
- if 'report-status' in self._send_capabilities:
- self._parse_status_report(proto)
+ if 'report-status' in negotiated_capabilities:
+ report_status_parser = ReportStatusParser()
+ else:
+ report_status_parser = None
+ if "side-band-64k" in negotiated_capabilities:
+ channel_callbacks = { 2: progress }
+ if 'report-status' in negotiated_capabilities:
+ channel_callbacks[1] = PktLineParser(
+ report_status_parser.handle_packet).parse
+ self._read_side_band64k_data(proto, channel_callbacks)
+ else:
+ if 'report-status':
+ for pkt in proto.read_pkt_seq():
+ report_status_parser.handle_packet(pkt)
+ if report_status_parser is not None:
+ report_status_parser.check()
# wait for EOF before returning
data = proto.read()
if data:
@@ -240,7 +250,7 @@ commit()
def fetch_pack(self, path, determine_wants, graph_walker, pack_data,
- progress):
+ progress=None):
"""Retrieve a pack from a git smart server.
:param determine_wants: Callback that returns list of commits to fetch
@@ -250,13 +260,14 @@ """
proto, can_read = self._connect('upload-pack', path)
(refs, server_capabilities) = self._read_refs(proto)
+ negotiated_capabilities = list(self._fetch_capabilities)
wants = determine_wants(refs)
if not wants:
proto.write_pkt_line(None)
return refs
assert isinstance(wants, list) and type(wants[0]) == str
proto.write_pkt_line('want %s %s\n' % (
- wants[0], ' '.join(self._fetch_capabilities)))
+ wants[0], ' '.join(negotiated_capabilities)))
for want in wants[1:]:
proto.write_pkt_line('want %s\n' % want)
proto.write_pkt_line(None)
@@ -279,19 +290,36 @@ if len(parts) < 3 or parts[2] != 'continue':
break
pkt = proto.read_pkt_line()
- # TODO(durin42): this is broken if the server didn't support the
- # side-band-64k capability.
+ if "side-band-64k" in negotiated_capabilities:
+ self._read_side_band64k_data(proto, {1: pack_data, 2: progress})
+ # wait for EOF before returning
+ data = proto.read()
+ if data:
+ raise Exception('Unexpected response %r' % data)
+ else:
+ # FIXME: Buffering?
+ pack_data(self.read())
+ return refs
+
+ def _read_side_band64k_data(self, proto, channel_callbacks):
+ """Read per-channel data.
+
+ This requires the side-band-64k capability.
+
+ :param proto: Protocol object to read from
+ :param channel_callbacks: Dictionary mapping channels to packet
+ handlers to use. None for a callback discards channel data.
+ """
for pkt in proto.read_pkt_seq():
channel = ord(pkt[0])
pkt = pkt[1:]
- if channel == 1:
- pack_data(pkt)
- elif channel == 2:
- if progress is not None:
- progress(pkt)
+ try:
+ cb = channel_callbacks[channel]
+ except KeyError:
+ raise AssertionError('Invalid sideband channel %d' % channel)
else:
- raise AssertionError('Invalid sideband channel %d' % channel)
- return refs
+ if cb is not None:
+ cb(pkt)
class TCPGitClient(GitClient):
|
@@ -63,7 +63,7 @@ self.assertEquals(set(['multi_ack', 'side-band-64k', 'ofs-delta',
'thin-pack']),
set(self.client._fetch_capabilities))
- self.assertEquals(set(['ofs-delta', 'report-status']),
+ self.assertEquals(set(['ofs-delta', 'report-status', 'side-band-64k']),
set(self.client._send_capabilities))
def test_fetch_pack_none(self):
|
Loading...