##// END OF EJS Templates
wireprotov2: let clients drive delta behavior...
Gregory Szorc -
r39677:aa7e3123 default
parent child Browse files
Show More
@@ -1,394 +1,396
1 1 # exchangev2.py - repository exchange for wire protocol version 2
2 2 #
3 3 # Copyright 2018 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import collections
11 11 import weakref
12 12
13 13 from .i18n import _
14 14 from .node import (
15 15 nullid,
16 16 short,
17 17 )
18 18 from . import (
19 19 bookmarks,
20 20 error,
21 21 mdiff,
22 22 phases,
23 23 pycompat,
24 24 setdiscovery,
25 25 )
26 26
27 27 def pull(pullop):
28 28 """Pull using wire protocol version 2."""
29 29 repo = pullop.repo
30 30 remote = pullop.remote
31 31 tr = pullop.trmanager.transaction()
32 32
33 33 # Figure out what needs to be fetched.
34 34 common, fetch, remoteheads = _pullchangesetdiscovery(
35 35 repo, remote, pullop.heads, abortwhenunrelated=pullop.force)
36 36
37 37 # And fetch the data.
38 38 pullheads = pullop.heads or remoteheads
39 39 csetres = _fetchchangesets(repo, tr, remote, common, fetch, pullheads)
40 40
41 41 # New revisions are written to the changelog. But all other updates
42 42 # are deferred. Do those now.
43 43
44 44 # Ensure all new changesets are draft by default. If the repo is
45 45 # publishing, the phase will be adjusted by the loop below.
46 46 if csetres['added']:
47 47 phases.registernew(repo, tr, phases.draft, csetres['added'])
48 48
49 49 # And adjust the phase of all changesets accordingly.
50 50 for phase in phases.phasenames:
51 51 if phase == b'secret' or not csetres['nodesbyphase'][phase]:
52 52 continue
53 53
54 54 phases.advanceboundary(repo, tr, phases.phasenames.index(phase),
55 55 csetres['nodesbyphase'][phase])
56 56
57 57 # Write bookmark updates.
58 58 bookmarks.updatefromremote(repo.ui, repo, csetres['bookmarks'],
59 59 remote.url(), pullop.gettransaction,
60 60 explicit=pullop.explicitbookmarks)
61 61
62 62 manres = _fetchmanifests(repo, tr, remote, csetres['manifestnodes'])
63 63
64 64 # Find all file nodes referenced by added manifests and fetch those
65 65 # revisions.
66 66 fnodes = _derivefilesfrommanifests(repo, manres['added'])
67 67 _fetchfiles(repo, tr, remote, fnodes, manres['linkrevs'])
68 68
69 69 def _pullchangesetdiscovery(repo, remote, heads, abortwhenunrelated=True):
70 70 """Determine which changesets need to be pulled."""
71 71
72 72 if heads:
73 73 knownnode = repo.changelog.hasnode
74 74 if all(knownnode(head) for head in heads):
75 75 return heads, False, heads
76 76
77 77 # TODO wire protocol version 2 is capable of more efficient discovery
78 78 # than setdiscovery. Consider implementing something better.
79 79 common, fetch, remoteheads = setdiscovery.findcommonheads(
80 80 repo.ui, repo, remote, abortwhenunrelated=abortwhenunrelated)
81 81
82 82 common = set(common)
83 83 remoteheads = set(remoteheads)
84 84
85 85 # If a remote head is filtered locally, put it back in the common set.
86 86 # See the comment in exchange._pulldiscoverychangegroup() for more.
87 87
88 88 if fetch and remoteheads:
89 89 nodemap = repo.unfiltered().changelog.nodemap
90 90
91 91 common |= {head for head in remoteheads if head in nodemap}
92 92
93 93 if set(remoteheads).issubset(common):
94 94 fetch = []
95 95
96 96 common.discard(nullid)
97 97
98 98 return common, fetch, remoteheads
99 99
100 100 def _fetchchangesets(repo, tr, remote, common, fetch, remoteheads):
101 101 # TODO consider adding a step here where we obtain the DAG shape first
102 102 # (or ask the server to slice changesets into chunks for us) so that
103 103 # we can perform multiple fetches in batches. This will facilitate
104 104 # resuming interrupted clones, higher server-side cache hit rates due
105 105 # to smaller segments, etc.
106 106 with remote.commandexecutor() as e:
107 107 objs = e.callcommand(b'changesetdata', {
108 108 b'noderange': [sorted(common), sorted(remoteheads)],
109 109 b'fields': {b'bookmarks', b'parents', b'phase', b'revision'},
110 110 }).result()
111 111
112 112 # The context manager waits on all response data when exiting. So
113 113 # we need to remain in the context manager in order to stream data.
114 114 return _processchangesetdata(repo, tr, objs)
115 115
116 116 def _processchangesetdata(repo, tr, objs):
117 117 repo.hook('prechangegroup', throw=True,
118 118 **pycompat.strkwargs(tr.hookargs))
119 119
120 120 urepo = repo.unfiltered()
121 121 cl = urepo.changelog
122 122
123 123 cl.delayupdate(tr)
124 124
125 125 # The first emitted object is a header describing the data that
126 126 # follows.
127 127 meta = next(objs)
128 128
129 129 progress = repo.ui.makeprogress(_('changesets'),
130 130 unit=_('chunks'),
131 131 total=meta.get(b'totalitems'))
132 132
133 133 manifestnodes = {}
134 134
135 135 def linkrev(node):
136 136 repo.ui.debug('add changeset %s\n' % short(node))
137 137 # Linkrev for changelog is always self.
138 138 return len(cl)
139 139
140 140 def onchangeset(cl, node):
141 141 progress.increment()
142 142
143 143 revision = cl.changelogrevision(node)
144 144
145 145 # We need to preserve the mapping of changelog revision to node
146 146 # so we can set the linkrev accordingly when manifests are added.
147 147 manifestnodes[cl.rev(node)] = revision.manifest
148 148
149 149 nodesbyphase = {phase: set() for phase in phases.phasenames}
150 150 remotebookmarks = {}
151 151
152 152 # addgroup() expects a 7-tuple describing revisions. This normalizes
153 153 # the wire data to that format.
154 154 #
155 155 # This loop also aggregates non-revision metadata, such as phase
156 156 # data.
157 157 def iterrevisions():
158 158 for cset in objs:
159 159 node = cset[b'node']
160 160
161 161 if b'phase' in cset:
162 162 nodesbyphase[cset[b'phase']].add(node)
163 163
164 164 for mark in cset.get(b'bookmarks', []):
165 165 remotebookmarks[mark] = node
166 166
167 167 # TODO add mechanism for extensions to examine records so they
168 168 # can siphon off custom data fields.
169 169
170 170 # Some entries might only be metadata only updates.
171 171 if b'revisionsize' not in cset:
172 172 continue
173 173
174 174 data = next(objs)
175 175
176 176 yield (
177 177 node,
178 178 cset[b'parents'][0],
179 179 cset[b'parents'][1],
180 180 # Linknode is always itself for changesets.
181 181 cset[b'node'],
182 182 # We always send full revisions. So delta base is not set.
183 183 nullid,
184 184 mdiff.trivialdiffheader(len(data)) + data,
185 185 # Flags not yet supported.
186 186 0,
187 187 )
188 188
189 189 added = cl.addgroup(iterrevisions(), linkrev, weakref.proxy(tr),
190 190 addrevisioncb=onchangeset)
191 191
192 192 progress.complete()
193 193
194 194 return {
195 195 'added': added,
196 196 'nodesbyphase': nodesbyphase,
197 197 'bookmarks': remotebookmarks,
198 198 'manifestnodes': manifestnodes,
199 199 }
200 200
201 201 def _fetchmanifests(repo, tr, remote, manifestnodes):
202 202 rootmanifest = repo.manifestlog.getstorage(b'')
203 203
204 204 # Some manifests can be shared between changesets. Filter out revisions
205 205 # we already know about.
206 206 fetchnodes = []
207 207 linkrevs = {}
208 208 seen = set()
209 209
210 210 for clrev, node in sorted(manifestnodes.iteritems()):
211 211 if node in seen:
212 212 continue
213 213
214 214 try:
215 215 rootmanifest.rev(node)
216 216 except error.LookupError:
217 217 fetchnodes.append(node)
218 218 linkrevs[node] = clrev
219 219
220 220 seen.add(node)
221 221
222 222 # TODO handle tree manifests
223 223
224 224 # addgroup() expects 7-tuple describing revisions. This normalizes
225 225 # the wire data to that format.
226 226 def iterrevisions(objs, progress):
227 227 for manifest in objs:
228 228 node = manifest[b'node']
229 229
230 230 if b'deltasize' in manifest:
231 231 basenode = manifest[b'deltabasenode']
232 232 delta = next(objs)
233 233 elif b'revisionsize' in manifest:
234 234 basenode = nullid
235 235 revision = next(objs)
236 236 delta = mdiff.trivialdiffheader(len(revision)) + revision
237 237 else:
238 238 continue
239 239
240 240 yield (
241 241 node,
242 242 manifest[b'parents'][0],
243 243 manifest[b'parents'][1],
244 244 # The value passed in is passed to the lookup function passed
245 245 # to addgroup(). We already have a map of manifest node to
246 246 # changelog revision number. So we just pass in the
247 247 # manifest node here and use linkrevs.__getitem__ as the
248 248 # resolution function.
249 249 node,
250 250 basenode,
251 251 delta,
252 252 # Flags not yet supported.
253 253 0
254 254 )
255 255
256 256 progress.increment()
257 257
258 258 progress = repo.ui.makeprogress(_('manifests'), unit=_('chunks'),
259 259 total=len(fetchnodes))
260 260
261 261 # Fetch manifests 10,000 per command.
262 262 # TODO have server advertise preferences?
263 263 # TODO make size configurable on client?
264 264 batchsize = 10000
265 265
266 266 # We send commands 1 at a time to the remote. This is not the most
267 267 # efficient because we incur a round trip at the end of each batch.
268 268 # However, the existing frame-based reactor keeps consuming server
269 269 # data in the background. And this results in response data buffering
270 270 # in memory. This can consume gigabytes of memory.
271 271 # TODO send multiple commands in a request once background buffering
272 272 # issues are resolved.
273 273
274 274 added = []
275 275
276 276 for i in pycompat.xrange(0, len(fetchnodes), batchsize):
277 277 batch = [node for node in fetchnodes[i:i + batchsize]]
278 278 if not batch:
279 279 continue
280 280
281 281 with remote.commandexecutor() as e:
282 282 objs = e.callcommand(b'manifestdata', {
283 283 b'tree': b'',
284 284 b'nodes': batch,
285 285 b'fields': {b'parents', b'revision'},
286 b'haveparents': True,
286 287 }).result()
287 288
288 289 # Chomp off header object.
289 290 next(objs)
290 291
291 292 added.extend(rootmanifest.addgroup(
292 293 iterrevisions(objs, progress),
293 294 linkrevs.__getitem__,
294 295 weakref.proxy(tr)))
295 296
296 297 progress.complete()
297 298
298 299 return {
299 300 'added': added,
300 301 'linkrevs': linkrevs,
301 302 }
302 303
303 304 def _derivefilesfrommanifests(repo, manifestnodes):
304 305 """Determine what file nodes are relevant given a set of manifest nodes.
305 306
306 307 Returns a dict mapping file paths to dicts of file node to first manifest
307 308 node.
308 309 """
309 310 ml = repo.manifestlog
310 311 fnodes = collections.defaultdict(dict)
311 312
312 313 for manifestnode in manifestnodes:
313 314 m = ml.get(b'', manifestnode)
314 315
315 316 # TODO this will pull in unwanted nodes because it takes the storage
316 317 # delta into consideration. What we really want is something that takes
317 318 # the delta between the manifest's parents. And ideally we would
318 319 # ignore file nodes that are known locally. For now, ignore both
319 320 # these limitations. This will result in incremental fetches requesting
320 321 # data we already have. So this is far from ideal.
321 322 md = m.readfast()
322 323
323 324 for path, fnode in md.items():
324 325 fnodes[path].setdefault(fnode, manifestnode)
325 326
326 327 return fnodes
327 328
328 329 def _fetchfiles(repo, tr, remote, fnodes, linkrevs):
329 330 def iterrevisions(objs, progress):
330 331 for filerevision in objs:
331 332 node = filerevision[b'node']
332 333
333 334 if b'deltasize' in filerevision:
334 335 basenode = filerevision[b'deltabasenode']
335 336 delta = next(objs)
336 337 elif b'revisionsize' in filerevision:
337 338 basenode = nullid
338 339 revision = next(objs)
339 340 delta = mdiff.trivialdiffheader(len(revision)) + revision
340 341 else:
341 342 continue
342 343
343 344 yield (
344 345 node,
345 346 filerevision[b'parents'][0],
346 347 filerevision[b'parents'][1],
347 348 node,
348 349 basenode,
349 350 delta,
350 351 # Flags not yet supported.
351 352 0,
352 353 )
353 354
354 355 progress.increment()
355 356
356 357 progress = repo.ui.makeprogress(
357 358 _('files'), unit=_('chunks'),
358 359 total=sum(len(v) for v in fnodes.itervalues()))
359 360
360 361 # TODO make batch size configurable
361 362 batchsize = 10000
362 363 fnodeslist = [x for x in sorted(fnodes.items())]
363 364
364 365 for i in pycompat.xrange(0, len(fnodeslist), batchsize):
365 366 batch = [x for x in fnodeslist[i:i + batchsize]]
366 367 if not batch:
367 368 continue
368 369
369 370 with remote.commandexecutor() as e:
370 371 fs = []
371 372 locallinkrevs = {}
372 373
373 374 for path, nodes in batch:
374 375 fs.append((path, e.callcommand(b'filedata', {
375 376 b'path': path,
376 377 b'nodes': sorted(nodes),
377 b'fields': {b'parents', b'revision'}
378 b'fields': {b'parents', b'revision'},
379 b'haveparents': True,
378 380 })))
379 381
380 382 locallinkrevs[path] = {
381 383 node: linkrevs[manifestnode]
382 384 for node, manifestnode in nodes.iteritems()}
383 385
384 386 for path, f in fs:
385 387 objs = f.result()
386 388
387 389 # Chomp off header objects.
388 390 next(objs)
389 391
390 392 store = repo.file(path)
391 393 store.addgroup(
392 394 iterrevisions(objs, progress),
393 395 locallinkrevs[path].__getitem__,
394 396 weakref.proxy(tr))
@@ -1,425 +1,440
1 1 **Experimental and under active development**
2 2
3 3 This section documents the wire protocol commands exposed to transports
4 4 using the frame-based protocol. The set of commands exposed through
5 5 these transports is distinct from the set of commands exposed to legacy
6 6 transports.
7 7
8 8 The frame-based protocol uses CBOR to encode command execution requests.
9 9 All command arguments must be mapped to a specific or set of CBOR data
10 10 types.
11 11
12 12 The response to many commands is also CBOR. There is no common response
13 13 format: each command defines its own response format.
14 14
15 15 TODOs
16 16 =====
17 17
18 18 * Add "node namespace" support to each command. In order to support
19 19 SHA-1 hash transition, we want servers to be able to expose different
20 20 "node namespaces" for the same data. Every command operating on nodes
21 21 should specify which "node namespace" it is operating on and responses
22 22 should encode the "node namespace" accordingly.
23 23
24 24 Commands
25 25 ========
26 26
27 27 The sections below detail all commands available to wire protocol version
28 28 2.
29 29
30 30 branchmap
31 31 ---------
32 32
33 33 Obtain heads in named branches.
34 34
35 35 Receives no arguments.
36 36
37 37 The response is a map with bytestring keys defining the branch name.
38 38 Values are arrays of bytestring defining raw changeset nodes.
39 39
40 40 capabilities
41 41 ------------
42 42
43 43 Obtain the server's capabilities.
44 44
45 45 Receives no arguments.
46 46
47 47 This command is typically called only as part of the handshake during
48 48 initial connection establishment.
49 49
50 50 The response is a map with bytestring keys defining server information.
51 51
52 52 The defined keys are:
53 53
54 54 commands
55 55 A map defining available wire protocol commands on this server.
56 56
57 57 Keys in the map are the names of commands that can be invoked. Values
58 58 are maps defining information about that command. The bytestring keys
59 59 are:
60 60
61 61 args
62 62 A map of argument names and their expected types.
63 63
64 64 Types are defined as a representative value for the expected type.
65 65 e.g. an argument expecting a boolean type will have its value
66 66 set to true. An integer type will have its value set to 42. The
67 67 actual values are arbitrary and may not have meaning.
68 68 permissions
69 69 An array of permissions required to execute this command.
70 70
71 71 compression
72 72 An array of maps defining available compression format support.
73 73
74 74 The array is sorted from most preferred to least preferred.
75 75
76 76 Each entry has the following bytestring keys:
77 77
78 78 name
79 79 Name of the compression engine. e.g. ``zstd`` or ``zlib``.
80 80
81 81 framingmediatypes
82 82 An array of bytestrings defining the supported framing protocol
83 83 media types. Servers will not accept media types not in this list.
84 84
85 85 rawrepoformats
86 86 An array of storage formats the repository is using. This set of
87 87 requirements can be used to determine whether a client can read a
88 88 *raw* copy of file data available.
89 89
90 90 changesetdata
91 91 -------------
92 92
93 93 Obtain various data related to changesets.
94 94
95 95 The command accepts the following arguments:
96 96
97 97 noderange
98 98 (array of arrays of bytestrings) An array of 2 elements, each being an
99 99 array of node bytestrings. The first array denotes the changelog revisions
100 100 that are already known to the client. The second array denotes the changelog
101 101 revision DAG heads to fetch. The argument essentially defines a DAG range
102 102 bounded by root and head nodes to fetch.
103 103
104 104 The roots array may be empty. The heads array must be defined.
105 105
106 106 nodes
107 107 (array of bytestrings) Changelog revisions to request explicitly.
108 108
109 109 fields
110 110 (set of bytestring) Which data associated with changelog revisions to
111 111 fetch. The following values are recognized:
112 112
113 113 bookmarks
114 114 Bookmarks associated with a revision.
115 115
116 116 parents
117 117 Parent revisions.
118 118
119 119 phase
120 120 The phase state of a revision.
121 121
122 122 revision
123 123 The raw, revision data for the changelog entry. The hash of this data
124 124 will match the revision's node value.
125 125
126 126 The server resolves the set of revisions relevant to the request by taking
127 127 the union of the ``noderange`` and ``nodes`` arguments. At least one of these
128 128 arguments must be defined.
129 129
130 130 The response bytestream starts with a CBOR map describing the data that follows.
131 131 This map has the following bytestring keys:
132 132
133 133 totalitems
134 134 (unsigned integer) Total number of changelog revisions whose data is being
135 135 transferred. This maps to the set of revisions in the requested node
136 136 range, not the total number of records that follow (see below for why).
137 137
138 138 Following the map header is a series of 0 or more CBOR values. If values
139 139 are present, the first value will always be a map describing a single changeset
140 140 revision. If revision data is requested, the raw revision data (encoded as
141 141 a CBOR bytestring) will follow the map describing it. Otherwise, another CBOR
142 142 map describing the next changeset revision will occur.
143 143
144 144 Each map has the following bytestring keys:
145 145
146 146 node
147 147 (bytestring) The node value for this revision. This is the SHA-1 hash of
148 148 the raw revision data.
149 149
150 150 bookmarks (optional)
151 151 (array of bytestrings) Bookmarks attached to this revision. Only present
152 152 if ``bookmarks`` data is being requested and the revision has bookmarks
153 153 attached.
154 154
155 155 parents (optional)
156 156 (array of bytestrings) The nodes representing the parent revisions of this
157 157 revision. Only present if ``parents`` data is being requested.
158 158
159 159 phase (optional)
160 160 (bytestring) The phase that a revision is in. Recognized values are
161 161 ``secret``, ``draft``, and ``public``. Only present if ``phase`` data
162 162 is being requested.
163 163
164 164 revisionsize (optional)
165 165 (unsigned integer) Indicates the size of raw revision data that follows this
166 166 map. The following data contains a serialized form of the changeset data,
167 167 including the author, date, commit message, set of changed files, manifest
168 168 node, and other metadata.
169 169
170 170 Only present if ``revision`` data was requested and the data follows this
171 171 map.
172 172
173 173 If nodes are requested via ``noderange``, they will be emitted in DAG order,
174 174 parents always before children.
175 175
176 176 If nodes are requested via ``nodes``, they will be emitted in requested order.
177 177
178 178 Nodes from ``nodes`` are emitted before nodes from ``noderange``.
179 179
180 180 The set of changeset revisions emitted may not match the exact set of
181 181 changesets requested. Furthermore, the set of keys present on each
182 182 map may vary. This is to facilitate emitting changeset updates as well
183 183 as new revisions.
184 184
185 185 For example, if the request wants ``phase`` and ``revision`` data,
186 186 the response may contain entries for each changeset in the common nodes
187 187 set with the ``phase`` key and without the ``revision`` key in order
188 188 to reflect a phase-only update.
189 189
190 190 TODO support different revision selection mechanisms (e.g. non-public, specific
191 191 revisions)
192 192 TODO support different hash "namespaces" for revisions (e.g. sha-1 versus other)
193 193 TODO support emitting obsolescence data
194 194 TODO support filtering based on relevant paths (narrow clone)
195 195 TODO support depth limiting
196 196 TODO support hgtagsfnodes cache / tags data
197 197 TODO support branch heads cache
198 198
199 199 filedata
200 200 --------
201 201
202 202 Obtain various data related to an individual tracked file.
203 203
204 204 The command accepts the following arguments:
205 205
206 206 fields
207 207 (set of bytestring) Which data associated with a file to fetch.
208 208 The following values are recognized:
209 209
210 210 parents
211 211 Parent nodes for the revision.
212 212
213 213 revision
214 214 The raw revision data for a file.
215 215
216 haveparents
217 (bool) Whether the client has the parent revisions of all requested
218 nodes. If set, the server may emit revision data as deltas against
219 any parent revision. If not set, the server MUST only emit deltas for
220 revisions previously emitted by this command.
221
222 False is assumed in the absence of any value.
223
216 224 nodes
217 225 (array of bytestrings) File nodes whose data to retrieve.
218 226
219 227 path
220 228 (bytestring) Path of the tracked file whose data to retrieve.
221 229
222 230 TODO allow specifying revisions via alternate means (such as from
223 231 changeset revisions or ranges)
224 232
225 233 The response bytestream starts with a CBOR map describing the data that
226 234 follows. It has the following bytestream keys:
227 235
228 236 totalitems
229 237 (unsigned integer) Total number of file revisions whose data is
230 238 being returned.
231 239
232 240 Following the header map is a series of 0 or more CBOR values. The first
233 241 value is always a map describing a file revision. If this map has the
234 242 ``deltasize`` or ``revisionsize`` keys, a bytestring containing the delta
235 243 or revision, respectively, will immediately follow the map. Otherwise
236 244 the next value will be a map describing the next file revision.
237 245
238 246 Each map has the following bytestring keys:
239 247
240 248 node
241 249 (bytestring) The node of the file revision whose data is represented.
242 250
243 251 deltabasenode
244 252 (bytestring) Node of the file revision the following delta is against.
245 253
246 254 Only present if the ``revision`` field is requested and delta data
247 255 follows this map.
248 256
249 257 deltasize
250 258 (unsigned integer) The size of the delta data that follows this map.
251 259
252 260 Only present if the ``revision`` field is requested and delta data
253 261 follows this map.
254 262
255 263 parents
256 264 (array of bytestring) The nodes of the parents of this file revision.
257 265
258 266 Only present if the ``parents`` field is requested.
259 267
260 268 revisionsize
261 269 (unsigned integer) The size of the fulltext revision data that follows
262 270 this map.
263 271
264 272 Only present if the ``revision`` field is requested and fulltext revision
265 273 data follows this map.
266 274
267 275 When ``revision`` data is requested, the server chooses to emit either fulltext
268 276 revision data or a delta. What the server decides can be inferred by looking
269 277 for the presence of the ``deltasize`` or ``revisionsize`` keys in the map.
270 278 Servers MUST NOT define both keys.
271 279
272 280 heads
273 281 -----
274 282
275 283 Obtain DAG heads in the repository.
276 284
277 285 The command accepts the following arguments:
278 286
279 287 publiconly (optional)
280 288 (boolean) If set, operate on the DAG for public phase changesets only.
281 289 Non-public (i.e. draft) phase DAG heads will not be returned.
282 290
283 291 The response is a CBOR array of bytestrings defining changeset nodes
284 292 of DAG heads. The array can be empty if the repository is empty or no
285 293 changesets satisfied the request.
286 294
287 295 TODO consider exposing phase of heads in response
288 296
289 297 known
290 298 -----
291 299
292 300 Determine whether a series of changeset nodes is known to the server.
293 301
294 302 The command accepts the following arguments:
295 303
296 304 nodes
297 305 (array of bytestrings) List of changeset nodes whose presence to
298 306 query.
299 307
300 308 The response is a bytestring where each byte contains a 0 or 1 for the
301 309 corresponding requested node at the same index.
302 310
303 311 TODO use a bit array for even more compact response
304 312
305 313 listkeys
306 314 --------
307 315
308 316 List values in a specified ``pushkey`` namespace.
309 317
310 318 The command receives the following arguments:
311 319
312 320 namespace
313 321 (bytestring) Pushkey namespace to query.
314 322
315 323 The response is a map with bytestring keys and values.
316 324
317 325 TODO consider using binary to represent nodes in certain pushkey namespaces.
318 326
319 327 lookup
320 328 ------
321 329
322 330 Try to resolve a value to a changeset revision.
323 331
324 332 Unlike ``known`` which operates on changeset nodes, lookup operates on
325 333 node fragments and other names that a user may use.
326 334
327 335 The command receives the following arguments:
328 336
329 337 key
330 338 (bytestring) Value to try to resolve.
331 339
332 340 On success, returns a bytestring containing the resolved node.
333 341
334 342 manifestdata
335 343 ------------
336 344
337 345 Obtain various data related to manifests (which are lists of files in
338 346 a revision).
339 347
340 348 The command accepts the following arguments:
341 349
342 350 fields
343 351 (set of bytestring) Which data associated with manifests to fetch.
344 352 The following values are recognized:
345 353
346 354 parents
347 355 Parent nodes for the manifest.
348 356
349 357 revision
350 358 The raw revision data for the manifest.
351 359
360 haveparents
361 (bool) Whether the client has the parent revisions of all requested
362 nodes. If set, the server may emit revision data as deltas against
363 any parent revision. If not set, the server MUST only emit deltas for
364 revisions previously emitted by this command.
365
366 False is assumed in the absence of any value.
367
352 368 nodes
353 369 (array of bytestring) Manifest nodes whose data to retrieve.
354 370
355 371 tree
356 372 (bytestring) Path to manifest to retrieve. The empty bytestring represents
357 373 the root manifest. All other values represent directories/trees within
358 374 the repository.
359 375
360 376 TODO allow specifying revisions via alternate means (such as from changeset
361 377 revisions or ranges)
362 378 TODO consider recursive expansion of manifests (with path filtering for
363 379 narrow use cases)
364 TODO more control over whether to emit fulltexts or deltas
365 380
366 381 The response bytestream starts with a CBOR map describing the data that
367 382 follows. It has the following bytestring keys:
368 383
369 384 totalitems
370 385 (unsigned integer) Total number of manifest revisions whose data is
371 386 being returned.
372 387
373 388 Following the header map is a series of 0 or more CBOR values. The first
374 389 value is always a map describing a manifest revision. If this map has the
375 390 ``deltasize`` or ``revisionsize`` keys, a bytestring containing the delta
376 391 or revision, respectively, will immediately follow the map. Otherwise
377 392 the next value will be a map describing the next manifest revision.
378 393
379 394 Each map has the following bytestring keys:
380 395
381 396 node
382 397 (bytestring) The node of the manifest revision whose data is represented.
383 398
384 399 deltabasenode
385 400 (bytestring) The node that the delta representation of this revision is
386 401 computed against. Only present if the ``revision`` field is requested and
387 402 a delta is being emitted.
388 403
389 404 deltasize
390 405 (unsigned integer) The size of the delta data that follows this map.
391 406 Only present if the ``revision`` field is requested and a delta is
392 407 being emitted.
393 408
394 409 parents
395 410 (array of bytestring) The nodes of the parents of this manifest revision.
396 411 Only present if the ``parents`` field is requested.
397 412
398 413 revisionsize
399 414 (unsigned integer) The size of the fulltext revision data that follows
400 415 this map. Only present if the ``revision`` field is requested and a fulltext
401 416 revision is being emitted.
402 417
403 418 When ``revision`` data is requested, the server chooses to emit either fulltext
404 419 revision data or a delta. What the server decides can be inferred by looking
405 420 for the presence of the ``deltasize`` or ``revisionsize`` keys in the map.
406 421 Servers MUST NOT define both keys.
407 422
408 423 pushkey
409 424 -------
410 425
411 426 Set a value using the ``pushkey`` protocol.
412 427
413 428 The command receives the following arguments:
414 429
415 430 namespace
416 431 (bytestring) Pushkey namespace to operate on.
417 432 key
418 433 (bytestring) The pushkey key to set.
419 434 old
420 435 (bytestring) Old value for this key.
421 436 new
422 437 (bytestring) New value for this key.
423 438
424 439 TODO consider using binary to represent nodes is certain pushkey namespaces.
425 440 TODO better define response type and meaning.
@@ -1,898 +1,921
1 1 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 2 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 3 #
4 4 # This software may be used and distributed according to the terms of the
5 5 # GNU General Public License version 2 or any later version.
6 6
7 7 from __future__ import absolute_import
8 8
9 9 import contextlib
10 10
11 11 from .i18n import _
12 12 from .node import (
13 13 hex,
14 14 nullid,
15 15 nullrev,
16 16 )
17 17 from . import (
18 18 changegroup,
19 19 dagop,
20 20 discovery,
21 21 encoding,
22 22 error,
23 23 pycompat,
24 24 streamclone,
25 25 util,
26 26 wireprotoframing,
27 27 wireprototypes,
28 28 )
29 29 from .utils import (
30 30 interfaceutil,
31 31 )
32 32
33 33 FRAMINGTYPE = b'application/mercurial-exp-framing-0005'
34 34
35 35 HTTP_WIREPROTO_V2 = wireprototypes.HTTP_WIREPROTO_V2
36 36
37 37 COMMANDS = wireprototypes.commanddict()
38 38
39 39 def handlehttpv2request(rctx, req, res, checkperm, urlparts):
40 40 from .hgweb import common as hgwebcommon
41 41
42 42 # URL space looks like: <permissions>/<command>, where <permission> can
43 43 # be ``ro`` or ``rw`` to signal read-only or read-write, respectively.
44 44
45 45 # Root URL does nothing meaningful... yet.
46 46 if not urlparts:
47 47 res.status = b'200 OK'
48 48 res.headers[b'Content-Type'] = b'text/plain'
49 49 res.setbodybytes(_('HTTP version 2 API handler'))
50 50 return
51 51
52 52 if len(urlparts) == 1:
53 53 res.status = b'404 Not Found'
54 54 res.headers[b'Content-Type'] = b'text/plain'
55 55 res.setbodybytes(_('do not know how to process %s\n') %
56 56 req.dispatchpath)
57 57 return
58 58
59 59 permission, command = urlparts[0:2]
60 60
61 61 if permission not in (b'ro', b'rw'):
62 62 res.status = b'404 Not Found'
63 63 res.headers[b'Content-Type'] = b'text/plain'
64 64 res.setbodybytes(_('unknown permission: %s') % permission)
65 65 return
66 66
67 67 if req.method != 'POST':
68 68 res.status = b'405 Method Not Allowed'
69 69 res.headers[b'Allow'] = b'POST'
70 70 res.setbodybytes(_('commands require POST requests'))
71 71 return
72 72
73 73 # At some point we'll want to use our own API instead of recycling the
74 74 # behavior of version 1 of the wire protocol...
75 75 # TODO return reasonable responses - not responses that overload the
76 76 # HTTP status line message for error reporting.
77 77 try:
78 78 checkperm(rctx, req, 'pull' if permission == b'ro' else 'push')
79 79 except hgwebcommon.ErrorResponse as e:
80 80 res.status = hgwebcommon.statusmessage(e.code, pycompat.bytestr(e))
81 81 for k, v in e.headers:
82 82 res.headers[k] = v
83 83 res.setbodybytes('permission denied')
84 84 return
85 85
86 86 # We have a special endpoint to reflect the request back at the client.
87 87 if command == b'debugreflect':
88 88 _processhttpv2reflectrequest(rctx.repo.ui, rctx.repo, req, res)
89 89 return
90 90
91 91 # Extra commands that we handle that aren't really wire protocol
92 92 # commands. Think extra hard before making this hackery available to
93 93 # extension.
94 94 extracommands = {'multirequest'}
95 95
96 96 if command not in COMMANDS and command not in extracommands:
97 97 res.status = b'404 Not Found'
98 98 res.headers[b'Content-Type'] = b'text/plain'
99 99 res.setbodybytes(_('unknown wire protocol command: %s\n') % command)
100 100 return
101 101
102 102 repo = rctx.repo
103 103 ui = repo.ui
104 104
105 105 proto = httpv2protocolhandler(req, ui)
106 106
107 107 if (not COMMANDS.commandavailable(command, proto)
108 108 and command not in extracommands):
109 109 res.status = b'404 Not Found'
110 110 res.headers[b'Content-Type'] = b'text/plain'
111 111 res.setbodybytes(_('invalid wire protocol command: %s') % command)
112 112 return
113 113
114 114 # TODO consider cases where proxies may add additional Accept headers.
115 115 if req.headers.get(b'Accept') != FRAMINGTYPE:
116 116 res.status = b'406 Not Acceptable'
117 117 res.headers[b'Content-Type'] = b'text/plain'
118 118 res.setbodybytes(_('client MUST specify Accept header with value: %s\n')
119 119 % FRAMINGTYPE)
120 120 return
121 121
122 122 if req.headers.get(b'Content-Type') != FRAMINGTYPE:
123 123 res.status = b'415 Unsupported Media Type'
124 124 # TODO we should send a response with appropriate media type,
125 125 # since client does Accept it.
126 126 res.headers[b'Content-Type'] = b'text/plain'
127 127 res.setbodybytes(_('client MUST send Content-Type header with '
128 128 'value: %s\n') % FRAMINGTYPE)
129 129 return
130 130
131 131 _processhttpv2request(ui, repo, req, res, permission, command, proto)
132 132
133 133 def _processhttpv2reflectrequest(ui, repo, req, res):
134 134 """Reads unified frame protocol request and dumps out state to client.
135 135
136 136 This special endpoint can be used to help debug the wire protocol.
137 137
138 138 Instead of routing the request through the normal dispatch mechanism,
139 139 we instead read all frames, decode them, and feed them into our state
140 140 tracker. We then dump the log of all that activity back out to the
141 141 client.
142 142 """
143 143 import json
144 144
145 145 # Reflection APIs have a history of being abused, accidentally disclosing
146 146 # sensitive data, etc. So we have a config knob.
147 147 if not ui.configbool('experimental', 'web.api.debugreflect'):
148 148 res.status = b'404 Not Found'
149 149 res.headers[b'Content-Type'] = b'text/plain'
150 150 res.setbodybytes(_('debugreflect service not available'))
151 151 return
152 152
153 153 # We assume we have a unified framing protocol request body.
154 154
155 155 reactor = wireprotoframing.serverreactor()
156 156 states = []
157 157
158 158 while True:
159 159 frame = wireprotoframing.readframe(req.bodyfh)
160 160
161 161 if not frame:
162 162 states.append(b'received: <no frame>')
163 163 break
164 164
165 165 states.append(b'received: %d %d %d %s' % (frame.typeid, frame.flags,
166 166 frame.requestid,
167 167 frame.payload))
168 168
169 169 action, meta = reactor.onframerecv(frame)
170 170 states.append(json.dumps((action, meta), sort_keys=True,
171 171 separators=(', ', ': ')))
172 172
173 173 action, meta = reactor.oninputeof()
174 174 meta['action'] = action
175 175 states.append(json.dumps(meta, sort_keys=True, separators=(', ',': ')))
176 176
177 177 res.status = b'200 OK'
178 178 res.headers[b'Content-Type'] = b'text/plain'
179 179 res.setbodybytes(b'\n'.join(states))
180 180
181 181 def _processhttpv2request(ui, repo, req, res, authedperm, reqcommand, proto):
182 182 """Post-validation handler for HTTPv2 requests.
183 183
184 184 Called when the HTTP request contains unified frame-based protocol
185 185 frames for evaluation.
186 186 """
187 187 # TODO Some HTTP clients are full duplex and can receive data before
188 188 # the entire request is transmitted. Figure out a way to indicate support
189 189 # for that so we can opt into full duplex mode.
190 190 reactor = wireprotoframing.serverreactor(deferoutput=True)
191 191 seencommand = False
192 192
193 193 outstream = reactor.makeoutputstream()
194 194
195 195 while True:
196 196 frame = wireprotoframing.readframe(req.bodyfh)
197 197 if not frame:
198 198 break
199 199
200 200 action, meta = reactor.onframerecv(frame)
201 201
202 202 if action == 'wantframe':
203 203 # Need more data before we can do anything.
204 204 continue
205 205 elif action == 'runcommand':
206 206 sentoutput = _httpv2runcommand(ui, repo, req, res, authedperm,
207 207 reqcommand, reactor, outstream,
208 208 meta, issubsequent=seencommand)
209 209
210 210 if sentoutput:
211 211 return
212 212
213 213 seencommand = True
214 214
215 215 elif action == 'error':
216 216 # TODO define proper error mechanism.
217 217 res.status = b'200 OK'
218 218 res.headers[b'Content-Type'] = b'text/plain'
219 219 res.setbodybytes(meta['message'] + b'\n')
220 220 return
221 221 else:
222 222 raise error.ProgrammingError(
223 223 'unhandled action from frame processor: %s' % action)
224 224
225 225 action, meta = reactor.oninputeof()
226 226 if action == 'sendframes':
227 227 # We assume we haven't started sending the response yet. If we're
228 228 # wrong, the response type will raise an exception.
229 229 res.status = b'200 OK'
230 230 res.headers[b'Content-Type'] = FRAMINGTYPE
231 231 res.setbodygen(meta['framegen'])
232 232 elif action == 'noop':
233 233 pass
234 234 else:
235 235 raise error.ProgrammingError('unhandled action from frame processor: %s'
236 236 % action)
237 237
238 238 def _httpv2runcommand(ui, repo, req, res, authedperm, reqcommand, reactor,
239 239 outstream, command, issubsequent):
240 240 """Dispatch a wire protocol command made from HTTPv2 requests.
241 241
242 242 The authenticated permission (``authedperm``) along with the original
243 243 command from the URL (``reqcommand``) are passed in.
244 244 """
245 245 # We already validated that the session has permissions to perform the
246 246 # actions in ``authedperm``. In the unified frame protocol, the canonical
247 247 # command to run is expressed in a frame. However, the URL also requested
248 248 # to run a specific command. We need to be careful that the command we
249 249 # run doesn't have permissions requirements greater than what was granted
250 250 # by ``authedperm``.
251 251 #
252 252 # Our rule for this is we only allow one command per HTTP request and
253 253 # that command must match the command in the URL. However, we make
254 254 # an exception for the ``multirequest`` URL. This URL is allowed to
255 255 # execute multiple commands. We double check permissions of each command
256 256 # as it is invoked to ensure there is no privilege escalation.
257 257 # TODO consider allowing multiple commands to regular command URLs
258 258 # iff each command is the same.
259 259
260 260 proto = httpv2protocolhandler(req, ui, args=command['args'])
261 261
262 262 if reqcommand == b'multirequest':
263 263 if not COMMANDS.commandavailable(command['command'], proto):
264 264 # TODO proper error mechanism
265 265 res.status = b'200 OK'
266 266 res.headers[b'Content-Type'] = b'text/plain'
267 267 res.setbodybytes(_('wire protocol command not available: %s') %
268 268 command['command'])
269 269 return True
270 270
271 271 # TODO don't use assert here, since it may be elided by -O.
272 272 assert authedperm in (b'ro', b'rw')
273 273 wirecommand = COMMANDS[command['command']]
274 274 assert wirecommand.permission in ('push', 'pull')
275 275
276 276 if authedperm == b'ro' and wirecommand.permission != 'pull':
277 277 # TODO proper error mechanism
278 278 res.status = b'403 Forbidden'
279 279 res.headers[b'Content-Type'] = b'text/plain'
280 280 res.setbodybytes(_('insufficient permissions to execute '
281 281 'command: %s') % command['command'])
282 282 return True
283 283
284 284 # TODO should we also call checkperm() here? Maybe not if we're going
285 285 # to overhaul that API. The granted scope from the URL check should
286 286 # be good enough.
287 287
288 288 else:
289 289 # Don't allow multiple commands outside of ``multirequest`` URL.
290 290 if issubsequent:
291 291 # TODO proper error mechanism
292 292 res.status = b'200 OK'
293 293 res.headers[b'Content-Type'] = b'text/plain'
294 294 res.setbodybytes(_('multiple commands cannot be issued to this '
295 295 'URL'))
296 296 return True
297 297
298 298 if reqcommand != command['command']:
299 299 # TODO define proper error mechanism
300 300 res.status = b'200 OK'
301 301 res.headers[b'Content-Type'] = b'text/plain'
302 302 res.setbodybytes(_('command in frame must match command in URL'))
303 303 return True
304 304
305 305 res.status = b'200 OK'
306 306 res.headers[b'Content-Type'] = FRAMINGTYPE
307 307
308 308 try:
309 309 objs = dispatch(repo, proto, command['command'])
310 310
311 311 action, meta = reactor.oncommandresponsereadyobjects(
312 312 outstream, command['requestid'], objs)
313 313
314 314 except Exception as e:
315 315 action, meta = reactor.onservererror(
316 316 outstream, command['requestid'],
317 317 _('exception when invoking command: %s') % e)
318 318
319 319 if action == 'sendframes':
320 320 res.setbodygen(meta['framegen'])
321 321 return True
322 322 elif action == 'noop':
323 323 return False
324 324 else:
325 325 raise error.ProgrammingError('unhandled event from reactor: %s' %
326 326 action)
327 327
328 328 def getdispatchrepo(repo, proto, command):
329 329 return repo.filtered('served')
330 330
331 331 def dispatch(repo, proto, command):
332 332 repo = getdispatchrepo(repo, proto, command)
333 333
334 334 func, spec = COMMANDS[command]
335 335 args = proto.getargs(spec)
336 336
337 337 return func(repo, proto, **args)
338 338
339 339 @interfaceutil.implementer(wireprototypes.baseprotocolhandler)
340 340 class httpv2protocolhandler(object):
341 341 def __init__(self, req, ui, args=None):
342 342 self._req = req
343 343 self._ui = ui
344 344 self._args = args
345 345
346 346 @property
347 347 def name(self):
348 348 return HTTP_WIREPROTO_V2
349 349
350 350 def getargs(self, args):
351 351 data = {}
352 352 for k, typ in args.items():
353 353 if k == '*':
354 354 raise NotImplementedError('do not support * args')
355 355 elif k in self._args:
356 356 # TODO consider validating value types.
357 357 data[k] = self._args[k]
358 358
359 359 return data
360 360
361 361 def getprotocaps(self):
362 362 # Protocol capabilities are currently not implemented for HTTP V2.
363 363 return set()
364 364
365 365 def getpayload(self):
366 366 raise NotImplementedError
367 367
368 368 @contextlib.contextmanager
369 369 def mayberedirectstdio(self):
370 370 raise NotImplementedError
371 371
372 372 def client(self):
373 373 raise NotImplementedError
374 374
375 375 def addcapabilities(self, repo, caps):
376 376 return caps
377 377
378 378 def checkperm(self, perm):
379 379 raise NotImplementedError
380 380
381 381 def httpv2apidescriptor(req, repo):
382 382 proto = httpv2protocolhandler(req, repo.ui)
383 383
384 384 return _capabilitiesv2(repo, proto)
385 385
386 386 def _capabilitiesv2(repo, proto):
387 387 """Obtain the set of capabilities for version 2 transports.
388 388
389 389 These capabilities are distinct from the capabilities for version 1
390 390 transports.
391 391 """
392 392 compression = []
393 393 for engine in wireprototypes.supportedcompengines(repo.ui, util.SERVERROLE):
394 394 compression.append({
395 395 b'name': engine.wireprotosupport().name,
396 396 })
397 397
398 398 caps = {
399 399 'commands': {},
400 400 'compression': compression,
401 401 'framingmediatypes': [FRAMINGTYPE],
402 402 }
403 403
404 404 # TODO expose available changesetdata fields.
405 405
406 406 for command, entry in COMMANDS.items():
407 407 caps['commands'][command] = {
408 408 'args': entry.args,
409 409 'permissions': [entry.permission],
410 410 }
411 411
412 412 if streamclone.allowservergeneration(repo):
413 413 caps['rawrepoformats'] = sorted(repo.requirements &
414 414 repo.supportedformats)
415 415
416 416 return proto.addcapabilities(repo, caps)
417 417
418 def builddeltarequests(store, nodes):
418 def builddeltarequests(store, nodes, haveparents):
419 419 """Build a series of revision delta requests against a backend store.
420 420
421 421 Returns a list of revision numbers in the order they should be sent
422 422 and a list of ``irevisiondeltarequest`` instances to be made against
423 423 the backend store.
424 424 """
425 425 # We sort and send nodes in DAG order because this is optimal for
426 426 # storage emission.
427 427 # TODO we may want a better storage API here - one where we can throw
428 428 # a list of nodes and delta preconditions over a figurative wall and
429 429 # have the storage backend figure it out for us.
430 430 revs = dagop.linearize({store.rev(n) for n in nodes}, store.parentrevs)
431 431
432 432 requests = []
433 seenrevs = set()
433 434
434 435 for rev in revs:
435 436 node = store.node(rev)
436 parents = store.parents(node)
437 deltaparent = store.node(store.deltaparent(rev))
437 parentnodes = store.parents(node)
438 parentrevs = [store.rev(n) for n in parentnodes]
439 deltabaserev = store.deltaparent(rev)
440 deltabasenode = store.node(deltabaserev)
438 441
439 # There is a delta in storage. That means we can send the delta
440 # efficiently.
442 # The choice of whether to send a fulltext revision or a delta and
443 # what delta to send is governed by a few factors.
441 444 #
442 # But, the delta may be against a revision the receiver doesn't
443 # have (e.g. shallow clone or when the delta isn't against a parent
444 # revision). For now, we ignore the problem of shallow clone. As
445 # long as a delta exists against a parent, we send it.
446 # TODO allow arguments to control this behavior, as the receiver
447 # may not have the base revision in some scenarios.
448 if deltaparent != nullid and deltaparent in parents:
449 basenode = deltaparent
445 # To send a delta, we need to ensure the receiver is capable of
446 # decoding it. And that requires the receiver to have the base
447 # revision the delta is against.
448 #
449 # We can only guarantee the receiver has the base revision if
450 # a) we've already sent the revision as part of this group
451 # b) the receiver has indicated they already have the revision.
452 # And the mechanism for "b" is the client indicating they have
453 # parent revisions. So this means we can only send the delta if
454 # it is sent before or it is against a delta and the receiver says
455 # they have a parent.
450 456
451 # Else there is no delta parent in storage or the delta that is
452 # # there isn't suitable. Let's use a delta against a parent
453 # revision, if possible.
454 #
455 # There is room to check if the delta parent is in the ancestry of
456 # this node. But there isn't an API on the manifest storage object
457 # for that. So ignore this case for now.
457 # We can send storage delta if it is against a revision we've sent
458 # in this group.
459 if deltabaserev != nullrev and deltabaserev in seenrevs:
460 basenode = deltabasenode
461
462 # We can send storage delta if it is against a parent revision and
463 # the receiver indicates they have the parents.
464 elif (deltabaserev != nullrev and deltabaserev in parentrevs
465 and haveparents):
466 basenode = deltabasenode
458 467
459 elif parents[0] != nullid:
460 basenode = parents[0]
461 elif parents[1] != nullid:
462 basenode = parents[1]
468 # Otherwise the storage delta isn't appropriate. Fall back to
469 # using another delta, if possible.
463 470
464 # No potential bases to delta against. Send a full revision.
471 # Use p1 if we've emitted it or receiver says they have it.
472 elif parentrevs[0] != nullrev and (
473 parentrevs[0] in seenrevs or haveparents):
474 basenode = parentnodes[0]
475
476 # Use p2 if we've emitted it or receiver says they have it.
477 elif parentrevs[1] != nullrev and (
478 parentrevs[1] in seenrevs or haveparents):
479 basenode = parentnodes[1]
480
481 # Nothing appropriate to delta against. Send the full revision.
465 482 else:
466 483 basenode = nullid
467 484
468 485 requests.append(changegroup.revisiondeltarequest(
469 486 node=node,
470 p1node=parents[0],
471 p2node=parents[1],
487 p1node=parentnodes[0],
488 p2node=parentnodes[1],
472 489 # Receiver deals with linknode resolution.
473 490 linknode=nullid,
474 491 basenode=basenode,
475 492 ))
476 493
494 seenrevs.add(rev)
495
477 496 return revs, requests
478 497
479 498 def wireprotocommand(name, args=None, permission='push'):
480 499 """Decorator to declare a wire protocol command.
481 500
482 501 ``name`` is the name of the wire protocol command being provided.
483 502
484 503 ``args`` is a dict of argument names to example values.
485 504
486 505 ``permission`` defines the permission type needed to run this command.
487 506 Can be ``push`` or ``pull``. These roughly map to read-write and read-only,
488 507 respectively. Default is to assume command requires ``push`` permissions
489 508 because otherwise commands not declaring their permissions could modify
490 509 a repository that is supposed to be read-only.
491 510
492 511 Wire protocol commands are generators of objects to be serialized and
493 512 sent to the client.
494 513
495 514 If a command raises an uncaught exception, this will be translated into
496 515 a command error.
497 516 """
498 517 transports = {k for k, v in wireprototypes.TRANSPORTS.items()
499 518 if v['version'] == 2}
500 519
501 520 if permission not in ('push', 'pull'):
502 521 raise error.ProgrammingError('invalid wire protocol permission; '
503 522 'got %s; expected "push" or "pull"' %
504 523 permission)
505 524
506 525 if args is None:
507 526 args = {}
508 527
509 528 if not isinstance(args, dict):
510 529 raise error.ProgrammingError('arguments for version 2 commands '
511 530 'must be declared as dicts')
512 531
513 532 def register(func):
514 533 if name in COMMANDS:
515 534 raise error.ProgrammingError('%s command already registered '
516 535 'for version 2' % name)
517 536
518 537 COMMANDS[name] = wireprototypes.commandentry(
519 538 func, args=args, transports=transports, permission=permission)
520 539
521 540 return func
522 541
523 542 return register
524 543
525 544 @wireprotocommand('branchmap', permission='pull')
526 545 def branchmapv2(repo, proto):
527 546 yield {encoding.fromlocal(k): v
528 547 for k, v in repo.branchmap().iteritems()}
529 548
530 549 @wireprotocommand('capabilities', permission='pull')
531 550 def capabilitiesv2(repo, proto):
532 551 yield _capabilitiesv2(repo, proto)
533 552
534 553 @wireprotocommand('changesetdata',
535 554 args={
536 555 'noderange': [[b'0123456...'], [b'abcdef...']],
537 556 'nodes': [b'0123456...'],
538 557 'fields': {b'parents', b'revision'},
539 558 },
540 559 permission='pull')
541 560 def changesetdata(repo, proto, noderange=None, nodes=None, fields=None):
542 561 fields = fields or set()
543 562
544 563 # TODO look for unknown fields and abort when they can't be serviced.
545 564
546 565 if noderange is None and nodes is None:
547 566 raise error.WireprotoCommandError(
548 567 'noderange or nodes must be defined')
549 568
550 569 if noderange is not None:
551 570 if len(noderange) != 2:
552 571 raise error.WireprotoCommandError(
553 572 'noderange must consist of 2 elements')
554 573
555 574 if not noderange[1]:
556 575 raise error.WireprotoCommandError(
557 576 'heads in noderange request cannot be empty')
558 577
559 578 cl = repo.changelog
560 579 hasnode = cl.hasnode
561 580
562 581 seen = set()
563 582 outgoing = []
564 583
565 584 if nodes is not None:
566 585 outgoing.extend(n for n in nodes if hasnode(n))
567 586 seen |= set(outgoing)
568 587
569 588 if noderange is not None:
570 589 if noderange[0]:
571 590 common = [n for n in noderange[0] if hasnode(n)]
572 591 else:
573 592 common = [nullid]
574 593
575 594 for n in discovery.outgoing(repo, common, noderange[1]).missing:
576 595 if n not in seen:
577 596 outgoing.append(n)
578 597 # Don't need to add to seen here because this is the final
579 598 # source of nodes and there should be no duplicates in this
580 599 # list.
581 600
582 601 seen.clear()
583 602 publishing = repo.publishing()
584 603
585 604 if outgoing:
586 605 repo.hook('preoutgoing', throw=True, source='serve')
587 606
588 607 yield {
589 608 b'totalitems': len(outgoing),
590 609 }
591 610
592 611 # The phases of nodes already transferred to the client may have changed
593 612 # since the client last requested data. We send phase-only records
594 613 # for these revisions, if requested.
595 614 if b'phase' in fields and noderange is not None:
596 615 # TODO skip nodes whose phase will be reflected by a node in the
597 616 # outgoing set. This is purely an optimization to reduce data
598 617 # size.
599 618 for node in noderange[0]:
600 619 yield {
601 620 b'node': node,
602 621 b'phase': b'public' if publishing else repo[node].phasestr()
603 622 }
604 623
605 624 nodebookmarks = {}
606 625 for mark, node in repo._bookmarks.items():
607 626 nodebookmarks.setdefault(node, set()).add(mark)
608 627
609 628 # It is already topologically sorted by revision number.
610 629 for node in outgoing:
611 630 d = {
612 631 b'node': node,
613 632 }
614 633
615 634 if b'parents' in fields:
616 635 d[b'parents'] = cl.parents(node)
617 636
618 637 if b'phase' in fields:
619 638 if publishing:
620 639 d[b'phase'] = b'public'
621 640 else:
622 641 ctx = repo[node]
623 642 d[b'phase'] = ctx.phasestr()
624 643
625 644 if b'bookmarks' in fields and node in nodebookmarks:
626 645 d[b'bookmarks'] = sorted(nodebookmarks[node])
627 646 del nodebookmarks[node]
628 647
629 648 revisiondata = None
630 649
631 650 if b'revision' in fields:
632 651 revisiondata = cl.revision(node, raw=True)
633 652 d[b'revisionsize'] = len(revisiondata)
634 653
635 654 # TODO make it possible for extensions to wrap a function or register
636 655 # a handler to service custom fields.
637 656
638 657 yield d
639 658
640 659 if revisiondata is not None:
641 660 yield revisiondata
642 661
643 662 # If requested, send bookmarks from nodes that didn't have revision
644 663 # data sent so receiver is aware of any bookmark updates.
645 664 if b'bookmarks' in fields:
646 665 for node, marks in sorted(nodebookmarks.iteritems()):
647 666 yield {
648 667 b'node': node,
649 668 b'bookmarks': sorted(marks),
650 669 }
651 670
652 671 class FileAccessError(Exception):
653 672 """Represents an error accessing a specific file."""
654 673
655 674 def __init__(self, path, msg, args):
656 675 self.path = path
657 676 self.msg = msg
658 677 self.args = args
659 678
660 679 def getfilestore(repo, proto, path):
661 680 """Obtain a file storage object for use with wire protocol.
662 681
663 682 Exists as a standalone function so extensions can monkeypatch to add
664 683 access control.
665 684 """
666 685 # This seems to work even if the file doesn't exist. So catch
667 686 # "empty" files and return an error.
668 687 fl = repo.file(path)
669 688
670 689 if not len(fl):
671 690 raise FileAccessError(path, 'unknown file: %s', (path,))
672 691
673 692 return fl
674 693
675 694 @wireprotocommand('filedata',
676 695 args={
696 'haveparents': True,
677 697 'nodes': [b'0123456...'],
678 698 'fields': [b'parents', b'revision'],
679 699 'path': b'foo.txt',
680 700 },
681 701 permission='pull')
682 def filedata(repo, proto, nodes=None, fields=None, path=None):
702 def filedata(repo, proto, haveparents=False, nodes=None, fields=None,
703 path=None):
683 704 fields = fields or set()
684 705
685 706 if nodes is None:
686 707 raise error.WireprotoCommandError('nodes argument must be defined')
687 708
688 709 if path is None:
689 710 raise error.WireprotoCommandError('path argument must be defined')
690 711
691 712 try:
692 713 # Extensions may wish to access the protocol handler.
693 714 store = getfilestore(repo, proto, path)
694 715 except FileAccessError as e:
695 716 raise error.WireprotoCommandError(e.msg, e.args)
696 717
697 718 # Validate requested nodes.
698 719 for node in nodes:
699 720 try:
700 721 store.rev(node)
701 722 except error.LookupError:
702 723 raise error.WireprotoCommandError('unknown file node: %s',
703 724 (hex(node),))
704 725
705 revs, requests = builddeltarequests(store, nodes)
726 revs, requests = builddeltarequests(store, nodes, haveparents)
706 727
707 728 yield {
708 729 b'totalitems': len(revs),
709 730 }
710 731
711 732 if b'revision' in fields:
712 733 deltas = store.emitrevisiondeltas(requests)
713 734 else:
714 735 deltas = None
715 736
716 737 for rev in revs:
717 738 node = store.node(rev)
718 739
719 740 if deltas is not None:
720 741 delta = next(deltas)
721 742 else:
722 743 delta = None
723 744
724 745 d = {
725 746 b'node': node,
726 747 }
727 748
728 749 if b'parents' in fields:
729 750 d[b'parents'] = store.parents(node)
730 751
731 752 if b'revision' in fields:
732 753 assert delta is not None
733 754 assert delta.flags == 0
734 755 assert d[b'node'] == delta.node
735 756
736 757 if delta.revision is not None:
737 758 revisiondata = delta.revision
738 759 d[b'revisionsize'] = len(revisiondata)
739 760 else:
740 761 d[b'deltabasenode'] = delta.basenode
741 762 revisiondata = delta.delta
742 763 d[b'deltasize'] = len(revisiondata)
743 764 else:
744 765 revisiondata = None
745 766
746 767 yield d
747 768
748 769 if revisiondata is not None:
749 770 yield revisiondata
750 771
751 772 if deltas is not None:
752 773 try:
753 774 next(deltas)
754 775 raise error.ProgrammingError('should not have more deltas')
755 776 except GeneratorExit:
756 777 pass
757 778
758 779 @wireprotocommand('heads',
759 780 args={
760 781 'publiconly': False,
761 782 },
762 783 permission='pull')
763 784 def headsv2(repo, proto, publiconly=False):
764 785 if publiconly:
765 786 repo = repo.filtered('immutable')
766 787
767 788 yield repo.heads()
768 789
769 790 @wireprotocommand('known',
770 791 args={
771 792 'nodes': [b'deadbeef'],
772 793 },
773 794 permission='pull')
774 795 def knownv2(repo, proto, nodes=None):
775 796 nodes = nodes or []
776 797 result = b''.join(b'1' if n else b'0' for n in repo.known(nodes))
777 798 yield result
778 799
779 800 @wireprotocommand('listkeys',
780 801 args={
781 802 'namespace': b'ns',
782 803 },
783 804 permission='pull')
784 805 def listkeysv2(repo, proto, namespace=None):
785 806 keys = repo.listkeys(encoding.tolocal(namespace))
786 807 keys = {encoding.fromlocal(k): encoding.fromlocal(v)
787 808 for k, v in keys.iteritems()}
788 809
789 810 yield keys
790 811
791 812 @wireprotocommand('lookup',
792 813 args={
793 814 'key': b'foo',
794 815 },
795 816 permission='pull')
796 817 def lookupv2(repo, proto, key):
797 818 key = encoding.tolocal(key)
798 819
799 820 # TODO handle exception.
800 821 node = repo.lookup(key)
801 822
802 823 yield node
803 824
804 825 @wireprotocommand('manifestdata',
805 826 args={
806 827 'nodes': [b'0123456...'],
828 'haveparents': True,
807 829 'fields': [b'parents', b'revision'],
808 830 'tree': b'',
809 831 },
810 832 permission='pull')
811 def manifestdata(repo, proto, nodes=None, fields=None, tree=None):
833 def manifestdata(repo, proto, haveparents=False, nodes=None, fields=None,
834 tree=None):
812 835 fields = fields or set()
813 836
814 837 if nodes is None:
815 838 raise error.WireprotoCommandError(
816 839 'nodes argument must be defined')
817 840
818 841 if tree is None:
819 842 raise error.WireprotoCommandError(
820 843 'tree argument must be defined')
821 844
822 845 store = repo.manifestlog.getstorage(tree)
823 846
824 847 # Validate the node is known and abort on unknown revisions.
825 848 for node in nodes:
826 849 try:
827 850 store.rev(node)
828 851 except error.LookupError:
829 852 raise error.WireprotoCommandError(
830 853 'unknown node: %s', (node,))
831 854
832 revs, requests = builddeltarequests(store, nodes)
855 revs, requests = builddeltarequests(store, nodes, haveparents)
833 856
834 857 yield {
835 858 b'totalitems': len(revs),
836 859 }
837 860
838 861 if b'revision' in fields:
839 862 deltas = store.emitrevisiondeltas(requests)
840 863 else:
841 864 deltas = None
842 865
843 866 for rev in revs:
844 867 node = store.node(rev)
845 868
846 869 if deltas is not None:
847 870 delta = next(deltas)
848 871 else:
849 872 delta = None
850 873
851 874 d = {
852 875 b'node': node,
853 876 }
854 877
855 878 if b'parents' in fields:
856 879 d[b'parents'] = store.parents(node)
857 880
858 881 if b'revision' in fields:
859 882 assert delta is not None
860 883 assert delta.flags == 0
861 884 assert d[b'node'] == delta.node
862 885
863 886 if delta.revision is not None:
864 887 revisiondata = delta.revision
865 888 d[b'revisionsize'] = len(revisiondata)
866 889 else:
867 890 d[b'deltabasenode'] = delta.basenode
868 891 revisiondata = delta.delta
869 892 d[b'deltasize'] = len(revisiondata)
870 893 else:
871 894 revisiondata = None
872 895
873 896 yield d
874 897
875 898 if revisiondata is not None:
876 899 yield revisiondata
877 900
878 901 if deltas is not None:
879 902 try:
880 903 next(deltas)
881 904 raise error.ProgrammingError('should not have more deltas')
882 905 except GeneratorExit:
883 906 pass
884 907
885 908 @wireprotocommand('pushkey',
886 909 args={
887 910 'namespace': b'ns',
888 911 'key': b'key',
889 912 'old': b'old',
890 913 'new': b'new',
891 914 },
892 915 permission='push')
893 916 def pushkeyv2(repo, proto, namespace, key, old, new):
894 917 # TODO handle ui output redirection
895 918 yield repo.pushkey(encoding.tolocal(namespace),
896 919 encoding.tolocal(key),
897 920 encoding.tolocal(old),
898 921 encoding.tolocal(new))
@@ -1,749 +1,749
1 1 #require no-chg
2 2
3 3 $ . $TESTDIR/wireprotohelpers.sh
4 4
5 5 $ cat >> $HGRCPATH << EOF
6 6 > [web]
7 7 > push_ssl = false
8 8 > allow_push = *
9 9 > EOF
10 10
11 11 $ hg init server
12 12 $ cd server
13 13 $ touch a
14 14 $ hg -q commit -A -m initial
15 15 $ cd ..
16 16
17 17 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
18 18 $ cat hg.pid >> $DAEMON_PIDS
19 19
20 20 compression formats are advertised in compression capability
21 21
22 22 #if zstd
23 23 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zstd,zlib$' > /dev/null
24 24 #else
25 25 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=zlib$' > /dev/null
26 26 #endif
27 27
28 28 $ killdaemons.py
29 29
30 30 server.compressionengines can replace engines list wholesale
31 31
32 32 $ hg serve --config server.compressionengines=none -R server -p $HGPORT -d --pid-file hg.pid
33 33 $ cat hg.pid > $DAEMON_PIDS
34 34 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none$' > /dev/null
35 35
36 36 $ killdaemons.py
37 37
38 38 Order of engines can also change
39 39
40 40 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
41 41 $ cat hg.pid > $DAEMON_PIDS
42 42 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=capabilities' | tr ' ' '\n' | grep '^compression=none,zlib$' > /dev/null
43 43
44 44 $ killdaemons.py
45 45
46 46 Start a default server again
47 47
48 48 $ hg serve -R server -p $HGPORT -d --pid-file hg.pid
49 49 $ cat hg.pid > $DAEMON_PIDS
50 50
51 51 Server should send application/mercurial-0.1 to clients if no Accept is used
52 52
53 53 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
54 54 200 Script output follows
55 55 content-type: application/mercurial-0.1
56 56 date: $HTTP_DATE$
57 57 server: testing stub value
58 58 transfer-encoding: chunked
59 59
60 60 Server should send application/mercurial-0.1 when client says it wants it
61 61
62 62 $ get-with-headers.py --hgproto '0.1' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
63 63 200 Script output follows
64 64 content-type: application/mercurial-0.1
65 65 date: $HTTP_DATE$
66 66 server: testing stub value
67 67 transfer-encoding: chunked
68 68
69 69 Server should send application/mercurial-0.2 when client says it wants it
70 70
71 71 $ get-with-headers.py --hgproto '0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
72 72 200 Script output follows
73 73 content-type: application/mercurial-0.2
74 74 date: $HTTP_DATE$
75 75 server: testing stub value
76 76 transfer-encoding: chunked
77 77
78 78 $ get-with-headers.py --hgproto '0.1 0.2' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
79 79 200 Script output follows
80 80 content-type: application/mercurial-0.2
81 81 date: $HTTP_DATE$
82 82 server: testing stub value
83 83 transfer-encoding: chunked
84 84
85 85 Requesting a compression format that server doesn't support results will fall back to 0.1
86 86
87 87 $ get-with-headers.py --hgproto '0.2 comp=aa' --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' -
88 88 200 Script output follows
89 89 content-type: application/mercurial-0.1
90 90 date: $HTTP_DATE$
91 91 server: testing stub value
92 92 transfer-encoding: chunked
93 93
94 94 #if zstd
95 95 zstd is used if available
96 96
97 97 $ get-with-headers.py --hgproto '0.2 comp=zstd' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
98 98 $ f --size --hexdump --bytes 36 --sha1 resp
99 99 resp: size=248, sha1=4d8d8f87fb82bd542ce52881fdc94f850748
100 100 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
101 101 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 73 74 64 |t follows...zstd|
102 102 0020: 28 b5 2f fd |(./.|
103 103
104 104 #endif
105 105
106 106 application/mercurial-0.2 is not yet used on non-streaming responses
107 107
108 108 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=heads' -
109 109 200 Script output follows
110 110 content-length: 41
111 111 content-type: application/mercurial-0.1
112 112 date: $HTTP_DATE$
113 113 server: testing stub value
114 114
115 115 e93700bd72895c5addab234c56d4024b487a362f
116 116
117 117 Now test protocol preference usage
118 118
119 119 $ killdaemons.py
120 120 $ hg serve --config server.compressionengines=none,zlib -R server -p $HGPORT -d --pid-file hg.pid
121 121 $ cat hg.pid > $DAEMON_PIDS
122 122
123 123 No Accept will send 0.1+zlib, even though "none" is preferred b/c "none" isn't supported on 0.1
124 124
125 125 $ get-with-headers.py --headeronly $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' Content-Type
126 126 200 Script output follows
127 127 content-type: application/mercurial-0.1
128 128
129 129 $ get-with-headers.py $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
130 130 $ f --size --hexdump --bytes 28 --sha1 resp
131 131 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
132 132 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
133 133 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
134 134
135 135 Explicit 0.1 will send zlib because "none" isn't supported on 0.1
136 136
137 137 $ get-with-headers.py --hgproto '0.1' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
138 138 $ f --size --hexdump --bytes 28 --sha1 resp
139 139 resp: size=227, sha1=35a4c074da74f32f5440da3cbf04
140 140 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
141 141 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 78 |t follows..x|
142 142
143 143 0.2 with no compression will get "none" because that is server's preference
144 144 (spec says ZL and UN are implicitly supported)
145 145
146 146 $ get-with-headers.py --hgproto '0.2' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
147 147 $ f --size --hexdump --bytes 32 --sha1 resp
148 148 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
149 149 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
150 150 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
151 151
152 152 Client receives server preference even if local order doesn't match
153 153
154 154 $ get-with-headers.py --hgproto '0.2 comp=zlib,none' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
155 155 $ f --size --hexdump --bytes 32 --sha1 resp
156 156 resp: size=432, sha1=ac931b412ec185a02e0e5bcff98dac83
157 157 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
158 158 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 6e 6f 6e 65 |t follows...none|
159 159
160 160 Client receives only supported format even if not server preferred format
161 161
162 162 $ get-with-headers.py --hgproto '0.2 comp=zlib' $LOCALIP:$HGPORT '?cmd=getbundle&heads=e93700bd72895c5addab234c56d4024b487a362f&common=0000000000000000000000000000000000000000' > resp
163 163 $ f --size --hexdump --bytes 33 --sha1 resp
164 164 resp: size=232, sha1=a1c727f0c9693ca15742a75c30419bc36
165 165 0000: 32 30 30 20 53 63 72 69 70 74 20 6f 75 74 70 75 |200 Script outpu|
166 166 0010: 74 20 66 6f 6c 6c 6f 77 73 0a 0a 04 7a 6c 69 62 |t follows...zlib|
167 167 0020: 78 |x|
168 168
169 169 $ killdaemons.py
170 170 $ cd ..
171 171
172 172 Test listkeys for listing namespaces
173 173
174 174 $ hg init empty
175 175 $ hg -R empty serve -p $HGPORT -d --pid-file hg.pid
176 176 $ cat hg.pid > $DAEMON_PIDS
177 177
178 178 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
179 179 > command listkeys
180 180 > namespace namespaces
181 181 > EOF
182 182 s> GET /?cmd=capabilities HTTP/1.1\r\n
183 183 s> Accept-Encoding: identity\r\n
184 184 s> accept: application/mercurial-0.1\r\n
185 185 s> host: $LOCALIP:$HGPORT\r\n (glob)
186 186 s> user-agent: Mercurial debugwireproto\r\n
187 187 s> \r\n
188 188 s> makefile('rb', None)
189 189 s> HTTP/1.1 200 Script output follows\r\n
190 190 s> Server: testing stub value\r\n
191 191 s> Date: $HTTP_DATE$\r\n
192 192 s> Content-Type: application/mercurial-0.1\r\n
193 193 s> Content-Length: *\r\n (glob)
194 194 s> \r\n
195 195 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
196 196 sending listkeys command
197 197 s> GET /?cmd=listkeys HTTP/1.1\r\n
198 198 s> Accept-Encoding: identity\r\n
199 199 s> vary: X-HgArg-1,X-HgProto-1\r\n
200 200 s> x-hgarg-1: namespace=namespaces\r\n
201 201 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
202 202 s> accept: application/mercurial-0.1\r\n
203 203 s> host: $LOCALIP:$HGPORT\r\n (glob)
204 204 s> user-agent: Mercurial debugwireproto\r\n
205 205 s> \r\n
206 206 s> makefile('rb', None)
207 207 s> HTTP/1.1 200 Script output follows\r\n
208 208 s> Server: testing stub value\r\n
209 209 s> Date: $HTTP_DATE$\r\n
210 210 s> Content-Type: application/mercurial-0.1\r\n
211 211 s> Content-Length: 30\r\n
212 212 s> \r\n
213 213 s> bookmarks\t\n
214 214 s> namespaces\t\n
215 215 s> phases\t
216 216 response: {
217 217 b'bookmarks': b'',
218 218 b'namespaces': b'',
219 219 b'phases': b''
220 220 }
221 221
222 222 Same thing, but with "httprequest" command
223 223
224 224 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
225 225 > httprequest GET ?cmd=listkeys
226 226 > user-agent: test
227 227 > x-hgarg-1: namespace=namespaces
228 228 > EOF
229 229 using raw connection to peer
230 230 s> GET /?cmd=listkeys HTTP/1.1\r\n
231 231 s> Accept-Encoding: identity\r\n
232 232 s> user-agent: test\r\n
233 233 s> x-hgarg-1: namespace=namespaces\r\n
234 234 s> host: $LOCALIP:$HGPORT\r\n (glob)
235 235 s> \r\n
236 236 s> makefile('rb', None)
237 237 s> HTTP/1.1 200 Script output follows\r\n
238 238 s> Server: testing stub value\r\n
239 239 s> Date: $HTTP_DATE$\r\n
240 240 s> Content-Type: application/mercurial-0.1\r\n
241 241 s> Content-Length: 30\r\n
242 242 s> \r\n
243 243 s> bookmarks\t\n
244 244 s> namespaces\t\n
245 245 s> phases\t
246 246
247 247 Client with HTTPv2 enabled advertises that and gets old capabilities response from old server
248 248
249 249 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
250 250 > command heads
251 251 > EOF
252 252 s> GET /?cmd=capabilities HTTP/1.1\r\n
253 253 s> Accept-Encoding: identity\r\n
254 254 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
255 255 s> x-hgproto-1: cbor\r\n
256 256 s> x-hgupgrade-1: exp-http-v2-0001\r\n
257 257 s> accept: application/mercurial-0.1\r\n
258 258 s> host: $LOCALIP:$HGPORT\r\n (glob)
259 259 s> user-agent: Mercurial debugwireproto\r\n
260 260 s> \r\n
261 261 s> makefile('rb', None)
262 262 s> HTTP/1.1 200 Script output follows\r\n
263 263 s> Server: testing stub value\r\n
264 264 s> Date: $HTTP_DATE$\r\n
265 265 s> Content-Type: application/mercurial-0.1\r\n
266 266 s> Content-Length: *\r\n (glob)
267 267 s> \r\n
268 268 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
269 269 sending heads command
270 270 s> GET /?cmd=heads HTTP/1.1\r\n
271 271 s> Accept-Encoding: identity\r\n
272 272 s> vary: X-HgProto-1\r\n
273 273 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
274 274 s> accept: application/mercurial-0.1\r\n
275 275 s> host: $LOCALIP:$HGPORT\r\n (glob)
276 276 s> user-agent: Mercurial debugwireproto\r\n
277 277 s> \r\n
278 278 s> makefile('rb', None)
279 279 s> HTTP/1.1 200 Script output follows\r\n
280 280 s> Server: testing stub value\r\n
281 281 s> Date: $HTTP_DATE$\r\n
282 282 s> Content-Type: application/mercurial-0.1\r\n
283 283 s> Content-Length: 41\r\n
284 284 s> \r\n
285 285 s> 0000000000000000000000000000000000000000\n
286 286 response: [
287 287 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
288 288 ]
289 289
290 290 $ killdaemons.py
291 291 $ enablehttpv2 empty
292 292 $ hg --config server.compressionengines=zlib -R empty serve -p $HGPORT -d --pid-file hg.pid
293 293 $ cat hg.pid > $DAEMON_PIDS
294 294
295 295 Client with HTTPv2 enabled automatically upgrades if the server supports it
296 296
297 297 $ hg --config experimental.httppeer.advertise-v2=true --verbose debugwireproto http://$LOCALIP:$HGPORT << EOF
298 298 > command heads
299 299 > EOF
300 300 s> GET /?cmd=capabilities HTTP/1.1\r\n
301 301 s> Accept-Encoding: identity\r\n
302 302 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
303 303 s> x-hgproto-1: cbor\r\n
304 304 s> x-hgupgrade-1: exp-http-v2-0001\r\n
305 305 s> accept: application/mercurial-0.1\r\n
306 306 s> host: $LOCALIP:$HGPORT\r\n (glob)
307 307 s> user-agent: Mercurial debugwireproto\r\n
308 308 s> \r\n
309 309 s> makefile('rb', None)
310 310 s> HTTP/1.1 200 OK\r\n
311 311 s> Server: testing stub value\r\n
312 312 s> Date: $HTTP_DATE$\r\n
313 313 s> Content-Type: application/mercurial-cbor\r\n
314 314 s> Content-Length: *\r\n (glob)
315 315 s> \r\n
316 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
316 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
317 317 sending heads command
318 318 s> POST /api/exp-http-v2-0001/ro/heads HTTP/1.1\r\n
319 319 s> Accept-Encoding: identity\r\n
320 320 s> accept: application/mercurial-exp-framing-0005\r\n
321 321 s> content-type: application/mercurial-exp-framing-0005\r\n
322 322 s> content-length: 20\r\n
323 323 s> host: $LOCALIP:$HGPORT\r\n (glob)
324 324 s> user-agent: Mercurial debugwireproto\r\n
325 325 s> \r\n
326 326 s> \x0c\x00\x00\x01\x00\x01\x01\x11\xa1DnameEheads
327 327 s> makefile('rb', None)
328 328 s> HTTP/1.1 200 OK\r\n
329 329 s> Server: testing stub value\r\n
330 330 s> Date: $HTTP_DATE$\r\n
331 331 s> Content-Type: application/mercurial-exp-framing-0005\r\n
332 332 s> Transfer-Encoding: chunked\r\n
333 333 s> \r\n
334 334 s> 13\r\n
335 335 s> \x0b\x00\x00\x01\x00\x02\x011
336 336 s> \xa1FstatusBok
337 337 s> \r\n
338 338 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
339 339 s> 1e\r\n
340 340 s> \x16\x00\x00\x01\x00\x02\x001
341 341 s> \x81T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
342 342 s> \r\n
343 343 received frame(size=22; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
344 344 s> 8\r\n
345 345 s> \x00\x00\x00\x01\x00\x02\x002
346 346 s> \r\n
347 347 s> 0\r\n
348 348 s> \r\n
349 349 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
350 350 response: [
351 351 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
352 352 ]
353 353
354 354 $ killdaemons.py
355 355
356 356 HTTP client follows HTTP redirect on handshake to new repo
357 357
358 358 $ cd $TESTTMP
359 359
360 360 $ hg init redirector
361 361 $ hg init redirected
362 362 $ cd redirected
363 363 $ touch foo
364 364 $ hg -q commit -A -m initial
365 365 $ cd ..
366 366
367 367 $ cat > paths.conf << EOF
368 368 > [paths]
369 369 > / = $TESTTMP/*
370 370 > EOF
371 371
372 372 $ cat > redirectext.py << EOF
373 373 > from mercurial import extensions, wireprotoserver
374 374 > def wrappedcallhttp(orig, repo, req, res, proto, cmd):
375 375 > path = req.advertisedurl[len(req.advertisedbaseurl):]
376 376 > if not path.startswith(b'/redirector'):
377 377 > return orig(repo, req, res, proto, cmd)
378 378 > relpath = path[len(b'/redirector'):]
379 379 > res.status = b'301 Redirect'
380 380 > newurl = b'%s/redirected%s' % (req.baseurl, relpath)
381 381 > if not repo.ui.configbool('testing', 'redirectqs', True) and b'?' in newurl:
382 382 > newurl = newurl[0:newurl.index(b'?')]
383 383 > res.headers[b'Location'] = newurl
384 384 > res.headers[b'Content-Type'] = b'text/plain'
385 385 > res.setbodybytes(b'redirected')
386 386 > return True
387 387 >
388 388 > extensions.wrapfunction(wireprotoserver, '_callhttp', wrappedcallhttp)
389 389 > EOF
390 390
391 391 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
392 392 > --config server.compressionengines=zlib \
393 393 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
394 394 $ cat hg.pid > $DAEMON_PIDS
395 395
396 396 Verify our HTTP 301 is served properly
397 397
398 398 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
399 399 > httprequest GET /redirector?cmd=capabilities
400 400 > user-agent: test
401 401 > EOF
402 402 using raw connection to peer
403 403 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
404 404 s> Accept-Encoding: identity\r\n
405 405 s> user-agent: test\r\n
406 406 s> host: $LOCALIP:$HGPORT\r\n (glob)
407 407 s> \r\n
408 408 s> makefile('rb', None)
409 409 s> HTTP/1.1 301 Redirect\r\n
410 410 s> Server: testing stub value\r\n
411 411 s> Date: $HTTP_DATE$\r\n
412 412 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
413 413 s> Content-Type: text/plain\r\n
414 414 s> Content-Length: 10\r\n
415 415 s> \r\n
416 416 s> redirected
417 417 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
418 418 s> Accept-Encoding: identity\r\n
419 419 s> user-agent: test\r\n
420 420 s> host: $LOCALIP:$HGPORT\r\n (glob)
421 421 s> \r\n
422 422 s> makefile('rb', None)
423 423 s> HTTP/1.1 200 Script output follows\r\n
424 424 s> Server: testing stub value\r\n
425 425 s> Date: $HTTP_DATE$\r\n
426 426 s> Content-Type: application/mercurial-0.1\r\n
427 427 s> Content-Length: 453\r\n
428 428 s> \r\n
429 429 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
430 430
431 431 Test with the HTTP peer
432 432
433 433 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
434 434 > command heads
435 435 > EOF
436 436 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
437 437 s> Accept-Encoding: identity\r\n
438 438 s> accept: application/mercurial-0.1\r\n
439 439 s> host: $LOCALIP:$HGPORT\r\n (glob)
440 440 s> user-agent: Mercurial debugwireproto\r\n
441 441 s> \r\n
442 442 s> makefile('rb', None)
443 443 s> HTTP/1.1 301 Redirect\r\n
444 444 s> Server: testing stub value\r\n
445 445 s> Date: $HTTP_DATE$\r\n
446 446 s> Location: http://$LOCALIP:$HGPORT/redirected?cmd=capabilities\r\n (glob)
447 447 s> Content-Type: text/plain\r\n
448 448 s> Content-Length: 10\r\n
449 449 s> \r\n
450 450 s> redirected
451 451 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
452 452 s> Accept-Encoding: identity\r\n
453 453 s> accept: application/mercurial-0.1\r\n
454 454 s> host: $LOCALIP:$HGPORT\r\n (glob)
455 455 s> user-agent: Mercurial debugwireproto\r\n
456 456 s> \r\n
457 457 s> makefile('rb', None)
458 458 s> HTTP/1.1 200 Script output follows\r\n
459 459 s> Server: testing stub value\r\n
460 460 s> Date: $HTTP_DATE$\r\n
461 461 s> Content-Type: application/mercurial-0.1\r\n
462 462 s> Content-Length: 453\r\n
463 463 s> \r\n
464 464 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
465 465 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
466 466 sending heads command
467 467 s> GET /redirected?cmd=heads HTTP/1.1\r\n
468 468 s> Accept-Encoding: identity\r\n
469 469 s> vary: X-HgProto-1\r\n
470 470 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
471 471 s> accept: application/mercurial-0.1\r\n
472 472 s> host: $LOCALIP:$HGPORT\r\n (glob)
473 473 s> user-agent: Mercurial debugwireproto\r\n
474 474 s> \r\n
475 475 s> makefile('rb', None)
476 476 s> HTTP/1.1 200 Script output follows\r\n
477 477 s> Server: testing stub value\r\n
478 478 s> Date: $HTTP_DATE$\r\n
479 479 s> Content-Type: application/mercurial-0.1\r\n
480 480 s> Content-Length: 41\r\n
481 481 s> \r\n
482 482 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
483 483 response: [
484 484 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
485 485 ]
486 486
487 487 $ killdaemons.py
488 488
489 489 Now test a variation where we strip the query string from the redirect URL.
490 490 (SCM Manager apparently did this and clients would recover from it)
491 491
492 492 $ hg --config extensions.redirect=$TESTTMP/redirectext.py \
493 493 > --config server.compressionengines=zlib \
494 494 > --config testing.redirectqs=false \
495 495 > serve --web-conf paths.conf --pid-file hg.pid -p $HGPORT -d
496 496 $ cat hg.pid > $DAEMON_PIDS
497 497
498 498 $ hg --verbose debugwireproto --peer raw http://$LOCALIP:$HGPORT << EOF
499 499 > httprequest GET /redirector?cmd=capabilities
500 500 > user-agent: test
501 501 > EOF
502 502 using raw connection to peer
503 503 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
504 504 s> Accept-Encoding: identity\r\n
505 505 s> user-agent: test\r\n
506 506 s> host: $LOCALIP:$HGPORT\r\n (glob)
507 507 s> \r\n
508 508 s> makefile('rb', None)
509 509 s> HTTP/1.1 301 Redirect\r\n
510 510 s> Server: testing stub value\r\n
511 511 s> Date: $HTTP_DATE$\r\n
512 512 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
513 513 s> Content-Type: text/plain\r\n
514 514 s> Content-Length: 10\r\n
515 515 s> \r\n
516 516 s> redirected
517 517 s> GET /redirected HTTP/1.1\r\n
518 518 s> Accept-Encoding: identity\r\n
519 519 s> user-agent: test\r\n
520 520 s> host: $LOCALIP:$HGPORT\r\n (glob)
521 521 s> \r\n
522 522 s> makefile('rb', None)
523 523 s> HTTP/1.1 200 Script output follows\r\n
524 524 s> Server: testing stub value\r\n
525 525 s> Date: $HTTP_DATE$\r\n
526 526 s> ETag: W/"*"\r\n (glob)
527 527 s> Content-Type: text/html; charset=ascii\r\n
528 528 s> Transfer-Encoding: chunked\r\n
529 529 s> \r\n
530 530 s> 414\r\n
531 531 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
532 532 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
533 533 s> <head>\n
534 534 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
535 535 s> <meta name="robots" content="index, nofollow" />\n
536 536 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
537 537 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
538 538 s> \n
539 539 s> <title>redirected: log</title>\n
540 540 s> <link rel="alternate" type="application/atom+xml"\n
541 541 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
542 542 s> <link rel="alternate" type="application/rss+xml"\n
543 543 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
544 544 s> </head>\n
545 545 s> <body>\n
546 546 s> \n
547 547 s> <div class="container">\n
548 548 s> <div class="menu">\n
549 549 s> <div class="logo">\n
550 550 s> <a href="https://mercurial-scm.org/">\n
551 551 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
552 552 s> </div>\n
553 553 s> <ul>\n
554 554 s> <li class="active">log</li>\n
555 555 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
556 556 s> <li><a href="/redirected/tags">tags</a></li>\n
557 557 s> <li><a href="
558 558 s> \r\n
559 559 s> 810\r\n
560 560 s> /redirected/bookmarks">bookmarks</a></li>\n
561 561 s> <li><a href="/redirected/branches">branches</a></li>\n
562 562 s> </ul>\n
563 563 s> <ul>\n
564 564 s> <li><a href="/redirected/rev/tip">changeset</a></li>\n
565 565 s> <li><a href="/redirected/file/tip">browse</a></li>\n
566 566 s> </ul>\n
567 567 s> <ul>\n
568 568 s> \n
569 569 s> </ul>\n
570 570 s> <ul>\n
571 571 s> <li><a href="/redirected/help">help</a></li>\n
572 572 s> </ul>\n
573 573 s> <div class="atom-logo">\n
574 574 s> <a href="/redirected/atom-log" title="subscribe to atom feed">\n
575 575 s> <img class="atom-logo" src="/redirected/static/feed-icon-14x14.png" alt="atom feed" />\n
576 576 s> </a>\n
577 577 s> </div>\n
578 578 s> </div>\n
579 579 s> \n
580 580 s> <div class="main">\n
581 581 s> <h2 class="breadcrumb"><a href="/">Mercurial</a> &gt; <a href="/redirected">redirected</a> </h2>\n
582 582 s> <h3>log</h3>\n
583 583 s> \n
584 584 s> \n
585 585 s> <form class="search" action="/redirected/log">\n
586 586 s> \n
587 587 s> <p><input name="rev" id="search1" type="text" size="30" value="" /></p>\n
588 588 s> <div id="hint">Find changesets by keywords (author, files, the commit message), revision\n
589 589 s> number or hash, or <a href="/redirected/help/revsets">revset expression</a>.</div>\n
590 590 s> </form>\n
591 591 s> \n
592 592 s> <div class="navigate">\n
593 593 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
594 594 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
595 595 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
596 596 s> </div>\n
597 597 s> \n
598 598 s> <table class="bigtable">\n
599 599 s> <thead>\n
600 600 s> <tr>\n
601 601 s> <th class="age">age</th>\n
602 602 s> <th class="author">author</th>\n
603 603 s> <th class="description">description</th>\n
604 604 s> </tr>\n
605 605 s> </thead>\n
606 606 s> <tbody class="stripes2">\n
607 607 s> <tr>\n
608 608 s> <td class="age">Thu, 01 Jan 1970 00:00:00 +0000</td>\n
609 609 s> <td class="author">test</td>\n
610 610 s> <td class="description">\n
611 611 s> <a href="/redirected/rev/96ee1d7354c4">initial</a>\n
612 612 s> <span class="phase">draft</span> <span class="branchhead">default</span> <span class="tag">tip</span> \n
613 613 s> </td>\n
614 614 s> </tr>\n
615 615 s> \n
616 616 s> </tbody>\n
617 617 s> </table>\n
618 618 s> \n
619 619 s> <div class="navigate">\n
620 620 s> <a href="/redirected/shortlog/tip?revcount=30">less</a>\n
621 621 s> <a href="/redirected/shortlog/tip?revcount=120">more</a>\n
622 622 s> | rev 0: <a href="/redirected/shortlog/96ee1d7354c4">(0)</a> <a href="/redirected/shortlog/tip">tip</a> \n
623 623 s> </div>\n
624 624 s> \n
625 625 s> <script type="text/javascript">\n
626 626 s> ajaxScrollInit(\n
627 627 s> \'/redirected/shortlog/%next%\',\n
628 628 s> \'\', <!-- NEXTHASH\n
629 629 s> function (htmlText) {
630 630 s> \r\n
631 631 s> 14a\r\n
632 632 s> \n
633 633 s> var m = htmlText.match(/\'(\\w+)\', <!-- NEXTHASH/);\n
634 634 s> return m ? m[1] : null;\n
635 635 s> },\n
636 636 s> \'.bigtable > tbody\',\n
637 637 s> \'<tr class="%class%">\\\n
638 638 s> <td colspan="3" style="text-align: center;">%text%</td>\\\n
639 639 s> </tr>\'\n
640 640 s> );\n
641 641 s> </script>\n
642 642 s> \n
643 643 s> </div>\n
644 644 s> </div>\n
645 645 s> \n
646 646 s> \n
647 647 s> \n
648 648 s> </body>\n
649 649 s> </html>\n
650 650 s> \n
651 651 s> \r\n
652 652 s> 0\r\n
653 653 s> \r\n
654 654
655 655 $ hg --verbose debugwireproto http://$LOCALIP:$HGPORT/redirector << EOF
656 656 > command heads
657 657 > EOF
658 658 s> GET /redirector?cmd=capabilities HTTP/1.1\r\n
659 659 s> Accept-Encoding: identity\r\n
660 660 s> accept: application/mercurial-0.1\r\n
661 661 s> host: $LOCALIP:$HGPORT\r\n (glob)
662 662 s> user-agent: Mercurial debugwireproto\r\n
663 663 s> \r\n
664 664 s> makefile('rb', None)
665 665 s> HTTP/1.1 301 Redirect\r\n
666 666 s> Server: testing stub value\r\n
667 667 s> Date: $HTTP_DATE$\r\n
668 668 s> Location: http://$LOCALIP:$HGPORT/redirected\r\n (glob)
669 669 s> Content-Type: text/plain\r\n
670 670 s> Content-Length: 10\r\n
671 671 s> \r\n
672 672 s> redirected
673 673 s> GET /redirected HTTP/1.1\r\n
674 674 s> Accept-Encoding: identity\r\n
675 675 s> accept: application/mercurial-0.1\r\n
676 676 s> host: $LOCALIP:$HGPORT\r\n (glob)
677 677 s> user-agent: Mercurial debugwireproto\r\n
678 678 s> \r\n
679 679 s> makefile('rb', None)
680 680 s> HTTP/1.1 200 Script output follows\r\n
681 681 s> Server: testing stub value\r\n
682 682 s> Date: $HTTP_DATE$\r\n
683 683 s> ETag: W/"*"\r\n (glob)
684 684 s> Content-Type: text/html; charset=ascii\r\n
685 685 s> Transfer-Encoding: chunked\r\n
686 686 s> \r\n
687 687 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
688 688 s> 414\r\n
689 689 s> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n
690 690 s> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">\n
691 691 s> <head>\n
692 692 s> <link rel="icon" href="/redirected/static/hgicon.png" type="image/png" />\n
693 693 s> <meta name="robots" content="index, nofollow" />\n
694 694 s> <link rel="stylesheet" href="/redirected/static/style-paper.css" type="text/css" />\n
695 695 s> <script type="text/javascript" src="/redirected/static/mercurial.js"></script>\n
696 696 s> \n
697 697 s> <title>redirected: log</title>\n
698 698 s> <link rel="alternate" type="application/atom+xml"\n
699 699 s> href="/redirected/atom-log" title="Atom feed for redirected" />\n
700 700 s> <link rel="alternate" type="application/rss+xml"\n
701 701 s> href="/redirected/rss-log" title="RSS feed for redirected" />\n
702 702 s> </head>\n
703 703 s> <body>\n
704 704 s> \n
705 705 s> <div class="container">\n
706 706 s> <div class="menu">\n
707 707 s> <div class="logo">\n
708 708 s> <a href="https://mercurial-scm.org/">\n
709 709 s> <img src="/redirected/static/hglogo.png" alt="mercurial" /></a>\n
710 710 s> </div>\n
711 711 s> <ul>\n
712 712 s> <li class="active">log</li>\n
713 713 s> <li><a href="/redirected/graph/tip">graph</a></li>\n
714 714 s> <li><a href="/redirected/tags">tags</a
715 715 s> GET /redirected?cmd=capabilities HTTP/1.1\r\n
716 716 s> Accept-Encoding: identity\r\n
717 717 s> accept: application/mercurial-0.1\r\n
718 718 s> host: $LOCALIP:$HGPORT\r\n (glob)
719 719 s> user-agent: Mercurial debugwireproto\r\n
720 720 s> \r\n
721 721 s> makefile('rb', None)
722 722 s> HTTP/1.1 200 Script output follows\r\n
723 723 s> Server: testing stub value\r\n
724 724 s> Date: $HTTP_DATE$\r\n
725 725 s> Content-Type: application/mercurial-0.1\r\n
726 726 s> Content-Length: 453\r\n
727 727 s> \r\n
728 728 real URL is http://$LOCALIP:$HGPORT/redirected (glob)
729 729 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
730 730 sending heads command
731 731 s> GET /redirected?cmd=heads HTTP/1.1\r\n
732 732 s> Accept-Encoding: identity\r\n
733 733 s> vary: X-HgProto-1\r\n
734 734 s> x-hgproto-1: 0.1 0.2 comp=$USUAL_COMPRESSIONS$ partial-pull\r\n
735 735 s> accept: application/mercurial-0.1\r\n
736 736 s> host: $LOCALIP:$HGPORT\r\n (glob)
737 737 s> user-agent: Mercurial debugwireproto\r\n
738 738 s> \r\n
739 739 s> makefile('rb', None)
740 740 s> HTTP/1.1 200 Script output follows\r\n
741 741 s> Server: testing stub value\r\n
742 742 s> Date: $HTTP_DATE$\r\n
743 743 s> Content-Type: application/mercurial-0.1\r\n
744 744 s> Content-Length: 41\r\n
745 745 s> \r\n
746 746 s> 96ee1d7354c4ad7372047672c36a1f561e3a6a4c\n
747 747 response: [
748 748 b'\x96\xee\x1dsT\xc4\xadsr\x04vr\xc3j\x1fV\x1e:jL'
749 749 ]
@@ -1,532 +1,536
1 1 #require no-chg
2 2
3 3 $ . $TESTDIR/wireprotohelpers.sh
4 4
5 5 $ hg init server
6 6
7 7 zstd isn't present in plain builds. Make tests easier by removing
8 8 zstd from the equation.
9 9
10 10 $ cat >> server/.hg/hgrc << EOF
11 11 > [server]
12 12 > compressionengines = zlib
13 13 > EOF
14 14
15 15 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
16 16 $ cat hg.pid > $DAEMON_PIDS
17 17
18 18 A normal capabilities request is serviced for version 1
19 19
20 20 $ sendhttpraw << EOF
21 21 > httprequest GET ?cmd=capabilities
22 22 > user-agent: test
23 23 > EOF
24 24 using raw connection to peer
25 25 s> GET /?cmd=capabilities HTTP/1.1\r\n
26 26 s> Accept-Encoding: identity\r\n
27 27 s> user-agent: test\r\n
28 28 s> host: $LOCALIP:$HGPORT\r\n (glob)
29 29 s> \r\n
30 30 s> makefile('rb', None)
31 31 s> HTTP/1.1 200 Script output follows\r\n
32 32 s> Server: testing stub value\r\n
33 33 s> Date: $HTTP_DATE$\r\n
34 34 s> Content-Type: application/mercurial-0.1\r\n
35 35 s> Content-Length: *\r\n (glob)
36 36 s> \r\n
37 37 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
38 38
39 39 A proper request without the API server enabled returns the legacy response
40 40
41 41 $ sendhttpraw << EOF
42 42 > httprequest GET ?cmd=capabilities
43 43 > user-agent: test
44 44 > x-hgupgrade-1: foo
45 45 > x-hgproto-1: cbor
46 46 > EOF
47 47 using raw connection to peer
48 48 s> GET /?cmd=capabilities HTTP/1.1\r\n
49 49 s> Accept-Encoding: identity\r\n
50 50 s> user-agent: test\r\n
51 51 s> x-hgproto-1: cbor\r\n
52 52 s> x-hgupgrade-1: foo\r\n
53 53 s> host: $LOCALIP:$HGPORT\r\n (glob)
54 54 s> \r\n
55 55 s> makefile('rb', None)
56 56 s> HTTP/1.1 200 Script output follows\r\n
57 57 s> Server: testing stub value\r\n
58 58 s> Date: $HTTP_DATE$\r\n
59 59 s> Content-Type: application/mercurial-0.1\r\n
60 60 s> Content-Length: *\r\n (glob)
61 61 s> \r\n
62 62 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
63 63
64 64 Restart with just API server enabled. This enables serving the new format.
65 65
66 66 $ killdaemons.py
67 67 $ cat error.log
68 68
69 69 $ cat >> server/.hg/hgrc << EOF
70 70 > [experimental]
71 71 > web.apiserver = true
72 72 > EOF
73 73
74 74 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
75 75 $ cat hg.pid > $DAEMON_PIDS
76 76
77 77 X-HgUpgrade-<N> without CBOR advertisement uses legacy response
78 78
79 79 $ sendhttpraw << EOF
80 80 > httprequest GET ?cmd=capabilities
81 81 > user-agent: test
82 82 > x-hgupgrade-1: foo bar
83 83 > EOF
84 84 using raw connection to peer
85 85 s> GET /?cmd=capabilities HTTP/1.1\r\n
86 86 s> Accept-Encoding: identity\r\n
87 87 s> user-agent: test\r\n
88 88 s> x-hgupgrade-1: foo bar\r\n
89 89 s> host: $LOCALIP:$HGPORT\r\n (glob)
90 90 s> \r\n
91 91 s> makefile('rb', None)
92 92 s> HTTP/1.1 200 Script output follows\r\n
93 93 s> Server: testing stub value\r\n
94 94 s> Date: $HTTP_DATE$\r\n
95 95 s> Content-Type: application/mercurial-0.1\r\n
96 96 s> Content-Length: *\r\n (glob)
97 97 s> \r\n
98 98 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
99 99
100 100 X-HgUpgrade-<N> without known serialization in X-HgProto-<N> uses legacy response
101 101
102 102 $ sendhttpraw << EOF
103 103 > httprequest GET ?cmd=capabilities
104 104 > user-agent: test
105 105 > x-hgupgrade-1: foo bar
106 106 > x-hgproto-1: some value
107 107 > EOF
108 108 using raw connection to peer
109 109 s> GET /?cmd=capabilities HTTP/1.1\r\n
110 110 s> Accept-Encoding: identity\r\n
111 111 s> user-agent: test\r\n
112 112 s> x-hgproto-1: some value\r\n
113 113 s> x-hgupgrade-1: foo bar\r\n
114 114 s> host: $LOCALIP:$HGPORT\r\n (glob)
115 115 s> \r\n
116 116 s> makefile('rb', None)
117 117 s> HTTP/1.1 200 Script output follows\r\n
118 118 s> Server: testing stub value\r\n
119 119 s> Date: $HTTP_DATE$\r\n
120 120 s> Content-Type: application/mercurial-0.1\r\n
121 121 s> Content-Length: *\r\n (glob)
122 122 s> \r\n
123 123 s> batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
124 124
125 125 X-HgUpgrade-<N> + X-HgProto-<N> headers trigger new response format
126 126
127 127 $ sendhttpraw << EOF
128 128 > httprequest GET ?cmd=capabilities
129 129 > user-agent: test
130 130 > x-hgupgrade-1: foo bar
131 131 > x-hgproto-1: cbor
132 132 > EOF
133 133 using raw connection to peer
134 134 s> GET /?cmd=capabilities HTTP/1.1\r\n
135 135 s> Accept-Encoding: identity\r\n
136 136 s> user-agent: test\r\n
137 137 s> x-hgproto-1: cbor\r\n
138 138 s> x-hgupgrade-1: foo bar\r\n
139 139 s> host: $LOCALIP:$HGPORT\r\n (glob)
140 140 s> \r\n
141 141 s> makefile('rb', None)
142 142 s> HTTP/1.1 200 OK\r\n
143 143 s> Server: testing stub value\r\n
144 144 s> Date: $HTTP_DATE$\r\n
145 145 s> Content-Type: application/mercurial-cbor\r\n
146 146 s> Content-Length: *\r\n (glob)
147 147 s> \r\n
148 148 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
149 149 cbor> {
150 150 b'apibase': b'api/',
151 151 b'apis': {},
152 152 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
153 153 }
154 154
155 155 Restart server to enable HTTPv2
156 156
157 157 $ killdaemons.py
158 158 $ enablehttpv2 server
159 159 $ hg -R server serve -p $HGPORT -d --pid-file hg.pid -E error.log
160 160 $ cat hg.pid > $DAEMON_PIDS
161 161
162 162 Only requested API services are returned
163 163
164 164 $ sendhttpraw << EOF
165 165 > httprequest GET ?cmd=capabilities
166 166 > user-agent: test
167 167 > x-hgupgrade-1: foo bar
168 168 > x-hgproto-1: cbor
169 169 > EOF
170 170 using raw connection to peer
171 171 s> GET /?cmd=capabilities HTTP/1.1\r\n
172 172 s> Accept-Encoding: identity\r\n
173 173 s> user-agent: test\r\n
174 174 s> x-hgproto-1: cbor\r\n
175 175 s> x-hgupgrade-1: foo bar\r\n
176 176 s> host: $LOCALIP:$HGPORT\r\n (glob)
177 177 s> \r\n
178 178 s> makefile('rb', None)
179 179 s> HTTP/1.1 200 OK\r\n
180 180 s> Server: testing stub value\r\n
181 181 s> Date: $HTTP_DATE$\r\n
182 182 s> Content-Type: application/mercurial-cbor\r\n
183 183 s> Content-Length: *\r\n (glob)
184 184 s> \r\n
185 185 s> \xa3GapibaseDapi/Dapis\xa0Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
186 186 cbor> {
187 187 b'apibase': b'api/',
188 188 b'apis': {},
189 189 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
190 190 }
191 191
192 192 Request for HTTPv2 service returns information about it
193 193
194 194 $ sendhttpraw << EOF
195 195 > httprequest GET ?cmd=capabilities
196 196 > user-agent: test
197 197 > x-hgupgrade-1: exp-http-v2-0001 foo bar
198 198 > x-hgproto-1: cbor
199 199 > EOF
200 200 using raw connection to peer
201 201 s> GET /?cmd=capabilities HTTP/1.1\r\n
202 202 s> Accept-Encoding: identity\r\n
203 203 s> user-agent: test\r\n
204 204 s> x-hgproto-1: cbor\r\n
205 205 s> x-hgupgrade-1: exp-http-v2-0001 foo bar\r\n
206 206 s> host: $LOCALIP:$HGPORT\r\n (glob)
207 207 s> \r\n
208 208 s> makefile('rb', None)
209 209 s> HTTP/1.1 200 OK\r\n
210 210 s> Server: testing stub value\r\n
211 211 s> Date: $HTTP_DATE$\r\n
212 212 s> Content-Type: application/mercurial-cbor\r\n
213 213 s> Content-Length: *\r\n (glob)
214 214 s> \r\n
215 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
215 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
216 216 cbor> {
217 217 b'apibase': b'api/',
218 218 b'apis': {
219 219 b'exp-http-v2-0001': {
220 220 b'commands': {
221 221 b'branchmap': {
222 222 b'args': {},
223 223 b'permissions': [
224 224 b'pull'
225 225 ]
226 226 },
227 227 b'capabilities': {
228 228 b'args': {},
229 229 b'permissions': [
230 230 b'pull'
231 231 ]
232 232 },
233 233 b'changesetdata': {
234 234 b'args': {
235 235 b'fields': set([
236 236 b'parents',
237 237 b'revision'
238 238 ]),
239 239 b'noderange': [
240 240 [
241 241 b'0123456...'
242 242 ],
243 243 [
244 244 b'abcdef...'
245 245 ]
246 246 ],
247 247 b'nodes': [
248 248 b'0123456...'
249 249 ]
250 250 },
251 251 b'permissions': [
252 252 b'pull'
253 253 ]
254 254 },
255 255 b'filedata': {
256 256 b'args': {
257 257 b'fields': [
258 258 b'parents',
259 259 b'revision'
260 260 ],
261 b'haveparents': True,
261 262 b'nodes': [
262 263 b'0123456...'
263 264 ],
264 265 b'path': b'foo.txt'
265 266 },
266 267 b'permissions': [
267 268 b'pull'
268 269 ]
269 270 },
270 271 b'heads': {
271 272 b'args': {
272 273 b'publiconly': False
273 274 },
274 275 b'permissions': [
275 276 b'pull'
276 277 ]
277 278 },
278 279 b'known': {
279 280 b'args': {
280 281 b'nodes': [
281 282 b'deadbeef'
282 283 ]
283 284 },
284 285 b'permissions': [
285 286 b'pull'
286 287 ]
287 288 },
288 289 b'listkeys': {
289 290 b'args': {
290 291 b'namespace': b'ns'
291 292 },
292 293 b'permissions': [
293 294 b'pull'
294 295 ]
295 296 },
296 297 b'lookup': {
297 298 b'args': {
298 299 b'key': b'foo'
299 300 },
300 301 b'permissions': [
301 302 b'pull'
302 303 ]
303 304 },
304 305 b'manifestdata': {
305 306 b'args': {
306 307 b'fields': [
307 308 b'parents',
308 309 b'revision'
309 310 ],
311 b'haveparents': True,
310 312 b'nodes': [
311 313 b'0123456...'
312 314 ],
313 315 b'tree': b''
314 316 },
315 317 b'permissions': [
316 318 b'pull'
317 319 ]
318 320 },
319 321 b'pushkey': {
320 322 b'args': {
321 323 b'key': b'key',
322 324 b'namespace': b'ns',
323 325 b'new': b'new',
324 326 b'old': b'old'
325 327 },
326 328 b'permissions': [
327 329 b'push'
328 330 ]
329 331 }
330 332 },
331 333 b'compression': [
332 334 {
333 335 b'name': b'zlib'
334 336 }
335 337 ],
336 338 b'framingmediatypes': [
337 339 b'application/mercurial-exp-framing-0005'
338 340 ],
339 341 b'rawrepoformats': [
340 342 b'generaldelta',
341 343 b'revlogv1'
342 344 ]
343 345 }
344 346 },
345 347 b'v1capabilities': b'batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash'
346 348 }
347 349
348 350 capabilities command returns expected info
349 351
350 352 $ sendhttpv2peerhandshake << EOF
351 353 > command capabilities
352 354 > EOF
353 355 creating http peer for wire protocol version 2
354 356 s> GET /?cmd=capabilities HTTP/1.1\r\n
355 357 s> Accept-Encoding: identity\r\n
356 358 s> vary: X-HgProto-1,X-HgUpgrade-1\r\n
357 359 s> x-hgproto-1: cbor\r\n
358 360 s> x-hgupgrade-1: exp-http-v2-0001\r\n
359 361 s> accept: application/mercurial-0.1\r\n
360 362 s> host: $LOCALIP:$HGPORT\r\n (glob)
361 363 s> user-agent: Mercurial debugwireproto\r\n
362 364 s> \r\n
363 365 s> makefile('rb', None)
364 366 s> HTTP/1.1 200 OK\r\n
365 367 s> Server: testing stub value\r\n
366 368 s> Date: $HTTP_DATE$\r\n
367 369 s> Content-Type: application/mercurial-cbor\r\n
368 370 s> Content-Length: *\r\n (glob)
369 371 s> \r\n
370 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
372 s> \xa3GapibaseDapi/Dapis\xa1Pexp-http-v2-0001\xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1Nv1capabilitiesY\x01\xc5batch branchmap $USUAL_BUNDLE2_CAPS_SERVER$ changegroupsubset compression=$BUNDLE2_COMPRESSIONS$ getbundle httpheader=1024 httpmediatype=0.1rx,0.1tx,0.2tx known lookup pushkey streamreqs=generaldelta,revlogv1 unbundle=HG10GZ,HG10BZ,HG10UN unbundlehash
371 373 sending capabilities command
372 374 s> POST /api/exp-http-v2-0001/ro/capabilities HTTP/1.1\r\n
373 375 s> Accept-Encoding: identity\r\n
374 376 s> accept: application/mercurial-exp-framing-0005\r\n
375 377 s> content-type: application/mercurial-exp-framing-0005\r\n
376 378 s> content-length: 27\r\n
377 379 s> host: $LOCALIP:$HGPORT\r\n (glob)
378 380 s> user-agent: Mercurial debugwireproto\r\n
379 381 s> \r\n
380 382 s> \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLcapabilities
381 383 s> makefile('rb', None)
382 384 s> HTTP/1.1 200 OK\r\n
383 385 s> Server: testing stub value\r\n
384 386 s> Date: $HTTP_DATE$\r\n
385 387 s> Content-Type: application/mercurial-exp-framing-0005\r\n
386 388 s> Transfer-Encoding: chunked\r\n
387 389 s> \r\n
388 390 s> 13\r\n
389 391 s> \x0b\x00\x00\x01\x00\x02\x011
390 392 s> \xa1FstatusBok
391 393 s> \r\n
392 394 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
393 s> 2f4\r\n
394 s> \xec\x02\x00\x01\x00\x02\x001
395 s> \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1
395 s> 30e\r\n
396 s> \x06\x03\x00\x01\x00\x02\x001
397 s> \xa4Hcommands\xaaIbranchmap\xa2Dargs\xa0Kpermissions\x81DpullLcapabilities\xa2Dargs\xa0Kpermissions\x81DpullMchangesetdata\xa2Dargs\xa3Ffields\xd9\x01\x02\x82GparentsHrevisionInoderange\x82\x81J0123456...\x81Iabcdef...Enodes\x81J0123456...Kpermissions\x81DpullHfiledata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...DpathGfoo.txtKpermissions\x81DpullEheads\xa2Dargs\xa1Jpubliconly\xf4Kpermissions\x81DpullEknown\xa2Dargs\xa1Enodes\x81HdeadbeefKpermissions\x81DpullHlistkeys\xa2Dargs\xa1InamespaceBnsKpermissions\x81DpullFlookup\xa2Dargs\xa1CkeyCfooKpermissions\x81DpullLmanifestdata\xa2Dargs\xa4Ffields\x82GparentsHrevisionKhaveparents\xf5Enodes\x81J0123456...Dtree@Kpermissions\x81DpullGpushkey\xa2Dargs\xa4CkeyCkeyInamespaceBnsCnewCnewColdColdKpermissions\x81DpushKcompression\x81\xa1DnameDzlibQframingmediatypes\x81X&application/mercurial-exp-framing-0005Nrawrepoformats\x82LgeneraldeltaHrevlogv1
396 398 s> \r\n
397 received frame(size=748; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
399 received frame(size=774; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
398 400 s> 8\r\n
399 401 s> \x00\x00\x00\x01\x00\x02\x002
400 402 s> \r\n
401 403 s> 0\r\n
402 404 s> \r\n
403 405 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
404 406 response: gen[
405 407 {
406 408 b'commands': {
407 409 b'branchmap': {
408 410 b'args': {},
409 411 b'permissions': [
410 412 b'pull'
411 413 ]
412 414 },
413 415 b'capabilities': {
414 416 b'args': {},
415 417 b'permissions': [
416 418 b'pull'
417 419 ]
418 420 },
419 421 b'changesetdata': {
420 422 b'args': {
421 423 b'fields': set([
422 424 b'parents',
423 425 b'revision'
424 426 ]),
425 427 b'noderange': [
426 428 [
427 429 b'0123456...'
428 430 ],
429 431 [
430 432 b'abcdef...'
431 433 ]
432 434 ],
433 435 b'nodes': [
434 436 b'0123456...'
435 437 ]
436 438 },
437 439 b'permissions': [
438 440 b'pull'
439 441 ]
440 442 },
441 443 b'filedata': {
442 444 b'args': {
443 445 b'fields': [
444 446 b'parents',
445 447 b'revision'
446 448 ],
449 b'haveparents': True,
447 450 b'nodes': [
448 451 b'0123456...'
449 452 ],
450 453 b'path': b'foo.txt'
451 454 },
452 455 b'permissions': [
453 456 b'pull'
454 457 ]
455 458 },
456 459 b'heads': {
457 460 b'args': {
458 461 b'publiconly': False
459 462 },
460 463 b'permissions': [
461 464 b'pull'
462 465 ]
463 466 },
464 467 b'known': {
465 468 b'args': {
466 469 b'nodes': [
467 470 b'deadbeef'
468 471 ]
469 472 },
470 473 b'permissions': [
471 474 b'pull'
472 475 ]
473 476 },
474 477 b'listkeys': {
475 478 b'args': {
476 479 b'namespace': b'ns'
477 480 },
478 481 b'permissions': [
479 482 b'pull'
480 483 ]
481 484 },
482 485 b'lookup': {
483 486 b'args': {
484 487 b'key': b'foo'
485 488 },
486 489 b'permissions': [
487 490 b'pull'
488 491 ]
489 492 },
490 493 b'manifestdata': {
491 494 b'args': {
492 495 b'fields': [
493 496 b'parents',
494 497 b'revision'
495 498 ],
499 b'haveparents': True,
496 500 b'nodes': [
497 501 b'0123456...'
498 502 ],
499 503 b'tree': b''
500 504 },
501 505 b'permissions': [
502 506 b'pull'
503 507 ]
504 508 },
505 509 b'pushkey': {
506 510 b'args': {
507 511 b'key': b'key',
508 512 b'namespace': b'ns',
509 513 b'new': b'new',
510 514 b'old': b'old'
511 515 },
512 516 b'permissions': [
513 517 b'push'
514 518 ]
515 519 }
516 520 },
517 521 b'compression': [
518 522 {
519 523 b'name': b'zlib'
520 524 }
521 525 ],
522 526 b'framingmediatypes': [
523 527 b'application/mercurial-exp-framing-0005'
524 528 ],
525 529 b'rawrepoformats': [
526 530 b'generaldelta',
527 531 b'revlogv1'
528 532 ]
529 533 }
530 534 ]
531 535
532 536 $ cat error.log
@@ -1,497 +1,604
1 1 $ . $TESTDIR/wireprotohelpers.sh
2 2
3 3 $ hg init server
4 4 $ enablehttpv2 server
5 5 $ cd server
6 6 $ echo a0 > a
7 7 $ echo b0 > b
8 8 $ mkdir -p dir0/child0 dir0/child1 dir1
9 9 $ echo c0 > dir0/c
10 10 $ echo d0 > dir0/d
11 11 $ echo e0 > dir0/child0/e
12 12 $ echo f0 > dir0/child1/f
13 13 $ hg -q commit -A -m 'commit 0'
14 14
15 15 $ echo a1 > a
16 16 $ echo d1 > dir0/d
17 17 $ hg commit -m 'commit 1'
18 18 $ echo f0 > dir0/child1/f
19 19 $ hg commit -m 'commit 2'
20 20 nothing changed
21 21 [1]
22 22
23 23 $ hg -q up -r 0
24 24 $ echo a2 > a
25 25 $ hg commit -m 'commit 3'
26 26 created new head
27 27
28 28 $ hg log -G -T '{rev}:{node} {desc}\n'
29 29 @ 2:c8757a2ffe552850d1e0dfe60d295ebf64c196d9 commit 3
30 30 |
31 31 | o 1:650165e803375748a94df471e5b58d85763e0b29 commit 1
32 32 |/
33 33 o 0:6d85ca1270b377d320098556ba5bfad34a9ee12d commit 0
34 34
35 35
36 36 $ hg --debug debugindex a
37 37 rev linkrev nodeid p1 p2
38 38 0 0 2b4eb07319bfa077a40a2f04913659aef0da42da 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
39 39 1 1 9a38122997b3ac97be2a9aa2e556838341fdf2cc 2b4eb07319bfa077a40a2f04913659aef0da42da 0000000000000000000000000000000000000000
40 40 2 2 0879345e39377229634b420c639454156726c6b6 2b4eb07319bfa077a40a2f04913659aef0da42da 0000000000000000000000000000000000000000
41 41
42 42 $ hg --debug debugindex dir0/child0/e
43 43 rev linkrev nodeid p1 p2
44 44 0 0 bbba6c06b30f443d34ff841bc985c4d0827c6be4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
45 45
46 46 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
47 47 $ cat hg.pid > $DAEMON_PIDS
48 48
49 49 Missing arguments is an error
50 50
51 51 $ sendhttpv2peer << EOF
52 52 > command filedata
53 53 > EOF
54 54 creating http peer for wire protocol version 2
55 55 sending filedata command
56 56 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
57 57 s> Accept-Encoding: identity\r\n
58 58 s> accept: application/mercurial-exp-framing-0005\r\n
59 59 s> content-type: application/mercurial-exp-framing-0005\r\n
60 60 s> content-length: 23\r\n
61 61 s> host: $LOCALIP:$HGPORT\r\n (glob)
62 62 s> user-agent: Mercurial debugwireproto\r\n
63 63 s> \r\n
64 64 s> \x0f\x00\x00\x01\x00\x01\x01\x11\xa1DnameHfiledata
65 65 s> makefile('rb', None)
66 66 s> HTTP/1.1 200 OK\r\n
67 67 s> Server: testing stub value\r\n
68 68 s> Date: $HTTP_DATE$\r\n
69 69 s> Content-Type: application/mercurial-exp-framing-0005\r\n
70 70 s> Transfer-Encoding: chunked\r\n
71 71 s> \r\n
72 72 s> 45\r\n
73 73 s> =\x00\x00\x01\x00\x02\x012
74 74 s> \xa2Eerror\xa1GmessageX\x1enodes argument must be definedFstatusEerror
75 75 s> \r\n
76 76 received frame(size=61; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
77 77 s> 0\r\n
78 78 s> \r\n
79 79 abort: nodes argument must be defined!
80 80 [255]
81 81
82 82 $ sendhttpv2peer << EOF
83 83 > command filedata
84 84 > nodes eval:[]
85 85 > EOF
86 86 creating http peer for wire protocol version 2
87 87 sending filedata command
88 88 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
89 89 s> Accept-Encoding: identity\r\n
90 90 s> accept: application/mercurial-exp-framing-0005\r\n
91 91 s> content-type: application/mercurial-exp-framing-0005\r\n
92 92 s> content-length: 36\r\n
93 93 s> host: $LOCALIP:$HGPORT\r\n (glob)
94 94 s> user-agent: Mercurial debugwireproto\r\n
95 95 s> \r\n
96 96 s> \x1c\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa1Enodes\x80DnameHfiledata
97 97 s> makefile('rb', None)
98 98 s> HTTP/1.1 200 OK\r\n
99 99 s> Server: testing stub value\r\n
100 100 s> Date: $HTTP_DATE$\r\n
101 101 s> Content-Type: application/mercurial-exp-framing-0005\r\n
102 102 s> Transfer-Encoding: chunked\r\n
103 103 s> \r\n
104 104 s> 44\r\n
105 105 s> <\x00\x00\x01\x00\x02\x012
106 106 s> \xa2Eerror\xa1GmessageX\x1dpath argument must be definedFstatusEerror
107 107 s> \r\n
108 108 received frame(size=60; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
109 109 s> 0\r\n
110 110 s> \r\n
111 111 abort: path argument must be defined!
112 112 [255]
113 113
114 114 Unknown node is an error
115 115
116 116 $ sendhttpv2peer << EOF
117 117 > command filedata
118 118 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
119 119 > path eval:b'a'
120 120 > EOF
121 121 creating http peer for wire protocol version 2
122 122 sending filedata command
123 123 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
124 124 s> Accept-Encoding: identity\r\n
125 125 s> accept: application/mercurial-exp-framing-0005\r\n
126 126 s> content-type: application/mercurial-exp-framing-0005\r\n
127 127 s> content-length: 64\r\n
128 128 s> host: $LOCALIP:$HGPORT\r\n (glob)
129 129 s> user-agent: Mercurial debugwireproto\r\n
130 130 s> \r\n
131 131 s> 8\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Enodes\x81T\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaaDpathAaDnameHfiledata
132 132 s> makefile('rb', None)
133 133 s> HTTP/1.1 200 OK\r\n
134 134 s> Server: testing stub value\r\n
135 135 s> Date: $HTTP_DATE$\r\n
136 136 s> Content-Type: application/mercurial-exp-framing-0005\r\n
137 137 s> Transfer-Encoding: chunked\r\n
138 138 s> \r\n
139 139 s> 6b\r\n
140 140 s> c\x00\x00\x01\x00\x02\x012
141 141 s> \xa2Eerror\xa2Dargs\x81X(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaGmessageUunknown file node: %sFstatusEerror
142 142 s> \r\n
143 143 received frame(size=99; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
144 144 s> 0\r\n
145 145 s> \r\n
146 146 abort: unknown file node: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!
147 147 [255]
148 148
149 149 Fetching a single revision returns just metadata by default
150 150
151 151 $ sendhttpv2peer << EOF
152 152 > command filedata
153 153 > nodes eval:[b'\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
154 154 > path eval:b'a'
155 155 > EOF
156 156 creating http peer for wire protocol version 2
157 157 sending filedata command
158 158 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
159 159 s> Accept-Encoding: identity\r\n
160 160 s> accept: application/mercurial-exp-framing-0005\r\n
161 161 s> content-type: application/mercurial-exp-framing-0005\r\n
162 162 s> content-length: 64\r\n
163 163 s> host: $LOCALIP:$HGPORT\r\n (glob)
164 164 s> user-agent: Mercurial debugwireproto\r\n
165 165 s> \r\n
166 166 s> 8\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Enodes\x81T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
167 167 s> makefile('rb', None)
168 168 s> HTTP/1.1 200 OK\r\n
169 169 s> Server: testing stub value\r\n
170 170 s> Date: $HTTP_DATE$\r\n
171 171 s> Content-Type: application/mercurial-exp-framing-0005\r\n
172 172 s> Transfer-Encoding: chunked\r\n
173 173 s> \r\n
174 174 s> 13\r\n
175 175 s> \x0b\x00\x00\x01\x00\x02\x011
176 176 s> \xa1FstatusBok
177 177 s> \r\n
178 178 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
179 179 s> 30\r\n
180 180 s> (\x00\x00\x01\x00\x02\x001
181 181 s> \xa1Jtotalitems\x01\xa1DnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc
182 182 s> \r\n
183 183 received frame(size=40; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
184 184 s> 8\r\n
185 185 s> \x00\x00\x00\x01\x00\x02\x002
186 186 s> \r\n
187 187 s> 0\r\n
188 188 s> \r\n
189 189 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
190 190 response: gen[
191 191 {
192 192 b'totalitems': 1
193 193 },
194 194 {
195 195 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc'
196 196 }
197 197 ]
198 198
199 199 Requesting parents works
200 200
201 201 $ sendhttpv2peer << EOF
202 202 > command filedata
203 203 > nodes eval:[b'\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
204 204 > path eval:b'a'
205 205 > fields eval:[b'parents']
206 206 > EOF
207 207 creating http peer for wire protocol version 2
208 208 sending filedata command
209 209 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
210 210 s> Accept-Encoding: identity\r\n
211 211 s> accept: application/mercurial-exp-framing-0005\r\n
212 212 s> content-type: application/mercurial-exp-framing-0005\r\n
213 213 s> content-length: 80\r\n
214 214 s> host: $LOCALIP:$HGPORT\r\n (glob)
215 215 s> user-agent: Mercurial debugwireproto\r\n
216 216 s> \r\n
217 217 s> H\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81GparentsEnodes\x81T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
218 218 s> makefile('rb', None)
219 219 s> HTTP/1.1 200 OK\r\n
220 220 s> Server: testing stub value\r\n
221 221 s> Date: $HTTP_DATE$\r\n
222 222 s> Content-Type: application/mercurial-exp-framing-0005\r\n
223 223 s> Transfer-Encoding: chunked\r\n
224 224 s> \r\n
225 225 s> 13\r\n
226 226 s> \x0b\x00\x00\x01\x00\x02\x011
227 227 s> \xa1FstatusBok
228 228 s> \r\n
229 229 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
230 230 s> 63\r\n
231 231 s> [\x00\x00\x01\x00\x02\x001
232 232 s> \xa1Jtotalitems\x01\xa2DnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccGparents\x82T+N\xb0s\x19\xbf\xa0w\xa4\n
233 233 s> /\x04\x916Y\xae\xf0\xdaB\xdaT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
234 234 s> \r\n
235 235 received frame(size=91; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
236 236 s> 8\r\n
237 237 s> \x00\x00\x00\x01\x00\x02\x002
238 238 s> \r\n
239 239 s> 0\r\n
240 240 s> \r\n
241 241 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
242 242 response: gen[
243 243 {
244 244 b'totalitems': 1
245 245 },
246 246 {
247 247 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc',
248 248 b'parents': [
249 249 b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
250 250 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
251 251 ]
252 252 }
253 253 ]
254 254
255 255 Requesting revision data works
256 (haveparents defaults to False, so fulltext is emitted)
256 257
257 258 $ sendhttpv2peer << EOF
258 259 > command filedata
259 260 > nodes eval:[b'\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
260 261 > path eval:b'a'
261 262 > fields eval:[b'revision']
262 263 > EOF
263 264 creating http peer for wire protocol version 2
264 265 sending filedata command
265 266 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
266 267 s> Accept-Encoding: identity\r\n
267 268 s> accept: application/mercurial-exp-framing-0005\r\n
268 269 s> content-type: application/mercurial-exp-framing-0005\r\n
269 270 s> content-length: 81\r\n
270 271 s> host: $LOCALIP:$HGPORT\r\n (glob)
271 272 s> user-agent: Mercurial debugwireproto\r\n
272 273 s> \r\n
273 274 s> I\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x81T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
274 275 s> makefile('rb', None)
275 276 s> HTTP/1.1 200 OK\r\n
276 277 s> Server: testing stub value\r\n
277 278 s> Date: $HTTP_DATE$\r\n
278 279 s> Content-Type: application/mercurial-exp-framing-0005\r\n
279 280 s> Transfer-Encoding: chunked\r\n
280 281 s> \r\n
281 282 s> 13\r\n
282 283 s> \x0b\x00\x00\x01\x00\x02\x011
283 284 s> \xa1FstatusBok
284 285 s> \r\n
285 286 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
287 s> 42\r\n
288 s> :\x00\x00\x01\x00\x02\x001
289 s> \xa1Jtotalitems\x01\xa2DnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccLrevisionsize\x03Ca1\n
290 s> \r\n
291 received frame(size=58; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
292 s> 8\r\n
293 s> \x00\x00\x00\x01\x00\x02\x002
294 s> \r\n
295 s> 0\r\n
296 s> \r\n
297 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
298 response: gen[
299 {
300 b'totalitems': 1
301 },
302 {
303 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc',
304 b'revisionsize': 3
305 },
306 b'a1\n'
307 ]
308
309 haveparents=False should be same as above
310
311 $ sendhttpv2peer << EOF
312 > command filedata
313 > nodes eval:[b'\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
314 > path eval:b'a'
315 > fields eval:[b'revision']
316 > haveparents eval:False
317 > EOF
318 creating http peer for wire protocol version 2
319 sending filedata command
320 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
321 s> Accept-Encoding: identity\r\n
322 s> accept: application/mercurial-exp-framing-0005\r\n
323 s> content-type: application/mercurial-exp-framing-0005\r\n
324 s> content-length: 94\r\n
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
326 s> user-agent: Mercurial debugwireproto\r\n
327 s> \r\n
328 s> V\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa4Ffields\x81HrevisionKhaveparents\xf4Enodes\x81T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
329 s> makefile('rb', None)
330 s> HTTP/1.1 200 OK\r\n
331 s> Server: testing stub value\r\n
332 s> Date: $HTTP_DATE$\r\n
333 s> Content-Type: application/mercurial-exp-framing-0005\r\n
334 s> Transfer-Encoding: chunked\r\n
335 s> \r\n
336 s> 13\r\n
337 s> \x0b\x00\x00\x01\x00\x02\x011
338 s> \xa1FstatusBok
339 s> \r\n
340 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
341 s> 42\r\n
342 s> :\x00\x00\x01\x00\x02\x001
343 s> \xa1Jtotalitems\x01\xa2DnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccLrevisionsize\x03Ca1\n
344 s> \r\n
345 received frame(size=58; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
346 s> 8\r\n
347 s> \x00\x00\x00\x01\x00\x02\x002
348 s> \r\n
349 s> 0\r\n
350 s> \r\n
351 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
352 response: gen[
353 {
354 b'totalitems': 1
355 },
356 {
357 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc',
358 b'revisionsize': 3
359 },
360 b'a1\n'
361 ]
362
363 haveparents=True should emit a delta
364
365 $ sendhttpv2peer << EOF
366 > command filedata
367 > nodes eval:[b'\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
368 > path eval:b'a'
369 > fields eval:[b'revision']
370 > haveparents eval:True
371 > EOF
372 creating http peer for wire protocol version 2
373 sending filedata command
374 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
375 s> Accept-Encoding: identity\r\n
376 s> accept: application/mercurial-exp-framing-0005\r\n
377 s> content-type: application/mercurial-exp-framing-0005\r\n
378 s> content-length: 94\r\n
379 s> host: $LOCALIP:$HGPORT\r\n (glob)
380 s> user-agent: Mercurial debugwireproto\r\n
381 s> \r\n
382 s> V\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa4Ffields\x81HrevisionKhaveparents\xf5Enodes\x81T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
383 s> makefile('rb', None)
384 s> HTTP/1.1 200 OK\r\n
385 s> Server: testing stub value\r\n
386 s> Date: $HTTP_DATE$\r\n
387 s> Content-Type: application/mercurial-exp-framing-0005\r\n
388 s> Transfer-Encoding: chunked\r\n
389 s> \r\n
390 s> 13\r\n
391 s> \x0b\x00\x00\x01\x00\x02\x011
392 s> \xa1FstatusBok
393 s> \r\n
394 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
286 395 s> 6e\r\n
287 396 s> f\x00\x00\x01\x00\x02\x001
288 397 s> \xa1Jtotalitems\x01\xa3MdeltabasenodeT+N\xb0s\x19\xbf\xa0w\xa4\n
289 398 s> /\x04\x916Y\xae\xf0\xdaB\xdaIdeltasize\x0fDnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccO\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n
290 399 s> \r\n
291 400 received frame(size=102; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
292 401 s> 8\r\n
293 402 s> \x00\x00\x00\x01\x00\x02\x002
294 403 s> \r\n
295 404 s> 0\r\n
296 405 s> \r\n
297 406 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
298 407 response: gen[
299 408 {
300 409 b'totalitems': 1
301 410 },
302 411 {
303 412 b'deltabasenode': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
304 413 b'deltasize': 15,
305 414 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc'
306 415 },
307 416 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n'
308 417 ]
309 418
310 419 Requesting multiple revisions works
311 (first revision should be fulltext, subsequents are deltas)
420 (first revision is a fulltext since haveparents=False by default)
312 421
313 422 $ sendhttpv2peer << EOF
314 423 > command filedata
315 424 > nodes eval:['\x2b\x4e\xb0\x73\x19\xbf\xa0\x77\xa4\x0a\x2f\x04\x91\x36\x59\xae\xf0\xda\x42\xda', '\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc']
316 425 > path eval:b'a'
317 426 > fields eval:[b'revision']
318 427 > EOF
319 428 creating http peer for wire protocol version 2
320 429 sending filedata command
321 430 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
322 431 s> Accept-Encoding: identity\r\n
323 432 s> accept: application/mercurial-exp-framing-0005\r\n
324 433 s> content-type: application/mercurial-exp-framing-0005\r\n
325 434 s> content-length: 102\r\n
326 435 s> host: $LOCALIP:$HGPORT\r\n (glob)
327 436 s> user-agent: Mercurial debugwireproto\r\n
328 437 s> \r\n
329 438 s> ^\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x82T+N\xb0s\x19\xbf\xa0w\xa4\n
330 439 s> /\x04\x916Y\xae\xf0\xdaB\xdaT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccDpathAaDnameHfiledata
331 440 s> makefile('rb', None)
332 441 s> HTTP/1.1 200 OK\r\n
333 442 s> Server: testing stub value\r\n
334 443 s> Date: $HTTP_DATE$\r\n
335 444 s> Content-Type: application/mercurial-exp-framing-0005\r\n
336 445 s> Transfer-Encoding: chunked\r\n
337 446 s> \r\n
338 447 s> 13\r\n
339 448 s> \x0b\x00\x00\x01\x00\x02\x011
340 449 s> \xa1FstatusBok
341 450 s> \r\n
342 451 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
343 452 s> 9b\r\n
344 453 s> \x93\x00\x00\x01\x00\x02\x001
345 454 s> \xa1Jtotalitems\x02\xa2DnodeT+N\xb0s\x19\xbf\xa0w\xa4\n
346 455 s> /\x04\x916Y\xae\xf0\xdaB\xdaLrevisionsize\x03Ca0\n
347 456 s> \xa3MdeltabasenodeT+N\xb0s\x19\xbf\xa0w\xa4\n
348 457 s> /\x04\x916Y\xae\xf0\xdaB\xdaIdeltasize\x0fDnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccO\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n
349 458 s> \r\n
350 459 received frame(size=147; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
351 460 s> 8\r\n
352 461 s> \x00\x00\x00\x01\x00\x02\x002
353 462 s> \r\n
354 463 s> 0\r\n
355 464 s> \r\n
356 465 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 466 response: gen[
358 467 {
359 468 b'totalitems': 2
360 469 },
361 470 {
362 471 b'node': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
363 472 b'revisionsize': 3
364 473 },
365 474 b'a0\n',
366 475 {
367 476 b'deltabasenode': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
368 477 b'deltasize': 15,
369 478 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc'
370 479 },
371 480 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n'
372 481 ]
373 482
374 483 Revisions are sorted by DAG order, parents first
375 484
376 485 $ sendhttpv2peer << EOF
377 486 > command filedata
378 487 > nodes eval:['\x9a\x38\x12\x29\x97\xb3\xac\x97\xbe\x2a\x9a\xa2\xe5\x56\x83\x83\x41\xfd\xf2\xcc', '\x2b\x4e\xb0\x73\x19\xbf\xa0\x77\xa4\x0a\x2f\x04\x91\x36\x59\xae\xf0\xda\x42\xda']
379 488 > path eval:b'a'
380 489 > fields eval:[b'revision']
381 490 > EOF
382 491 creating http peer for wire protocol version 2
383 492 sending filedata command
384 493 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
385 494 s> Accept-Encoding: identity\r\n
386 495 s> accept: application/mercurial-exp-framing-0005\r\n
387 496 s> content-type: application/mercurial-exp-framing-0005\r\n
388 497 s> content-length: 102\r\n
389 498 s> host: $LOCALIP:$HGPORT\r\n (glob)
390 499 s> user-agent: Mercurial debugwireproto\r\n
391 500 s> \r\n
392 501 s> ^\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x82T\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccT+N\xb0s\x19\xbf\xa0w\xa4\n
393 502 s> /\x04\x916Y\xae\xf0\xdaB\xdaDpathAaDnameHfiledata
394 503 s> makefile('rb', None)
395 504 s> HTTP/1.1 200 OK\r\n
396 505 s> Server: testing stub value\r\n
397 506 s> Date: $HTTP_DATE$\r\n
398 507 s> Content-Type: application/mercurial-exp-framing-0005\r\n
399 508 s> Transfer-Encoding: chunked\r\n
400 509 s> \r\n
401 510 s> 13\r\n
402 511 s> \x0b\x00\x00\x01\x00\x02\x011
403 512 s> \xa1FstatusBok
404 513 s> \r\n
405 514 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
406 515 s> 9b\r\n
407 516 s> \x93\x00\x00\x01\x00\x02\x001
408 517 s> \xa1Jtotalitems\x02\xa2DnodeT+N\xb0s\x19\xbf\xa0w\xa4\n
409 518 s> /\x04\x916Y\xae\xf0\xdaB\xdaLrevisionsize\x03Ca0\n
410 519 s> \xa3MdeltabasenodeT+N\xb0s\x19\xbf\xa0w\xa4\n
411 520 s> /\x04\x916Y\xae\xf0\xdaB\xdaIdeltasize\x0fDnodeT\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xccO\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n
412 521 s> \r\n
413 522 received frame(size=147; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
414 523 s> 8\r\n
415 524 s> \x00\x00\x00\x01\x00\x02\x002
416 525 s> \r\n
417 526 s> 0\r\n
418 527 s> \r\n
419 528 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
420 529 response: gen[
421 530 {
422 531 b'totalitems': 2
423 532 },
424 533 {
425 534 b'node': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
426 535 b'revisionsize': 3
427 536 },
428 537 b'a0\n',
429 538 {
430 539 b'deltabasenode': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
431 540 b'deltasize': 15,
432 541 b'node': b'\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc'
433 542 },
434 543 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a1\n'
435 544 ]
436 545
437 546 Requesting parents and revision data works
438 547
439 548 $ sendhttpv2peer << EOF
440 549 > command filedata
441 550 > nodes eval:['\x08\x79\x34\x5e\x39\x37\x72\x29\x63\x4b\x42\x0c\x63\x94\x54\x15\x67\x26\xc6\xb6']
442 551 > path eval:b'a'
443 552 > fields eval:[b'parents', b'revision']
444 553 > EOF
445 554 creating http peer for wire protocol version 2
446 555 sending filedata command
447 556 s> POST /api/exp-http-v2-0001/ro/filedata HTTP/1.1\r\n
448 557 s> Accept-Encoding: identity\r\n
449 558 s> accept: application/mercurial-exp-framing-0005\r\n
450 559 s> content-type: application/mercurial-exp-framing-0005\r\n
451 560 s> content-length: 89\r\n
452 561 s> host: $LOCALIP:$HGPORT\r\n (glob)
453 562 s> user-agent: Mercurial debugwireproto\r\n
454 563 s> \r\n
455 564 s> Q\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x81T\x08y4^97r)cKB\x0cc\x94T\x15g&\xc6\xb6DpathAaDnameHfiledata
456 565 s> makefile('rb', None)
457 566 s> HTTP/1.1 200 OK\r\n
458 567 s> Server: testing stub value\r\n
459 568 s> Date: $HTTP_DATE$\r\n
460 569 s> Content-Type: application/mercurial-exp-framing-0005\r\n
461 570 s> Transfer-Encoding: chunked\r\n
462 571 s> \r\n
463 572 s> 13\r\n
464 573 s> \x0b\x00\x00\x01\x00\x02\x011
465 574 s> \xa1FstatusBok
466 575 s> \r\n
467 576 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
468 s> a1\r\n
469 s> \x99\x00\x00\x01\x00\x02\x001
470 s> \xa1Jtotalitems\x01\xa4MdeltabasenodeT+N\xb0s\x19\xbf\xa0w\xa4\n
471 s> /\x04\x916Y\xae\xf0\xdaB\xdaIdeltasize\x0fDnodeT\x08y4^97r)cKB\x0cc\x94T\x15g&\xc6\xb6Gparents\x82T+N\xb0s\x19\xbf\xa0w\xa4\n
472 s> /\x04\x916Y\xae\xf0\xdaB\xdaT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00O\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a2\n
577 s> 75\r\n
578 s> m\x00\x00\x01\x00\x02\x001
579 s> \xa1Jtotalitems\x01\xa3DnodeT\x08y4^97r)cKB\x0cc\x94T\x15g&\xc6\xb6Gparents\x82T+N\xb0s\x19\xbf\xa0w\xa4\n
580 s> /\x04\x916Y\xae\xf0\xdaB\xdaT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Lrevisionsize\x03Ca2\n
473 581 s> \r\n
474 received frame(size=153; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
582 received frame(size=109; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
475 583 s> 8\r\n
476 584 s> \x00\x00\x00\x01\x00\x02\x002
477 585 s> \r\n
478 586 s> 0\r\n
479 587 s> \r\n
480 588 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
481 589 response: gen[
482 590 {
483 591 b'totalitems': 1
484 592 },
485 593 {
486 b'deltabasenode': b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
487 b'deltasize': 15,
488 594 b'node': b'\x08y4^97r)cKB\x0cc\x94T\x15g&\xc6\xb6',
489 595 b'parents': [
490 596 b'+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
491 597 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
492 ]
598 ],
599 b'revisionsize': 3
493 600 },
494 b'\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x03a2\n'
601 b'a2\n'
495 602 ]
496 603
497 604 $ cat error.log
@@ -1,507 +1,694
1 1 $ . $TESTDIR/wireprotohelpers.sh
2 2
3 3 $ hg init server
4 4 $ enablehttpv2 server
5 5 $ cd server
6 6 $ echo a0 > a
7 7 $ echo b0 > b
8 8 $ mkdir -p dir0/child0 dir0/child1 dir1
9 9 $ echo c0 > dir0/c
10 10 $ echo d0 > dir0/d
11 11 $ echo e0 > dir0/child0/e
12 12 $ echo f0 > dir0/child1/f
13 13 $ hg -q commit -A -m 'commit 0'
14 14
15 15 $ echo a1 > a
16 16 $ echo d1 > dir0/d
17 17 $ hg commit -m 'commit 1'
18 18 $ echo f0 > dir0/child1/f
19 19 $ hg commit -m 'commit 2'
20 20 nothing changed
21 21 [1]
22 22
23 23 $ hg -q up -r 0
24 24 $ echo a2 > a
25 25 $ hg commit -m 'commit 3'
26 26 created new head
27 27
28 28 $ hg log -G -T '{rev}:{node} {desc}\n'
29 29 @ 2:c8757a2ffe552850d1e0dfe60d295ebf64c196d9 commit 3
30 30 |
31 31 | o 1:650165e803375748a94df471e5b58d85763e0b29 commit 1
32 32 |/
33 33 o 0:6d85ca1270b377d320098556ba5bfad34a9ee12d commit 0
34 34
35 35
36 36 $ hg --debug debugindex -m
37 37 rev linkrev nodeid p1 p2
38 38 0 0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000
39 39 1 1 91e0bdbfb0dde0023fa063edc1445f207a22eac7 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000
40 40 2 2 46a6721b5edaf0ea04b79a5cb3218854a4d2aba0 1b175b595f022cfab5b809cc0ed551bd0b3ff5e4 0000000000000000000000000000000000000000
41 41
42 42 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
43 43 $ cat hg.pid > $DAEMON_PIDS
44 44
45 45 Missing arguments is an error
46 46
47 47 $ sendhttpv2peer << EOF
48 48 > command manifestdata
49 49 > EOF
50 50 creating http peer for wire protocol version 2
51 51 sending manifestdata command
52 52 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
53 53 s> Accept-Encoding: identity\r\n
54 54 s> accept: application/mercurial-exp-framing-0005\r\n
55 55 s> content-type: application/mercurial-exp-framing-0005\r\n
56 56 s> content-length: 27\r\n
57 57 s> host: $LOCALIP:$HGPORT\r\n (glob)
58 58 s> user-agent: Mercurial debugwireproto\r\n
59 59 s> \r\n
60 60 s> \x13\x00\x00\x01\x00\x01\x01\x11\xa1DnameLmanifestdata
61 61 s> makefile('rb', None)
62 62 s> HTTP/1.1 200 OK\r\n
63 63 s> Server: testing stub value\r\n
64 64 s> Date: $HTTP_DATE$\r\n
65 65 s> Content-Type: application/mercurial-exp-framing-0005\r\n
66 66 s> Transfer-Encoding: chunked\r\n
67 67 s> \r\n
68 68 s> 45\r\n
69 69 s> =\x00\x00\x01\x00\x02\x012
70 70 s> \xa2Eerror\xa1GmessageX\x1enodes argument must be definedFstatusEerror
71 71 s> \r\n
72 72 received frame(size=61; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
73 73 s> 0\r\n
74 74 s> \r\n
75 75 abort: nodes argument must be defined!
76 76 [255]
77 77
78 78 $ sendhttpv2peer << EOF
79 79 > command manifestdata
80 80 > nodes eval:[]
81 81 > EOF
82 82 creating http peer for wire protocol version 2
83 83 sending manifestdata command
84 84 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
85 85 s> Accept-Encoding: identity\r\n
86 86 s> accept: application/mercurial-exp-framing-0005\r\n
87 87 s> content-type: application/mercurial-exp-framing-0005\r\n
88 88 s> content-length: 40\r\n
89 89 s> host: $LOCALIP:$HGPORT\r\n (glob)
90 90 s> user-agent: Mercurial debugwireproto\r\n
91 91 s> \r\n
92 92 s> \x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa1Enodes\x80DnameLmanifestdata
93 93 s> makefile('rb', None)
94 94 s> HTTP/1.1 200 OK\r\n
95 95 s> Server: testing stub value\r\n
96 96 s> Date: $HTTP_DATE$\r\n
97 97 s> Content-Type: application/mercurial-exp-framing-0005\r\n
98 98 s> Transfer-Encoding: chunked\r\n
99 99 s> \r\n
100 100 s> 44\r\n
101 101 s> <\x00\x00\x01\x00\x02\x012
102 102 s> \xa2Eerror\xa1GmessageX\x1dtree argument must be definedFstatusEerror
103 103 s> \r\n
104 104 received frame(size=60; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
105 105 s> 0\r\n
106 106 s> \r\n
107 107 abort: tree argument must be defined!
108 108 [255]
109 109
110 110 Unknown node is an error
111 111
112 112 $ sendhttpv2peer << EOF
113 113 > command manifestdata
114 114 > nodes eval:[b'\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa']
115 115 > tree eval:b''
116 116 > EOF
117 117 creating http peer for wire protocol version 2
118 118 sending manifestdata command
119 119 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
120 120 s> Accept-Encoding: identity\r\n
121 121 s> accept: application/mercurial-exp-framing-0005\r\n
122 122 s> content-type: application/mercurial-exp-framing-0005\r\n
123 123 s> content-length: 67\r\n
124 124 s> host: $LOCALIP:$HGPORT\r\n (glob)
125 125 s> user-agent: Mercurial debugwireproto\r\n
126 126 s> \r\n
127 127 s> ;\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Enodes\x81T\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaaDtree@DnameLmanifestdata
128 128 s> makefile('rb', None)
129 129 s> HTTP/1.1 200 OK\r\n
130 130 s> Server: testing stub value\r\n
131 131 s> Date: $HTTP_DATE$\r\n
132 132 s> Content-Type: application/mercurial-exp-framing-0005\r\n
133 133 s> Transfer-Encoding: chunked\r\n
134 134 s> \r\n
135 135 s> 51\r\n
136 136 s> I\x00\x00\x01\x00\x02\x012
137 137 s> \xa2Eerror\xa2Dargs\x81T\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaaGmessagePunknown node: %sFstatusEerror
138 138 s> \r\n
139 139 received frame(size=73; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=eos)
140 140 s> 0\r\n
141 141 s> \r\n
142 142 abort: unknown node: \xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa! (esc)
143 143 [255]
144 144
145 145 Fetching a single revision returns just metadata by default
146 146
147 147 $ sendhttpv2peer << EOF
148 148 > command manifestdata
149 149 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
150 150 > tree eval:b''
151 151 > EOF
152 152 creating http peer for wire protocol version 2
153 153 sending manifestdata command
154 154 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
155 155 s> Accept-Encoding: identity\r\n
156 156 s> accept: application/mercurial-exp-framing-0005\r\n
157 157 s> content-type: application/mercurial-exp-framing-0005\r\n
158 158 s> content-length: 67\r\n
159 159 s> host: $LOCALIP:$HGPORT\r\n (glob)
160 160 s> user-agent: Mercurial debugwireproto\r\n
161 161 s> \r\n
162 162 s> ;\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa2Enodes\x81TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
163 163 s> makefile('rb', None)
164 164 s> HTTP/1.1 200 OK\r\n
165 165 s> Server: testing stub value\r\n
166 166 s> Date: $HTTP_DATE$\r\n
167 167 s> Content-Type: application/mercurial-exp-framing-0005\r\n
168 168 s> Transfer-Encoding: chunked\r\n
169 169 s> \r\n
170 170 s> 13\r\n
171 171 s> \x0b\x00\x00\x01\x00\x02\x011
172 172 s> \xa1FstatusBok
173 173 s> \r\n
174 174 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
175 175 s> 30\r\n
176 176 s> (\x00\x00\x01\x00\x02\x001
177 177 s> \xa1Jtotalitems\x01\xa1DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0
178 178 s> \r\n
179 179 received frame(size=40; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
180 180 s> 8\r\n
181 181 s> \x00\x00\x00\x01\x00\x02\x002
182 182 s> \r\n
183 183 s> 0\r\n
184 184 s> \r\n
185 185 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
186 186 response: gen[
187 187 {
188 188 b'totalitems': 1
189 189 },
190 190 {
191 191 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
192 192 }
193 193 ]
194 194
195 195 Requesting parents works
196 196
197 197 $ sendhttpv2peer << EOF
198 198 > command manifestdata
199 199 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
200 200 > tree eval:b''
201 201 > fields eval:[b'parents']
202 202 > EOF
203 203 creating http peer for wire protocol version 2
204 204 sending manifestdata command
205 205 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
206 206 s> Accept-Encoding: identity\r\n
207 207 s> accept: application/mercurial-exp-framing-0005\r\n
208 208 s> content-type: application/mercurial-exp-framing-0005\r\n
209 209 s> content-length: 83\r\n
210 210 s> host: $LOCALIP:$HGPORT\r\n (glob)
211 211 s> user-agent: Mercurial debugwireproto\r\n
212 212 s> \r\n
213 213 s> K\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81GparentsEnodes\x81TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
214 214 s> makefile('rb', None)
215 215 s> HTTP/1.1 200 OK\r\n
216 216 s> Server: testing stub value\r\n
217 217 s> Date: $HTTP_DATE$\r\n
218 218 s> Content-Type: application/mercurial-exp-framing-0005\r\n
219 219 s> Transfer-Encoding: chunked\r\n
220 220 s> \r\n
221 221 s> 13\r\n
222 222 s> \x0b\x00\x00\x01\x00\x02\x011
223 223 s> \xa1FstatusBok
224 224 s> \r\n
225 225 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
226 226 s> 63\r\n
227 227 s> [\x00\x00\x01\x00\x02\x001
228 228 s> \xa1Jtotalitems\x01\xa2DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Gparents\x82T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
229 229 s> \r\n
230 230 received frame(size=91; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
231 231 s> 8\r\n
232 232 s> \x00\x00\x00\x01\x00\x02\x002
233 233 s> \r\n
234 234 s> 0\r\n
235 235 s> \r\n
236 236 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
237 237 response: gen[
238 238 {
239 239 b'totalitems': 1
240 240 },
241 241 {
242 242 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
243 243 b'parents': [
244 244 b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
245 245 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
246 246 ]
247 247 }
248 248 ]
249 249
250 250 Requesting revision data works
251 (haveparents defaults to false, so fulltext is emitted)
251 252
252 253 $ sendhttpv2peer << EOF
253 254 > command manifestdata
254 255 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
255 256 > tree eval:b''
256 257 > fields eval:[b'revision']
257 258 > EOF
258 259 creating http peer for wire protocol version 2
259 260 sending manifestdata command
260 261 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
261 262 s> Accept-Encoding: identity\r\n
262 263 s> accept: application/mercurial-exp-framing-0005\r\n
263 264 s> content-type: application/mercurial-exp-framing-0005\r\n
264 265 s> content-length: 84\r\n
265 266 s> host: $LOCALIP:$HGPORT\r\n (glob)
266 267 s> user-agent: Mercurial debugwireproto\r\n
267 268 s> \r\n
268 269 s> L\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x81TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
269 270 s> makefile('rb', None)
270 271 s> HTTP/1.1 200 OK\r\n
271 272 s> Server: testing stub value\r\n
272 273 s> Date: $HTTP_DATE$\r\n
273 274 s> Content-Type: application/mercurial-exp-framing-0005\r\n
274 275 s> Transfer-Encoding: chunked\r\n
275 276 s> \r\n
276 277 s> 13\r\n
277 278 s> \x0b\x00\x00\x01\x00\x02\x011
278 279 s> \xa1FstatusBok
279 280 s> \r\n
280 281 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
282 s> 167\r\n
283 s> _\x01\x00\x01\x00\x02\x001
284 s> \xa1Jtotalitems\x01\xa2DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Lrevisionsize\x19\x01$Y\x01$a\x000879345e39377229634b420c639454156726c6b6\n
285 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
286 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
287 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
288 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
289 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
290 s> \r\n
291 received frame(size=351; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
292 s> 8\r\n
293 s> \x00\x00\x00\x01\x00\x02\x002
294 s> \r\n
295 s> 0\r\n
296 s> \r\n
297 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
298 response: gen[
299 {
300 b'totalitems': 1
301 },
302 {
303 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
304 b'revisionsize': 292
305 },
306 b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n'
307 ]
308
309 haveparents=False yields same output
310
311 $ sendhttpv2peer << EOF
312 > command manifestdata
313 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
314 > tree eval:b''
315 > fields eval:[b'revision']
316 > haveparents eval:False
317 > EOF
318 creating http peer for wire protocol version 2
319 sending manifestdata command
320 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
321 s> Accept-Encoding: identity\r\n
322 s> accept: application/mercurial-exp-framing-0005\r\n
323 s> content-type: application/mercurial-exp-framing-0005\r\n
324 s> content-length: 97\r\n
325 s> host: $LOCALIP:$HGPORT\r\n (glob)
326 s> user-agent: Mercurial debugwireproto\r\n
327 s> \r\n
328 s> Y\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa4Ffields\x81HrevisionKhaveparents\xf4Enodes\x81TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
329 s> makefile('rb', None)
330 s> HTTP/1.1 200 OK\r\n
331 s> Server: testing stub value\r\n
332 s> Date: $HTTP_DATE$\r\n
333 s> Content-Type: application/mercurial-exp-framing-0005\r\n
334 s> Transfer-Encoding: chunked\r\n
335 s> \r\n
336 s> 13\r\n
337 s> \x0b\x00\x00\x01\x00\x02\x011
338 s> \xa1FstatusBok
339 s> \r\n
340 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
341 s> 167\r\n
342 s> _\x01\x00\x01\x00\x02\x001
343 s> \xa1Jtotalitems\x01\xa2DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Lrevisionsize\x19\x01$Y\x01$a\x000879345e39377229634b420c639454156726c6b6\n
344 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
345 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
346 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
347 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
348 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
349 s> \r\n
350 received frame(size=351; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
351 s> 8\r\n
352 s> \x00\x00\x00\x01\x00\x02\x002
353 s> \r\n
354 s> 0\r\n
355 s> \r\n
356 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 response: gen[
358 {
359 b'totalitems': 1
360 },
361 {
362 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
363 b'revisionsize': 292
364 },
365 b'a\x000879345e39377229634b420c639454156726c6b6\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n'
366 ]
367
368 haveparents=True will emit delta
369
370 $ sendhttpv2peer << EOF
371 > command manifestdata
372 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
373 > tree eval:b''
374 > fields eval:[b'revision']
375 > haveparents eval:True
376 > EOF
377 creating http peer for wire protocol version 2
378 sending manifestdata command
379 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
380 s> Accept-Encoding: identity\r\n
381 s> accept: application/mercurial-exp-framing-0005\r\n
382 s> content-type: application/mercurial-exp-framing-0005\r\n
383 s> content-length: 97\r\n
384 s> host: $LOCALIP:$HGPORT\r\n (glob)
385 s> user-agent: Mercurial debugwireproto\r\n
386 s> \r\n
387 s> Y\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa4Ffields\x81HrevisionKhaveparents\xf5Enodes\x81TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
388 s> makefile('rb', None)
389 s> HTTP/1.1 200 OK\r\n
390 s> Server: testing stub value\r\n
391 s> Date: $HTTP_DATE$\r\n
392 s> Content-Type: application/mercurial-exp-framing-0005\r\n
393 s> Transfer-Encoding: chunked\r\n
394 s> \r\n
395 s> 13\r\n
396 s> \x0b\x00\x00\x01\x00\x02\x011
397 s> \xa1FstatusBok
398 s> \r\n
399 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
281 400 s> 98\r\n
282 401 s> \x90\x00\x00\x01\x00\x02\x001
283 402 s> \xa1Jtotalitems\x01\xa3MdeltabasenodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Ideltasize\x187DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0X7\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n
284 403 s> \r\n
285 404 received frame(size=144; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
286 405 s> 8\r\n
287 406 s> \x00\x00\x00\x01\x00\x02\x002
288 407 s> \r\n
289 408 s> 0\r\n
290 409 s> \r\n
291 410 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
292 411 response: gen[
293 412 {
294 413 b'totalitems': 1
295 414 },
296 415 {
297 416 b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
298 417 b'deltasize': 55,
299 418 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
300 419 },
301 420 b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
302 421 ]
303 422
304 423 Requesting multiple revisions works
424 (haveparents defaults to false, so fulltext is emitted unless a parent
425 has been emitted)
305 426
306 427 $ sendhttpv2peer << EOF
307 428 > command manifestdata
308 429 > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
309 430 > tree eval:b''
310 431 > fields eval:[b'revision']
311 432 > EOF
312 433 creating http peer for wire protocol version 2
313 434 sending manifestdata command
314 435 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
315 436 s> Accept-Encoding: identity\r\n
316 437 s> accept: application/mercurial-exp-framing-0005\r\n
317 438 s> content-type: application/mercurial-exp-framing-0005\r\n
318 439 s> content-length: 105\r\n
319 440 s> host: $LOCALIP:$HGPORT\r\n (glob)
320 441 s> user-agent: Mercurial debugwireproto\r\n
321 442 s> \r\n
322 443 s> a\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x82T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
323 444 s> makefile('rb', None)
324 445 s> HTTP/1.1 200 OK\r\n
325 446 s> Server: testing stub value\r\n
326 447 s> Date: $HTTP_DATE$\r\n
327 448 s> Content-Type: application/mercurial-exp-framing-0005\r\n
328 449 s> Transfer-Encoding: chunked\r\n
329 450 s> \r\n
330 451 s> 13\r\n
331 452 s> \x0b\x00\x00\x01\x00\x02\x011
332 453 s> \xa1FstatusBok
333 454 s> \r\n
334 455 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
335 456 s> 1ea\r\n
336 457 s> \xe2\x01\x00\x01\x00\x02\x001
337 458 s> \xa1Jtotalitems\x02\xa2DnodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Lrevisionsize\x19\x01$Y\x01$a\x002b4eb07319bfa077a40a2f04913659aef0da42da\n
338 459 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
339 460 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
340 461 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
341 462 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
342 463 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
343 464 s> \xa3MdeltabasenodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Ideltasize\x187DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0X7\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n
344 465 s> \r\n
345 466 received frame(size=482; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
346 467 s> 8\r\n
347 468 s> \x00\x00\x00\x01\x00\x02\x002
348 469 s> \r\n
349 470 s> 0\r\n
350 471 s> \r\n
351 472 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
352 473 response: gen[
353 474 {
354 475 b'totalitems': 2
355 476 },
356 477 {
357 478 b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
358 479 b'revisionsize': 292
359 480 },
360 481 b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
361 482 {
362 483 b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
363 484 b'deltasize': 55,
364 485 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
365 486 },
366 487 b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
367 488 ]
368 489
490 With haveparents=True, first revision is a delta instead of fulltext
491
492 $ sendhttpv2peer << EOF
493 > command manifestdata
494 > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
495 > tree eval:b''
496 > fields eval:[b'revision']
497 > haveparents eval:True
498 > EOF
499 creating http peer for wire protocol version 2
500 sending manifestdata command
501 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
502 s> Accept-Encoding: identity\r\n
503 s> accept: application/mercurial-exp-framing-0005\r\n
504 s> content-type: application/mercurial-exp-framing-0005\r\n
505 s> content-length: 118\r\n
506 s> host: $LOCALIP:$HGPORT\r\n (glob)
507 s> user-agent: Mercurial debugwireproto\r\n
508 s> \r\n
509 s> n\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa4Ffields\x81HrevisionKhaveparents\xf5Enodes\x82T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
510 s> makefile('rb', None)
511 s> HTTP/1.1 200 OK\r\n
512 s> Server: testing stub value\r\n
513 s> Date: $HTTP_DATE$\r\n
514 s> Content-Type: application/mercurial-exp-framing-0005\r\n
515 s> Transfer-Encoding: chunked\r\n
516 s> \r\n
517 s> 13\r\n
518 s> \x0b\x00\x00\x01\x00\x02\x011
519 s> \xa1FstatusBok
520 s> \r\n
521 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
522 s> 1ea\r\n
523 s> \xe2\x01\x00\x01\x00\x02\x001
524 s> \xa1Jtotalitems\x02\xa2DnodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Lrevisionsize\x19\x01$Y\x01$a\x002b4eb07319bfa077a40a2f04913659aef0da42da\n
525 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
526 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
527 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
528 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
529 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
530 s> \xa3MdeltabasenodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Ideltasize\x187DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0X7\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n
531 s> \r\n
532 received frame(size=482; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
533 s> 8\r\n
534 s> \x00\x00\x00\x01\x00\x02\x002
535 s> \r\n
536 s> 0\r\n
537 s> \r\n
538 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
539 response: gen[
540 {
541 b'totalitems': 2
542 },
543 {
544 b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
545 b'revisionsize': 292
546 },
547 b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
548 {
549 b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
550 b'deltasize': 55,
551 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
552 },
553 b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
554 ]
555
369 556 Revisions are sorted by DAG order, parents first
370 557
371 558 $ sendhttpv2peer << EOF
372 559 > command manifestdata
373 560 > nodes eval:[b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0', b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4']
374 561 > tree eval:b''
375 562 > fields eval:[b'revision']
376 563 > EOF
377 564 creating http peer for wire protocol version 2
378 565 sending manifestdata command
379 566 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
380 567 s> Accept-Encoding: identity\r\n
381 568 s> accept: application/mercurial-exp-framing-0005\r\n
382 569 s> content-type: application/mercurial-exp-framing-0005\r\n
383 570 s> content-length: 105\r\n
384 571 s> host: $LOCALIP:$HGPORT\r\n (glob)
385 572 s> user-agent: Mercurial debugwireproto\r\n
386 573 s> \r\n
387 574 s> a\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x81HrevisionEnodes\x82TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Dtree@DnameLmanifestdata
388 575 s> makefile('rb', None)
389 576 s> HTTP/1.1 200 OK\r\n
390 577 s> Server: testing stub value\r\n
391 578 s> Date: $HTTP_DATE$\r\n
392 579 s> Content-Type: application/mercurial-exp-framing-0005\r\n
393 580 s> Transfer-Encoding: chunked\r\n
394 581 s> \r\n
395 582 s> 13\r\n
396 583 s> \x0b\x00\x00\x01\x00\x02\x011
397 584 s> \xa1FstatusBok
398 585 s> \r\n
399 586 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
400 587 s> 1ea\r\n
401 588 s> \xe2\x01\x00\x01\x00\x02\x001
402 589 s> \xa1Jtotalitems\x02\xa2DnodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Lrevisionsize\x19\x01$Y\x01$a\x002b4eb07319bfa077a40a2f04913659aef0da42da\n
403 590 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
404 591 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
405 592 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
406 593 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
407 594 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
408 595 s> \xa3MdeltabasenodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Ideltasize\x187DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0X7\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n
409 596 s> \r\n
410 597 received frame(size=482; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
411 598 s> 8\r\n
412 599 s> \x00\x00\x00\x01\x00\x02\x002
413 600 s> \r\n
414 601 s> 0\r\n
415 602 s> \r\n
416 603 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
417 604 response: gen[
418 605 {
419 606 b'totalitems': 2
420 607 },
421 608 {
422 609 b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
423 610 b'revisionsize': 292
424 611 },
425 612 b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
426 613 {
427 614 b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
428 615 b'deltasize': 55,
429 616 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0'
430 617 },
431 618 b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
432 619 ]
433 620
434 621 Requesting parents and revision data works
435 622
436 623 $ sendhttpv2peer << EOF
437 624 > command manifestdata
438 625 > nodes eval:[b'\x1b\x17\x5b\x59\x5f\x02\x2c\xfa\xb5\xb8\x09\xcc\x0e\xd5\x51\xbd\x0b\x3f\xf5\xe4', b'\x46\xa6\x72\x1b\x5e\xda\xf0\xea\x04\xb7\x9a\x5c\xb3\x21\x88\x54\xa4\xd2\xab\xa0']
439 626 > tree eval:b''
440 627 > fields eval:[b'parents', b'revision']
441 628 > EOF
442 629 creating http peer for wire protocol version 2
443 630 sending manifestdata command
444 631 s> POST /api/exp-http-v2-0001/ro/manifestdata HTTP/1.1\r\n
445 632 s> Accept-Encoding: identity\r\n
446 633 s> accept: application/mercurial-exp-framing-0005\r\n
447 634 s> content-type: application/mercurial-exp-framing-0005\r\n
448 635 s> content-length: 113\r\n
449 636 s> host: $LOCALIP:$HGPORT\r\n (glob)
450 637 s> user-agent: Mercurial debugwireproto\r\n
451 638 s> \r\n
452 639 s> i\x00\x00\x01\x00\x01\x01\x11\xa2Dargs\xa3Ffields\x82GparentsHrevisionEnodes\x82T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4TF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Dtree@DnameLmanifestdata
453 640 s> makefile('rb', None)
454 641 s> HTTP/1.1 200 OK\r\n
455 642 s> Server: testing stub value\r\n
456 643 s> Date: $HTTP_DATE$\r\n
457 644 s> Content-Type: application/mercurial-exp-framing-0005\r\n
458 645 s> Transfer-Encoding: chunked\r\n
459 646 s> \r\n
460 647 s> 13\r\n
461 648 s> \x0b\x00\x00\x01\x00\x02\x011
462 649 s> \xa1FstatusBok
463 650 s> \r\n
464 651 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
465 652 s> 250\r\n
466 653 s> H\x02\x00\x01\x00\x02\x001
467 654 s> \xa1Jtotalitems\x02\xa3DnodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Gparents\x82T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00Lrevisionsize\x19\x01$Y\x01$a\x002b4eb07319bfa077a40a2f04913659aef0da42da\n
468 655 s> b\x00819e258d31a5e1606629f365bb902a1b21ee4216\n
469 656 s> dir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\n
470 657 s> dir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\n
471 658 s> dir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\n
472 659 s> dir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n
473 660 s> \xa4MdeltabasenodeT\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4Ideltasize\x187DnodeTF\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0Gparents\x82T\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4T\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00X7\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n
474 661 s> \r\n
475 662 received frame(size=584; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
476 663 s> 8\r\n
477 664 s> \x00\x00\x00\x01\x00\x02\x002
478 665 s> \r\n
479 666 s> 0\r\n
480 667 s> \r\n
481 668 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
482 669 response: gen[
483 670 {
484 671 b'totalitems': 2
485 672 },
486 673 {
487 674 b'node': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
488 675 b'parents': [
489 676 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00',
490 677 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
491 678 ],
492 679 b'revisionsize': 292
493 680 },
494 681 b'a\x002b4eb07319bfa077a40a2f04913659aef0da42da\nb\x00819e258d31a5e1606629f365bb902a1b21ee4216\ndir0/c\x00914445346a0ca0629bd47ceb5dfe07e4d4cf2501\ndir0/child0/e\x00bbba6c06b30f443d34ff841bc985c4d0827c6be4\ndir0/child1/f\x0012fc7dcd773b5a0a929ce195228083c6ddc9cec4\ndir0/d\x00538206dc971e521540d6843abfe6d16032f6d426\n',
495 682 {
496 683 b'deltabasenode': b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
497 684 b'deltasize': 55,
498 685 b'node': b'F\xa6r\x1b^\xda\xf0\xea\x04\xb7\x9a\\\xb3!\x88T\xa4\xd2\xab\xa0',
499 686 b'parents': [
500 687 b'\x1b\x17[Y_\x02,\xfa\xb5\xb8\t\xcc\x0e\xd5Q\xbd\x0b?\xf5\xe4',
501 688 b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
502 689 ]
503 690 },
504 691 b'\x00\x00\x00\x00\x00\x00\x00+\x00\x00\x00+a\x000879345e39377229634b420c639454156726c6b6\n'
505 692 ]
506 693
507 694 $ cat error.log
@@ -1,605 +1,617
1 1 Tests for wire protocol version 2 exchange.
2 2 Tests in this file should be folded into existing tests once protocol
3 3 v2 has enough features that it can be enabled via #testcase in existing
4 4 tests.
5 5
6 6 $ . $TESTDIR/wireprotohelpers.sh
7 7 $ enablehttpv2client
8 8
9 9 $ hg init server-simple
10 10 $ enablehttpv2 server-simple
11 11 $ cd server-simple
12 12 $ cat >> .hg/hgrc << EOF
13 13 > [phases]
14 14 > publish = false
15 15 > EOF
16 16 $ echo a0 > a
17 17 $ echo b0 > b
18 18 $ hg -q commit -A -m 'commit 0'
19 19
20 20 $ echo a1 > a
21 21 $ hg commit -m 'commit 1'
22 22 $ hg phase --public -r .
23 23 $ echo a2 > a
24 24 $ hg commit -m 'commit 2'
25 25
26 26 $ hg -q up -r 0
27 27 $ echo b1 > b
28 28 $ hg -q commit -m 'head 2 commit 1'
29 29 $ echo b2 > b
30 30 $ hg -q commit -m 'head 2 commit 2'
31 31
32 32 $ hg serve -p $HGPORT -d --pid-file hg.pid -E error.log
33 33 $ cat hg.pid > $DAEMON_PIDS
34 34
35 35 $ cd ..
36 36
37 37 Test basic clone
38 38
39 39 $ hg --debug clone -U http://localhost:$HGPORT client-simple
40 40 using http://localhost:$HGPORT/
41 41 sending capabilities command
42 42 query 1; heads
43 43 sending 2 commands
44 44 sending command heads: {}
45 45 sending command known: {
46 46 'nodes': []
47 47 }
48 48 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
49 49 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
50 50 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
51 51 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
52 52 received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
53 53 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
54 54 sending 1 commands
55 55 sending command changesetdata: {
56 56 'fields': set([
57 57 'bookmarks',
58 58 'parents',
59 59 'phase',
60 60 'revision'
61 61 ]),
62 62 'noderange': [
63 63 [],
64 64 [
65 65 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
66 66 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
67 67 ]
68 68 ]
69 69 }
70 70 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
71 71 received frame(size=871; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
72 72 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
73 73 add changeset 3390ef850073
74 74 add changeset 4432d83626e8
75 75 add changeset cd2534766bec
76 76 add changeset e96ae20f4188
77 77 add changeset caa2a465451d
78 78 checking for updated bookmarks
79 79 sending 1 commands
80 80 sending command manifestdata: {
81 81 'fields': set([
82 82 'parents',
83 83 'revision'
84 84 ]),
85 'haveparents': True,
85 86 'nodes': [
86 87 '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
87 88 '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
88 89 '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
89 90 '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
90 91 '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
91 92 ],
92 93 'tree': ''
93 94 }
94 95 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
95 96 received frame(size=922; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
96 97 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
97 98 sending 2 commands
98 99 sending command filedata: {
99 100 'fields': set([
100 101 'parents',
101 102 'revision'
102 103 ]),
104 'haveparents': True,
103 105 'nodes': [
104 106 '+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
105 107 '\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc',
106 108 '\xc2\xa2\x05\xc8\xb2\xad\xe2J\xf2`b\xe5<\xd5\xbc8\x01\xd6`\xda'
107 109 ],
108 110 'path': 'a'
109 111 }
110 112 sending command filedata: {
111 113 'fields': set([
112 114 'parents',
113 115 'revision'
114 116 ]),
117 'haveparents': True,
115 118 'nodes': [
116 119 '\x81\x9e%\x8d1\xa5\xe1`f)\xf3e\xbb\x90*\x1b!\xeeB\x16',
117 120 '\xb1zk\xd3g=\x9a\xb8\xce\xd5\x81\xa2\t\xf6/=\xa5\xccEx',
118 121 '\xc5\xb1\xf9\xd3n\x1c\xc18\xbf\xb6\xef\xb3\xde\xb7]\x8c\xcad\x94\xc3'
119 122 ],
120 123 'path': 'b'
121 124 }
122 125 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
123 126 received frame(size=389; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
124 127 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
125 128 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
126 129 received frame(size=389; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
127 130 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
128 131 updating the branch cache
129 132 new changesets 3390ef850073:caa2a465451d (3 drafts)
130 133
131 134 All changesets should have been transferred
132 135
133 136 $ hg -R client-simple debugindex -c
134 137 rev linkrev nodeid p1 p2
135 138 0 0 3390ef850073 000000000000 000000000000
136 139 1 1 4432d83626e8 3390ef850073 000000000000
137 140 2 2 cd2534766bec 4432d83626e8 000000000000
138 141 3 3 e96ae20f4188 3390ef850073 000000000000
139 142 4 4 caa2a465451d e96ae20f4188 000000000000
140 143
141 144 $ hg -R client-simple log -G -T '{rev} {node} {phase}\n'
142 145 o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft
143 146 |
144 147 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
145 148 |
146 149 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
147 150 | |
148 151 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
149 152 |/
150 153 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
151 154
152 155
153 156 All manifests should have been transferred
154 157
155 158 $ hg -R client-simple debugindex -m
156 159 rev linkrev nodeid p1 p2
157 160 0 0 992f4779029a 000000000000 000000000000
158 161 1 1 a988fb43583e 992f4779029a 000000000000
159 162 2 2 ec804e488c20 a988fb43583e 000000000000
160 163 3 3 045c7f3927da 992f4779029a 000000000000
161 164 4 4 379cb0c2e664 045c7f3927da 000000000000
162 165
163 166 Cloning only a specific revision works
164 167
165 168 $ hg --debug clone -U -r 4432d83626e8 http://localhost:$HGPORT client-singlehead
166 169 using http://localhost:$HGPORT/
167 170 sending capabilities command
168 171 sending 1 commands
169 172 sending command lookup: {
170 173 'key': '4432d83626e8'
171 174 }
172 175 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
173 176 received frame(size=21; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
174 177 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
175 178 query 1; heads
176 179 sending 2 commands
177 180 sending command heads: {}
178 181 sending command known: {
179 182 'nodes': []
180 183 }
181 184 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
182 185 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
183 186 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
184 187 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
185 188 received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
186 189 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
187 190 sending 1 commands
188 191 sending command changesetdata: {
189 192 'fields': set([
190 193 'bookmarks',
191 194 'parents',
192 195 'phase',
193 196 'revision'
194 197 ]),
195 198 'noderange': [
196 199 [],
197 200 [
198 201 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
199 202 ]
200 203 ]
201 204 }
202 205 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
203 206 received frame(size=353; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
204 207 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
205 208 add changeset 3390ef850073
206 209 add changeset 4432d83626e8
207 210 checking for updated bookmarks
208 211 sending 1 commands
209 212 sending command manifestdata: {
210 213 'fields': set([
211 214 'parents',
212 215 'revision'
213 216 ]),
217 'haveparents': True,
214 218 'nodes': [
215 219 '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
216 220 '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8'
217 221 ],
218 222 'tree': ''
219 223 }
220 224 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
221 225 received frame(size=376; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
222 226 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
223 227 sending 2 commands
224 228 sending command filedata: {
225 229 'fields': set([
226 230 'parents',
227 231 'revision'
228 232 ]),
233 'haveparents': True,
229 234 'nodes': [
230 235 '+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
231 236 '\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc'
232 237 ],
233 238 'path': 'a'
234 239 }
235 240 sending command filedata: {
236 241 'fields': set([
237 242 'parents',
238 243 'revision'
239 244 ]),
245 'haveparents': True,
240 246 'nodes': [
241 247 '\x81\x9e%\x8d1\xa5\xe1`f)\xf3e\xbb\x90*\x1b!\xeeB\x16'
242 248 ],
243 249 'path': 'b'
244 250 }
245 251 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
246 252 received frame(size=249; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
247 253 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
248 254 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
249 255 received frame(size=109; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
250 256 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
251 257 updating the branch cache
252 258 new changesets 3390ef850073:4432d83626e8
253 259
254 260 $ cd client-singlehead
255 261
256 262 $ hg log -G -T '{rev} {node} {phase}\n'
257 263 o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
258 264 |
259 265 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
260 266
261 267
262 268 $ hg debugindex -m
263 269 rev linkrev nodeid p1 p2
264 270 0 0 992f4779029a 000000000000 000000000000
265 271 1 1 a988fb43583e 992f4779029a 000000000000
266 272
267 273 Incremental pull works
268 274
269 275 $ hg --debug pull
270 276 pulling from http://localhost:$HGPORT/
271 277 using http://localhost:$HGPORT/
272 278 sending capabilities command
273 279 query 1; heads
274 280 sending 2 commands
275 281 sending command heads: {}
276 282 sending command known: {
277 283 'nodes': [
278 284 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
279 285 ]
280 286 }
281 287 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
282 288 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
283 289 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
284 290 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
285 291 received frame(size=2; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
286 292 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
287 293 searching for changes
288 294 all local heads known remotely
289 295 sending 1 commands
290 296 sending command changesetdata: {
291 297 'fields': set([
292 298 'bookmarks',
293 299 'parents',
294 300 'phase',
295 301 'revision'
296 302 ]),
297 303 'noderange': [
298 304 [
299 305 'D2\xd86&\xe8\xa9\x86U\xf0b\xec\x1f*C\xb0\x7f\x7f\xbb\xb0'
300 306 ],
301 307 [
302 308 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
303 309 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
304 310 ]
305 311 ]
306 312 }
307 313 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
308 314 received frame(size=571; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
309 315 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
310 316 add changeset cd2534766bec
311 317 add changeset e96ae20f4188
312 318 add changeset caa2a465451d
313 319 checking for updated bookmarks
314 320 sending 1 commands
315 321 sending command manifestdata: {
316 322 'fields': set([
317 323 'parents',
318 324 'revision'
319 325 ]),
326 'haveparents': True,
320 327 'nodes': [
321 328 '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
322 329 '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
323 330 '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
324 331 ],
325 332 'tree': ''
326 333 }
327 334 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
328 335 received frame(size=559; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
329 336 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
330 337 sending 2 commands
331 338 sending command filedata: {
332 339 'fields': set([
333 340 'parents',
334 341 'revision'
335 342 ]),
343 'haveparents': True,
336 344 'nodes': [
337 345 '+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
338 346 '\xc2\xa2\x05\xc8\xb2\xad\xe2J\xf2`b\xe5<\xd5\xbc8\x01\xd6`\xda'
339 347 ],
340 348 'path': 'a'
341 349 }
342 350 sending command filedata: {
343 351 'fields': set([
344 352 'parents',
345 353 'revision'
346 354 ]),
355 'haveparents': True,
347 356 'nodes': [
348 357 '\x81\x9e%\x8d1\xa5\xe1`f)\xf3e\xbb\x90*\x1b!\xeeB\x16',
349 358 '\xb1zk\xd3g=\x9a\xb8\xce\xd5\x81\xa2\t\xf6/=\xa5\xccEx',
350 359 '\xc5\xb1\xf9\xd3n\x1c\xc18\xbf\xb6\xef\xb3\xde\xb7]\x8c\xcad\x94\xc3'
351 360 ],
352 361 'path': 'b'
353 362 }
354 363 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
355 364 received frame(size=249; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
356 365 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
357 366 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
358 367 received frame(size=389; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
359 368 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
360 369 updating the branch cache
361 370 new changesets cd2534766bec:caa2a465451d (3 drafts)
362 371 (run 'hg update' to get a working copy)
363 372
364 373 $ hg log -G -T '{rev} {node} {phase}\n'
365 374 o 4 caa2a465451dd1facda0f5b12312c355584188a1 draft
366 375 |
367 376 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 draft
368 377 |
369 378 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
370 379 | |
371 380 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
372 381 |/
373 382 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
374 383
375 384
376 385 $ hg debugindex -m
377 386 rev linkrev nodeid p1 p2
378 387 0 0 992f4779029a 000000000000 000000000000
379 388 1 1 a988fb43583e 992f4779029a 000000000000
380 389 2 2 ec804e488c20 a988fb43583e 000000000000
381 390 3 3 045c7f3927da 992f4779029a 000000000000
382 391 4 4 379cb0c2e664 045c7f3927da 000000000000
383 392
384 393 Phase-only update works
385 394
386 395 $ hg -R ../server-simple phase --public -r caa2a465451dd
387 396 $ hg --debug pull
388 397 pulling from http://localhost:$HGPORT/
389 398 using http://localhost:$HGPORT/
390 399 sending capabilities command
391 400 query 1; heads
392 401 sending 2 commands
393 402 sending command heads: {}
394 403 sending command known: {
395 404 'nodes': [
396 405 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
397 406 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
398 407 ]
399 408 }
400 409 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
401 410 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
402 411 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
403 412 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
404 413 received frame(size=3; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
405 414 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
406 415 searching for changes
407 416 all remote heads known locally
408 417 sending 1 commands
409 418 sending command changesetdata: {
410 419 'fields': set([
411 420 'bookmarks',
412 421 'parents',
413 422 'phase',
414 423 'revision'
415 424 ]),
416 425 'noderange': [
417 426 [
418 427 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
419 428 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
420 429 ],
421 430 [
422 431 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
423 432 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
424 433 ]
425 434 ]
426 435 }
427 436 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
428 437 received frame(size=92; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
429 438 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
430 439 checking for updated bookmarks
431 440 2 local changesets published
432 441 (run 'hg update' to get a working copy)
433 442
434 443 $ hg log -G -T '{rev} {node} {phase}\n'
435 444 o 4 caa2a465451dd1facda0f5b12312c355584188a1 public
436 445 |
437 446 o 3 e96ae20f4188487b9ae4ef3941c27c81143146e5 public
438 447 |
439 448 | o 2 cd2534766bece138c7c1afdc6825302f0f62d81f draft
440 449 | |
441 450 | o 1 4432d83626e8a98655f062ec1f2a43b07f7fbbb0 public
442 451 |/
443 452 o 0 3390ef850073fbc2f0dfff2244342c8e9229013a public
444 453
445 454
446 455 $ cd ..
447 456
448 457 Bookmarks are transferred on clone
449 458
450 459 $ hg -R server-simple bookmark -r 3390ef850073fbc2f0dfff2244342c8e9229013a book-1
451 460 $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-2
452 461
453 462 $ hg --debug clone -U http://localhost:$HGPORT/ client-bookmarks
454 463 using http://localhost:$HGPORT/
455 464 sending capabilities command
456 465 query 1; heads
457 466 sending 2 commands
458 467 sending command heads: {}
459 468 sending command known: {
460 469 'nodes': []
461 470 }
462 471 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
463 472 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
464 473 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
465 474 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
466 475 received frame(size=1; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
467 476 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
468 477 sending 1 commands
469 478 sending command changesetdata: {
470 479 'fields': set([
471 480 'bookmarks',
472 481 'parents',
473 482 'phase',
474 483 'revision'
475 484 ]),
476 485 'noderange': [
477 486 [],
478 487 [
479 488 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
480 489 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
481 490 ]
482 491 ]
483 492 }
484 493 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
485 494 received frame(size=909; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
486 495 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
487 496 add changeset 3390ef850073
488 497 add changeset 4432d83626e8
489 498 add changeset cd2534766bec
490 499 add changeset e96ae20f4188
491 500 add changeset caa2a465451d
492 501 checking for updated bookmarks
493 502 adding remote bookmark book-1
494 503 adding remote bookmark book-2
495 504 sending 1 commands
496 505 sending command manifestdata: {
497 506 'fields': set([
498 507 'parents',
499 508 'revision'
500 509 ]),
510 'haveparents': True,
501 511 'nodes': [
502 512 '\x99/Gy\x02\x9a=\xf8\xd0fm\x00\xbb\x92OicN&A',
503 513 '\xa9\x88\xfbCX>\x87\x1d\x1e\xd5u\x0e\xe0t\xc6\xd8@\xbb\xbf\xc8',
504 514 '\xec\x80NH\x8c \x88\xc25\t\x9a\x10 u\x13\xbe\xcd\xc3\xdd\xa5',
505 515 '\x04\\\x7f9\'\xda\x13\xe7Z\xf8\xf0\xe4\xf0HI\xe4a\xa9x\x0f',
506 516 '7\x9c\xb0\xc2\xe6d\\y\xdd\xc5\x9a\x1dG\'\xa9\xfb\x83\n\xeb&'
507 517 ],
508 518 'tree': ''
509 519 }
510 520 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
511 521 received frame(size=922; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
512 522 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
513 523 sending 2 commands
514 524 sending command filedata: {
515 525 'fields': set([
516 526 'parents',
517 527 'revision'
518 528 ]),
529 'haveparents': True,
519 530 'nodes': [
520 531 '+N\xb0s\x19\xbf\xa0w\xa4\n/\x04\x916Y\xae\xf0\xdaB\xda',
521 532 '\x9a8\x12)\x97\xb3\xac\x97\xbe*\x9a\xa2\xe5V\x83\x83A\xfd\xf2\xcc',
522 533 '\xc2\xa2\x05\xc8\xb2\xad\xe2J\xf2`b\xe5<\xd5\xbc8\x01\xd6`\xda'
523 534 ],
524 535 'path': 'a'
525 536 }
526 537 sending command filedata: {
527 538 'fields': set([
528 539 'parents',
529 540 'revision'
530 541 ]),
542 'haveparents': True,
531 543 'nodes': [
532 544 '\x81\x9e%\x8d1\xa5\xe1`f)\xf3e\xbb\x90*\x1b!\xeeB\x16',
533 545 '\xb1zk\xd3g=\x9a\xb8\xce\xd5\x81\xa2\t\xf6/=\xa5\xccEx',
534 546 '\xc5\xb1\xf9\xd3n\x1c\xc18\xbf\xb6\xef\xb3\xde\xb7]\x8c\xcad\x94\xc3'
535 547 ],
536 548 'path': 'b'
537 549 }
538 550 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
539 551 received frame(size=389; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
540 552 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
541 553 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
542 554 received frame(size=389; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
543 555 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
544 556 updating the branch cache
545 557 new changesets 3390ef850073:caa2a465451d (1 drafts)
546 558
547 559 $ hg -R client-bookmarks bookmarks
548 560 book-1 0:3390ef850073
549 561 book-2 2:cd2534766bec
550 562
551 563 Server-side bookmark moves are reflected during `hg pull`
552 564
553 565 $ hg -R server-simple bookmark -r cd2534766bece138c7c1afdc6825302f0f62d81f book-1
554 566 moving bookmark 'book-1' forward from 3390ef850073
555 567
556 568 $ hg -R client-bookmarks --debug pull
557 569 pulling from http://localhost:$HGPORT/
558 570 using http://localhost:$HGPORT/
559 571 sending capabilities command
560 572 query 1; heads
561 573 sending 2 commands
562 574 sending command heads: {}
563 575 sending command known: {
564 576 'nodes': [
565 577 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f',
566 578 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1'
567 579 ]
568 580 }
569 581 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
570 582 received frame(size=43; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
571 583 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
572 584 received frame(size=11; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
573 585 received frame(size=3; request=3; stream=2; streamflags=; type=command-response; flags=continuation)
574 586 received frame(size=0; request=3; stream=2; streamflags=; type=command-response; flags=eos)
575 587 searching for changes
576 588 all remote heads known locally
577 589 sending 1 commands
578 590 sending command changesetdata: {
579 591 'fields': set([
580 592 'bookmarks',
581 593 'parents',
582 594 'phase',
583 595 'revision'
584 596 ]),
585 597 'noderange': [
586 598 [
587 599 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
588 600 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
589 601 ],
590 602 [
591 603 '\xca\xa2\xa4eE\x1d\xd1\xfa\xcd\xa0\xf5\xb1#\x12\xc3UXA\x88\xa1',
592 604 '\xcd%4vk\xec\xe18\xc7\xc1\xaf\xdch%0/\x0fb\xd8\x1f'
593 605 ]
594 606 ]
595 607 }
596 608 received frame(size=11; request=1; stream=2; streamflags=stream-begin; type=command-response; flags=continuation)
597 609 received frame(size=144; request=1; stream=2; streamflags=; type=command-response; flags=continuation)
598 610 received frame(size=0; request=1; stream=2; streamflags=; type=command-response; flags=eos)
599 611 checking for updated bookmarks
600 612 updating bookmark book-1
601 613 (run 'hg update' to get a working copy)
602 614
603 615 $ hg -R client-bookmarks bookmarks
604 616 book-1 2:cd2534766bec
605 617 book-2 2:cd2534766bec
General Comments 0
You need to be logged in to leave comments. Login now