Merge upstream
[jelmer/dulwich-libgit2.git] / dulwich / protocol.py
1 # protocol.py -- Shared parts of the git protocols
2 # Copryight (C) 2008 John Carr <john.carr@unrouted.co.uk>
3 # Copyright (C) 2008 Jelmer Vernooij <jelmer@samba.org>
4 #
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; version 2
8 # of the License.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18 # MA  02110-1301, USA.
19
20 TCP_GIT_PORT = 9418
21
22 class Protocol(object):
23
24     def __init__(self, read, write):
25         self.read = read
26         self.write = write
27
28     def read_pkt_line(self):
29         """
30         Reads a 'pkt line' from the remote git process
31
32         :return: The next string from the stream
33         """
34         sizestr = self.read(4)
35         if not sizestr:
36             return None
37         size = int(sizestr, 16)
38         if size == 0:
39             return None
40         return self.read(size-4)
41
42     def read_pkt_seq(self):
43         pkt = self.read_pkt_line()
44         while pkt:
45             yield pkt
46             pkt = self.read_pkt_line()
47
48     def write_pkt_line(self, line):
49         """
50         Sends a 'pkt line' to the remote git process
51
52         :param line: A string containing the data to send
53         """
54         if line is None:
55             self.write("0000")
56         else:
57             self.write("%04x%s" % (len(line)+4, line))
58
59     def write_sideband(self, channel, blob):
60         """
61         Write data to the sideband (a git multiplexing method)
62
63         :param channel: int specifying which channel to write to
64         :param blob: a blob of data (as a string) to send on this channel
65         """
66         # a pktline can be a max of 65535. a sideband line can therefore be
67         # 65535-5 = 65530
68         # WTF: Why have the len in ASCII, but the channel in binary.
69         while blob:
70             self.write_pkt_line("%s%s" % (chr(channel), blob[:65530]))
71             blob = blob[65530:]
72
73     def send_cmd(self, cmd, *args):
74         """
75         Send a command and some arguments to a git server
76
77         Only used for git://
78
79         :param cmd: The remote service to access
80         :param args: List of arguments to send to remove service
81         """
82         self.proto.write_pkt_line("%s %s" % (name, "".join(["%s\0" % a for a in args])))
83
84     def read_cmd(self):
85         """
86         Read a command and some arguments from the git client
87
88         Only used for git://
89
90         :return: A tuple of (command, [list of arguments])
91         """
92         line = self.read_pkt_line()
93         splice_at = line.find(" ")
94         cmd, args = line[:splice_at], line[splice_at+1:]
95         return cmd, args.split(chr(0))
96  
97
98 def extract_capabilities(text):
99     if not "\0" in text:
100         return text
101     capabilities = text.split("\0")
102     return (capabilities[0], capabilities[1:])
103