##// END OF EJS Templates
bundle2: convey PushkeyFailed error over the wire...
Pierre-Yves David -
r25493:d8e7b078 default
parent child Browse files
Show More
@@ -1,1394 +1,1406 b''
1 # bundle2.py - generic container format to transmit arbitrary data.
1 # bundle2.py - generic container format to transmit arbitrary data.
2 #
2 #
3 # Copyright 2013 Facebook, Inc.
3 # Copyright 2013 Facebook, Inc.
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7 """Handling of the new bundle2 format
7 """Handling of the new bundle2 format
8
8
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
10 payloads in an application agnostic way. It consist in a sequence of "parts"
10 payloads in an application agnostic way. It consist in a sequence of "parts"
11 that will be handed to and processed by the application layer.
11 that will be handed to and processed by the application layer.
12
12
13
13
14 General format architecture
14 General format architecture
15 ===========================
15 ===========================
16
16
17 The format is architectured as follow
17 The format is architectured as follow
18
18
19 - magic string
19 - magic string
20 - stream level parameters
20 - stream level parameters
21 - payload parts (any number)
21 - payload parts (any number)
22 - end of stream marker.
22 - end of stream marker.
23
23
24 the Binary format
24 the Binary format
25 ============================
25 ============================
26
26
27 All numbers are unsigned and big-endian.
27 All numbers are unsigned and big-endian.
28
28
29 stream level parameters
29 stream level parameters
30 ------------------------
30 ------------------------
31
31
32 Binary format is as follow
32 Binary format is as follow
33
33
34 :params size: int32
34 :params size: int32
35
35
36 The total number of Bytes used by the parameters
36 The total number of Bytes used by the parameters
37
37
38 :params value: arbitrary number of Bytes
38 :params value: arbitrary number of Bytes
39
39
40 A blob of `params size` containing the serialized version of all stream level
40 A blob of `params size` containing the serialized version of all stream level
41 parameters.
41 parameters.
42
42
43 The blob contains a space separated list of parameters. Parameters with value
43 The blob contains a space separated list of parameters. Parameters with value
44 are stored in the form `<name>=<value>`. Both name and value are urlquoted.
44 are stored in the form `<name>=<value>`. Both name and value are urlquoted.
45
45
46 Empty name are obviously forbidden.
46 Empty name are obviously forbidden.
47
47
48 Name MUST start with a letter. If this first letter is lower case, the
48 Name MUST start with a letter. If this first letter is lower case, the
49 parameter is advisory and can be safely ignored. However when the first
49 parameter is advisory and can be safely ignored. However when the first
50 letter is capital, the parameter is mandatory and the bundling process MUST
50 letter is capital, the parameter is mandatory and the bundling process MUST
51 stop if he is not able to proceed it.
51 stop if he is not able to proceed it.
52
52
53 Stream parameters use a simple textual format for two main reasons:
53 Stream parameters use a simple textual format for two main reasons:
54
54
55 - Stream level parameters should remain simple and we want to discourage any
55 - Stream level parameters should remain simple and we want to discourage any
56 crazy usage.
56 crazy usage.
57 - Textual data allow easy human inspection of a bundle2 header in case of
57 - Textual data allow easy human inspection of a bundle2 header in case of
58 troubles.
58 troubles.
59
59
60 Any Applicative level options MUST go into a bundle2 part instead.
60 Any Applicative level options MUST go into a bundle2 part instead.
61
61
62 Payload part
62 Payload part
63 ------------------------
63 ------------------------
64
64
65 Binary format is as follow
65 Binary format is as follow
66
66
67 :header size: int32
67 :header size: int32
68
68
69 The total number of Bytes used by the part headers. When the header is empty
69 The total number of Bytes used by the part headers. When the header is empty
70 (size = 0) this is interpreted as the end of stream marker.
70 (size = 0) this is interpreted as the end of stream marker.
71
71
72 :header:
72 :header:
73
73
74 The header defines how to interpret the part. It contains two piece of
74 The header defines how to interpret the part. It contains two piece of
75 data: the part type, and the part parameters.
75 data: the part type, and the part parameters.
76
76
77 The part type is used to route an application level handler, that can
77 The part type is used to route an application level handler, that can
78 interpret payload.
78 interpret payload.
79
79
80 Part parameters are passed to the application level handler. They are
80 Part parameters are passed to the application level handler. They are
81 meant to convey information that will help the application level object to
81 meant to convey information that will help the application level object to
82 interpret the part payload.
82 interpret the part payload.
83
83
84 The binary format of the header is has follow
84 The binary format of the header is has follow
85
85
86 :typesize: (one byte)
86 :typesize: (one byte)
87
87
88 :parttype: alphanumerical part name (restricted to [a-zA-Z0-9_:-]*)
88 :parttype: alphanumerical part name (restricted to [a-zA-Z0-9_:-]*)
89
89
90 :partid: A 32bits integer (unique in the bundle) that can be used to refer
90 :partid: A 32bits integer (unique in the bundle) that can be used to refer
91 to this part.
91 to this part.
92
92
93 :parameters:
93 :parameters:
94
94
95 Part's parameter may have arbitrary content, the binary structure is::
95 Part's parameter may have arbitrary content, the binary structure is::
96
96
97 <mandatory-count><advisory-count><param-sizes><param-data>
97 <mandatory-count><advisory-count><param-sizes><param-data>
98
98
99 :mandatory-count: 1 byte, number of mandatory parameters
99 :mandatory-count: 1 byte, number of mandatory parameters
100
100
101 :advisory-count: 1 byte, number of advisory parameters
101 :advisory-count: 1 byte, number of advisory parameters
102
102
103 :param-sizes:
103 :param-sizes:
104
104
105 N couple of bytes, where N is the total number of parameters. Each
105 N couple of bytes, where N is the total number of parameters. Each
106 couple contains (<size-of-key>, <size-of-value) for one parameter.
106 couple contains (<size-of-key>, <size-of-value) for one parameter.
107
107
108 :param-data:
108 :param-data:
109
109
110 A blob of bytes from which each parameter key and value can be
110 A blob of bytes from which each parameter key and value can be
111 retrieved using the list of size couples stored in the previous
111 retrieved using the list of size couples stored in the previous
112 field.
112 field.
113
113
114 Mandatory parameters comes first, then the advisory ones.
114 Mandatory parameters comes first, then the advisory ones.
115
115
116 Each parameter's key MUST be unique within the part.
116 Each parameter's key MUST be unique within the part.
117
117
118 :payload:
118 :payload:
119
119
120 payload is a series of `<chunksize><chunkdata>`.
120 payload is a series of `<chunksize><chunkdata>`.
121
121
122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
123 `chunksize` says)` The payload part is concluded by a zero size chunk.
123 `chunksize` says)` The payload part is concluded by a zero size chunk.
124
124
125 The current implementation always produces either zero or one chunk.
125 The current implementation always produces either zero or one chunk.
126 This is an implementation limitation that will ultimately be lifted.
126 This is an implementation limitation that will ultimately be lifted.
127
127
128 `chunksize` can be negative to trigger special case processing. No such
128 `chunksize` can be negative to trigger special case processing. No such
129 processing is in place yet.
129 processing is in place yet.
130
130
131 Bundle processing
131 Bundle processing
132 ============================
132 ============================
133
133
134 Each part is processed in order using a "part handler". Handler are registered
134 Each part is processed in order using a "part handler". Handler are registered
135 for a certain part type.
135 for a certain part type.
136
136
137 The matching of a part to its handler is case insensitive. The case of the
137 The matching of a part to its handler is case insensitive. The case of the
138 part type is used to know if a part is mandatory or advisory. If the Part type
138 part type is used to know if a part is mandatory or advisory. If the Part type
139 contains any uppercase char it is considered mandatory. When no handler is
139 contains any uppercase char it is considered mandatory. When no handler is
140 known for a Mandatory part, the process is aborted and an exception is raised.
140 known for a Mandatory part, the process is aborted and an exception is raised.
141 If the part is advisory and no handler is known, the part is ignored. When the
141 If the part is advisory and no handler is known, the part is ignored. When the
142 process is aborted, the full bundle is still read from the stream to keep the
142 process is aborted, the full bundle is still read from the stream to keep the
143 channel usable. But none of the part read from an abort are processed. In the
143 channel usable. But none of the part read from an abort are processed. In the
144 future, dropping the stream may become an option for channel we do not care to
144 future, dropping the stream may become an option for channel we do not care to
145 preserve.
145 preserve.
146 """
146 """
147
147
148 import errno
148 import errno
149 import sys
149 import sys
150 import util
150 import util
151 import struct
151 import struct
152 import urllib
152 import urllib
153 import string
153 import string
154 import obsolete
154 import obsolete
155 import pushkey
155 import pushkey
156 import url
156 import url
157 import re
157 import re
158
158
159 import changegroup, error, tags
159 import changegroup, error, tags
160 from i18n import _
160 from i18n import _
161
161
162 _pack = struct.pack
162 _pack = struct.pack
163 _unpack = struct.unpack
163 _unpack = struct.unpack
164
164
165 _fstreamparamsize = '>i'
165 _fstreamparamsize = '>i'
166 _fpartheadersize = '>i'
166 _fpartheadersize = '>i'
167 _fparttypesize = '>B'
167 _fparttypesize = '>B'
168 _fpartid = '>I'
168 _fpartid = '>I'
169 _fpayloadsize = '>i'
169 _fpayloadsize = '>i'
170 _fpartparamcount = '>BB'
170 _fpartparamcount = '>BB'
171
171
172 preferedchunksize = 4096
172 preferedchunksize = 4096
173
173
174 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
174 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
175
175
176 def outdebug(ui, message):
176 def outdebug(ui, message):
177 """debug regarding output stream (bundling)"""
177 """debug regarding output stream (bundling)"""
178 if ui.configbool('devel', 'bundle2.debug', False):
178 if ui.configbool('devel', 'bundle2.debug', False):
179 ui.debug('bundle2-output: %s\n' % message)
179 ui.debug('bundle2-output: %s\n' % message)
180
180
181 def indebug(ui, message):
181 def indebug(ui, message):
182 """debug on input stream (unbundling)"""
182 """debug on input stream (unbundling)"""
183 if ui.configbool('devel', 'bundle2.debug', False):
183 if ui.configbool('devel', 'bundle2.debug', False):
184 ui.debug('bundle2-input: %s\n' % message)
184 ui.debug('bundle2-input: %s\n' % message)
185
185
186 def validateparttype(parttype):
186 def validateparttype(parttype):
187 """raise ValueError if a parttype contains invalid character"""
187 """raise ValueError if a parttype contains invalid character"""
188 if _parttypeforbidden.search(parttype):
188 if _parttypeforbidden.search(parttype):
189 raise ValueError(parttype)
189 raise ValueError(parttype)
190
190
191 def _makefpartparamsizes(nbparams):
191 def _makefpartparamsizes(nbparams):
192 """return a struct format to read part parameter sizes
192 """return a struct format to read part parameter sizes
193
193
194 The number parameters is variable so we need to build that format
194 The number parameters is variable so we need to build that format
195 dynamically.
195 dynamically.
196 """
196 """
197 return '>'+('BB'*nbparams)
197 return '>'+('BB'*nbparams)
198
198
199 parthandlermapping = {}
199 parthandlermapping = {}
200
200
201 def parthandler(parttype, params=()):
201 def parthandler(parttype, params=()):
202 """decorator that register a function as a bundle2 part handler
202 """decorator that register a function as a bundle2 part handler
203
203
204 eg::
204 eg::
205
205
206 @parthandler('myparttype', ('mandatory', 'param', 'handled'))
206 @parthandler('myparttype', ('mandatory', 'param', 'handled'))
207 def myparttypehandler(...):
207 def myparttypehandler(...):
208 '''process a part of type "my part".'''
208 '''process a part of type "my part".'''
209 ...
209 ...
210 """
210 """
211 validateparttype(parttype)
211 validateparttype(parttype)
212 def _decorator(func):
212 def _decorator(func):
213 lparttype = parttype.lower() # enforce lower case matching.
213 lparttype = parttype.lower() # enforce lower case matching.
214 assert lparttype not in parthandlermapping
214 assert lparttype not in parthandlermapping
215 parthandlermapping[lparttype] = func
215 parthandlermapping[lparttype] = func
216 func.params = frozenset(params)
216 func.params = frozenset(params)
217 return func
217 return func
218 return _decorator
218 return _decorator
219
219
220 class unbundlerecords(object):
220 class unbundlerecords(object):
221 """keep record of what happens during and unbundle
221 """keep record of what happens during and unbundle
222
222
223 New records are added using `records.add('cat', obj)`. Where 'cat' is a
223 New records are added using `records.add('cat', obj)`. Where 'cat' is a
224 category of record and obj is an arbitrary object.
224 category of record and obj is an arbitrary object.
225
225
226 `records['cat']` will return all entries of this category 'cat'.
226 `records['cat']` will return all entries of this category 'cat'.
227
227
228 Iterating on the object itself will yield `('category', obj)` tuples
228 Iterating on the object itself will yield `('category', obj)` tuples
229 for all entries.
229 for all entries.
230
230
231 All iterations happens in chronological order.
231 All iterations happens in chronological order.
232 """
232 """
233
233
234 def __init__(self):
234 def __init__(self):
235 self._categories = {}
235 self._categories = {}
236 self._sequences = []
236 self._sequences = []
237 self._replies = {}
237 self._replies = {}
238
238
239 def add(self, category, entry, inreplyto=None):
239 def add(self, category, entry, inreplyto=None):
240 """add a new record of a given category.
240 """add a new record of a given category.
241
241
242 The entry can then be retrieved in the list returned by
242 The entry can then be retrieved in the list returned by
243 self['category']."""
243 self['category']."""
244 self._categories.setdefault(category, []).append(entry)
244 self._categories.setdefault(category, []).append(entry)
245 self._sequences.append((category, entry))
245 self._sequences.append((category, entry))
246 if inreplyto is not None:
246 if inreplyto is not None:
247 self.getreplies(inreplyto).add(category, entry)
247 self.getreplies(inreplyto).add(category, entry)
248
248
249 def getreplies(self, partid):
249 def getreplies(self, partid):
250 """get the records that are replies to a specific part"""
250 """get the records that are replies to a specific part"""
251 return self._replies.setdefault(partid, unbundlerecords())
251 return self._replies.setdefault(partid, unbundlerecords())
252
252
253 def __getitem__(self, cat):
253 def __getitem__(self, cat):
254 return tuple(self._categories.get(cat, ()))
254 return tuple(self._categories.get(cat, ()))
255
255
256 def __iter__(self):
256 def __iter__(self):
257 return iter(self._sequences)
257 return iter(self._sequences)
258
258
259 def __len__(self):
259 def __len__(self):
260 return len(self._sequences)
260 return len(self._sequences)
261
261
262 def __nonzero__(self):
262 def __nonzero__(self):
263 return bool(self._sequences)
263 return bool(self._sequences)
264
264
265 class bundleoperation(object):
265 class bundleoperation(object):
266 """an object that represents a single bundling process
266 """an object that represents a single bundling process
267
267
268 Its purpose is to carry unbundle-related objects and states.
268 Its purpose is to carry unbundle-related objects and states.
269
269
270 A new object should be created at the beginning of each bundle processing.
270 A new object should be created at the beginning of each bundle processing.
271 The object is to be returned by the processing function.
271 The object is to be returned by the processing function.
272
272
273 The object has very little content now it will ultimately contain:
273 The object has very little content now it will ultimately contain:
274 * an access to the repo the bundle is applied to,
274 * an access to the repo the bundle is applied to,
275 * a ui object,
275 * a ui object,
276 * a way to retrieve a transaction to add changes to the repo,
276 * a way to retrieve a transaction to add changes to the repo,
277 * a way to record the result of processing each part,
277 * a way to record the result of processing each part,
278 * a way to construct a bundle response when applicable.
278 * a way to construct a bundle response when applicable.
279 """
279 """
280
280
281 def __init__(self, repo, transactiongetter, captureoutput=True):
281 def __init__(self, repo, transactiongetter, captureoutput=True):
282 self.repo = repo
282 self.repo = repo
283 self.ui = repo.ui
283 self.ui = repo.ui
284 self.records = unbundlerecords()
284 self.records = unbundlerecords()
285 self.gettransaction = transactiongetter
285 self.gettransaction = transactiongetter
286 self.reply = None
286 self.reply = None
287 self.captureoutput = captureoutput
287 self.captureoutput = captureoutput
288
288
289 class TransactionUnavailable(RuntimeError):
289 class TransactionUnavailable(RuntimeError):
290 pass
290 pass
291
291
292 def _notransaction():
292 def _notransaction():
293 """default method to get a transaction while processing a bundle
293 """default method to get a transaction while processing a bundle
294
294
295 Raise an exception to highlight the fact that no transaction was expected
295 Raise an exception to highlight the fact that no transaction was expected
296 to be created"""
296 to be created"""
297 raise TransactionUnavailable()
297 raise TransactionUnavailable()
298
298
299 def processbundle(repo, unbundler, transactiongetter=None, op=None):
299 def processbundle(repo, unbundler, transactiongetter=None, op=None):
300 """This function process a bundle, apply effect to/from a repo
300 """This function process a bundle, apply effect to/from a repo
301
301
302 It iterates over each part then searches for and uses the proper handling
302 It iterates over each part then searches for and uses the proper handling
303 code to process the part. Parts are processed in order.
303 code to process the part. Parts are processed in order.
304
304
305 This is very early version of this function that will be strongly reworked
305 This is very early version of this function that will be strongly reworked
306 before final usage.
306 before final usage.
307
307
308 Unknown Mandatory part will abort the process.
308 Unknown Mandatory part will abort the process.
309
309
310 It is temporarily possible to provide a prebuilt bundleoperation to the
310 It is temporarily possible to provide a prebuilt bundleoperation to the
311 function. This is used to ensure output is properly propagated in case of
311 function. This is used to ensure output is properly propagated in case of
312 an error during the unbundling. This output capturing part will likely be
312 an error during the unbundling. This output capturing part will likely be
313 reworked and this ability will probably go away in the process.
313 reworked and this ability will probably go away in the process.
314 """
314 """
315 if op is None:
315 if op is None:
316 if transactiongetter is None:
316 if transactiongetter is None:
317 transactiongetter = _notransaction
317 transactiongetter = _notransaction
318 op = bundleoperation(repo, transactiongetter)
318 op = bundleoperation(repo, transactiongetter)
319 # todo:
319 # todo:
320 # - replace this is a init function soon.
320 # - replace this is a init function soon.
321 # - exception catching
321 # - exception catching
322 unbundler.params
322 unbundler.params
323 if repo.ui.debugflag:
323 if repo.ui.debugflag:
324 msg = ['bundle2-input-bundle:']
324 msg = ['bundle2-input-bundle:']
325 if unbundler.params:
325 if unbundler.params:
326 msg.append(' %i params')
326 msg.append(' %i params')
327 if op.gettransaction is None:
327 if op.gettransaction is None:
328 msg.append(' no-transaction')
328 msg.append(' no-transaction')
329 else:
329 else:
330 msg.append(' with-transaction')
330 msg.append(' with-transaction')
331 msg.append('\n')
331 msg.append('\n')
332 repo.ui.debug(''.join(msg))
332 repo.ui.debug(''.join(msg))
333 iterparts = enumerate(unbundler.iterparts())
333 iterparts = enumerate(unbundler.iterparts())
334 part = None
334 part = None
335 nbpart = 0
335 nbpart = 0
336 try:
336 try:
337 for nbpart, part in iterparts:
337 for nbpart, part in iterparts:
338 _processpart(op, part)
338 _processpart(op, part)
339 except BaseException, exc:
339 except BaseException, exc:
340 for nbpart, part in iterparts:
340 for nbpart, part in iterparts:
341 # consume the bundle content
341 # consume the bundle content
342 part.seek(0, 2)
342 part.seek(0, 2)
343 # Small hack to let caller code distinguish exceptions from bundle2
343 # Small hack to let caller code distinguish exceptions from bundle2
344 # processing from processing the old format. This is mostly
344 # processing from processing the old format. This is mostly
345 # needed to handle different return codes to unbundle according to the
345 # needed to handle different return codes to unbundle according to the
346 # type of bundle. We should probably clean up or drop this return code
346 # type of bundle. We should probably clean up or drop this return code
347 # craziness in a future version.
347 # craziness in a future version.
348 exc.duringunbundle2 = True
348 exc.duringunbundle2 = True
349 salvaged = []
349 salvaged = []
350 replycaps = None
350 replycaps = None
351 if op.reply is not None:
351 if op.reply is not None:
352 salvaged = op.reply.salvageoutput()
352 salvaged = op.reply.salvageoutput()
353 replycaps = op.reply.capabilities
353 replycaps = op.reply.capabilities
354 exc._replycaps = replycaps
354 exc._replycaps = replycaps
355 exc._bundle2salvagedoutput = salvaged
355 exc._bundle2salvagedoutput = salvaged
356 raise
356 raise
357 finally:
357 finally:
358 repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
358 repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
359
359
360 return op
360 return op
361
361
362 def _processpart(op, part):
362 def _processpart(op, part):
363 """process a single part from a bundle
363 """process a single part from a bundle
364
364
365 The part is guaranteed to have been fully consumed when the function exits
365 The part is guaranteed to have been fully consumed when the function exits
366 (even if an exception is raised)."""
366 (even if an exception is raised)."""
367 status = 'unknown' # used by debug output
367 status = 'unknown' # used by debug output
368 try:
368 try:
369 try:
369 try:
370 handler = parthandlermapping.get(part.type)
370 handler = parthandlermapping.get(part.type)
371 if handler is None:
371 if handler is None:
372 status = 'unsupported-type'
372 status = 'unsupported-type'
373 raise error.UnsupportedPartError(parttype=part.type)
373 raise error.UnsupportedPartError(parttype=part.type)
374 indebug(op.ui, 'found a handler for part %r' % part.type)
374 indebug(op.ui, 'found a handler for part %r' % part.type)
375 unknownparams = part.mandatorykeys - handler.params
375 unknownparams = part.mandatorykeys - handler.params
376 if unknownparams:
376 if unknownparams:
377 unknownparams = list(unknownparams)
377 unknownparams = list(unknownparams)
378 unknownparams.sort()
378 unknownparams.sort()
379 status = 'unsupported-params (%s)' % unknownparams
379 status = 'unsupported-params (%s)' % unknownparams
380 raise error.UnsupportedPartError(parttype=part.type,
380 raise error.UnsupportedPartError(parttype=part.type,
381 params=unknownparams)
381 params=unknownparams)
382 status = 'supported'
382 status = 'supported'
383 except error.UnsupportedPartError, exc:
383 except error.UnsupportedPartError, exc:
384 if part.mandatory: # mandatory parts
384 if part.mandatory: # mandatory parts
385 raise
385 raise
386 indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
386 indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
387 return # skip to part processing
387 return # skip to part processing
388 finally:
388 finally:
389 if op.ui.debugflag:
389 if op.ui.debugflag:
390 msg = ['bundle2-input-part: "%s"' % part.type]
390 msg = ['bundle2-input-part: "%s"' % part.type]
391 if not part.mandatory:
391 if not part.mandatory:
392 msg.append(' (advisory)')
392 msg.append(' (advisory)')
393 nbmp = len(part.mandatorykeys)
393 nbmp = len(part.mandatorykeys)
394 nbap = len(part.params) - nbmp
394 nbap = len(part.params) - nbmp
395 if nbmp or nbap:
395 if nbmp or nbap:
396 msg.append(' (params:')
396 msg.append(' (params:')
397 if nbmp:
397 if nbmp:
398 msg.append(' %i mandatory' % nbmp)
398 msg.append(' %i mandatory' % nbmp)
399 if nbap:
399 if nbap:
400 msg.append(' %i advisory' % nbmp)
400 msg.append(' %i advisory' % nbmp)
401 msg.append(')')
401 msg.append(')')
402 msg.append(' %s\n' % status)
402 msg.append(' %s\n' % status)
403 op.ui.debug(''.join(msg))
403 op.ui.debug(''.join(msg))
404
404
405 # handler is called outside the above try block so that we don't
405 # handler is called outside the above try block so that we don't
406 # risk catching KeyErrors from anything other than the
406 # risk catching KeyErrors from anything other than the
407 # parthandlermapping lookup (any KeyError raised by handler()
407 # parthandlermapping lookup (any KeyError raised by handler()
408 # itself represents a defect of a different variety).
408 # itself represents a defect of a different variety).
409 output = None
409 output = None
410 if op.captureoutput and op.reply is not None:
410 if op.captureoutput and op.reply is not None:
411 op.ui.pushbuffer(error=True, subproc=True)
411 op.ui.pushbuffer(error=True, subproc=True)
412 output = ''
412 output = ''
413 try:
413 try:
414 handler(op, part)
414 handler(op, part)
415 finally:
415 finally:
416 if output is not None:
416 if output is not None:
417 output = op.ui.popbuffer()
417 output = op.ui.popbuffer()
418 if output:
418 if output:
419 outpart = op.reply.newpart('output', data=output,
419 outpart = op.reply.newpart('output', data=output,
420 mandatory=False)
420 mandatory=False)
421 outpart.addparam('in-reply-to', str(part.id), mandatory=False)
421 outpart.addparam('in-reply-to', str(part.id), mandatory=False)
422 finally:
422 finally:
423 # consume the part content to not corrupt the stream.
423 # consume the part content to not corrupt the stream.
424 part.seek(0, 2)
424 part.seek(0, 2)
425
425
426
426
427 def decodecaps(blob):
427 def decodecaps(blob):
428 """decode a bundle2 caps bytes blob into a dictionary
428 """decode a bundle2 caps bytes blob into a dictionary
429
429
430 The blob is a list of capabilities (one per line)
430 The blob is a list of capabilities (one per line)
431 Capabilities may have values using a line of the form::
431 Capabilities may have values using a line of the form::
432
432
433 capability=value1,value2,value3
433 capability=value1,value2,value3
434
434
435 The values are always a list."""
435 The values are always a list."""
436 caps = {}
436 caps = {}
437 for line in blob.splitlines():
437 for line in blob.splitlines():
438 if not line:
438 if not line:
439 continue
439 continue
440 if '=' not in line:
440 if '=' not in line:
441 key, vals = line, ()
441 key, vals = line, ()
442 else:
442 else:
443 key, vals = line.split('=', 1)
443 key, vals = line.split('=', 1)
444 vals = vals.split(',')
444 vals = vals.split(',')
445 key = urllib.unquote(key)
445 key = urllib.unquote(key)
446 vals = [urllib.unquote(v) for v in vals]
446 vals = [urllib.unquote(v) for v in vals]
447 caps[key] = vals
447 caps[key] = vals
448 return caps
448 return caps
449
449
450 def encodecaps(caps):
450 def encodecaps(caps):
451 """encode a bundle2 caps dictionary into a bytes blob"""
451 """encode a bundle2 caps dictionary into a bytes blob"""
452 chunks = []
452 chunks = []
453 for ca in sorted(caps):
453 for ca in sorted(caps):
454 vals = caps[ca]
454 vals = caps[ca]
455 ca = urllib.quote(ca)
455 ca = urllib.quote(ca)
456 vals = [urllib.quote(v) for v in vals]
456 vals = [urllib.quote(v) for v in vals]
457 if vals:
457 if vals:
458 ca = "%s=%s" % (ca, ','.join(vals))
458 ca = "%s=%s" % (ca, ','.join(vals))
459 chunks.append(ca)
459 chunks.append(ca)
460 return '\n'.join(chunks)
460 return '\n'.join(chunks)
461
461
462 class bundle20(object):
462 class bundle20(object):
463 """represent an outgoing bundle2 container
463 """represent an outgoing bundle2 container
464
464
465 Use the `addparam` method to add stream level parameter. and `newpart` to
465 Use the `addparam` method to add stream level parameter. and `newpart` to
466 populate it. Then call `getchunks` to retrieve all the binary chunks of
466 populate it. Then call `getchunks` to retrieve all the binary chunks of
467 data that compose the bundle2 container."""
467 data that compose the bundle2 container."""
468
468
469 _magicstring = 'HG20'
469 _magicstring = 'HG20'
470
470
471 def __init__(self, ui, capabilities=()):
471 def __init__(self, ui, capabilities=()):
472 self.ui = ui
472 self.ui = ui
473 self._params = []
473 self._params = []
474 self._parts = []
474 self._parts = []
475 self.capabilities = dict(capabilities)
475 self.capabilities = dict(capabilities)
476
476
477 @property
477 @property
478 def nbparts(self):
478 def nbparts(self):
479 """total number of parts added to the bundler"""
479 """total number of parts added to the bundler"""
480 return len(self._parts)
480 return len(self._parts)
481
481
482 # methods used to defines the bundle2 content
482 # methods used to defines the bundle2 content
483 def addparam(self, name, value=None):
483 def addparam(self, name, value=None):
484 """add a stream level parameter"""
484 """add a stream level parameter"""
485 if not name:
485 if not name:
486 raise ValueError('empty parameter name')
486 raise ValueError('empty parameter name')
487 if name[0] not in string.letters:
487 if name[0] not in string.letters:
488 raise ValueError('non letter first character: %r' % name)
488 raise ValueError('non letter first character: %r' % name)
489 self._params.append((name, value))
489 self._params.append((name, value))
490
490
491 def addpart(self, part):
491 def addpart(self, part):
492 """add a new part to the bundle2 container
492 """add a new part to the bundle2 container
493
493
494 Parts contains the actual applicative payload."""
494 Parts contains the actual applicative payload."""
495 assert part.id is None
495 assert part.id is None
496 part.id = len(self._parts) # very cheap counter
496 part.id = len(self._parts) # very cheap counter
497 self._parts.append(part)
497 self._parts.append(part)
498
498
499 def newpart(self, typeid, *args, **kwargs):
499 def newpart(self, typeid, *args, **kwargs):
500 """create a new part and add it to the containers
500 """create a new part and add it to the containers
501
501
502 As the part is directly added to the containers. For now, this means
502 As the part is directly added to the containers. For now, this means
503 that any failure to properly initialize the part after calling
503 that any failure to properly initialize the part after calling
504 ``newpart`` should result in a failure of the whole bundling process.
504 ``newpart`` should result in a failure of the whole bundling process.
505
505
506 You can still fall back to manually create and add if you need better
506 You can still fall back to manually create and add if you need better
507 control."""
507 control."""
508 part = bundlepart(typeid, *args, **kwargs)
508 part = bundlepart(typeid, *args, **kwargs)
509 self.addpart(part)
509 self.addpart(part)
510 return part
510 return part
511
511
512 # methods used to generate the bundle2 stream
512 # methods used to generate the bundle2 stream
513 def getchunks(self):
513 def getchunks(self):
514 if self.ui.debugflag:
514 if self.ui.debugflag:
515 msg = ['bundle2-output-bundle: "%s",' % self._magicstring]
515 msg = ['bundle2-output-bundle: "%s",' % self._magicstring]
516 if self._params:
516 if self._params:
517 msg.append(' (%i params)' % len(self._params))
517 msg.append(' (%i params)' % len(self._params))
518 msg.append(' %i parts total\n' % len(self._parts))
518 msg.append(' %i parts total\n' % len(self._parts))
519 self.ui.debug(''.join(msg))
519 self.ui.debug(''.join(msg))
520 outdebug(self.ui, 'start emission of %s stream' % self._magicstring)
520 outdebug(self.ui, 'start emission of %s stream' % self._magicstring)
521 yield self._magicstring
521 yield self._magicstring
522 param = self._paramchunk()
522 param = self._paramchunk()
523 outdebug(self.ui, 'bundle parameter: %s' % param)
523 outdebug(self.ui, 'bundle parameter: %s' % param)
524 yield _pack(_fstreamparamsize, len(param))
524 yield _pack(_fstreamparamsize, len(param))
525 if param:
525 if param:
526 yield param
526 yield param
527
527
528 outdebug(self.ui, 'start of parts')
528 outdebug(self.ui, 'start of parts')
529 for part in self._parts:
529 for part in self._parts:
530 outdebug(self.ui, 'bundle part: "%s"' % part.type)
530 outdebug(self.ui, 'bundle part: "%s"' % part.type)
531 for chunk in part.getchunks(ui=self.ui):
531 for chunk in part.getchunks(ui=self.ui):
532 yield chunk
532 yield chunk
533 outdebug(self.ui, 'end of bundle')
533 outdebug(self.ui, 'end of bundle')
534 yield _pack(_fpartheadersize, 0)
534 yield _pack(_fpartheadersize, 0)
535
535
536 def _paramchunk(self):
536 def _paramchunk(self):
537 """return a encoded version of all stream parameters"""
537 """return a encoded version of all stream parameters"""
538 blocks = []
538 blocks = []
539 for par, value in self._params:
539 for par, value in self._params:
540 par = urllib.quote(par)
540 par = urllib.quote(par)
541 if value is not None:
541 if value is not None:
542 value = urllib.quote(value)
542 value = urllib.quote(value)
543 par = '%s=%s' % (par, value)
543 par = '%s=%s' % (par, value)
544 blocks.append(par)
544 blocks.append(par)
545 return ' '.join(blocks)
545 return ' '.join(blocks)
546
546
547 def salvageoutput(self):
547 def salvageoutput(self):
548 """return a list with a copy of all output parts in the bundle
548 """return a list with a copy of all output parts in the bundle
549
549
550 This is meant to be used during error handling to make sure we preserve
550 This is meant to be used during error handling to make sure we preserve
551 server output"""
551 server output"""
552 salvaged = []
552 salvaged = []
553 for part in self._parts:
553 for part in self._parts:
554 if part.type.startswith('output'):
554 if part.type.startswith('output'):
555 salvaged.append(part.copy())
555 salvaged.append(part.copy())
556 return salvaged
556 return salvaged
557
557
558
558
559 class unpackermixin(object):
559 class unpackermixin(object):
560 """A mixin to extract bytes and struct data from a stream"""
560 """A mixin to extract bytes and struct data from a stream"""
561
561
562 def __init__(self, fp):
562 def __init__(self, fp):
563 self._fp = fp
563 self._fp = fp
564 self._seekable = (util.safehasattr(fp, 'seek') and
564 self._seekable = (util.safehasattr(fp, 'seek') and
565 util.safehasattr(fp, 'tell'))
565 util.safehasattr(fp, 'tell'))
566
566
567 def _unpack(self, format):
567 def _unpack(self, format):
568 """unpack this struct format from the stream"""
568 """unpack this struct format from the stream"""
569 data = self._readexact(struct.calcsize(format))
569 data = self._readexact(struct.calcsize(format))
570 return _unpack(format, data)
570 return _unpack(format, data)
571
571
572 def _readexact(self, size):
572 def _readexact(self, size):
573 """read exactly <size> bytes from the stream"""
573 """read exactly <size> bytes from the stream"""
574 return changegroup.readexactly(self._fp, size)
574 return changegroup.readexactly(self._fp, size)
575
575
576 def seek(self, offset, whence=0):
576 def seek(self, offset, whence=0):
577 """move the underlying file pointer"""
577 """move the underlying file pointer"""
578 if self._seekable:
578 if self._seekable:
579 return self._fp.seek(offset, whence)
579 return self._fp.seek(offset, whence)
580 else:
580 else:
581 raise NotImplementedError(_('File pointer is not seekable'))
581 raise NotImplementedError(_('File pointer is not seekable'))
582
582
583 def tell(self):
583 def tell(self):
584 """return the file offset, or None if file is not seekable"""
584 """return the file offset, or None if file is not seekable"""
585 if self._seekable:
585 if self._seekable:
586 try:
586 try:
587 return self._fp.tell()
587 return self._fp.tell()
588 except IOError, e:
588 except IOError, e:
589 if e.errno == errno.ESPIPE:
589 if e.errno == errno.ESPIPE:
590 self._seekable = False
590 self._seekable = False
591 else:
591 else:
592 raise
592 raise
593 return None
593 return None
594
594
595 def close(self):
595 def close(self):
596 """close underlying file"""
596 """close underlying file"""
597 if util.safehasattr(self._fp, 'close'):
597 if util.safehasattr(self._fp, 'close'):
598 return self._fp.close()
598 return self._fp.close()
599
599
600 def getunbundler(ui, fp, header=None):
600 def getunbundler(ui, fp, header=None):
601 """return a valid unbundler object for a given header"""
601 """return a valid unbundler object for a given header"""
602 if header is None:
602 if header is None:
603 header = changegroup.readexactly(fp, 4)
603 header = changegroup.readexactly(fp, 4)
604 magic, version = header[0:2], header[2:4]
604 magic, version = header[0:2], header[2:4]
605 if magic != 'HG':
605 if magic != 'HG':
606 raise util.Abort(_('not a Mercurial bundle'))
606 raise util.Abort(_('not a Mercurial bundle'))
607 unbundlerclass = formatmap.get(version)
607 unbundlerclass = formatmap.get(version)
608 if unbundlerclass is None:
608 if unbundlerclass is None:
609 raise util.Abort(_('unknown bundle version %s') % version)
609 raise util.Abort(_('unknown bundle version %s') % version)
610 unbundler = unbundlerclass(ui, fp)
610 unbundler = unbundlerclass(ui, fp)
611 indebug(ui, 'start processing of %s stream' % header)
611 indebug(ui, 'start processing of %s stream' % header)
612 return unbundler
612 return unbundler
613
613
614 class unbundle20(unpackermixin):
614 class unbundle20(unpackermixin):
615 """interpret a bundle2 stream
615 """interpret a bundle2 stream
616
616
617 This class is fed with a binary stream and yields parts through its
617 This class is fed with a binary stream and yields parts through its
618 `iterparts` methods."""
618 `iterparts` methods."""
619
619
620 def __init__(self, ui, fp):
620 def __init__(self, ui, fp):
621 """If header is specified, we do not read it out of the stream."""
621 """If header is specified, we do not read it out of the stream."""
622 self.ui = ui
622 self.ui = ui
623 super(unbundle20, self).__init__(fp)
623 super(unbundle20, self).__init__(fp)
624
624
625 @util.propertycache
625 @util.propertycache
626 def params(self):
626 def params(self):
627 """dictionary of stream level parameters"""
627 """dictionary of stream level parameters"""
628 indebug(self.ui, 'reading bundle2 stream parameters')
628 indebug(self.ui, 'reading bundle2 stream parameters')
629 params = {}
629 params = {}
630 paramssize = self._unpack(_fstreamparamsize)[0]
630 paramssize = self._unpack(_fstreamparamsize)[0]
631 if paramssize < 0:
631 if paramssize < 0:
632 raise error.BundleValueError('negative bundle param size: %i'
632 raise error.BundleValueError('negative bundle param size: %i'
633 % paramssize)
633 % paramssize)
634 if paramssize:
634 if paramssize:
635 for p in self._readexact(paramssize).split(' '):
635 for p in self._readexact(paramssize).split(' '):
636 p = p.split('=', 1)
636 p = p.split('=', 1)
637 p = [urllib.unquote(i) for i in p]
637 p = [urllib.unquote(i) for i in p]
638 if len(p) < 2:
638 if len(p) < 2:
639 p.append(None)
639 p.append(None)
640 self._processparam(*p)
640 self._processparam(*p)
641 params[p[0]] = p[1]
641 params[p[0]] = p[1]
642 return params
642 return params
643
643
644 def _processparam(self, name, value):
644 def _processparam(self, name, value):
645 """process a parameter, applying its effect if needed
645 """process a parameter, applying its effect if needed
646
646
647 Parameter starting with a lower case letter are advisory and will be
647 Parameter starting with a lower case letter are advisory and will be
648 ignored when unknown. Those starting with an upper case letter are
648 ignored when unknown. Those starting with an upper case letter are
649 mandatory and will this function will raise a KeyError when unknown.
649 mandatory and will this function will raise a KeyError when unknown.
650
650
651 Note: no option are currently supported. Any input will be either
651 Note: no option are currently supported. Any input will be either
652 ignored or failing.
652 ignored or failing.
653 """
653 """
654 if not name:
654 if not name:
655 raise ValueError('empty parameter name')
655 raise ValueError('empty parameter name')
656 if name[0] not in string.letters:
656 if name[0] not in string.letters:
657 raise ValueError('non letter first character: %r' % name)
657 raise ValueError('non letter first character: %r' % name)
658 # Some logic will be later added here to try to process the option for
658 # Some logic will be later added here to try to process the option for
659 # a dict of known parameter.
659 # a dict of known parameter.
660 if name[0].islower():
660 if name[0].islower():
661 indebug(self.ui, "ignoring unknown parameter %r" % name)
661 indebug(self.ui, "ignoring unknown parameter %r" % name)
662 else:
662 else:
663 raise error.UnsupportedPartError(params=(name,))
663 raise error.UnsupportedPartError(params=(name,))
664
664
665
665
666 def iterparts(self):
666 def iterparts(self):
667 """yield all parts contained in the stream"""
667 """yield all parts contained in the stream"""
668 # make sure param have been loaded
668 # make sure param have been loaded
669 self.params
669 self.params
670 indebug(self.ui, 'start extraction of bundle2 parts')
670 indebug(self.ui, 'start extraction of bundle2 parts')
671 headerblock = self._readpartheader()
671 headerblock = self._readpartheader()
672 while headerblock is not None:
672 while headerblock is not None:
673 part = unbundlepart(self.ui, headerblock, self._fp)
673 part = unbundlepart(self.ui, headerblock, self._fp)
674 yield part
674 yield part
675 part.seek(0, 2)
675 part.seek(0, 2)
676 headerblock = self._readpartheader()
676 headerblock = self._readpartheader()
677 indebug(self.ui, 'end of bundle2 stream')
677 indebug(self.ui, 'end of bundle2 stream')
678
678
679 def _readpartheader(self):
679 def _readpartheader(self):
680 """reads a part header size and return the bytes blob
680 """reads a part header size and return the bytes blob
681
681
682 returns None if empty"""
682 returns None if empty"""
683 headersize = self._unpack(_fpartheadersize)[0]
683 headersize = self._unpack(_fpartheadersize)[0]
684 if headersize < 0:
684 if headersize < 0:
685 raise error.BundleValueError('negative part header size: %i'
685 raise error.BundleValueError('negative part header size: %i'
686 % headersize)
686 % headersize)
687 indebug(self.ui, 'part header size: %i' % headersize)
687 indebug(self.ui, 'part header size: %i' % headersize)
688 if headersize:
688 if headersize:
689 return self._readexact(headersize)
689 return self._readexact(headersize)
690 return None
690 return None
691
691
692 def compressed(self):
692 def compressed(self):
693 return False
693 return False
694
694
695 formatmap = {'20': unbundle20}
695 formatmap = {'20': unbundle20}
696
696
697 class bundlepart(object):
697 class bundlepart(object):
698 """A bundle2 part contains application level payload
698 """A bundle2 part contains application level payload
699
699
700 The part `type` is used to route the part to the application level
700 The part `type` is used to route the part to the application level
701 handler.
701 handler.
702
702
703 The part payload is contained in ``part.data``. It could be raw bytes or a
703 The part payload is contained in ``part.data``. It could be raw bytes or a
704 generator of byte chunks.
704 generator of byte chunks.
705
705
706 You can add parameters to the part using the ``addparam`` method.
706 You can add parameters to the part using the ``addparam`` method.
707 Parameters can be either mandatory (default) or advisory. Remote side
707 Parameters can be either mandatory (default) or advisory. Remote side
708 should be able to safely ignore the advisory ones.
708 should be able to safely ignore the advisory ones.
709
709
710 Both data and parameters cannot be modified after the generation has begun.
710 Both data and parameters cannot be modified after the generation has begun.
711 """
711 """
712
712
713 def __init__(self, parttype, mandatoryparams=(), advisoryparams=(),
713 def __init__(self, parttype, mandatoryparams=(), advisoryparams=(),
714 data='', mandatory=True):
714 data='', mandatory=True):
715 validateparttype(parttype)
715 validateparttype(parttype)
716 self.id = None
716 self.id = None
717 self.type = parttype
717 self.type = parttype
718 self._data = data
718 self._data = data
719 self._mandatoryparams = list(mandatoryparams)
719 self._mandatoryparams = list(mandatoryparams)
720 self._advisoryparams = list(advisoryparams)
720 self._advisoryparams = list(advisoryparams)
721 # checking for duplicated entries
721 # checking for duplicated entries
722 self._seenparams = set()
722 self._seenparams = set()
723 for pname, __ in self._mandatoryparams + self._advisoryparams:
723 for pname, __ in self._mandatoryparams + self._advisoryparams:
724 if pname in self._seenparams:
724 if pname in self._seenparams:
725 raise RuntimeError('duplicated params: %s' % pname)
725 raise RuntimeError('duplicated params: %s' % pname)
726 self._seenparams.add(pname)
726 self._seenparams.add(pname)
727 # status of the part's generation:
727 # status of the part's generation:
728 # - None: not started,
728 # - None: not started,
729 # - False: currently generated,
729 # - False: currently generated,
730 # - True: generation done.
730 # - True: generation done.
731 self._generated = None
731 self._generated = None
732 self.mandatory = mandatory
732 self.mandatory = mandatory
733
733
734 def copy(self):
734 def copy(self):
735 """return a copy of the part
735 """return a copy of the part
736
736
737 The new part have the very same content but no partid assigned yet.
737 The new part have the very same content but no partid assigned yet.
738 Parts with generated data cannot be copied."""
738 Parts with generated data cannot be copied."""
739 assert not util.safehasattr(self.data, 'next')
739 assert not util.safehasattr(self.data, 'next')
740 return self.__class__(self.type, self._mandatoryparams,
740 return self.__class__(self.type, self._mandatoryparams,
741 self._advisoryparams, self._data, self.mandatory)
741 self._advisoryparams, self._data, self.mandatory)
742
742
743 # methods used to defines the part content
743 # methods used to defines the part content
744 def __setdata(self, data):
744 def __setdata(self, data):
745 if self._generated is not None:
745 if self._generated is not None:
746 raise error.ReadOnlyPartError('part is being generated')
746 raise error.ReadOnlyPartError('part is being generated')
747 self._data = data
747 self._data = data
748 def __getdata(self):
748 def __getdata(self):
749 return self._data
749 return self._data
750 data = property(__getdata, __setdata)
750 data = property(__getdata, __setdata)
751
751
752 @property
752 @property
753 def mandatoryparams(self):
753 def mandatoryparams(self):
754 # make it an immutable tuple to force people through ``addparam``
754 # make it an immutable tuple to force people through ``addparam``
755 return tuple(self._mandatoryparams)
755 return tuple(self._mandatoryparams)
756
756
757 @property
757 @property
758 def advisoryparams(self):
758 def advisoryparams(self):
759 # make it an immutable tuple to force people through ``addparam``
759 # make it an immutable tuple to force people through ``addparam``
760 return tuple(self._advisoryparams)
760 return tuple(self._advisoryparams)
761
761
762 def addparam(self, name, value='', mandatory=True):
762 def addparam(self, name, value='', mandatory=True):
763 if self._generated is not None:
763 if self._generated is not None:
764 raise error.ReadOnlyPartError('part is being generated')
764 raise error.ReadOnlyPartError('part is being generated')
765 if name in self._seenparams:
765 if name in self._seenparams:
766 raise ValueError('duplicated params: %s' % name)
766 raise ValueError('duplicated params: %s' % name)
767 self._seenparams.add(name)
767 self._seenparams.add(name)
768 params = self._advisoryparams
768 params = self._advisoryparams
769 if mandatory:
769 if mandatory:
770 params = self._mandatoryparams
770 params = self._mandatoryparams
771 params.append((name, value))
771 params.append((name, value))
772
772
773 # methods used to generates the bundle2 stream
773 # methods used to generates the bundle2 stream
774 def getchunks(self, ui):
774 def getchunks(self, ui):
775 if self._generated is not None:
775 if self._generated is not None:
776 raise RuntimeError('part can only be consumed once')
776 raise RuntimeError('part can only be consumed once')
777 self._generated = False
777 self._generated = False
778
778
779 if ui.debugflag:
779 if ui.debugflag:
780 msg = ['bundle2-output-part: "%s"' % self.type]
780 msg = ['bundle2-output-part: "%s"' % self.type]
781 if not self.mandatory:
781 if not self.mandatory:
782 msg.append(' (advisory)')
782 msg.append(' (advisory)')
783 nbmp = len(self.mandatoryparams)
783 nbmp = len(self.mandatoryparams)
784 nbap = len(self.advisoryparams)
784 nbap = len(self.advisoryparams)
785 if nbmp or nbap:
785 if nbmp or nbap:
786 msg.append(' (params:')
786 msg.append(' (params:')
787 if nbmp:
787 if nbmp:
788 msg.append(' %i mandatory' % nbmp)
788 msg.append(' %i mandatory' % nbmp)
789 if nbap:
789 if nbap:
790 msg.append(' %i advisory' % nbmp)
790 msg.append(' %i advisory' % nbmp)
791 msg.append(')')
791 msg.append(')')
792 if not self.data:
792 if not self.data:
793 msg.append(' empty payload')
793 msg.append(' empty payload')
794 elif util.safehasattr(self.data, 'next'):
794 elif util.safehasattr(self.data, 'next'):
795 msg.append(' streamed payload')
795 msg.append(' streamed payload')
796 else:
796 else:
797 msg.append(' %i bytes payload' % len(self.data))
797 msg.append(' %i bytes payload' % len(self.data))
798 msg.append('\n')
798 msg.append('\n')
799 ui.debug(''.join(msg))
799 ui.debug(''.join(msg))
800
800
801 #### header
801 #### header
802 if self.mandatory:
802 if self.mandatory:
803 parttype = self.type.upper()
803 parttype = self.type.upper()
804 else:
804 else:
805 parttype = self.type.lower()
805 parttype = self.type.lower()
806 outdebug(ui, 'part %s: "%s"' % (self.id, parttype))
806 outdebug(ui, 'part %s: "%s"' % (self.id, parttype))
807 ## parttype
807 ## parttype
808 header = [_pack(_fparttypesize, len(parttype)),
808 header = [_pack(_fparttypesize, len(parttype)),
809 parttype, _pack(_fpartid, self.id),
809 parttype, _pack(_fpartid, self.id),
810 ]
810 ]
811 ## parameters
811 ## parameters
812 # count
812 # count
813 manpar = self.mandatoryparams
813 manpar = self.mandatoryparams
814 advpar = self.advisoryparams
814 advpar = self.advisoryparams
815 header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
815 header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
816 # size
816 # size
817 parsizes = []
817 parsizes = []
818 for key, value in manpar:
818 for key, value in manpar:
819 parsizes.append(len(key))
819 parsizes.append(len(key))
820 parsizes.append(len(value))
820 parsizes.append(len(value))
821 for key, value in advpar:
821 for key, value in advpar:
822 parsizes.append(len(key))
822 parsizes.append(len(key))
823 parsizes.append(len(value))
823 parsizes.append(len(value))
824 paramsizes = _pack(_makefpartparamsizes(len(parsizes) / 2), *parsizes)
824 paramsizes = _pack(_makefpartparamsizes(len(parsizes) / 2), *parsizes)
825 header.append(paramsizes)
825 header.append(paramsizes)
826 # key, value
826 # key, value
827 for key, value in manpar:
827 for key, value in manpar:
828 header.append(key)
828 header.append(key)
829 header.append(value)
829 header.append(value)
830 for key, value in advpar:
830 for key, value in advpar:
831 header.append(key)
831 header.append(key)
832 header.append(value)
832 header.append(value)
833 ## finalize header
833 ## finalize header
834 headerchunk = ''.join(header)
834 headerchunk = ''.join(header)
835 outdebug(ui, 'header chunk size: %i' % len(headerchunk))
835 outdebug(ui, 'header chunk size: %i' % len(headerchunk))
836 yield _pack(_fpartheadersize, len(headerchunk))
836 yield _pack(_fpartheadersize, len(headerchunk))
837 yield headerchunk
837 yield headerchunk
838 ## payload
838 ## payload
839 try:
839 try:
840 for chunk in self._payloadchunks():
840 for chunk in self._payloadchunks():
841 outdebug(ui, 'payload chunk size: %i' % len(chunk))
841 outdebug(ui, 'payload chunk size: %i' % len(chunk))
842 yield _pack(_fpayloadsize, len(chunk))
842 yield _pack(_fpayloadsize, len(chunk))
843 yield chunk
843 yield chunk
844 except BaseException, exc:
844 except BaseException, exc:
845 # backup exception data for later
845 # backup exception data for later
846 ui.debug('bundle2-input-stream-interrupt: encoding exception %s'
846 ui.debug('bundle2-input-stream-interrupt: encoding exception %s'
847 % exc)
847 % exc)
848 exc_info = sys.exc_info()
848 exc_info = sys.exc_info()
849 msg = 'unexpected error: %s' % exc
849 msg = 'unexpected error: %s' % exc
850 interpart = bundlepart('error:abort', [('message', msg)],
850 interpart = bundlepart('error:abort', [('message', msg)],
851 mandatory=False)
851 mandatory=False)
852 interpart.id = 0
852 interpart.id = 0
853 yield _pack(_fpayloadsize, -1)
853 yield _pack(_fpayloadsize, -1)
854 for chunk in interpart.getchunks(ui=ui):
854 for chunk in interpart.getchunks(ui=ui):
855 yield chunk
855 yield chunk
856 outdebug(ui, 'closing payload chunk')
856 outdebug(ui, 'closing payload chunk')
857 # abort current part payload
857 # abort current part payload
858 yield _pack(_fpayloadsize, 0)
858 yield _pack(_fpayloadsize, 0)
859 raise exc_info[0], exc_info[1], exc_info[2]
859 raise exc_info[0], exc_info[1], exc_info[2]
860 # end of payload
860 # end of payload
861 outdebug(ui, 'closing payload chunk')
861 outdebug(ui, 'closing payload chunk')
862 yield _pack(_fpayloadsize, 0)
862 yield _pack(_fpayloadsize, 0)
863 self._generated = True
863 self._generated = True
864
864
865 def _payloadchunks(self):
865 def _payloadchunks(self):
866 """yield chunks of a the part payload
866 """yield chunks of a the part payload
867
867
868 Exists to handle the different methods to provide data to a part."""
868 Exists to handle the different methods to provide data to a part."""
869 # we only support fixed size data now.
869 # we only support fixed size data now.
870 # This will be improved in the future.
870 # This will be improved in the future.
871 if util.safehasattr(self.data, 'next'):
871 if util.safehasattr(self.data, 'next'):
872 buff = util.chunkbuffer(self.data)
872 buff = util.chunkbuffer(self.data)
873 chunk = buff.read(preferedchunksize)
873 chunk = buff.read(preferedchunksize)
874 while chunk:
874 while chunk:
875 yield chunk
875 yield chunk
876 chunk = buff.read(preferedchunksize)
876 chunk = buff.read(preferedchunksize)
877 elif len(self.data):
877 elif len(self.data):
878 yield self.data
878 yield self.data
879
879
880
880
881 flaginterrupt = -1
881 flaginterrupt = -1
882
882
883 class interrupthandler(unpackermixin):
883 class interrupthandler(unpackermixin):
884 """read one part and process it with restricted capability
884 """read one part and process it with restricted capability
885
885
886 This allows to transmit exception raised on the producer size during part
886 This allows to transmit exception raised on the producer size during part
887 iteration while the consumer is reading a part.
887 iteration while the consumer is reading a part.
888
888
889 Part processed in this manner only have access to a ui object,"""
889 Part processed in this manner only have access to a ui object,"""
890
890
891 def __init__(self, ui, fp):
891 def __init__(self, ui, fp):
892 super(interrupthandler, self).__init__(fp)
892 super(interrupthandler, self).__init__(fp)
893 self.ui = ui
893 self.ui = ui
894
894
895 def _readpartheader(self):
895 def _readpartheader(self):
896 """reads a part header size and return the bytes blob
896 """reads a part header size and return the bytes blob
897
897
898 returns None if empty"""
898 returns None if empty"""
899 headersize = self._unpack(_fpartheadersize)[0]
899 headersize = self._unpack(_fpartheadersize)[0]
900 if headersize < 0:
900 if headersize < 0:
901 raise error.BundleValueError('negative part header size: %i'
901 raise error.BundleValueError('negative part header size: %i'
902 % headersize)
902 % headersize)
903 indebug(self.ui, 'part header size: %i\n' % headersize)
903 indebug(self.ui, 'part header size: %i\n' % headersize)
904 if headersize:
904 if headersize:
905 return self._readexact(headersize)
905 return self._readexact(headersize)
906 return None
906 return None
907
907
908 def __call__(self):
908 def __call__(self):
909
909
910 self.ui.debug('bundle2-input-stream-interrupt:'
910 self.ui.debug('bundle2-input-stream-interrupt:'
911 ' opening out of band context\n')
911 ' opening out of band context\n')
912 indebug(self.ui, 'bundle2 stream interruption, looking for a part.')
912 indebug(self.ui, 'bundle2 stream interruption, looking for a part.')
913 headerblock = self._readpartheader()
913 headerblock = self._readpartheader()
914 if headerblock is None:
914 if headerblock is None:
915 indebug(self.ui, 'no part found during interruption.')
915 indebug(self.ui, 'no part found during interruption.')
916 return
916 return
917 part = unbundlepart(self.ui, headerblock, self._fp)
917 part = unbundlepart(self.ui, headerblock, self._fp)
918 op = interruptoperation(self.ui)
918 op = interruptoperation(self.ui)
919 _processpart(op, part)
919 _processpart(op, part)
920 self.ui.debug('bundle2-input-stream-interrupt:'
920 self.ui.debug('bundle2-input-stream-interrupt:'
921 ' closing out of band context\n')
921 ' closing out of band context\n')
922
922
923 class interruptoperation(object):
923 class interruptoperation(object):
924 """A limited operation to be use by part handler during interruption
924 """A limited operation to be use by part handler during interruption
925
925
926 It only have access to an ui object.
926 It only have access to an ui object.
927 """
927 """
928
928
929 def __init__(self, ui):
929 def __init__(self, ui):
930 self.ui = ui
930 self.ui = ui
931 self.reply = None
931 self.reply = None
932 self.captureoutput = False
932 self.captureoutput = False
933
933
934 @property
934 @property
935 def repo(self):
935 def repo(self):
936 raise RuntimeError('no repo access from stream interruption')
936 raise RuntimeError('no repo access from stream interruption')
937
937
938 def gettransaction(self):
938 def gettransaction(self):
939 raise TransactionUnavailable('no repo access from stream interruption')
939 raise TransactionUnavailable('no repo access from stream interruption')
940
940
941 class unbundlepart(unpackermixin):
941 class unbundlepart(unpackermixin):
942 """a bundle part read from a bundle"""
942 """a bundle part read from a bundle"""
943
943
944 def __init__(self, ui, header, fp):
944 def __init__(self, ui, header, fp):
945 super(unbundlepart, self).__init__(fp)
945 super(unbundlepart, self).__init__(fp)
946 self.ui = ui
946 self.ui = ui
947 # unbundle state attr
947 # unbundle state attr
948 self._headerdata = header
948 self._headerdata = header
949 self._headeroffset = 0
949 self._headeroffset = 0
950 self._initialized = False
950 self._initialized = False
951 self.consumed = False
951 self.consumed = False
952 # part data
952 # part data
953 self.id = None
953 self.id = None
954 self.type = None
954 self.type = None
955 self.mandatoryparams = None
955 self.mandatoryparams = None
956 self.advisoryparams = None
956 self.advisoryparams = None
957 self.params = None
957 self.params = None
958 self.mandatorykeys = ()
958 self.mandatorykeys = ()
959 self._payloadstream = None
959 self._payloadstream = None
960 self._readheader()
960 self._readheader()
961 self._mandatory = None
961 self._mandatory = None
962 self._chunkindex = [] #(payload, file) position tuples for chunk starts
962 self._chunkindex = [] #(payload, file) position tuples for chunk starts
963 self._pos = 0
963 self._pos = 0
964
964
965 def _fromheader(self, size):
965 def _fromheader(self, size):
966 """return the next <size> byte from the header"""
966 """return the next <size> byte from the header"""
967 offset = self._headeroffset
967 offset = self._headeroffset
968 data = self._headerdata[offset:(offset + size)]
968 data = self._headerdata[offset:(offset + size)]
969 self._headeroffset = offset + size
969 self._headeroffset = offset + size
970 return data
970 return data
971
971
972 def _unpackheader(self, format):
972 def _unpackheader(self, format):
973 """read given format from header
973 """read given format from header
974
974
975 This automatically compute the size of the format to read."""
975 This automatically compute the size of the format to read."""
976 data = self._fromheader(struct.calcsize(format))
976 data = self._fromheader(struct.calcsize(format))
977 return _unpack(format, data)
977 return _unpack(format, data)
978
978
979 def _initparams(self, mandatoryparams, advisoryparams):
979 def _initparams(self, mandatoryparams, advisoryparams):
980 """internal function to setup all logic related parameters"""
980 """internal function to setup all logic related parameters"""
981 # make it read only to prevent people touching it by mistake.
981 # make it read only to prevent people touching it by mistake.
982 self.mandatoryparams = tuple(mandatoryparams)
982 self.mandatoryparams = tuple(mandatoryparams)
983 self.advisoryparams = tuple(advisoryparams)
983 self.advisoryparams = tuple(advisoryparams)
984 # user friendly UI
984 # user friendly UI
985 self.params = dict(self.mandatoryparams)
985 self.params = dict(self.mandatoryparams)
986 self.params.update(dict(self.advisoryparams))
986 self.params.update(dict(self.advisoryparams))
987 self.mandatorykeys = frozenset(p[0] for p in mandatoryparams)
987 self.mandatorykeys = frozenset(p[0] for p in mandatoryparams)
988
988
989 def _payloadchunks(self, chunknum=0):
989 def _payloadchunks(self, chunknum=0):
990 '''seek to specified chunk and start yielding data'''
990 '''seek to specified chunk and start yielding data'''
991 if len(self._chunkindex) == 0:
991 if len(self._chunkindex) == 0:
992 assert chunknum == 0, 'Must start with chunk 0'
992 assert chunknum == 0, 'Must start with chunk 0'
993 self._chunkindex.append((0, super(unbundlepart, self).tell()))
993 self._chunkindex.append((0, super(unbundlepart, self).tell()))
994 else:
994 else:
995 assert chunknum < len(self._chunkindex), \
995 assert chunknum < len(self._chunkindex), \
996 'Unknown chunk %d' % chunknum
996 'Unknown chunk %d' % chunknum
997 super(unbundlepart, self).seek(self._chunkindex[chunknum][1])
997 super(unbundlepart, self).seek(self._chunkindex[chunknum][1])
998
998
999 pos = self._chunkindex[chunknum][0]
999 pos = self._chunkindex[chunknum][0]
1000 payloadsize = self._unpack(_fpayloadsize)[0]
1000 payloadsize = self._unpack(_fpayloadsize)[0]
1001 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
1001 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
1002 while payloadsize:
1002 while payloadsize:
1003 if payloadsize == flaginterrupt:
1003 if payloadsize == flaginterrupt:
1004 # interruption detection, the handler will now read a
1004 # interruption detection, the handler will now read a
1005 # single part and process it.
1005 # single part and process it.
1006 interrupthandler(self.ui, self._fp)()
1006 interrupthandler(self.ui, self._fp)()
1007 elif payloadsize < 0:
1007 elif payloadsize < 0:
1008 msg = 'negative payload chunk size: %i' % payloadsize
1008 msg = 'negative payload chunk size: %i' % payloadsize
1009 raise error.BundleValueError(msg)
1009 raise error.BundleValueError(msg)
1010 else:
1010 else:
1011 result = self._readexact(payloadsize)
1011 result = self._readexact(payloadsize)
1012 chunknum += 1
1012 chunknum += 1
1013 pos += payloadsize
1013 pos += payloadsize
1014 if chunknum == len(self._chunkindex):
1014 if chunknum == len(self._chunkindex):
1015 self._chunkindex.append((pos,
1015 self._chunkindex.append((pos,
1016 super(unbundlepart, self).tell()))
1016 super(unbundlepart, self).tell()))
1017 yield result
1017 yield result
1018 payloadsize = self._unpack(_fpayloadsize)[0]
1018 payloadsize = self._unpack(_fpayloadsize)[0]
1019 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
1019 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
1020
1020
1021 def _findchunk(self, pos):
1021 def _findchunk(self, pos):
1022 '''for a given payload position, return a chunk number and offset'''
1022 '''for a given payload position, return a chunk number and offset'''
1023 for chunk, (ppos, fpos) in enumerate(self._chunkindex):
1023 for chunk, (ppos, fpos) in enumerate(self._chunkindex):
1024 if ppos == pos:
1024 if ppos == pos:
1025 return chunk, 0
1025 return chunk, 0
1026 elif ppos > pos:
1026 elif ppos > pos:
1027 return chunk - 1, pos - self._chunkindex[chunk - 1][0]
1027 return chunk - 1, pos - self._chunkindex[chunk - 1][0]
1028 raise ValueError('Unknown chunk')
1028 raise ValueError('Unknown chunk')
1029
1029
1030 def _readheader(self):
1030 def _readheader(self):
1031 """read the header and setup the object"""
1031 """read the header and setup the object"""
1032 typesize = self._unpackheader(_fparttypesize)[0]
1032 typesize = self._unpackheader(_fparttypesize)[0]
1033 self.type = self._fromheader(typesize)
1033 self.type = self._fromheader(typesize)
1034 indebug(self.ui, 'part type: "%s"' % self.type)
1034 indebug(self.ui, 'part type: "%s"' % self.type)
1035 self.id = self._unpackheader(_fpartid)[0]
1035 self.id = self._unpackheader(_fpartid)[0]
1036 indebug(self.ui, 'part id: "%s"' % self.id)
1036 indebug(self.ui, 'part id: "%s"' % self.id)
1037 # extract mandatory bit from type
1037 # extract mandatory bit from type
1038 self.mandatory = (self.type != self.type.lower())
1038 self.mandatory = (self.type != self.type.lower())
1039 self.type = self.type.lower()
1039 self.type = self.type.lower()
1040 ## reading parameters
1040 ## reading parameters
1041 # param count
1041 # param count
1042 mancount, advcount = self._unpackheader(_fpartparamcount)
1042 mancount, advcount = self._unpackheader(_fpartparamcount)
1043 indebug(self.ui, 'part parameters: %i' % (mancount + advcount))
1043 indebug(self.ui, 'part parameters: %i' % (mancount + advcount))
1044 # param size
1044 # param size
1045 fparamsizes = _makefpartparamsizes(mancount + advcount)
1045 fparamsizes = _makefpartparamsizes(mancount + advcount)
1046 paramsizes = self._unpackheader(fparamsizes)
1046 paramsizes = self._unpackheader(fparamsizes)
1047 # make it a list of couple again
1047 # make it a list of couple again
1048 paramsizes = zip(paramsizes[::2], paramsizes[1::2])
1048 paramsizes = zip(paramsizes[::2], paramsizes[1::2])
1049 # split mandatory from advisory
1049 # split mandatory from advisory
1050 mansizes = paramsizes[:mancount]
1050 mansizes = paramsizes[:mancount]
1051 advsizes = paramsizes[mancount:]
1051 advsizes = paramsizes[mancount:]
1052 # retrieve param value
1052 # retrieve param value
1053 manparams = []
1053 manparams = []
1054 for key, value in mansizes:
1054 for key, value in mansizes:
1055 manparams.append((self._fromheader(key), self._fromheader(value)))
1055 manparams.append((self._fromheader(key), self._fromheader(value)))
1056 advparams = []
1056 advparams = []
1057 for key, value in advsizes:
1057 for key, value in advsizes:
1058 advparams.append((self._fromheader(key), self._fromheader(value)))
1058 advparams.append((self._fromheader(key), self._fromheader(value)))
1059 self._initparams(manparams, advparams)
1059 self._initparams(manparams, advparams)
1060 ## part payload
1060 ## part payload
1061 self._payloadstream = util.chunkbuffer(self._payloadchunks())
1061 self._payloadstream = util.chunkbuffer(self._payloadchunks())
1062 # we read the data, tell it
1062 # we read the data, tell it
1063 self._initialized = True
1063 self._initialized = True
1064
1064
1065 def read(self, size=None):
1065 def read(self, size=None):
1066 """read payload data"""
1066 """read payload data"""
1067 if not self._initialized:
1067 if not self._initialized:
1068 self._readheader()
1068 self._readheader()
1069 if size is None:
1069 if size is None:
1070 data = self._payloadstream.read()
1070 data = self._payloadstream.read()
1071 else:
1071 else:
1072 data = self._payloadstream.read(size)
1072 data = self._payloadstream.read(size)
1073 self._pos += len(data)
1073 self._pos += len(data)
1074 if size is None or len(data) < size:
1074 if size is None or len(data) < size:
1075 if not self.consumed and self._pos:
1075 if not self.consumed and self._pos:
1076 self.ui.debug('bundle2-input-part: total payload size %i\n'
1076 self.ui.debug('bundle2-input-part: total payload size %i\n'
1077 % self._pos)
1077 % self._pos)
1078 self.consumed = True
1078 self.consumed = True
1079 return data
1079 return data
1080
1080
1081 def tell(self):
1081 def tell(self):
1082 return self._pos
1082 return self._pos
1083
1083
1084 def seek(self, offset, whence=0):
1084 def seek(self, offset, whence=0):
1085 if whence == 0:
1085 if whence == 0:
1086 newpos = offset
1086 newpos = offset
1087 elif whence == 1:
1087 elif whence == 1:
1088 newpos = self._pos + offset
1088 newpos = self._pos + offset
1089 elif whence == 2:
1089 elif whence == 2:
1090 if not self.consumed:
1090 if not self.consumed:
1091 self.read()
1091 self.read()
1092 newpos = self._chunkindex[-1][0] - offset
1092 newpos = self._chunkindex[-1][0] - offset
1093 else:
1093 else:
1094 raise ValueError('Unknown whence value: %r' % (whence,))
1094 raise ValueError('Unknown whence value: %r' % (whence,))
1095
1095
1096 if newpos > self._chunkindex[-1][0] and not self.consumed:
1096 if newpos > self._chunkindex[-1][0] and not self.consumed:
1097 self.read()
1097 self.read()
1098 if not 0 <= newpos <= self._chunkindex[-1][0]:
1098 if not 0 <= newpos <= self._chunkindex[-1][0]:
1099 raise ValueError('Offset out of range')
1099 raise ValueError('Offset out of range')
1100
1100
1101 if self._pos != newpos:
1101 if self._pos != newpos:
1102 chunk, internaloffset = self._findchunk(newpos)
1102 chunk, internaloffset = self._findchunk(newpos)
1103 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
1103 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
1104 adjust = self.read(internaloffset)
1104 adjust = self.read(internaloffset)
1105 if len(adjust) != internaloffset:
1105 if len(adjust) != internaloffset:
1106 raise util.Abort(_('Seek failed\n'))
1106 raise util.Abort(_('Seek failed\n'))
1107 self._pos = newpos
1107 self._pos = newpos
1108
1108
1109 # These are only the static capabilities.
1109 # These are only the static capabilities.
1110 # Check the 'getrepocaps' function for the rest.
1110 # Check the 'getrepocaps' function for the rest.
1111 capabilities = {'HG20': (),
1111 capabilities = {'HG20': (),
1112 'error': ('abort', 'unsupportedcontent', 'pushraced'),
1112 'error': ('abort', 'unsupportedcontent', 'pushraced',
1113 'pushkey'),
1113 'listkeys': (),
1114 'listkeys': (),
1114 'pushkey': (),
1115 'pushkey': (),
1115 'digests': tuple(sorted(util.DIGESTS.keys())),
1116 'digests': tuple(sorted(util.DIGESTS.keys())),
1116 'remote-changegroup': ('http', 'https'),
1117 'remote-changegroup': ('http', 'https'),
1117 'hgtagsfnodes': (),
1118 'hgtagsfnodes': (),
1118 }
1119 }
1119
1120
1120 def getrepocaps(repo, allowpushback=False):
1121 def getrepocaps(repo, allowpushback=False):
1121 """return the bundle2 capabilities for a given repo
1122 """return the bundle2 capabilities for a given repo
1122
1123
1123 Exists to allow extensions (like evolution) to mutate the capabilities.
1124 Exists to allow extensions (like evolution) to mutate the capabilities.
1124 """
1125 """
1125 caps = capabilities.copy()
1126 caps = capabilities.copy()
1126 caps['changegroup'] = tuple(sorted(changegroup.packermap.keys()))
1127 caps['changegroup'] = tuple(sorted(changegroup.packermap.keys()))
1127 if obsolete.isenabled(repo, obsolete.exchangeopt):
1128 if obsolete.isenabled(repo, obsolete.exchangeopt):
1128 supportedformat = tuple('V%i' % v for v in obsolete.formats)
1129 supportedformat = tuple('V%i' % v for v in obsolete.formats)
1129 caps['obsmarkers'] = supportedformat
1130 caps['obsmarkers'] = supportedformat
1130 if allowpushback:
1131 if allowpushback:
1131 caps['pushback'] = ()
1132 caps['pushback'] = ()
1132 return caps
1133 return caps
1133
1134
1134 def bundle2caps(remote):
1135 def bundle2caps(remote):
1135 """return the bundle capabilities of a peer as dict"""
1136 """return the bundle capabilities of a peer as dict"""
1136 raw = remote.capable('bundle2')
1137 raw = remote.capable('bundle2')
1137 if not raw and raw != '':
1138 if not raw and raw != '':
1138 return {}
1139 return {}
1139 capsblob = urllib.unquote(remote.capable('bundle2'))
1140 capsblob = urllib.unquote(remote.capable('bundle2'))
1140 return decodecaps(capsblob)
1141 return decodecaps(capsblob)
1141
1142
1142 def obsmarkersversion(caps):
1143 def obsmarkersversion(caps):
1143 """extract the list of supported obsmarkers versions from a bundle2caps dict
1144 """extract the list of supported obsmarkers versions from a bundle2caps dict
1144 """
1145 """
1145 obscaps = caps.get('obsmarkers', ())
1146 obscaps = caps.get('obsmarkers', ())
1146 return [int(c[1:]) for c in obscaps if c.startswith('V')]
1147 return [int(c[1:]) for c in obscaps if c.startswith('V')]
1147
1148
1148 @parthandler('changegroup', ('version',))
1149 @parthandler('changegroup', ('version',))
1149 def handlechangegroup(op, inpart):
1150 def handlechangegroup(op, inpart):
1150 """apply a changegroup part on the repo
1151 """apply a changegroup part on the repo
1151
1152
1152 This is a very early implementation that will massive rework before being
1153 This is a very early implementation that will massive rework before being
1153 inflicted to any end-user.
1154 inflicted to any end-user.
1154 """
1155 """
1155 # Make sure we trigger a transaction creation
1156 # Make sure we trigger a transaction creation
1156 #
1157 #
1157 # The addchangegroup function will get a transaction object by itself, but
1158 # The addchangegroup function will get a transaction object by itself, but
1158 # we need to make sure we trigger the creation of a transaction object used
1159 # we need to make sure we trigger the creation of a transaction object used
1159 # for the whole processing scope.
1160 # for the whole processing scope.
1160 op.gettransaction()
1161 op.gettransaction()
1161 unpackerversion = inpart.params.get('version', '01')
1162 unpackerversion = inpart.params.get('version', '01')
1162 # We should raise an appropriate exception here
1163 # We should raise an appropriate exception here
1163 unpacker = changegroup.packermap[unpackerversion][1]
1164 unpacker = changegroup.packermap[unpackerversion][1]
1164 cg = unpacker(inpart, 'UN')
1165 cg = unpacker(inpart, 'UN')
1165 # the source and url passed here are overwritten by the one contained in
1166 # the source and url passed here are overwritten by the one contained in
1166 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1167 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1167 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1168 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1168 op.records.add('changegroup', {'return': ret})
1169 op.records.add('changegroup', {'return': ret})
1169 if op.reply is not None:
1170 if op.reply is not None:
1170 # This is definitely not the final form of this
1171 # This is definitely not the final form of this
1171 # return. But one need to start somewhere.
1172 # return. But one need to start somewhere.
1172 part = op.reply.newpart('reply:changegroup', mandatory=False)
1173 part = op.reply.newpart('reply:changegroup', mandatory=False)
1173 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1174 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1174 part.addparam('return', '%i' % ret, mandatory=False)
1175 part.addparam('return', '%i' % ret, mandatory=False)
1175 assert not inpart.read()
1176 assert not inpart.read()
1176
1177
1177 _remotechangegroupparams = tuple(['url', 'size', 'digests'] +
1178 _remotechangegroupparams = tuple(['url', 'size', 'digests'] +
1178 ['digest:%s' % k for k in util.DIGESTS.keys()])
1179 ['digest:%s' % k for k in util.DIGESTS.keys()])
1179 @parthandler('remote-changegroup', _remotechangegroupparams)
1180 @parthandler('remote-changegroup', _remotechangegroupparams)
1180 def handleremotechangegroup(op, inpart):
1181 def handleremotechangegroup(op, inpart):
1181 """apply a bundle10 on the repo, given an url and validation information
1182 """apply a bundle10 on the repo, given an url and validation information
1182
1183
1183 All the information about the remote bundle to import are given as
1184 All the information about the remote bundle to import are given as
1184 parameters. The parameters include:
1185 parameters. The parameters include:
1185 - url: the url to the bundle10.
1186 - url: the url to the bundle10.
1186 - size: the bundle10 file size. It is used to validate what was
1187 - size: the bundle10 file size. It is used to validate what was
1187 retrieved by the client matches the server knowledge about the bundle.
1188 retrieved by the client matches the server knowledge about the bundle.
1188 - digests: a space separated list of the digest types provided as
1189 - digests: a space separated list of the digest types provided as
1189 parameters.
1190 parameters.
1190 - digest:<digest-type>: the hexadecimal representation of the digest with
1191 - digest:<digest-type>: the hexadecimal representation of the digest with
1191 that name. Like the size, it is used to validate what was retrieved by
1192 that name. Like the size, it is used to validate what was retrieved by
1192 the client matches what the server knows about the bundle.
1193 the client matches what the server knows about the bundle.
1193
1194
1194 When multiple digest types are given, all of them are checked.
1195 When multiple digest types are given, all of them are checked.
1195 """
1196 """
1196 try:
1197 try:
1197 raw_url = inpart.params['url']
1198 raw_url = inpart.params['url']
1198 except KeyError:
1199 except KeyError:
1199 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
1200 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
1200 parsed_url = util.url(raw_url)
1201 parsed_url = util.url(raw_url)
1201 if parsed_url.scheme not in capabilities['remote-changegroup']:
1202 if parsed_url.scheme not in capabilities['remote-changegroup']:
1202 raise util.Abort(_('remote-changegroup does not support %s urls') %
1203 raise util.Abort(_('remote-changegroup does not support %s urls') %
1203 parsed_url.scheme)
1204 parsed_url.scheme)
1204
1205
1205 try:
1206 try:
1206 size = int(inpart.params['size'])
1207 size = int(inpart.params['size'])
1207 except ValueError:
1208 except ValueError:
1208 raise util.Abort(_('remote-changegroup: invalid value for param "%s"')
1209 raise util.Abort(_('remote-changegroup: invalid value for param "%s"')
1209 % 'size')
1210 % 'size')
1210 except KeyError:
1211 except KeyError:
1211 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')
1212 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')
1212
1213
1213 digests = {}
1214 digests = {}
1214 for typ in inpart.params.get('digests', '').split():
1215 for typ in inpart.params.get('digests', '').split():
1215 param = 'digest:%s' % typ
1216 param = 'digest:%s' % typ
1216 try:
1217 try:
1217 value = inpart.params[param]
1218 value = inpart.params[param]
1218 except KeyError:
1219 except KeyError:
1219 raise util.Abort(_('remote-changegroup: missing "%s" param') %
1220 raise util.Abort(_('remote-changegroup: missing "%s" param') %
1220 param)
1221 param)
1221 digests[typ] = value
1222 digests[typ] = value
1222
1223
1223 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
1224 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
1224
1225
1225 # Make sure we trigger a transaction creation
1226 # Make sure we trigger a transaction creation
1226 #
1227 #
1227 # The addchangegroup function will get a transaction object by itself, but
1228 # The addchangegroup function will get a transaction object by itself, but
1228 # we need to make sure we trigger the creation of a transaction object used
1229 # we need to make sure we trigger the creation of a transaction object used
1229 # for the whole processing scope.
1230 # for the whole processing scope.
1230 op.gettransaction()
1231 op.gettransaction()
1231 import exchange
1232 import exchange
1232 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
1233 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
1233 if not isinstance(cg, changegroup.cg1unpacker):
1234 if not isinstance(cg, changegroup.cg1unpacker):
1234 raise util.Abort(_('%s: not a bundle version 1.0') %
1235 raise util.Abort(_('%s: not a bundle version 1.0') %
1235 util.hidepassword(raw_url))
1236 util.hidepassword(raw_url))
1236 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1237 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1237 op.records.add('changegroup', {'return': ret})
1238 op.records.add('changegroup', {'return': ret})
1238 if op.reply is not None:
1239 if op.reply is not None:
1239 # This is definitely not the final form of this
1240 # This is definitely not the final form of this
1240 # return. But one need to start somewhere.
1241 # return. But one need to start somewhere.
1241 part = op.reply.newpart('reply:changegroup')
1242 part = op.reply.newpart('reply:changegroup')
1242 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1243 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1243 part.addparam('return', '%i' % ret, mandatory=False)
1244 part.addparam('return', '%i' % ret, mandatory=False)
1244 try:
1245 try:
1245 real_part.validate()
1246 real_part.validate()
1246 except util.Abort, e:
1247 except util.Abort, e:
1247 raise util.Abort(_('bundle at %s is corrupted:\n%s') %
1248 raise util.Abort(_('bundle at %s is corrupted:\n%s') %
1248 (util.hidepassword(raw_url), str(e)))
1249 (util.hidepassword(raw_url), str(e)))
1249 assert not inpart.read()
1250 assert not inpart.read()
1250
1251
1251 @parthandler('reply:changegroup', ('return', 'in-reply-to'))
1252 @parthandler('reply:changegroup', ('return', 'in-reply-to'))
1252 def handlereplychangegroup(op, inpart):
1253 def handlereplychangegroup(op, inpart):
1253 ret = int(inpart.params['return'])
1254 ret = int(inpart.params['return'])
1254 replyto = int(inpart.params['in-reply-to'])
1255 replyto = int(inpart.params['in-reply-to'])
1255 op.records.add('changegroup', {'return': ret}, replyto)
1256 op.records.add('changegroup', {'return': ret}, replyto)
1256
1257
1257 @parthandler('check:heads')
1258 @parthandler('check:heads')
1258 def handlecheckheads(op, inpart):
1259 def handlecheckheads(op, inpart):
1259 """check that head of the repo did not change
1260 """check that head of the repo did not change
1260
1261
1261 This is used to detect a push race when using unbundle.
1262 This is used to detect a push race when using unbundle.
1262 This replaces the "heads" argument of unbundle."""
1263 This replaces the "heads" argument of unbundle."""
1263 h = inpart.read(20)
1264 h = inpart.read(20)
1264 heads = []
1265 heads = []
1265 while len(h) == 20:
1266 while len(h) == 20:
1266 heads.append(h)
1267 heads.append(h)
1267 h = inpart.read(20)
1268 h = inpart.read(20)
1268 assert not h
1269 assert not h
1269 if heads != op.repo.heads():
1270 if heads != op.repo.heads():
1270 raise error.PushRaced('repository changed while pushing - '
1271 raise error.PushRaced('repository changed while pushing - '
1271 'please try again')
1272 'please try again')
1272
1273
1273 @parthandler('output')
1274 @parthandler('output')
1274 def handleoutput(op, inpart):
1275 def handleoutput(op, inpart):
1275 """forward output captured on the server to the client"""
1276 """forward output captured on the server to the client"""
1276 for line in inpart.read().splitlines():
1277 for line in inpart.read().splitlines():
1277 op.ui.status(('remote: %s\n' % line))
1278 op.ui.status(('remote: %s\n' % line))
1278
1279
1279 @parthandler('replycaps')
1280 @parthandler('replycaps')
1280 def handlereplycaps(op, inpart):
1281 def handlereplycaps(op, inpart):
1281 """Notify that a reply bundle should be created
1282 """Notify that a reply bundle should be created
1282
1283
1283 The payload contains the capabilities information for the reply"""
1284 The payload contains the capabilities information for the reply"""
1284 caps = decodecaps(inpart.read())
1285 caps = decodecaps(inpart.read())
1285 if op.reply is None:
1286 if op.reply is None:
1286 op.reply = bundle20(op.ui, caps)
1287 op.reply = bundle20(op.ui, caps)
1287
1288
1288 @parthandler('error:abort', ('message', 'hint'))
1289 @parthandler('error:abort', ('message', 'hint'))
1289 def handleerrorabort(op, inpart):
1290 def handleerrorabort(op, inpart):
1290 """Used to transmit abort error over the wire"""
1291 """Used to transmit abort error over the wire"""
1291 raise util.Abort(inpart.params['message'], hint=inpart.params.get('hint'))
1292 raise util.Abort(inpart.params['message'], hint=inpart.params.get('hint'))
1292
1293
1294 @parthandler('error:pushkey', ('namespace', 'key', 'new', 'old', 'ret',
1295 'in-reply-to'))
1296 def handleerrorpushkey(op, inpart):
1297 """Used to transmit failure of a mandatory pushkey over the wire"""
1298 kwargs = {}
1299 for name in ('namespace', 'key', 'new', 'old', 'ret'):
1300 value = inpart.params.get(name)
1301 if value is not None:
1302 kwargs[name] = value
1303 raise error.PushkeyFailed(inpart.params['in-reply-to'], **kwargs)
1304
1293 @parthandler('error:unsupportedcontent', ('parttype', 'params'))
1305 @parthandler('error:unsupportedcontent', ('parttype', 'params'))
1294 def handleerrorunsupportedcontent(op, inpart):
1306 def handleerrorunsupportedcontent(op, inpart):
1295 """Used to transmit unknown content error over the wire"""
1307 """Used to transmit unknown content error over the wire"""
1296 kwargs = {}
1308 kwargs = {}
1297 parttype = inpart.params.get('parttype')
1309 parttype = inpart.params.get('parttype')
1298 if parttype is not None:
1310 if parttype is not None:
1299 kwargs['parttype'] = parttype
1311 kwargs['parttype'] = parttype
1300 params = inpart.params.get('params')
1312 params = inpart.params.get('params')
1301 if params is not None:
1313 if params is not None:
1302 kwargs['params'] = params.split('\0')
1314 kwargs['params'] = params.split('\0')
1303
1315
1304 raise error.UnsupportedPartError(**kwargs)
1316 raise error.UnsupportedPartError(**kwargs)
1305
1317
1306 @parthandler('error:pushraced', ('message',))
1318 @parthandler('error:pushraced', ('message',))
1307 def handleerrorpushraced(op, inpart):
1319 def handleerrorpushraced(op, inpart):
1308 """Used to transmit push race error over the wire"""
1320 """Used to transmit push race error over the wire"""
1309 raise error.ResponseError(_('push failed:'), inpart.params['message'])
1321 raise error.ResponseError(_('push failed:'), inpart.params['message'])
1310
1322
1311 @parthandler('listkeys', ('namespace',))
1323 @parthandler('listkeys', ('namespace',))
1312 def handlelistkeys(op, inpart):
1324 def handlelistkeys(op, inpart):
1313 """retrieve pushkey namespace content stored in a bundle2"""
1325 """retrieve pushkey namespace content stored in a bundle2"""
1314 namespace = inpart.params['namespace']
1326 namespace = inpart.params['namespace']
1315 r = pushkey.decodekeys(inpart.read())
1327 r = pushkey.decodekeys(inpart.read())
1316 op.records.add('listkeys', (namespace, r))
1328 op.records.add('listkeys', (namespace, r))
1317
1329
1318 @parthandler('pushkey', ('namespace', 'key', 'old', 'new'))
1330 @parthandler('pushkey', ('namespace', 'key', 'old', 'new'))
1319 def handlepushkey(op, inpart):
1331 def handlepushkey(op, inpart):
1320 """process a pushkey request"""
1332 """process a pushkey request"""
1321 dec = pushkey.decode
1333 dec = pushkey.decode
1322 namespace = dec(inpart.params['namespace'])
1334 namespace = dec(inpart.params['namespace'])
1323 key = dec(inpart.params['key'])
1335 key = dec(inpart.params['key'])
1324 old = dec(inpart.params['old'])
1336 old = dec(inpart.params['old'])
1325 new = dec(inpart.params['new'])
1337 new = dec(inpart.params['new'])
1326 ret = op.repo.pushkey(namespace, key, old, new)
1338 ret = op.repo.pushkey(namespace, key, old, new)
1327 record = {'namespace': namespace,
1339 record = {'namespace': namespace,
1328 'key': key,
1340 'key': key,
1329 'old': old,
1341 'old': old,
1330 'new': new}
1342 'new': new}
1331 op.records.add('pushkey', record)
1343 op.records.add('pushkey', record)
1332 if op.reply is not None:
1344 if op.reply is not None:
1333 rpart = op.reply.newpart('reply:pushkey')
1345 rpart = op.reply.newpart('reply:pushkey')
1334 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1346 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1335 rpart.addparam('return', '%i' % ret, mandatory=False)
1347 rpart.addparam('return', '%i' % ret, mandatory=False)
1336 if inpart.mandatory and not ret:
1348 if inpart.mandatory and not ret:
1337 kwargs = {}
1349 kwargs = {}
1338 for key in ('namespace', 'key', 'new', 'old', 'ret'):
1350 for key in ('namespace', 'key', 'new', 'old', 'ret'):
1339 if key in inpart.params:
1351 if key in inpart.params:
1340 kwargs[key] = inpart.params[key]
1352 kwargs[key] = inpart.params[key]
1341 raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
1353 raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
1342
1354
1343 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1355 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1344 def handlepushkeyreply(op, inpart):
1356 def handlepushkeyreply(op, inpart):
1345 """retrieve the result of a pushkey request"""
1357 """retrieve the result of a pushkey request"""
1346 ret = int(inpart.params['return'])
1358 ret = int(inpart.params['return'])
1347 partid = int(inpart.params['in-reply-to'])
1359 partid = int(inpart.params['in-reply-to'])
1348 op.records.add('pushkey', {'return': ret}, partid)
1360 op.records.add('pushkey', {'return': ret}, partid)
1349
1361
1350 @parthandler('obsmarkers')
1362 @parthandler('obsmarkers')
1351 def handleobsmarker(op, inpart):
1363 def handleobsmarker(op, inpart):
1352 """add a stream of obsmarkers to the repo"""
1364 """add a stream of obsmarkers to the repo"""
1353 tr = op.gettransaction()
1365 tr = op.gettransaction()
1354 markerdata = inpart.read()
1366 markerdata = inpart.read()
1355 if op.ui.config('experimental', 'obsmarkers-exchange-debug', False):
1367 if op.ui.config('experimental', 'obsmarkers-exchange-debug', False):
1356 op.ui.write(('obsmarker-exchange: %i bytes received\n')
1368 op.ui.write(('obsmarker-exchange: %i bytes received\n')
1357 % len(markerdata))
1369 % len(markerdata))
1358 new = op.repo.obsstore.mergemarkers(tr, markerdata)
1370 new = op.repo.obsstore.mergemarkers(tr, markerdata)
1359 if new:
1371 if new:
1360 op.repo.ui.status(_('%i new obsolescence markers\n') % new)
1372 op.repo.ui.status(_('%i new obsolescence markers\n') % new)
1361 op.records.add('obsmarkers', {'new': new})
1373 op.records.add('obsmarkers', {'new': new})
1362 if op.reply is not None:
1374 if op.reply is not None:
1363 rpart = op.reply.newpart('reply:obsmarkers')
1375 rpart = op.reply.newpart('reply:obsmarkers')
1364 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1376 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1365 rpart.addparam('new', '%i' % new, mandatory=False)
1377 rpart.addparam('new', '%i' % new, mandatory=False)
1366
1378
1367
1379
1368 @parthandler('reply:obsmarkers', ('new', 'in-reply-to'))
1380 @parthandler('reply:obsmarkers', ('new', 'in-reply-to'))
1369 def handlepushkeyreply(op, inpart):
1381 def handlepushkeyreply(op, inpart):
1370 """retrieve the result of a pushkey request"""
1382 """retrieve the result of a pushkey request"""
1371 ret = int(inpart.params['new'])
1383 ret = int(inpart.params['new'])
1372 partid = int(inpart.params['in-reply-to'])
1384 partid = int(inpart.params['in-reply-to'])
1373 op.records.add('obsmarkers', {'new': ret}, partid)
1385 op.records.add('obsmarkers', {'new': ret}, partid)
1374
1386
1375 @parthandler('hgtagsfnodes')
1387 @parthandler('hgtagsfnodes')
1376 def handlehgtagsfnodes(op, inpart):
1388 def handlehgtagsfnodes(op, inpart):
1377 """Applies .hgtags fnodes cache entries to the local repo.
1389 """Applies .hgtags fnodes cache entries to the local repo.
1378
1390
1379 Payload is pairs of 20 byte changeset nodes and filenodes.
1391 Payload is pairs of 20 byte changeset nodes and filenodes.
1380 """
1392 """
1381 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
1393 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
1382
1394
1383 count = 0
1395 count = 0
1384 while True:
1396 while True:
1385 node = inpart.read(20)
1397 node = inpart.read(20)
1386 fnode = inpart.read(20)
1398 fnode = inpart.read(20)
1387 if len(node) < 20 or len(fnode) < 20:
1399 if len(node) < 20 or len(fnode) < 20:
1388 op.ui.debug('received incomplete .hgtags fnodes data, ignoring\n')
1400 op.ui.debug('received incomplete .hgtags fnodes data, ignoring\n')
1389 break
1401 break
1390 cache.setfnode(node, fnode)
1402 cache.setfnode(node, fnode)
1391 count += 1
1403 count += 1
1392
1404
1393 cache.write()
1405 cache.write()
1394 op.ui.debug('applied %i hgtags fnodes cache entries\n' % count)
1406 op.ui.debug('applied %i hgtags fnodes cache entries\n' % count)
@@ -1,838 +1,858 b''
1 # wireproto.py - generic wire protocol support functions
1 # wireproto.py - generic wire protocol support functions
2 #
2 #
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 import urllib, tempfile, os, sys
8 import urllib, tempfile, os, sys
9 from i18n import _
9 from i18n import _
10 from node import bin, hex
10 from node import bin, hex
11 import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
11 import changegroup as changegroupmod, bundle2, pushkey as pushkeymod
12 import peer, error, encoding, util, exchange
12 import peer, error, encoding, util, exchange
13
13
14
14
15 class abstractserverproto(object):
15 class abstractserverproto(object):
16 """abstract class that summarizes the protocol API
16 """abstract class that summarizes the protocol API
17
17
18 Used as reference and documentation.
18 Used as reference and documentation.
19 """
19 """
20
20
21 def getargs(self, args):
21 def getargs(self, args):
22 """return the value for arguments in <args>
22 """return the value for arguments in <args>
23
23
24 returns a list of values (same order as <args>)"""
24 returns a list of values (same order as <args>)"""
25 raise NotImplementedError()
25 raise NotImplementedError()
26
26
27 def getfile(self, fp):
27 def getfile(self, fp):
28 """write the whole content of a file into a file like object
28 """write the whole content of a file into a file like object
29
29
30 The file is in the form::
30 The file is in the form::
31
31
32 (<chunk-size>\n<chunk>)+0\n
32 (<chunk-size>\n<chunk>)+0\n
33
33
34 chunk size is the ascii version of the int.
34 chunk size is the ascii version of the int.
35 """
35 """
36 raise NotImplementedError()
36 raise NotImplementedError()
37
37
38 def redirect(self):
38 def redirect(self):
39 """may setup interception for stdout and stderr
39 """may setup interception for stdout and stderr
40
40
41 See also the `restore` method."""
41 See also the `restore` method."""
42 raise NotImplementedError()
42 raise NotImplementedError()
43
43
44 # If the `redirect` function does install interception, the `restore`
44 # If the `redirect` function does install interception, the `restore`
45 # function MUST be defined. If interception is not used, this function
45 # function MUST be defined. If interception is not used, this function
46 # MUST NOT be defined.
46 # MUST NOT be defined.
47 #
47 #
48 # left commented here on purpose
48 # left commented here on purpose
49 #
49 #
50 #def restore(self):
50 #def restore(self):
51 # """reinstall previous stdout and stderr and return intercepted stdout
51 # """reinstall previous stdout and stderr and return intercepted stdout
52 # """
52 # """
53 # raise NotImplementedError()
53 # raise NotImplementedError()
54
54
55 def groupchunks(self, cg):
55 def groupchunks(self, cg):
56 """return 4096 chunks from a changegroup object
56 """return 4096 chunks from a changegroup object
57
57
58 Some protocols may have compressed the contents."""
58 Some protocols may have compressed the contents."""
59 raise NotImplementedError()
59 raise NotImplementedError()
60
60
61 # abstract batching support
61 # abstract batching support
62
62
63 class future(object):
63 class future(object):
64 '''placeholder for a value to be set later'''
64 '''placeholder for a value to be set later'''
65 def set(self, value):
65 def set(self, value):
66 if util.safehasattr(self, 'value'):
66 if util.safehasattr(self, 'value'):
67 raise error.RepoError("future is already set")
67 raise error.RepoError("future is already set")
68 self.value = value
68 self.value = value
69
69
70 class batcher(object):
70 class batcher(object):
71 '''base class for batches of commands submittable in a single request
71 '''base class for batches of commands submittable in a single request
72
72
73 All methods invoked on instances of this class are simply queued and
73 All methods invoked on instances of this class are simply queued and
74 return a a future for the result. Once you call submit(), all the queued
74 return a a future for the result. Once you call submit(), all the queued
75 calls are performed and the results set in their respective futures.
75 calls are performed and the results set in their respective futures.
76 '''
76 '''
77 def __init__(self):
77 def __init__(self):
78 self.calls = []
78 self.calls = []
79 def __getattr__(self, name):
79 def __getattr__(self, name):
80 def call(*args, **opts):
80 def call(*args, **opts):
81 resref = future()
81 resref = future()
82 self.calls.append((name, args, opts, resref,))
82 self.calls.append((name, args, opts, resref,))
83 return resref
83 return resref
84 return call
84 return call
85 def submit(self):
85 def submit(self):
86 pass
86 pass
87
87
88 class localbatch(batcher):
88 class localbatch(batcher):
89 '''performs the queued calls directly'''
89 '''performs the queued calls directly'''
90 def __init__(self, local):
90 def __init__(self, local):
91 batcher.__init__(self)
91 batcher.__init__(self)
92 self.local = local
92 self.local = local
93 def submit(self):
93 def submit(self):
94 for name, args, opts, resref in self.calls:
94 for name, args, opts, resref in self.calls:
95 resref.set(getattr(self.local, name)(*args, **opts))
95 resref.set(getattr(self.local, name)(*args, **opts))
96
96
97 class remotebatch(batcher):
97 class remotebatch(batcher):
98 '''batches the queued calls; uses as few roundtrips as possible'''
98 '''batches the queued calls; uses as few roundtrips as possible'''
99 def __init__(self, remote):
99 def __init__(self, remote):
100 '''remote must support _submitbatch(encbatch) and
100 '''remote must support _submitbatch(encbatch) and
101 _submitone(op, encargs)'''
101 _submitone(op, encargs)'''
102 batcher.__init__(self)
102 batcher.__init__(self)
103 self.remote = remote
103 self.remote = remote
104 def submit(self):
104 def submit(self):
105 req, rsp = [], []
105 req, rsp = [], []
106 for name, args, opts, resref in self.calls:
106 for name, args, opts, resref in self.calls:
107 mtd = getattr(self.remote, name)
107 mtd = getattr(self.remote, name)
108 batchablefn = getattr(mtd, 'batchable', None)
108 batchablefn = getattr(mtd, 'batchable', None)
109 if batchablefn is not None:
109 if batchablefn is not None:
110 batchable = batchablefn(mtd.im_self, *args, **opts)
110 batchable = batchablefn(mtd.im_self, *args, **opts)
111 encargsorres, encresref = batchable.next()
111 encargsorres, encresref = batchable.next()
112 if encresref:
112 if encresref:
113 req.append((name, encargsorres,))
113 req.append((name, encargsorres,))
114 rsp.append((batchable, encresref, resref,))
114 rsp.append((batchable, encresref, resref,))
115 else:
115 else:
116 resref.set(encargsorres)
116 resref.set(encargsorres)
117 else:
117 else:
118 if req:
118 if req:
119 self._submitreq(req, rsp)
119 self._submitreq(req, rsp)
120 req, rsp = [], []
120 req, rsp = [], []
121 resref.set(mtd(*args, **opts))
121 resref.set(mtd(*args, **opts))
122 if req:
122 if req:
123 self._submitreq(req, rsp)
123 self._submitreq(req, rsp)
124 def _submitreq(self, req, rsp):
124 def _submitreq(self, req, rsp):
125 encresults = self.remote._submitbatch(req)
125 encresults = self.remote._submitbatch(req)
126 for encres, r in zip(encresults, rsp):
126 for encres, r in zip(encresults, rsp):
127 batchable, encresref, resref = r
127 batchable, encresref, resref = r
128 encresref.set(encres)
128 encresref.set(encres)
129 resref.set(batchable.next())
129 resref.set(batchable.next())
130
130
131 def batchable(f):
131 def batchable(f):
132 '''annotation for batchable methods
132 '''annotation for batchable methods
133
133
134 Such methods must implement a coroutine as follows:
134 Such methods must implement a coroutine as follows:
135
135
136 @batchable
136 @batchable
137 def sample(self, one, two=None):
137 def sample(self, one, two=None):
138 # Handle locally computable results first:
138 # Handle locally computable results first:
139 if not one:
139 if not one:
140 yield "a local result", None
140 yield "a local result", None
141 # Build list of encoded arguments suitable for your wire protocol:
141 # Build list of encoded arguments suitable for your wire protocol:
142 encargs = [('one', encode(one),), ('two', encode(two),)]
142 encargs = [('one', encode(one),), ('two', encode(two),)]
143 # Create future for injection of encoded result:
143 # Create future for injection of encoded result:
144 encresref = future()
144 encresref = future()
145 # Return encoded arguments and future:
145 # Return encoded arguments and future:
146 yield encargs, encresref
146 yield encargs, encresref
147 # Assuming the future to be filled with the result from the batched
147 # Assuming the future to be filled with the result from the batched
148 # request now. Decode it:
148 # request now. Decode it:
149 yield decode(encresref.value)
149 yield decode(encresref.value)
150
150
151 The decorator returns a function which wraps this coroutine as a plain
151 The decorator returns a function which wraps this coroutine as a plain
152 method, but adds the original method as an attribute called "batchable",
152 method, but adds the original method as an attribute called "batchable",
153 which is used by remotebatch to split the call into separate encoding and
153 which is used by remotebatch to split the call into separate encoding and
154 decoding phases.
154 decoding phases.
155 '''
155 '''
156 def plain(*args, **opts):
156 def plain(*args, **opts):
157 batchable = f(*args, **opts)
157 batchable = f(*args, **opts)
158 encargsorres, encresref = batchable.next()
158 encargsorres, encresref = batchable.next()
159 if not encresref:
159 if not encresref:
160 return encargsorres # a local result in this case
160 return encargsorres # a local result in this case
161 self = args[0]
161 self = args[0]
162 encresref.set(self._submitone(f.func_name, encargsorres))
162 encresref.set(self._submitone(f.func_name, encargsorres))
163 return batchable.next()
163 return batchable.next()
164 setattr(plain, 'batchable', f)
164 setattr(plain, 'batchable', f)
165 return plain
165 return plain
166
166
167 # list of nodes encoding / decoding
167 # list of nodes encoding / decoding
168
168
169 def decodelist(l, sep=' '):
169 def decodelist(l, sep=' '):
170 if l:
170 if l:
171 return map(bin, l.split(sep))
171 return map(bin, l.split(sep))
172 return []
172 return []
173
173
174 def encodelist(l, sep=' '):
174 def encodelist(l, sep=' '):
175 try:
175 try:
176 return sep.join(map(hex, l))
176 return sep.join(map(hex, l))
177 except TypeError:
177 except TypeError:
178 print l
178 print l
179 raise
179 raise
180
180
181 # batched call argument encoding
181 # batched call argument encoding
182
182
183 def escapearg(plain):
183 def escapearg(plain):
184 return (plain
184 return (plain
185 .replace(':', '::')
185 .replace(':', '::')
186 .replace(',', ':,')
186 .replace(',', ':,')
187 .replace(';', ':;')
187 .replace(';', ':;')
188 .replace('=', ':='))
188 .replace('=', ':='))
189
189
190 def unescapearg(escaped):
190 def unescapearg(escaped):
191 return (escaped
191 return (escaped
192 .replace(':=', '=')
192 .replace(':=', '=')
193 .replace(':;', ';')
193 .replace(':;', ';')
194 .replace(':,', ',')
194 .replace(':,', ',')
195 .replace('::', ':'))
195 .replace('::', ':'))
196
196
197 # mapping of options accepted by getbundle and their types
197 # mapping of options accepted by getbundle and their types
198 #
198 #
199 # Meant to be extended by extensions. It is extensions responsibility to ensure
199 # Meant to be extended by extensions. It is extensions responsibility to ensure
200 # such options are properly processed in exchange.getbundle.
200 # such options are properly processed in exchange.getbundle.
201 #
201 #
202 # supported types are:
202 # supported types are:
203 #
203 #
204 # :nodes: list of binary nodes
204 # :nodes: list of binary nodes
205 # :csv: list of comma-separated values
205 # :csv: list of comma-separated values
206 # :scsv: list of comma-separated values return as set
206 # :scsv: list of comma-separated values return as set
207 # :plain: string with no transformation needed.
207 # :plain: string with no transformation needed.
208 gboptsmap = {'heads': 'nodes',
208 gboptsmap = {'heads': 'nodes',
209 'common': 'nodes',
209 'common': 'nodes',
210 'obsmarkers': 'boolean',
210 'obsmarkers': 'boolean',
211 'bundlecaps': 'scsv',
211 'bundlecaps': 'scsv',
212 'listkeys': 'csv',
212 'listkeys': 'csv',
213 'cg': 'boolean'}
213 'cg': 'boolean'}
214
214
215 # client side
215 # client side
216
216
217 class wirepeer(peer.peerrepository):
217 class wirepeer(peer.peerrepository):
218
218
219 def batch(self):
219 def batch(self):
220 return remotebatch(self)
220 return remotebatch(self)
221 def _submitbatch(self, req):
221 def _submitbatch(self, req):
222 cmds = []
222 cmds = []
223 for op, argsdict in req:
223 for op, argsdict in req:
224 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
224 args = ','.join('%s=%s' % p for p in argsdict.iteritems())
225 cmds.append('%s %s' % (op, args))
225 cmds.append('%s %s' % (op, args))
226 rsp = self._call("batch", cmds=';'.join(cmds))
226 rsp = self._call("batch", cmds=';'.join(cmds))
227 return rsp.split(';')
227 return rsp.split(';')
228 def _submitone(self, op, args):
228 def _submitone(self, op, args):
229 return self._call(op, **args)
229 return self._call(op, **args)
230
230
231 @batchable
231 @batchable
232 def lookup(self, key):
232 def lookup(self, key):
233 self.requirecap('lookup', _('look up remote revision'))
233 self.requirecap('lookup', _('look up remote revision'))
234 f = future()
234 f = future()
235 yield {'key': encoding.fromlocal(key)}, f
235 yield {'key': encoding.fromlocal(key)}, f
236 d = f.value
236 d = f.value
237 success, data = d[:-1].split(" ", 1)
237 success, data = d[:-1].split(" ", 1)
238 if int(success):
238 if int(success):
239 yield bin(data)
239 yield bin(data)
240 self._abort(error.RepoError(data))
240 self._abort(error.RepoError(data))
241
241
242 @batchable
242 @batchable
243 def heads(self):
243 def heads(self):
244 f = future()
244 f = future()
245 yield {}, f
245 yield {}, f
246 d = f.value
246 d = f.value
247 try:
247 try:
248 yield decodelist(d[:-1])
248 yield decodelist(d[:-1])
249 except ValueError:
249 except ValueError:
250 self._abort(error.ResponseError(_("unexpected response:"), d))
250 self._abort(error.ResponseError(_("unexpected response:"), d))
251
251
252 @batchable
252 @batchable
253 def known(self, nodes):
253 def known(self, nodes):
254 f = future()
254 f = future()
255 yield {'nodes': encodelist(nodes)}, f
255 yield {'nodes': encodelist(nodes)}, f
256 d = f.value
256 d = f.value
257 try:
257 try:
258 yield [bool(int(b)) for b in d]
258 yield [bool(int(b)) for b in d]
259 except ValueError:
259 except ValueError:
260 self._abort(error.ResponseError(_("unexpected response:"), d))
260 self._abort(error.ResponseError(_("unexpected response:"), d))
261
261
262 @batchable
262 @batchable
263 def branchmap(self):
263 def branchmap(self):
264 f = future()
264 f = future()
265 yield {}, f
265 yield {}, f
266 d = f.value
266 d = f.value
267 try:
267 try:
268 branchmap = {}
268 branchmap = {}
269 for branchpart in d.splitlines():
269 for branchpart in d.splitlines():
270 branchname, branchheads = branchpart.split(' ', 1)
270 branchname, branchheads = branchpart.split(' ', 1)
271 branchname = encoding.tolocal(urllib.unquote(branchname))
271 branchname = encoding.tolocal(urllib.unquote(branchname))
272 branchheads = decodelist(branchheads)
272 branchheads = decodelist(branchheads)
273 branchmap[branchname] = branchheads
273 branchmap[branchname] = branchheads
274 yield branchmap
274 yield branchmap
275 except TypeError:
275 except TypeError:
276 self._abort(error.ResponseError(_("unexpected response:"), d))
276 self._abort(error.ResponseError(_("unexpected response:"), d))
277
277
278 def branches(self, nodes):
278 def branches(self, nodes):
279 n = encodelist(nodes)
279 n = encodelist(nodes)
280 d = self._call("branches", nodes=n)
280 d = self._call("branches", nodes=n)
281 try:
281 try:
282 br = [tuple(decodelist(b)) for b in d.splitlines()]
282 br = [tuple(decodelist(b)) for b in d.splitlines()]
283 return br
283 return br
284 except ValueError:
284 except ValueError:
285 self._abort(error.ResponseError(_("unexpected response:"), d))
285 self._abort(error.ResponseError(_("unexpected response:"), d))
286
286
287 def between(self, pairs):
287 def between(self, pairs):
288 batch = 8 # avoid giant requests
288 batch = 8 # avoid giant requests
289 r = []
289 r = []
290 for i in xrange(0, len(pairs), batch):
290 for i in xrange(0, len(pairs), batch):
291 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
291 n = " ".join([encodelist(p, '-') for p in pairs[i:i + batch]])
292 d = self._call("between", pairs=n)
292 d = self._call("between", pairs=n)
293 try:
293 try:
294 r.extend(l and decodelist(l) or [] for l in d.splitlines())
294 r.extend(l and decodelist(l) or [] for l in d.splitlines())
295 except ValueError:
295 except ValueError:
296 self._abort(error.ResponseError(_("unexpected response:"), d))
296 self._abort(error.ResponseError(_("unexpected response:"), d))
297 return r
297 return r
298
298
299 @batchable
299 @batchable
300 def pushkey(self, namespace, key, old, new):
300 def pushkey(self, namespace, key, old, new):
301 if not self.capable('pushkey'):
301 if not self.capable('pushkey'):
302 yield False, None
302 yield False, None
303 f = future()
303 f = future()
304 self.ui.debug('preparing pushkey for "%s:%s"\n' % (namespace, key))
304 self.ui.debug('preparing pushkey for "%s:%s"\n' % (namespace, key))
305 yield {'namespace': encoding.fromlocal(namespace),
305 yield {'namespace': encoding.fromlocal(namespace),
306 'key': encoding.fromlocal(key),
306 'key': encoding.fromlocal(key),
307 'old': encoding.fromlocal(old),
307 'old': encoding.fromlocal(old),
308 'new': encoding.fromlocal(new)}, f
308 'new': encoding.fromlocal(new)}, f
309 d = f.value
309 d = f.value
310 d, output = d.split('\n', 1)
310 d, output = d.split('\n', 1)
311 try:
311 try:
312 d = bool(int(d))
312 d = bool(int(d))
313 except ValueError:
313 except ValueError:
314 raise error.ResponseError(
314 raise error.ResponseError(
315 _('push failed (unexpected response):'), d)
315 _('push failed (unexpected response):'), d)
316 for l in output.splitlines(True):
316 for l in output.splitlines(True):
317 self.ui.status(_('remote: '), l)
317 self.ui.status(_('remote: '), l)
318 yield d
318 yield d
319
319
320 @batchable
320 @batchable
321 def listkeys(self, namespace):
321 def listkeys(self, namespace):
322 if not self.capable('pushkey'):
322 if not self.capable('pushkey'):
323 yield {}, None
323 yield {}, None
324 f = future()
324 f = future()
325 self.ui.debug('preparing listkeys for "%s"\n' % namespace)
325 self.ui.debug('preparing listkeys for "%s"\n' % namespace)
326 yield {'namespace': encoding.fromlocal(namespace)}, f
326 yield {'namespace': encoding.fromlocal(namespace)}, f
327 d = f.value
327 d = f.value
328 self.ui.debug('received listkey for "%s": %i bytes\n'
328 self.ui.debug('received listkey for "%s": %i bytes\n'
329 % (namespace, len(d)))
329 % (namespace, len(d)))
330 yield pushkeymod.decodekeys(d)
330 yield pushkeymod.decodekeys(d)
331
331
332 def stream_out(self):
332 def stream_out(self):
333 return self._callstream('stream_out')
333 return self._callstream('stream_out')
334
334
335 def changegroup(self, nodes, kind):
335 def changegroup(self, nodes, kind):
336 n = encodelist(nodes)
336 n = encodelist(nodes)
337 f = self._callcompressable("changegroup", roots=n)
337 f = self._callcompressable("changegroup", roots=n)
338 return changegroupmod.cg1unpacker(f, 'UN')
338 return changegroupmod.cg1unpacker(f, 'UN')
339
339
340 def changegroupsubset(self, bases, heads, kind):
340 def changegroupsubset(self, bases, heads, kind):
341 self.requirecap('changegroupsubset', _('look up remote changes'))
341 self.requirecap('changegroupsubset', _('look up remote changes'))
342 bases = encodelist(bases)
342 bases = encodelist(bases)
343 heads = encodelist(heads)
343 heads = encodelist(heads)
344 f = self._callcompressable("changegroupsubset",
344 f = self._callcompressable("changegroupsubset",
345 bases=bases, heads=heads)
345 bases=bases, heads=heads)
346 return changegroupmod.cg1unpacker(f, 'UN')
346 return changegroupmod.cg1unpacker(f, 'UN')
347
347
348 def getbundle(self, source, **kwargs):
348 def getbundle(self, source, **kwargs):
349 self.requirecap('getbundle', _('look up remote changes'))
349 self.requirecap('getbundle', _('look up remote changes'))
350 opts = {}
350 opts = {}
351 bundlecaps = kwargs.get('bundlecaps')
351 bundlecaps = kwargs.get('bundlecaps')
352 if bundlecaps is not None:
352 if bundlecaps is not None:
353 kwargs['bundlecaps'] = sorted(bundlecaps)
353 kwargs['bundlecaps'] = sorted(bundlecaps)
354 else:
354 else:
355 bundlecaps = () # kwargs could have it to None
355 bundlecaps = () # kwargs could have it to None
356 for key, value in kwargs.iteritems():
356 for key, value in kwargs.iteritems():
357 if value is None:
357 if value is None:
358 continue
358 continue
359 keytype = gboptsmap.get(key)
359 keytype = gboptsmap.get(key)
360 if keytype is None:
360 if keytype is None:
361 assert False, 'unexpected'
361 assert False, 'unexpected'
362 elif keytype == 'nodes':
362 elif keytype == 'nodes':
363 value = encodelist(value)
363 value = encodelist(value)
364 elif keytype in ('csv', 'scsv'):
364 elif keytype in ('csv', 'scsv'):
365 value = ','.join(value)
365 value = ','.join(value)
366 elif keytype == 'boolean':
366 elif keytype == 'boolean':
367 value = '%i' % bool(value)
367 value = '%i' % bool(value)
368 elif keytype != 'plain':
368 elif keytype != 'plain':
369 raise KeyError('unknown getbundle option type %s'
369 raise KeyError('unknown getbundle option type %s'
370 % keytype)
370 % keytype)
371 opts[key] = value
371 opts[key] = value
372 f = self._callcompressable("getbundle", **opts)
372 f = self._callcompressable("getbundle", **opts)
373 if any((cap.startswith('HG2') for cap in bundlecaps)):
373 if any((cap.startswith('HG2') for cap in bundlecaps)):
374 return bundle2.getunbundler(self.ui, f)
374 return bundle2.getunbundler(self.ui, f)
375 else:
375 else:
376 return changegroupmod.cg1unpacker(f, 'UN')
376 return changegroupmod.cg1unpacker(f, 'UN')
377
377
378 def unbundle(self, cg, heads, source):
378 def unbundle(self, cg, heads, source):
379 '''Send cg (a readable file-like object representing the
379 '''Send cg (a readable file-like object representing the
380 changegroup to push, typically a chunkbuffer object) to the
380 changegroup to push, typically a chunkbuffer object) to the
381 remote server as a bundle.
381 remote server as a bundle.
382
382
383 When pushing a bundle10 stream, return an integer indicating the
383 When pushing a bundle10 stream, return an integer indicating the
384 result of the push (see localrepository.addchangegroup()).
384 result of the push (see localrepository.addchangegroup()).
385
385
386 When pushing a bundle20 stream, return a bundle20 stream.'''
386 When pushing a bundle20 stream, return a bundle20 stream.'''
387
387
388 if heads != ['force'] and self.capable('unbundlehash'):
388 if heads != ['force'] and self.capable('unbundlehash'):
389 heads = encodelist(['hashed',
389 heads = encodelist(['hashed',
390 util.sha1(''.join(sorted(heads))).digest()])
390 util.sha1(''.join(sorted(heads))).digest()])
391 else:
391 else:
392 heads = encodelist(heads)
392 heads = encodelist(heads)
393
393
394 if util.safehasattr(cg, 'deltaheader'):
394 if util.safehasattr(cg, 'deltaheader'):
395 # this a bundle10, do the old style call sequence
395 # this a bundle10, do the old style call sequence
396 ret, output = self._callpush("unbundle", cg, heads=heads)
396 ret, output = self._callpush("unbundle", cg, heads=heads)
397 if ret == "":
397 if ret == "":
398 raise error.ResponseError(
398 raise error.ResponseError(
399 _('push failed:'), output)
399 _('push failed:'), output)
400 try:
400 try:
401 ret = int(ret)
401 ret = int(ret)
402 except ValueError:
402 except ValueError:
403 raise error.ResponseError(
403 raise error.ResponseError(
404 _('push failed (unexpected response):'), ret)
404 _('push failed (unexpected response):'), ret)
405
405
406 for l in output.splitlines(True):
406 for l in output.splitlines(True):
407 self.ui.status(_('remote: '), l)
407 self.ui.status(_('remote: '), l)
408 else:
408 else:
409 # bundle2 push. Send a stream, fetch a stream.
409 # bundle2 push. Send a stream, fetch a stream.
410 stream = self._calltwowaystream('unbundle', cg, heads=heads)
410 stream = self._calltwowaystream('unbundle', cg, heads=heads)
411 ret = bundle2.getunbundler(self.ui, stream)
411 ret = bundle2.getunbundler(self.ui, stream)
412 return ret
412 return ret
413
413
414 def debugwireargs(self, one, two, three=None, four=None, five=None):
414 def debugwireargs(self, one, two, three=None, four=None, five=None):
415 # don't pass optional arguments left at their default value
415 # don't pass optional arguments left at their default value
416 opts = {}
416 opts = {}
417 if three is not None:
417 if three is not None:
418 opts['three'] = three
418 opts['three'] = three
419 if four is not None:
419 if four is not None:
420 opts['four'] = four
420 opts['four'] = four
421 return self._call('debugwireargs', one=one, two=two, **opts)
421 return self._call('debugwireargs', one=one, two=two, **opts)
422
422
423 def _call(self, cmd, **args):
423 def _call(self, cmd, **args):
424 """execute <cmd> on the server
424 """execute <cmd> on the server
425
425
426 The command is expected to return a simple string.
426 The command is expected to return a simple string.
427
427
428 returns the server reply as a string."""
428 returns the server reply as a string."""
429 raise NotImplementedError()
429 raise NotImplementedError()
430
430
431 def _callstream(self, cmd, **args):
431 def _callstream(self, cmd, **args):
432 """execute <cmd> on the server
432 """execute <cmd> on the server
433
433
434 The command is expected to return a stream.
434 The command is expected to return a stream.
435
435
436 returns the server reply as a file like object."""
436 returns the server reply as a file like object."""
437 raise NotImplementedError()
437 raise NotImplementedError()
438
438
439 def _callcompressable(self, cmd, **args):
439 def _callcompressable(self, cmd, **args):
440 """execute <cmd> on the server
440 """execute <cmd> on the server
441
441
442 The command is expected to return a stream.
442 The command is expected to return a stream.
443
443
444 The stream may have been compressed in some implementations. This
444 The stream may have been compressed in some implementations. This
445 function takes care of the decompression. This is the only difference
445 function takes care of the decompression. This is the only difference
446 with _callstream.
446 with _callstream.
447
447
448 returns the server reply as a file like object.
448 returns the server reply as a file like object.
449 """
449 """
450 raise NotImplementedError()
450 raise NotImplementedError()
451
451
452 def _callpush(self, cmd, fp, **args):
452 def _callpush(self, cmd, fp, **args):
453 """execute a <cmd> on server
453 """execute a <cmd> on server
454
454
455 The command is expected to be related to a push. Push has a special
455 The command is expected to be related to a push. Push has a special
456 return method.
456 return method.
457
457
458 returns the server reply as a (ret, output) tuple. ret is either
458 returns the server reply as a (ret, output) tuple. ret is either
459 empty (error) or a stringified int.
459 empty (error) or a stringified int.
460 """
460 """
461 raise NotImplementedError()
461 raise NotImplementedError()
462
462
463 def _calltwowaystream(self, cmd, fp, **args):
463 def _calltwowaystream(self, cmd, fp, **args):
464 """execute <cmd> on server
464 """execute <cmd> on server
465
465
466 The command will send a stream to the server and get a stream in reply.
466 The command will send a stream to the server and get a stream in reply.
467 """
467 """
468 raise NotImplementedError()
468 raise NotImplementedError()
469
469
470 def _abort(self, exception):
470 def _abort(self, exception):
471 """clearly abort the wire protocol connection and raise the exception
471 """clearly abort the wire protocol connection and raise the exception
472 """
472 """
473 raise NotImplementedError()
473 raise NotImplementedError()
474
474
475 # server side
475 # server side
476
476
477 # wire protocol command can either return a string or one of these classes.
477 # wire protocol command can either return a string or one of these classes.
478 class streamres(object):
478 class streamres(object):
479 """wireproto reply: binary stream
479 """wireproto reply: binary stream
480
480
481 The call was successful and the result is a stream.
481 The call was successful and the result is a stream.
482 Iterate on the `self.gen` attribute to retrieve chunks.
482 Iterate on the `self.gen` attribute to retrieve chunks.
483 """
483 """
484 def __init__(self, gen):
484 def __init__(self, gen):
485 self.gen = gen
485 self.gen = gen
486
486
487 class pushres(object):
487 class pushres(object):
488 """wireproto reply: success with simple integer return
488 """wireproto reply: success with simple integer return
489
489
490 The call was successful and returned an integer contained in `self.res`.
490 The call was successful and returned an integer contained in `self.res`.
491 """
491 """
492 def __init__(self, res):
492 def __init__(self, res):
493 self.res = res
493 self.res = res
494
494
495 class pusherr(object):
495 class pusherr(object):
496 """wireproto reply: failure
496 """wireproto reply: failure
497
497
498 The call failed. The `self.res` attribute contains the error message.
498 The call failed. The `self.res` attribute contains the error message.
499 """
499 """
500 def __init__(self, res):
500 def __init__(self, res):
501 self.res = res
501 self.res = res
502
502
503 class ooberror(object):
503 class ooberror(object):
504 """wireproto reply: failure of a batch of operation
504 """wireproto reply: failure of a batch of operation
505
505
506 Something failed during a batch call. The error message is stored in
506 Something failed during a batch call. The error message is stored in
507 `self.message`.
507 `self.message`.
508 """
508 """
509 def __init__(self, message):
509 def __init__(self, message):
510 self.message = message
510 self.message = message
511
511
512 def dispatch(repo, proto, command):
512 def dispatch(repo, proto, command):
513 repo = repo.filtered("served")
513 repo = repo.filtered("served")
514 func, spec = commands[command]
514 func, spec = commands[command]
515 args = proto.getargs(spec)
515 args = proto.getargs(spec)
516 return func(repo, proto, *args)
516 return func(repo, proto, *args)
517
517
518 def options(cmd, keys, others):
518 def options(cmd, keys, others):
519 opts = {}
519 opts = {}
520 for k in keys:
520 for k in keys:
521 if k in others:
521 if k in others:
522 opts[k] = others[k]
522 opts[k] = others[k]
523 del others[k]
523 del others[k]
524 if others:
524 if others:
525 sys.stderr.write("warning: %s ignored unexpected arguments %s\n"
525 sys.stderr.write("warning: %s ignored unexpected arguments %s\n"
526 % (cmd, ",".join(others)))
526 % (cmd, ",".join(others)))
527 return opts
527 return opts
528
528
529 # list of commands
529 # list of commands
530 commands = {}
530 commands = {}
531
531
532 def wireprotocommand(name, args=''):
532 def wireprotocommand(name, args=''):
533 """decorator for wire protocol command"""
533 """decorator for wire protocol command"""
534 def register(func):
534 def register(func):
535 commands[name] = (func, args)
535 commands[name] = (func, args)
536 return func
536 return func
537 return register
537 return register
538
538
539 @wireprotocommand('batch', 'cmds *')
539 @wireprotocommand('batch', 'cmds *')
540 def batch(repo, proto, cmds, others):
540 def batch(repo, proto, cmds, others):
541 repo = repo.filtered("served")
541 repo = repo.filtered("served")
542 res = []
542 res = []
543 for pair in cmds.split(';'):
543 for pair in cmds.split(';'):
544 op, args = pair.split(' ', 1)
544 op, args = pair.split(' ', 1)
545 vals = {}
545 vals = {}
546 for a in args.split(','):
546 for a in args.split(','):
547 if a:
547 if a:
548 n, v = a.split('=')
548 n, v = a.split('=')
549 vals[n] = unescapearg(v)
549 vals[n] = unescapearg(v)
550 func, spec = commands[op]
550 func, spec = commands[op]
551 if spec:
551 if spec:
552 keys = spec.split()
552 keys = spec.split()
553 data = {}
553 data = {}
554 for k in keys:
554 for k in keys:
555 if k == '*':
555 if k == '*':
556 star = {}
556 star = {}
557 for key in vals.keys():
557 for key in vals.keys():
558 if key not in keys:
558 if key not in keys:
559 star[key] = vals[key]
559 star[key] = vals[key]
560 data['*'] = star
560 data['*'] = star
561 else:
561 else:
562 data[k] = vals[k]
562 data[k] = vals[k]
563 result = func(repo, proto, *[data[k] for k in keys])
563 result = func(repo, proto, *[data[k] for k in keys])
564 else:
564 else:
565 result = func(repo, proto)
565 result = func(repo, proto)
566 if isinstance(result, ooberror):
566 if isinstance(result, ooberror):
567 return result
567 return result
568 res.append(escapearg(result))
568 res.append(escapearg(result))
569 return ';'.join(res)
569 return ';'.join(res)
570
570
571 @wireprotocommand('between', 'pairs')
571 @wireprotocommand('between', 'pairs')
572 def between(repo, proto, pairs):
572 def between(repo, proto, pairs):
573 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
573 pairs = [decodelist(p, '-') for p in pairs.split(" ")]
574 r = []
574 r = []
575 for b in repo.between(pairs):
575 for b in repo.between(pairs):
576 r.append(encodelist(b) + "\n")
576 r.append(encodelist(b) + "\n")
577 return "".join(r)
577 return "".join(r)
578
578
579 @wireprotocommand('branchmap')
579 @wireprotocommand('branchmap')
580 def branchmap(repo, proto):
580 def branchmap(repo, proto):
581 branchmap = repo.branchmap()
581 branchmap = repo.branchmap()
582 heads = []
582 heads = []
583 for branch, nodes in branchmap.iteritems():
583 for branch, nodes in branchmap.iteritems():
584 branchname = urllib.quote(encoding.fromlocal(branch))
584 branchname = urllib.quote(encoding.fromlocal(branch))
585 branchnodes = encodelist(nodes)
585 branchnodes = encodelist(nodes)
586 heads.append('%s %s' % (branchname, branchnodes))
586 heads.append('%s %s' % (branchname, branchnodes))
587 return '\n'.join(heads)
587 return '\n'.join(heads)
588
588
589 @wireprotocommand('branches', 'nodes')
589 @wireprotocommand('branches', 'nodes')
590 def branches(repo, proto, nodes):
590 def branches(repo, proto, nodes):
591 nodes = decodelist(nodes)
591 nodes = decodelist(nodes)
592 r = []
592 r = []
593 for b in repo.branches(nodes):
593 for b in repo.branches(nodes):
594 r.append(encodelist(b) + "\n")
594 r.append(encodelist(b) + "\n")
595 return "".join(r)
595 return "".join(r)
596
596
597
597
598 wireprotocaps = ['lookup', 'changegroupsubset', 'branchmap', 'pushkey',
598 wireprotocaps = ['lookup', 'changegroupsubset', 'branchmap', 'pushkey',
599 'known', 'getbundle', 'unbundlehash', 'batch']
599 'known', 'getbundle', 'unbundlehash', 'batch']
600
600
601 def _capabilities(repo, proto):
601 def _capabilities(repo, proto):
602 """return a list of capabilities for a repo
602 """return a list of capabilities for a repo
603
603
604 This function exists to allow extensions to easily wrap capabilities
604 This function exists to allow extensions to easily wrap capabilities
605 computation
605 computation
606
606
607 - returns a lists: easy to alter
607 - returns a lists: easy to alter
608 - change done here will be propagated to both `capabilities` and `hello`
608 - change done here will be propagated to both `capabilities` and `hello`
609 command without any other action needed.
609 command without any other action needed.
610 """
610 """
611 # copy to prevent modification of the global list
611 # copy to prevent modification of the global list
612 caps = list(wireprotocaps)
612 caps = list(wireprotocaps)
613 if _allowstream(repo.ui):
613 if _allowstream(repo.ui):
614 if repo.ui.configbool('server', 'preferuncompressed', False):
614 if repo.ui.configbool('server', 'preferuncompressed', False):
615 caps.append('stream-preferred')
615 caps.append('stream-preferred')
616 requiredformats = repo.requirements & repo.supportedformats
616 requiredformats = repo.requirements & repo.supportedformats
617 # if our local revlogs are just revlogv1, add 'stream' cap
617 # if our local revlogs are just revlogv1, add 'stream' cap
618 if not requiredformats - set(('revlogv1',)):
618 if not requiredformats - set(('revlogv1',)):
619 caps.append('stream')
619 caps.append('stream')
620 # otherwise, add 'streamreqs' detailing our local revlog format
620 # otherwise, add 'streamreqs' detailing our local revlog format
621 else:
621 else:
622 caps.append('streamreqs=%s' % ','.join(requiredformats))
622 caps.append('streamreqs=%s' % ','.join(requiredformats))
623 if repo.ui.configbool('experimental', 'bundle2-advertise', True):
623 if repo.ui.configbool('experimental', 'bundle2-advertise', True):
624 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
624 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
625 caps.append('bundle2=' + urllib.quote(capsblob))
625 caps.append('bundle2=' + urllib.quote(capsblob))
626 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
626 caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority))
627 caps.append('httpheader=1024')
627 caps.append('httpheader=1024')
628 return caps
628 return caps
629
629
630 # If you are writing an extension and consider wrapping this function. Wrap
630 # If you are writing an extension and consider wrapping this function. Wrap
631 # `_capabilities` instead.
631 # `_capabilities` instead.
632 @wireprotocommand('capabilities')
632 @wireprotocommand('capabilities')
633 def capabilities(repo, proto):
633 def capabilities(repo, proto):
634 return ' '.join(_capabilities(repo, proto))
634 return ' '.join(_capabilities(repo, proto))
635
635
636 @wireprotocommand('changegroup', 'roots')
636 @wireprotocommand('changegroup', 'roots')
637 def changegroup(repo, proto, roots):
637 def changegroup(repo, proto, roots):
638 nodes = decodelist(roots)
638 nodes = decodelist(roots)
639 cg = changegroupmod.changegroup(repo, nodes, 'serve')
639 cg = changegroupmod.changegroup(repo, nodes, 'serve')
640 return streamres(proto.groupchunks(cg))
640 return streamres(proto.groupchunks(cg))
641
641
642 @wireprotocommand('changegroupsubset', 'bases heads')
642 @wireprotocommand('changegroupsubset', 'bases heads')
643 def changegroupsubset(repo, proto, bases, heads):
643 def changegroupsubset(repo, proto, bases, heads):
644 bases = decodelist(bases)
644 bases = decodelist(bases)
645 heads = decodelist(heads)
645 heads = decodelist(heads)
646 cg = changegroupmod.changegroupsubset(repo, bases, heads, 'serve')
646 cg = changegroupmod.changegroupsubset(repo, bases, heads, 'serve')
647 return streamres(proto.groupchunks(cg))
647 return streamres(proto.groupchunks(cg))
648
648
649 @wireprotocommand('debugwireargs', 'one two *')
649 @wireprotocommand('debugwireargs', 'one two *')
650 def debugwireargs(repo, proto, one, two, others):
650 def debugwireargs(repo, proto, one, two, others):
651 # only accept optional args from the known set
651 # only accept optional args from the known set
652 opts = options('debugwireargs', ['three', 'four'], others)
652 opts = options('debugwireargs', ['three', 'four'], others)
653 return repo.debugwireargs(one, two, **opts)
653 return repo.debugwireargs(one, two, **opts)
654
654
655 # List of options accepted by getbundle.
655 # List of options accepted by getbundle.
656 #
656 #
657 # Meant to be extended by extensions. It is the extension's responsibility to
657 # Meant to be extended by extensions. It is the extension's responsibility to
658 # ensure such options are properly processed in exchange.getbundle.
658 # ensure such options are properly processed in exchange.getbundle.
659 gboptslist = ['heads', 'common', 'bundlecaps']
659 gboptslist = ['heads', 'common', 'bundlecaps']
660
660
661 @wireprotocommand('getbundle', '*')
661 @wireprotocommand('getbundle', '*')
662 def getbundle(repo, proto, others):
662 def getbundle(repo, proto, others):
663 opts = options('getbundle', gboptsmap.keys(), others)
663 opts = options('getbundle', gboptsmap.keys(), others)
664 for k, v in opts.iteritems():
664 for k, v in opts.iteritems():
665 keytype = gboptsmap[k]
665 keytype = gboptsmap[k]
666 if keytype == 'nodes':
666 if keytype == 'nodes':
667 opts[k] = decodelist(v)
667 opts[k] = decodelist(v)
668 elif keytype == 'csv':
668 elif keytype == 'csv':
669 opts[k] = list(v.split(','))
669 opts[k] = list(v.split(','))
670 elif keytype == 'scsv':
670 elif keytype == 'scsv':
671 opts[k] = set(v.split(','))
671 opts[k] = set(v.split(','))
672 elif keytype == 'boolean':
672 elif keytype == 'boolean':
673 opts[k] = bool(v)
673 opts[k] = bool(v)
674 elif keytype != 'plain':
674 elif keytype != 'plain':
675 raise KeyError('unknown getbundle option type %s'
675 raise KeyError('unknown getbundle option type %s'
676 % keytype)
676 % keytype)
677 cg = exchange.getbundle(repo, 'serve', **opts)
677 cg = exchange.getbundle(repo, 'serve', **opts)
678 return streamres(proto.groupchunks(cg))
678 return streamres(proto.groupchunks(cg))
679
679
680 @wireprotocommand('heads')
680 @wireprotocommand('heads')
681 def heads(repo, proto):
681 def heads(repo, proto):
682 h = repo.heads()
682 h = repo.heads()
683 return encodelist(h) + "\n"
683 return encodelist(h) + "\n"
684
684
685 @wireprotocommand('hello')
685 @wireprotocommand('hello')
686 def hello(repo, proto):
686 def hello(repo, proto):
687 '''the hello command returns a set of lines describing various
687 '''the hello command returns a set of lines describing various
688 interesting things about the server, in an RFC822-like format.
688 interesting things about the server, in an RFC822-like format.
689 Currently the only one defined is "capabilities", which
689 Currently the only one defined is "capabilities", which
690 consists of a line in the form:
690 consists of a line in the form:
691
691
692 capabilities: space separated list of tokens
692 capabilities: space separated list of tokens
693 '''
693 '''
694 return "capabilities: %s\n" % (capabilities(repo, proto))
694 return "capabilities: %s\n" % (capabilities(repo, proto))
695
695
696 @wireprotocommand('listkeys', 'namespace')
696 @wireprotocommand('listkeys', 'namespace')
697 def listkeys(repo, proto, namespace):
697 def listkeys(repo, proto, namespace):
698 d = repo.listkeys(encoding.tolocal(namespace)).items()
698 d = repo.listkeys(encoding.tolocal(namespace)).items()
699 return pushkeymod.encodekeys(d)
699 return pushkeymod.encodekeys(d)
700
700
701 @wireprotocommand('lookup', 'key')
701 @wireprotocommand('lookup', 'key')
702 def lookup(repo, proto, key):
702 def lookup(repo, proto, key):
703 try:
703 try:
704 k = encoding.tolocal(key)
704 k = encoding.tolocal(key)
705 c = repo[k]
705 c = repo[k]
706 r = c.hex()
706 r = c.hex()
707 success = 1
707 success = 1
708 except Exception, inst:
708 except Exception, inst:
709 r = str(inst)
709 r = str(inst)
710 success = 0
710 success = 0
711 return "%s %s\n" % (success, r)
711 return "%s %s\n" % (success, r)
712
712
713 @wireprotocommand('known', 'nodes *')
713 @wireprotocommand('known', 'nodes *')
714 def known(repo, proto, nodes, others):
714 def known(repo, proto, nodes, others):
715 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
715 return ''.join(b and "1" or "0" for b in repo.known(decodelist(nodes)))
716
716
717 @wireprotocommand('pushkey', 'namespace key old new')
717 @wireprotocommand('pushkey', 'namespace key old new')
718 def pushkey(repo, proto, namespace, key, old, new):
718 def pushkey(repo, proto, namespace, key, old, new):
719 # compatibility with pre-1.8 clients which were accidentally
719 # compatibility with pre-1.8 clients which were accidentally
720 # sending raw binary nodes rather than utf-8-encoded hex
720 # sending raw binary nodes rather than utf-8-encoded hex
721 if len(new) == 20 and new.encode('string-escape') != new:
721 if len(new) == 20 and new.encode('string-escape') != new:
722 # looks like it could be a binary node
722 # looks like it could be a binary node
723 try:
723 try:
724 new.decode('utf-8')
724 new.decode('utf-8')
725 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
725 new = encoding.tolocal(new) # but cleanly decodes as UTF-8
726 except UnicodeDecodeError:
726 except UnicodeDecodeError:
727 pass # binary, leave unmodified
727 pass # binary, leave unmodified
728 else:
728 else:
729 new = encoding.tolocal(new) # normal path
729 new = encoding.tolocal(new) # normal path
730
730
731 if util.safehasattr(proto, 'restore'):
731 if util.safehasattr(proto, 'restore'):
732
732
733 proto.redirect()
733 proto.redirect()
734
734
735 try:
735 try:
736 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
736 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
737 encoding.tolocal(old), new) or False
737 encoding.tolocal(old), new) or False
738 except util.Abort:
738 except util.Abort:
739 r = False
739 r = False
740
740
741 output = proto.restore()
741 output = proto.restore()
742
742
743 return '%s\n%s' % (int(r), output)
743 return '%s\n%s' % (int(r), output)
744
744
745 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
745 r = repo.pushkey(encoding.tolocal(namespace), encoding.tolocal(key),
746 encoding.tolocal(old), new)
746 encoding.tolocal(old), new)
747 return '%s\n' % int(r)
747 return '%s\n' % int(r)
748
748
749 def _allowstream(ui):
749 def _allowstream(ui):
750 return ui.configbool('server', 'uncompressed', True, untrusted=True)
750 return ui.configbool('server', 'uncompressed', True, untrusted=True)
751
751
752 @wireprotocommand('stream_out')
752 @wireprotocommand('stream_out')
753 def stream(repo, proto):
753 def stream(repo, proto):
754 '''If the server supports streaming clone, it advertises the "stream"
754 '''If the server supports streaming clone, it advertises the "stream"
755 capability with a value representing the version and flags of the repo
755 capability with a value representing the version and flags of the repo
756 it is serving. Client checks to see if it understands the format.
756 it is serving. Client checks to see if it understands the format.
757 '''
757 '''
758 if not _allowstream(repo.ui):
758 if not _allowstream(repo.ui):
759 return '1\n'
759 return '1\n'
760
760
761 def getstream(it):
761 def getstream(it):
762 yield '0\n'
762 yield '0\n'
763 for chunk in it:
763 for chunk in it:
764 yield chunk
764 yield chunk
765
765
766 try:
766 try:
767 # LockError may be raised before the first result is yielded. Don't
767 # LockError may be raised before the first result is yielded. Don't
768 # emit output until we're sure we got the lock successfully.
768 # emit output until we're sure we got the lock successfully.
769 it = exchange.generatestreamclone(repo)
769 it = exchange.generatestreamclone(repo)
770 return streamres(getstream(it))
770 return streamres(getstream(it))
771 except error.LockError:
771 except error.LockError:
772 return '2\n'
772 return '2\n'
773
773
774 @wireprotocommand('unbundle', 'heads')
774 @wireprotocommand('unbundle', 'heads')
775 def unbundle(repo, proto, heads):
775 def unbundle(repo, proto, heads):
776 their_heads = decodelist(heads)
776 their_heads = decodelist(heads)
777
777
778 try:
778 try:
779 proto.redirect()
779 proto.redirect()
780
780
781 exchange.check_heads(repo, their_heads, 'preparing changes')
781 exchange.check_heads(repo, their_heads, 'preparing changes')
782
782
783 # write bundle data to temporary file because it can be big
783 # write bundle data to temporary file because it can be big
784 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
784 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
785 fp = os.fdopen(fd, 'wb+')
785 fp = os.fdopen(fd, 'wb+')
786 r = 0
786 r = 0
787 try:
787 try:
788 proto.getfile(fp)
788 proto.getfile(fp)
789 fp.seek(0)
789 fp.seek(0)
790 gen = exchange.readbundle(repo.ui, fp, None)
790 gen = exchange.readbundle(repo.ui, fp, None)
791 r = exchange.unbundle(repo, gen, their_heads, 'serve',
791 r = exchange.unbundle(repo, gen, their_heads, 'serve',
792 proto._client())
792 proto._client())
793 if util.safehasattr(r, 'addpart'):
793 if util.safehasattr(r, 'addpart'):
794 # The return looks streamable, we are in the bundle2 case and
794 # The return looks streamable, we are in the bundle2 case and
795 # should return a stream.
795 # should return a stream.
796 return streamres(r.getchunks())
796 return streamres(r.getchunks())
797 return pushres(r)
797 return pushres(r)
798
798
799 finally:
799 finally:
800 fp.close()
800 fp.close()
801 os.unlink(tempname)
801 os.unlink(tempname)
802
802
803 except (error.BundleValueError, util.Abort, error.PushRaced), exc:
803 except (error.BundleValueError, util.Abort, error.PushRaced), exc:
804 # handle non-bundle2 case first
804 # handle non-bundle2 case first
805 if not getattr(exc, 'duringunbundle2', False):
805 if not getattr(exc, 'duringunbundle2', False):
806 try:
806 try:
807 raise
807 raise
808 except util.Abort:
808 except util.Abort:
809 # The old code we moved used sys.stderr directly.
809 # The old code we moved used sys.stderr directly.
810 # We did not change it to minimise code change.
810 # We did not change it to minimise code change.
811 # This need to be moved to something proper.
811 # This need to be moved to something proper.
812 # Feel free to do it.
812 # Feel free to do it.
813 sys.stderr.write("abort: %s\n" % exc)
813 sys.stderr.write("abort: %s\n" % exc)
814 return pushres(0)
814 return pushres(0)
815 except error.PushRaced:
815 except error.PushRaced:
816 return pusherr(str(exc))
816 return pusherr(str(exc))
817
817
818 bundler = bundle2.bundle20(repo.ui)
818 bundler = bundle2.bundle20(repo.ui)
819 for out in getattr(exc, '_bundle2salvagedoutput', ()):
819 for out in getattr(exc, '_bundle2salvagedoutput', ()):
820 bundler.addpart(out)
820 bundler.addpart(out)
821 try:
821 try:
822 raise
822 try:
823 raise
824 except error.PushkeyFailed, exc:
825 # check client caps
826 remotecaps = getattr(exc, '_replycaps', None)
827 if (remotecaps is not None
828 and 'pushkey' not in remotecaps.get('error', ())):
829 # no support remote side, fallback to Abort handler.
830 raise
831 part = bundler.newpart('error:pushkey')
832 part.addparam('in-reply-to', exc.partid)
833 if exc.namespace is not None:
834 part.addparam('namespace', exc.namespace, mandatory=False)
835 if exc.key is not None:
836 part.addparam('key', exc.key, mandatory=False)
837 if exc.new is not None:
838 part.addparam('new', exc.new, mandatory=False)
839 if exc.old is not None:
840 part.addparam('old', exc.old, mandatory=False)
841 if exc.ret is not None:
842 part.addparam('ret', exc.ret, mandatory=False)
823 except error.BundleValueError, exc:
843 except error.BundleValueError, exc:
824 errpart = bundler.newpart('error:unsupportedcontent')
844 errpart = bundler.newpart('error:unsupportedcontent')
825 if exc.parttype is not None:
845 if exc.parttype is not None:
826 errpart.addparam('parttype', exc.parttype)
846 errpart.addparam('parttype', exc.parttype)
827 if exc.params:
847 if exc.params:
828 errpart.addparam('params', '\0'.join(exc.params))
848 errpart.addparam('params', '\0'.join(exc.params))
829 except util.Abort, exc:
849 except util.Abort, exc:
830 manargs = [('message', str(exc))]
850 manargs = [('message', str(exc))]
831 advargs = []
851 advargs = []
832 if exc.hint is not None:
852 if exc.hint is not None:
833 advargs.append(('hint', exc.hint))
853 advargs.append(('hint', exc.hint))
834 bundler.addpart(bundle2.bundlepart('error:abort',
854 bundler.addpart(bundle2.bundlepart('error:abort',
835 manargs, advargs))
855 manargs, advargs))
836 except error.PushRaced, exc:
856 except error.PushRaced, exc:
837 bundler.newpart('error:pushraced', [('message', str(exc))])
857 bundler.newpart('error:pushraced', [('message', str(exc))])
838 return streamres(bundler.getchunks())
858 return streamres(bundler.getchunks())
@@ -1,2166 +1,2166 b''
1 > do_push()
1 > do_push()
2 > {
2 > {
3 > user=$1
3 > user=$1
4 > shift
4 > shift
5 > echo "Pushing as user $user"
5 > echo "Pushing as user $user"
6 > echo 'hgrc = """'
6 > echo 'hgrc = """'
7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
8 > echo '"""'
8 > echo '"""'
9 > if test -f acl.config; then
9 > if test -f acl.config; then
10 > echo 'acl.config = """'
10 > echo 'acl.config = """'
11 > cat acl.config
11 > cat acl.config
12 > echo '"""'
12 > echo '"""'
13 > fi
13 > fi
14 > # On AIX /etc/profile sets LOGNAME read-only. So
14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 > # LOGNAME=$user hg --cws a --debug push ../b
15 > # LOGNAME=$user hg --cws a --debug push ../b
16 > # fails with "This variable is read only."
16 > # fails with "This variable is read only."
17 > # Use env to work around this.
17 > # Use env to work around this.
18 > env LOGNAME=$user hg --cwd a --debug push ../b
18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 > hg --cwd b rollback
19 > hg --cwd b rollback
20 > hg --cwd b --quiet tip
20 > hg --cwd b --quiet tip
21 > echo
21 > echo
22 > }
22 > }
23
23
24 > init_config()
24 > init_config()
25 > {
25 > {
26 > cat > fakegroups.py <<EOF
26 > cat > fakegroups.py <<EOF
27 > from hgext import acl
27 > from hgext import acl
28 > def fakegetusers(ui, group):
28 > def fakegetusers(ui, group):
29 > try:
29 > try:
30 > return acl._getusersorig(ui, group)
30 > return acl._getusersorig(ui, group)
31 > except:
31 > except:
32 > return ["fred", "betty"]
32 > return ["fred", "betty"]
33 > acl._getusersorig = acl._getusers
33 > acl._getusersorig = acl._getusers
34 > acl._getusers = fakegetusers
34 > acl._getusers = fakegetusers
35 > EOF
35 > EOF
36 > rm -f acl.config
36 > rm -f acl.config
37 > cat > $config <<EOF
37 > cat > $config <<EOF
38 > [hooks]
38 > [hooks]
39 > pretxnchangegroup.acl = python:hgext.acl.hook
39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 > [acl]
40 > [acl]
41 > sources = push
41 > sources = push
42 > [extensions]
42 > [extensions]
43 > f=`pwd`/fakegroups.py
43 > f=`pwd`/fakegroups.py
44 > EOF
44 > EOF
45 > }
45 > }
46
46
47 $ cat << EOF >> $HGRCPATH
47 $ cat << EOF >> $HGRCPATH
48 > [experimental]
48 > [experimental]
49 > # drop me once bundle2 is the default,
49 > # drop me once bundle2 is the default,
50 > # added to get test change early.
50 > # added to get test change early.
51 > bundle2-exp = True
51 > bundle2-exp = True
52 > EOF
52 > EOF
53
53
54 $ hg init a
54 $ hg init a
55 $ cd a
55 $ cd a
56 $ mkdir foo foo/Bar quux
56 $ mkdir foo foo/Bar quux
57 $ echo 'in foo' > foo/file.txt
57 $ echo 'in foo' > foo/file.txt
58 $ echo 'in foo/Bar' > foo/Bar/file.txt
58 $ echo 'in foo/Bar' > foo/Bar/file.txt
59 $ echo 'in quux' > quux/file.py
59 $ echo 'in quux' > quux/file.py
60 $ hg add -q
60 $ hg add -q
61 $ hg ci -m 'add files' -d '1000000 0'
61 $ hg ci -m 'add files' -d '1000000 0'
62 $ echo >> foo/file.txt
62 $ echo >> foo/file.txt
63 $ hg ci -m 'change foo/file' -d '1000001 0'
63 $ hg ci -m 'change foo/file' -d '1000001 0'
64 $ echo >> foo/Bar/file.txt
64 $ echo >> foo/Bar/file.txt
65 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
65 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
66 $ echo >> quux/file.py
66 $ echo >> quux/file.py
67 $ hg ci -m 'change quux/file' -d '1000003 0'
67 $ hg ci -m 'change quux/file' -d '1000003 0'
68 $ hg tip --quiet
68 $ hg tip --quiet
69 3:911600dab2ae
69 3:911600dab2ae
70
70
71 $ cd ..
71 $ cd ..
72 $ hg clone -r 0 a b
72 $ hg clone -r 0 a b
73 adding changesets
73 adding changesets
74 adding manifests
74 adding manifests
75 adding file changes
75 adding file changes
76 added 1 changesets with 3 changes to 3 files
76 added 1 changesets with 3 changes to 3 files
77 updating to branch default
77 updating to branch default
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
79
79
80 $ config=b/.hg/hgrc
80 $ config=b/.hg/hgrc
81
81
82 Extension disabled for lack of a hook
82 Extension disabled for lack of a hook
83
83
84 $ do_push fred
84 $ do_push fred
85 Pushing as user fred
85 Pushing as user fred
86 hgrc = """
86 hgrc = """
87 """
87 """
88 pushing to ../b
88 pushing to ../b
89 query 1; heads
89 query 1; heads
90 searching for changes
90 searching for changes
91 all remote heads known locally
91 all remote heads known locally
92 listing keys for "phases"
92 listing keys for "phases"
93 checking for updated bookmarks
93 checking for updated bookmarks
94 listing keys for "bookmarks"
94 listing keys for "bookmarks"
95 listing keys for "bookmarks"
95 listing keys for "bookmarks"
96 3 changesets found
96 3 changesets found
97 list of changesets:
97 list of changesets:
98 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
98 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
99 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
99 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
100 911600dab2ae7a9baff75958b84fe606851ce955
100 911600dab2ae7a9baff75958b84fe606851ce955
101 bundle2-output-bundle: "HG20", 4 parts total
101 bundle2-output-bundle: "HG20", 4 parts total
102 bundle2-output-part: "replycaps" 147 bytes payload
102 bundle2-output-part: "replycaps" 155 bytes payload
103 bundle2-output-part: "check:heads" streamed payload
103 bundle2-output-part: "check:heads" streamed payload
104 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
104 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
105 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
105 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
106 bundle2-input-bundle: with-transaction
106 bundle2-input-bundle: with-transaction
107 bundle2-input-part: "replycaps" supported
107 bundle2-input-part: "replycaps" supported
108 bundle2-input-part: total payload size 147
108 bundle2-input-part: total payload size 155
109 bundle2-input-part: "check:heads" supported
109 bundle2-input-part: "check:heads" supported
110 bundle2-input-part: total payload size 20
110 bundle2-input-part: total payload size 20
111 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
111 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
112 adding changesets
112 adding changesets
113 add changeset ef1ea85a6374
113 add changeset ef1ea85a6374
114 add changeset f9cafe1212c8
114 add changeset f9cafe1212c8
115 add changeset 911600dab2ae
115 add changeset 911600dab2ae
116 adding manifests
116 adding manifests
117 adding file changes
117 adding file changes
118 adding foo/Bar/file.txt revisions
118 adding foo/Bar/file.txt revisions
119 adding foo/file.txt revisions
119 adding foo/file.txt revisions
120 adding quux/file.py revisions
120 adding quux/file.py revisions
121 added 3 changesets with 3 changes to 3 files
121 added 3 changesets with 3 changes to 3 files
122 bundle2-input-part: total payload size 1606
122 bundle2-input-part: total payload size 1606
123 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
123 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
124 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
124 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
125 bundle2-input-bundle: 3 parts total
125 bundle2-input-bundle: 3 parts total
126 updating the branch cache
126 updating the branch cache
127 bundle2-output-bundle: "HG20", 2 parts total
127 bundle2-output-bundle: "HG20", 2 parts total
128 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
128 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
129 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
129 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
130 bundle2-input-bundle: with-transaction
130 bundle2-input-bundle: with-transaction
131 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
131 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
132 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
132 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
133 bundle2-input-bundle: 1 parts total
133 bundle2-input-bundle: 1 parts total
134 listing keys for "phases"
134 listing keys for "phases"
135 try to push obsolete markers to remote
135 try to push obsolete markers to remote
136 repository tip rolled back to revision 0 (undo push)
136 repository tip rolled back to revision 0 (undo push)
137 0:6675d58eff77
137 0:6675d58eff77
138
138
139
139
140 $ echo '[hooks]' >> $config
140 $ echo '[hooks]' >> $config
141 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
141 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
142
142
143 Extension disabled for lack of acl.sources
143 Extension disabled for lack of acl.sources
144
144
145 $ do_push fred
145 $ do_push fred
146 Pushing as user fred
146 Pushing as user fred
147 hgrc = """
147 hgrc = """
148 [hooks]
148 [hooks]
149 pretxnchangegroup.acl = python:hgext.acl.hook
149 pretxnchangegroup.acl = python:hgext.acl.hook
150 """
150 """
151 pushing to ../b
151 pushing to ../b
152 query 1; heads
152 query 1; heads
153 searching for changes
153 searching for changes
154 all remote heads known locally
154 all remote heads known locally
155 listing keys for "phases"
155 listing keys for "phases"
156 checking for updated bookmarks
156 checking for updated bookmarks
157 listing keys for "bookmarks"
157 listing keys for "bookmarks"
158 invalid branchheads cache (served): tip differs
158 invalid branchheads cache (served): tip differs
159 listing keys for "bookmarks"
159 listing keys for "bookmarks"
160 3 changesets found
160 3 changesets found
161 list of changesets:
161 list of changesets:
162 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
162 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
163 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
163 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
164 911600dab2ae7a9baff75958b84fe606851ce955
164 911600dab2ae7a9baff75958b84fe606851ce955
165 bundle2-output-bundle: "HG20", 4 parts total
165 bundle2-output-bundle: "HG20", 4 parts total
166 bundle2-output-part: "replycaps" 147 bytes payload
166 bundle2-output-part: "replycaps" 155 bytes payload
167 bundle2-output-part: "check:heads" streamed payload
167 bundle2-output-part: "check:heads" streamed payload
168 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
168 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
169 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
169 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
170 bundle2-input-bundle: with-transaction
170 bundle2-input-bundle: with-transaction
171 bundle2-input-part: "replycaps" supported
171 bundle2-input-part: "replycaps" supported
172 bundle2-input-part: total payload size 147
172 bundle2-input-part: total payload size 155
173 bundle2-input-part: "check:heads" supported
173 bundle2-input-part: "check:heads" supported
174 bundle2-input-part: total payload size 20
174 bundle2-input-part: total payload size 20
175 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
175 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
176 adding changesets
176 adding changesets
177 add changeset ef1ea85a6374
177 add changeset ef1ea85a6374
178 add changeset f9cafe1212c8
178 add changeset f9cafe1212c8
179 add changeset 911600dab2ae
179 add changeset 911600dab2ae
180 adding manifests
180 adding manifests
181 adding file changes
181 adding file changes
182 adding foo/Bar/file.txt revisions
182 adding foo/Bar/file.txt revisions
183 adding foo/file.txt revisions
183 adding foo/file.txt revisions
184 adding quux/file.py revisions
184 adding quux/file.py revisions
185 added 3 changesets with 3 changes to 3 files
185 added 3 changesets with 3 changes to 3 files
186 calling hook pretxnchangegroup.acl: hgext.acl.hook
186 calling hook pretxnchangegroup.acl: hgext.acl.hook
187 acl: changes have source "push" - skipping
187 acl: changes have source "push" - skipping
188 bundle2-input-part: total payload size 1606
188 bundle2-input-part: total payload size 1606
189 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
189 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
190 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
190 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
191 bundle2-input-bundle: 3 parts total
191 bundle2-input-bundle: 3 parts total
192 updating the branch cache
192 updating the branch cache
193 bundle2-output-bundle: "HG20", 2 parts total
193 bundle2-output-bundle: "HG20", 2 parts total
194 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
194 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
195 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
195 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
196 bundle2-input-bundle: with-transaction
196 bundle2-input-bundle: with-transaction
197 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
197 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
198 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
198 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
199 bundle2-input-bundle: 1 parts total
199 bundle2-input-bundle: 1 parts total
200 listing keys for "phases"
200 listing keys for "phases"
201 try to push obsolete markers to remote
201 try to push obsolete markers to remote
202 repository tip rolled back to revision 0 (undo push)
202 repository tip rolled back to revision 0 (undo push)
203 0:6675d58eff77
203 0:6675d58eff77
204
204
205
205
206 No [acl.allow]/[acl.deny]
206 No [acl.allow]/[acl.deny]
207
207
208 $ echo '[acl]' >> $config
208 $ echo '[acl]' >> $config
209 $ echo 'sources = push' >> $config
209 $ echo 'sources = push' >> $config
210 $ do_push fred
210 $ do_push fred
211 Pushing as user fred
211 Pushing as user fred
212 hgrc = """
212 hgrc = """
213 [hooks]
213 [hooks]
214 pretxnchangegroup.acl = python:hgext.acl.hook
214 pretxnchangegroup.acl = python:hgext.acl.hook
215 [acl]
215 [acl]
216 sources = push
216 sources = push
217 """
217 """
218 pushing to ../b
218 pushing to ../b
219 query 1; heads
219 query 1; heads
220 searching for changes
220 searching for changes
221 all remote heads known locally
221 all remote heads known locally
222 listing keys for "phases"
222 listing keys for "phases"
223 checking for updated bookmarks
223 checking for updated bookmarks
224 listing keys for "bookmarks"
224 listing keys for "bookmarks"
225 invalid branchheads cache (served): tip differs
225 invalid branchheads cache (served): tip differs
226 listing keys for "bookmarks"
226 listing keys for "bookmarks"
227 3 changesets found
227 3 changesets found
228 list of changesets:
228 list of changesets:
229 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
229 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
230 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
230 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
231 911600dab2ae7a9baff75958b84fe606851ce955
231 911600dab2ae7a9baff75958b84fe606851ce955
232 bundle2-output-bundle: "HG20", 4 parts total
232 bundle2-output-bundle: "HG20", 4 parts total
233 bundle2-output-part: "replycaps" 147 bytes payload
233 bundle2-output-part: "replycaps" 155 bytes payload
234 bundle2-output-part: "check:heads" streamed payload
234 bundle2-output-part: "check:heads" streamed payload
235 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
235 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
236 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
236 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
237 bundle2-input-bundle: with-transaction
237 bundle2-input-bundle: with-transaction
238 bundle2-input-part: "replycaps" supported
238 bundle2-input-part: "replycaps" supported
239 bundle2-input-part: total payload size 147
239 bundle2-input-part: total payload size 155
240 bundle2-input-part: "check:heads" supported
240 bundle2-input-part: "check:heads" supported
241 bundle2-input-part: total payload size 20
241 bundle2-input-part: total payload size 20
242 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
242 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
243 adding changesets
243 adding changesets
244 add changeset ef1ea85a6374
244 add changeset ef1ea85a6374
245 add changeset f9cafe1212c8
245 add changeset f9cafe1212c8
246 add changeset 911600dab2ae
246 add changeset 911600dab2ae
247 adding manifests
247 adding manifests
248 adding file changes
248 adding file changes
249 adding foo/Bar/file.txt revisions
249 adding foo/Bar/file.txt revisions
250 adding foo/file.txt revisions
250 adding foo/file.txt revisions
251 adding quux/file.py revisions
251 adding quux/file.py revisions
252 added 3 changesets with 3 changes to 3 files
252 added 3 changesets with 3 changes to 3 files
253 calling hook pretxnchangegroup.acl: hgext.acl.hook
253 calling hook pretxnchangegroup.acl: hgext.acl.hook
254 acl: checking access for user "fred"
254 acl: checking access for user "fred"
255 acl: acl.allow.branches not enabled
255 acl: acl.allow.branches not enabled
256 acl: acl.deny.branches not enabled
256 acl: acl.deny.branches not enabled
257 acl: acl.allow not enabled
257 acl: acl.allow not enabled
258 acl: acl.deny not enabled
258 acl: acl.deny not enabled
259 acl: branch access granted: "ef1ea85a6374" on branch "default"
259 acl: branch access granted: "ef1ea85a6374" on branch "default"
260 acl: path access granted: "ef1ea85a6374"
260 acl: path access granted: "ef1ea85a6374"
261 acl: branch access granted: "f9cafe1212c8" on branch "default"
261 acl: branch access granted: "f9cafe1212c8" on branch "default"
262 acl: path access granted: "f9cafe1212c8"
262 acl: path access granted: "f9cafe1212c8"
263 acl: branch access granted: "911600dab2ae" on branch "default"
263 acl: branch access granted: "911600dab2ae" on branch "default"
264 acl: path access granted: "911600dab2ae"
264 acl: path access granted: "911600dab2ae"
265 bundle2-input-part: total payload size 1606
265 bundle2-input-part: total payload size 1606
266 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
266 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
267 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
267 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
268 bundle2-input-bundle: 3 parts total
268 bundle2-input-bundle: 3 parts total
269 updating the branch cache
269 updating the branch cache
270 bundle2-output-bundle: "HG20", 2 parts total
270 bundle2-output-bundle: "HG20", 2 parts total
271 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
271 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
272 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
272 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
273 bundle2-input-bundle: with-transaction
273 bundle2-input-bundle: with-transaction
274 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
274 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
275 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
275 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
276 bundle2-input-bundle: 1 parts total
276 bundle2-input-bundle: 1 parts total
277 listing keys for "phases"
277 listing keys for "phases"
278 try to push obsolete markers to remote
278 try to push obsolete markers to remote
279 repository tip rolled back to revision 0 (undo push)
279 repository tip rolled back to revision 0 (undo push)
280 0:6675d58eff77
280 0:6675d58eff77
281
281
282
282
283 Empty [acl.allow]
283 Empty [acl.allow]
284
284
285 $ echo '[acl.allow]' >> $config
285 $ echo '[acl.allow]' >> $config
286 $ do_push fred
286 $ do_push fred
287 Pushing as user fred
287 Pushing as user fred
288 hgrc = """
288 hgrc = """
289 [hooks]
289 [hooks]
290 pretxnchangegroup.acl = python:hgext.acl.hook
290 pretxnchangegroup.acl = python:hgext.acl.hook
291 [acl]
291 [acl]
292 sources = push
292 sources = push
293 [acl.allow]
293 [acl.allow]
294 """
294 """
295 pushing to ../b
295 pushing to ../b
296 query 1; heads
296 query 1; heads
297 searching for changes
297 searching for changes
298 all remote heads known locally
298 all remote heads known locally
299 listing keys for "phases"
299 listing keys for "phases"
300 checking for updated bookmarks
300 checking for updated bookmarks
301 listing keys for "bookmarks"
301 listing keys for "bookmarks"
302 invalid branchheads cache (served): tip differs
302 invalid branchheads cache (served): tip differs
303 listing keys for "bookmarks"
303 listing keys for "bookmarks"
304 3 changesets found
304 3 changesets found
305 list of changesets:
305 list of changesets:
306 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
306 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
307 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
307 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
308 911600dab2ae7a9baff75958b84fe606851ce955
308 911600dab2ae7a9baff75958b84fe606851ce955
309 bundle2-output-bundle: "HG20", 4 parts total
309 bundle2-output-bundle: "HG20", 4 parts total
310 bundle2-output-part: "replycaps" 147 bytes payload
310 bundle2-output-part: "replycaps" 155 bytes payload
311 bundle2-output-part: "check:heads" streamed payload
311 bundle2-output-part: "check:heads" streamed payload
312 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
312 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
313 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
313 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
314 bundle2-input-bundle: with-transaction
314 bundle2-input-bundle: with-transaction
315 bundle2-input-part: "replycaps" supported
315 bundle2-input-part: "replycaps" supported
316 bundle2-input-part: total payload size 147
316 bundle2-input-part: total payload size 155
317 bundle2-input-part: "check:heads" supported
317 bundle2-input-part: "check:heads" supported
318 bundle2-input-part: total payload size 20
318 bundle2-input-part: total payload size 20
319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
320 adding changesets
320 adding changesets
321 add changeset ef1ea85a6374
321 add changeset ef1ea85a6374
322 add changeset f9cafe1212c8
322 add changeset f9cafe1212c8
323 add changeset 911600dab2ae
323 add changeset 911600dab2ae
324 adding manifests
324 adding manifests
325 adding file changes
325 adding file changes
326 adding foo/Bar/file.txt revisions
326 adding foo/Bar/file.txt revisions
327 adding foo/file.txt revisions
327 adding foo/file.txt revisions
328 adding quux/file.py revisions
328 adding quux/file.py revisions
329 added 3 changesets with 3 changes to 3 files
329 added 3 changesets with 3 changes to 3 files
330 calling hook pretxnchangegroup.acl: hgext.acl.hook
330 calling hook pretxnchangegroup.acl: hgext.acl.hook
331 acl: checking access for user "fred"
331 acl: checking access for user "fred"
332 acl: acl.allow.branches not enabled
332 acl: acl.allow.branches not enabled
333 acl: acl.deny.branches not enabled
333 acl: acl.deny.branches not enabled
334 acl: acl.allow enabled, 0 entries for user fred
334 acl: acl.allow enabled, 0 entries for user fred
335 acl: acl.deny not enabled
335 acl: acl.deny not enabled
336 acl: branch access granted: "ef1ea85a6374" on branch "default"
336 acl: branch access granted: "ef1ea85a6374" on branch "default"
337 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
337 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
338 bundle2-input-part: total payload size 1606
338 bundle2-input-part: total payload size 1606
339 bundle2-input-bundle: 3 parts total
339 bundle2-input-bundle: 3 parts total
340 transaction abort!
340 transaction abort!
341 rollback completed
341 rollback completed
342 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
342 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
343 no rollback information available
343 no rollback information available
344 0:6675d58eff77
344 0:6675d58eff77
345
345
346
346
347 fred is allowed inside foo/
347 fred is allowed inside foo/
348
348
349 $ echo 'foo/** = fred' >> $config
349 $ echo 'foo/** = fred' >> $config
350 $ do_push fred
350 $ do_push fred
351 Pushing as user fred
351 Pushing as user fred
352 hgrc = """
352 hgrc = """
353 [hooks]
353 [hooks]
354 pretxnchangegroup.acl = python:hgext.acl.hook
354 pretxnchangegroup.acl = python:hgext.acl.hook
355 [acl]
355 [acl]
356 sources = push
356 sources = push
357 [acl.allow]
357 [acl.allow]
358 foo/** = fred
358 foo/** = fred
359 """
359 """
360 pushing to ../b
360 pushing to ../b
361 query 1; heads
361 query 1; heads
362 searching for changes
362 searching for changes
363 all remote heads known locally
363 all remote heads known locally
364 listing keys for "phases"
364 listing keys for "phases"
365 checking for updated bookmarks
365 checking for updated bookmarks
366 listing keys for "bookmarks"
366 listing keys for "bookmarks"
367 invalid branchheads cache (served): tip differs
367 invalid branchheads cache (served): tip differs
368 listing keys for "bookmarks"
368 listing keys for "bookmarks"
369 3 changesets found
369 3 changesets found
370 list of changesets:
370 list of changesets:
371 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
371 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
372 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
372 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
373 911600dab2ae7a9baff75958b84fe606851ce955
373 911600dab2ae7a9baff75958b84fe606851ce955
374 bundle2-output-bundle: "HG20", 4 parts total
374 bundle2-output-bundle: "HG20", 4 parts total
375 bundle2-output-part: "replycaps" 147 bytes payload
375 bundle2-output-part: "replycaps" 155 bytes payload
376 bundle2-output-part: "check:heads" streamed payload
376 bundle2-output-part: "check:heads" streamed payload
377 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
377 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
378 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
378 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
379 bundle2-input-bundle: with-transaction
379 bundle2-input-bundle: with-transaction
380 bundle2-input-part: "replycaps" supported
380 bundle2-input-part: "replycaps" supported
381 bundle2-input-part: total payload size 147
381 bundle2-input-part: total payload size 155
382 bundle2-input-part: "check:heads" supported
382 bundle2-input-part: "check:heads" supported
383 bundle2-input-part: total payload size 20
383 bundle2-input-part: total payload size 20
384 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
384 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
385 adding changesets
385 adding changesets
386 add changeset ef1ea85a6374
386 add changeset ef1ea85a6374
387 add changeset f9cafe1212c8
387 add changeset f9cafe1212c8
388 add changeset 911600dab2ae
388 add changeset 911600dab2ae
389 adding manifests
389 adding manifests
390 adding file changes
390 adding file changes
391 adding foo/Bar/file.txt revisions
391 adding foo/Bar/file.txt revisions
392 adding foo/file.txt revisions
392 adding foo/file.txt revisions
393 adding quux/file.py revisions
393 adding quux/file.py revisions
394 added 3 changesets with 3 changes to 3 files
394 added 3 changesets with 3 changes to 3 files
395 calling hook pretxnchangegroup.acl: hgext.acl.hook
395 calling hook pretxnchangegroup.acl: hgext.acl.hook
396 acl: checking access for user "fred"
396 acl: checking access for user "fred"
397 acl: acl.allow.branches not enabled
397 acl: acl.allow.branches not enabled
398 acl: acl.deny.branches not enabled
398 acl: acl.deny.branches not enabled
399 acl: acl.allow enabled, 1 entries for user fred
399 acl: acl.allow enabled, 1 entries for user fred
400 acl: acl.deny not enabled
400 acl: acl.deny not enabled
401 acl: branch access granted: "ef1ea85a6374" on branch "default"
401 acl: branch access granted: "ef1ea85a6374" on branch "default"
402 acl: path access granted: "ef1ea85a6374"
402 acl: path access granted: "ef1ea85a6374"
403 acl: branch access granted: "f9cafe1212c8" on branch "default"
403 acl: branch access granted: "f9cafe1212c8" on branch "default"
404 acl: path access granted: "f9cafe1212c8"
404 acl: path access granted: "f9cafe1212c8"
405 acl: branch access granted: "911600dab2ae" on branch "default"
405 acl: branch access granted: "911600dab2ae" on branch "default"
406 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
406 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
407 bundle2-input-part: total payload size 1606
407 bundle2-input-part: total payload size 1606
408 bundle2-input-bundle: 3 parts total
408 bundle2-input-bundle: 3 parts total
409 transaction abort!
409 transaction abort!
410 rollback completed
410 rollback completed
411 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
411 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
412 no rollback information available
412 no rollback information available
413 0:6675d58eff77
413 0:6675d58eff77
414
414
415
415
416 Empty [acl.deny]
416 Empty [acl.deny]
417
417
418 $ echo '[acl.deny]' >> $config
418 $ echo '[acl.deny]' >> $config
419 $ do_push barney
419 $ do_push barney
420 Pushing as user barney
420 Pushing as user barney
421 hgrc = """
421 hgrc = """
422 [hooks]
422 [hooks]
423 pretxnchangegroup.acl = python:hgext.acl.hook
423 pretxnchangegroup.acl = python:hgext.acl.hook
424 [acl]
424 [acl]
425 sources = push
425 sources = push
426 [acl.allow]
426 [acl.allow]
427 foo/** = fred
427 foo/** = fred
428 [acl.deny]
428 [acl.deny]
429 """
429 """
430 pushing to ../b
430 pushing to ../b
431 query 1; heads
431 query 1; heads
432 searching for changes
432 searching for changes
433 all remote heads known locally
433 all remote heads known locally
434 listing keys for "phases"
434 listing keys for "phases"
435 checking for updated bookmarks
435 checking for updated bookmarks
436 listing keys for "bookmarks"
436 listing keys for "bookmarks"
437 invalid branchheads cache (served): tip differs
437 invalid branchheads cache (served): tip differs
438 listing keys for "bookmarks"
438 listing keys for "bookmarks"
439 3 changesets found
439 3 changesets found
440 list of changesets:
440 list of changesets:
441 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
441 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
442 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
442 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
443 911600dab2ae7a9baff75958b84fe606851ce955
443 911600dab2ae7a9baff75958b84fe606851ce955
444 bundle2-output-bundle: "HG20", 4 parts total
444 bundle2-output-bundle: "HG20", 4 parts total
445 bundle2-output-part: "replycaps" 147 bytes payload
445 bundle2-output-part: "replycaps" 155 bytes payload
446 bundle2-output-part: "check:heads" streamed payload
446 bundle2-output-part: "check:heads" streamed payload
447 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
447 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
448 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
448 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
449 bundle2-input-bundle: with-transaction
449 bundle2-input-bundle: with-transaction
450 bundle2-input-part: "replycaps" supported
450 bundle2-input-part: "replycaps" supported
451 bundle2-input-part: total payload size 147
451 bundle2-input-part: total payload size 155
452 bundle2-input-part: "check:heads" supported
452 bundle2-input-part: "check:heads" supported
453 bundle2-input-part: total payload size 20
453 bundle2-input-part: total payload size 20
454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
455 adding changesets
455 adding changesets
456 add changeset ef1ea85a6374
456 add changeset ef1ea85a6374
457 add changeset f9cafe1212c8
457 add changeset f9cafe1212c8
458 add changeset 911600dab2ae
458 add changeset 911600dab2ae
459 adding manifests
459 adding manifests
460 adding file changes
460 adding file changes
461 adding foo/Bar/file.txt revisions
461 adding foo/Bar/file.txt revisions
462 adding foo/file.txt revisions
462 adding foo/file.txt revisions
463 adding quux/file.py revisions
463 adding quux/file.py revisions
464 added 3 changesets with 3 changes to 3 files
464 added 3 changesets with 3 changes to 3 files
465 calling hook pretxnchangegroup.acl: hgext.acl.hook
465 calling hook pretxnchangegroup.acl: hgext.acl.hook
466 acl: checking access for user "barney"
466 acl: checking access for user "barney"
467 acl: acl.allow.branches not enabled
467 acl: acl.allow.branches not enabled
468 acl: acl.deny.branches not enabled
468 acl: acl.deny.branches not enabled
469 acl: acl.allow enabled, 0 entries for user barney
469 acl: acl.allow enabled, 0 entries for user barney
470 acl: acl.deny enabled, 0 entries for user barney
470 acl: acl.deny enabled, 0 entries for user barney
471 acl: branch access granted: "ef1ea85a6374" on branch "default"
471 acl: branch access granted: "ef1ea85a6374" on branch "default"
472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
473 bundle2-input-part: total payload size 1606
473 bundle2-input-part: total payload size 1606
474 bundle2-input-bundle: 3 parts total
474 bundle2-input-bundle: 3 parts total
475 transaction abort!
475 transaction abort!
476 rollback completed
476 rollback completed
477 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
477 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
478 no rollback information available
478 no rollback information available
479 0:6675d58eff77
479 0:6675d58eff77
480
480
481
481
482 fred is allowed inside foo/, but not foo/bar/ (case matters)
482 fred is allowed inside foo/, but not foo/bar/ (case matters)
483
483
484 $ echo 'foo/bar/** = fred' >> $config
484 $ echo 'foo/bar/** = fred' >> $config
485 $ do_push fred
485 $ do_push fred
486 Pushing as user fred
486 Pushing as user fred
487 hgrc = """
487 hgrc = """
488 [hooks]
488 [hooks]
489 pretxnchangegroup.acl = python:hgext.acl.hook
489 pretxnchangegroup.acl = python:hgext.acl.hook
490 [acl]
490 [acl]
491 sources = push
491 sources = push
492 [acl.allow]
492 [acl.allow]
493 foo/** = fred
493 foo/** = fred
494 [acl.deny]
494 [acl.deny]
495 foo/bar/** = fred
495 foo/bar/** = fred
496 """
496 """
497 pushing to ../b
497 pushing to ../b
498 query 1; heads
498 query 1; heads
499 searching for changes
499 searching for changes
500 all remote heads known locally
500 all remote heads known locally
501 listing keys for "phases"
501 listing keys for "phases"
502 checking for updated bookmarks
502 checking for updated bookmarks
503 listing keys for "bookmarks"
503 listing keys for "bookmarks"
504 invalid branchheads cache (served): tip differs
504 invalid branchheads cache (served): tip differs
505 listing keys for "bookmarks"
505 listing keys for "bookmarks"
506 3 changesets found
506 3 changesets found
507 list of changesets:
507 list of changesets:
508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
510 911600dab2ae7a9baff75958b84fe606851ce955
510 911600dab2ae7a9baff75958b84fe606851ce955
511 bundle2-output-bundle: "HG20", 4 parts total
511 bundle2-output-bundle: "HG20", 4 parts total
512 bundle2-output-part: "replycaps" 147 bytes payload
512 bundle2-output-part: "replycaps" 155 bytes payload
513 bundle2-output-part: "check:heads" streamed payload
513 bundle2-output-part: "check:heads" streamed payload
514 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
514 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
515 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
515 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
516 bundle2-input-bundle: with-transaction
516 bundle2-input-bundle: with-transaction
517 bundle2-input-part: "replycaps" supported
517 bundle2-input-part: "replycaps" supported
518 bundle2-input-part: total payload size 147
518 bundle2-input-part: total payload size 155
519 bundle2-input-part: "check:heads" supported
519 bundle2-input-part: "check:heads" supported
520 bundle2-input-part: total payload size 20
520 bundle2-input-part: total payload size 20
521 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
521 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
522 adding changesets
522 adding changesets
523 add changeset ef1ea85a6374
523 add changeset ef1ea85a6374
524 add changeset f9cafe1212c8
524 add changeset f9cafe1212c8
525 add changeset 911600dab2ae
525 add changeset 911600dab2ae
526 adding manifests
526 adding manifests
527 adding file changes
527 adding file changes
528 adding foo/Bar/file.txt revisions
528 adding foo/Bar/file.txt revisions
529 adding foo/file.txt revisions
529 adding foo/file.txt revisions
530 adding quux/file.py revisions
530 adding quux/file.py revisions
531 added 3 changesets with 3 changes to 3 files
531 added 3 changesets with 3 changes to 3 files
532 calling hook pretxnchangegroup.acl: hgext.acl.hook
532 calling hook pretxnchangegroup.acl: hgext.acl.hook
533 acl: checking access for user "fred"
533 acl: checking access for user "fred"
534 acl: acl.allow.branches not enabled
534 acl: acl.allow.branches not enabled
535 acl: acl.deny.branches not enabled
535 acl: acl.deny.branches not enabled
536 acl: acl.allow enabled, 1 entries for user fred
536 acl: acl.allow enabled, 1 entries for user fred
537 acl: acl.deny enabled, 1 entries for user fred
537 acl: acl.deny enabled, 1 entries for user fred
538 acl: branch access granted: "ef1ea85a6374" on branch "default"
538 acl: branch access granted: "ef1ea85a6374" on branch "default"
539 acl: path access granted: "ef1ea85a6374"
539 acl: path access granted: "ef1ea85a6374"
540 acl: branch access granted: "f9cafe1212c8" on branch "default"
540 acl: branch access granted: "f9cafe1212c8" on branch "default"
541 acl: path access granted: "f9cafe1212c8"
541 acl: path access granted: "f9cafe1212c8"
542 acl: branch access granted: "911600dab2ae" on branch "default"
542 acl: branch access granted: "911600dab2ae" on branch "default"
543 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
543 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
544 bundle2-input-part: total payload size 1606
544 bundle2-input-part: total payload size 1606
545 bundle2-input-bundle: 3 parts total
545 bundle2-input-bundle: 3 parts total
546 transaction abort!
546 transaction abort!
547 rollback completed
547 rollback completed
548 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
548 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
549 no rollback information available
549 no rollback information available
550 0:6675d58eff77
550 0:6675d58eff77
551
551
552
552
553 fred is allowed inside foo/, but not foo/Bar/
553 fred is allowed inside foo/, but not foo/Bar/
554
554
555 $ echo 'foo/Bar/** = fred' >> $config
555 $ echo 'foo/Bar/** = fred' >> $config
556 $ do_push fred
556 $ do_push fred
557 Pushing as user fred
557 Pushing as user fred
558 hgrc = """
558 hgrc = """
559 [hooks]
559 [hooks]
560 pretxnchangegroup.acl = python:hgext.acl.hook
560 pretxnchangegroup.acl = python:hgext.acl.hook
561 [acl]
561 [acl]
562 sources = push
562 sources = push
563 [acl.allow]
563 [acl.allow]
564 foo/** = fred
564 foo/** = fred
565 [acl.deny]
565 [acl.deny]
566 foo/bar/** = fred
566 foo/bar/** = fred
567 foo/Bar/** = fred
567 foo/Bar/** = fred
568 """
568 """
569 pushing to ../b
569 pushing to ../b
570 query 1; heads
570 query 1; heads
571 searching for changes
571 searching for changes
572 all remote heads known locally
572 all remote heads known locally
573 listing keys for "phases"
573 listing keys for "phases"
574 checking for updated bookmarks
574 checking for updated bookmarks
575 listing keys for "bookmarks"
575 listing keys for "bookmarks"
576 invalid branchheads cache (served): tip differs
576 invalid branchheads cache (served): tip differs
577 listing keys for "bookmarks"
577 listing keys for "bookmarks"
578 3 changesets found
578 3 changesets found
579 list of changesets:
579 list of changesets:
580 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
580 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
581 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
581 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
582 911600dab2ae7a9baff75958b84fe606851ce955
582 911600dab2ae7a9baff75958b84fe606851ce955
583 bundle2-output-bundle: "HG20", 4 parts total
583 bundle2-output-bundle: "HG20", 4 parts total
584 bundle2-output-part: "replycaps" 147 bytes payload
584 bundle2-output-part: "replycaps" 155 bytes payload
585 bundle2-output-part: "check:heads" streamed payload
585 bundle2-output-part: "check:heads" streamed payload
586 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
586 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
587 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
587 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
588 bundle2-input-bundle: with-transaction
588 bundle2-input-bundle: with-transaction
589 bundle2-input-part: "replycaps" supported
589 bundle2-input-part: "replycaps" supported
590 bundle2-input-part: total payload size 147
590 bundle2-input-part: total payload size 155
591 bundle2-input-part: "check:heads" supported
591 bundle2-input-part: "check:heads" supported
592 bundle2-input-part: total payload size 20
592 bundle2-input-part: total payload size 20
593 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
593 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
594 adding changesets
594 adding changesets
595 add changeset ef1ea85a6374
595 add changeset ef1ea85a6374
596 add changeset f9cafe1212c8
596 add changeset f9cafe1212c8
597 add changeset 911600dab2ae
597 add changeset 911600dab2ae
598 adding manifests
598 adding manifests
599 adding file changes
599 adding file changes
600 adding foo/Bar/file.txt revisions
600 adding foo/Bar/file.txt revisions
601 adding foo/file.txt revisions
601 adding foo/file.txt revisions
602 adding quux/file.py revisions
602 adding quux/file.py revisions
603 added 3 changesets with 3 changes to 3 files
603 added 3 changesets with 3 changes to 3 files
604 calling hook pretxnchangegroup.acl: hgext.acl.hook
604 calling hook pretxnchangegroup.acl: hgext.acl.hook
605 acl: checking access for user "fred"
605 acl: checking access for user "fred"
606 acl: acl.allow.branches not enabled
606 acl: acl.allow.branches not enabled
607 acl: acl.deny.branches not enabled
607 acl: acl.deny.branches not enabled
608 acl: acl.allow enabled, 1 entries for user fred
608 acl: acl.allow enabled, 1 entries for user fred
609 acl: acl.deny enabled, 2 entries for user fred
609 acl: acl.deny enabled, 2 entries for user fred
610 acl: branch access granted: "ef1ea85a6374" on branch "default"
610 acl: branch access granted: "ef1ea85a6374" on branch "default"
611 acl: path access granted: "ef1ea85a6374"
611 acl: path access granted: "ef1ea85a6374"
612 acl: branch access granted: "f9cafe1212c8" on branch "default"
612 acl: branch access granted: "f9cafe1212c8" on branch "default"
613 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
613 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
614 bundle2-input-part: total payload size 1606
614 bundle2-input-part: total payload size 1606
615 bundle2-input-bundle: 3 parts total
615 bundle2-input-bundle: 3 parts total
616 transaction abort!
616 transaction abort!
617 rollback completed
617 rollback completed
618 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
618 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
619 no rollback information available
619 no rollback information available
620 0:6675d58eff77
620 0:6675d58eff77
621
621
622
622
623 $ echo 'barney is not mentioned => not allowed anywhere'
623 $ echo 'barney is not mentioned => not allowed anywhere'
624 barney is not mentioned => not allowed anywhere
624 barney is not mentioned => not allowed anywhere
625 $ do_push barney
625 $ do_push barney
626 Pushing as user barney
626 Pushing as user barney
627 hgrc = """
627 hgrc = """
628 [hooks]
628 [hooks]
629 pretxnchangegroup.acl = python:hgext.acl.hook
629 pretxnchangegroup.acl = python:hgext.acl.hook
630 [acl]
630 [acl]
631 sources = push
631 sources = push
632 [acl.allow]
632 [acl.allow]
633 foo/** = fred
633 foo/** = fred
634 [acl.deny]
634 [acl.deny]
635 foo/bar/** = fred
635 foo/bar/** = fred
636 foo/Bar/** = fred
636 foo/Bar/** = fred
637 """
637 """
638 pushing to ../b
638 pushing to ../b
639 query 1; heads
639 query 1; heads
640 searching for changes
640 searching for changes
641 all remote heads known locally
641 all remote heads known locally
642 listing keys for "phases"
642 listing keys for "phases"
643 checking for updated bookmarks
643 checking for updated bookmarks
644 listing keys for "bookmarks"
644 listing keys for "bookmarks"
645 invalid branchheads cache (served): tip differs
645 invalid branchheads cache (served): tip differs
646 listing keys for "bookmarks"
646 listing keys for "bookmarks"
647 3 changesets found
647 3 changesets found
648 list of changesets:
648 list of changesets:
649 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
649 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
650 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
650 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
651 911600dab2ae7a9baff75958b84fe606851ce955
651 911600dab2ae7a9baff75958b84fe606851ce955
652 bundle2-output-bundle: "HG20", 4 parts total
652 bundle2-output-bundle: "HG20", 4 parts total
653 bundle2-output-part: "replycaps" 147 bytes payload
653 bundle2-output-part: "replycaps" 155 bytes payload
654 bundle2-output-part: "check:heads" streamed payload
654 bundle2-output-part: "check:heads" streamed payload
655 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
655 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
656 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
656 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
657 bundle2-input-bundle: with-transaction
657 bundle2-input-bundle: with-transaction
658 bundle2-input-part: "replycaps" supported
658 bundle2-input-part: "replycaps" supported
659 bundle2-input-part: total payload size 147
659 bundle2-input-part: total payload size 155
660 bundle2-input-part: "check:heads" supported
660 bundle2-input-part: "check:heads" supported
661 bundle2-input-part: total payload size 20
661 bundle2-input-part: total payload size 20
662 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
662 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
663 adding changesets
663 adding changesets
664 add changeset ef1ea85a6374
664 add changeset ef1ea85a6374
665 add changeset f9cafe1212c8
665 add changeset f9cafe1212c8
666 add changeset 911600dab2ae
666 add changeset 911600dab2ae
667 adding manifests
667 adding manifests
668 adding file changes
668 adding file changes
669 adding foo/Bar/file.txt revisions
669 adding foo/Bar/file.txt revisions
670 adding foo/file.txt revisions
670 adding foo/file.txt revisions
671 adding quux/file.py revisions
671 adding quux/file.py revisions
672 added 3 changesets with 3 changes to 3 files
672 added 3 changesets with 3 changes to 3 files
673 calling hook pretxnchangegroup.acl: hgext.acl.hook
673 calling hook pretxnchangegroup.acl: hgext.acl.hook
674 acl: checking access for user "barney"
674 acl: checking access for user "barney"
675 acl: acl.allow.branches not enabled
675 acl: acl.allow.branches not enabled
676 acl: acl.deny.branches not enabled
676 acl: acl.deny.branches not enabled
677 acl: acl.allow enabled, 0 entries for user barney
677 acl: acl.allow enabled, 0 entries for user barney
678 acl: acl.deny enabled, 0 entries for user barney
678 acl: acl.deny enabled, 0 entries for user barney
679 acl: branch access granted: "ef1ea85a6374" on branch "default"
679 acl: branch access granted: "ef1ea85a6374" on branch "default"
680 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
680 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
681 bundle2-input-part: total payload size 1606
681 bundle2-input-part: total payload size 1606
682 bundle2-input-bundle: 3 parts total
682 bundle2-input-bundle: 3 parts total
683 transaction abort!
683 transaction abort!
684 rollback completed
684 rollback completed
685 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
685 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
686 no rollback information available
686 no rollback information available
687 0:6675d58eff77
687 0:6675d58eff77
688
688
689
689
690 barney is allowed everywhere
690 barney is allowed everywhere
691
691
692 $ echo '[acl.allow]' >> $config
692 $ echo '[acl.allow]' >> $config
693 $ echo '** = barney' >> $config
693 $ echo '** = barney' >> $config
694 $ do_push barney
694 $ do_push barney
695 Pushing as user barney
695 Pushing as user barney
696 hgrc = """
696 hgrc = """
697 [hooks]
697 [hooks]
698 pretxnchangegroup.acl = python:hgext.acl.hook
698 pretxnchangegroup.acl = python:hgext.acl.hook
699 [acl]
699 [acl]
700 sources = push
700 sources = push
701 [acl.allow]
701 [acl.allow]
702 foo/** = fred
702 foo/** = fred
703 [acl.deny]
703 [acl.deny]
704 foo/bar/** = fred
704 foo/bar/** = fred
705 foo/Bar/** = fred
705 foo/Bar/** = fred
706 [acl.allow]
706 [acl.allow]
707 ** = barney
707 ** = barney
708 """
708 """
709 pushing to ../b
709 pushing to ../b
710 query 1; heads
710 query 1; heads
711 searching for changes
711 searching for changes
712 all remote heads known locally
712 all remote heads known locally
713 listing keys for "phases"
713 listing keys for "phases"
714 checking for updated bookmarks
714 checking for updated bookmarks
715 listing keys for "bookmarks"
715 listing keys for "bookmarks"
716 invalid branchheads cache (served): tip differs
716 invalid branchheads cache (served): tip differs
717 listing keys for "bookmarks"
717 listing keys for "bookmarks"
718 3 changesets found
718 3 changesets found
719 list of changesets:
719 list of changesets:
720 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
720 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
721 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
721 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
722 911600dab2ae7a9baff75958b84fe606851ce955
722 911600dab2ae7a9baff75958b84fe606851ce955
723 bundle2-output-bundle: "HG20", 4 parts total
723 bundle2-output-bundle: "HG20", 4 parts total
724 bundle2-output-part: "replycaps" 147 bytes payload
724 bundle2-output-part: "replycaps" 155 bytes payload
725 bundle2-output-part: "check:heads" streamed payload
725 bundle2-output-part: "check:heads" streamed payload
726 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
726 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
727 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
727 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
728 bundle2-input-bundle: with-transaction
728 bundle2-input-bundle: with-transaction
729 bundle2-input-part: "replycaps" supported
729 bundle2-input-part: "replycaps" supported
730 bundle2-input-part: total payload size 147
730 bundle2-input-part: total payload size 155
731 bundle2-input-part: "check:heads" supported
731 bundle2-input-part: "check:heads" supported
732 bundle2-input-part: total payload size 20
732 bundle2-input-part: total payload size 20
733 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
733 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
734 adding changesets
734 adding changesets
735 add changeset ef1ea85a6374
735 add changeset ef1ea85a6374
736 add changeset f9cafe1212c8
736 add changeset f9cafe1212c8
737 add changeset 911600dab2ae
737 add changeset 911600dab2ae
738 adding manifests
738 adding manifests
739 adding file changes
739 adding file changes
740 adding foo/Bar/file.txt revisions
740 adding foo/Bar/file.txt revisions
741 adding foo/file.txt revisions
741 adding foo/file.txt revisions
742 adding quux/file.py revisions
742 adding quux/file.py revisions
743 added 3 changesets with 3 changes to 3 files
743 added 3 changesets with 3 changes to 3 files
744 calling hook pretxnchangegroup.acl: hgext.acl.hook
744 calling hook pretxnchangegroup.acl: hgext.acl.hook
745 acl: checking access for user "barney"
745 acl: checking access for user "barney"
746 acl: acl.allow.branches not enabled
746 acl: acl.allow.branches not enabled
747 acl: acl.deny.branches not enabled
747 acl: acl.deny.branches not enabled
748 acl: acl.allow enabled, 1 entries for user barney
748 acl: acl.allow enabled, 1 entries for user barney
749 acl: acl.deny enabled, 0 entries for user barney
749 acl: acl.deny enabled, 0 entries for user barney
750 acl: branch access granted: "ef1ea85a6374" on branch "default"
750 acl: branch access granted: "ef1ea85a6374" on branch "default"
751 acl: path access granted: "ef1ea85a6374"
751 acl: path access granted: "ef1ea85a6374"
752 acl: branch access granted: "f9cafe1212c8" on branch "default"
752 acl: branch access granted: "f9cafe1212c8" on branch "default"
753 acl: path access granted: "f9cafe1212c8"
753 acl: path access granted: "f9cafe1212c8"
754 acl: branch access granted: "911600dab2ae" on branch "default"
754 acl: branch access granted: "911600dab2ae" on branch "default"
755 acl: path access granted: "911600dab2ae"
755 acl: path access granted: "911600dab2ae"
756 bundle2-input-part: total payload size 1606
756 bundle2-input-part: total payload size 1606
757 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
757 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
758 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
758 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
759 bundle2-input-bundle: 3 parts total
759 bundle2-input-bundle: 3 parts total
760 updating the branch cache
760 updating the branch cache
761 bundle2-output-bundle: "HG20", 2 parts total
761 bundle2-output-bundle: "HG20", 2 parts total
762 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
762 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
763 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
763 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
764 bundle2-input-bundle: with-transaction
764 bundle2-input-bundle: with-transaction
765 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
765 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
766 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
766 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
767 bundle2-input-bundle: 1 parts total
767 bundle2-input-bundle: 1 parts total
768 listing keys for "phases"
768 listing keys for "phases"
769 try to push obsolete markers to remote
769 try to push obsolete markers to remote
770 repository tip rolled back to revision 0 (undo push)
770 repository tip rolled back to revision 0 (undo push)
771 0:6675d58eff77
771 0:6675d58eff77
772
772
773
773
774 wilma can change files with a .txt extension
774 wilma can change files with a .txt extension
775
775
776 $ echo '**/*.txt = wilma' >> $config
776 $ echo '**/*.txt = wilma' >> $config
777 $ do_push wilma
777 $ do_push wilma
778 Pushing as user wilma
778 Pushing as user wilma
779 hgrc = """
779 hgrc = """
780 [hooks]
780 [hooks]
781 pretxnchangegroup.acl = python:hgext.acl.hook
781 pretxnchangegroup.acl = python:hgext.acl.hook
782 [acl]
782 [acl]
783 sources = push
783 sources = push
784 [acl.allow]
784 [acl.allow]
785 foo/** = fred
785 foo/** = fred
786 [acl.deny]
786 [acl.deny]
787 foo/bar/** = fred
787 foo/bar/** = fred
788 foo/Bar/** = fred
788 foo/Bar/** = fred
789 [acl.allow]
789 [acl.allow]
790 ** = barney
790 ** = barney
791 **/*.txt = wilma
791 **/*.txt = wilma
792 """
792 """
793 pushing to ../b
793 pushing to ../b
794 query 1; heads
794 query 1; heads
795 searching for changes
795 searching for changes
796 all remote heads known locally
796 all remote heads known locally
797 listing keys for "phases"
797 listing keys for "phases"
798 checking for updated bookmarks
798 checking for updated bookmarks
799 listing keys for "bookmarks"
799 listing keys for "bookmarks"
800 invalid branchheads cache (served): tip differs
800 invalid branchheads cache (served): tip differs
801 listing keys for "bookmarks"
801 listing keys for "bookmarks"
802 3 changesets found
802 3 changesets found
803 list of changesets:
803 list of changesets:
804 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
804 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
805 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
805 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
806 911600dab2ae7a9baff75958b84fe606851ce955
806 911600dab2ae7a9baff75958b84fe606851ce955
807 bundle2-output-bundle: "HG20", 4 parts total
807 bundle2-output-bundle: "HG20", 4 parts total
808 bundle2-output-part: "replycaps" 147 bytes payload
808 bundle2-output-part: "replycaps" 155 bytes payload
809 bundle2-output-part: "check:heads" streamed payload
809 bundle2-output-part: "check:heads" streamed payload
810 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
810 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
811 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
811 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
812 bundle2-input-bundle: with-transaction
812 bundle2-input-bundle: with-transaction
813 bundle2-input-part: "replycaps" supported
813 bundle2-input-part: "replycaps" supported
814 bundle2-input-part: total payload size 147
814 bundle2-input-part: total payload size 155
815 bundle2-input-part: "check:heads" supported
815 bundle2-input-part: "check:heads" supported
816 bundle2-input-part: total payload size 20
816 bundle2-input-part: total payload size 20
817 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
817 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
818 adding changesets
818 adding changesets
819 add changeset ef1ea85a6374
819 add changeset ef1ea85a6374
820 add changeset f9cafe1212c8
820 add changeset f9cafe1212c8
821 add changeset 911600dab2ae
821 add changeset 911600dab2ae
822 adding manifests
822 adding manifests
823 adding file changes
823 adding file changes
824 adding foo/Bar/file.txt revisions
824 adding foo/Bar/file.txt revisions
825 adding foo/file.txt revisions
825 adding foo/file.txt revisions
826 adding quux/file.py revisions
826 adding quux/file.py revisions
827 added 3 changesets with 3 changes to 3 files
827 added 3 changesets with 3 changes to 3 files
828 calling hook pretxnchangegroup.acl: hgext.acl.hook
828 calling hook pretxnchangegroup.acl: hgext.acl.hook
829 acl: checking access for user "wilma"
829 acl: checking access for user "wilma"
830 acl: acl.allow.branches not enabled
830 acl: acl.allow.branches not enabled
831 acl: acl.deny.branches not enabled
831 acl: acl.deny.branches not enabled
832 acl: acl.allow enabled, 1 entries for user wilma
832 acl: acl.allow enabled, 1 entries for user wilma
833 acl: acl.deny enabled, 0 entries for user wilma
833 acl: acl.deny enabled, 0 entries for user wilma
834 acl: branch access granted: "ef1ea85a6374" on branch "default"
834 acl: branch access granted: "ef1ea85a6374" on branch "default"
835 acl: path access granted: "ef1ea85a6374"
835 acl: path access granted: "ef1ea85a6374"
836 acl: branch access granted: "f9cafe1212c8" on branch "default"
836 acl: branch access granted: "f9cafe1212c8" on branch "default"
837 acl: path access granted: "f9cafe1212c8"
837 acl: path access granted: "f9cafe1212c8"
838 acl: branch access granted: "911600dab2ae" on branch "default"
838 acl: branch access granted: "911600dab2ae" on branch "default"
839 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
839 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
840 bundle2-input-part: total payload size 1606
840 bundle2-input-part: total payload size 1606
841 bundle2-input-bundle: 3 parts total
841 bundle2-input-bundle: 3 parts total
842 transaction abort!
842 transaction abort!
843 rollback completed
843 rollback completed
844 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
844 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
845 no rollback information available
845 no rollback information available
846 0:6675d58eff77
846 0:6675d58eff77
847
847
848
848
849 file specified by acl.config does not exist
849 file specified by acl.config does not exist
850
850
851 $ echo '[acl]' >> $config
851 $ echo '[acl]' >> $config
852 $ echo 'config = ../acl.config' >> $config
852 $ echo 'config = ../acl.config' >> $config
853 $ do_push barney
853 $ do_push barney
854 Pushing as user barney
854 Pushing as user barney
855 hgrc = """
855 hgrc = """
856 [hooks]
856 [hooks]
857 pretxnchangegroup.acl = python:hgext.acl.hook
857 pretxnchangegroup.acl = python:hgext.acl.hook
858 [acl]
858 [acl]
859 sources = push
859 sources = push
860 [acl.allow]
860 [acl.allow]
861 foo/** = fred
861 foo/** = fred
862 [acl.deny]
862 [acl.deny]
863 foo/bar/** = fred
863 foo/bar/** = fred
864 foo/Bar/** = fred
864 foo/Bar/** = fred
865 [acl.allow]
865 [acl.allow]
866 ** = barney
866 ** = barney
867 **/*.txt = wilma
867 **/*.txt = wilma
868 [acl]
868 [acl]
869 config = ../acl.config
869 config = ../acl.config
870 """
870 """
871 pushing to ../b
871 pushing to ../b
872 query 1; heads
872 query 1; heads
873 searching for changes
873 searching for changes
874 all remote heads known locally
874 all remote heads known locally
875 listing keys for "phases"
875 listing keys for "phases"
876 checking for updated bookmarks
876 checking for updated bookmarks
877 listing keys for "bookmarks"
877 listing keys for "bookmarks"
878 invalid branchheads cache (served): tip differs
878 invalid branchheads cache (served): tip differs
879 listing keys for "bookmarks"
879 listing keys for "bookmarks"
880 3 changesets found
880 3 changesets found
881 list of changesets:
881 list of changesets:
882 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
882 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
883 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
883 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
884 911600dab2ae7a9baff75958b84fe606851ce955
884 911600dab2ae7a9baff75958b84fe606851ce955
885 bundle2-output-bundle: "HG20", 4 parts total
885 bundle2-output-bundle: "HG20", 4 parts total
886 bundle2-output-part: "replycaps" 147 bytes payload
886 bundle2-output-part: "replycaps" 155 bytes payload
887 bundle2-output-part: "check:heads" streamed payload
887 bundle2-output-part: "check:heads" streamed payload
888 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
888 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
889 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
889 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
890 bundle2-input-bundle: with-transaction
890 bundle2-input-bundle: with-transaction
891 bundle2-input-part: "replycaps" supported
891 bundle2-input-part: "replycaps" supported
892 bundle2-input-part: total payload size 147
892 bundle2-input-part: total payload size 155
893 bundle2-input-part: "check:heads" supported
893 bundle2-input-part: "check:heads" supported
894 bundle2-input-part: total payload size 20
894 bundle2-input-part: total payload size 20
895 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
895 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
896 adding changesets
896 adding changesets
897 add changeset ef1ea85a6374
897 add changeset ef1ea85a6374
898 add changeset f9cafe1212c8
898 add changeset f9cafe1212c8
899 add changeset 911600dab2ae
899 add changeset 911600dab2ae
900 adding manifests
900 adding manifests
901 adding file changes
901 adding file changes
902 adding foo/Bar/file.txt revisions
902 adding foo/Bar/file.txt revisions
903 adding foo/file.txt revisions
903 adding foo/file.txt revisions
904 adding quux/file.py revisions
904 adding quux/file.py revisions
905 added 3 changesets with 3 changes to 3 files
905 added 3 changesets with 3 changes to 3 files
906 calling hook pretxnchangegroup.acl: hgext.acl.hook
906 calling hook pretxnchangegroup.acl: hgext.acl.hook
907 acl: checking access for user "barney"
907 acl: checking access for user "barney"
908 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
908 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
909 bundle2-input-part: total payload size 1606
909 bundle2-input-part: total payload size 1606
910 bundle2-input-bundle: 3 parts total
910 bundle2-input-bundle: 3 parts total
911 transaction abort!
911 transaction abort!
912 rollback completed
912 rollback completed
913 abort: No such file or directory: ../acl.config
913 abort: No such file or directory: ../acl.config
914 no rollback information available
914 no rollback information available
915 0:6675d58eff77
915 0:6675d58eff77
916
916
917
917
918 betty is allowed inside foo/ by a acl.config file
918 betty is allowed inside foo/ by a acl.config file
919
919
920 $ echo '[acl.allow]' >> acl.config
920 $ echo '[acl.allow]' >> acl.config
921 $ echo 'foo/** = betty' >> acl.config
921 $ echo 'foo/** = betty' >> acl.config
922 $ do_push betty
922 $ do_push betty
923 Pushing as user betty
923 Pushing as user betty
924 hgrc = """
924 hgrc = """
925 [hooks]
925 [hooks]
926 pretxnchangegroup.acl = python:hgext.acl.hook
926 pretxnchangegroup.acl = python:hgext.acl.hook
927 [acl]
927 [acl]
928 sources = push
928 sources = push
929 [acl.allow]
929 [acl.allow]
930 foo/** = fred
930 foo/** = fred
931 [acl.deny]
931 [acl.deny]
932 foo/bar/** = fred
932 foo/bar/** = fred
933 foo/Bar/** = fred
933 foo/Bar/** = fred
934 [acl.allow]
934 [acl.allow]
935 ** = barney
935 ** = barney
936 **/*.txt = wilma
936 **/*.txt = wilma
937 [acl]
937 [acl]
938 config = ../acl.config
938 config = ../acl.config
939 """
939 """
940 acl.config = """
940 acl.config = """
941 [acl.allow]
941 [acl.allow]
942 foo/** = betty
942 foo/** = betty
943 """
943 """
944 pushing to ../b
944 pushing to ../b
945 query 1; heads
945 query 1; heads
946 searching for changes
946 searching for changes
947 all remote heads known locally
947 all remote heads known locally
948 listing keys for "phases"
948 listing keys for "phases"
949 checking for updated bookmarks
949 checking for updated bookmarks
950 listing keys for "bookmarks"
950 listing keys for "bookmarks"
951 invalid branchheads cache (served): tip differs
951 invalid branchheads cache (served): tip differs
952 listing keys for "bookmarks"
952 listing keys for "bookmarks"
953 3 changesets found
953 3 changesets found
954 list of changesets:
954 list of changesets:
955 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
955 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
956 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
956 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
957 911600dab2ae7a9baff75958b84fe606851ce955
957 911600dab2ae7a9baff75958b84fe606851ce955
958 bundle2-output-bundle: "HG20", 4 parts total
958 bundle2-output-bundle: "HG20", 4 parts total
959 bundle2-output-part: "replycaps" 147 bytes payload
959 bundle2-output-part: "replycaps" 155 bytes payload
960 bundle2-output-part: "check:heads" streamed payload
960 bundle2-output-part: "check:heads" streamed payload
961 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
961 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
962 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
962 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
963 bundle2-input-bundle: with-transaction
963 bundle2-input-bundle: with-transaction
964 bundle2-input-part: "replycaps" supported
964 bundle2-input-part: "replycaps" supported
965 bundle2-input-part: total payload size 147
965 bundle2-input-part: total payload size 155
966 bundle2-input-part: "check:heads" supported
966 bundle2-input-part: "check:heads" supported
967 bundle2-input-part: total payload size 20
967 bundle2-input-part: total payload size 20
968 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
968 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
969 adding changesets
969 adding changesets
970 add changeset ef1ea85a6374
970 add changeset ef1ea85a6374
971 add changeset f9cafe1212c8
971 add changeset f9cafe1212c8
972 add changeset 911600dab2ae
972 add changeset 911600dab2ae
973 adding manifests
973 adding manifests
974 adding file changes
974 adding file changes
975 adding foo/Bar/file.txt revisions
975 adding foo/Bar/file.txt revisions
976 adding foo/file.txt revisions
976 adding foo/file.txt revisions
977 adding quux/file.py revisions
977 adding quux/file.py revisions
978 added 3 changesets with 3 changes to 3 files
978 added 3 changesets with 3 changes to 3 files
979 calling hook pretxnchangegroup.acl: hgext.acl.hook
979 calling hook pretxnchangegroup.acl: hgext.acl.hook
980 acl: checking access for user "betty"
980 acl: checking access for user "betty"
981 acl: acl.allow.branches not enabled
981 acl: acl.allow.branches not enabled
982 acl: acl.deny.branches not enabled
982 acl: acl.deny.branches not enabled
983 acl: acl.allow enabled, 1 entries for user betty
983 acl: acl.allow enabled, 1 entries for user betty
984 acl: acl.deny enabled, 0 entries for user betty
984 acl: acl.deny enabled, 0 entries for user betty
985 acl: branch access granted: "ef1ea85a6374" on branch "default"
985 acl: branch access granted: "ef1ea85a6374" on branch "default"
986 acl: path access granted: "ef1ea85a6374"
986 acl: path access granted: "ef1ea85a6374"
987 acl: branch access granted: "f9cafe1212c8" on branch "default"
987 acl: branch access granted: "f9cafe1212c8" on branch "default"
988 acl: path access granted: "f9cafe1212c8"
988 acl: path access granted: "f9cafe1212c8"
989 acl: branch access granted: "911600dab2ae" on branch "default"
989 acl: branch access granted: "911600dab2ae" on branch "default"
990 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
990 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
991 bundle2-input-part: total payload size 1606
991 bundle2-input-part: total payload size 1606
992 bundle2-input-bundle: 3 parts total
992 bundle2-input-bundle: 3 parts total
993 transaction abort!
993 transaction abort!
994 rollback completed
994 rollback completed
995 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
995 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
996 no rollback information available
996 no rollback information available
997 0:6675d58eff77
997 0:6675d58eff77
998
998
999
999
1000 acl.config can set only [acl.allow]/[acl.deny]
1000 acl.config can set only [acl.allow]/[acl.deny]
1001
1001
1002 $ echo '[hooks]' >> acl.config
1002 $ echo '[hooks]' >> acl.config
1003 $ echo 'changegroup.acl = false' >> acl.config
1003 $ echo 'changegroup.acl = false' >> acl.config
1004 $ do_push barney
1004 $ do_push barney
1005 Pushing as user barney
1005 Pushing as user barney
1006 hgrc = """
1006 hgrc = """
1007 [hooks]
1007 [hooks]
1008 pretxnchangegroup.acl = python:hgext.acl.hook
1008 pretxnchangegroup.acl = python:hgext.acl.hook
1009 [acl]
1009 [acl]
1010 sources = push
1010 sources = push
1011 [acl.allow]
1011 [acl.allow]
1012 foo/** = fred
1012 foo/** = fred
1013 [acl.deny]
1013 [acl.deny]
1014 foo/bar/** = fred
1014 foo/bar/** = fred
1015 foo/Bar/** = fred
1015 foo/Bar/** = fred
1016 [acl.allow]
1016 [acl.allow]
1017 ** = barney
1017 ** = barney
1018 **/*.txt = wilma
1018 **/*.txt = wilma
1019 [acl]
1019 [acl]
1020 config = ../acl.config
1020 config = ../acl.config
1021 """
1021 """
1022 acl.config = """
1022 acl.config = """
1023 [acl.allow]
1023 [acl.allow]
1024 foo/** = betty
1024 foo/** = betty
1025 [hooks]
1025 [hooks]
1026 changegroup.acl = false
1026 changegroup.acl = false
1027 """
1027 """
1028 pushing to ../b
1028 pushing to ../b
1029 query 1; heads
1029 query 1; heads
1030 searching for changes
1030 searching for changes
1031 all remote heads known locally
1031 all remote heads known locally
1032 listing keys for "phases"
1032 listing keys for "phases"
1033 checking for updated bookmarks
1033 checking for updated bookmarks
1034 listing keys for "bookmarks"
1034 listing keys for "bookmarks"
1035 invalid branchheads cache (served): tip differs
1035 invalid branchheads cache (served): tip differs
1036 listing keys for "bookmarks"
1036 listing keys for "bookmarks"
1037 3 changesets found
1037 3 changesets found
1038 list of changesets:
1038 list of changesets:
1039 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1039 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1040 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1040 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1041 911600dab2ae7a9baff75958b84fe606851ce955
1041 911600dab2ae7a9baff75958b84fe606851ce955
1042 bundle2-output-bundle: "HG20", 4 parts total
1042 bundle2-output-bundle: "HG20", 4 parts total
1043 bundle2-output-part: "replycaps" 147 bytes payload
1043 bundle2-output-part: "replycaps" 155 bytes payload
1044 bundle2-output-part: "check:heads" streamed payload
1044 bundle2-output-part: "check:heads" streamed payload
1045 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1045 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1046 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1046 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1047 bundle2-input-bundle: with-transaction
1047 bundle2-input-bundle: with-transaction
1048 bundle2-input-part: "replycaps" supported
1048 bundle2-input-part: "replycaps" supported
1049 bundle2-input-part: total payload size 147
1049 bundle2-input-part: total payload size 155
1050 bundle2-input-part: "check:heads" supported
1050 bundle2-input-part: "check:heads" supported
1051 bundle2-input-part: total payload size 20
1051 bundle2-input-part: total payload size 20
1052 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1052 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1053 adding changesets
1053 adding changesets
1054 add changeset ef1ea85a6374
1054 add changeset ef1ea85a6374
1055 add changeset f9cafe1212c8
1055 add changeset f9cafe1212c8
1056 add changeset 911600dab2ae
1056 add changeset 911600dab2ae
1057 adding manifests
1057 adding manifests
1058 adding file changes
1058 adding file changes
1059 adding foo/Bar/file.txt revisions
1059 adding foo/Bar/file.txt revisions
1060 adding foo/file.txt revisions
1060 adding foo/file.txt revisions
1061 adding quux/file.py revisions
1061 adding quux/file.py revisions
1062 added 3 changesets with 3 changes to 3 files
1062 added 3 changesets with 3 changes to 3 files
1063 calling hook pretxnchangegroup.acl: hgext.acl.hook
1063 calling hook pretxnchangegroup.acl: hgext.acl.hook
1064 acl: checking access for user "barney"
1064 acl: checking access for user "barney"
1065 acl: acl.allow.branches not enabled
1065 acl: acl.allow.branches not enabled
1066 acl: acl.deny.branches not enabled
1066 acl: acl.deny.branches not enabled
1067 acl: acl.allow enabled, 1 entries for user barney
1067 acl: acl.allow enabled, 1 entries for user barney
1068 acl: acl.deny enabled, 0 entries for user barney
1068 acl: acl.deny enabled, 0 entries for user barney
1069 acl: branch access granted: "ef1ea85a6374" on branch "default"
1069 acl: branch access granted: "ef1ea85a6374" on branch "default"
1070 acl: path access granted: "ef1ea85a6374"
1070 acl: path access granted: "ef1ea85a6374"
1071 acl: branch access granted: "f9cafe1212c8" on branch "default"
1071 acl: branch access granted: "f9cafe1212c8" on branch "default"
1072 acl: path access granted: "f9cafe1212c8"
1072 acl: path access granted: "f9cafe1212c8"
1073 acl: branch access granted: "911600dab2ae" on branch "default"
1073 acl: branch access granted: "911600dab2ae" on branch "default"
1074 acl: path access granted: "911600dab2ae"
1074 acl: path access granted: "911600dab2ae"
1075 bundle2-input-part: total payload size 1606
1075 bundle2-input-part: total payload size 1606
1076 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1076 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1077 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1077 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1078 bundle2-input-bundle: 3 parts total
1078 bundle2-input-bundle: 3 parts total
1079 updating the branch cache
1079 updating the branch cache
1080 bundle2-output-bundle: "HG20", 2 parts total
1080 bundle2-output-bundle: "HG20", 2 parts total
1081 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1081 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1082 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1082 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1083 bundle2-input-bundle: with-transaction
1083 bundle2-input-bundle: with-transaction
1084 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1084 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1085 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1085 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1086 bundle2-input-bundle: 1 parts total
1086 bundle2-input-bundle: 1 parts total
1087 listing keys for "phases"
1087 listing keys for "phases"
1088 try to push obsolete markers to remote
1088 try to push obsolete markers to remote
1089 repository tip rolled back to revision 0 (undo push)
1089 repository tip rolled back to revision 0 (undo push)
1090 0:6675d58eff77
1090 0:6675d58eff77
1091
1091
1092
1092
1093 asterisk
1093 asterisk
1094
1094
1095 $ init_config
1095 $ init_config
1096
1096
1097 asterisk test
1097 asterisk test
1098
1098
1099 $ echo '[acl.allow]' >> $config
1099 $ echo '[acl.allow]' >> $config
1100 $ echo "** = fred" >> $config
1100 $ echo "** = fred" >> $config
1101
1101
1102 fred is always allowed
1102 fred is always allowed
1103
1103
1104 $ do_push fred
1104 $ do_push fred
1105 Pushing as user fred
1105 Pushing as user fred
1106 hgrc = """
1106 hgrc = """
1107 [hooks]
1107 [hooks]
1108 pretxnchangegroup.acl = python:hgext.acl.hook
1108 pretxnchangegroup.acl = python:hgext.acl.hook
1109 [acl]
1109 [acl]
1110 sources = push
1110 sources = push
1111 [extensions]
1111 [extensions]
1112 [acl.allow]
1112 [acl.allow]
1113 ** = fred
1113 ** = fred
1114 """
1114 """
1115 pushing to ../b
1115 pushing to ../b
1116 query 1; heads
1116 query 1; heads
1117 searching for changes
1117 searching for changes
1118 all remote heads known locally
1118 all remote heads known locally
1119 listing keys for "phases"
1119 listing keys for "phases"
1120 checking for updated bookmarks
1120 checking for updated bookmarks
1121 listing keys for "bookmarks"
1121 listing keys for "bookmarks"
1122 invalid branchheads cache (served): tip differs
1122 invalid branchheads cache (served): tip differs
1123 listing keys for "bookmarks"
1123 listing keys for "bookmarks"
1124 3 changesets found
1124 3 changesets found
1125 list of changesets:
1125 list of changesets:
1126 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1126 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1127 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1127 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1128 911600dab2ae7a9baff75958b84fe606851ce955
1128 911600dab2ae7a9baff75958b84fe606851ce955
1129 bundle2-output-bundle: "HG20", 4 parts total
1129 bundle2-output-bundle: "HG20", 4 parts total
1130 bundle2-output-part: "replycaps" 147 bytes payload
1130 bundle2-output-part: "replycaps" 155 bytes payload
1131 bundle2-output-part: "check:heads" streamed payload
1131 bundle2-output-part: "check:heads" streamed payload
1132 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1132 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1133 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1133 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1134 bundle2-input-bundle: with-transaction
1134 bundle2-input-bundle: with-transaction
1135 bundle2-input-part: "replycaps" supported
1135 bundle2-input-part: "replycaps" supported
1136 bundle2-input-part: total payload size 147
1136 bundle2-input-part: total payload size 155
1137 bundle2-input-part: "check:heads" supported
1137 bundle2-input-part: "check:heads" supported
1138 bundle2-input-part: total payload size 20
1138 bundle2-input-part: total payload size 20
1139 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1139 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1140 adding changesets
1140 adding changesets
1141 add changeset ef1ea85a6374
1141 add changeset ef1ea85a6374
1142 add changeset f9cafe1212c8
1142 add changeset f9cafe1212c8
1143 add changeset 911600dab2ae
1143 add changeset 911600dab2ae
1144 adding manifests
1144 adding manifests
1145 adding file changes
1145 adding file changes
1146 adding foo/Bar/file.txt revisions
1146 adding foo/Bar/file.txt revisions
1147 adding foo/file.txt revisions
1147 adding foo/file.txt revisions
1148 adding quux/file.py revisions
1148 adding quux/file.py revisions
1149 added 3 changesets with 3 changes to 3 files
1149 added 3 changesets with 3 changes to 3 files
1150 calling hook pretxnchangegroup.acl: hgext.acl.hook
1150 calling hook pretxnchangegroup.acl: hgext.acl.hook
1151 acl: checking access for user "fred"
1151 acl: checking access for user "fred"
1152 acl: acl.allow.branches not enabled
1152 acl: acl.allow.branches not enabled
1153 acl: acl.deny.branches not enabled
1153 acl: acl.deny.branches not enabled
1154 acl: acl.allow enabled, 1 entries for user fred
1154 acl: acl.allow enabled, 1 entries for user fred
1155 acl: acl.deny not enabled
1155 acl: acl.deny not enabled
1156 acl: branch access granted: "ef1ea85a6374" on branch "default"
1156 acl: branch access granted: "ef1ea85a6374" on branch "default"
1157 acl: path access granted: "ef1ea85a6374"
1157 acl: path access granted: "ef1ea85a6374"
1158 acl: branch access granted: "f9cafe1212c8" on branch "default"
1158 acl: branch access granted: "f9cafe1212c8" on branch "default"
1159 acl: path access granted: "f9cafe1212c8"
1159 acl: path access granted: "f9cafe1212c8"
1160 acl: branch access granted: "911600dab2ae" on branch "default"
1160 acl: branch access granted: "911600dab2ae" on branch "default"
1161 acl: path access granted: "911600dab2ae"
1161 acl: path access granted: "911600dab2ae"
1162 bundle2-input-part: total payload size 1606
1162 bundle2-input-part: total payload size 1606
1163 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1163 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1164 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1164 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1165 bundle2-input-bundle: 3 parts total
1165 bundle2-input-bundle: 3 parts total
1166 updating the branch cache
1166 updating the branch cache
1167 bundle2-output-bundle: "HG20", 2 parts total
1167 bundle2-output-bundle: "HG20", 2 parts total
1168 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1168 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1169 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1169 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1170 bundle2-input-bundle: with-transaction
1170 bundle2-input-bundle: with-transaction
1171 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1171 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1172 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1172 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1173 bundle2-input-bundle: 1 parts total
1173 bundle2-input-bundle: 1 parts total
1174 listing keys for "phases"
1174 listing keys for "phases"
1175 try to push obsolete markers to remote
1175 try to push obsolete markers to remote
1176 repository tip rolled back to revision 0 (undo push)
1176 repository tip rolled back to revision 0 (undo push)
1177 0:6675d58eff77
1177 0:6675d58eff77
1178
1178
1179
1179
1180 $ echo '[acl.deny]' >> $config
1180 $ echo '[acl.deny]' >> $config
1181 $ echo "foo/Bar/** = *" >> $config
1181 $ echo "foo/Bar/** = *" >> $config
1182
1182
1183 no one is allowed inside foo/Bar/
1183 no one is allowed inside foo/Bar/
1184
1184
1185 $ do_push fred
1185 $ do_push fred
1186 Pushing as user fred
1186 Pushing as user fred
1187 hgrc = """
1187 hgrc = """
1188 [hooks]
1188 [hooks]
1189 pretxnchangegroup.acl = python:hgext.acl.hook
1189 pretxnchangegroup.acl = python:hgext.acl.hook
1190 [acl]
1190 [acl]
1191 sources = push
1191 sources = push
1192 [extensions]
1192 [extensions]
1193 [acl.allow]
1193 [acl.allow]
1194 ** = fred
1194 ** = fred
1195 [acl.deny]
1195 [acl.deny]
1196 foo/Bar/** = *
1196 foo/Bar/** = *
1197 """
1197 """
1198 pushing to ../b
1198 pushing to ../b
1199 query 1; heads
1199 query 1; heads
1200 searching for changes
1200 searching for changes
1201 all remote heads known locally
1201 all remote heads known locally
1202 listing keys for "phases"
1202 listing keys for "phases"
1203 checking for updated bookmarks
1203 checking for updated bookmarks
1204 listing keys for "bookmarks"
1204 listing keys for "bookmarks"
1205 invalid branchheads cache (served): tip differs
1205 invalid branchheads cache (served): tip differs
1206 listing keys for "bookmarks"
1206 listing keys for "bookmarks"
1207 3 changesets found
1207 3 changesets found
1208 list of changesets:
1208 list of changesets:
1209 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1209 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1210 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1210 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1211 911600dab2ae7a9baff75958b84fe606851ce955
1211 911600dab2ae7a9baff75958b84fe606851ce955
1212 bundle2-output-bundle: "HG20", 4 parts total
1212 bundle2-output-bundle: "HG20", 4 parts total
1213 bundle2-output-part: "replycaps" 147 bytes payload
1213 bundle2-output-part: "replycaps" 155 bytes payload
1214 bundle2-output-part: "check:heads" streamed payload
1214 bundle2-output-part: "check:heads" streamed payload
1215 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1215 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1216 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1216 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1217 bundle2-input-bundle: with-transaction
1217 bundle2-input-bundle: with-transaction
1218 bundle2-input-part: "replycaps" supported
1218 bundle2-input-part: "replycaps" supported
1219 bundle2-input-part: total payload size 147
1219 bundle2-input-part: total payload size 155
1220 bundle2-input-part: "check:heads" supported
1220 bundle2-input-part: "check:heads" supported
1221 bundle2-input-part: total payload size 20
1221 bundle2-input-part: total payload size 20
1222 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1222 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1223 adding changesets
1223 adding changesets
1224 add changeset ef1ea85a6374
1224 add changeset ef1ea85a6374
1225 add changeset f9cafe1212c8
1225 add changeset f9cafe1212c8
1226 add changeset 911600dab2ae
1226 add changeset 911600dab2ae
1227 adding manifests
1227 adding manifests
1228 adding file changes
1228 adding file changes
1229 adding foo/Bar/file.txt revisions
1229 adding foo/Bar/file.txt revisions
1230 adding foo/file.txt revisions
1230 adding foo/file.txt revisions
1231 adding quux/file.py revisions
1231 adding quux/file.py revisions
1232 added 3 changesets with 3 changes to 3 files
1232 added 3 changesets with 3 changes to 3 files
1233 calling hook pretxnchangegroup.acl: hgext.acl.hook
1233 calling hook pretxnchangegroup.acl: hgext.acl.hook
1234 acl: checking access for user "fred"
1234 acl: checking access for user "fred"
1235 acl: acl.allow.branches not enabled
1235 acl: acl.allow.branches not enabled
1236 acl: acl.deny.branches not enabled
1236 acl: acl.deny.branches not enabled
1237 acl: acl.allow enabled, 1 entries for user fred
1237 acl: acl.allow enabled, 1 entries for user fred
1238 acl: acl.deny enabled, 1 entries for user fred
1238 acl: acl.deny enabled, 1 entries for user fred
1239 acl: branch access granted: "ef1ea85a6374" on branch "default"
1239 acl: branch access granted: "ef1ea85a6374" on branch "default"
1240 acl: path access granted: "ef1ea85a6374"
1240 acl: path access granted: "ef1ea85a6374"
1241 acl: branch access granted: "f9cafe1212c8" on branch "default"
1241 acl: branch access granted: "f9cafe1212c8" on branch "default"
1242 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1242 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1243 bundle2-input-part: total payload size 1606
1243 bundle2-input-part: total payload size 1606
1244 bundle2-input-bundle: 3 parts total
1244 bundle2-input-bundle: 3 parts total
1245 transaction abort!
1245 transaction abort!
1246 rollback completed
1246 rollback completed
1247 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1247 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1248 no rollback information available
1248 no rollback information available
1249 0:6675d58eff77
1249 0:6675d58eff77
1250
1250
1251
1251
1252 Groups
1252 Groups
1253
1253
1254 $ init_config
1254 $ init_config
1255
1255
1256 OS-level groups
1256 OS-level groups
1257
1257
1258 $ echo '[acl.allow]' >> $config
1258 $ echo '[acl.allow]' >> $config
1259 $ echo "** = @group1" >> $config
1259 $ echo "** = @group1" >> $config
1260
1260
1261 @group1 is always allowed
1261 @group1 is always allowed
1262
1262
1263 $ do_push fred
1263 $ do_push fred
1264 Pushing as user fred
1264 Pushing as user fred
1265 hgrc = """
1265 hgrc = """
1266 [hooks]
1266 [hooks]
1267 pretxnchangegroup.acl = python:hgext.acl.hook
1267 pretxnchangegroup.acl = python:hgext.acl.hook
1268 [acl]
1268 [acl]
1269 sources = push
1269 sources = push
1270 [extensions]
1270 [extensions]
1271 [acl.allow]
1271 [acl.allow]
1272 ** = @group1
1272 ** = @group1
1273 """
1273 """
1274 pushing to ../b
1274 pushing to ../b
1275 query 1; heads
1275 query 1; heads
1276 searching for changes
1276 searching for changes
1277 all remote heads known locally
1277 all remote heads known locally
1278 listing keys for "phases"
1278 listing keys for "phases"
1279 checking for updated bookmarks
1279 checking for updated bookmarks
1280 listing keys for "bookmarks"
1280 listing keys for "bookmarks"
1281 invalid branchheads cache (served): tip differs
1281 invalid branchheads cache (served): tip differs
1282 listing keys for "bookmarks"
1282 listing keys for "bookmarks"
1283 3 changesets found
1283 3 changesets found
1284 list of changesets:
1284 list of changesets:
1285 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1285 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1286 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1286 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1287 911600dab2ae7a9baff75958b84fe606851ce955
1287 911600dab2ae7a9baff75958b84fe606851ce955
1288 bundle2-output-bundle: "HG20", 4 parts total
1288 bundle2-output-bundle: "HG20", 4 parts total
1289 bundle2-output-part: "replycaps" 147 bytes payload
1289 bundle2-output-part: "replycaps" 155 bytes payload
1290 bundle2-output-part: "check:heads" streamed payload
1290 bundle2-output-part: "check:heads" streamed payload
1291 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1291 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1292 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1292 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1293 bundle2-input-bundle: with-transaction
1293 bundle2-input-bundle: with-transaction
1294 bundle2-input-part: "replycaps" supported
1294 bundle2-input-part: "replycaps" supported
1295 bundle2-input-part: total payload size 147
1295 bundle2-input-part: total payload size 155
1296 bundle2-input-part: "check:heads" supported
1296 bundle2-input-part: "check:heads" supported
1297 bundle2-input-part: total payload size 20
1297 bundle2-input-part: total payload size 20
1298 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1298 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1299 adding changesets
1299 adding changesets
1300 add changeset ef1ea85a6374
1300 add changeset ef1ea85a6374
1301 add changeset f9cafe1212c8
1301 add changeset f9cafe1212c8
1302 add changeset 911600dab2ae
1302 add changeset 911600dab2ae
1303 adding manifests
1303 adding manifests
1304 adding file changes
1304 adding file changes
1305 adding foo/Bar/file.txt revisions
1305 adding foo/Bar/file.txt revisions
1306 adding foo/file.txt revisions
1306 adding foo/file.txt revisions
1307 adding quux/file.py revisions
1307 adding quux/file.py revisions
1308 added 3 changesets with 3 changes to 3 files
1308 added 3 changesets with 3 changes to 3 files
1309 calling hook pretxnchangegroup.acl: hgext.acl.hook
1309 calling hook pretxnchangegroup.acl: hgext.acl.hook
1310 acl: checking access for user "fred"
1310 acl: checking access for user "fred"
1311 acl: acl.allow.branches not enabled
1311 acl: acl.allow.branches not enabled
1312 acl: acl.deny.branches not enabled
1312 acl: acl.deny.branches not enabled
1313 acl: "group1" not defined in [acl.groups]
1313 acl: "group1" not defined in [acl.groups]
1314 acl: acl.allow enabled, 1 entries for user fred
1314 acl: acl.allow enabled, 1 entries for user fred
1315 acl: acl.deny not enabled
1315 acl: acl.deny not enabled
1316 acl: branch access granted: "ef1ea85a6374" on branch "default"
1316 acl: branch access granted: "ef1ea85a6374" on branch "default"
1317 acl: path access granted: "ef1ea85a6374"
1317 acl: path access granted: "ef1ea85a6374"
1318 acl: branch access granted: "f9cafe1212c8" on branch "default"
1318 acl: branch access granted: "f9cafe1212c8" on branch "default"
1319 acl: path access granted: "f9cafe1212c8"
1319 acl: path access granted: "f9cafe1212c8"
1320 acl: branch access granted: "911600dab2ae" on branch "default"
1320 acl: branch access granted: "911600dab2ae" on branch "default"
1321 acl: path access granted: "911600dab2ae"
1321 acl: path access granted: "911600dab2ae"
1322 bundle2-input-part: total payload size 1606
1322 bundle2-input-part: total payload size 1606
1323 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1323 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1324 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1324 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1325 bundle2-input-bundle: 3 parts total
1325 bundle2-input-bundle: 3 parts total
1326 updating the branch cache
1326 updating the branch cache
1327 bundle2-output-bundle: "HG20", 2 parts total
1327 bundle2-output-bundle: "HG20", 2 parts total
1328 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1328 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1329 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1329 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1330 bundle2-input-bundle: with-transaction
1330 bundle2-input-bundle: with-transaction
1331 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1331 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1332 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1332 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1333 bundle2-input-bundle: 1 parts total
1333 bundle2-input-bundle: 1 parts total
1334 listing keys for "phases"
1334 listing keys for "phases"
1335 try to push obsolete markers to remote
1335 try to push obsolete markers to remote
1336 repository tip rolled back to revision 0 (undo push)
1336 repository tip rolled back to revision 0 (undo push)
1337 0:6675d58eff77
1337 0:6675d58eff77
1338
1338
1339
1339
1340 $ echo '[acl.deny]' >> $config
1340 $ echo '[acl.deny]' >> $config
1341 $ echo "foo/Bar/** = @group1" >> $config
1341 $ echo "foo/Bar/** = @group1" >> $config
1342
1342
1343 @group is allowed inside anything but foo/Bar/
1343 @group is allowed inside anything but foo/Bar/
1344
1344
1345 $ do_push fred
1345 $ do_push fred
1346 Pushing as user fred
1346 Pushing as user fred
1347 hgrc = """
1347 hgrc = """
1348 [hooks]
1348 [hooks]
1349 pretxnchangegroup.acl = python:hgext.acl.hook
1349 pretxnchangegroup.acl = python:hgext.acl.hook
1350 [acl]
1350 [acl]
1351 sources = push
1351 sources = push
1352 [extensions]
1352 [extensions]
1353 [acl.allow]
1353 [acl.allow]
1354 ** = @group1
1354 ** = @group1
1355 [acl.deny]
1355 [acl.deny]
1356 foo/Bar/** = @group1
1356 foo/Bar/** = @group1
1357 """
1357 """
1358 pushing to ../b
1358 pushing to ../b
1359 query 1; heads
1359 query 1; heads
1360 searching for changes
1360 searching for changes
1361 all remote heads known locally
1361 all remote heads known locally
1362 listing keys for "phases"
1362 listing keys for "phases"
1363 checking for updated bookmarks
1363 checking for updated bookmarks
1364 listing keys for "bookmarks"
1364 listing keys for "bookmarks"
1365 invalid branchheads cache (served): tip differs
1365 invalid branchheads cache (served): tip differs
1366 listing keys for "bookmarks"
1366 listing keys for "bookmarks"
1367 3 changesets found
1367 3 changesets found
1368 list of changesets:
1368 list of changesets:
1369 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1369 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1370 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1370 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1371 911600dab2ae7a9baff75958b84fe606851ce955
1371 911600dab2ae7a9baff75958b84fe606851ce955
1372 bundle2-output-bundle: "HG20", 4 parts total
1372 bundle2-output-bundle: "HG20", 4 parts total
1373 bundle2-output-part: "replycaps" 147 bytes payload
1373 bundle2-output-part: "replycaps" 155 bytes payload
1374 bundle2-output-part: "check:heads" streamed payload
1374 bundle2-output-part: "check:heads" streamed payload
1375 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1375 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1376 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1376 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1377 bundle2-input-bundle: with-transaction
1377 bundle2-input-bundle: with-transaction
1378 bundle2-input-part: "replycaps" supported
1378 bundle2-input-part: "replycaps" supported
1379 bundle2-input-part: total payload size 147
1379 bundle2-input-part: total payload size 155
1380 bundle2-input-part: "check:heads" supported
1380 bundle2-input-part: "check:heads" supported
1381 bundle2-input-part: total payload size 20
1381 bundle2-input-part: total payload size 20
1382 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1382 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1383 adding changesets
1383 adding changesets
1384 add changeset ef1ea85a6374
1384 add changeset ef1ea85a6374
1385 add changeset f9cafe1212c8
1385 add changeset f9cafe1212c8
1386 add changeset 911600dab2ae
1386 add changeset 911600dab2ae
1387 adding manifests
1387 adding manifests
1388 adding file changes
1388 adding file changes
1389 adding foo/Bar/file.txt revisions
1389 adding foo/Bar/file.txt revisions
1390 adding foo/file.txt revisions
1390 adding foo/file.txt revisions
1391 adding quux/file.py revisions
1391 adding quux/file.py revisions
1392 added 3 changesets with 3 changes to 3 files
1392 added 3 changesets with 3 changes to 3 files
1393 calling hook pretxnchangegroup.acl: hgext.acl.hook
1393 calling hook pretxnchangegroup.acl: hgext.acl.hook
1394 acl: checking access for user "fred"
1394 acl: checking access for user "fred"
1395 acl: acl.allow.branches not enabled
1395 acl: acl.allow.branches not enabled
1396 acl: acl.deny.branches not enabled
1396 acl: acl.deny.branches not enabled
1397 acl: "group1" not defined in [acl.groups]
1397 acl: "group1" not defined in [acl.groups]
1398 acl: acl.allow enabled, 1 entries for user fred
1398 acl: acl.allow enabled, 1 entries for user fred
1399 acl: "group1" not defined in [acl.groups]
1399 acl: "group1" not defined in [acl.groups]
1400 acl: acl.deny enabled, 1 entries for user fred
1400 acl: acl.deny enabled, 1 entries for user fred
1401 acl: branch access granted: "ef1ea85a6374" on branch "default"
1401 acl: branch access granted: "ef1ea85a6374" on branch "default"
1402 acl: path access granted: "ef1ea85a6374"
1402 acl: path access granted: "ef1ea85a6374"
1403 acl: branch access granted: "f9cafe1212c8" on branch "default"
1403 acl: branch access granted: "f9cafe1212c8" on branch "default"
1404 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1404 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1405 bundle2-input-part: total payload size 1606
1405 bundle2-input-part: total payload size 1606
1406 bundle2-input-bundle: 3 parts total
1406 bundle2-input-bundle: 3 parts total
1407 transaction abort!
1407 transaction abort!
1408 rollback completed
1408 rollback completed
1409 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1409 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1410 no rollback information available
1410 no rollback information available
1411 0:6675d58eff77
1411 0:6675d58eff77
1412
1412
1413
1413
1414 Invalid group
1414 Invalid group
1415
1415
1416 Disable the fakegroups trick to get real failures
1416 Disable the fakegroups trick to get real failures
1417
1417
1418 $ grep -v fakegroups $config > config.tmp
1418 $ grep -v fakegroups $config > config.tmp
1419 $ mv config.tmp $config
1419 $ mv config.tmp $config
1420 $ echo '[acl.allow]' >> $config
1420 $ echo '[acl.allow]' >> $config
1421 $ echo "** = @unlikelytoexist" >> $config
1421 $ echo "** = @unlikelytoexist" >> $config
1422 $ do_push fred 2>&1 | grep unlikelytoexist
1422 $ do_push fred 2>&1 | grep unlikelytoexist
1423 ** = @unlikelytoexist
1423 ** = @unlikelytoexist
1424 acl: "unlikelytoexist" not defined in [acl.groups]
1424 acl: "unlikelytoexist" not defined in [acl.groups]
1425 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1425 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1426 abort: group 'unlikelytoexist' is undefined
1426 abort: group 'unlikelytoexist' is undefined
1427
1427
1428
1428
1429 Branch acl tests setup
1429 Branch acl tests setup
1430
1430
1431 $ init_config
1431 $ init_config
1432 $ cd b
1432 $ cd b
1433 $ hg up
1433 $ hg up
1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1435 $ hg branch foobar
1435 $ hg branch foobar
1436 marked working directory as branch foobar
1436 marked working directory as branch foobar
1437 (branches are permanent and global, did you want a bookmark?)
1437 (branches are permanent and global, did you want a bookmark?)
1438 $ hg commit -m 'create foobar'
1438 $ hg commit -m 'create foobar'
1439 $ echo 'foo contents' > abc.txt
1439 $ echo 'foo contents' > abc.txt
1440 $ hg add abc.txt
1440 $ hg add abc.txt
1441 $ hg commit -m 'foobar contents'
1441 $ hg commit -m 'foobar contents'
1442 $ cd ..
1442 $ cd ..
1443 $ hg --cwd a pull ../b
1443 $ hg --cwd a pull ../b
1444 pulling from ../b
1444 pulling from ../b
1445 searching for changes
1445 searching for changes
1446 adding changesets
1446 adding changesets
1447 adding manifests
1447 adding manifests
1448 adding file changes
1448 adding file changes
1449 added 2 changesets with 1 changes to 1 files (+1 heads)
1449 added 2 changesets with 1 changes to 1 files (+1 heads)
1450 (run 'hg heads' to see heads)
1450 (run 'hg heads' to see heads)
1451
1451
1452 Create additional changeset on foobar branch
1452 Create additional changeset on foobar branch
1453
1453
1454 $ cd a
1454 $ cd a
1455 $ hg up -C foobar
1455 $ hg up -C foobar
1456 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1456 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1457 $ echo 'foo contents2' > abc.txt
1457 $ echo 'foo contents2' > abc.txt
1458 $ hg commit -m 'foobar contents2'
1458 $ hg commit -m 'foobar contents2'
1459 $ cd ..
1459 $ cd ..
1460
1460
1461
1461
1462 No branch acls specified
1462 No branch acls specified
1463
1463
1464 $ do_push astro
1464 $ do_push astro
1465 Pushing as user astro
1465 Pushing as user astro
1466 hgrc = """
1466 hgrc = """
1467 [hooks]
1467 [hooks]
1468 pretxnchangegroup.acl = python:hgext.acl.hook
1468 pretxnchangegroup.acl = python:hgext.acl.hook
1469 [acl]
1469 [acl]
1470 sources = push
1470 sources = push
1471 [extensions]
1471 [extensions]
1472 """
1472 """
1473 pushing to ../b
1473 pushing to ../b
1474 query 1; heads
1474 query 1; heads
1475 searching for changes
1475 searching for changes
1476 all remote heads known locally
1476 all remote heads known locally
1477 listing keys for "phases"
1477 listing keys for "phases"
1478 checking for updated bookmarks
1478 checking for updated bookmarks
1479 listing keys for "bookmarks"
1479 listing keys for "bookmarks"
1480 listing keys for "bookmarks"
1480 listing keys for "bookmarks"
1481 4 changesets found
1481 4 changesets found
1482 list of changesets:
1482 list of changesets:
1483 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1483 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1484 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1484 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1485 911600dab2ae7a9baff75958b84fe606851ce955
1485 911600dab2ae7a9baff75958b84fe606851ce955
1486 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1486 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1487 bundle2-output-bundle: "HG20", 5 parts total
1487 bundle2-output-bundle: "HG20", 5 parts total
1488 bundle2-output-part: "replycaps" 147 bytes payload
1488 bundle2-output-part: "replycaps" 155 bytes payload
1489 bundle2-output-part: "check:heads" streamed payload
1489 bundle2-output-part: "check:heads" streamed payload
1490 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1490 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1491 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1491 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1492 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1492 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1493 bundle2-input-bundle: with-transaction
1493 bundle2-input-bundle: with-transaction
1494 bundle2-input-part: "replycaps" supported
1494 bundle2-input-part: "replycaps" supported
1495 bundle2-input-part: total payload size 147
1495 bundle2-input-part: total payload size 155
1496 bundle2-input-part: "check:heads" supported
1496 bundle2-input-part: "check:heads" supported
1497 bundle2-input-part: total payload size 20
1497 bundle2-input-part: total payload size 20
1498 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1498 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1499 adding changesets
1499 adding changesets
1500 add changeset ef1ea85a6374
1500 add changeset ef1ea85a6374
1501 add changeset f9cafe1212c8
1501 add changeset f9cafe1212c8
1502 add changeset 911600dab2ae
1502 add changeset 911600dab2ae
1503 add changeset e8fc755d4d82
1503 add changeset e8fc755d4d82
1504 adding manifests
1504 adding manifests
1505 adding file changes
1505 adding file changes
1506 adding abc.txt revisions
1506 adding abc.txt revisions
1507 adding foo/Bar/file.txt revisions
1507 adding foo/Bar/file.txt revisions
1508 adding foo/file.txt revisions
1508 adding foo/file.txt revisions
1509 adding quux/file.py revisions
1509 adding quux/file.py revisions
1510 added 4 changesets with 4 changes to 4 files (+1 heads)
1510 added 4 changesets with 4 changes to 4 files (+1 heads)
1511 calling hook pretxnchangegroup.acl: hgext.acl.hook
1511 calling hook pretxnchangegroup.acl: hgext.acl.hook
1512 acl: checking access for user "astro"
1512 acl: checking access for user "astro"
1513 acl: acl.allow.branches not enabled
1513 acl: acl.allow.branches not enabled
1514 acl: acl.deny.branches not enabled
1514 acl: acl.deny.branches not enabled
1515 acl: acl.allow not enabled
1515 acl: acl.allow not enabled
1516 acl: acl.deny not enabled
1516 acl: acl.deny not enabled
1517 acl: branch access granted: "ef1ea85a6374" on branch "default"
1517 acl: branch access granted: "ef1ea85a6374" on branch "default"
1518 acl: path access granted: "ef1ea85a6374"
1518 acl: path access granted: "ef1ea85a6374"
1519 acl: branch access granted: "f9cafe1212c8" on branch "default"
1519 acl: branch access granted: "f9cafe1212c8" on branch "default"
1520 acl: path access granted: "f9cafe1212c8"
1520 acl: path access granted: "f9cafe1212c8"
1521 acl: branch access granted: "911600dab2ae" on branch "default"
1521 acl: branch access granted: "911600dab2ae" on branch "default"
1522 acl: path access granted: "911600dab2ae"
1522 acl: path access granted: "911600dab2ae"
1523 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1523 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1524 acl: path access granted: "e8fc755d4d82"
1524 acl: path access granted: "e8fc755d4d82"
1525 bundle2-input-part: total payload size 2101
1525 bundle2-input-part: total payload size 2101
1526 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1526 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1527 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1527 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1528 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1528 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1529 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1529 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1530 bundle2-input-bundle: 4 parts total
1530 bundle2-input-bundle: 4 parts total
1531 updating the branch cache
1531 updating the branch cache
1532 bundle2-output-bundle: "HG20", 3 parts total
1532 bundle2-output-bundle: "HG20", 3 parts total
1533 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1533 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1534 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1534 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1535 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1535 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1536 bundle2-input-bundle: with-transaction
1536 bundle2-input-bundle: with-transaction
1537 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1537 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1538 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1538 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1539 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1539 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1540 bundle2-input-bundle: 2 parts total
1540 bundle2-input-bundle: 2 parts total
1541 listing keys for "phases"
1541 listing keys for "phases"
1542 try to push obsolete markers to remote
1542 try to push obsolete markers to remote
1543 repository tip rolled back to revision 2 (undo push)
1543 repository tip rolled back to revision 2 (undo push)
1544 2:fb35475503ef
1544 2:fb35475503ef
1545
1545
1546
1546
1547 Branch acl deny test
1547 Branch acl deny test
1548
1548
1549 $ echo "[acl.deny.branches]" >> $config
1549 $ echo "[acl.deny.branches]" >> $config
1550 $ echo "foobar = *" >> $config
1550 $ echo "foobar = *" >> $config
1551 $ do_push astro
1551 $ do_push astro
1552 Pushing as user astro
1552 Pushing as user astro
1553 hgrc = """
1553 hgrc = """
1554 [hooks]
1554 [hooks]
1555 pretxnchangegroup.acl = python:hgext.acl.hook
1555 pretxnchangegroup.acl = python:hgext.acl.hook
1556 [acl]
1556 [acl]
1557 sources = push
1557 sources = push
1558 [extensions]
1558 [extensions]
1559 [acl.deny.branches]
1559 [acl.deny.branches]
1560 foobar = *
1560 foobar = *
1561 """
1561 """
1562 pushing to ../b
1562 pushing to ../b
1563 query 1; heads
1563 query 1; heads
1564 searching for changes
1564 searching for changes
1565 all remote heads known locally
1565 all remote heads known locally
1566 listing keys for "phases"
1566 listing keys for "phases"
1567 checking for updated bookmarks
1567 checking for updated bookmarks
1568 listing keys for "bookmarks"
1568 listing keys for "bookmarks"
1569 listing keys for "bookmarks"
1569 listing keys for "bookmarks"
1570 4 changesets found
1570 4 changesets found
1571 list of changesets:
1571 list of changesets:
1572 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1572 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1573 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1573 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1574 911600dab2ae7a9baff75958b84fe606851ce955
1574 911600dab2ae7a9baff75958b84fe606851ce955
1575 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1575 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1576 bundle2-output-bundle: "HG20", 5 parts total
1576 bundle2-output-bundle: "HG20", 5 parts total
1577 bundle2-output-part: "replycaps" 147 bytes payload
1577 bundle2-output-part: "replycaps" 155 bytes payload
1578 bundle2-output-part: "check:heads" streamed payload
1578 bundle2-output-part: "check:heads" streamed payload
1579 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1579 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1580 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1580 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1581 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1581 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1582 bundle2-input-bundle: with-transaction
1582 bundle2-input-bundle: with-transaction
1583 bundle2-input-part: "replycaps" supported
1583 bundle2-input-part: "replycaps" supported
1584 bundle2-input-part: total payload size 147
1584 bundle2-input-part: total payload size 155
1585 bundle2-input-part: "check:heads" supported
1585 bundle2-input-part: "check:heads" supported
1586 bundle2-input-part: total payload size 20
1586 bundle2-input-part: total payload size 20
1587 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1587 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1588 adding changesets
1588 adding changesets
1589 add changeset ef1ea85a6374
1589 add changeset ef1ea85a6374
1590 add changeset f9cafe1212c8
1590 add changeset f9cafe1212c8
1591 add changeset 911600dab2ae
1591 add changeset 911600dab2ae
1592 add changeset e8fc755d4d82
1592 add changeset e8fc755d4d82
1593 adding manifests
1593 adding manifests
1594 adding file changes
1594 adding file changes
1595 adding abc.txt revisions
1595 adding abc.txt revisions
1596 adding foo/Bar/file.txt revisions
1596 adding foo/Bar/file.txt revisions
1597 adding foo/file.txt revisions
1597 adding foo/file.txt revisions
1598 adding quux/file.py revisions
1598 adding quux/file.py revisions
1599 added 4 changesets with 4 changes to 4 files (+1 heads)
1599 added 4 changesets with 4 changes to 4 files (+1 heads)
1600 calling hook pretxnchangegroup.acl: hgext.acl.hook
1600 calling hook pretxnchangegroup.acl: hgext.acl.hook
1601 acl: checking access for user "astro"
1601 acl: checking access for user "astro"
1602 acl: acl.allow.branches not enabled
1602 acl: acl.allow.branches not enabled
1603 acl: acl.deny.branches enabled, 1 entries for user astro
1603 acl: acl.deny.branches enabled, 1 entries for user astro
1604 acl: acl.allow not enabled
1604 acl: acl.allow not enabled
1605 acl: acl.deny not enabled
1605 acl: acl.deny not enabled
1606 acl: branch access granted: "ef1ea85a6374" on branch "default"
1606 acl: branch access granted: "ef1ea85a6374" on branch "default"
1607 acl: path access granted: "ef1ea85a6374"
1607 acl: path access granted: "ef1ea85a6374"
1608 acl: branch access granted: "f9cafe1212c8" on branch "default"
1608 acl: branch access granted: "f9cafe1212c8" on branch "default"
1609 acl: path access granted: "f9cafe1212c8"
1609 acl: path access granted: "f9cafe1212c8"
1610 acl: branch access granted: "911600dab2ae" on branch "default"
1610 acl: branch access granted: "911600dab2ae" on branch "default"
1611 acl: path access granted: "911600dab2ae"
1611 acl: path access granted: "911600dab2ae"
1612 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1612 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1613 bundle2-input-part: total payload size 2101
1613 bundle2-input-part: total payload size 2101
1614 bundle2-input-bundle: 4 parts total
1614 bundle2-input-bundle: 4 parts total
1615 transaction abort!
1615 transaction abort!
1616 rollback completed
1616 rollback completed
1617 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1617 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1618 no rollback information available
1618 no rollback information available
1619 2:fb35475503ef
1619 2:fb35475503ef
1620
1620
1621
1621
1622 Branch acl empty allow test
1622 Branch acl empty allow test
1623
1623
1624 $ init_config
1624 $ init_config
1625 $ echo "[acl.allow.branches]" >> $config
1625 $ echo "[acl.allow.branches]" >> $config
1626 $ do_push astro
1626 $ do_push astro
1627 Pushing as user astro
1627 Pushing as user astro
1628 hgrc = """
1628 hgrc = """
1629 [hooks]
1629 [hooks]
1630 pretxnchangegroup.acl = python:hgext.acl.hook
1630 pretxnchangegroup.acl = python:hgext.acl.hook
1631 [acl]
1631 [acl]
1632 sources = push
1632 sources = push
1633 [extensions]
1633 [extensions]
1634 [acl.allow.branches]
1634 [acl.allow.branches]
1635 """
1635 """
1636 pushing to ../b
1636 pushing to ../b
1637 query 1; heads
1637 query 1; heads
1638 searching for changes
1638 searching for changes
1639 all remote heads known locally
1639 all remote heads known locally
1640 listing keys for "phases"
1640 listing keys for "phases"
1641 checking for updated bookmarks
1641 checking for updated bookmarks
1642 listing keys for "bookmarks"
1642 listing keys for "bookmarks"
1643 listing keys for "bookmarks"
1643 listing keys for "bookmarks"
1644 4 changesets found
1644 4 changesets found
1645 list of changesets:
1645 list of changesets:
1646 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1646 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1647 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1647 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1648 911600dab2ae7a9baff75958b84fe606851ce955
1648 911600dab2ae7a9baff75958b84fe606851ce955
1649 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1649 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1650 bundle2-output-bundle: "HG20", 5 parts total
1650 bundle2-output-bundle: "HG20", 5 parts total
1651 bundle2-output-part: "replycaps" 147 bytes payload
1651 bundle2-output-part: "replycaps" 155 bytes payload
1652 bundle2-output-part: "check:heads" streamed payload
1652 bundle2-output-part: "check:heads" streamed payload
1653 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1653 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1654 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1654 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1655 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1655 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1656 bundle2-input-bundle: with-transaction
1656 bundle2-input-bundle: with-transaction
1657 bundle2-input-part: "replycaps" supported
1657 bundle2-input-part: "replycaps" supported
1658 bundle2-input-part: total payload size 147
1658 bundle2-input-part: total payload size 155
1659 bundle2-input-part: "check:heads" supported
1659 bundle2-input-part: "check:heads" supported
1660 bundle2-input-part: total payload size 20
1660 bundle2-input-part: total payload size 20
1661 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1661 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1662 adding changesets
1662 adding changesets
1663 add changeset ef1ea85a6374
1663 add changeset ef1ea85a6374
1664 add changeset f9cafe1212c8
1664 add changeset f9cafe1212c8
1665 add changeset 911600dab2ae
1665 add changeset 911600dab2ae
1666 add changeset e8fc755d4d82
1666 add changeset e8fc755d4d82
1667 adding manifests
1667 adding manifests
1668 adding file changes
1668 adding file changes
1669 adding abc.txt revisions
1669 adding abc.txt revisions
1670 adding foo/Bar/file.txt revisions
1670 adding foo/Bar/file.txt revisions
1671 adding foo/file.txt revisions
1671 adding foo/file.txt revisions
1672 adding quux/file.py revisions
1672 adding quux/file.py revisions
1673 added 4 changesets with 4 changes to 4 files (+1 heads)
1673 added 4 changesets with 4 changes to 4 files (+1 heads)
1674 calling hook pretxnchangegroup.acl: hgext.acl.hook
1674 calling hook pretxnchangegroup.acl: hgext.acl.hook
1675 acl: checking access for user "astro"
1675 acl: checking access for user "astro"
1676 acl: acl.allow.branches enabled, 0 entries for user astro
1676 acl: acl.allow.branches enabled, 0 entries for user astro
1677 acl: acl.deny.branches not enabled
1677 acl: acl.deny.branches not enabled
1678 acl: acl.allow not enabled
1678 acl: acl.allow not enabled
1679 acl: acl.deny not enabled
1679 acl: acl.deny not enabled
1680 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1680 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1681 bundle2-input-part: total payload size 2101
1681 bundle2-input-part: total payload size 2101
1682 bundle2-input-bundle: 4 parts total
1682 bundle2-input-bundle: 4 parts total
1683 transaction abort!
1683 transaction abort!
1684 rollback completed
1684 rollback completed
1685 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1685 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1686 no rollback information available
1686 no rollback information available
1687 2:fb35475503ef
1687 2:fb35475503ef
1688
1688
1689
1689
1690 Branch acl allow other
1690 Branch acl allow other
1691
1691
1692 $ init_config
1692 $ init_config
1693 $ echo "[acl.allow.branches]" >> $config
1693 $ echo "[acl.allow.branches]" >> $config
1694 $ echo "* = george" >> $config
1694 $ echo "* = george" >> $config
1695 $ do_push astro
1695 $ do_push astro
1696 Pushing as user astro
1696 Pushing as user astro
1697 hgrc = """
1697 hgrc = """
1698 [hooks]
1698 [hooks]
1699 pretxnchangegroup.acl = python:hgext.acl.hook
1699 pretxnchangegroup.acl = python:hgext.acl.hook
1700 [acl]
1700 [acl]
1701 sources = push
1701 sources = push
1702 [extensions]
1702 [extensions]
1703 [acl.allow.branches]
1703 [acl.allow.branches]
1704 * = george
1704 * = george
1705 """
1705 """
1706 pushing to ../b
1706 pushing to ../b
1707 query 1; heads
1707 query 1; heads
1708 searching for changes
1708 searching for changes
1709 all remote heads known locally
1709 all remote heads known locally
1710 listing keys for "phases"
1710 listing keys for "phases"
1711 checking for updated bookmarks
1711 checking for updated bookmarks
1712 listing keys for "bookmarks"
1712 listing keys for "bookmarks"
1713 listing keys for "bookmarks"
1713 listing keys for "bookmarks"
1714 4 changesets found
1714 4 changesets found
1715 list of changesets:
1715 list of changesets:
1716 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1716 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1717 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1717 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1718 911600dab2ae7a9baff75958b84fe606851ce955
1718 911600dab2ae7a9baff75958b84fe606851ce955
1719 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1719 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1720 bundle2-output-bundle: "HG20", 5 parts total
1720 bundle2-output-bundle: "HG20", 5 parts total
1721 bundle2-output-part: "replycaps" 147 bytes payload
1721 bundle2-output-part: "replycaps" 155 bytes payload
1722 bundle2-output-part: "check:heads" streamed payload
1722 bundle2-output-part: "check:heads" streamed payload
1723 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1723 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1724 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1724 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1725 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1725 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1726 bundle2-input-bundle: with-transaction
1726 bundle2-input-bundle: with-transaction
1727 bundle2-input-part: "replycaps" supported
1727 bundle2-input-part: "replycaps" supported
1728 bundle2-input-part: total payload size 147
1728 bundle2-input-part: total payload size 155
1729 bundle2-input-part: "check:heads" supported
1729 bundle2-input-part: "check:heads" supported
1730 bundle2-input-part: total payload size 20
1730 bundle2-input-part: total payload size 20
1731 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1731 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1732 adding changesets
1732 adding changesets
1733 add changeset ef1ea85a6374
1733 add changeset ef1ea85a6374
1734 add changeset f9cafe1212c8
1734 add changeset f9cafe1212c8
1735 add changeset 911600dab2ae
1735 add changeset 911600dab2ae
1736 add changeset e8fc755d4d82
1736 add changeset e8fc755d4d82
1737 adding manifests
1737 adding manifests
1738 adding file changes
1738 adding file changes
1739 adding abc.txt revisions
1739 adding abc.txt revisions
1740 adding foo/Bar/file.txt revisions
1740 adding foo/Bar/file.txt revisions
1741 adding foo/file.txt revisions
1741 adding foo/file.txt revisions
1742 adding quux/file.py revisions
1742 adding quux/file.py revisions
1743 added 4 changesets with 4 changes to 4 files (+1 heads)
1743 added 4 changesets with 4 changes to 4 files (+1 heads)
1744 calling hook pretxnchangegroup.acl: hgext.acl.hook
1744 calling hook pretxnchangegroup.acl: hgext.acl.hook
1745 acl: checking access for user "astro"
1745 acl: checking access for user "astro"
1746 acl: acl.allow.branches enabled, 0 entries for user astro
1746 acl: acl.allow.branches enabled, 0 entries for user astro
1747 acl: acl.deny.branches not enabled
1747 acl: acl.deny.branches not enabled
1748 acl: acl.allow not enabled
1748 acl: acl.allow not enabled
1749 acl: acl.deny not enabled
1749 acl: acl.deny not enabled
1750 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1750 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1751 bundle2-input-part: total payload size 2101
1751 bundle2-input-part: total payload size 2101
1752 bundle2-input-bundle: 4 parts total
1752 bundle2-input-bundle: 4 parts total
1753 transaction abort!
1753 transaction abort!
1754 rollback completed
1754 rollback completed
1755 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1755 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1756 no rollback information available
1756 no rollback information available
1757 2:fb35475503ef
1757 2:fb35475503ef
1758
1758
1759 $ do_push george
1759 $ do_push george
1760 Pushing as user george
1760 Pushing as user george
1761 hgrc = """
1761 hgrc = """
1762 [hooks]
1762 [hooks]
1763 pretxnchangegroup.acl = python:hgext.acl.hook
1763 pretxnchangegroup.acl = python:hgext.acl.hook
1764 [acl]
1764 [acl]
1765 sources = push
1765 sources = push
1766 [extensions]
1766 [extensions]
1767 [acl.allow.branches]
1767 [acl.allow.branches]
1768 * = george
1768 * = george
1769 """
1769 """
1770 pushing to ../b
1770 pushing to ../b
1771 query 1; heads
1771 query 1; heads
1772 searching for changes
1772 searching for changes
1773 all remote heads known locally
1773 all remote heads known locally
1774 listing keys for "phases"
1774 listing keys for "phases"
1775 checking for updated bookmarks
1775 checking for updated bookmarks
1776 listing keys for "bookmarks"
1776 listing keys for "bookmarks"
1777 listing keys for "bookmarks"
1777 listing keys for "bookmarks"
1778 4 changesets found
1778 4 changesets found
1779 list of changesets:
1779 list of changesets:
1780 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1780 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1781 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1781 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1782 911600dab2ae7a9baff75958b84fe606851ce955
1782 911600dab2ae7a9baff75958b84fe606851ce955
1783 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1783 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1784 bundle2-output-bundle: "HG20", 5 parts total
1784 bundle2-output-bundle: "HG20", 5 parts total
1785 bundle2-output-part: "replycaps" 147 bytes payload
1785 bundle2-output-part: "replycaps" 155 bytes payload
1786 bundle2-output-part: "check:heads" streamed payload
1786 bundle2-output-part: "check:heads" streamed payload
1787 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1787 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1788 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1788 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1789 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1789 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1790 bundle2-input-bundle: with-transaction
1790 bundle2-input-bundle: with-transaction
1791 bundle2-input-part: "replycaps" supported
1791 bundle2-input-part: "replycaps" supported
1792 bundle2-input-part: total payload size 147
1792 bundle2-input-part: total payload size 155
1793 bundle2-input-part: "check:heads" supported
1793 bundle2-input-part: "check:heads" supported
1794 bundle2-input-part: total payload size 20
1794 bundle2-input-part: total payload size 20
1795 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1795 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1796 adding changesets
1796 adding changesets
1797 add changeset ef1ea85a6374
1797 add changeset ef1ea85a6374
1798 add changeset f9cafe1212c8
1798 add changeset f9cafe1212c8
1799 add changeset 911600dab2ae
1799 add changeset 911600dab2ae
1800 add changeset e8fc755d4d82
1800 add changeset e8fc755d4d82
1801 adding manifests
1801 adding manifests
1802 adding file changes
1802 adding file changes
1803 adding abc.txt revisions
1803 adding abc.txt revisions
1804 adding foo/Bar/file.txt revisions
1804 adding foo/Bar/file.txt revisions
1805 adding foo/file.txt revisions
1805 adding foo/file.txt revisions
1806 adding quux/file.py revisions
1806 adding quux/file.py revisions
1807 added 4 changesets with 4 changes to 4 files (+1 heads)
1807 added 4 changesets with 4 changes to 4 files (+1 heads)
1808 calling hook pretxnchangegroup.acl: hgext.acl.hook
1808 calling hook pretxnchangegroup.acl: hgext.acl.hook
1809 acl: checking access for user "george"
1809 acl: checking access for user "george"
1810 acl: acl.allow.branches enabled, 1 entries for user george
1810 acl: acl.allow.branches enabled, 1 entries for user george
1811 acl: acl.deny.branches not enabled
1811 acl: acl.deny.branches not enabled
1812 acl: acl.allow not enabled
1812 acl: acl.allow not enabled
1813 acl: acl.deny not enabled
1813 acl: acl.deny not enabled
1814 acl: branch access granted: "ef1ea85a6374" on branch "default"
1814 acl: branch access granted: "ef1ea85a6374" on branch "default"
1815 acl: path access granted: "ef1ea85a6374"
1815 acl: path access granted: "ef1ea85a6374"
1816 acl: branch access granted: "f9cafe1212c8" on branch "default"
1816 acl: branch access granted: "f9cafe1212c8" on branch "default"
1817 acl: path access granted: "f9cafe1212c8"
1817 acl: path access granted: "f9cafe1212c8"
1818 acl: branch access granted: "911600dab2ae" on branch "default"
1818 acl: branch access granted: "911600dab2ae" on branch "default"
1819 acl: path access granted: "911600dab2ae"
1819 acl: path access granted: "911600dab2ae"
1820 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1820 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1821 acl: path access granted: "e8fc755d4d82"
1821 acl: path access granted: "e8fc755d4d82"
1822 bundle2-input-part: total payload size 2101
1822 bundle2-input-part: total payload size 2101
1823 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1823 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1824 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1824 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1825 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1825 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1826 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1826 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1827 bundle2-input-bundle: 4 parts total
1827 bundle2-input-bundle: 4 parts total
1828 updating the branch cache
1828 updating the branch cache
1829 bundle2-output-bundle: "HG20", 3 parts total
1829 bundle2-output-bundle: "HG20", 3 parts total
1830 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1830 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1831 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1831 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1832 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1832 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1833 bundle2-input-bundle: with-transaction
1833 bundle2-input-bundle: with-transaction
1834 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1834 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1835 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1835 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1836 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1836 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1837 bundle2-input-bundle: 2 parts total
1837 bundle2-input-bundle: 2 parts total
1838 listing keys for "phases"
1838 listing keys for "phases"
1839 try to push obsolete markers to remote
1839 try to push obsolete markers to remote
1840 repository tip rolled back to revision 2 (undo push)
1840 repository tip rolled back to revision 2 (undo push)
1841 2:fb35475503ef
1841 2:fb35475503ef
1842
1842
1843
1843
1844 Branch acl conflicting allow
1844 Branch acl conflicting allow
1845 asterisk ends up applying to all branches and allowing george to
1845 asterisk ends up applying to all branches and allowing george to
1846 push foobar into the remote
1846 push foobar into the remote
1847
1847
1848 $ init_config
1848 $ init_config
1849 $ echo "[acl.allow.branches]" >> $config
1849 $ echo "[acl.allow.branches]" >> $config
1850 $ echo "foobar = astro" >> $config
1850 $ echo "foobar = astro" >> $config
1851 $ echo "* = george" >> $config
1851 $ echo "* = george" >> $config
1852 $ do_push george
1852 $ do_push george
1853 Pushing as user george
1853 Pushing as user george
1854 hgrc = """
1854 hgrc = """
1855 [hooks]
1855 [hooks]
1856 pretxnchangegroup.acl = python:hgext.acl.hook
1856 pretxnchangegroup.acl = python:hgext.acl.hook
1857 [acl]
1857 [acl]
1858 sources = push
1858 sources = push
1859 [extensions]
1859 [extensions]
1860 [acl.allow.branches]
1860 [acl.allow.branches]
1861 foobar = astro
1861 foobar = astro
1862 * = george
1862 * = george
1863 """
1863 """
1864 pushing to ../b
1864 pushing to ../b
1865 query 1; heads
1865 query 1; heads
1866 searching for changes
1866 searching for changes
1867 all remote heads known locally
1867 all remote heads known locally
1868 listing keys for "phases"
1868 listing keys for "phases"
1869 checking for updated bookmarks
1869 checking for updated bookmarks
1870 listing keys for "bookmarks"
1870 listing keys for "bookmarks"
1871 listing keys for "bookmarks"
1871 listing keys for "bookmarks"
1872 4 changesets found
1872 4 changesets found
1873 list of changesets:
1873 list of changesets:
1874 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1874 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1875 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1875 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1876 911600dab2ae7a9baff75958b84fe606851ce955
1876 911600dab2ae7a9baff75958b84fe606851ce955
1877 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1877 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1878 bundle2-output-bundle: "HG20", 5 parts total
1878 bundle2-output-bundle: "HG20", 5 parts total
1879 bundle2-output-part: "replycaps" 147 bytes payload
1879 bundle2-output-part: "replycaps" 155 bytes payload
1880 bundle2-output-part: "check:heads" streamed payload
1880 bundle2-output-part: "check:heads" streamed payload
1881 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1881 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1882 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1882 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1883 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1883 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1884 bundle2-input-bundle: with-transaction
1884 bundle2-input-bundle: with-transaction
1885 bundle2-input-part: "replycaps" supported
1885 bundle2-input-part: "replycaps" supported
1886 bundle2-input-part: total payload size 147
1886 bundle2-input-part: total payload size 155
1887 bundle2-input-part: "check:heads" supported
1887 bundle2-input-part: "check:heads" supported
1888 bundle2-input-part: total payload size 20
1888 bundle2-input-part: total payload size 20
1889 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1889 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1890 adding changesets
1890 adding changesets
1891 add changeset ef1ea85a6374
1891 add changeset ef1ea85a6374
1892 add changeset f9cafe1212c8
1892 add changeset f9cafe1212c8
1893 add changeset 911600dab2ae
1893 add changeset 911600dab2ae
1894 add changeset e8fc755d4d82
1894 add changeset e8fc755d4d82
1895 adding manifests
1895 adding manifests
1896 adding file changes
1896 adding file changes
1897 adding abc.txt revisions
1897 adding abc.txt revisions
1898 adding foo/Bar/file.txt revisions
1898 adding foo/Bar/file.txt revisions
1899 adding foo/file.txt revisions
1899 adding foo/file.txt revisions
1900 adding quux/file.py revisions
1900 adding quux/file.py revisions
1901 added 4 changesets with 4 changes to 4 files (+1 heads)
1901 added 4 changesets with 4 changes to 4 files (+1 heads)
1902 calling hook pretxnchangegroup.acl: hgext.acl.hook
1902 calling hook pretxnchangegroup.acl: hgext.acl.hook
1903 acl: checking access for user "george"
1903 acl: checking access for user "george"
1904 acl: acl.allow.branches enabled, 1 entries for user george
1904 acl: acl.allow.branches enabled, 1 entries for user george
1905 acl: acl.deny.branches not enabled
1905 acl: acl.deny.branches not enabled
1906 acl: acl.allow not enabled
1906 acl: acl.allow not enabled
1907 acl: acl.deny not enabled
1907 acl: acl.deny not enabled
1908 acl: branch access granted: "ef1ea85a6374" on branch "default"
1908 acl: branch access granted: "ef1ea85a6374" on branch "default"
1909 acl: path access granted: "ef1ea85a6374"
1909 acl: path access granted: "ef1ea85a6374"
1910 acl: branch access granted: "f9cafe1212c8" on branch "default"
1910 acl: branch access granted: "f9cafe1212c8" on branch "default"
1911 acl: path access granted: "f9cafe1212c8"
1911 acl: path access granted: "f9cafe1212c8"
1912 acl: branch access granted: "911600dab2ae" on branch "default"
1912 acl: branch access granted: "911600dab2ae" on branch "default"
1913 acl: path access granted: "911600dab2ae"
1913 acl: path access granted: "911600dab2ae"
1914 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1914 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1915 acl: path access granted: "e8fc755d4d82"
1915 acl: path access granted: "e8fc755d4d82"
1916 bundle2-input-part: total payload size 2101
1916 bundle2-input-part: total payload size 2101
1917 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1917 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1918 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1918 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1919 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1919 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1920 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1920 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1921 bundle2-input-bundle: 4 parts total
1921 bundle2-input-bundle: 4 parts total
1922 updating the branch cache
1922 updating the branch cache
1923 bundle2-output-bundle: "HG20", 3 parts total
1923 bundle2-output-bundle: "HG20", 3 parts total
1924 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1924 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1925 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1925 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1926 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1926 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1927 bundle2-input-bundle: with-transaction
1927 bundle2-input-bundle: with-transaction
1928 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1928 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1929 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1929 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1930 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1930 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1931 bundle2-input-bundle: 2 parts total
1931 bundle2-input-bundle: 2 parts total
1932 listing keys for "phases"
1932 listing keys for "phases"
1933 try to push obsolete markers to remote
1933 try to push obsolete markers to remote
1934 repository tip rolled back to revision 2 (undo push)
1934 repository tip rolled back to revision 2 (undo push)
1935 2:fb35475503ef
1935 2:fb35475503ef
1936
1936
1937 Branch acl conflicting deny
1937 Branch acl conflicting deny
1938
1938
1939 $ init_config
1939 $ init_config
1940 $ echo "[acl.deny.branches]" >> $config
1940 $ echo "[acl.deny.branches]" >> $config
1941 $ echo "foobar = astro" >> $config
1941 $ echo "foobar = astro" >> $config
1942 $ echo "default = astro" >> $config
1942 $ echo "default = astro" >> $config
1943 $ echo "* = george" >> $config
1943 $ echo "* = george" >> $config
1944 $ do_push george
1944 $ do_push george
1945 Pushing as user george
1945 Pushing as user george
1946 hgrc = """
1946 hgrc = """
1947 [hooks]
1947 [hooks]
1948 pretxnchangegroup.acl = python:hgext.acl.hook
1948 pretxnchangegroup.acl = python:hgext.acl.hook
1949 [acl]
1949 [acl]
1950 sources = push
1950 sources = push
1951 [extensions]
1951 [extensions]
1952 [acl.deny.branches]
1952 [acl.deny.branches]
1953 foobar = astro
1953 foobar = astro
1954 default = astro
1954 default = astro
1955 * = george
1955 * = george
1956 """
1956 """
1957 pushing to ../b
1957 pushing to ../b
1958 query 1; heads
1958 query 1; heads
1959 searching for changes
1959 searching for changes
1960 all remote heads known locally
1960 all remote heads known locally
1961 listing keys for "phases"
1961 listing keys for "phases"
1962 checking for updated bookmarks
1962 checking for updated bookmarks
1963 listing keys for "bookmarks"
1963 listing keys for "bookmarks"
1964 listing keys for "bookmarks"
1964 listing keys for "bookmarks"
1965 4 changesets found
1965 4 changesets found
1966 list of changesets:
1966 list of changesets:
1967 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1967 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1968 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1968 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1969 911600dab2ae7a9baff75958b84fe606851ce955
1969 911600dab2ae7a9baff75958b84fe606851ce955
1970 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1970 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1971 bundle2-output-bundle: "HG20", 5 parts total
1971 bundle2-output-bundle: "HG20", 5 parts total
1972 bundle2-output-part: "replycaps" 147 bytes payload
1972 bundle2-output-part: "replycaps" 155 bytes payload
1973 bundle2-output-part: "check:heads" streamed payload
1973 bundle2-output-part: "check:heads" streamed payload
1974 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1974 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1975 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1975 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1976 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1976 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1977 bundle2-input-bundle: with-transaction
1977 bundle2-input-bundle: with-transaction
1978 bundle2-input-part: "replycaps" supported
1978 bundle2-input-part: "replycaps" supported
1979 bundle2-input-part: total payload size 147
1979 bundle2-input-part: total payload size 155
1980 bundle2-input-part: "check:heads" supported
1980 bundle2-input-part: "check:heads" supported
1981 bundle2-input-part: total payload size 20
1981 bundle2-input-part: total payload size 20
1982 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1982 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1983 adding changesets
1983 adding changesets
1984 add changeset ef1ea85a6374
1984 add changeset ef1ea85a6374
1985 add changeset f9cafe1212c8
1985 add changeset f9cafe1212c8
1986 add changeset 911600dab2ae
1986 add changeset 911600dab2ae
1987 add changeset e8fc755d4d82
1987 add changeset e8fc755d4d82
1988 adding manifests
1988 adding manifests
1989 adding file changes
1989 adding file changes
1990 adding abc.txt revisions
1990 adding abc.txt revisions
1991 adding foo/Bar/file.txt revisions
1991 adding foo/Bar/file.txt revisions
1992 adding foo/file.txt revisions
1992 adding foo/file.txt revisions
1993 adding quux/file.py revisions
1993 adding quux/file.py revisions
1994 added 4 changesets with 4 changes to 4 files (+1 heads)
1994 added 4 changesets with 4 changes to 4 files (+1 heads)
1995 calling hook pretxnchangegroup.acl: hgext.acl.hook
1995 calling hook pretxnchangegroup.acl: hgext.acl.hook
1996 acl: checking access for user "george"
1996 acl: checking access for user "george"
1997 acl: acl.allow.branches not enabled
1997 acl: acl.allow.branches not enabled
1998 acl: acl.deny.branches enabled, 1 entries for user george
1998 acl: acl.deny.branches enabled, 1 entries for user george
1999 acl: acl.allow not enabled
1999 acl: acl.allow not enabled
2000 acl: acl.deny not enabled
2000 acl: acl.deny not enabled
2001 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2001 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2002 bundle2-input-part: total payload size 2101
2002 bundle2-input-part: total payload size 2101
2003 bundle2-input-bundle: 4 parts total
2003 bundle2-input-bundle: 4 parts total
2004 transaction abort!
2004 transaction abort!
2005 rollback completed
2005 rollback completed
2006 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2006 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2007 no rollback information available
2007 no rollback information available
2008 2:fb35475503ef
2008 2:fb35475503ef
2009
2009
2010 User 'astro' must not be denied
2010 User 'astro' must not be denied
2011
2011
2012 $ init_config
2012 $ init_config
2013 $ echo "[acl.deny.branches]" >> $config
2013 $ echo "[acl.deny.branches]" >> $config
2014 $ echo "default = !astro" >> $config
2014 $ echo "default = !astro" >> $config
2015 $ do_push astro
2015 $ do_push astro
2016 Pushing as user astro
2016 Pushing as user astro
2017 hgrc = """
2017 hgrc = """
2018 [hooks]
2018 [hooks]
2019 pretxnchangegroup.acl = python:hgext.acl.hook
2019 pretxnchangegroup.acl = python:hgext.acl.hook
2020 [acl]
2020 [acl]
2021 sources = push
2021 sources = push
2022 [extensions]
2022 [extensions]
2023 [acl.deny.branches]
2023 [acl.deny.branches]
2024 default = !astro
2024 default = !astro
2025 """
2025 """
2026 pushing to ../b
2026 pushing to ../b
2027 query 1; heads
2027 query 1; heads
2028 searching for changes
2028 searching for changes
2029 all remote heads known locally
2029 all remote heads known locally
2030 listing keys for "phases"
2030 listing keys for "phases"
2031 checking for updated bookmarks
2031 checking for updated bookmarks
2032 listing keys for "bookmarks"
2032 listing keys for "bookmarks"
2033 listing keys for "bookmarks"
2033 listing keys for "bookmarks"
2034 4 changesets found
2034 4 changesets found
2035 list of changesets:
2035 list of changesets:
2036 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2036 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2037 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2037 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2038 911600dab2ae7a9baff75958b84fe606851ce955
2038 911600dab2ae7a9baff75958b84fe606851ce955
2039 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2039 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2040 bundle2-output-bundle: "HG20", 5 parts total
2040 bundle2-output-bundle: "HG20", 5 parts total
2041 bundle2-output-part: "replycaps" 147 bytes payload
2041 bundle2-output-part: "replycaps" 155 bytes payload
2042 bundle2-output-part: "check:heads" streamed payload
2042 bundle2-output-part: "check:heads" streamed payload
2043 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2043 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2044 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2044 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2045 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2045 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2046 bundle2-input-bundle: with-transaction
2046 bundle2-input-bundle: with-transaction
2047 bundle2-input-part: "replycaps" supported
2047 bundle2-input-part: "replycaps" supported
2048 bundle2-input-part: total payload size 147
2048 bundle2-input-part: total payload size 155
2049 bundle2-input-part: "check:heads" supported
2049 bundle2-input-part: "check:heads" supported
2050 bundle2-input-part: total payload size 20
2050 bundle2-input-part: total payload size 20
2051 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2051 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2052 adding changesets
2052 adding changesets
2053 add changeset ef1ea85a6374
2053 add changeset ef1ea85a6374
2054 add changeset f9cafe1212c8
2054 add changeset f9cafe1212c8
2055 add changeset 911600dab2ae
2055 add changeset 911600dab2ae
2056 add changeset e8fc755d4d82
2056 add changeset e8fc755d4d82
2057 adding manifests
2057 adding manifests
2058 adding file changes
2058 adding file changes
2059 adding abc.txt revisions
2059 adding abc.txt revisions
2060 adding foo/Bar/file.txt revisions
2060 adding foo/Bar/file.txt revisions
2061 adding foo/file.txt revisions
2061 adding foo/file.txt revisions
2062 adding quux/file.py revisions
2062 adding quux/file.py revisions
2063 added 4 changesets with 4 changes to 4 files (+1 heads)
2063 added 4 changesets with 4 changes to 4 files (+1 heads)
2064 calling hook pretxnchangegroup.acl: hgext.acl.hook
2064 calling hook pretxnchangegroup.acl: hgext.acl.hook
2065 acl: checking access for user "astro"
2065 acl: checking access for user "astro"
2066 acl: acl.allow.branches not enabled
2066 acl: acl.allow.branches not enabled
2067 acl: acl.deny.branches enabled, 0 entries for user astro
2067 acl: acl.deny.branches enabled, 0 entries for user astro
2068 acl: acl.allow not enabled
2068 acl: acl.allow not enabled
2069 acl: acl.deny not enabled
2069 acl: acl.deny not enabled
2070 acl: branch access granted: "ef1ea85a6374" on branch "default"
2070 acl: branch access granted: "ef1ea85a6374" on branch "default"
2071 acl: path access granted: "ef1ea85a6374"
2071 acl: path access granted: "ef1ea85a6374"
2072 acl: branch access granted: "f9cafe1212c8" on branch "default"
2072 acl: branch access granted: "f9cafe1212c8" on branch "default"
2073 acl: path access granted: "f9cafe1212c8"
2073 acl: path access granted: "f9cafe1212c8"
2074 acl: branch access granted: "911600dab2ae" on branch "default"
2074 acl: branch access granted: "911600dab2ae" on branch "default"
2075 acl: path access granted: "911600dab2ae"
2075 acl: path access granted: "911600dab2ae"
2076 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2076 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2077 acl: path access granted: "e8fc755d4d82"
2077 acl: path access granted: "e8fc755d4d82"
2078 bundle2-input-part: total payload size 2101
2078 bundle2-input-part: total payload size 2101
2079 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2079 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2080 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2080 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2081 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2081 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2082 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2082 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2083 bundle2-input-bundle: 4 parts total
2083 bundle2-input-bundle: 4 parts total
2084 updating the branch cache
2084 updating the branch cache
2085 bundle2-output-bundle: "HG20", 3 parts total
2085 bundle2-output-bundle: "HG20", 3 parts total
2086 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2086 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2087 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2087 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2088 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2088 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2089 bundle2-input-bundle: with-transaction
2089 bundle2-input-bundle: with-transaction
2090 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2090 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2091 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2091 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2092 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2092 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2093 bundle2-input-bundle: 2 parts total
2093 bundle2-input-bundle: 2 parts total
2094 listing keys for "phases"
2094 listing keys for "phases"
2095 try to push obsolete markers to remote
2095 try to push obsolete markers to remote
2096 repository tip rolled back to revision 2 (undo push)
2096 repository tip rolled back to revision 2 (undo push)
2097 2:fb35475503ef
2097 2:fb35475503ef
2098
2098
2099
2099
2100 Non-astro users must be denied
2100 Non-astro users must be denied
2101
2101
2102 $ do_push george
2102 $ do_push george
2103 Pushing as user george
2103 Pushing as user george
2104 hgrc = """
2104 hgrc = """
2105 [hooks]
2105 [hooks]
2106 pretxnchangegroup.acl = python:hgext.acl.hook
2106 pretxnchangegroup.acl = python:hgext.acl.hook
2107 [acl]
2107 [acl]
2108 sources = push
2108 sources = push
2109 [extensions]
2109 [extensions]
2110 [acl.deny.branches]
2110 [acl.deny.branches]
2111 default = !astro
2111 default = !astro
2112 """
2112 """
2113 pushing to ../b
2113 pushing to ../b
2114 query 1; heads
2114 query 1; heads
2115 searching for changes
2115 searching for changes
2116 all remote heads known locally
2116 all remote heads known locally
2117 listing keys for "phases"
2117 listing keys for "phases"
2118 checking for updated bookmarks
2118 checking for updated bookmarks
2119 listing keys for "bookmarks"
2119 listing keys for "bookmarks"
2120 listing keys for "bookmarks"
2120 listing keys for "bookmarks"
2121 4 changesets found
2121 4 changesets found
2122 list of changesets:
2122 list of changesets:
2123 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2123 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2124 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2124 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2125 911600dab2ae7a9baff75958b84fe606851ce955
2125 911600dab2ae7a9baff75958b84fe606851ce955
2126 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2126 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2127 bundle2-output-bundle: "HG20", 5 parts total
2127 bundle2-output-bundle: "HG20", 5 parts total
2128 bundle2-output-part: "replycaps" 147 bytes payload
2128 bundle2-output-part: "replycaps" 155 bytes payload
2129 bundle2-output-part: "check:heads" streamed payload
2129 bundle2-output-part: "check:heads" streamed payload
2130 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2130 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2131 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2131 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2132 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2132 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2133 bundle2-input-bundle: with-transaction
2133 bundle2-input-bundle: with-transaction
2134 bundle2-input-part: "replycaps" supported
2134 bundle2-input-part: "replycaps" supported
2135 bundle2-input-part: total payload size 147
2135 bundle2-input-part: total payload size 155
2136 bundle2-input-part: "check:heads" supported
2136 bundle2-input-part: "check:heads" supported
2137 bundle2-input-part: total payload size 20
2137 bundle2-input-part: total payload size 20
2138 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2138 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2139 adding changesets
2139 adding changesets
2140 add changeset ef1ea85a6374
2140 add changeset ef1ea85a6374
2141 add changeset f9cafe1212c8
2141 add changeset f9cafe1212c8
2142 add changeset 911600dab2ae
2142 add changeset 911600dab2ae
2143 add changeset e8fc755d4d82
2143 add changeset e8fc755d4d82
2144 adding manifests
2144 adding manifests
2145 adding file changes
2145 adding file changes
2146 adding abc.txt revisions
2146 adding abc.txt revisions
2147 adding foo/Bar/file.txt revisions
2147 adding foo/Bar/file.txt revisions
2148 adding foo/file.txt revisions
2148 adding foo/file.txt revisions
2149 adding quux/file.py revisions
2149 adding quux/file.py revisions
2150 added 4 changesets with 4 changes to 4 files (+1 heads)
2150 added 4 changesets with 4 changes to 4 files (+1 heads)
2151 calling hook pretxnchangegroup.acl: hgext.acl.hook
2151 calling hook pretxnchangegroup.acl: hgext.acl.hook
2152 acl: checking access for user "george"
2152 acl: checking access for user "george"
2153 acl: acl.allow.branches not enabled
2153 acl: acl.allow.branches not enabled
2154 acl: acl.deny.branches enabled, 1 entries for user george
2154 acl: acl.deny.branches enabled, 1 entries for user george
2155 acl: acl.allow not enabled
2155 acl: acl.allow not enabled
2156 acl: acl.deny not enabled
2156 acl: acl.deny not enabled
2157 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2157 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2158 bundle2-input-part: total payload size 2101
2158 bundle2-input-part: total payload size 2101
2159 bundle2-input-bundle: 4 parts total
2159 bundle2-input-bundle: 4 parts total
2160 transaction abort!
2160 transaction abort!
2161 rollback completed
2161 rollback completed
2162 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2162 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2163 no rollback information available
2163 no rollback information available
2164 2:fb35475503ef
2164 2:fb35475503ef
2165
2165
2166
2166
@@ -1,869 +1,869 b''
1 Test exchange of common information using bundle2
1 Test exchange of common information using bundle2
2
2
3
3
4 $ getmainid() {
4 $ getmainid() {
5 > hg -R main log --template '{node}\n' --rev "$1"
5 > hg -R main log --template '{node}\n' --rev "$1"
6 > }
6 > }
7
7
8 enable obsolescence
8 enable obsolescence
9
9
10 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
10 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
11 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
11 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
12 > hg debuglock
12 > hg debuglock
13 > EOF
13 > EOF
14
14
15 $ cat >> $HGRCPATH << EOF
15 $ cat >> $HGRCPATH << EOF
16 > [experimental]
16 > [experimental]
17 > evolution=createmarkers,exchange
17 > evolution=createmarkers,exchange
18 > bundle2-exp=True
18 > bundle2-exp=True
19 > bundle2-output-capture=True
19 > bundle2-output-capture=True
20 > [ui]
20 > [ui]
21 > ssh=dummyssh
21 > ssh=dummyssh
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 > [web]
23 > [web]
24 > push_ssl = false
24 > push_ssl = false
25 > allow_push = *
25 > allow_push = *
26 > [phases]
26 > [phases]
27 > publish=False
27 > publish=False
28 > [hooks]
28 > [hooks]
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
33 > EOF
33 > EOF
34
34
35 The extension requires a repo (currently unused)
35 The extension requires a repo (currently unused)
36
36
37 $ hg init main
37 $ hg init main
38 $ cd main
38 $ cd main
39 $ touch a
39 $ touch a
40 $ hg add a
40 $ hg add a
41 $ hg commit -m 'a'
41 $ hg commit -m 'a'
42 pre-close-tip:3903775176ed draft
42 pre-close-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
45
45
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
47 adding changesets
47 adding changesets
48 adding manifests
48 adding manifests
49 adding file changes
49 adding file changes
50 added 8 changesets with 7 changes to 7 files (+3 heads)
50 added 8 changesets with 7 changes to 7 files (+3 heads)
51 pre-close-tip:02de42196ebe draft
51 pre-close-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob)
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob)
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
56
56
57 $ cd ..
57 $ cd ..
58
58
59 Real world exchange
59 Real world exchange
60 =====================
60 =====================
61
61
62 Add more obsolescence information
62 Add more obsolescence information
63
63
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
65 pre-close-tip:02de42196ebe draft
65 pre-close-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
69 pre-close-tip:02de42196ebe draft
69 pre-close-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
72
72
73 clone --pull
73 clone --pull
74
74
75 $ hg -R main phase --public cd010b8cd998
75 $ hg -R main phase --public cd010b8cd998
76 pre-close-tip:02de42196ebe draft
76 pre-close-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
79 $ hg clone main other --pull --rev 9520eea781bc
79 $ hg clone main other --pull --rev 9520eea781bc
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 2 changesets with 2 changes to 2 files
83 added 2 changesets with 2 changes to 2 files
84 1 new obsolescence markers
84 1 new obsolescence markers
85 pre-close-tip:9520eea781bc draft
85 pre-close-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
89 updating to branch default
89 updating to branch default
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 $ hg -R other log -G
91 $ hg -R other log -G
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
93 |
93 |
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
95
95
96 $ hg -R other debugobsolete
96 $ hg -R other debugobsolete
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
98
98
99 pull
99 pull
100
100
101 $ hg -R main phase --public 9520eea781bc
101 $ hg -R main phase --public 9520eea781bc
102 pre-close-tip:02de42196ebe draft
102 pre-close-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
105 $ hg -R other pull -r 24b6387c8c8c
105 $ hg -R other pull -r 24b6387c8c8c
106 pulling from $TESTTMP/main (glob)
106 pulling from $TESTTMP/main (glob)
107 searching for changes
107 searching for changes
108 adding changesets
108 adding changesets
109 adding manifests
109 adding manifests
110 adding file changes
110 adding file changes
111 added 1 changesets with 1 changes to 1 files (+1 heads)
111 added 1 changesets with 1 changes to 1 files (+1 heads)
112 1 new obsolescence markers
112 1 new obsolescence markers
113 pre-close-tip:24b6387c8c8c draft
113 pre-close-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
118 $ hg -R other log -G
118 $ hg -R other log -G
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
120 |
120 |
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
122 |/
122 |/
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
124
124
125 $ hg -R other debugobsolete
125 $ hg -R other debugobsolete
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
128
128
129 pull empty (with phase movement)
129 pull empty (with phase movement)
130
130
131 $ hg -R main phase --public 24b6387c8c8c
131 $ hg -R main phase --public 24b6387c8c8c
132 pre-close-tip:02de42196ebe draft
132 pre-close-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
135 $ hg -R other pull -r 24b6387c8c8c
135 $ hg -R other pull -r 24b6387c8c8c
136 pulling from $TESTTMP/main (glob)
136 pulling from $TESTTMP/main (glob)
137 no changes found
137 no changes found
138 pre-close-tip:24b6387c8c8c public
138 pre-close-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
142 $ hg -R other log -G
142 $ hg -R other log -G
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
144 |
144 |
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
146 |/
146 |/
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
148
148
149 $ hg -R other debugobsolete
149 $ hg -R other debugobsolete
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
152
152
153 pull empty
153 pull empty
154
154
155 $ hg -R other pull -r 24b6387c8c8c
155 $ hg -R other pull -r 24b6387c8c8c
156 pulling from $TESTTMP/main (glob)
156 pulling from $TESTTMP/main (glob)
157 no changes found
157 no changes found
158 pre-close-tip:24b6387c8c8c public
158 pre-close-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
162 $ hg -R other log -G
162 $ hg -R other log -G
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
164 |
164 |
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
166 |/
166 |/
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
168
168
169 $ hg -R other debugobsolete
169 $ hg -R other debugobsolete
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
172
172
173 add extra data to test their exchange during push
173 add extra data to test their exchange during push
174
174
175 $ hg -R main bookmark --rev eea13746799a book_eea1
175 $ hg -R main bookmark --rev eea13746799a book_eea1
176 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
176 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
177 pre-close-tip:02de42196ebe draft
177 pre-close-tip:02de42196ebe draft
178 postclose-tip:02de42196ebe draft
178 postclose-tip:02de42196ebe draft
179 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
179 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
180 $ hg -R main bookmark --rev 02de42196ebe book_02de
180 $ hg -R main bookmark --rev 02de42196ebe book_02de
181 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
181 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
182 pre-close-tip:02de42196ebe draft book_02de
182 pre-close-tip:02de42196ebe draft book_02de
183 postclose-tip:02de42196ebe draft book_02de
183 postclose-tip:02de42196ebe draft book_02de
184 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
184 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
185 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
185 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
186 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
186 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
187 pre-close-tip:02de42196ebe draft book_02de
187 pre-close-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
188 postclose-tip:02de42196ebe draft book_02de
189 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
189 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
190 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
190 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
191 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
191 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
192 pre-close-tip:02de42196ebe draft book_02de
192 pre-close-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
194 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
194 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
195 $ hg -R main bookmark --rev 32af7686d403 book_32af
195 $ hg -R main bookmark --rev 32af7686d403 book_32af
196 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
196 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
197 pre-close-tip:02de42196ebe draft book_02de
197 pre-close-tip:02de42196ebe draft book_02de
198 postclose-tip:02de42196ebe draft book_02de
198 postclose-tip:02de42196ebe draft book_02de
199 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
199 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
200
200
201 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
201 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
202 $ hg -R other bookmark --rev cd010b8cd998 book_02de
202 $ hg -R other bookmark --rev cd010b8cd998 book_02de
203 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
203 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
204 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
204 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
205 $ hg -R other bookmark --rev cd010b8cd998 book_32af
205 $ hg -R other bookmark --rev cd010b8cd998 book_32af
206
206
207 $ hg -R main phase --public eea13746799a
207 $ hg -R main phase --public eea13746799a
208 pre-close-tip:02de42196ebe draft book_02de
208 pre-close-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
210 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
210 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
211
211
212 push
212 push
213 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
213 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
214 pushing to other
214 pushing to other
215 searching for changes
215 searching for changes
216 remote: adding changesets
216 remote: adding changesets
217 remote: adding manifests
217 remote: adding manifests
218 remote: adding file changes
218 remote: adding file changes
219 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
219 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
220 remote: 1 new obsolescence markers
220 remote: 1 new obsolescence markers
221 remote: pre-close-tip:eea13746799a public book_eea1
221 remote: pre-close-tip:eea13746799a public book_eea1
222 remote: pushkey: lock state after "phases"
222 remote: pushkey: lock state after "phases"
223 remote: lock: free
223 remote: lock: free
224 remote: wlock: free
224 remote: wlock: free
225 remote: pushkey: lock state after "bookmarks"
225 remote: pushkey: lock state after "bookmarks"
226 remote: lock: free
226 remote: lock: free
227 remote: wlock: free
227 remote: wlock: free
228 remote: postclose-tip:eea13746799a public book_eea1
228 remote: postclose-tip:eea13746799a public book_eea1
229 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
229 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=push (glob)
230 updating bookmark book_eea1
230 updating bookmark book_eea1
231 pre-close-tip:02de42196ebe draft book_02de
231 pre-close-tip:02de42196ebe draft book_02de
232 postclose-tip:02de42196ebe draft book_02de
232 postclose-tip:02de42196ebe draft book_02de
233 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
233 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
234 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
234 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
235 $ hg -R other log -G
235 $ hg -R other log -G
236 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
236 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
237 |\
237 |\
238 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
238 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
239 | |
239 | |
240 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
240 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
241 |/
241 |/
242 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
242 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
243
243
244 $ hg -R other debugobsolete
244 $ hg -R other debugobsolete
245 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
245 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
247 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
247 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
248
248
249 pull over ssh
249 pull over ssh
250
250
251 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
251 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
252 pulling from ssh://user@dummy/main
252 pulling from ssh://user@dummy/main
253 searching for changes
253 searching for changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 1 changesets with 1 changes to 1 files (+1 heads)
257 added 1 changesets with 1 changes to 1 files (+1 heads)
258 1 new obsolescence markers
258 1 new obsolescence markers
259 updating bookmark book_02de
259 updating bookmark book_02de
260 pre-close-tip:02de42196ebe draft book_02de
260 pre-close-tip:02de42196ebe draft book_02de
261 postclose-tip:02de42196ebe draft book_02de
261 postclose-tip:02de42196ebe draft book_02de
262 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
262 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
263 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
263 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
264 (run 'hg heads' to see heads, 'hg merge' to merge)
264 (run 'hg heads' to see heads, 'hg merge' to merge)
265 $ hg -R other debugobsolete
265 $ hg -R other debugobsolete
266 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
266 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
267 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
267 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
268 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
268 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
269 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
269 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
270
270
271 pull over http
271 pull over http
272
272
273 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
273 $ hg -R main serve -p $HGPORT -d --pid-file=main.pid -E main-error.log
274 $ cat main.pid >> $DAEMON_PIDS
274 $ cat main.pid >> $DAEMON_PIDS
275
275
276 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
276 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
277 pulling from http://localhost:$HGPORT/
277 pulling from http://localhost:$HGPORT/
278 searching for changes
278 searching for changes
279 adding changesets
279 adding changesets
280 adding manifests
280 adding manifests
281 adding file changes
281 adding file changes
282 added 1 changesets with 1 changes to 1 files (+1 heads)
282 added 1 changesets with 1 changes to 1 files (+1 heads)
283 1 new obsolescence markers
283 1 new obsolescence markers
284 updating bookmark book_42cc
284 updating bookmark book_42cc
285 pre-close-tip:42ccdea3bb16 draft book_42cc
285 pre-close-tip:42ccdea3bb16 draft book_42cc
286 postclose-tip:42ccdea3bb16 draft book_42cc
286 postclose-tip:42ccdea3bb16 draft book_42cc
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
287 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
288 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
288 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
289 (run 'hg heads .' to see heads, 'hg merge' to merge)
289 (run 'hg heads .' to see heads, 'hg merge' to merge)
290 $ cat main-error.log
290 $ cat main-error.log
291 $ hg -R other debugobsolete
291 $ hg -R other debugobsolete
292 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
292 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
293 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
293 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
294 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
294 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
295 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
295 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
296 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
296 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
297
297
298 push over ssh
298 push over ssh
299
299
300 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
300 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
301 pushing to ssh://user@dummy/other
301 pushing to ssh://user@dummy/other
302 searching for changes
302 searching for changes
303 remote: adding changesets
303 remote: adding changesets
304 remote: adding manifests
304 remote: adding manifests
305 remote: adding file changes
305 remote: adding file changes
306 remote: added 1 changesets with 1 changes to 1 files
306 remote: added 1 changesets with 1 changes to 1 files
307 remote: 1 new obsolescence markers
307 remote: 1 new obsolescence markers
308 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
308 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
309 remote: pushkey: lock state after "bookmarks"
309 remote: pushkey: lock state after "bookmarks"
310 remote: lock: free
310 remote: lock: free
311 remote: wlock: free
311 remote: wlock: free
312 remote: postclose-tip:5fddd98957c8 draft book_5fdd
312 remote: postclose-tip:5fddd98957c8 draft book_5fdd
313 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:127.0.0.1 (glob)
313 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:127.0.0.1 (glob)
314 updating bookmark book_5fdd
314 updating bookmark book_5fdd
315 pre-close-tip:02de42196ebe draft book_02de
315 pre-close-tip:02de42196ebe draft book_02de
316 postclose-tip:02de42196ebe draft book_02de
316 postclose-tip:02de42196ebe draft book_02de
317 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
317 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
318 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
318 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
319 $ hg -R other log -G
319 $ hg -R other log -G
320 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
320 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
321 |
321 |
322 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
322 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
323 |
323 |
324 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
324 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
325 | |
325 | |
326 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
326 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
327 | |/|
327 | |/|
328 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
328 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
329 |/ /
329 |/ /
330 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
330 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
331 |/
331 |/
332 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
332 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
333
333
334 $ hg -R other debugobsolete
334 $ hg -R other debugobsolete
335 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
335 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
336 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
336 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
337 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
337 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
338 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
338 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
339 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
339 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
340 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
340 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
341
341
342 push over http
342 push over http
343
343
344 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
344 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
345 $ cat other.pid >> $DAEMON_PIDS
345 $ cat other.pid >> $DAEMON_PIDS
346
346
347 $ hg -R main phase --public 32af7686d403
347 $ hg -R main phase --public 32af7686d403
348 pre-close-tip:02de42196ebe draft book_02de
348 pre-close-tip:02de42196ebe draft book_02de
349 postclose-tip:02de42196ebe draft book_02de
349 postclose-tip:02de42196ebe draft book_02de
350 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
350 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
351 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
351 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
352 pushing to http://localhost:$HGPORT2/
352 pushing to http://localhost:$HGPORT2/
353 searching for changes
353 searching for changes
354 remote: adding changesets
354 remote: adding changesets
355 remote: adding manifests
355 remote: adding manifests
356 remote: adding file changes
356 remote: adding file changes
357 remote: added 1 changesets with 1 changes to 1 files
357 remote: added 1 changesets with 1 changes to 1 files
358 remote: 1 new obsolescence markers
358 remote: 1 new obsolescence markers
359 remote: pre-close-tip:32af7686d403 public book_32af
359 remote: pre-close-tip:32af7686d403 public book_32af
360 remote: pushkey: lock state after "phases"
360 remote: pushkey: lock state after "phases"
361 remote: lock: free
361 remote: lock: free
362 remote: wlock: free
362 remote: wlock: free
363 remote: pushkey: lock state after "bookmarks"
363 remote: pushkey: lock state after "bookmarks"
364 remote: lock: free
364 remote: lock: free
365 remote: wlock: free
365 remote: wlock: free
366 remote: postclose-tip:32af7686d403 public book_32af
366 remote: postclose-tip:32af7686d403 public book_32af
367 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:127.0.0.1: (glob)
367 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:127.0.0.1: (glob)
368 updating bookmark book_32af
368 updating bookmark book_32af
369 pre-close-tip:02de42196ebe draft book_02de
369 pre-close-tip:02de42196ebe draft book_02de
370 postclose-tip:02de42196ebe draft book_02de
370 postclose-tip:02de42196ebe draft book_02de
371 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
371 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
372 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
372 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
373 $ cat other-error.log
373 $ cat other-error.log
374
374
375 Check final content.
375 Check final content.
376
376
377 $ hg -R other log -G
377 $ hg -R other log -G
378 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
378 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
379 |
379 |
380 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
380 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
381 |
381 |
382 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
382 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
383 |
383 |
384 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
384 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
385 | |
385 | |
386 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
386 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
387 | |/|
387 | |/|
388 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
388 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
389 |/ /
389 |/ /
390 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
390 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
391 |/
391 |/
392 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
392 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
393
393
394 $ hg -R other debugobsolete
394 $ hg -R other debugobsolete
395 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
395 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
396 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
396 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
399 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
399 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
400 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
400 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
401 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
401 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
402
402
403 (check that no 'pending' files remain)
403 (check that no 'pending' files remain)
404
404
405 $ ls -1 other/.hg/bookmarks*
405 $ ls -1 other/.hg/bookmarks*
406 other/.hg/bookmarks
406 other/.hg/bookmarks
407 $ ls -1 other/.hg/store/phaseroots*
407 $ ls -1 other/.hg/store/phaseroots*
408 other/.hg/store/phaseroots
408 other/.hg/store/phaseroots
409 $ ls -1 other/.hg/store/00changelog.i*
409 $ ls -1 other/.hg/store/00changelog.i*
410 other/.hg/store/00changelog.i
410 other/.hg/store/00changelog.i
411
411
412 Error Handling
412 Error Handling
413 ==============
413 ==============
414
414
415 Check that errors are properly returned to the client during push.
415 Check that errors are properly returned to the client during push.
416
416
417 Setting up
417 Setting up
418
418
419 $ cat > failpush.py << EOF
419 $ cat > failpush.py << EOF
420 > """A small extension that makes push fails when using bundle2
420 > """A small extension that makes push fails when using bundle2
421 >
421 >
422 > used to test error handling in bundle2
422 > used to test error handling in bundle2
423 > """
423 > """
424 >
424 >
425 > from mercurial import util
425 > from mercurial import util
426 > from mercurial import bundle2
426 > from mercurial import bundle2
427 > from mercurial import exchange
427 > from mercurial import exchange
428 > from mercurial import extensions
428 > from mercurial import extensions
429 >
429 >
430 > def _pushbundle2failpart(pushop, bundler):
430 > def _pushbundle2failpart(pushop, bundler):
431 > reason = pushop.ui.config('failpush', 'reason', None)
431 > reason = pushop.ui.config('failpush', 'reason', None)
432 > part = None
432 > part = None
433 > if reason == 'abort':
433 > if reason == 'abort':
434 > bundler.newpart('test:abort')
434 > bundler.newpart('test:abort')
435 > if reason == 'unknown':
435 > if reason == 'unknown':
436 > bundler.newpart('test:unknown')
436 > bundler.newpart('test:unknown')
437 > if reason == 'race':
437 > if reason == 'race':
438 > # 20 Bytes of crap
438 > # 20 Bytes of crap
439 > bundler.newpart('check:heads', data='01234567890123456789')
439 > bundler.newpart('check:heads', data='01234567890123456789')
440 >
440 >
441 > @bundle2.parthandler("test:abort")
441 > @bundle2.parthandler("test:abort")
442 > def handleabort(op, part):
442 > def handleabort(op, part):
443 > raise util.Abort('Abandon ship!', hint="don't panic")
443 > raise util.Abort('Abandon ship!', hint="don't panic")
444 >
444 >
445 > def uisetup(ui):
445 > def uisetup(ui):
446 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
446 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
447 > exchange.b2partsgenorder.insert(0, 'failpart')
447 > exchange.b2partsgenorder.insert(0, 'failpart')
448 >
448 >
449 > EOF
449 > EOF
450
450
451 $ cd main
451 $ cd main
452 $ hg up tip
452 $ hg up tip
453 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
453 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
454 $ echo 'I' > I
454 $ echo 'I' > I
455 $ hg add I
455 $ hg add I
456 $ hg ci -m 'I'
456 $ hg ci -m 'I'
457 pre-close-tip:e7ec4e813ba6 draft
457 pre-close-tip:e7ec4e813ba6 draft
458 postclose-tip:e7ec4e813ba6 draft
458 postclose-tip:e7ec4e813ba6 draft
459 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
459 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
460 $ hg id
460 $ hg id
461 e7ec4e813ba6 tip
461 e7ec4e813ba6 tip
462 $ cd ..
462 $ cd ..
463
463
464 $ cat << EOF >> $HGRCPATH
464 $ cat << EOF >> $HGRCPATH
465 > [extensions]
465 > [extensions]
466 > failpush=$TESTTMP/failpush.py
466 > failpush=$TESTTMP/failpush.py
467 > EOF
467 > EOF
468
468
469 $ killdaemons.py
469 $ killdaemons.py
470 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
470 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
471 $ cat other.pid >> $DAEMON_PIDS
471 $ cat other.pid >> $DAEMON_PIDS
472
472
473 Doing the actual push: Abort error
473 Doing the actual push: Abort error
474
474
475 $ cat << EOF >> $HGRCPATH
475 $ cat << EOF >> $HGRCPATH
476 > [failpush]
476 > [failpush]
477 > reason = abort
477 > reason = abort
478 > EOF
478 > EOF
479
479
480 $ hg -R main push other -r e7ec4e813ba6
480 $ hg -R main push other -r e7ec4e813ba6
481 pushing to other
481 pushing to other
482 searching for changes
482 searching for changes
483 abort: Abandon ship!
483 abort: Abandon ship!
484 (don't panic)
484 (don't panic)
485 [255]
485 [255]
486
486
487 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
487 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
488 pushing to ssh://user@dummy/other
488 pushing to ssh://user@dummy/other
489 searching for changes
489 searching for changes
490 abort: Abandon ship!
490 abort: Abandon ship!
491 (don't panic)
491 (don't panic)
492 [255]
492 [255]
493
493
494 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
494 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
495 pushing to http://localhost:$HGPORT2/
495 pushing to http://localhost:$HGPORT2/
496 searching for changes
496 searching for changes
497 abort: Abandon ship!
497 abort: Abandon ship!
498 (don't panic)
498 (don't panic)
499 [255]
499 [255]
500
500
501
501
502 Doing the actual push: unknown mandatory parts
502 Doing the actual push: unknown mandatory parts
503
503
504 $ cat << EOF >> $HGRCPATH
504 $ cat << EOF >> $HGRCPATH
505 > [failpush]
505 > [failpush]
506 > reason = unknown
506 > reason = unknown
507 > EOF
507 > EOF
508
508
509 $ hg -R main push other -r e7ec4e813ba6
509 $ hg -R main push other -r e7ec4e813ba6
510 pushing to other
510 pushing to other
511 searching for changes
511 searching for changes
512 abort: missing support for test:unknown
512 abort: missing support for test:unknown
513 [255]
513 [255]
514
514
515 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
515 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
516 pushing to ssh://user@dummy/other
516 pushing to ssh://user@dummy/other
517 searching for changes
517 searching for changes
518 abort: missing support for test:unknown
518 abort: missing support for test:unknown
519 [255]
519 [255]
520
520
521 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
521 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
522 pushing to http://localhost:$HGPORT2/
522 pushing to http://localhost:$HGPORT2/
523 searching for changes
523 searching for changes
524 abort: missing support for test:unknown
524 abort: missing support for test:unknown
525 [255]
525 [255]
526
526
527 Doing the actual push: race
527 Doing the actual push: race
528
528
529 $ cat << EOF >> $HGRCPATH
529 $ cat << EOF >> $HGRCPATH
530 > [failpush]
530 > [failpush]
531 > reason = race
531 > reason = race
532 > EOF
532 > EOF
533
533
534 $ hg -R main push other -r e7ec4e813ba6
534 $ hg -R main push other -r e7ec4e813ba6
535 pushing to other
535 pushing to other
536 searching for changes
536 searching for changes
537 abort: push failed:
537 abort: push failed:
538 'repository changed while pushing - please try again'
538 'repository changed while pushing - please try again'
539 [255]
539 [255]
540
540
541 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
541 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
542 pushing to ssh://user@dummy/other
542 pushing to ssh://user@dummy/other
543 searching for changes
543 searching for changes
544 abort: push failed:
544 abort: push failed:
545 'repository changed while pushing - please try again'
545 'repository changed while pushing - please try again'
546 [255]
546 [255]
547
547
548 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
548 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
549 pushing to http://localhost:$HGPORT2/
549 pushing to http://localhost:$HGPORT2/
550 searching for changes
550 searching for changes
551 abort: push failed:
551 abort: push failed:
552 'repository changed while pushing - please try again'
552 'repository changed while pushing - please try again'
553 [255]
553 [255]
554
554
555 Doing the actual push: hook abort
555 Doing the actual push: hook abort
556
556
557 $ cat << EOF >> $HGRCPATH
557 $ cat << EOF >> $HGRCPATH
558 > [failpush]
558 > [failpush]
559 > reason =
559 > reason =
560 > [hooks]
560 > [hooks]
561 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
561 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
562 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
562 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
563 > EOF
563 > EOF
564
564
565 $ killdaemons.py
565 $ killdaemons.py
566 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
566 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
567 $ cat other.pid >> $DAEMON_PIDS
567 $ cat other.pid >> $DAEMON_PIDS
568
568
569 $ hg -R main push other -r e7ec4e813ba6
569 $ hg -R main push other -r e7ec4e813ba6
570 pushing to other
570 pushing to other
571 searching for changes
571 searching for changes
572 remote: adding changesets
572 remote: adding changesets
573 remote: adding manifests
573 remote: adding manifests
574 remote: adding file changes
574 remote: adding file changes
575 remote: added 1 changesets with 1 changes to 1 files
575 remote: added 1 changesets with 1 changes to 1 files
576 remote: pre-close-tip:e7ec4e813ba6 draft
576 remote: pre-close-tip:e7ec4e813ba6 draft
577 remote: You shall not pass!
577 remote: You shall not pass!
578 remote: transaction abort!
578 remote: transaction abort!
579 remote: Cleaning up the mess...
579 remote: Cleaning up the mess...
580 remote: rollback completed
580 remote: rollback completed
581 abort: pretxnclose.failpush hook exited with status 1
581 abort: pretxnclose.failpush hook exited with status 1
582 [255]
582 [255]
583
583
584 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
584 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
585 pushing to ssh://user@dummy/other
585 pushing to ssh://user@dummy/other
586 searching for changes
586 searching for changes
587 remote: adding changesets
587 remote: adding changesets
588 remote: adding manifests
588 remote: adding manifests
589 remote: adding file changes
589 remote: adding file changes
590 remote: added 1 changesets with 1 changes to 1 files
590 remote: added 1 changesets with 1 changes to 1 files
591 remote: pre-close-tip:e7ec4e813ba6 draft
591 remote: pre-close-tip:e7ec4e813ba6 draft
592 remote: You shall not pass!
592 remote: You shall not pass!
593 remote: transaction abort!
593 remote: transaction abort!
594 remote: Cleaning up the mess...
594 remote: Cleaning up the mess...
595 remote: rollback completed
595 remote: rollback completed
596 abort: pretxnclose.failpush hook exited with status 1
596 abort: pretxnclose.failpush hook exited with status 1
597 [255]
597 [255]
598
598
599 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
599 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
600 pushing to http://localhost:$HGPORT2/
600 pushing to http://localhost:$HGPORT2/
601 searching for changes
601 searching for changes
602 remote: adding changesets
602 remote: adding changesets
603 remote: adding manifests
603 remote: adding manifests
604 remote: adding file changes
604 remote: adding file changes
605 remote: added 1 changesets with 1 changes to 1 files
605 remote: added 1 changesets with 1 changes to 1 files
606 remote: pre-close-tip:e7ec4e813ba6 draft
606 remote: pre-close-tip:e7ec4e813ba6 draft
607 remote: You shall not pass!
607 remote: You shall not pass!
608 remote: transaction abort!
608 remote: transaction abort!
609 remote: Cleaning up the mess...
609 remote: Cleaning up the mess...
610 remote: rollback completed
610 remote: rollback completed
611 abort: pretxnclose.failpush hook exited with status 1
611 abort: pretxnclose.failpush hook exited with status 1
612 [255]
612 [255]
613
613
614 (check that no 'pending' files remain)
614 (check that no 'pending' files remain)
615
615
616 $ ls -1 other/.hg/bookmarks*
616 $ ls -1 other/.hg/bookmarks*
617 other/.hg/bookmarks
617 other/.hg/bookmarks
618 $ ls -1 other/.hg/store/phaseroots*
618 $ ls -1 other/.hg/store/phaseroots*
619 other/.hg/store/phaseroots
619 other/.hg/store/phaseroots
620 $ ls -1 other/.hg/store/00changelog.i*
620 $ ls -1 other/.hg/store/00changelog.i*
621 other/.hg/store/00changelog.i
621 other/.hg/store/00changelog.i
622
622
623 Check error from hook during the unbundling process itself
623 Check error from hook during the unbundling process itself
624
624
625 $ cat << EOF >> $HGRCPATH
625 $ cat << EOF >> $HGRCPATH
626 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
626 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
627 > EOF
627 > EOF
628 $ killdaemons.py # reload http config
628 $ killdaemons.py # reload http config
629 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
629 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
630 $ cat other.pid >> $DAEMON_PIDS
630 $ cat other.pid >> $DAEMON_PIDS
631
631
632 $ hg -R main push other -r e7ec4e813ba6
632 $ hg -R main push other -r e7ec4e813ba6
633 pushing to other
633 pushing to other
634 searching for changes
634 searching for changes
635 remote: adding changesets
635 remote: adding changesets
636 remote: adding manifests
636 remote: adding manifests
637 remote: adding file changes
637 remote: adding file changes
638 remote: added 1 changesets with 1 changes to 1 files
638 remote: added 1 changesets with 1 changes to 1 files
639 remote: Fail early!
639 remote: Fail early!
640 remote: transaction abort!
640 remote: transaction abort!
641 remote: Cleaning up the mess...
641 remote: Cleaning up the mess...
642 remote: rollback completed
642 remote: rollback completed
643 abort: pretxnchangegroup hook exited with status 1
643 abort: pretxnchangegroup hook exited with status 1
644 [255]
644 [255]
645 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
645 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
646 pushing to ssh://user@dummy/other
646 pushing to ssh://user@dummy/other
647 searching for changes
647 searching for changes
648 remote: adding changesets
648 remote: adding changesets
649 remote: adding manifests
649 remote: adding manifests
650 remote: adding file changes
650 remote: adding file changes
651 remote: added 1 changesets with 1 changes to 1 files
651 remote: added 1 changesets with 1 changes to 1 files
652 remote: Fail early!
652 remote: Fail early!
653 remote: transaction abort!
653 remote: transaction abort!
654 remote: Cleaning up the mess...
654 remote: Cleaning up the mess...
655 remote: rollback completed
655 remote: rollback completed
656 abort: pretxnchangegroup hook exited with status 1
656 abort: pretxnchangegroup hook exited with status 1
657 [255]
657 [255]
658 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
658 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
659 pushing to http://localhost:$HGPORT2/
659 pushing to http://localhost:$HGPORT2/
660 searching for changes
660 searching for changes
661 remote: adding changesets
661 remote: adding changesets
662 remote: adding manifests
662 remote: adding manifests
663 remote: adding file changes
663 remote: adding file changes
664 remote: added 1 changesets with 1 changes to 1 files
664 remote: added 1 changesets with 1 changes to 1 files
665 remote: Fail early!
665 remote: Fail early!
666 remote: transaction abort!
666 remote: transaction abort!
667 remote: Cleaning up the mess...
667 remote: Cleaning up the mess...
668 remote: rollback completed
668 remote: rollback completed
669 abort: pretxnchangegroup hook exited with status 1
669 abort: pretxnchangegroup hook exited with status 1
670 [255]
670 [255]
671
671
672 Check output capture control.
672 Check output capture control.
673
673
674 (should be still forced for http, disabled for local and ssh)
674 (should be still forced for http, disabled for local and ssh)
675
675
676 $ cat >> $HGRCPATH << EOF
676 $ cat >> $HGRCPATH << EOF
677 > [experimental]
677 > [experimental]
678 > bundle2-output-capture=False
678 > bundle2-output-capture=False
679 > EOF
679 > EOF
680
680
681 $ hg -R main push other -r e7ec4e813ba6
681 $ hg -R main push other -r e7ec4e813ba6
682 pushing to other
682 pushing to other
683 searching for changes
683 searching for changes
684 adding changesets
684 adding changesets
685 adding manifests
685 adding manifests
686 adding file changes
686 adding file changes
687 added 1 changesets with 1 changes to 1 files
687 added 1 changesets with 1 changes to 1 files
688 Fail early!
688 Fail early!
689 transaction abort!
689 transaction abort!
690 Cleaning up the mess...
690 Cleaning up the mess...
691 rollback completed
691 rollback completed
692 abort: pretxnchangegroup hook exited with status 1
692 abort: pretxnchangegroup hook exited with status 1
693 [255]
693 [255]
694 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
694 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
695 pushing to ssh://user@dummy/other
695 pushing to ssh://user@dummy/other
696 searching for changes
696 searching for changes
697 remote: adding changesets
697 remote: adding changesets
698 remote: adding manifests
698 remote: adding manifests
699 remote: adding file changes
699 remote: adding file changes
700 remote: added 1 changesets with 1 changes to 1 files
700 remote: added 1 changesets with 1 changes to 1 files
701 remote: Fail early!
701 remote: Fail early!
702 remote: transaction abort!
702 remote: transaction abort!
703 remote: Cleaning up the mess...
703 remote: Cleaning up the mess...
704 remote: rollback completed
704 remote: rollback completed
705 abort: pretxnchangegroup hook exited with status 1
705 abort: pretxnchangegroup hook exited with status 1
706 [255]
706 [255]
707 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
707 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
708 pushing to http://localhost:$HGPORT2/
708 pushing to http://localhost:$HGPORT2/
709 searching for changes
709 searching for changes
710 remote: adding changesets
710 remote: adding changesets
711 remote: adding manifests
711 remote: adding manifests
712 remote: adding file changes
712 remote: adding file changes
713 remote: added 1 changesets with 1 changes to 1 files
713 remote: added 1 changesets with 1 changes to 1 files
714 remote: Fail early!
714 remote: Fail early!
715 remote: transaction abort!
715 remote: transaction abort!
716 remote: Cleaning up the mess...
716 remote: Cleaning up the mess...
717 remote: rollback completed
717 remote: rollback completed
718 abort: pretxnchangegroup hook exited with status 1
718 abort: pretxnchangegroup hook exited with status 1
719 [255]
719 [255]
720
720
721 Check abort from mandatory pushkey
721 Check abort from mandatory pushkey
722
722
723 $ cat > mandatorypart.py << EOF
723 $ cat > mandatorypart.py << EOF
724 > from mercurial import exchange
724 > from mercurial import exchange
725 > from mercurial import pushkey
725 > from mercurial import pushkey
726 > from mercurial import node
726 > from mercurial import node
727 > from mercurial import error
727 > from mercurial import error
728 > @exchange.b2partsgenerator('failingpuskey')
728 > @exchange.b2partsgenerator('failingpuskey')
729 > def addfailingpushey(pushop, bundler):
729 > def addfailingpushey(pushop, bundler):
730 > enc = pushkey.encode
730 > enc = pushkey.encode
731 > part = bundler.newpart('pushkey')
731 > part = bundler.newpart('pushkey')
732 > part.addparam('namespace', enc('phases'))
732 > part.addparam('namespace', enc('phases'))
733 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
733 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
734 > part.addparam('old', enc(str(0))) # successful update
734 > part.addparam('old', enc(str(0))) # successful update
735 > part.addparam('new', enc(str(0)))
735 > part.addparam('new', enc(str(0)))
736 > def fail(pushop, exc):
736 > def fail(pushop, exc):
737 > raise error.Abort('Correct phase push failed (because hooks)')
737 > raise error.Abort('Correct phase push failed (because hooks)')
738 > pushop.pkfailcb[part.id] = fail
738 > pushop.pkfailcb[part.id] = fail
739 > EOF
739 > EOF
740 $ cat >> $HGRCPATH << EOF
740 $ cat >> $HGRCPATH << EOF
741 > [hooks]
741 > [hooks]
742 > pretxnchangegroup=
742 > pretxnchangegroup=
743 > pretxnclose.failpush=
743 > pretxnclose.failpush=
744 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
744 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
745 > [extensions]
745 > [extensions]
746 > mandatorypart=$TESTTMP/mandatorypart.py
746 > mandatorypart=$TESTTMP/mandatorypart.py
747 > EOF
747 > EOF
748 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
748 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
749 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
749 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
750 $ cat other.pid >> $DAEMON_PIDS
750 $ cat other.pid >> $DAEMON_PIDS
751
751
752 (Failure from a hook)
752 (Failure from a hook)
753
753
754 $ hg -R main push other -r e7ec4e813ba6
754 $ hg -R main push other -r e7ec4e813ba6
755 pushing to other
755 pushing to other
756 searching for changes
756 searching for changes
757 adding changesets
757 adding changesets
758 adding manifests
758 adding manifests
759 adding file changes
759 adding file changes
760 added 1 changesets with 1 changes to 1 files
760 added 1 changesets with 1 changes to 1 files
761 do not push the key !
761 do not push the key !
762 pushkey-abort: prepushkey.failpush hook exited with status 1
762 pushkey-abort: prepushkey.failpush hook exited with status 1
763 transaction abort!
763 transaction abort!
764 Cleaning up the mess...
764 Cleaning up the mess...
765 rollback completed
765 rollback completed
766 abort: Correct phase push failed (because hooks)
766 abort: Correct phase push failed (because hooks)
767 [255]
767 [255]
768 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
768 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
769 pushing to ssh://user@dummy/other
769 pushing to ssh://user@dummy/other
770 searching for changes
770 searching for changes
771 remote: adding changesets
771 remote: adding changesets
772 remote: adding manifests
772 remote: adding manifests
773 remote: adding file changes
773 remote: adding file changes
774 remote: added 1 changesets with 1 changes to 1 files
774 remote: added 1 changesets with 1 changes to 1 files
775 remote: do not push the key !
775 remote: do not push the key !
776 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
776 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
777 remote: transaction abort!
777 remote: transaction abort!
778 remote: Cleaning up the mess...
778 remote: Cleaning up the mess...
779 remote: rollback completed
779 remote: rollback completed
780 abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
780 abort: Correct phase push failed (because hooks)
781 [255]
781 [255]
782 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
782 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
783 pushing to http://localhost:$HGPORT2/
783 pushing to http://localhost:$HGPORT2/
784 searching for changes
784 searching for changes
785 remote: adding changesets
785 remote: adding changesets
786 remote: adding manifests
786 remote: adding manifests
787 remote: adding file changes
787 remote: adding file changes
788 remote: added 1 changesets with 1 changes to 1 files
788 remote: added 1 changesets with 1 changes to 1 files
789 remote: do not push the key !
789 remote: do not push the key !
790 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
790 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
791 remote: transaction abort!
791 remote: transaction abort!
792 remote: Cleaning up the mess...
792 remote: Cleaning up the mess...
793 remote: rollback completed
793 remote: rollback completed
794 abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
794 abort: Correct phase push failed (because hooks)
795 [255]
795 [255]
796
796
797 (Failure from a the pushkey)
797 (Failure from a the pushkey)
798
798
799 $ cat > mandatorypart.py << EOF
799 $ cat > mandatorypart.py << EOF
800 > from mercurial import exchange
800 > from mercurial import exchange
801 > from mercurial import pushkey
801 > from mercurial import pushkey
802 > from mercurial import node
802 > from mercurial import node
803 > from mercurial import error
803 > from mercurial import error
804 > @exchange.b2partsgenerator('failingpuskey')
804 > @exchange.b2partsgenerator('failingpuskey')
805 > def addfailingpushey(pushop, bundler):
805 > def addfailingpushey(pushop, bundler):
806 > enc = pushkey.encode
806 > enc = pushkey.encode
807 > part = bundler.newpart('pushkey')
807 > part = bundler.newpart('pushkey')
808 > part.addparam('namespace', enc('phases'))
808 > part.addparam('namespace', enc('phases'))
809 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
809 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
810 > part.addparam('old', enc(str(4))) # will fail
810 > part.addparam('old', enc(str(4))) # will fail
811 > part.addparam('new', enc(str(3)))
811 > part.addparam('new', enc(str(3)))
812 > def fail(pushop, exc):
812 > def fail(pushop, exc):
813 > raise error.Abort('Clown phase push failed')
813 > raise error.Abort('Clown phase push failed')
814 > pushop.pkfailcb[part.id] = fail
814 > pushop.pkfailcb[part.id] = fail
815 > EOF
815 > EOF
816 $ cat >> $HGRCPATH << EOF
816 $ cat >> $HGRCPATH << EOF
817 > [hooks]
817 > [hooks]
818 > prepushkey.failpush =
818 > prepushkey.failpush =
819 > EOF
819 > EOF
820 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
820 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
821 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
821 $ hg -R other serve -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
822 $ cat other.pid >> $DAEMON_PIDS
822 $ cat other.pid >> $DAEMON_PIDS
823
823
824 $ hg -R main push other -r e7ec4e813ba6
824 $ hg -R main push other -r e7ec4e813ba6
825 pushing to other
825 pushing to other
826 searching for changes
826 searching for changes
827 adding changesets
827 adding changesets
828 adding manifests
828 adding manifests
829 adding file changes
829 adding file changes
830 added 1 changesets with 1 changes to 1 files
830 added 1 changesets with 1 changes to 1 files
831 transaction abort!
831 transaction abort!
832 Cleaning up the mess...
832 Cleaning up the mess...
833 rollback completed
833 rollback completed
834 pushkey: lock state after "phases"
834 pushkey: lock state after "phases"
835 lock: free
835 lock: free
836 wlock: free
836 wlock: free
837 abort: Clown phase push failed
837 abort: Clown phase push failed
838 [255]
838 [255]
839 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
839 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
840 pushing to ssh://user@dummy/other
840 pushing to ssh://user@dummy/other
841 searching for changes
841 searching for changes
842 remote: adding changesets
842 remote: adding changesets
843 remote: adding manifests
843 remote: adding manifests
844 remote: adding file changes
844 remote: adding file changes
845 remote: added 1 changesets with 1 changes to 1 files
845 remote: added 1 changesets with 1 changes to 1 files
846 remote: transaction abort!
846 remote: transaction abort!
847 remote: Cleaning up the mess...
847 remote: Cleaning up the mess...
848 remote: rollback completed
848 remote: rollback completed
849 remote: pushkey: lock state after "phases"
849 remote: pushkey: lock state after "phases"
850 remote: lock: free
850 remote: lock: free
851 remote: wlock: free
851 remote: wlock: free
852 abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
852 abort: Clown phase push failed
853 [255]
853 [255]
854 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
854 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
855 pushing to http://localhost:$HGPORT2/
855 pushing to http://localhost:$HGPORT2/
856 searching for changes
856 searching for changes
857 remote: adding changesets
857 remote: adding changesets
858 remote: adding manifests
858 remote: adding manifests
859 remote: adding file changes
859 remote: adding file changes
860 remote: added 1 changesets with 1 changes to 1 files
860 remote: added 1 changesets with 1 changes to 1 files
861 remote: transaction abort!
861 remote: transaction abort!
862 remote: Cleaning up the mess...
862 remote: Cleaning up the mess...
863 remote: rollback completed
863 remote: rollback completed
864 remote: pushkey: lock state after "phases"
864 remote: pushkey: lock state after "phases"
865 remote: lock: free
865 remote: lock: free
866 remote: wlock: free
866 remote: wlock: free
867 abort: failed to update value for "phases/cd010b8cd998f3981a5a8115f94f8da4ab506089"
867 abort: Clown phase push failed
868 [255]
868 [255]
869
869
@@ -1,130 +1,130 b''
1 #require serve
1 #require serve
2 $ cat << EOF >> $HGRCPATH
2 $ cat << EOF >> $HGRCPATH
3 > [experimental]
3 > [experimental]
4 > # drop me once bundle2 is the default,
4 > # drop me once bundle2 is the default,
5 > # added to get test change early.
5 > # added to get test change early.
6 > bundle2-exp = True
6 > bundle2-exp = True
7 > EOF
7 > EOF
8
8
9 $ hg init a
9 $ hg init a
10 $ cd a
10 $ cd a
11 $ echo a > a
11 $ echo a > a
12 $ hg ci -Ama -d '1123456789 0'
12 $ hg ci -Ama -d '1123456789 0'
13 adding a
13 adding a
14 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
14 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
15 $ cat hg.pid >> $DAEMON_PIDS
15 $ cat hg.pid >> $DAEMON_PIDS
16 $ cd ..
16 $ cd ..
17 $ tinyproxy.py $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
17 $ tinyproxy.py $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
18 $ while [ ! -f proxy.pid ]; do sleep 0; done
18 $ while [ ! -f proxy.pid ]; do sleep 0; done
19 $ cat proxy.pid >> $DAEMON_PIDS
19 $ cat proxy.pid >> $DAEMON_PIDS
20
20
21 url for proxy, stream
21 url for proxy, stream
22
22
23 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
23 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
24 streaming all changes
24 streaming all changes
25 3 files to transfer, 303 bytes of data
25 3 files to transfer, 303 bytes of data
26 transferred * bytes in * seconds (*/sec) (glob)
26 transferred * bytes in * seconds (*/sec) (glob)
27 searching for changes
27 searching for changes
28 no changes found
28 no changes found
29 updating to branch default
29 updating to branch default
30 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 $ cd b
31 $ cd b
32 $ hg verify
32 $ hg verify
33 checking changesets
33 checking changesets
34 checking manifests
34 checking manifests
35 crosschecking files in changesets and manifests
35 crosschecking files in changesets and manifests
36 checking files
36 checking files
37 1 files, 1 changesets, 1 total revisions
37 1 files, 1 changesets, 1 total revisions
38 $ cd ..
38 $ cd ..
39
39
40 url for proxy, pull
40 url for proxy, pull
41
41
42 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
42 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
43 requesting all changes
43 requesting all changes
44 adding changesets
44 adding changesets
45 adding manifests
45 adding manifests
46 adding file changes
46 adding file changes
47 added 1 changesets with 1 changes to 1 files
47 added 1 changesets with 1 changes to 1 files
48 updating to branch default
48 updating to branch default
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 $ cd b-pull
50 $ cd b-pull
51 $ hg verify
51 $ hg verify
52 checking changesets
52 checking changesets
53 checking manifests
53 checking manifests
54 crosschecking files in changesets and manifests
54 crosschecking files in changesets and manifests
55 checking files
55 checking files
56 1 files, 1 changesets, 1 total revisions
56 1 files, 1 changesets, 1 total revisions
57 $ cd ..
57 $ cd ..
58
58
59 host:port for proxy
59 host:port for proxy
60
60
61 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
61 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
62 requesting all changes
62 requesting all changes
63 adding changesets
63 adding changesets
64 adding manifests
64 adding manifests
65 adding file changes
65 adding file changes
66 added 1 changesets with 1 changes to 1 files
66 added 1 changesets with 1 changes to 1 files
67 updating to branch default
67 updating to branch default
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69
69
70 proxy url with user name and password
70 proxy url with user name and password
71
71
72 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
72 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
73 requesting all changes
73 requesting all changes
74 adding changesets
74 adding changesets
75 adding manifests
75 adding manifests
76 adding file changes
76 adding file changes
77 added 1 changesets with 1 changes to 1 files
77 added 1 changesets with 1 changes to 1 files
78 updating to branch default
78 updating to branch default
79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80
80
81 url with user name and password
81 url with user name and password
82
82
83 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
83 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
84 requesting all changes
84 requesting all changes
85 adding changesets
85 adding changesets
86 adding manifests
86 adding manifests
87 adding file changes
87 adding file changes
88 added 1 changesets with 1 changes to 1 files
88 added 1 changesets with 1 changes to 1 files
89 updating to branch default
89 updating to branch default
90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91
91
92 bad host:port for proxy
92 bad host:port for proxy
93
93
94 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
94 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
95 abort: error: Connection refused
95 abort: error: Connection refused
96 [255]
96 [255]
97
97
98 do not use the proxy if it is in the no list
98 do not use the proxy if it is in the no list
99
99
100 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
100 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
101 requesting all changes
101 requesting all changes
102 adding changesets
102 adding changesets
103 adding manifests
103 adding manifests
104 adding file changes
104 adding file changes
105 added 1 changesets with 1 changes to 1 files
105 added 1 changesets with 1 changes to 1 files
106 updating to branch default
106 updating to branch default
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 $ cat proxy.log
108 $ cat proxy.log
109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
110 * - - [*] "GET http://localhost:$HGPORT/?cmd=branchmap HTTP/1.1" - - (glob)
110 * - - [*] "GET http://localhost:$HGPORT/?cmd=branchmap HTTP/1.1" - - (glob)
111 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
111 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
112 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
112 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
113 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=83180e7845de420a1bb46896fd5fe05294f8d629&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
113 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=83180e7845de420a1bb46896fd5fe05294f8d629&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
114 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
114 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
115 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
115 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
116 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
116 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
117 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
117 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
120 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
120 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
121 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
121 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
123 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
123 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
124 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
124 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
125 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
125 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
126 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
126 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
127 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
127 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
128 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
128 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
129 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
129 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
130 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
130 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
@@ -1,323 +1,323 b''
1 #require serve
1 #require serve
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo foo>foo
5 $ echo foo>foo
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
7 $ echo foo>foo.d/foo
7 $ echo foo>foo.d/foo
8 $ echo bar>foo.d/bAr.hg.d/BaR
8 $ echo bar>foo.d/bAr.hg.d/BaR
9 $ echo bar>foo.d/baR.d.hg/bAR
9 $ echo bar>foo.d/baR.d.hg/bAR
10 $ hg commit -A -m 1
10 $ hg commit -A -m 1
11 adding foo
11 adding foo
12 adding foo.d/bAr.hg.d/BaR
12 adding foo.d/bAr.hg.d/BaR
13 adding foo.d/baR.d.hg/bAR
13 adding foo.d/baR.d.hg/bAR
14 adding foo.d/foo
14 adding foo.d/foo
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
17
17
18 Test server address cannot be reused
18 Test server address cannot be reused
19
19
20 #if windows
20 #if windows
21 $ hg serve -p $HGPORT1 2>&1
21 $ hg serve -p $HGPORT1 2>&1
22 abort: cannot start server at ':$HGPORT1': * (glob)
22 abort: cannot start server at ':$HGPORT1': * (glob)
23 [255]
23 [255]
24 #else
24 #else
25 $ hg serve -p $HGPORT1 2>&1
25 $ hg serve -p $HGPORT1 2>&1
26 abort: cannot start server at ':$HGPORT1': Address already in use
26 abort: cannot start server at ':$HGPORT1': Address already in use
27 [255]
27 [255]
28 #endif
28 #endif
29 $ cd ..
29 $ cd ..
30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
31
31
32 clone via stream
32 clone via stream
33
33
34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
35 streaming all changes
35 streaming all changes
36 6 files to transfer, 606 bytes of data
36 6 files to transfer, 606 bytes of data
37 transferred * bytes in * seconds (*/sec) (glob)
37 transferred * bytes in * seconds (*/sec) (glob)
38 searching for changes
38 searching for changes
39 no changes found
39 no changes found
40 updating to branch default
40 updating to branch default
41 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 $ hg verify -R copy
42 $ hg verify -R copy
43 checking changesets
43 checking changesets
44 checking manifests
44 checking manifests
45 crosschecking files in changesets and manifests
45 crosschecking files in changesets and manifests
46 checking files
46 checking files
47 4 files, 1 changesets, 4 total revisions
47 4 files, 1 changesets, 4 total revisions
48
48
49 try to clone via stream, should use pull instead
49 try to clone via stream, should use pull instead
50
50
51 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
51 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
52 requesting all changes
52 requesting all changes
53 adding changesets
53 adding changesets
54 adding manifests
54 adding manifests
55 adding file changes
55 adding file changes
56 added 1 changesets with 4 changes to 4 files
56 added 1 changesets with 4 changes to 4 files
57 updating to branch default
57 updating to branch default
58 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
59
59
60 clone via pull
60 clone via pull
61
61
62 $ hg clone http://localhost:$HGPORT1/ copy-pull
62 $ hg clone http://localhost:$HGPORT1/ copy-pull
63 requesting all changes
63 requesting all changes
64 adding changesets
64 adding changesets
65 adding manifests
65 adding manifests
66 adding file changes
66 adding file changes
67 added 1 changesets with 4 changes to 4 files
67 added 1 changesets with 4 changes to 4 files
68 updating to branch default
68 updating to branch default
69 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 $ hg verify -R copy-pull
70 $ hg verify -R copy-pull
71 checking changesets
71 checking changesets
72 checking manifests
72 checking manifests
73 crosschecking files in changesets and manifests
73 crosschecking files in changesets and manifests
74 checking files
74 checking files
75 4 files, 1 changesets, 4 total revisions
75 4 files, 1 changesets, 4 total revisions
76 $ cd test
76 $ cd test
77 $ echo bar > bar
77 $ echo bar > bar
78 $ hg commit -A -d '1 0' -m 2
78 $ hg commit -A -d '1 0' -m 2
79 adding bar
79 adding bar
80 $ cd ..
80 $ cd ..
81
81
82 clone over http with --update
82 clone over http with --update
83
83
84 $ hg clone http://localhost:$HGPORT1/ updated --update 0
84 $ hg clone http://localhost:$HGPORT1/ updated --update 0
85 requesting all changes
85 requesting all changes
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 2 changesets with 5 changes to 5 files
89 added 2 changesets with 5 changes to 5 files
90 updating to branch default
90 updating to branch default
91 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 $ hg log -r . -R updated
92 $ hg log -r . -R updated
93 changeset: 0:8b6053c928fe
93 changeset: 0:8b6053c928fe
94 user: test
94 user: test
95 date: Thu Jan 01 00:00:00 1970 +0000
95 date: Thu Jan 01 00:00:00 1970 +0000
96 summary: 1
96 summary: 1
97
97
98 $ rm -rf updated
98 $ rm -rf updated
99
99
100 incoming via HTTP
100 incoming via HTTP
101
101
102 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
102 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 1 changesets with 4 changes to 4 files
106 added 1 changesets with 4 changes to 4 files
107 updating to branch default
107 updating to branch default
108 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 $ cd partial
109 $ cd partial
110 $ touch LOCAL
110 $ touch LOCAL
111 $ hg ci -qAm LOCAL
111 $ hg ci -qAm LOCAL
112 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
112 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
113 comparing with http://localhost:$HGPORT1/
113 comparing with http://localhost:$HGPORT1/
114 searching for changes
114 searching for changes
115 2
115 2
116 $ cd ..
116 $ cd ..
117
117
118 pull
118 pull
119
119
120 $ cd copy-pull
120 $ cd copy-pull
121 $ echo '[hooks]' >> .hg/hgrc
121 $ echo '[hooks]' >> .hg/hgrc
122 $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
122 $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
123 $ hg pull
123 $ hg pull
124 pulling from http://localhost:$HGPORT1/
124 pulling from http://localhost:$HGPORT1/
125 searching for changes
125 searching for changes
126 adding changesets
126 adding changesets
127 adding manifests
127 adding manifests
128 adding file changes
128 adding file changes
129 added 1 changesets with 1 changes to 1 files
129 added 1 changesets with 1 changes to 1 files
130 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
130 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
131 (run 'hg update' to get a working copy)
131 (run 'hg update' to get a working copy)
132 $ cd ..
132 $ cd ..
133
133
134 clone from invalid URL
134 clone from invalid URL
135
135
136 $ hg clone http://localhost:$HGPORT/bad
136 $ hg clone http://localhost:$HGPORT/bad
137 abort: HTTP Error 404: Not Found
137 abort: HTTP Error 404: Not Found
138 [255]
138 [255]
139
139
140 test http authentication
140 test http authentication
141 + use the same server to test server side streaming preference
141 + use the same server to test server side streaming preference
142
142
143 $ cd test
143 $ cd test
144 $ cat << EOT > userpass.py
144 $ cat << EOT > userpass.py
145 > import base64
145 > import base64
146 > from mercurial.hgweb import common
146 > from mercurial.hgweb import common
147 > def perform_authentication(hgweb, req, op):
147 > def perform_authentication(hgweb, req, op):
148 > auth = req.env.get('HTTP_AUTHORIZATION')
148 > auth = req.env.get('HTTP_AUTHORIZATION')
149 > if not auth:
149 > if not auth:
150 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
150 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
151 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
151 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
152 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
152 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
153 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
153 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
154 > def extsetup():
154 > def extsetup():
155 > common.permhooks.insert(0, perform_authentication)
155 > common.permhooks.insert(0, perform_authentication)
156 > EOT
156 > EOT
157 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
157 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
158 > --config server.preferuncompressed=True \
158 > --config server.preferuncompressed=True \
159 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
159 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
160 $ cat pid >> $DAEMON_PIDS
160 $ cat pid >> $DAEMON_PIDS
161
161
162 $ cat << EOF > get_pass.py
162 $ cat << EOF > get_pass.py
163 > import getpass
163 > import getpass
164 > def newgetpass(arg):
164 > def newgetpass(arg):
165 > return "pass"
165 > return "pass"
166 > getpass.getpass = newgetpass
166 > getpass.getpass = newgetpass
167 > EOF
167 > EOF
168
168
169 $ hg id http://localhost:$HGPORT2/
169 $ hg id http://localhost:$HGPORT2/
170 abort: http authorization required for http://localhost:$HGPORT2/
170 abort: http authorization required for http://localhost:$HGPORT2/
171 [255]
171 [255]
172 $ hg id http://localhost:$HGPORT2/
172 $ hg id http://localhost:$HGPORT2/
173 abort: http authorization required for http://localhost:$HGPORT2/
173 abort: http authorization required for http://localhost:$HGPORT2/
174 [255]
174 [255]
175 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
175 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
176 http authorization required for http://localhost:$HGPORT2/
176 http authorization required for http://localhost:$HGPORT2/
177 realm: mercurial
177 realm: mercurial
178 user: user
178 user: user
179 password: 5fed3813f7f5
179 password: 5fed3813f7f5
180 $ hg id http://user:pass@localhost:$HGPORT2/
180 $ hg id http://user:pass@localhost:$HGPORT2/
181 5fed3813f7f5
181 5fed3813f7f5
182 $ echo '[auth]' >> .hg/hgrc
182 $ echo '[auth]' >> .hg/hgrc
183 $ echo 'l.schemes=http' >> .hg/hgrc
183 $ echo 'l.schemes=http' >> .hg/hgrc
184 $ echo 'l.prefix=lo' >> .hg/hgrc
184 $ echo 'l.prefix=lo' >> .hg/hgrc
185 $ echo 'l.username=user' >> .hg/hgrc
185 $ echo 'l.username=user' >> .hg/hgrc
186 $ echo 'l.password=pass' >> .hg/hgrc
186 $ echo 'l.password=pass' >> .hg/hgrc
187 $ hg id http://localhost:$HGPORT2/
187 $ hg id http://localhost:$HGPORT2/
188 5fed3813f7f5
188 5fed3813f7f5
189 $ hg id http://localhost:$HGPORT2/
189 $ hg id http://localhost:$HGPORT2/
190 5fed3813f7f5
190 5fed3813f7f5
191 $ hg id http://user@localhost:$HGPORT2/
191 $ hg id http://user@localhost:$HGPORT2/
192 5fed3813f7f5
192 5fed3813f7f5
193 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
193 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
194 streaming all changes
194 streaming all changes
195 7 files to transfer, 916 bytes of data
195 7 files to transfer, 916 bytes of data
196 transferred * bytes in * seconds (*/sec) (glob)
196 transferred * bytes in * seconds (*/sec) (glob)
197 searching for changes
197 searching for changes
198 no changes found
198 no changes found
199 updating to branch default
199 updating to branch default
200 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 --pull should override server's preferuncompressed
201 --pull should override server's preferuncompressed
202 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
202 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
203 requesting all changes
203 requesting all changes
204 adding changesets
204 adding changesets
205 adding manifests
205 adding manifests
206 adding file changes
206 adding file changes
207 added 2 changesets with 5 changes to 5 files
207 added 2 changesets with 5 changes to 5 files
208 updating to branch default
208 updating to branch default
209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
210
210
211 $ hg id http://user2@localhost:$HGPORT2/
211 $ hg id http://user2@localhost:$HGPORT2/
212 abort: http authorization required for http://localhost:$HGPORT2/
212 abort: http authorization required for http://localhost:$HGPORT2/
213 [255]
213 [255]
214 $ hg id http://user:pass2@localhost:$HGPORT2/
214 $ hg id http://user:pass2@localhost:$HGPORT2/
215 abort: HTTP Error 403: no
215 abort: HTTP Error 403: no
216 [255]
216 [255]
217
217
218 $ hg -R dest tag -r tip top
218 $ hg -R dest tag -r tip top
219 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
219 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
220 pushing to http://user:***@localhost:$HGPORT2/
220 pushing to http://user:***@localhost:$HGPORT2/
221 searching for changes
221 searching for changes
222 remote: adding changesets
222 remote: adding changesets
223 remote: adding manifests
223 remote: adding manifests
224 remote: adding file changes
224 remote: adding file changes
225 remote: added 1 changesets with 1 changes to 1 files
225 remote: added 1 changesets with 1 changes to 1 files
226 $ hg rollback -q
226 $ hg rollback -q
227
227
228 $ cut -c38- ../access.log
228 $ cut -c38- ../access.log
229 "GET /?cmd=capabilities HTTP/1.1" 200 -
229 "GET /?cmd=capabilities HTTP/1.1" 200 -
230 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
230 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
231 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
231 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
232 "GET /?cmd=capabilities HTTP/1.1" 200 -
232 "GET /?cmd=capabilities HTTP/1.1" 200 -
233 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
233 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
234 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
234 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
235 "GET /?cmd=capabilities HTTP/1.1" 200 -
235 "GET /?cmd=capabilities HTTP/1.1" 200 -
236 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
236 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
237 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
237 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
238 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
238 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
239 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
239 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
240 "GET /?cmd=capabilities HTTP/1.1" 200 -
240 "GET /?cmd=capabilities HTTP/1.1" 200 -
241 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
241 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
242 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
242 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
243 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
243 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
244 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
244 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
245 "GET /?cmd=capabilities HTTP/1.1" 200 -
245 "GET /?cmd=capabilities HTTP/1.1" 200 -
246 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
246 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
247 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
247 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
248 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
248 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
249 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
249 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
250 "GET /?cmd=capabilities HTTP/1.1" 200 -
250 "GET /?cmd=capabilities HTTP/1.1" 200 -
251 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
251 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
252 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
252 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
253 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
253 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
254 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
254 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
255 "GET /?cmd=capabilities HTTP/1.1" 200 -
255 "GET /?cmd=capabilities HTTP/1.1" 200 -
256 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
256 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
257 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
257 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
258 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
258 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
259 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
259 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
260 "GET /?cmd=capabilities HTTP/1.1" 200 -
260 "GET /?cmd=capabilities HTTP/1.1" 200 -
261 "GET /?cmd=branchmap HTTP/1.1" 200 -
261 "GET /?cmd=branchmap HTTP/1.1" 200 -
262 "GET /?cmd=stream_out HTTP/1.1" 401 -
262 "GET /?cmd=stream_out HTTP/1.1" 401 -
263 "GET /?cmd=stream_out HTTP/1.1" 200 -
263 "GET /?cmd=stream_out HTTP/1.1" 200 -
264 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d
264 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d
265 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
265 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
266 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
266 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
267 "GET /?cmd=capabilities HTTP/1.1" 200 -
267 "GET /?cmd=capabilities HTTP/1.1" 200 -
268 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D
268 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D
269 "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
269 "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
270 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
270 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
271 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
271 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
272 "GET /?cmd=capabilities HTTP/1.1" 200 -
272 "GET /?cmd=capabilities HTTP/1.1" 200 -
273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
274 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
274 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
275 "GET /?cmd=capabilities HTTP/1.1" 200 -
275 "GET /?cmd=capabilities HTTP/1.1" 200 -
276 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
276 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
277 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
277 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
278 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces
278 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces
279 "GET /?cmd=capabilities HTTP/1.1" 200 -
279 "GET /?cmd=capabilities HTTP/1.1" 200 -
280 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872
280 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872
281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases
281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases
282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
284 "GET /?cmd=branchmap HTTP/1.1" 200 -
284 "GET /?cmd=branchmap HTTP/1.1" 200 -
285 "GET /?cmd=branchmap HTTP/1.1" 200 -
285 "GET /?cmd=branchmap HTTP/1.1" 200 -
286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
287 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365
287 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365
288 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
288 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
289
289
290 $ cd ..
290 $ cd ..
291
291
292 clone of serve with repo in root and unserved subrepo (issue2970)
292 clone of serve with repo in root and unserved subrepo (issue2970)
293
293
294 $ hg --cwd test init sub
294 $ hg --cwd test init sub
295 $ echo empty > test/sub/empty
295 $ echo empty > test/sub/empty
296 $ hg --cwd test/sub add empty
296 $ hg --cwd test/sub add empty
297 $ hg --cwd test/sub commit -qm 'add empty'
297 $ hg --cwd test/sub commit -qm 'add empty'
298 $ hg --cwd test/sub tag -r 0 something
298 $ hg --cwd test/sub tag -r 0 something
299 $ echo sub = sub > test/.hgsub
299 $ echo sub = sub > test/.hgsub
300 $ hg --cwd test add .hgsub
300 $ hg --cwd test add .hgsub
301 $ hg --cwd test commit -qm 'add subrepo'
301 $ hg --cwd test commit -qm 'add subrepo'
302 $ hg clone http://localhost:$HGPORT noslash-clone
302 $ hg clone http://localhost:$HGPORT noslash-clone
303 requesting all changes
303 requesting all changes
304 adding changesets
304 adding changesets
305 adding manifests
305 adding manifests
306 adding file changes
306 adding file changes
307 added 3 changesets with 7 changes to 7 files
307 added 3 changesets with 7 changes to 7 files
308 updating to branch default
308 updating to branch default
309 abort: HTTP Error 404: Not Found
309 abort: HTTP Error 404: Not Found
310 [255]
310 [255]
311 $ hg clone http://localhost:$HGPORT/ slash-clone
311 $ hg clone http://localhost:$HGPORT/ slash-clone
312 requesting all changes
312 requesting all changes
313 adding changesets
313 adding changesets
314 adding manifests
314 adding manifests
315 adding file changes
315 adding file changes
316 added 3 changesets with 7 changes to 7 files
316 added 3 changesets with 7 changes to 7 files
317 updating to branch default
317 updating to branch default
318 abort: HTTP Error 404: Not Found
318 abort: HTTP Error 404: Not Found
319 [255]
319 [255]
320
320
321 check error log
321 check error log
322
322
323 $ cat error.log
323 $ cat error.log
@@ -1,512 +1,512 b''
1 This test is a duplicate of 'test-http.t' feel free to factor out
1 This test is a duplicate of 'test-http.t' feel free to factor out
2 parts that are not bundle1/bundle2 specific.
2 parts that are not bundle1/bundle2 specific.
3
3
4 $ cat << EOF >> $HGRCPATH
4 $ cat << EOF >> $HGRCPATH
5 > [experimental]
5 > [experimental]
6 > # This test is dedicated to interaction through old bundle
6 > # This test is dedicated to interaction through old bundle
7 > bundle2-exp = False
7 > bundle2-exp = False
8 > EOF
8 > EOF
9
9
10
10
11 This test tries to exercise the ssh functionality with a dummy script
11 This test tries to exercise the ssh functionality with a dummy script
12
12
13 creating 'remote' repo
13 creating 'remote' repo
14
14
15 $ hg init remote
15 $ hg init remote
16 $ cd remote
16 $ cd remote
17 $ echo this > foo
17 $ echo this > foo
18 $ echo this > fooO
18 $ echo this > fooO
19 $ hg ci -A -m "init" foo fooO
19 $ hg ci -A -m "init" foo fooO
20
20
21 insert a closed branch (issue4428)
21 insert a closed branch (issue4428)
22
22
23 $ hg up null
23 $ hg up null
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 $ hg branch closed
25 $ hg branch closed
26 marked working directory as branch closed
26 marked working directory as branch closed
27 (branches are permanent and global, did you want a bookmark?)
27 (branches are permanent and global, did you want a bookmark?)
28 $ hg ci -mc0
28 $ hg ci -mc0
29 $ hg ci --close-branch -mc1
29 $ hg ci --close-branch -mc1
30 $ hg up -q default
30 $ hg up -q default
31
31
32 configure for serving
32 configure for serving
33
33
34 $ cat <<EOF > .hg/hgrc
34 $ cat <<EOF > .hg/hgrc
35 > [server]
35 > [server]
36 > uncompressed = True
36 > uncompressed = True
37 >
37 >
38 > [hooks]
38 > [hooks]
39 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
39 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
40 > EOF
40 > EOF
41 $ cd ..
41 $ cd ..
42
42
43 repo not found error
43 repo not found error
44
44
45 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
45 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
46 remote: abort: there is no Mercurial repository here (.hg not found)!
46 remote: abort: there is no Mercurial repository here (.hg not found)!
47 abort: no suitable response from remote hg!
47 abort: no suitable response from remote hg!
48 [255]
48 [255]
49
49
50 non-existent absolute path
50 non-existent absolute path
51
51
52 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
52 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
53 remote: abort: there is no Mercurial repository here (.hg not found)!
53 remote: abort: there is no Mercurial repository here (.hg not found)!
54 abort: no suitable response from remote hg!
54 abort: no suitable response from remote hg!
55 [255]
55 [255]
56
56
57 clone remote via stream
57 clone remote via stream
58
58
59 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
59 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
60 streaming all changes
60 streaming all changes
61 4 files to transfer, 615 bytes of data
61 4 files to transfer, 615 bytes of data
62 transferred 615 bytes in * seconds (*) (glob)
62 transferred 615 bytes in * seconds (*) (glob)
63 searching for changes
63 searching for changes
64 no changes found
64 no changes found
65 updating to branch default
65 updating to branch default
66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 $ cd local-stream
67 $ cd local-stream
68 $ hg verify
68 $ hg verify
69 checking changesets
69 checking changesets
70 checking manifests
70 checking manifests
71 crosschecking files in changesets and manifests
71 crosschecking files in changesets and manifests
72 checking files
72 checking files
73 2 files, 3 changesets, 2 total revisions
73 2 files, 3 changesets, 2 total revisions
74 $ hg branches
74 $ hg branches
75 default 0:1160648e36ce
75 default 0:1160648e36ce
76 $ cd ..
76 $ cd ..
77
77
78 clone bookmarks via stream
78 clone bookmarks via stream
79
79
80 $ hg -R local-stream book mybook
80 $ hg -R local-stream book mybook
81 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
81 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
82 streaming all changes
82 streaming all changes
83 4 files to transfer, 615 bytes of data
83 4 files to transfer, 615 bytes of data
84 transferred 615 bytes in * seconds (*) (glob)
84 transferred 615 bytes in * seconds (*) (glob)
85 searching for changes
85 searching for changes
86 no changes found
86 no changes found
87 updating to branch default
87 updating to branch default
88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ cd stream2
89 $ cd stream2
90 $ hg book
90 $ hg book
91 mybook 0:1160648e36ce
91 mybook 0:1160648e36ce
92 $ cd ..
92 $ cd ..
93 $ rm -rf local-stream stream2
93 $ rm -rf local-stream stream2
94
94
95 clone remote via pull
95 clone remote via pull
96
96
97 $ hg clone -e dummyssh ssh://user@dummy/remote local
97 $ hg clone -e dummyssh ssh://user@dummy/remote local
98 requesting all changes
98 requesting all changes
99 adding changesets
99 adding changesets
100 adding manifests
100 adding manifests
101 adding file changes
101 adding file changes
102 added 3 changesets with 2 changes to 2 files
102 added 3 changesets with 2 changes to 2 files
103 updating to branch default
103 updating to branch default
104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105
105
106 verify
106 verify
107
107
108 $ cd local
108 $ cd local
109 $ hg verify
109 $ hg verify
110 checking changesets
110 checking changesets
111 checking manifests
111 checking manifests
112 crosschecking files in changesets and manifests
112 crosschecking files in changesets and manifests
113 checking files
113 checking files
114 2 files, 3 changesets, 2 total revisions
114 2 files, 3 changesets, 2 total revisions
115 $ echo '[hooks]' >> .hg/hgrc
115 $ echo '[hooks]' >> .hg/hgrc
116 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
116 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
117
117
118 empty default pull
118 empty default pull
119
119
120 $ hg paths
120 $ hg paths
121 default = ssh://user@dummy/remote
121 default = ssh://user@dummy/remote
122 $ hg pull -e dummyssh
122 $ hg pull -e dummyssh
123 pulling from ssh://user@dummy/remote
123 pulling from ssh://user@dummy/remote
124 searching for changes
124 searching for changes
125 no changes found
125 no changes found
126
126
127 pull from wrong ssh URL
127 pull from wrong ssh URL
128
128
129 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
129 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
130 pulling from ssh://user@dummy/doesnotexist
130 pulling from ssh://user@dummy/doesnotexist
131 remote: abort: there is no Mercurial repository here (.hg not found)!
131 remote: abort: there is no Mercurial repository here (.hg not found)!
132 abort: no suitable response from remote hg!
132 abort: no suitable response from remote hg!
133 [255]
133 [255]
134
134
135 local change
135 local change
136
136
137 $ echo bleah > foo
137 $ echo bleah > foo
138 $ hg ci -m "add"
138 $ hg ci -m "add"
139
139
140 updating rc
140 updating rc
141
141
142 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
142 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
143 $ echo "[ui]" >> .hg/hgrc
143 $ echo "[ui]" >> .hg/hgrc
144 $ echo "ssh = dummyssh" >> .hg/hgrc
144 $ echo "ssh = dummyssh" >> .hg/hgrc
145
145
146 find outgoing
146 find outgoing
147
147
148 $ hg out ssh://user@dummy/remote
148 $ hg out ssh://user@dummy/remote
149 comparing with ssh://user@dummy/remote
149 comparing with ssh://user@dummy/remote
150 searching for changes
150 searching for changes
151 changeset: 3:a28a9d1a809c
151 changeset: 3:a28a9d1a809c
152 tag: tip
152 tag: tip
153 parent: 0:1160648e36ce
153 parent: 0:1160648e36ce
154 user: test
154 user: test
155 date: Thu Jan 01 00:00:00 1970 +0000
155 date: Thu Jan 01 00:00:00 1970 +0000
156 summary: add
156 summary: add
157
157
158
158
159 find incoming on the remote side
159 find incoming on the remote side
160
160
161 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
161 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
162 comparing with ssh://user@dummy/local
162 comparing with ssh://user@dummy/local
163 searching for changes
163 searching for changes
164 changeset: 3:a28a9d1a809c
164 changeset: 3:a28a9d1a809c
165 tag: tip
165 tag: tip
166 parent: 0:1160648e36ce
166 parent: 0:1160648e36ce
167 user: test
167 user: test
168 date: Thu Jan 01 00:00:00 1970 +0000
168 date: Thu Jan 01 00:00:00 1970 +0000
169 summary: add
169 summary: add
170
170
171
171
172 find incoming on the remote side (using absolute path)
172 find incoming on the remote side (using absolute path)
173
173
174 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
174 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
175 comparing with ssh://user@dummy/$TESTTMP/local
175 comparing with ssh://user@dummy/$TESTTMP/local
176 searching for changes
176 searching for changes
177 changeset: 3:a28a9d1a809c
177 changeset: 3:a28a9d1a809c
178 tag: tip
178 tag: tip
179 parent: 0:1160648e36ce
179 parent: 0:1160648e36ce
180 user: test
180 user: test
181 date: Thu Jan 01 00:00:00 1970 +0000
181 date: Thu Jan 01 00:00:00 1970 +0000
182 summary: add
182 summary: add
183
183
184
184
185 push
185 push
186
186
187 $ hg push
187 $ hg push
188 pushing to ssh://user@dummy/remote
188 pushing to ssh://user@dummy/remote
189 searching for changes
189 searching for changes
190 remote: adding changesets
190 remote: adding changesets
191 remote: adding manifests
191 remote: adding manifests
192 remote: adding file changes
192 remote: adding file changes
193 remote: added 1 changesets with 1 changes to 1 files
193 remote: added 1 changesets with 1 changes to 1 files
194 $ cd ../remote
194 $ cd ../remote
195
195
196 check remote tip
196 check remote tip
197
197
198 $ hg tip
198 $ hg tip
199 changeset: 3:a28a9d1a809c
199 changeset: 3:a28a9d1a809c
200 tag: tip
200 tag: tip
201 parent: 0:1160648e36ce
201 parent: 0:1160648e36ce
202 user: test
202 user: test
203 date: Thu Jan 01 00:00:00 1970 +0000
203 date: Thu Jan 01 00:00:00 1970 +0000
204 summary: add
204 summary: add
205
205
206 $ hg verify
206 $ hg verify
207 checking changesets
207 checking changesets
208 checking manifests
208 checking manifests
209 crosschecking files in changesets and manifests
209 crosschecking files in changesets and manifests
210 checking files
210 checking files
211 2 files, 4 changesets, 3 total revisions
211 2 files, 4 changesets, 3 total revisions
212 $ hg cat -r tip foo
212 $ hg cat -r tip foo
213 bleah
213 bleah
214 $ echo z > z
214 $ echo z > z
215 $ hg ci -A -m z z
215 $ hg ci -A -m z z
216 created new head
216 created new head
217
217
218 test pushkeys and bookmarks
218 test pushkeys and bookmarks
219
219
220 $ cd ../local
220 $ cd ../local
221 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
221 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
222 bookmarks
222 bookmarks
223 namespaces
223 namespaces
224 phases
224 phases
225 $ hg book foo -r 0
225 $ hg book foo -r 0
226 $ hg out -B
226 $ hg out -B
227 comparing with ssh://user@dummy/remote
227 comparing with ssh://user@dummy/remote
228 searching for changed bookmarks
228 searching for changed bookmarks
229 foo 1160648e36ce
229 foo 1160648e36ce
230 $ hg push -B foo
230 $ hg push -B foo
231 pushing to ssh://user@dummy/remote
231 pushing to ssh://user@dummy/remote
232 searching for changes
232 searching for changes
233 no changes found
233 no changes found
234 exporting bookmark foo
234 exporting bookmark foo
235 [1]
235 [1]
236 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
236 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
237 foo 1160648e36cec0054048a7edc4110c6f84fde594
237 foo 1160648e36cec0054048a7edc4110c6f84fde594
238 $ hg book -f foo
238 $ hg book -f foo
239 $ hg push --traceback
239 $ hg push --traceback
240 pushing to ssh://user@dummy/remote
240 pushing to ssh://user@dummy/remote
241 searching for changes
241 searching for changes
242 no changes found
242 no changes found
243 updating bookmark foo
243 updating bookmark foo
244 [1]
244 [1]
245 $ hg book -d foo
245 $ hg book -d foo
246 $ hg in -B
246 $ hg in -B
247 comparing with ssh://user@dummy/remote
247 comparing with ssh://user@dummy/remote
248 searching for changed bookmarks
248 searching for changed bookmarks
249 foo a28a9d1a809c
249 foo a28a9d1a809c
250 $ hg book -f -r 0 foo
250 $ hg book -f -r 0 foo
251 $ hg pull -B foo
251 $ hg pull -B foo
252 pulling from ssh://user@dummy/remote
252 pulling from ssh://user@dummy/remote
253 no changes found
253 no changes found
254 updating bookmark foo
254 updating bookmark foo
255 $ hg book -d foo
255 $ hg book -d foo
256 $ hg push -B foo
256 $ hg push -B foo
257 pushing to ssh://user@dummy/remote
257 pushing to ssh://user@dummy/remote
258 searching for changes
258 searching for changes
259 no changes found
259 no changes found
260 deleting remote bookmark foo
260 deleting remote bookmark foo
261 [1]
261 [1]
262
262
263 a bad, evil hook that prints to stdout
263 a bad, evil hook that prints to stdout
264
264
265 $ cat <<EOF > $TESTTMP/badhook
265 $ cat <<EOF > $TESTTMP/badhook
266 > import sys
266 > import sys
267 > sys.stdout.write("KABOOM\n")
267 > sys.stdout.write("KABOOM\n")
268 > EOF
268 > EOF
269
269
270 $ echo '[hooks]' >> ../remote/.hg/hgrc
270 $ echo '[hooks]' >> ../remote/.hg/hgrc
271 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
271 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
272 $ echo r > r
272 $ echo r > r
273 $ hg ci -A -m z r
273 $ hg ci -A -m z r
274
274
275 push should succeed even though it has an unexpected response
275 push should succeed even though it has an unexpected response
276
276
277 $ hg push
277 $ hg push
278 pushing to ssh://user@dummy/remote
278 pushing to ssh://user@dummy/remote
279 searching for changes
279 searching for changes
280 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
280 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
281 remote: adding changesets
281 remote: adding changesets
282 remote: adding manifests
282 remote: adding manifests
283 remote: adding file changes
283 remote: adding file changes
284 remote: added 1 changesets with 1 changes to 1 files
284 remote: added 1 changesets with 1 changes to 1 files
285 remote: KABOOM
285 remote: KABOOM
286 $ hg -R ../remote heads
286 $ hg -R ../remote heads
287 changeset: 5:1383141674ec
287 changeset: 5:1383141674ec
288 tag: tip
288 tag: tip
289 parent: 3:a28a9d1a809c
289 parent: 3:a28a9d1a809c
290 user: test
290 user: test
291 date: Thu Jan 01 00:00:00 1970 +0000
291 date: Thu Jan 01 00:00:00 1970 +0000
292 summary: z
292 summary: z
293
293
294 changeset: 4:6c0482d977a3
294 changeset: 4:6c0482d977a3
295 parent: 0:1160648e36ce
295 parent: 0:1160648e36ce
296 user: test
296 user: test
297 date: Thu Jan 01 00:00:00 1970 +0000
297 date: Thu Jan 01 00:00:00 1970 +0000
298 summary: z
298 summary: z
299
299
300
300
301 clone bookmarks
301 clone bookmarks
302
302
303 $ hg -R ../remote bookmark test
303 $ hg -R ../remote bookmark test
304 $ hg -R ../remote bookmarks
304 $ hg -R ../remote bookmarks
305 * test 4:6c0482d977a3
305 * test 4:6c0482d977a3
306 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
306 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
307 requesting all changes
307 requesting all changes
308 adding changesets
308 adding changesets
309 adding manifests
309 adding manifests
310 adding file changes
310 adding file changes
311 added 6 changesets with 5 changes to 4 files (+1 heads)
311 added 6 changesets with 5 changes to 4 files (+1 heads)
312 updating to branch default
312 updating to branch default
313 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 $ hg -R local-bookmarks bookmarks
314 $ hg -R local-bookmarks bookmarks
315 test 4:6c0482d977a3
315 test 4:6c0482d977a3
316
316
317 passwords in ssh urls are not supported
317 passwords in ssh urls are not supported
318 (we use a glob here because different Python versions give different
318 (we use a glob here because different Python versions give different
319 results here)
319 results here)
320
320
321 $ hg push ssh://user:erroneouspwd@dummy/remote
321 $ hg push ssh://user:erroneouspwd@dummy/remote
322 pushing to ssh://user:*@dummy/remote (glob)
322 pushing to ssh://user:*@dummy/remote (glob)
323 abort: password in URL not supported!
323 abort: password in URL not supported!
324 [255]
324 [255]
325
325
326 $ cd ..
326 $ cd ..
327
327
328 hide outer repo
328 hide outer repo
329 $ hg init
329 $ hg init
330
330
331 Test remote paths with spaces (issue2983):
331 Test remote paths with spaces (issue2983):
332
332
333 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
333 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
334 $ touch "$TESTTMP/a repo/test"
334 $ touch "$TESTTMP/a repo/test"
335 $ hg -R 'a repo' commit -A -m "test"
335 $ hg -R 'a repo' commit -A -m "test"
336 adding test
336 adding test
337 $ hg -R 'a repo' tag tag
337 $ hg -R 'a repo' tag tag
338 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
338 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
339 73649e48688a
339 73649e48688a
340
340
341 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
341 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
342 abort: unknown revision 'noNoNO'!
342 abort: unknown revision 'noNoNO'!
343 [255]
343 [255]
344
344
345 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
345 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
346
346
347 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
347 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
348 destination directory: a repo
348 destination directory: a repo
349 abort: destination 'a repo' is not empty
349 abort: destination 'a repo' is not empty
350 [255]
350 [255]
351
351
352 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
352 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
353 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
353 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
354 parameters:
354 parameters:
355
355
356 $ cat > ssh.sh << EOF
356 $ cat > ssh.sh << EOF
357 > userhost="\$1"
357 > userhost="\$1"
358 > SSH_ORIGINAL_COMMAND="\$2"
358 > SSH_ORIGINAL_COMMAND="\$2"
359 > export SSH_ORIGINAL_COMMAND
359 > export SSH_ORIGINAL_COMMAND
360 > PYTHONPATH="$PYTHONPATH"
360 > PYTHONPATH="$PYTHONPATH"
361 > export PYTHONPATH
361 > export PYTHONPATH
362 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
362 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
363 > EOF
363 > EOF
364
364
365 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
365 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
366 73649e48688a
366 73649e48688a
367
367
368 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
368 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
369 remote: Illegal repository "$TESTTMP/a'repo" (glob)
369 remote: Illegal repository "$TESTTMP/a'repo" (glob)
370 abort: no suitable response from remote hg!
370 abort: no suitable response from remote hg!
371 [255]
371 [255]
372
372
373 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
373 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
374 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
374 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
375 abort: no suitable response from remote hg!
375 abort: no suitable response from remote hg!
376 [255]
376 [255]
377
377
378 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
378 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
379 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
379 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
380 [255]
380 [255]
381
381
382 Test hg-ssh in read-only mode:
382 Test hg-ssh in read-only mode:
383
383
384 $ cat > ssh.sh << EOF
384 $ cat > ssh.sh << EOF
385 > userhost="\$1"
385 > userhost="\$1"
386 > SSH_ORIGINAL_COMMAND="\$2"
386 > SSH_ORIGINAL_COMMAND="\$2"
387 > export SSH_ORIGINAL_COMMAND
387 > export SSH_ORIGINAL_COMMAND
388 > PYTHONPATH="$PYTHONPATH"
388 > PYTHONPATH="$PYTHONPATH"
389 > export PYTHONPATH
389 > export PYTHONPATH
390 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
390 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
391 > EOF
391 > EOF
392
392
393 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
393 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
394 requesting all changes
394 requesting all changes
395 adding changesets
395 adding changesets
396 adding manifests
396 adding manifests
397 adding file changes
397 adding file changes
398 added 6 changesets with 5 changes to 4 files (+1 heads)
398 added 6 changesets with 5 changes to 4 files (+1 heads)
399 updating to branch default
399 updating to branch default
400 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
400 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
401
401
402 $ cd read-only-local
402 $ cd read-only-local
403 $ echo "baz" > bar
403 $ echo "baz" > bar
404 $ hg ci -A -m "unpushable commit" bar
404 $ hg ci -A -m "unpushable commit" bar
405 $ hg push --ssh "sh ../ssh.sh"
405 $ hg push --ssh "sh ../ssh.sh"
406 pushing to ssh://user@dummy/*/remote (glob)
406 pushing to ssh://user@dummy/*/remote (glob)
407 searching for changes
407 searching for changes
408 remote: Permission denied
408 remote: Permission denied
409 remote: abort: pretxnopen.hg-ssh hook failed
409 remote: abort: pretxnopen.hg-ssh hook failed
410 remote: Permission denied
410 remote: Permission denied
411 remote: pushkey-abort: prepushkey.hg-ssh hook failed
411 remote: pushkey-abort: prepushkey.hg-ssh hook failed
412 updating 6c0482d977a3 to public failed!
412 updating 6c0482d977a3 to public failed!
413 [1]
413 [1]
414
414
415 $ cd ..
415 $ cd ..
416
416
417 stderr from remote commands should be printed before stdout from local code (issue4336)
417 stderr from remote commands should be printed before stdout from local code (issue4336)
418
418
419 $ hg clone remote stderr-ordering
419 $ hg clone remote stderr-ordering
420 updating to branch default
420 updating to branch default
421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 $ cd stderr-ordering
422 $ cd stderr-ordering
423 $ cat >> localwrite.py << EOF
423 $ cat >> localwrite.py << EOF
424 > from mercurial import exchange, extensions
424 > from mercurial import exchange, extensions
425 >
425 >
426 > def wrappedpush(orig, repo, *args, **kwargs):
426 > def wrappedpush(orig, repo, *args, **kwargs):
427 > res = orig(repo, *args, **kwargs)
427 > res = orig(repo, *args, **kwargs)
428 > repo.ui.write('local stdout\n')
428 > repo.ui.write('local stdout\n')
429 > return res
429 > return res
430 >
430 >
431 > def extsetup(ui):
431 > def extsetup(ui):
432 > extensions.wrapfunction(exchange, 'push', wrappedpush)
432 > extensions.wrapfunction(exchange, 'push', wrappedpush)
433 > EOF
433 > EOF
434
434
435 $ cat >> .hg/hgrc << EOF
435 $ cat >> .hg/hgrc << EOF
436 > [paths]
436 > [paths]
437 > default-push = ssh://user@dummy/remote
437 > default-push = ssh://user@dummy/remote
438 > [ui]
438 > [ui]
439 > ssh = dummyssh
439 > ssh = dummyssh
440 > [extensions]
440 > [extensions]
441 > localwrite = localwrite.py
441 > localwrite = localwrite.py
442 > EOF
442 > EOF
443
443
444 $ echo localwrite > foo
444 $ echo localwrite > foo
445 $ hg commit -m 'testing localwrite'
445 $ hg commit -m 'testing localwrite'
446 $ hg push
446 $ hg push
447 pushing to ssh://user@dummy/remote
447 pushing to ssh://user@dummy/remote
448 searching for changes
448 searching for changes
449 remote: adding changesets
449 remote: adding changesets
450 remote: adding manifests
450 remote: adding manifests
451 remote: adding file changes
451 remote: adding file changes
452 remote: added 1 changesets with 1 changes to 1 files
452 remote: added 1 changesets with 1 changes to 1 files
453 remote: KABOOM
453 remote: KABOOM
454 local stdout
454 local stdout
455
455
456 debug output
456 debug output
457
457
458 $ hg pull --debug ssh://user@dummy/remote
458 $ hg pull --debug ssh://user@dummy/remote
459 pulling from ssh://user@dummy/remote
459 pulling from ssh://user@dummy/remote
460 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
460 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
461 sending hello command
461 sending hello command
462 sending between command
462 sending between command
463 remote: 335
463 remote: 345
464 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
464 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
465 remote: 1
465 remote: 1
466 preparing listkeys for "bookmarks"
466 preparing listkeys for "bookmarks"
467 sending listkeys command
467 sending listkeys command
468 received listkey for "bookmarks": 45 bytes
468 received listkey for "bookmarks": 45 bytes
469 query 1; heads
469 query 1; heads
470 sending batch command
470 sending batch command
471 searching for changes
471 searching for changes
472 all remote heads known locally
472 all remote heads known locally
473 no changes found
473 no changes found
474 preparing listkeys for "phases"
474 preparing listkeys for "phases"
475 sending listkeys command
475 sending listkeys command
476 received listkey for "phases": 15 bytes
476 received listkey for "phases": 15 bytes
477 checking for updated bookmarks
477 checking for updated bookmarks
478
478
479 $ cd ..
479 $ cd ..
480
480
481 $ cat dummylog
481 $ cat dummylog
482 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
482 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
483 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
483 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
484 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
484 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
485 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
485 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
488 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 Got arguments 1:user@dummy 2:hg -R local serve --stdio
490 Got arguments 1:user@dummy 2:hg -R local serve --stdio
491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
493 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
503 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 Got arguments 1:user@dummy 2:hg init 'a repo'
505 Got arguments 1:user@dummy 2:hg init 'a repo'
506 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
506 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
507 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
507 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
508 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
508 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
509 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
509 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
511 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
511 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
@@ -1,503 +1,503 b''
1
1
2 This test tries to exercise the ssh functionality with a dummy script
2 This test tries to exercise the ssh functionality with a dummy script
3
3
4 creating 'remote' repo
4 creating 'remote' repo
5
5
6 $ hg init remote
6 $ hg init remote
7 $ cd remote
7 $ cd remote
8 $ echo this > foo
8 $ echo this > foo
9 $ echo this > fooO
9 $ echo this > fooO
10 $ hg ci -A -m "init" foo fooO
10 $ hg ci -A -m "init" foo fooO
11
11
12 insert a closed branch (issue4428)
12 insert a closed branch (issue4428)
13
13
14 $ hg up null
14 $ hg up null
15 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
15 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
16 $ hg branch closed
16 $ hg branch closed
17 marked working directory as branch closed
17 marked working directory as branch closed
18 (branches are permanent and global, did you want a bookmark?)
18 (branches are permanent and global, did you want a bookmark?)
19 $ hg ci -mc0
19 $ hg ci -mc0
20 $ hg ci --close-branch -mc1
20 $ hg ci --close-branch -mc1
21 $ hg up -q default
21 $ hg up -q default
22
22
23 configure for serving
23 configure for serving
24
24
25 $ cat <<EOF > .hg/hgrc
25 $ cat <<EOF > .hg/hgrc
26 > [server]
26 > [server]
27 > uncompressed = True
27 > uncompressed = True
28 >
28 >
29 > [hooks]
29 > [hooks]
30 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
30 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
31 > EOF
31 > EOF
32 $ cd ..
32 $ cd ..
33
33
34 repo not found error
34 repo not found error
35
35
36 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
36 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
37 remote: abort: there is no Mercurial repository here (.hg not found)!
37 remote: abort: there is no Mercurial repository here (.hg not found)!
38 abort: no suitable response from remote hg!
38 abort: no suitable response from remote hg!
39 [255]
39 [255]
40
40
41 non-existent absolute path
41 non-existent absolute path
42
42
43 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
43 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
44 remote: abort: there is no Mercurial repository here (.hg not found)!
44 remote: abort: there is no Mercurial repository here (.hg not found)!
45 abort: no suitable response from remote hg!
45 abort: no suitable response from remote hg!
46 [255]
46 [255]
47
47
48 clone remote via stream
48 clone remote via stream
49
49
50 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
50 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
51 streaming all changes
51 streaming all changes
52 4 files to transfer, 615 bytes of data
52 4 files to transfer, 615 bytes of data
53 transferred 615 bytes in * seconds (*) (glob)
53 transferred 615 bytes in * seconds (*) (glob)
54 searching for changes
54 searching for changes
55 no changes found
55 no changes found
56 updating to branch default
56 updating to branch default
57 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
57 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 $ cd local-stream
58 $ cd local-stream
59 $ hg verify
59 $ hg verify
60 checking changesets
60 checking changesets
61 checking manifests
61 checking manifests
62 crosschecking files in changesets and manifests
62 crosschecking files in changesets and manifests
63 checking files
63 checking files
64 2 files, 3 changesets, 2 total revisions
64 2 files, 3 changesets, 2 total revisions
65 $ hg branches
65 $ hg branches
66 default 0:1160648e36ce
66 default 0:1160648e36ce
67 $ cd ..
67 $ cd ..
68
68
69 clone bookmarks via stream
69 clone bookmarks via stream
70
70
71 $ hg -R local-stream book mybook
71 $ hg -R local-stream book mybook
72 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
72 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
73 streaming all changes
73 streaming all changes
74 4 files to transfer, 615 bytes of data
74 4 files to transfer, 615 bytes of data
75 transferred 615 bytes in * seconds (*) (glob)
75 transferred 615 bytes in * seconds (*) (glob)
76 searching for changes
76 searching for changes
77 no changes found
77 no changes found
78 updating to branch default
78 updating to branch default
79 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 $ cd stream2
80 $ cd stream2
81 $ hg book
81 $ hg book
82 mybook 0:1160648e36ce
82 mybook 0:1160648e36ce
83 $ cd ..
83 $ cd ..
84 $ rm -rf local-stream stream2
84 $ rm -rf local-stream stream2
85
85
86 clone remote via pull
86 clone remote via pull
87
87
88 $ hg clone -e dummyssh ssh://user@dummy/remote local
88 $ hg clone -e dummyssh ssh://user@dummy/remote local
89 requesting all changes
89 requesting all changes
90 adding changesets
90 adding changesets
91 adding manifests
91 adding manifests
92 adding file changes
92 adding file changes
93 added 3 changesets with 2 changes to 2 files
93 added 3 changesets with 2 changes to 2 files
94 updating to branch default
94 updating to branch default
95 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
95 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
96
96
97 verify
97 verify
98
98
99 $ cd local
99 $ cd local
100 $ hg verify
100 $ hg verify
101 checking changesets
101 checking changesets
102 checking manifests
102 checking manifests
103 crosschecking files in changesets and manifests
103 crosschecking files in changesets and manifests
104 checking files
104 checking files
105 2 files, 3 changesets, 2 total revisions
105 2 files, 3 changesets, 2 total revisions
106 $ echo '[hooks]' >> .hg/hgrc
106 $ echo '[hooks]' >> .hg/hgrc
107 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
107 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
108
108
109 empty default pull
109 empty default pull
110
110
111 $ hg paths
111 $ hg paths
112 default = ssh://user@dummy/remote
112 default = ssh://user@dummy/remote
113 $ hg pull -e dummyssh
113 $ hg pull -e dummyssh
114 pulling from ssh://user@dummy/remote
114 pulling from ssh://user@dummy/remote
115 searching for changes
115 searching for changes
116 no changes found
116 no changes found
117
117
118 pull from wrong ssh URL
118 pull from wrong ssh URL
119
119
120 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
120 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
121 pulling from ssh://user@dummy/doesnotexist
121 pulling from ssh://user@dummy/doesnotexist
122 remote: abort: there is no Mercurial repository here (.hg not found)!
122 remote: abort: there is no Mercurial repository here (.hg not found)!
123 abort: no suitable response from remote hg!
123 abort: no suitable response from remote hg!
124 [255]
124 [255]
125
125
126 local change
126 local change
127
127
128 $ echo bleah > foo
128 $ echo bleah > foo
129 $ hg ci -m "add"
129 $ hg ci -m "add"
130
130
131 updating rc
131 updating rc
132
132
133 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
133 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
134 $ echo "[ui]" >> .hg/hgrc
134 $ echo "[ui]" >> .hg/hgrc
135 $ echo "ssh = dummyssh" >> .hg/hgrc
135 $ echo "ssh = dummyssh" >> .hg/hgrc
136
136
137 find outgoing
137 find outgoing
138
138
139 $ hg out ssh://user@dummy/remote
139 $ hg out ssh://user@dummy/remote
140 comparing with ssh://user@dummy/remote
140 comparing with ssh://user@dummy/remote
141 searching for changes
141 searching for changes
142 changeset: 3:a28a9d1a809c
142 changeset: 3:a28a9d1a809c
143 tag: tip
143 tag: tip
144 parent: 0:1160648e36ce
144 parent: 0:1160648e36ce
145 user: test
145 user: test
146 date: Thu Jan 01 00:00:00 1970 +0000
146 date: Thu Jan 01 00:00:00 1970 +0000
147 summary: add
147 summary: add
148
148
149
149
150 find incoming on the remote side
150 find incoming on the remote side
151
151
152 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
152 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
153 comparing with ssh://user@dummy/local
153 comparing with ssh://user@dummy/local
154 searching for changes
154 searching for changes
155 changeset: 3:a28a9d1a809c
155 changeset: 3:a28a9d1a809c
156 tag: tip
156 tag: tip
157 parent: 0:1160648e36ce
157 parent: 0:1160648e36ce
158 user: test
158 user: test
159 date: Thu Jan 01 00:00:00 1970 +0000
159 date: Thu Jan 01 00:00:00 1970 +0000
160 summary: add
160 summary: add
161
161
162
162
163 find incoming on the remote side (using absolute path)
163 find incoming on the remote side (using absolute path)
164
164
165 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
165 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
166 comparing with ssh://user@dummy/$TESTTMP/local
166 comparing with ssh://user@dummy/$TESTTMP/local
167 searching for changes
167 searching for changes
168 changeset: 3:a28a9d1a809c
168 changeset: 3:a28a9d1a809c
169 tag: tip
169 tag: tip
170 parent: 0:1160648e36ce
170 parent: 0:1160648e36ce
171 user: test
171 user: test
172 date: Thu Jan 01 00:00:00 1970 +0000
172 date: Thu Jan 01 00:00:00 1970 +0000
173 summary: add
173 summary: add
174
174
175
175
176 push
176 push
177
177
178 $ hg push
178 $ hg push
179 pushing to ssh://user@dummy/remote
179 pushing to ssh://user@dummy/remote
180 searching for changes
180 searching for changes
181 remote: adding changesets
181 remote: adding changesets
182 remote: adding manifests
182 remote: adding manifests
183 remote: adding file changes
183 remote: adding file changes
184 remote: added 1 changesets with 1 changes to 1 files
184 remote: added 1 changesets with 1 changes to 1 files
185 $ cd ../remote
185 $ cd ../remote
186
186
187 check remote tip
187 check remote tip
188
188
189 $ hg tip
189 $ hg tip
190 changeset: 3:a28a9d1a809c
190 changeset: 3:a28a9d1a809c
191 tag: tip
191 tag: tip
192 parent: 0:1160648e36ce
192 parent: 0:1160648e36ce
193 user: test
193 user: test
194 date: Thu Jan 01 00:00:00 1970 +0000
194 date: Thu Jan 01 00:00:00 1970 +0000
195 summary: add
195 summary: add
196
196
197 $ hg verify
197 $ hg verify
198 checking changesets
198 checking changesets
199 checking manifests
199 checking manifests
200 crosschecking files in changesets and manifests
200 crosschecking files in changesets and manifests
201 checking files
201 checking files
202 2 files, 4 changesets, 3 total revisions
202 2 files, 4 changesets, 3 total revisions
203 $ hg cat -r tip foo
203 $ hg cat -r tip foo
204 bleah
204 bleah
205 $ echo z > z
205 $ echo z > z
206 $ hg ci -A -m z z
206 $ hg ci -A -m z z
207 created new head
207 created new head
208
208
209 test pushkeys and bookmarks
209 test pushkeys and bookmarks
210
210
211 $ cd ../local
211 $ cd ../local
212 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
212 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
213 bookmarks
213 bookmarks
214 namespaces
214 namespaces
215 phases
215 phases
216 $ hg book foo -r 0
216 $ hg book foo -r 0
217 $ hg out -B
217 $ hg out -B
218 comparing with ssh://user@dummy/remote
218 comparing with ssh://user@dummy/remote
219 searching for changed bookmarks
219 searching for changed bookmarks
220 foo 1160648e36ce
220 foo 1160648e36ce
221 $ hg push -B foo
221 $ hg push -B foo
222 pushing to ssh://user@dummy/remote
222 pushing to ssh://user@dummy/remote
223 searching for changes
223 searching for changes
224 no changes found
224 no changes found
225 exporting bookmark foo
225 exporting bookmark foo
226 [1]
226 [1]
227 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
227 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
228 foo 1160648e36cec0054048a7edc4110c6f84fde594
228 foo 1160648e36cec0054048a7edc4110c6f84fde594
229 $ hg book -f foo
229 $ hg book -f foo
230 $ hg push --traceback
230 $ hg push --traceback
231 pushing to ssh://user@dummy/remote
231 pushing to ssh://user@dummy/remote
232 searching for changes
232 searching for changes
233 no changes found
233 no changes found
234 updating bookmark foo
234 updating bookmark foo
235 [1]
235 [1]
236 $ hg book -d foo
236 $ hg book -d foo
237 $ hg in -B
237 $ hg in -B
238 comparing with ssh://user@dummy/remote
238 comparing with ssh://user@dummy/remote
239 searching for changed bookmarks
239 searching for changed bookmarks
240 foo a28a9d1a809c
240 foo a28a9d1a809c
241 $ hg book -f -r 0 foo
241 $ hg book -f -r 0 foo
242 $ hg pull -B foo
242 $ hg pull -B foo
243 pulling from ssh://user@dummy/remote
243 pulling from ssh://user@dummy/remote
244 no changes found
244 no changes found
245 updating bookmark foo
245 updating bookmark foo
246 $ hg book -d foo
246 $ hg book -d foo
247 $ hg push -B foo
247 $ hg push -B foo
248 pushing to ssh://user@dummy/remote
248 pushing to ssh://user@dummy/remote
249 searching for changes
249 searching for changes
250 no changes found
250 no changes found
251 deleting remote bookmark foo
251 deleting remote bookmark foo
252 [1]
252 [1]
253
253
254 a bad, evil hook that prints to stdout
254 a bad, evil hook that prints to stdout
255
255
256 $ cat <<EOF > $TESTTMP/badhook
256 $ cat <<EOF > $TESTTMP/badhook
257 > import sys
257 > import sys
258 > sys.stdout.write("KABOOM\n")
258 > sys.stdout.write("KABOOM\n")
259 > EOF
259 > EOF
260
260
261 $ echo '[hooks]' >> ../remote/.hg/hgrc
261 $ echo '[hooks]' >> ../remote/.hg/hgrc
262 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
262 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
263 $ echo r > r
263 $ echo r > r
264 $ hg ci -A -m z r
264 $ hg ci -A -m z r
265
265
266 push should succeed even though it has an unexpected response
266 push should succeed even though it has an unexpected response
267
267
268 $ hg push
268 $ hg push
269 pushing to ssh://user@dummy/remote
269 pushing to ssh://user@dummy/remote
270 searching for changes
270 searching for changes
271 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
271 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
272 remote: adding changesets
272 remote: adding changesets
273 remote: adding manifests
273 remote: adding manifests
274 remote: adding file changes
274 remote: adding file changes
275 remote: added 1 changesets with 1 changes to 1 files
275 remote: added 1 changesets with 1 changes to 1 files
276 remote: KABOOM
276 remote: KABOOM
277 $ hg -R ../remote heads
277 $ hg -R ../remote heads
278 changeset: 5:1383141674ec
278 changeset: 5:1383141674ec
279 tag: tip
279 tag: tip
280 parent: 3:a28a9d1a809c
280 parent: 3:a28a9d1a809c
281 user: test
281 user: test
282 date: Thu Jan 01 00:00:00 1970 +0000
282 date: Thu Jan 01 00:00:00 1970 +0000
283 summary: z
283 summary: z
284
284
285 changeset: 4:6c0482d977a3
285 changeset: 4:6c0482d977a3
286 parent: 0:1160648e36ce
286 parent: 0:1160648e36ce
287 user: test
287 user: test
288 date: Thu Jan 01 00:00:00 1970 +0000
288 date: Thu Jan 01 00:00:00 1970 +0000
289 summary: z
289 summary: z
290
290
291
291
292 clone bookmarks
292 clone bookmarks
293
293
294 $ hg -R ../remote bookmark test
294 $ hg -R ../remote bookmark test
295 $ hg -R ../remote bookmarks
295 $ hg -R ../remote bookmarks
296 * test 4:6c0482d977a3
296 * test 4:6c0482d977a3
297 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
297 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
298 requesting all changes
298 requesting all changes
299 adding changesets
299 adding changesets
300 adding manifests
300 adding manifests
301 adding file changes
301 adding file changes
302 added 6 changesets with 5 changes to 4 files (+1 heads)
302 added 6 changesets with 5 changes to 4 files (+1 heads)
303 updating to branch default
303 updating to branch default
304 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
304 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 $ hg -R local-bookmarks bookmarks
305 $ hg -R local-bookmarks bookmarks
306 test 4:6c0482d977a3
306 test 4:6c0482d977a3
307
307
308 passwords in ssh urls are not supported
308 passwords in ssh urls are not supported
309 (we use a glob here because different Python versions give different
309 (we use a glob here because different Python versions give different
310 results here)
310 results here)
311
311
312 $ hg push ssh://user:erroneouspwd@dummy/remote
312 $ hg push ssh://user:erroneouspwd@dummy/remote
313 pushing to ssh://user:*@dummy/remote (glob)
313 pushing to ssh://user:*@dummy/remote (glob)
314 abort: password in URL not supported!
314 abort: password in URL not supported!
315 [255]
315 [255]
316
316
317 $ cd ..
317 $ cd ..
318
318
319 hide outer repo
319 hide outer repo
320 $ hg init
320 $ hg init
321
321
322 Test remote paths with spaces (issue2983):
322 Test remote paths with spaces (issue2983):
323
323
324 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
324 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
325 $ touch "$TESTTMP/a repo/test"
325 $ touch "$TESTTMP/a repo/test"
326 $ hg -R 'a repo' commit -A -m "test"
326 $ hg -R 'a repo' commit -A -m "test"
327 adding test
327 adding test
328 $ hg -R 'a repo' tag tag
328 $ hg -R 'a repo' tag tag
329 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
329 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
330 73649e48688a
330 73649e48688a
331
331
332 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
332 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
333 abort: unknown revision 'noNoNO'!
333 abort: unknown revision 'noNoNO'!
334 [255]
334 [255]
335
335
336 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
336 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
337
337
338 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
338 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
339 destination directory: a repo
339 destination directory: a repo
340 abort: destination 'a repo' is not empty
340 abort: destination 'a repo' is not empty
341 [255]
341 [255]
342
342
343 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
343 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
344 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
344 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
345 parameters:
345 parameters:
346
346
347 $ cat > ssh.sh << EOF
347 $ cat > ssh.sh << EOF
348 > userhost="\$1"
348 > userhost="\$1"
349 > SSH_ORIGINAL_COMMAND="\$2"
349 > SSH_ORIGINAL_COMMAND="\$2"
350 > export SSH_ORIGINAL_COMMAND
350 > export SSH_ORIGINAL_COMMAND
351 > PYTHONPATH="$PYTHONPATH"
351 > PYTHONPATH="$PYTHONPATH"
352 > export PYTHONPATH
352 > export PYTHONPATH
353 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
353 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
354 > EOF
354 > EOF
355
355
356 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
356 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
357 73649e48688a
357 73649e48688a
358
358
359 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
359 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
360 remote: Illegal repository "$TESTTMP/a'repo" (glob)
360 remote: Illegal repository "$TESTTMP/a'repo" (glob)
361 abort: no suitable response from remote hg!
361 abort: no suitable response from remote hg!
362 [255]
362 [255]
363
363
364 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
364 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
365 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
365 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
366 abort: no suitable response from remote hg!
366 abort: no suitable response from remote hg!
367 [255]
367 [255]
368
368
369 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
369 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
370 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
370 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
371 [255]
371 [255]
372
372
373 Test hg-ssh in read-only mode:
373 Test hg-ssh in read-only mode:
374
374
375 $ cat > ssh.sh << EOF
375 $ cat > ssh.sh << EOF
376 > userhost="\$1"
376 > userhost="\$1"
377 > SSH_ORIGINAL_COMMAND="\$2"
377 > SSH_ORIGINAL_COMMAND="\$2"
378 > export SSH_ORIGINAL_COMMAND
378 > export SSH_ORIGINAL_COMMAND
379 > PYTHONPATH="$PYTHONPATH"
379 > PYTHONPATH="$PYTHONPATH"
380 > export PYTHONPATH
380 > export PYTHONPATH
381 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
381 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
382 > EOF
382 > EOF
383
383
384 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
384 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
385 requesting all changes
385 requesting all changes
386 adding changesets
386 adding changesets
387 adding manifests
387 adding manifests
388 adding file changes
388 adding file changes
389 added 6 changesets with 5 changes to 4 files (+1 heads)
389 added 6 changesets with 5 changes to 4 files (+1 heads)
390 updating to branch default
390 updating to branch default
391 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
391 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
392
392
393 $ cd read-only-local
393 $ cd read-only-local
394 $ echo "baz" > bar
394 $ echo "baz" > bar
395 $ hg ci -A -m "unpushable commit" bar
395 $ hg ci -A -m "unpushable commit" bar
396 $ hg push --ssh "sh ../ssh.sh"
396 $ hg push --ssh "sh ../ssh.sh"
397 pushing to ssh://user@dummy/*/remote (glob)
397 pushing to ssh://user@dummy/*/remote (glob)
398 searching for changes
398 searching for changes
399 remote: Permission denied
399 remote: Permission denied
400 abort: pretxnopen.hg-ssh hook failed
400 abort: pretxnopen.hg-ssh hook failed
401 [255]
401 [255]
402
402
403 $ cd ..
403 $ cd ..
404
404
405 stderr from remote commands should be printed before stdout from local code (issue4336)
405 stderr from remote commands should be printed before stdout from local code (issue4336)
406
406
407 $ hg clone remote stderr-ordering
407 $ hg clone remote stderr-ordering
408 updating to branch default
408 updating to branch default
409 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
409 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 $ cd stderr-ordering
410 $ cd stderr-ordering
411 $ cat >> localwrite.py << EOF
411 $ cat >> localwrite.py << EOF
412 > from mercurial import exchange, extensions
412 > from mercurial import exchange, extensions
413 >
413 >
414 > def wrappedpush(orig, repo, *args, **kwargs):
414 > def wrappedpush(orig, repo, *args, **kwargs):
415 > res = orig(repo, *args, **kwargs)
415 > res = orig(repo, *args, **kwargs)
416 > repo.ui.write('local stdout\n')
416 > repo.ui.write('local stdout\n')
417 > return res
417 > return res
418 >
418 >
419 > def extsetup(ui):
419 > def extsetup(ui):
420 > extensions.wrapfunction(exchange, 'push', wrappedpush)
420 > extensions.wrapfunction(exchange, 'push', wrappedpush)
421 > EOF
421 > EOF
422
422
423 $ cat >> .hg/hgrc << EOF
423 $ cat >> .hg/hgrc << EOF
424 > [paths]
424 > [paths]
425 > default-push = ssh://user@dummy/remote
425 > default-push = ssh://user@dummy/remote
426 > [ui]
426 > [ui]
427 > ssh = dummyssh
427 > ssh = dummyssh
428 > [extensions]
428 > [extensions]
429 > localwrite = localwrite.py
429 > localwrite = localwrite.py
430 > EOF
430 > EOF
431
431
432 $ echo localwrite > foo
432 $ echo localwrite > foo
433 $ hg commit -m 'testing localwrite'
433 $ hg commit -m 'testing localwrite'
434 $ hg push
434 $ hg push
435 pushing to ssh://user@dummy/remote
435 pushing to ssh://user@dummy/remote
436 searching for changes
436 searching for changes
437 remote: adding changesets
437 remote: adding changesets
438 remote: adding manifests
438 remote: adding manifests
439 remote: adding file changes
439 remote: adding file changes
440 remote: added 1 changesets with 1 changes to 1 files
440 remote: added 1 changesets with 1 changes to 1 files
441 remote: KABOOM
441 remote: KABOOM
442 local stdout
442 local stdout
443
443
444 debug output
444 debug output
445
445
446 $ hg pull --debug ssh://user@dummy/remote
446 $ hg pull --debug ssh://user@dummy/remote
447 pulling from ssh://user@dummy/remote
447 pulling from ssh://user@dummy/remote
448 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
448 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
449 sending hello command
449 sending hello command
450 sending between command
450 sending between command
451 remote: 335
451 remote: 345
452 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
452 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
453 remote: 1
453 remote: 1
454 query 1; heads
454 query 1; heads
455 sending batch command
455 sending batch command
456 searching for changes
456 searching for changes
457 all remote heads known locally
457 all remote heads known locally
458 no changes found
458 no changes found
459 sending getbundle command
459 sending getbundle command
460 bundle2-input-bundle: with-transaction
460 bundle2-input-bundle: with-transaction
461 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
461 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
462 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
462 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
463 bundle2-input-part: total payload size 45
463 bundle2-input-part: total payload size 45
464 bundle2-input-bundle: 1 parts total
464 bundle2-input-bundle: 1 parts total
465 checking for updated bookmarks
465 checking for updated bookmarks
466 preparing listkeys for "phases"
466 preparing listkeys for "phases"
467 sending listkeys command
467 sending listkeys command
468 received listkey for "phases": 15 bytes
468 received listkey for "phases": 15 bytes
469
469
470 $ cd ..
470 $ cd ..
471
471
472 $ cat dummylog
472 $ cat dummylog
473 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
473 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
474 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
474 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
475 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
475 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
476 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
476 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
477 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
477 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
478 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
478 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
479 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
479 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
480 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
480 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
481 Got arguments 1:user@dummy 2:hg -R local serve --stdio
481 Got arguments 1:user@dummy 2:hg -R local serve --stdio
482 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
482 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
483 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
483 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
484 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
484 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
485 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
485 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
494 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 Got arguments 1:user@dummy 2:hg init 'a repo'
496 Got arguments 1:user@dummy 2:hg init 'a repo'
497 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
497 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
498 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
498 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
499 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
499 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
500 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
500 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
502 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
General Comments 0
You need to be logged in to leave comments. Login now