##// END OF EJS Templates
bundle2: clarify stream parameter design in the documentation...
Pierre-Yves David -
r20808:4c9130c7 default
parent child Browse files
Show More
@@ -1,168 +1,175 b''
1 # bundle2.py - generic container format to transmit arbitrary data.
1 # bundle2.py - generic container format to transmit arbitrary data.
2 #
2 #
3 # Copyright 2013 Facebook, Inc.
3 # Copyright 2013 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 """Handling of the new bundle2 format
7 """Handling of the new bundle2 format
8
8
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
10 payloads in an application agnostic way. It consist in a sequence of "parts"
10 payloads in an application agnostic way. It consist in a sequence of "parts"
11 that will be handed to and processed by the application layer.
11 that will be handed to and processed by the application layer.
12
12
13
13
14 General format architecture
14 General format architecture
15 ===========================
15 ===========================
16
16
17 The format is architectured as follow
17 The format is architectured as follow
18
18
19 - magic string
19 - magic string
20 - stream level parameters
20 - stream level parameters
21 - payload parts (any number)
21 - payload parts (any number)
22 - end of stream marker.
22 - end of stream marker.
23
23
24 The current implementation accept some stream level option but no part.
24 The current implementation accept some stream level option but no part.
25
25
26 Details on the Binary format
26 Details on the Binary format
27 ============================
27 ============================
28
28
29 All numbers are unsigned and big endian.
29 All numbers are unsigned and big endian.
30
30
31 stream level parameters
31 stream level parameters
32 ------------------------
32 ------------------------
33
33
34 Binary format is as follow
34 Binary format is as follow
35
35
36 :params size: (16 bits integer)
36 :params size: (16 bits integer)
37
37
38 The total number of Bytes used by the parameters
38 The total number of Bytes used by the parameters
39
39
40 :params value: arbitrary number of Bytes
40 :params value: arbitrary number of Bytes
41
41
42 A blob of `params size` containing the serialized version of all stream level
42 A blob of `params size` containing the serialized version of all stream level
43 parameters.
43 parameters.
44
44
45 The blob contains a space separated list of parameters.
45 The blob contains a space separated list of parameters.
46
46
47 Parameter value are not supported yet.
47 Parameter value are not supported yet.
48
48
49 Special character in param name are not supported yet.
49 Special character in param name are not supported yet.
50
50
51 Stream parameters use a simple textual format for two main reasons:
51
52
53 - Stream level parameters should remains simple and we want to discourage any
54 crazy usage.
55 - Textual data allow easy human inspection of a the bundle2 header in case of
56 troubles.
57
58 Any Applicative level options MUST go into a bundle2 part instead.
52
59
53
60
54 Payload part
61 Payload part
55 ------------------------
62 ------------------------
56
63
57 Binary format is as follow
64 Binary format is as follow
58
65
59 :header size: (16 bits inter)
66 :header size: (16 bits inter)
60
67
61 The total number of Bytes used by the part headers. When the header is empty
68 The total number of Bytes used by the part headers. When the header is empty
62 (size = 0) this is interpreted as the end of stream marker.
69 (size = 0) this is interpreted as the end of stream marker.
63
70
64 Currently forced to 0 in the current state of the implementation
71 Currently forced to 0 in the current state of the implementation
65 """
72 """
66
73
67 import util
74 import util
68 import struct
75 import struct
69
76
70 import changegroup
77 import changegroup
71 from i18n import _
78 from i18n import _
72
79
73 _pack = struct.pack
80 _pack = struct.pack
74 _unpack = struct.unpack
81 _unpack = struct.unpack
75
82
76 _magicstring = 'HG20'
83 _magicstring = 'HG20'
77
84
78 _fstreamparamsize = '>H'
85 _fstreamparamsize = '>H'
79
86
80 class bundle20(object):
87 class bundle20(object):
81 """represent an outgoing bundle2 container
88 """represent an outgoing bundle2 container
82
89
83 Use the `addparam` method to add stream level parameter. Then call
90 Use the `addparam` method to add stream level parameter. Then call
84 `getchunks` to retrieve all the binary chunks of datathat compose the
91 `getchunks` to retrieve all the binary chunks of datathat compose the
85 bundle2 container.
92 bundle2 container.
86
93
87 This object does not support payload part yet."""
94 This object does not support payload part yet."""
88
95
89 def __init__(self):
96 def __init__(self):
90 self._params = []
97 self._params = []
91 self._parts = []
98 self._parts = []
92
99
93 def addparam(self, name, value=None):
100 def addparam(self, name, value=None):
94 """add a stream level parameter"""
101 """add a stream level parameter"""
95 self._params.append((name, value))
102 self._params.append((name, value))
96
103
97 def getchunks(self):
104 def getchunks(self):
98 yield _magicstring
105 yield _magicstring
99 param = self._paramchunk()
106 param = self._paramchunk()
100 yield _pack(_fstreamparamsize, len(param))
107 yield _pack(_fstreamparamsize, len(param))
101 if param:
108 if param:
102 yield param
109 yield param
103
110
104 # no support for parts
111 # no support for parts
105 # to be obviously fixed soon.
112 # to be obviously fixed soon.
106 assert not self._parts
113 assert not self._parts
107 yield '\0\0'
114 yield '\0\0'
108
115
109 def _paramchunk(self):
116 def _paramchunk(self):
110 """return a encoded version of all stream parameters"""
117 """return a encoded version of all stream parameters"""
111 blocks = []
118 blocks = []
112 for key, value in self._params:
119 for key, value in self._params:
113 # XXX no support for value yet
120 # XXX no support for value yet
114 assert value is None
121 assert value is None
115 # XXX no escaping yet
122 # XXX no escaping yet
116 blocks.append(key)
123 blocks.append(key)
117 return ' '.join(blocks)
124 return ' '.join(blocks)
118
125
119 class unbundle20(object):
126 class unbundle20(object):
120 """interpret a bundle2 stream
127 """interpret a bundle2 stream
121
128
122 (this will eventually yield parts)"""
129 (this will eventually yield parts)"""
123
130
124 def __init__(self, fp):
131 def __init__(self, fp):
125 self._fp = fp
132 self._fp = fp
126 header = self._readexact(4)
133 header = self._readexact(4)
127 magic, version = header[0:2], header[2:4]
134 magic, version = header[0:2], header[2:4]
128 if magic != 'HG':
135 if magic != 'HG':
129 raise util.Abort(_('not a Mercurial bundle'))
136 raise util.Abort(_('not a Mercurial bundle'))
130 if version != '20':
137 if version != '20':
131 raise util.Abort(_('unknown bundle version %s') % version)
138 raise util.Abort(_('unknown bundle version %s') % version)
132
139
133 def _unpack(self, format):
140 def _unpack(self, format):
134 """unpack this struct format from the stream"""
141 """unpack this struct format from the stream"""
135 data = self._readexact(struct.calcsize(format))
142 data = self._readexact(struct.calcsize(format))
136 return _unpack(format, data)
143 return _unpack(format, data)
137
144
138 def _readexact(self, size):
145 def _readexact(self, size):
139 """read exactly <size> bytes from the stream"""
146 """read exactly <size> bytes from the stream"""
140 return changegroup.readexactly(self._fp, size)
147 return changegroup.readexactly(self._fp, size)
141
148
142 @util.propertycache
149 @util.propertycache
143 def params(self):
150 def params(self):
144 """dictionnary of stream level parameters"""
151 """dictionnary of stream level parameters"""
145 params = {}
152 params = {}
146 paramssize = self._unpack(_fstreamparamsize)[0]
153 paramssize = self._unpack(_fstreamparamsize)[0]
147 if paramssize:
154 if paramssize:
148 for p in self._readexact(paramssize).split(' '):
155 for p in self._readexact(paramssize).split(' '):
149 params[p] = None
156 params[p] = None
150 return params
157 return params
151
158
152 def __iter__(self):
159 def __iter__(self):
153 """yield all parts contained in the stream"""
160 """yield all parts contained in the stream"""
154 # make sure param have been loaded
161 # make sure param have been loaded
155 self.params
162 self.params
156 part = self._readpart()
163 part = self._readpart()
157 while part is not None:
164 while part is not None:
158 yield part
165 yield part
159 part = self._readpart()
166 part = self._readpart()
160
167
161 def _readpart(self):
168 def _readpart(self):
162 """return None when an end of stream markers is reach"""
169 """return None when an end of stream markers is reach"""
163 headersize = self._readexact(2)
170 headersize = self._readexact(2)
164 assert headersize == '\0\0'
171 assert headersize == '\0\0'
165 return None
172 return None
166
173
167
174
168
175
General Comments 0
You need to be logged in to leave comments. Login now