##// END OF EJS Templates
bundle2: add an 'error' capability...
Pierre-Yves David -
r25491:8cd01592 default
parent child Browse files
Show More
@@ -1,1390 +1,1391 b''
1 1 # bundle2.py - generic container format to transmit arbitrary data.
2 2 #
3 3 # Copyright 2013 Facebook, Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7 """Handling of the new bundle2 format
8 8
9 9 The goal of bundle2 is to act as an atomically packet to transmit a set of
10 10 payloads in an application agnostic way. It consist in a sequence of "parts"
11 11 that will be handed to and processed by the application layer.
12 12
13 13
14 14 General format architecture
15 15 ===========================
16 16
17 17 The format is architectured as follow
18 18
19 19 - magic string
20 20 - stream level parameters
21 21 - payload parts (any number)
22 22 - end of stream marker.
23 23
24 24 the Binary format
25 25 ============================
26 26
27 27 All numbers are unsigned and big-endian.
28 28
29 29 stream level parameters
30 30 ------------------------
31 31
32 32 Binary format is as follow
33 33
34 34 :params size: int32
35 35
36 36 The total number of Bytes used by the parameters
37 37
38 38 :params value: arbitrary number of Bytes
39 39
40 40 A blob of `params size` containing the serialized version of all stream level
41 41 parameters.
42 42
43 43 The blob contains a space separated list of parameters. Parameters with value
44 44 are stored in the form `<name>=<value>`. Both name and value are urlquoted.
45 45
46 46 Empty name are obviously forbidden.
47 47
48 48 Name MUST start with a letter. If this first letter is lower case, the
49 49 parameter is advisory and can be safely ignored. However when the first
50 50 letter is capital, the parameter is mandatory and the bundling process MUST
51 51 stop if he is not able to proceed it.
52 52
53 53 Stream parameters use a simple textual format for two main reasons:
54 54
55 55 - Stream level parameters should remain simple and we want to discourage any
56 56 crazy usage.
57 57 - Textual data allow easy human inspection of a bundle2 header in case of
58 58 troubles.
59 59
60 60 Any Applicative level options MUST go into a bundle2 part instead.
61 61
62 62 Payload part
63 63 ------------------------
64 64
65 65 Binary format is as follow
66 66
67 67 :header size: int32
68 68
69 69 The total number of Bytes used by the part headers. When the header is empty
70 70 (size = 0) this is interpreted as the end of stream marker.
71 71
72 72 :header:
73 73
74 74 The header defines how to interpret the part. It contains two piece of
75 75 data: the part type, and the part parameters.
76 76
77 77 The part type is used to route an application level handler, that can
78 78 interpret payload.
79 79
80 80 Part parameters are passed to the application level handler. They are
81 81 meant to convey information that will help the application level object to
82 82 interpret the part payload.
83 83
84 84 The binary format of the header is has follow
85 85
86 86 :typesize: (one byte)
87 87
88 88 :parttype: alphanumerical part name (restricted to [a-zA-Z0-9_:-]*)
89 89
90 90 :partid: A 32bits integer (unique in the bundle) that can be used to refer
91 91 to this part.
92 92
93 93 :parameters:
94 94
95 95 Part's parameter may have arbitrary content, the binary structure is::
96 96
97 97 <mandatory-count><advisory-count><param-sizes><param-data>
98 98
99 99 :mandatory-count: 1 byte, number of mandatory parameters
100 100
101 101 :advisory-count: 1 byte, number of advisory parameters
102 102
103 103 :param-sizes:
104 104
105 105 N couple of bytes, where N is the total number of parameters. Each
106 106 couple contains (<size-of-key>, <size-of-value) for one parameter.
107 107
108 108 :param-data:
109 109
110 110 A blob of bytes from which each parameter key and value can be
111 111 retrieved using the list of size couples stored in the previous
112 112 field.
113 113
114 114 Mandatory parameters comes first, then the advisory ones.
115 115
116 116 Each parameter's key MUST be unique within the part.
117 117
118 118 :payload:
119 119
120 120 payload is a series of `<chunksize><chunkdata>`.
121 121
122 122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
123 123 `chunksize` says)` The payload part is concluded by a zero size chunk.
124 124
125 125 The current implementation always produces either zero or one chunk.
126 126 This is an implementation limitation that will ultimately be lifted.
127 127
128 128 `chunksize` can be negative to trigger special case processing. No such
129 129 processing is in place yet.
130 130
131 131 Bundle processing
132 132 ============================
133 133
134 134 Each part is processed in order using a "part handler". Handler are registered
135 135 for a certain part type.
136 136
137 137 The matching of a part to its handler is case insensitive. The case of the
138 138 part type is used to know if a part is mandatory or advisory. If the Part type
139 139 contains any uppercase char it is considered mandatory. When no handler is
140 140 known for a Mandatory part, the process is aborted and an exception is raised.
141 141 If the part is advisory and no handler is known, the part is ignored. When the
142 142 process is aborted, the full bundle is still read from the stream to keep the
143 143 channel usable. But none of the part read from an abort are processed. In the
144 144 future, dropping the stream may become an option for channel we do not care to
145 145 preserve.
146 146 """
147 147
148 148 import errno
149 149 import sys
150 150 import util
151 151 import struct
152 152 import urllib
153 153 import string
154 154 import obsolete
155 155 import pushkey
156 156 import url
157 157 import re
158 158
159 159 import changegroup, error, tags
160 160 from i18n import _
161 161
162 162 _pack = struct.pack
163 163 _unpack = struct.unpack
164 164
165 165 _fstreamparamsize = '>i'
166 166 _fpartheadersize = '>i'
167 167 _fparttypesize = '>B'
168 168 _fpartid = '>I'
169 169 _fpayloadsize = '>i'
170 170 _fpartparamcount = '>BB'
171 171
172 172 preferedchunksize = 4096
173 173
174 174 _parttypeforbidden = re.compile('[^a-zA-Z0-9_:-]')
175 175
176 176 def outdebug(ui, message):
177 177 """debug regarding output stream (bundling)"""
178 178 if ui.configbool('devel', 'bundle2.debug', False):
179 179 ui.debug('bundle2-output: %s\n' % message)
180 180
181 181 def indebug(ui, message):
182 182 """debug on input stream (unbundling)"""
183 183 if ui.configbool('devel', 'bundle2.debug', False):
184 184 ui.debug('bundle2-input: %s\n' % message)
185 185
186 186 def validateparttype(parttype):
187 187 """raise ValueError if a parttype contains invalid character"""
188 188 if _parttypeforbidden.search(parttype):
189 189 raise ValueError(parttype)
190 190
191 191 def _makefpartparamsizes(nbparams):
192 192 """return a struct format to read part parameter sizes
193 193
194 194 The number parameters is variable so we need to build that format
195 195 dynamically.
196 196 """
197 197 return '>'+('BB'*nbparams)
198 198
199 199 parthandlermapping = {}
200 200
201 201 def parthandler(parttype, params=()):
202 202 """decorator that register a function as a bundle2 part handler
203 203
204 204 eg::
205 205
206 206 @parthandler('myparttype', ('mandatory', 'param', 'handled'))
207 207 def myparttypehandler(...):
208 208 '''process a part of type "my part".'''
209 209 ...
210 210 """
211 211 validateparttype(parttype)
212 212 def _decorator(func):
213 213 lparttype = parttype.lower() # enforce lower case matching.
214 214 assert lparttype not in parthandlermapping
215 215 parthandlermapping[lparttype] = func
216 216 func.params = frozenset(params)
217 217 return func
218 218 return _decorator
219 219
220 220 class unbundlerecords(object):
221 221 """keep record of what happens during and unbundle
222 222
223 223 New records are added using `records.add('cat', obj)`. Where 'cat' is a
224 224 category of record and obj is an arbitrary object.
225 225
226 226 `records['cat']` will return all entries of this category 'cat'.
227 227
228 228 Iterating on the object itself will yield `('category', obj)` tuples
229 229 for all entries.
230 230
231 231 All iterations happens in chronological order.
232 232 """
233 233
234 234 def __init__(self):
235 235 self._categories = {}
236 236 self._sequences = []
237 237 self._replies = {}
238 238
239 239 def add(self, category, entry, inreplyto=None):
240 240 """add a new record of a given category.
241 241
242 242 The entry can then be retrieved in the list returned by
243 243 self['category']."""
244 244 self._categories.setdefault(category, []).append(entry)
245 245 self._sequences.append((category, entry))
246 246 if inreplyto is not None:
247 247 self.getreplies(inreplyto).add(category, entry)
248 248
249 249 def getreplies(self, partid):
250 250 """get the records that are replies to a specific part"""
251 251 return self._replies.setdefault(partid, unbundlerecords())
252 252
253 253 def __getitem__(self, cat):
254 254 return tuple(self._categories.get(cat, ()))
255 255
256 256 def __iter__(self):
257 257 return iter(self._sequences)
258 258
259 259 def __len__(self):
260 260 return len(self._sequences)
261 261
262 262 def __nonzero__(self):
263 263 return bool(self._sequences)
264 264
265 265 class bundleoperation(object):
266 266 """an object that represents a single bundling process
267 267
268 268 Its purpose is to carry unbundle-related objects and states.
269 269
270 270 A new object should be created at the beginning of each bundle processing.
271 271 The object is to be returned by the processing function.
272 272
273 273 The object has very little content now it will ultimately contain:
274 274 * an access to the repo the bundle is applied to,
275 275 * a ui object,
276 276 * a way to retrieve a transaction to add changes to the repo,
277 277 * a way to record the result of processing each part,
278 278 * a way to construct a bundle response when applicable.
279 279 """
280 280
281 281 def __init__(self, repo, transactiongetter, captureoutput=True):
282 282 self.repo = repo
283 283 self.ui = repo.ui
284 284 self.records = unbundlerecords()
285 285 self.gettransaction = transactiongetter
286 286 self.reply = None
287 287 self.captureoutput = captureoutput
288 288
289 289 class TransactionUnavailable(RuntimeError):
290 290 pass
291 291
292 292 def _notransaction():
293 293 """default method to get a transaction while processing a bundle
294 294
295 295 Raise an exception to highlight the fact that no transaction was expected
296 296 to be created"""
297 297 raise TransactionUnavailable()
298 298
299 299 def processbundle(repo, unbundler, transactiongetter=None, op=None):
300 300 """This function process a bundle, apply effect to/from a repo
301 301
302 302 It iterates over each part then searches for and uses the proper handling
303 303 code to process the part. Parts are processed in order.
304 304
305 305 This is very early version of this function that will be strongly reworked
306 306 before final usage.
307 307
308 308 Unknown Mandatory part will abort the process.
309 309
310 310 It is temporarily possible to provide a prebuilt bundleoperation to the
311 311 function. This is used to ensure output is properly propagated in case of
312 312 an error during the unbundling. This output capturing part will likely be
313 313 reworked and this ability will probably go away in the process.
314 314 """
315 315 if op is None:
316 316 if transactiongetter is None:
317 317 transactiongetter = _notransaction
318 318 op = bundleoperation(repo, transactiongetter)
319 319 # todo:
320 320 # - replace this is a init function soon.
321 321 # - exception catching
322 322 unbundler.params
323 323 if repo.ui.debugflag:
324 324 msg = ['bundle2-input-bundle:']
325 325 if unbundler.params:
326 326 msg.append(' %i params')
327 327 if op.gettransaction is None:
328 328 msg.append(' no-transaction')
329 329 else:
330 330 msg.append(' with-transaction')
331 331 msg.append('\n')
332 332 repo.ui.debug(''.join(msg))
333 333 iterparts = enumerate(unbundler.iterparts())
334 334 part = None
335 335 nbpart = 0
336 336 try:
337 337 for nbpart, part in iterparts:
338 338 _processpart(op, part)
339 339 except BaseException, exc:
340 340 for nbpart, part in iterparts:
341 341 # consume the bundle content
342 342 part.seek(0, 2)
343 343 # Small hack to let caller code distinguish exceptions from bundle2
344 344 # processing from processing the old format. This is mostly
345 345 # needed to handle different return codes to unbundle according to the
346 346 # type of bundle. We should probably clean up or drop this return code
347 347 # craziness in a future version.
348 348 exc.duringunbundle2 = True
349 349 salvaged = []
350 350 if op.reply is not None:
351 351 salvaged = op.reply.salvageoutput()
352 352 exc._bundle2salvagedoutput = salvaged
353 353 raise
354 354 finally:
355 355 repo.ui.debug('bundle2-input-bundle: %i parts total\n' % nbpart)
356 356
357 357 return op
358 358
359 359 def _processpart(op, part):
360 360 """process a single part from a bundle
361 361
362 362 The part is guaranteed to have been fully consumed when the function exits
363 363 (even if an exception is raised)."""
364 364 status = 'unknown' # used by debug output
365 365 try:
366 366 try:
367 367 handler = parthandlermapping.get(part.type)
368 368 if handler is None:
369 369 status = 'unsupported-type'
370 370 raise error.UnsupportedPartError(parttype=part.type)
371 371 indebug(op.ui, 'found a handler for part %r' % part.type)
372 372 unknownparams = part.mandatorykeys - handler.params
373 373 if unknownparams:
374 374 unknownparams = list(unknownparams)
375 375 unknownparams.sort()
376 376 status = 'unsupported-params (%s)' % unknownparams
377 377 raise error.UnsupportedPartError(parttype=part.type,
378 378 params=unknownparams)
379 379 status = 'supported'
380 380 except error.UnsupportedPartError, exc:
381 381 if part.mandatory: # mandatory parts
382 382 raise
383 383 indebug(op.ui, 'ignoring unsupported advisory part %s' % exc)
384 384 return # skip to part processing
385 385 finally:
386 386 if op.ui.debugflag:
387 387 msg = ['bundle2-input-part: "%s"' % part.type]
388 388 if not part.mandatory:
389 389 msg.append(' (advisory)')
390 390 nbmp = len(part.mandatorykeys)
391 391 nbap = len(part.params) - nbmp
392 392 if nbmp or nbap:
393 393 msg.append(' (params:')
394 394 if nbmp:
395 395 msg.append(' %i mandatory' % nbmp)
396 396 if nbap:
397 397 msg.append(' %i advisory' % nbmp)
398 398 msg.append(')')
399 399 msg.append(' %s\n' % status)
400 400 op.ui.debug(''.join(msg))
401 401
402 402 # handler is called outside the above try block so that we don't
403 403 # risk catching KeyErrors from anything other than the
404 404 # parthandlermapping lookup (any KeyError raised by handler()
405 405 # itself represents a defect of a different variety).
406 406 output = None
407 407 if op.captureoutput and op.reply is not None:
408 408 op.ui.pushbuffer(error=True, subproc=True)
409 409 output = ''
410 410 try:
411 411 handler(op, part)
412 412 finally:
413 413 if output is not None:
414 414 output = op.ui.popbuffer()
415 415 if output:
416 416 outpart = op.reply.newpart('output', data=output,
417 417 mandatory=False)
418 418 outpart.addparam('in-reply-to', str(part.id), mandatory=False)
419 419 finally:
420 420 # consume the part content to not corrupt the stream.
421 421 part.seek(0, 2)
422 422
423 423
424 424 def decodecaps(blob):
425 425 """decode a bundle2 caps bytes blob into a dictionary
426 426
427 427 The blob is a list of capabilities (one per line)
428 428 Capabilities may have values using a line of the form::
429 429
430 430 capability=value1,value2,value3
431 431
432 432 The values are always a list."""
433 433 caps = {}
434 434 for line in blob.splitlines():
435 435 if not line:
436 436 continue
437 437 if '=' not in line:
438 438 key, vals = line, ()
439 439 else:
440 440 key, vals = line.split('=', 1)
441 441 vals = vals.split(',')
442 442 key = urllib.unquote(key)
443 443 vals = [urllib.unquote(v) for v in vals]
444 444 caps[key] = vals
445 445 return caps
446 446
447 447 def encodecaps(caps):
448 448 """encode a bundle2 caps dictionary into a bytes blob"""
449 449 chunks = []
450 450 for ca in sorted(caps):
451 451 vals = caps[ca]
452 452 ca = urllib.quote(ca)
453 453 vals = [urllib.quote(v) for v in vals]
454 454 if vals:
455 455 ca = "%s=%s" % (ca, ','.join(vals))
456 456 chunks.append(ca)
457 457 return '\n'.join(chunks)
458 458
459 459 class bundle20(object):
460 460 """represent an outgoing bundle2 container
461 461
462 462 Use the `addparam` method to add stream level parameter. and `newpart` to
463 463 populate it. Then call `getchunks` to retrieve all the binary chunks of
464 464 data that compose the bundle2 container."""
465 465
466 466 _magicstring = 'HG20'
467 467
468 468 def __init__(self, ui, capabilities=()):
469 469 self.ui = ui
470 470 self._params = []
471 471 self._parts = []
472 472 self.capabilities = dict(capabilities)
473 473
474 474 @property
475 475 def nbparts(self):
476 476 """total number of parts added to the bundler"""
477 477 return len(self._parts)
478 478
479 479 # methods used to defines the bundle2 content
480 480 def addparam(self, name, value=None):
481 481 """add a stream level parameter"""
482 482 if not name:
483 483 raise ValueError('empty parameter name')
484 484 if name[0] not in string.letters:
485 485 raise ValueError('non letter first character: %r' % name)
486 486 self._params.append((name, value))
487 487
488 488 def addpart(self, part):
489 489 """add a new part to the bundle2 container
490 490
491 491 Parts contains the actual applicative payload."""
492 492 assert part.id is None
493 493 part.id = len(self._parts) # very cheap counter
494 494 self._parts.append(part)
495 495
496 496 def newpart(self, typeid, *args, **kwargs):
497 497 """create a new part and add it to the containers
498 498
499 499 As the part is directly added to the containers. For now, this means
500 500 that any failure to properly initialize the part after calling
501 501 ``newpart`` should result in a failure of the whole bundling process.
502 502
503 503 You can still fall back to manually create and add if you need better
504 504 control."""
505 505 part = bundlepart(typeid, *args, **kwargs)
506 506 self.addpart(part)
507 507 return part
508 508
509 509 # methods used to generate the bundle2 stream
510 510 def getchunks(self):
511 511 if self.ui.debugflag:
512 512 msg = ['bundle2-output-bundle: "%s",' % self._magicstring]
513 513 if self._params:
514 514 msg.append(' (%i params)' % len(self._params))
515 515 msg.append(' %i parts total\n' % len(self._parts))
516 516 self.ui.debug(''.join(msg))
517 517 outdebug(self.ui, 'start emission of %s stream' % self._magicstring)
518 518 yield self._magicstring
519 519 param = self._paramchunk()
520 520 outdebug(self.ui, 'bundle parameter: %s' % param)
521 521 yield _pack(_fstreamparamsize, len(param))
522 522 if param:
523 523 yield param
524 524
525 525 outdebug(self.ui, 'start of parts')
526 526 for part in self._parts:
527 527 outdebug(self.ui, 'bundle part: "%s"' % part.type)
528 528 for chunk in part.getchunks(ui=self.ui):
529 529 yield chunk
530 530 outdebug(self.ui, 'end of bundle')
531 531 yield _pack(_fpartheadersize, 0)
532 532
533 533 def _paramchunk(self):
534 534 """return a encoded version of all stream parameters"""
535 535 blocks = []
536 536 for par, value in self._params:
537 537 par = urllib.quote(par)
538 538 if value is not None:
539 539 value = urllib.quote(value)
540 540 par = '%s=%s' % (par, value)
541 541 blocks.append(par)
542 542 return ' '.join(blocks)
543 543
544 544 def salvageoutput(self):
545 545 """return a list with a copy of all output parts in the bundle
546 546
547 547 This is meant to be used during error handling to make sure we preserve
548 548 server output"""
549 549 salvaged = []
550 550 for part in self._parts:
551 551 if part.type.startswith('output'):
552 552 salvaged.append(part.copy())
553 553 return salvaged
554 554
555 555
556 556 class unpackermixin(object):
557 557 """A mixin to extract bytes and struct data from a stream"""
558 558
559 559 def __init__(self, fp):
560 560 self._fp = fp
561 561 self._seekable = (util.safehasattr(fp, 'seek') and
562 562 util.safehasattr(fp, 'tell'))
563 563
564 564 def _unpack(self, format):
565 565 """unpack this struct format from the stream"""
566 566 data = self._readexact(struct.calcsize(format))
567 567 return _unpack(format, data)
568 568
569 569 def _readexact(self, size):
570 570 """read exactly <size> bytes from the stream"""
571 571 return changegroup.readexactly(self._fp, size)
572 572
573 573 def seek(self, offset, whence=0):
574 574 """move the underlying file pointer"""
575 575 if self._seekable:
576 576 return self._fp.seek(offset, whence)
577 577 else:
578 578 raise NotImplementedError(_('File pointer is not seekable'))
579 579
580 580 def tell(self):
581 581 """return the file offset, or None if file is not seekable"""
582 582 if self._seekable:
583 583 try:
584 584 return self._fp.tell()
585 585 except IOError, e:
586 586 if e.errno == errno.ESPIPE:
587 587 self._seekable = False
588 588 else:
589 589 raise
590 590 return None
591 591
592 592 def close(self):
593 593 """close underlying file"""
594 594 if util.safehasattr(self._fp, 'close'):
595 595 return self._fp.close()
596 596
597 597 def getunbundler(ui, fp, header=None):
598 598 """return a valid unbundler object for a given header"""
599 599 if header is None:
600 600 header = changegroup.readexactly(fp, 4)
601 601 magic, version = header[0:2], header[2:4]
602 602 if magic != 'HG':
603 603 raise util.Abort(_('not a Mercurial bundle'))
604 604 unbundlerclass = formatmap.get(version)
605 605 if unbundlerclass is None:
606 606 raise util.Abort(_('unknown bundle version %s') % version)
607 607 unbundler = unbundlerclass(ui, fp)
608 608 indebug(ui, 'start processing of %s stream' % header)
609 609 return unbundler
610 610
611 611 class unbundle20(unpackermixin):
612 612 """interpret a bundle2 stream
613 613
614 614 This class is fed with a binary stream and yields parts through its
615 615 `iterparts` methods."""
616 616
617 617 def __init__(self, ui, fp):
618 618 """If header is specified, we do not read it out of the stream."""
619 619 self.ui = ui
620 620 super(unbundle20, self).__init__(fp)
621 621
622 622 @util.propertycache
623 623 def params(self):
624 624 """dictionary of stream level parameters"""
625 625 indebug(self.ui, 'reading bundle2 stream parameters')
626 626 params = {}
627 627 paramssize = self._unpack(_fstreamparamsize)[0]
628 628 if paramssize < 0:
629 629 raise error.BundleValueError('negative bundle param size: %i'
630 630 % paramssize)
631 631 if paramssize:
632 632 for p in self._readexact(paramssize).split(' '):
633 633 p = p.split('=', 1)
634 634 p = [urllib.unquote(i) for i in p]
635 635 if len(p) < 2:
636 636 p.append(None)
637 637 self._processparam(*p)
638 638 params[p[0]] = p[1]
639 639 return params
640 640
641 641 def _processparam(self, name, value):
642 642 """process a parameter, applying its effect if needed
643 643
644 644 Parameter starting with a lower case letter are advisory and will be
645 645 ignored when unknown. Those starting with an upper case letter are
646 646 mandatory and will this function will raise a KeyError when unknown.
647 647
648 648 Note: no option are currently supported. Any input will be either
649 649 ignored or failing.
650 650 """
651 651 if not name:
652 652 raise ValueError('empty parameter name')
653 653 if name[0] not in string.letters:
654 654 raise ValueError('non letter first character: %r' % name)
655 655 # Some logic will be later added here to try to process the option for
656 656 # a dict of known parameter.
657 657 if name[0].islower():
658 658 indebug(self.ui, "ignoring unknown parameter %r" % name)
659 659 else:
660 660 raise error.UnsupportedPartError(params=(name,))
661 661
662 662
663 663 def iterparts(self):
664 664 """yield all parts contained in the stream"""
665 665 # make sure param have been loaded
666 666 self.params
667 667 indebug(self.ui, 'start extraction of bundle2 parts')
668 668 headerblock = self._readpartheader()
669 669 while headerblock is not None:
670 670 part = unbundlepart(self.ui, headerblock, self._fp)
671 671 yield part
672 672 part.seek(0, 2)
673 673 headerblock = self._readpartheader()
674 674 indebug(self.ui, 'end of bundle2 stream')
675 675
676 676 def _readpartheader(self):
677 677 """reads a part header size and return the bytes blob
678 678
679 679 returns None if empty"""
680 680 headersize = self._unpack(_fpartheadersize)[0]
681 681 if headersize < 0:
682 682 raise error.BundleValueError('negative part header size: %i'
683 683 % headersize)
684 684 indebug(self.ui, 'part header size: %i' % headersize)
685 685 if headersize:
686 686 return self._readexact(headersize)
687 687 return None
688 688
689 689 def compressed(self):
690 690 return False
691 691
692 692 formatmap = {'20': unbundle20}
693 693
694 694 class bundlepart(object):
695 695 """A bundle2 part contains application level payload
696 696
697 697 The part `type` is used to route the part to the application level
698 698 handler.
699 699
700 700 The part payload is contained in ``part.data``. It could be raw bytes or a
701 701 generator of byte chunks.
702 702
703 703 You can add parameters to the part using the ``addparam`` method.
704 704 Parameters can be either mandatory (default) or advisory. Remote side
705 705 should be able to safely ignore the advisory ones.
706 706
707 707 Both data and parameters cannot be modified after the generation has begun.
708 708 """
709 709
710 710 def __init__(self, parttype, mandatoryparams=(), advisoryparams=(),
711 711 data='', mandatory=True):
712 712 validateparttype(parttype)
713 713 self.id = None
714 714 self.type = parttype
715 715 self._data = data
716 716 self._mandatoryparams = list(mandatoryparams)
717 717 self._advisoryparams = list(advisoryparams)
718 718 # checking for duplicated entries
719 719 self._seenparams = set()
720 720 for pname, __ in self._mandatoryparams + self._advisoryparams:
721 721 if pname in self._seenparams:
722 722 raise RuntimeError('duplicated params: %s' % pname)
723 723 self._seenparams.add(pname)
724 724 # status of the part's generation:
725 725 # - None: not started,
726 726 # - False: currently generated,
727 727 # - True: generation done.
728 728 self._generated = None
729 729 self.mandatory = mandatory
730 730
731 731 def copy(self):
732 732 """return a copy of the part
733 733
734 734 The new part have the very same content but no partid assigned yet.
735 735 Parts with generated data cannot be copied."""
736 736 assert not util.safehasattr(self.data, 'next')
737 737 return self.__class__(self.type, self._mandatoryparams,
738 738 self._advisoryparams, self._data, self.mandatory)
739 739
740 740 # methods used to defines the part content
741 741 def __setdata(self, data):
742 742 if self._generated is not None:
743 743 raise error.ReadOnlyPartError('part is being generated')
744 744 self._data = data
745 745 def __getdata(self):
746 746 return self._data
747 747 data = property(__getdata, __setdata)
748 748
749 749 @property
750 750 def mandatoryparams(self):
751 751 # make it an immutable tuple to force people through ``addparam``
752 752 return tuple(self._mandatoryparams)
753 753
754 754 @property
755 755 def advisoryparams(self):
756 756 # make it an immutable tuple to force people through ``addparam``
757 757 return tuple(self._advisoryparams)
758 758
759 759 def addparam(self, name, value='', mandatory=True):
760 760 if self._generated is not None:
761 761 raise error.ReadOnlyPartError('part is being generated')
762 762 if name in self._seenparams:
763 763 raise ValueError('duplicated params: %s' % name)
764 764 self._seenparams.add(name)
765 765 params = self._advisoryparams
766 766 if mandatory:
767 767 params = self._mandatoryparams
768 768 params.append((name, value))
769 769
770 770 # methods used to generates the bundle2 stream
771 771 def getchunks(self, ui):
772 772 if self._generated is not None:
773 773 raise RuntimeError('part can only be consumed once')
774 774 self._generated = False
775 775
776 776 if ui.debugflag:
777 777 msg = ['bundle2-output-part: "%s"' % self.type]
778 778 if not self.mandatory:
779 779 msg.append(' (advisory)')
780 780 nbmp = len(self.mandatoryparams)
781 781 nbap = len(self.advisoryparams)
782 782 if nbmp or nbap:
783 783 msg.append(' (params:')
784 784 if nbmp:
785 785 msg.append(' %i mandatory' % nbmp)
786 786 if nbap:
787 787 msg.append(' %i advisory' % nbmp)
788 788 msg.append(')')
789 789 if not self.data:
790 790 msg.append(' empty payload')
791 791 elif util.safehasattr(self.data, 'next'):
792 792 msg.append(' streamed payload')
793 793 else:
794 794 msg.append(' %i bytes payload' % len(self.data))
795 795 msg.append('\n')
796 796 ui.debug(''.join(msg))
797 797
798 798 #### header
799 799 if self.mandatory:
800 800 parttype = self.type.upper()
801 801 else:
802 802 parttype = self.type.lower()
803 803 outdebug(ui, 'part %s: "%s"' % (self.id, parttype))
804 804 ## parttype
805 805 header = [_pack(_fparttypesize, len(parttype)),
806 806 parttype, _pack(_fpartid, self.id),
807 807 ]
808 808 ## parameters
809 809 # count
810 810 manpar = self.mandatoryparams
811 811 advpar = self.advisoryparams
812 812 header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
813 813 # size
814 814 parsizes = []
815 815 for key, value in manpar:
816 816 parsizes.append(len(key))
817 817 parsizes.append(len(value))
818 818 for key, value in advpar:
819 819 parsizes.append(len(key))
820 820 parsizes.append(len(value))
821 821 paramsizes = _pack(_makefpartparamsizes(len(parsizes) / 2), *parsizes)
822 822 header.append(paramsizes)
823 823 # key, value
824 824 for key, value in manpar:
825 825 header.append(key)
826 826 header.append(value)
827 827 for key, value in advpar:
828 828 header.append(key)
829 829 header.append(value)
830 830 ## finalize header
831 831 headerchunk = ''.join(header)
832 832 outdebug(ui, 'header chunk size: %i' % len(headerchunk))
833 833 yield _pack(_fpartheadersize, len(headerchunk))
834 834 yield headerchunk
835 835 ## payload
836 836 try:
837 837 for chunk in self._payloadchunks():
838 838 outdebug(ui, 'payload chunk size: %i' % len(chunk))
839 839 yield _pack(_fpayloadsize, len(chunk))
840 840 yield chunk
841 841 except BaseException, exc:
842 842 # backup exception data for later
843 843 ui.debug('bundle2-input-stream-interrupt: encoding exception %s'
844 844 % exc)
845 845 exc_info = sys.exc_info()
846 846 msg = 'unexpected error: %s' % exc
847 847 interpart = bundlepart('error:abort', [('message', msg)],
848 848 mandatory=False)
849 849 interpart.id = 0
850 850 yield _pack(_fpayloadsize, -1)
851 851 for chunk in interpart.getchunks(ui=ui):
852 852 yield chunk
853 853 outdebug(ui, 'closing payload chunk')
854 854 # abort current part payload
855 855 yield _pack(_fpayloadsize, 0)
856 856 raise exc_info[0], exc_info[1], exc_info[2]
857 857 # end of payload
858 858 outdebug(ui, 'closing payload chunk')
859 859 yield _pack(_fpayloadsize, 0)
860 860 self._generated = True
861 861
862 862 def _payloadchunks(self):
863 863 """yield chunks of a the part payload
864 864
865 865 Exists to handle the different methods to provide data to a part."""
866 866 # we only support fixed size data now.
867 867 # This will be improved in the future.
868 868 if util.safehasattr(self.data, 'next'):
869 869 buff = util.chunkbuffer(self.data)
870 870 chunk = buff.read(preferedchunksize)
871 871 while chunk:
872 872 yield chunk
873 873 chunk = buff.read(preferedchunksize)
874 874 elif len(self.data):
875 875 yield self.data
876 876
877 877
878 878 flaginterrupt = -1
879 879
880 880 class interrupthandler(unpackermixin):
881 881 """read one part and process it with restricted capability
882 882
883 883 This allows to transmit exception raised on the producer size during part
884 884 iteration while the consumer is reading a part.
885 885
886 886 Part processed in this manner only have access to a ui object,"""
887 887
888 888 def __init__(self, ui, fp):
889 889 super(interrupthandler, self).__init__(fp)
890 890 self.ui = ui
891 891
892 892 def _readpartheader(self):
893 893 """reads a part header size and return the bytes blob
894 894
895 895 returns None if empty"""
896 896 headersize = self._unpack(_fpartheadersize)[0]
897 897 if headersize < 0:
898 898 raise error.BundleValueError('negative part header size: %i'
899 899 % headersize)
900 900 indebug(self.ui, 'part header size: %i\n' % headersize)
901 901 if headersize:
902 902 return self._readexact(headersize)
903 903 return None
904 904
905 905 def __call__(self):
906 906
907 907 self.ui.debug('bundle2-input-stream-interrupt:'
908 908 ' opening out of band context\n')
909 909 indebug(self.ui, 'bundle2 stream interruption, looking for a part.')
910 910 headerblock = self._readpartheader()
911 911 if headerblock is None:
912 912 indebug(self.ui, 'no part found during interruption.')
913 913 return
914 914 part = unbundlepart(self.ui, headerblock, self._fp)
915 915 op = interruptoperation(self.ui)
916 916 _processpart(op, part)
917 917 self.ui.debug('bundle2-input-stream-interrupt:'
918 918 ' closing out of band context\n')
919 919
920 920 class interruptoperation(object):
921 921 """A limited operation to be use by part handler during interruption
922 922
923 923 It only have access to an ui object.
924 924 """
925 925
926 926 def __init__(self, ui):
927 927 self.ui = ui
928 928 self.reply = None
929 929 self.captureoutput = False
930 930
931 931 @property
932 932 def repo(self):
933 933 raise RuntimeError('no repo access from stream interruption')
934 934
935 935 def gettransaction(self):
936 936 raise TransactionUnavailable('no repo access from stream interruption')
937 937
938 938 class unbundlepart(unpackermixin):
939 939 """a bundle part read from a bundle"""
940 940
941 941 def __init__(self, ui, header, fp):
942 942 super(unbundlepart, self).__init__(fp)
943 943 self.ui = ui
944 944 # unbundle state attr
945 945 self._headerdata = header
946 946 self._headeroffset = 0
947 947 self._initialized = False
948 948 self.consumed = False
949 949 # part data
950 950 self.id = None
951 951 self.type = None
952 952 self.mandatoryparams = None
953 953 self.advisoryparams = None
954 954 self.params = None
955 955 self.mandatorykeys = ()
956 956 self._payloadstream = None
957 957 self._readheader()
958 958 self._mandatory = None
959 959 self._chunkindex = [] #(payload, file) position tuples for chunk starts
960 960 self._pos = 0
961 961
962 962 def _fromheader(self, size):
963 963 """return the next <size> byte from the header"""
964 964 offset = self._headeroffset
965 965 data = self._headerdata[offset:(offset + size)]
966 966 self._headeroffset = offset + size
967 967 return data
968 968
969 969 def _unpackheader(self, format):
970 970 """read given format from header
971 971
972 972 This automatically compute the size of the format to read."""
973 973 data = self._fromheader(struct.calcsize(format))
974 974 return _unpack(format, data)
975 975
976 976 def _initparams(self, mandatoryparams, advisoryparams):
977 977 """internal function to setup all logic related parameters"""
978 978 # make it read only to prevent people touching it by mistake.
979 979 self.mandatoryparams = tuple(mandatoryparams)
980 980 self.advisoryparams = tuple(advisoryparams)
981 981 # user friendly UI
982 982 self.params = dict(self.mandatoryparams)
983 983 self.params.update(dict(self.advisoryparams))
984 984 self.mandatorykeys = frozenset(p[0] for p in mandatoryparams)
985 985
986 986 def _payloadchunks(self, chunknum=0):
987 987 '''seek to specified chunk and start yielding data'''
988 988 if len(self._chunkindex) == 0:
989 989 assert chunknum == 0, 'Must start with chunk 0'
990 990 self._chunkindex.append((0, super(unbundlepart, self).tell()))
991 991 else:
992 992 assert chunknum < len(self._chunkindex), \
993 993 'Unknown chunk %d' % chunknum
994 994 super(unbundlepart, self).seek(self._chunkindex[chunknum][1])
995 995
996 996 pos = self._chunkindex[chunknum][0]
997 997 payloadsize = self._unpack(_fpayloadsize)[0]
998 998 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
999 999 while payloadsize:
1000 1000 if payloadsize == flaginterrupt:
1001 1001 # interruption detection, the handler will now read a
1002 1002 # single part and process it.
1003 1003 interrupthandler(self.ui, self._fp)()
1004 1004 elif payloadsize < 0:
1005 1005 msg = 'negative payload chunk size: %i' % payloadsize
1006 1006 raise error.BundleValueError(msg)
1007 1007 else:
1008 1008 result = self._readexact(payloadsize)
1009 1009 chunknum += 1
1010 1010 pos += payloadsize
1011 1011 if chunknum == len(self._chunkindex):
1012 1012 self._chunkindex.append((pos,
1013 1013 super(unbundlepart, self).tell()))
1014 1014 yield result
1015 1015 payloadsize = self._unpack(_fpayloadsize)[0]
1016 1016 indebug(self.ui, 'payload chunk size: %i' % payloadsize)
1017 1017
1018 1018 def _findchunk(self, pos):
1019 1019 '''for a given payload position, return a chunk number and offset'''
1020 1020 for chunk, (ppos, fpos) in enumerate(self._chunkindex):
1021 1021 if ppos == pos:
1022 1022 return chunk, 0
1023 1023 elif ppos > pos:
1024 1024 return chunk - 1, pos - self._chunkindex[chunk - 1][0]
1025 1025 raise ValueError('Unknown chunk')
1026 1026
1027 1027 def _readheader(self):
1028 1028 """read the header and setup the object"""
1029 1029 typesize = self._unpackheader(_fparttypesize)[0]
1030 1030 self.type = self._fromheader(typesize)
1031 1031 indebug(self.ui, 'part type: "%s"' % self.type)
1032 1032 self.id = self._unpackheader(_fpartid)[0]
1033 1033 indebug(self.ui, 'part id: "%s"' % self.id)
1034 1034 # extract mandatory bit from type
1035 1035 self.mandatory = (self.type != self.type.lower())
1036 1036 self.type = self.type.lower()
1037 1037 ## reading parameters
1038 1038 # param count
1039 1039 mancount, advcount = self._unpackheader(_fpartparamcount)
1040 1040 indebug(self.ui, 'part parameters: %i' % (mancount + advcount))
1041 1041 # param size
1042 1042 fparamsizes = _makefpartparamsizes(mancount + advcount)
1043 1043 paramsizes = self._unpackheader(fparamsizes)
1044 1044 # make it a list of couple again
1045 1045 paramsizes = zip(paramsizes[::2], paramsizes[1::2])
1046 1046 # split mandatory from advisory
1047 1047 mansizes = paramsizes[:mancount]
1048 1048 advsizes = paramsizes[mancount:]
1049 1049 # retrieve param value
1050 1050 manparams = []
1051 1051 for key, value in mansizes:
1052 1052 manparams.append((self._fromheader(key), self._fromheader(value)))
1053 1053 advparams = []
1054 1054 for key, value in advsizes:
1055 1055 advparams.append((self._fromheader(key), self._fromheader(value)))
1056 1056 self._initparams(manparams, advparams)
1057 1057 ## part payload
1058 1058 self._payloadstream = util.chunkbuffer(self._payloadchunks())
1059 1059 # we read the data, tell it
1060 1060 self._initialized = True
1061 1061
1062 1062 def read(self, size=None):
1063 1063 """read payload data"""
1064 1064 if not self._initialized:
1065 1065 self._readheader()
1066 1066 if size is None:
1067 1067 data = self._payloadstream.read()
1068 1068 else:
1069 1069 data = self._payloadstream.read(size)
1070 1070 self._pos += len(data)
1071 1071 if size is None or len(data) < size:
1072 1072 if not self.consumed and self._pos:
1073 1073 self.ui.debug('bundle2-input-part: total payload size %i\n'
1074 1074 % self._pos)
1075 1075 self.consumed = True
1076 1076 return data
1077 1077
1078 1078 def tell(self):
1079 1079 return self._pos
1080 1080
1081 1081 def seek(self, offset, whence=0):
1082 1082 if whence == 0:
1083 1083 newpos = offset
1084 1084 elif whence == 1:
1085 1085 newpos = self._pos + offset
1086 1086 elif whence == 2:
1087 1087 if not self.consumed:
1088 1088 self.read()
1089 1089 newpos = self._chunkindex[-1][0] - offset
1090 1090 else:
1091 1091 raise ValueError('Unknown whence value: %r' % (whence,))
1092 1092
1093 1093 if newpos > self._chunkindex[-1][0] and not self.consumed:
1094 1094 self.read()
1095 1095 if not 0 <= newpos <= self._chunkindex[-1][0]:
1096 1096 raise ValueError('Offset out of range')
1097 1097
1098 1098 if self._pos != newpos:
1099 1099 chunk, internaloffset = self._findchunk(newpos)
1100 1100 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
1101 1101 adjust = self.read(internaloffset)
1102 1102 if len(adjust) != internaloffset:
1103 1103 raise util.Abort(_('Seek failed\n'))
1104 1104 self._pos = newpos
1105 1105
1106 1106 # These are only the static capabilities.
1107 1107 # Check the 'getrepocaps' function for the rest.
1108 1108 capabilities = {'HG20': (),
1109 'error': ('abort', 'unsupportedcontent', 'pushraced'),
1109 1110 'listkeys': (),
1110 1111 'pushkey': (),
1111 1112 'digests': tuple(sorted(util.DIGESTS.keys())),
1112 1113 'remote-changegroup': ('http', 'https'),
1113 1114 'hgtagsfnodes': (),
1114 1115 }
1115 1116
1116 1117 def getrepocaps(repo, allowpushback=False):
1117 1118 """return the bundle2 capabilities for a given repo
1118 1119
1119 1120 Exists to allow extensions (like evolution) to mutate the capabilities.
1120 1121 """
1121 1122 caps = capabilities.copy()
1122 1123 caps['changegroup'] = tuple(sorted(changegroup.packermap.keys()))
1123 1124 if obsolete.isenabled(repo, obsolete.exchangeopt):
1124 1125 supportedformat = tuple('V%i' % v for v in obsolete.formats)
1125 1126 caps['obsmarkers'] = supportedformat
1126 1127 if allowpushback:
1127 1128 caps['pushback'] = ()
1128 1129 return caps
1129 1130
1130 1131 def bundle2caps(remote):
1131 1132 """return the bundle capabilities of a peer as dict"""
1132 1133 raw = remote.capable('bundle2')
1133 1134 if not raw and raw != '':
1134 1135 return {}
1135 1136 capsblob = urllib.unquote(remote.capable('bundle2'))
1136 1137 return decodecaps(capsblob)
1137 1138
1138 1139 def obsmarkersversion(caps):
1139 1140 """extract the list of supported obsmarkers versions from a bundle2caps dict
1140 1141 """
1141 1142 obscaps = caps.get('obsmarkers', ())
1142 1143 return [int(c[1:]) for c in obscaps if c.startswith('V')]
1143 1144
1144 1145 @parthandler('changegroup', ('version',))
1145 1146 def handlechangegroup(op, inpart):
1146 1147 """apply a changegroup part on the repo
1147 1148
1148 1149 This is a very early implementation that will massive rework before being
1149 1150 inflicted to any end-user.
1150 1151 """
1151 1152 # Make sure we trigger a transaction creation
1152 1153 #
1153 1154 # The addchangegroup function will get a transaction object by itself, but
1154 1155 # we need to make sure we trigger the creation of a transaction object used
1155 1156 # for the whole processing scope.
1156 1157 op.gettransaction()
1157 1158 unpackerversion = inpart.params.get('version', '01')
1158 1159 # We should raise an appropriate exception here
1159 1160 unpacker = changegroup.packermap[unpackerversion][1]
1160 1161 cg = unpacker(inpart, 'UN')
1161 1162 # the source and url passed here are overwritten by the one contained in
1162 1163 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1163 1164 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1164 1165 op.records.add('changegroup', {'return': ret})
1165 1166 if op.reply is not None:
1166 1167 # This is definitely not the final form of this
1167 1168 # return. But one need to start somewhere.
1168 1169 part = op.reply.newpart('reply:changegroup', mandatory=False)
1169 1170 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1170 1171 part.addparam('return', '%i' % ret, mandatory=False)
1171 1172 assert not inpart.read()
1172 1173
1173 1174 _remotechangegroupparams = tuple(['url', 'size', 'digests'] +
1174 1175 ['digest:%s' % k for k in util.DIGESTS.keys()])
1175 1176 @parthandler('remote-changegroup', _remotechangegroupparams)
1176 1177 def handleremotechangegroup(op, inpart):
1177 1178 """apply a bundle10 on the repo, given an url and validation information
1178 1179
1179 1180 All the information about the remote bundle to import are given as
1180 1181 parameters. The parameters include:
1181 1182 - url: the url to the bundle10.
1182 1183 - size: the bundle10 file size. It is used to validate what was
1183 1184 retrieved by the client matches the server knowledge about the bundle.
1184 1185 - digests: a space separated list of the digest types provided as
1185 1186 parameters.
1186 1187 - digest:<digest-type>: the hexadecimal representation of the digest with
1187 1188 that name. Like the size, it is used to validate what was retrieved by
1188 1189 the client matches what the server knows about the bundle.
1189 1190
1190 1191 When multiple digest types are given, all of them are checked.
1191 1192 """
1192 1193 try:
1193 1194 raw_url = inpart.params['url']
1194 1195 except KeyError:
1195 1196 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
1196 1197 parsed_url = util.url(raw_url)
1197 1198 if parsed_url.scheme not in capabilities['remote-changegroup']:
1198 1199 raise util.Abort(_('remote-changegroup does not support %s urls') %
1199 1200 parsed_url.scheme)
1200 1201
1201 1202 try:
1202 1203 size = int(inpart.params['size'])
1203 1204 except ValueError:
1204 1205 raise util.Abort(_('remote-changegroup: invalid value for param "%s"')
1205 1206 % 'size')
1206 1207 except KeyError:
1207 1208 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')
1208 1209
1209 1210 digests = {}
1210 1211 for typ in inpart.params.get('digests', '').split():
1211 1212 param = 'digest:%s' % typ
1212 1213 try:
1213 1214 value = inpart.params[param]
1214 1215 except KeyError:
1215 1216 raise util.Abort(_('remote-changegroup: missing "%s" param') %
1216 1217 param)
1217 1218 digests[typ] = value
1218 1219
1219 1220 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
1220 1221
1221 1222 # Make sure we trigger a transaction creation
1222 1223 #
1223 1224 # The addchangegroup function will get a transaction object by itself, but
1224 1225 # we need to make sure we trigger the creation of a transaction object used
1225 1226 # for the whole processing scope.
1226 1227 op.gettransaction()
1227 1228 import exchange
1228 1229 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
1229 1230 if not isinstance(cg, changegroup.cg1unpacker):
1230 1231 raise util.Abort(_('%s: not a bundle version 1.0') %
1231 1232 util.hidepassword(raw_url))
1232 1233 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1233 1234 op.records.add('changegroup', {'return': ret})
1234 1235 if op.reply is not None:
1235 1236 # This is definitely not the final form of this
1236 1237 # return. But one need to start somewhere.
1237 1238 part = op.reply.newpart('reply:changegroup')
1238 1239 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1239 1240 part.addparam('return', '%i' % ret, mandatory=False)
1240 1241 try:
1241 1242 real_part.validate()
1242 1243 except util.Abort, e:
1243 1244 raise util.Abort(_('bundle at %s is corrupted:\n%s') %
1244 1245 (util.hidepassword(raw_url), str(e)))
1245 1246 assert not inpart.read()
1246 1247
1247 1248 @parthandler('reply:changegroup', ('return', 'in-reply-to'))
1248 1249 def handlereplychangegroup(op, inpart):
1249 1250 ret = int(inpart.params['return'])
1250 1251 replyto = int(inpart.params['in-reply-to'])
1251 1252 op.records.add('changegroup', {'return': ret}, replyto)
1252 1253
1253 1254 @parthandler('check:heads')
1254 1255 def handlecheckheads(op, inpart):
1255 1256 """check that head of the repo did not change
1256 1257
1257 1258 This is used to detect a push race when using unbundle.
1258 1259 This replaces the "heads" argument of unbundle."""
1259 1260 h = inpart.read(20)
1260 1261 heads = []
1261 1262 while len(h) == 20:
1262 1263 heads.append(h)
1263 1264 h = inpart.read(20)
1264 1265 assert not h
1265 1266 if heads != op.repo.heads():
1266 1267 raise error.PushRaced('repository changed while pushing - '
1267 1268 'please try again')
1268 1269
1269 1270 @parthandler('output')
1270 1271 def handleoutput(op, inpart):
1271 1272 """forward output captured on the server to the client"""
1272 1273 for line in inpart.read().splitlines():
1273 1274 op.ui.status(('remote: %s\n' % line))
1274 1275
1275 1276 @parthandler('replycaps')
1276 1277 def handlereplycaps(op, inpart):
1277 1278 """Notify that a reply bundle should be created
1278 1279
1279 1280 The payload contains the capabilities information for the reply"""
1280 1281 caps = decodecaps(inpart.read())
1281 1282 if op.reply is None:
1282 1283 op.reply = bundle20(op.ui, caps)
1283 1284
1284 1285 @parthandler('error:abort', ('message', 'hint'))
1285 1286 def handleerrorabort(op, inpart):
1286 1287 """Used to transmit abort error over the wire"""
1287 1288 raise util.Abort(inpart.params['message'], hint=inpart.params.get('hint'))
1288 1289
1289 1290 @parthandler('error:unsupportedcontent', ('parttype', 'params'))
1290 1291 def handleerrorunsupportedcontent(op, inpart):
1291 1292 """Used to transmit unknown content error over the wire"""
1292 1293 kwargs = {}
1293 1294 parttype = inpart.params.get('parttype')
1294 1295 if parttype is not None:
1295 1296 kwargs['parttype'] = parttype
1296 1297 params = inpart.params.get('params')
1297 1298 if params is not None:
1298 1299 kwargs['params'] = params.split('\0')
1299 1300
1300 1301 raise error.UnsupportedPartError(**kwargs)
1301 1302
1302 1303 @parthandler('error:pushraced', ('message',))
1303 1304 def handleerrorpushraced(op, inpart):
1304 1305 """Used to transmit push race error over the wire"""
1305 1306 raise error.ResponseError(_('push failed:'), inpart.params['message'])
1306 1307
1307 1308 @parthandler('listkeys', ('namespace',))
1308 1309 def handlelistkeys(op, inpart):
1309 1310 """retrieve pushkey namespace content stored in a bundle2"""
1310 1311 namespace = inpart.params['namespace']
1311 1312 r = pushkey.decodekeys(inpart.read())
1312 1313 op.records.add('listkeys', (namespace, r))
1313 1314
1314 1315 @parthandler('pushkey', ('namespace', 'key', 'old', 'new'))
1315 1316 def handlepushkey(op, inpart):
1316 1317 """process a pushkey request"""
1317 1318 dec = pushkey.decode
1318 1319 namespace = dec(inpart.params['namespace'])
1319 1320 key = dec(inpart.params['key'])
1320 1321 old = dec(inpart.params['old'])
1321 1322 new = dec(inpart.params['new'])
1322 1323 ret = op.repo.pushkey(namespace, key, old, new)
1323 1324 record = {'namespace': namespace,
1324 1325 'key': key,
1325 1326 'old': old,
1326 1327 'new': new}
1327 1328 op.records.add('pushkey', record)
1328 1329 if op.reply is not None:
1329 1330 rpart = op.reply.newpart('reply:pushkey')
1330 1331 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1331 1332 rpart.addparam('return', '%i' % ret, mandatory=False)
1332 1333 if inpart.mandatory and not ret:
1333 1334 kwargs = {}
1334 1335 for key in ('namespace', 'key', 'new', 'old', 'ret'):
1335 1336 if key in inpart.params:
1336 1337 kwargs[key] = inpart.params[key]
1337 1338 raise error.PushkeyFailed(partid=str(inpart.id), **kwargs)
1338 1339
1339 1340 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1340 1341 def handlepushkeyreply(op, inpart):
1341 1342 """retrieve the result of a pushkey request"""
1342 1343 ret = int(inpart.params['return'])
1343 1344 partid = int(inpart.params['in-reply-to'])
1344 1345 op.records.add('pushkey', {'return': ret}, partid)
1345 1346
1346 1347 @parthandler('obsmarkers')
1347 1348 def handleobsmarker(op, inpart):
1348 1349 """add a stream of obsmarkers to the repo"""
1349 1350 tr = op.gettransaction()
1350 1351 markerdata = inpart.read()
1351 1352 if op.ui.config('experimental', 'obsmarkers-exchange-debug', False):
1352 1353 op.ui.write(('obsmarker-exchange: %i bytes received\n')
1353 1354 % len(markerdata))
1354 1355 new = op.repo.obsstore.mergemarkers(tr, markerdata)
1355 1356 if new:
1356 1357 op.repo.ui.status(_('%i new obsolescence markers\n') % new)
1357 1358 op.records.add('obsmarkers', {'new': new})
1358 1359 if op.reply is not None:
1359 1360 rpart = op.reply.newpart('reply:obsmarkers')
1360 1361 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1361 1362 rpart.addparam('new', '%i' % new, mandatory=False)
1362 1363
1363 1364
1364 1365 @parthandler('reply:obsmarkers', ('new', 'in-reply-to'))
1365 1366 def handlepushkeyreply(op, inpart):
1366 1367 """retrieve the result of a pushkey request"""
1367 1368 ret = int(inpart.params['new'])
1368 1369 partid = int(inpart.params['in-reply-to'])
1369 1370 op.records.add('obsmarkers', {'new': ret}, partid)
1370 1371
1371 1372 @parthandler('hgtagsfnodes')
1372 1373 def handlehgtagsfnodes(op, inpart):
1373 1374 """Applies .hgtags fnodes cache entries to the local repo.
1374 1375
1375 1376 Payload is pairs of 20 byte changeset nodes and filenodes.
1376 1377 """
1377 1378 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
1378 1379
1379 1380 count = 0
1380 1381 while True:
1381 1382 node = inpart.read(20)
1382 1383 fnode = inpart.read(20)
1383 1384 if len(node) < 20 or len(fnode) < 20:
1384 1385 op.ui.debug('received incomplete .hgtags fnodes data, ignoring\n')
1385 1386 break
1386 1387 cache.setfnode(node, fnode)
1387 1388 count += 1
1388 1389
1389 1390 cache.write()
1390 1391 op.ui.debug('applied %i hgtags fnodes cache entries\n' % count)
@@ -1,2166 +1,2166 b''
1 1 > do_push()
2 2 > {
3 3 > user=$1
4 4 > shift
5 5 > echo "Pushing as user $user"
6 6 > echo 'hgrc = """'
7 7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
8 8 > echo '"""'
9 9 > if test -f acl.config; then
10 10 > echo 'acl.config = """'
11 11 > cat acl.config
12 12 > echo '"""'
13 13 > fi
14 14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 15 > # LOGNAME=$user hg --cws a --debug push ../b
16 16 > # fails with "This variable is read only."
17 17 > # Use env to work around this.
18 18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 19 > hg --cwd b rollback
20 20 > hg --cwd b --quiet tip
21 21 > echo
22 22 > }
23 23
24 24 > init_config()
25 25 > {
26 26 > cat > fakegroups.py <<EOF
27 27 > from hgext import acl
28 28 > def fakegetusers(ui, group):
29 29 > try:
30 30 > return acl._getusersorig(ui, group)
31 31 > except:
32 32 > return ["fred", "betty"]
33 33 > acl._getusersorig = acl._getusers
34 34 > acl._getusers = fakegetusers
35 35 > EOF
36 36 > rm -f acl.config
37 37 > cat > $config <<EOF
38 38 > [hooks]
39 39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 40 > [acl]
41 41 > sources = push
42 42 > [extensions]
43 43 > f=`pwd`/fakegroups.py
44 44 > EOF
45 45 > }
46 46
47 47 $ cat << EOF >> $HGRCPATH
48 48 > [experimental]
49 49 > # drop me once bundle2 is the default,
50 50 > # added to get test change early.
51 51 > bundle2-exp = True
52 52 > EOF
53 53
54 54 $ hg init a
55 55 $ cd a
56 56 $ mkdir foo foo/Bar quux
57 57 $ echo 'in foo' > foo/file.txt
58 58 $ echo 'in foo/Bar' > foo/Bar/file.txt
59 59 $ echo 'in quux' > quux/file.py
60 60 $ hg add -q
61 61 $ hg ci -m 'add files' -d '1000000 0'
62 62 $ echo >> foo/file.txt
63 63 $ hg ci -m 'change foo/file' -d '1000001 0'
64 64 $ echo >> foo/Bar/file.txt
65 65 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
66 66 $ echo >> quux/file.py
67 67 $ hg ci -m 'change quux/file' -d '1000003 0'
68 68 $ hg tip --quiet
69 69 3:911600dab2ae
70 70
71 71 $ cd ..
72 72 $ hg clone -r 0 a b
73 73 adding changesets
74 74 adding manifests
75 75 adding file changes
76 76 added 1 changesets with 3 changes to 3 files
77 77 updating to branch default
78 78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 79
80 80 $ config=b/.hg/hgrc
81 81
82 82 Extension disabled for lack of a hook
83 83
84 84 $ do_push fred
85 85 Pushing as user fred
86 86 hgrc = """
87 87 """
88 88 pushing to ../b
89 89 query 1; heads
90 90 searching for changes
91 91 all remote heads known locally
92 92 listing keys for "phases"
93 93 checking for updated bookmarks
94 94 listing keys for "bookmarks"
95 95 listing keys for "bookmarks"
96 96 3 changesets found
97 97 list of changesets:
98 98 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
99 99 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
100 100 911600dab2ae7a9baff75958b84fe606851ce955
101 101 bundle2-output-bundle: "HG20", 4 parts total
102 bundle2-output-part: "replycaps" 106 bytes payload
102 bundle2-output-part: "replycaps" 147 bytes payload
103 103 bundle2-output-part: "check:heads" streamed payload
104 104 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
105 105 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
106 106 bundle2-input-bundle: with-transaction
107 107 bundle2-input-part: "replycaps" supported
108 bundle2-input-part: total payload size 106
108 bundle2-input-part: total payload size 147
109 109 bundle2-input-part: "check:heads" supported
110 110 bundle2-input-part: total payload size 20
111 111 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
112 112 adding changesets
113 113 add changeset ef1ea85a6374
114 114 add changeset f9cafe1212c8
115 115 add changeset 911600dab2ae
116 116 adding manifests
117 117 adding file changes
118 118 adding foo/Bar/file.txt revisions
119 119 adding foo/file.txt revisions
120 120 adding quux/file.py revisions
121 121 added 3 changesets with 3 changes to 3 files
122 122 bundle2-input-part: total payload size 1606
123 123 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
124 124 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
125 125 bundle2-input-bundle: 3 parts total
126 126 updating the branch cache
127 127 bundle2-output-bundle: "HG20", 2 parts total
128 128 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
129 129 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
130 130 bundle2-input-bundle: with-transaction
131 131 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
132 132 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
133 133 bundle2-input-bundle: 1 parts total
134 134 listing keys for "phases"
135 135 try to push obsolete markers to remote
136 136 repository tip rolled back to revision 0 (undo push)
137 137 0:6675d58eff77
138 138
139 139
140 140 $ echo '[hooks]' >> $config
141 141 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
142 142
143 143 Extension disabled for lack of acl.sources
144 144
145 145 $ do_push fred
146 146 Pushing as user fred
147 147 hgrc = """
148 148 [hooks]
149 149 pretxnchangegroup.acl = python:hgext.acl.hook
150 150 """
151 151 pushing to ../b
152 152 query 1; heads
153 153 searching for changes
154 154 all remote heads known locally
155 155 listing keys for "phases"
156 156 checking for updated bookmarks
157 157 listing keys for "bookmarks"
158 158 invalid branchheads cache (served): tip differs
159 159 listing keys for "bookmarks"
160 160 3 changesets found
161 161 list of changesets:
162 162 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
163 163 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
164 164 911600dab2ae7a9baff75958b84fe606851ce955
165 165 bundle2-output-bundle: "HG20", 4 parts total
166 bundle2-output-part: "replycaps" 106 bytes payload
166 bundle2-output-part: "replycaps" 147 bytes payload
167 167 bundle2-output-part: "check:heads" streamed payload
168 168 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
169 169 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
170 170 bundle2-input-bundle: with-transaction
171 171 bundle2-input-part: "replycaps" supported
172 bundle2-input-part: total payload size 106
172 bundle2-input-part: total payload size 147
173 173 bundle2-input-part: "check:heads" supported
174 174 bundle2-input-part: total payload size 20
175 175 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
176 176 adding changesets
177 177 add changeset ef1ea85a6374
178 178 add changeset f9cafe1212c8
179 179 add changeset 911600dab2ae
180 180 adding manifests
181 181 adding file changes
182 182 adding foo/Bar/file.txt revisions
183 183 adding foo/file.txt revisions
184 184 adding quux/file.py revisions
185 185 added 3 changesets with 3 changes to 3 files
186 186 calling hook pretxnchangegroup.acl: hgext.acl.hook
187 187 acl: changes have source "push" - skipping
188 188 bundle2-input-part: total payload size 1606
189 189 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
190 190 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
191 191 bundle2-input-bundle: 3 parts total
192 192 updating the branch cache
193 193 bundle2-output-bundle: "HG20", 2 parts total
194 194 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
195 195 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
196 196 bundle2-input-bundle: with-transaction
197 197 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
198 198 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
199 199 bundle2-input-bundle: 1 parts total
200 200 listing keys for "phases"
201 201 try to push obsolete markers to remote
202 202 repository tip rolled back to revision 0 (undo push)
203 203 0:6675d58eff77
204 204
205 205
206 206 No [acl.allow]/[acl.deny]
207 207
208 208 $ echo '[acl]' >> $config
209 209 $ echo 'sources = push' >> $config
210 210 $ do_push fred
211 211 Pushing as user fred
212 212 hgrc = """
213 213 [hooks]
214 214 pretxnchangegroup.acl = python:hgext.acl.hook
215 215 [acl]
216 216 sources = push
217 217 """
218 218 pushing to ../b
219 219 query 1; heads
220 220 searching for changes
221 221 all remote heads known locally
222 222 listing keys for "phases"
223 223 checking for updated bookmarks
224 224 listing keys for "bookmarks"
225 225 invalid branchheads cache (served): tip differs
226 226 listing keys for "bookmarks"
227 227 3 changesets found
228 228 list of changesets:
229 229 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
230 230 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
231 231 911600dab2ae7a9baff75958b84fe606851ce955
232 232 bundle2-output-bundle: "HG20", 4 parts total
233 bundle2-output-part: "replycaps" 106 bytes payload
233 bundle2-output-part: "replycaps" 147 bytes payload
234 234 bundle2-output-part: "check:heads" streamed payload
235 235 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
236 236 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
237 237 bundle2-input-bundle: with-transaction
238 238 bundle2-input-part: "replycaps" supported
239 bundle2-input-part: total payload size 106
239 bundle2-input-part: total payload size 147
240 240 bundle2-input-part: "check:heads" supported
241 241 bundle2-input-part: total payload size 20
242 242 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
243 243 adding changesets
244 244 add changeset ef1ea85a6374
245 245 add changeset f9cafe1212c8
246 246 add changeset 911600dab2ae
247 247 adding manifests
248 248 adding file changes
249 249 adding foo/Bar/file.txt revisions
250 250 adding foo/file.txt revisions
251 251 adding quux/file.py revisions
252 252 added 3 changesets with 3 changes to 3 files
253 253 calling hook pretxnchangegroup.acl: hgext.acl.hook
254 254 acl: checking access for user "fred"
255 255 acl: acl.allow.branches not enabled
256 256 acl: acl.deny.branches not enabled
257 257 acl: acl.allow not enabled
258 258 acl: acl.deny not enabled
259 259 acl: branch access granted: "ef1ea85a6374" on branch "default"
260 260 acl: path access granted: "ef1ea85a6374"
261 261 acl: branch access granted: "f9cafe1212c8" on branch "default"
262 262 acl: path access granted: "f9cafe1212c8"
263 263 acl: branch access granted: "911600dab2ae" on branch "default"
264 264 acl: path access granted: "911600dab2ae"
265 265 bundle2-input-part: total payload size 1606
266 266 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
267 267 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
268 268 bundle2-input-bundle: 3 parts total
269 269 updating the branch cache
270 270 bundle2-output-bundle: "HG20", 2 parts total
271 271 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
272 272 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
273 273 bundle2-input-bundle: with-transaction
274 274 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
275 275 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
276 276 bundle2-input-bundle: 1 parts total
277 277 listing keys for "phases"
278 278 try to push obsolete markers to remote
279 279 repository tip rolled back to revision 0 (undo push)
280 280 0:6675d58eff77
281 281
282 282
283 283 Empty [acl.allow]
284 284
285 285 $ echo '[acl.allow]' >> $config
286 286 $ do_push fred
287 287 Pushing as user fred
288 288 hgrc = """
289 289 [hooks]
290 290 pretxnchangegroup.acl = python:hgext.acl.hook
291 291 [acl]
292 292 sources = push
293 293 [acl.allow]
294 294 """
295 295 pushing to ../b
296 296 query 1; heads
297 297 searching for changes
298 298 all remote heads known locally
299 299 listing keys for "phases"
300 300 checking for updated bookmarks
301 301 listing keys for "bookmarks"
302 302 invalid branchheads cache (served): tip differs
303 303 listing keys for "bookmarks"
304 304 3 changesets found
305 305 list of changesets:
306 306 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
307 307 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
308 308 911600dab2ae7a9baff75958b84fe606851ce955
309 309 bundle2-output-bundle: "HG20", 4 parts total
310 bundle2-output-part: "replycaps" 106 bytes payload
310 bundle2-output-part: "replycaps" 147 bytes payload
311 311 bundle2-output-part: "check:heads" streamed payload
312 312 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
313 313 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
314 314 bundle2-input-bundle: with-transaction
315 315 bundle2-input-part: "replycaps" supported
316 bundle2-input-part: total payload size 106
316 bundle2-input-part: total payload size 147
317 317 bundle2-input-part: "check:heads" supported
318 318 bundle2-input-part: total payload size 20
319 319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
320 320 adding changesets
321 321 add changeset ef1ea85a6374
322 322 add changeset f9cafe1212c8
323 323 add changeset 911600dab2ae
324 324 adding manifests
325 325 adding file changes
326 326 adding foo/Bar/file.txt revisions
327 327 adding foo/file.txt revisions
328 328 adding quux/file.py revisions
329 329 added 3 changesets with 3 changes to 3 files
330 330 calling hook pretxnchangegroup.acl: hgext.acl.hook
331 331 acl: checking access for user "fred"
332 332 acl: acl.allow.branches not enabled
333 333 acl: acl.deny.branches not enabled
334 334 acl: acl.allow enabled, 0 entries for user fred
335 335 acl: acl.deny not enabled
336 336 acl: branch access granted: "ef1ea85a6374" on branch "default"
337 337 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
338 338 bundle2-input-part: total payload size 1606
339 339 bundle2-input-bundle: 3 parts total
340 340 transaction abort!
341 341 rollback completed
342 342 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
343 343 no rollback information available
344 344 0:6675d58eff77
345 345
346 346
347 347 fred is allowed inside foo/
348 348
349 349 $ echo 'foo/** = fred' >> $config
350 350 $ do_push fred
351 351 Pushing as user fred
352 352 hgrc = """
353 353 [hooks]
354 354 pretxnchangegroup.acl = python:hgext.acl.hook
355 355 [acl]
356 356 sources = push
357 357 [acl.allow]
358 358 foo/** = fred
359 359 """
360 360 pushing to ../b
361 361 query 1; heads
362 362 searching for changes
363 363 all remote heads known locally
364 364 listing keys for "phases"
365 365 checking for updated bookmarks
366 366 listing keys for "bookmarks"
367 367 invalid branchheads cache (served): tip differs
368 368 listing keys for "bookmarks"
369 369 3 changesets found
370 370 list of changesets:
371 371 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
372 372 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
373 373 911600dab2ae7a9baff75958b84fe606851ce955
374 374 bundle2-output-bundle: "HG20", 4 parts total
375 bundle2-output-part: "replycaps" 106 bytes payload
375 bundle2-output-part: "replycaps" 147 bytes payload
376 376 bundle2-output-part: "check:heads" streamed payload
377 377 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
378 378 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
379 379 bundle2-input-bundle: with-transaction
380 380 bundle2-input-part: "replycaps" supported
381 bundle2-input-part: total payload size 106
381 bundle2-input-part: total payload size 147
382 382 bundle2-input-part: "check:heads" supported
383 383 bundle2-input-part: total payload size 20
384 384 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
385 385 adding changesets
386 386 add changeset ef1ea85a6374
387 387 add changeset f9cafe1212c8
388 388 add changeset 911600dab2ae
389 389 adding manifests
390 390 adding file changes
391 391 adding foo/Bar/file.txt revisions
392 392 adding foo/file.txt revisions
393 393 adding quux/file.py revisions
394 394 added 3 changesets with 3 changes to 3 files
395 395 calling hook pretxnchangegroup.acl: hgext.acl.hook
396 396 acl: checking access for user "fred"
397 397 acl: acl.allow.branches not enabled
398 398 acl: acl.deny.branches not enabled
399 399 acl: acl.allow enabled, 1 entries for user fred
400 400 acl: acl.deny not enabled
401 401 acl: branch access granted: "ef1ea85a6374" on branch "default"
402 402 acl: path access granted: "ef1ea85a6374"
403 403 acl: branch access granted: "f9cafe1212c8" on branch "default"
404 404 acl: path access granted: "f9cafe1212c8"
405 405 acl: branch access granted: "911600dab2ae" on branch "default"
406 406 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
407 407 bundle2-input-part: total payload size 1606
408 408 bundle2-input-bundle: 3 parts total
409 409 transaction abort!
410 410 rollback completed
411 411 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
412 412 no rollback information available
413 413 0:6675d58eff77
414 414
415 415
416 416 Empty [acl.deny]
417 417
418 418 $ echo '[acl.deny]' >> $config
419 419 $ do_push barney
420 420 Pushing as user barney
421 421 hgrc = """
422 422 [hooks]
423 423 pretxnchangegroup.acl = python:hgext.acl.hook
424 424 [acl]
425 425 sources = push
426 426 [acl.allow]
427 427 foo/** = fred
428 428 [acl.deny]
429 429 """
430 430 pushing to ../b
431 431 query 1; heads
432 432 searching for changes
433 433 all remote heads known locally
434 434 listing keys for "phases"
435 435 checking for updated bookmarks
436 436 listing keys for "bookmarks"
437 437 invalid branchheads cache (served): tip differs
438 438 listing keys for "bookmarks"
439 439 3 changesets found
440 440 list of changesets:
441 441 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
442 442 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
443 443 911600dab2ae7a9baff75958b84fe606851ce955
444 444 bundle2-output-bundle: "HG20", 4 parts total
445 bundle2-output-part: "replycaps" 106 bytes payload
445 bundle2-output-part: "replycaps" 147 bytes payload
446 446 bundle2-output-part: "check:heads" streamed payload
447 447 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
448 448 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
449 449 bundle2-input-bundle: with-transaction
450 450 bundle2-input-part: "replycaps" supported
451 bundle2-input-part: total payload size 106
451 bundle2-input-part: total payload size 147
452 452 bundle2-input-part: "check:heads" supported
453 453 bundle2-input-part: total payload size 20
454 454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
455 455 adding changesets
456 456 add changeset ef1ea85a6374
457 457 add changeset f9cafe1212c8
458 458 add changeset 911600dab2ae
459 459 adding manifests
460 460 adding file changes
461 461 adding foo/Bar/file.txt revisions
462 462 adding foo/file.txt revisions
463 463 adding quux/file.py revisions
464 464 added 3 changesets with 3 changes to 3 files
465 465 calling hook pretxnchangegroup.acl: hgext.acl.hook
466 466 acl: checking access for user "barney"
467 467 acl: acl.allow.branches not enabled
468 468 acl: acl.deny.branches not enabled
469 469 acl: acl.allow enabled, 0 entries for user barney
470 470 acl: acl.deny enabled, 0 entries for user barney
471 471 acl: branch access granted: "ef1ea85a6374" on branch "default"
472 472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
473 473 bundle2-input-part: total payload size 1606
474 474 bundle2-input-bundle: 3 parts total
475 475 transaction abort!
476 476 rollback completed
477 477 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
478 478 no rollback information available
479 479 0:6675d58eff77
480 480
481 481
482 482 fred is allowed inside foo/, but not foo/bar/ (case matters)
483 483
484 484 $ echo 'foo/bar/** = fred' >> $config
485 485 $ do_push fred
486 486 Pushing as user fred
487 487 hgrc = """
488 488 [hooks]
489 489 pretxnchangegroup.acl = python:hgext.acl.hook
490 490 [acl]
491 491 sources = push
492 492 [acl.allow]
493 493 foo/** = fred
494 494 [acl.deny]
495 495 foo/bar/** = fred
496 496 """
497 497 pushing to ../b
498 498 query 1; heads
499 499 searching for changes
500 500 all remote heads known locally
501 501 listing keys for "phases"
502 502 checking for updated bookmarks
503 503 listing keys for "bookmarks"
504 504 invalid branchheads cache (served): tip differs
505 505 listing keys for "bookmarks"
506 506 3 changesets found
507 507 list of changesets:
508 508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
509 509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
510 510 911600dab2ae7a9baff75958b84fe606851ce955
511 511 bundle2-output-bundle: "HG20", 4 parts total
512 bundle2-output-part: "replycaps" 106 bytes payload
512 bundle2-output-part: "replycaps" 147 bytes payload
513 513 bundle2-output-part: "check:heads" streamed payload
514 514 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
515 515 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
516 516 bundle2-input-bundle: with-transaction
517 517 bundle2-input-part: "replycaps" supported
518 bundle2-input-part: total payload size 106
518 bundle2-input-part: total payload size 147
519 519 bundle2-input-part: "check:heads" supported
520 520 bundle2-input-part: total payload size 20
521 521 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
522 522 adding changesets
523 523 add changeset ef1ea85a6374
524 524 add changeset f9cafe1212c8
525 525 add changeset 911600dab2ae
526 526 adding manifests
527 527 adding file changes
528 528 adding foo/Bar/file.txt revisions
529 529 adding foo/file.txt revisions
530 530 adding quux/file.py revisions
531 531 added 3 changesets with 3 changes to 3 files
532 532 calling hook pretxnchangegroup.acl: hgext.acl.hook
533 533 acl: checking access for user "fred"
534 534 acl: acl.allow.branches not enabled
535 535 acl: acl.deny.branches not enabled
536 536 acl: acl.allow enabled, 1 entries for user fred
537 537 acl: acl.deny enabled, 1 entries for user fred
538 538 acl: branch access granted: "ef1ea85a6374" on branch "default"
539 539 acl: path access granted: "ef1ea85a6374"
540 540 acl: branch access granted: "f9cafe1212c8" on branch "default"
541 541 acl: path access granted: "f9cafe1212c8"
542 542 acl: branch access granted: "911600dab2ae" on branch "default"
543 543 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
544 544 bundle2-input-part: total payload size 1606
545 545 bundle2-input-bundle: 3 parts total
546 546 transaction abort!
547 547 rollback completed
548 548 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
549 549 no rollback information available
550 550 0:6675d58eff77
551 551
552 552
553 553 fred is allowed inside foo/, but not foo/Bar/
554 554
555 555 $ echo 'foo/Bar/** = fred' >> $config
556 556 $ do_push fred
557 557 Pushing as user fred
558 558 hgrc = """
559 559 [hooks]
560 560 pretxnchangegroup.acl = python:hgext.acl.hook
561 561 [acl]
562 562 sources = push
563 563 [acl.allow]
564 564 foo/** = fred
565 565 [acl.deny]
566 566 foo/bar/** = fred
567 567 foo/Bar/** = fred
568 568 """
569 569 pushing to ../b
570 570 query 1; heads
571 571 searching for changes
572 572 all remote heads known locally
573 573 listing keys for "phases"
574 574 checking for updated bookmarks
575 575 listing keys for "bookmarks"
576 576 invalid branchheads cache (served): tip differs
577 577 listing keys for "bookmarks"
578 578 3 changesets found
579 579 list of changesets:
580 580 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
581 581 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
582 582 911600dab2ae7a9baff75958b84fe606851ce955
583 583 bundle2-output-bundle: "HG20", 4 parts total
584 bundle2-output-part: "replycaps" 106 bytes payload
584 bundle2-output-part: "replycaps" 147 bytes payload
585 585 bundle2-output-part: "check:heads" streamed payload
586 586 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
587 587 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
588 588 bundle2-input-bundle: with-transaction
589 589 bundle2-input-part: "replycaps" supported
590 bundle2-input-part: total payload size 106
590 bundle2-input-part: total payload size 147
591 591 bundle2-input-part: "check:heads" supported
592 592 bundle2-input-part: total payload size 20
593 593 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
594 594 adding changesets
595 595 add changeset ef1ea85a6374
596 596 add changeset f9cafe1212c8
597 597 add changeset 911600dab2ae
598 598 adding manifests
599 599 adding file changes
600 600 adding foo/Bar/file.txt revisions
601 601 adding foo/file.txt revisions
602 602 adding quux/file.py revisions
603 603 added 3 changesets with 3 changes to 3 files
604 604 calling hook pretxnchangegroup.acl: hgext.acl.hook
605 605 acl: checking access for user "fred"
606 606 acl: acl.allow.branches not enabled
607 607 acl: acl.deny.branches not enabled
608 608 acl: acl.allow enabled, 1 entries for user fred
609 609 acl: acl.deny enabled, 2 entries for user fred
610 610 acl: branch access granted: "ef1ea85a6374" on branch "default"
611 611 acl: path access granted: "ef1ea85a6374"
612 612 acl: branch access granted: "f9cafe1212c8" on branch "default"
613 613 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
614 614 bundle2-input-part: total payload size 1606
615 615 bundle2-input-bundle: 3 parts total
616 616 transaction abort!
617 617 rollback completed
618 618 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
619 619 no rollback information available
620 620 0:6675d58eff77
621 621
622 622
623 623 $ echo 'barney is not mentioned => not allowed anywhere'
624 624 barney is not mentioned => not allowed anywhere
625 625 $ do_push barney
626 626 Pushing as user barney
627 627 hgrc = """
628 628 [hooks]
629 629 pretxnchangegroup.acl = python:hgext.acl.hook
630 630 [acl]
631 631 sources = push
632 632 [acl.allow]
633 633 foo/** = fred
634 634 [acl.deny]
635 635 foo/bar/** = fred
636 636 foo/Bar/** = fred
637 637 """
638 638 pushing to ../b
639 639 query 1; heads
640 640 searching for changes
641 641 all remote heads known locally
642 642 listing keys for "phases"
643 643 checking for updated bookmarks
644 644 listing keys for "bookmarks"
645 645 invalid branchheads cache (served): tip differs
646 646 listing keys for "bookmarks"
647 647 3 changesets found
648 648 list of changesets:
649 649 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
650 650 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
651 651 911600dab2ae7a9baff75958b84fe606851ce955
652 652 bundle2-output-bundle: "HG20", 4 parts total
653 bundle2-output-part: "replycaps" 106 bytes payload
653 bundle2-output-part: "replycaps" 147 bytes payload
654 654 bundle2-output-part: "check:heads" streamed payload
655 655 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
656 656 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
657 657 bundle2-input-bundle: with-transaction
658 658 bundle2-input-part: "replycaps" supported
659 bundle2-input-part: total payload size 106
659 bundle2-input-part: total payload size 147
660 660 bundle2-input-part: "check:heads" supported
661 661 bundle2-input-part: total payload size 20
662 662 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
663 663 adding changesets
664 664 add changeset ef1ea85a6374
665 665 add changeset f9cafe1212c8
666 666 add changeset 911600dab2ae
667 667 adding manifests
668 668 adding file changes
669 669 adding foo/Bar/file.txt revisions
670 670 adding foo/file.txt revisions
671 671 adding quux/file.py revisions
672 672 added 3 changesets with 3 changes to 3 files
673 673 calling hook pretxnchangegroup.acl: hgext.acl.hook
674 674 acl: checking access for user "barney"
675 675 acl: acl.allow.branches not enabled
676 676 acl: acl.deny.branches not enabled
677 677 acl: acl.allow enabled, 0 entries for user barney
678 678 acl: acl.deny enabled, 0 entries for user barney
679 679 acl: branch access granted: "ef1ea85a6374" on branch "default"
680 680 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
681 681 bundle2-input-part: total payload size 1606
682 682 bundle2-input-bundle: 3 parts total
683 683 transaction abort!
684 684 rollback completed
685 685 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
686 686 no rollback information available
687 687 0:6675d58eff77
688 688
689 689
690 690 barney is allowed everywhere
691 691
692 692 $ echo '[acl.allow]' >> $config
693 693 $ echo '** = barney' >> $config
694 694 $ do_push barney
695 695 Pushing as user barney
696 696 hgrc = """
697 697 [hooks]
698 698 pretxnchangegroup.acl = python:hgext.acl.hook
699 699 [acl]
700 700 sources = push
701 701 [acl.allow]
702 702 foo/** = fred
703 703 [acl.deny]
704 704 foo/bar/** = fred
705 705 foo/Bar/** = fred
706 706 [acl.allow]
707 707 ** = barney
708 708 """
709 709 pushing to ../b
710 710 query 1; heads
711 711 searching for changes
712 712 all remote heads known locally
713 713 listing keys for "phases"
714 714 checking for updated bookmarks
715 715 listing keys for "bookmarks"
716 716 invalid branchheads cache (served): tip differs
717 717 listing keys for "bookmarks"
718 718 3 changesets found
719 719 list of changesets:
720 720 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
721 721 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
722 722 911600dab2ae7a9baff75958b84fe606851ce955
723 723 bundle2-output-bundle: "HG20", 4 parts total
724 bundle2-output-part: "replycaps" 106 bytes payload
724 bundle2-output-part: "replycaps" 147 bytes payload
725 725 bundle2-output-part: "check:heads" streamed payload
726 726 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
727 727 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
728 728 bundle2-input-bundle: with-transaction
729 729 bundle2-input-part: "replycaps" supported
730 bundle2-input-part: total payload size 106
730 bundle2-input-part: total payload size 147
731 731 bundle2-input-part: "check:heads" supported
732 732 bundle2-input-part: total payload size 20
733 733 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
734 734 adding changesets
735 735 add changeset ef1ea85a6374
736 736 add changeset f9cafe1212c8
737 737 add changeset 911600dab2ae
738 738 adding manifests
739 739 adding file changes
740 740 adding foo/Bar/file.txt revisions
741 741 adding foo/file.txt revisions
742 742 adding quux/file.py revisions
743 743 added 3 changesets with 3 changes to 3 files
744 744 calling hook pretxnchangegroup.acl: hgext.acl.hook
745 745 acl: checking access for user "barney"
746 746 acl: acl.allow.branches not enabled
747 747 acl: acl.deny.branches not enabled
748 748 acl: acl.allow enabled, 1 entries for user barney
749 749 acl: acl.deny enabled, 0 entries for user barney
750 750 acl: branch access granted: "ef1ea85a6374" on branch "default"
751 751 acl: path access granted: "ef1ea85a6374"
752 752 acl: branch access granted: "f9cafe1212c8" on branch "default"
753 753 acl: path access granted: "f9cafe1212c8"
754 754 acl: branch access granted: "911600dab2ae" on branch "default"
755 755 acl: path access granted: "911600dab2ae"
756 756 bundle2-input-part: total payload size 1606
757 757 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
758 758 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
759 759 bundle2-input-bundle: 3 parts total
760 760 updating the branch cache
761 761 bundle2-output-bundle: "HG20", 2 parts total
762 762 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
763 763 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
764 764 bundle2-input-bundle: with-transaction
765 765 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
766 766 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
767 767 bundle2-input-bundle: 1 parts total
768 768 listing keys for "phases"
769 769 try to push obsolete markers to remote
770 770 repository tip rolled back to revision 0 (undo push)
771 771 0:6675d58eff77
772 772
773 773
774 774 wilma can change files with a .txt extension
775 775
776 776 $ echo '**/*.txt = wilma' >> $config
777 777 $ do_push wilma
778 778 Pushing as user wilma
779 779 hgrc = """
780 780 [hooks]
781 781 pretxnchangegroup.acl = python:hgext.acl.hook
782 782 [acl]
783 783 sources = push
784 784 [acl.allow]
785 785 foo/** = fred
786 786 [acl.deny]
787 787 foo/bar/** = fred
788 788 foo/Bar/** = fred
789 789 [acl.allow]
790 790 ** = barney
791 791 **/*.txt = wilma
792 792 """
793 793 pushing to ../b
794 794 query 1; heads
795 795 searching for changes
796 796 all remote heads known locally
797 797 listing keys for "phases"
798 798 checking for updated bookmarks
799 799 listing keys for "bookmarks"
800 800 invalid branchheads cache (served): tip differs
801 801 listing keys for "bookmarks"
802 802 3 changesets found
803 803 list of changesets:
804 804 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
805 805 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
806 806 911600dab2ae7a9baff75958b84fe606851ce955
807 807 bundle2-output-bundle: "HG20", 4 parts total
808 bundle2-output-part: "replycaps" 106 bytes payload
808 bundle2-output-part: "replycaps" 147 bytes payload
809 809 bundle2-output-part: "check:heads" streamed payload
810 810 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
811 811 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
812 812 bundle2-input-bundle: with-transaction
813 813 bundle2-input-part: "replycaps" supported
814 bundle2-input-part: total payload size 106
814 bundle2-input-part: total payload size 147
815 815 bundle2-input-part: "check:heads" supported
816 816 bundle2-input-part: total payload size 20
817 817 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
818 818 adding changesets
819 819 add changeset ef1ea85a6374
820 820 add changeset f9cafe1212c8
821 821 add changeset 911600dab2ae
822 822 adding manifests
823 823 adding file changes
824 824 adding foo/Bar/file.txt revisions
825 825 adding foo/file.txt revisions
826 826 adding quux/file.py revisions
827 827 added 3 changesets with 3 changes to 3 files
828 828 calling hook pretxnchangegroup.acl: hgext.acl.hook
829 829 acl: checking access for user "wilma"
830 830 acl: acl.allow.branches not enabled
831 831 acl: acl.deny.branches not enabled
832 832 acl: acl.allow enabled, 1 entries for user wilma
833 833 acl: acl.deny enabled, 0 entries for user wilma
834 834 acl: branch access granted: "ef1ea85a6374" on branch "default"
835 835 acl: path access granted: "ef1ea85a6374"
836 836 acl: branch access granted: "f9cafe1212c8" on branch "default"
837 837 acl: path access granted: "f9cafe1212c8"
838 838 acl: branch access granted: "911600dab2ae" on branch "default"
839 839 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
840 840 bundle2-input-part: total payload size 1606
841 841 bundle2-input-bundle: 3 parts total
842 842 transaction abort!
843 843 rollback completed
844 844 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
845 845 no rollback information available
846 846 0:6675d58eff77
847 847
848 848
849 849 file specified by acl.config does not exist
850 850
851 851 $ echo '[acl]' >> $config
852 852 $ echo 'config = ../acl.config' >> $config
853 853 $ do_push barney
854 854 Pushing as user barney
855 855 hgrc = """
856 856 [hooks]
857 857 pretxnchangegroup.acl = python:hgext.acl.hook
858 858 [acl]
859 859 sources = push
860 860 [acl.allow]
861 861 foo/** = fred
862 862 [acl.deny]
863 863 foo/bar/** = fred
864 864 foo/Bar/** = fred
865 865 [acl.allow]
866 866 ** = barney
867 867 **/*.txt = wilma
868 868 [acl]
869 869 config = ../acl.config
870 870 """
871 871 pushing to ../b
872 872 query 1; heads
873 873 searching for changes
874 874 all remote heads known locally
875 875 listing keys for "phases"
876 876 checking for updated bookmarks
877 877 listing keys for "bookmarks"
878 878 invalid branchheads cache (served): tip differs
879 879 listing keys for "bookmarks"
880 880 3 changesets found
881 881 list of changesets:
882 882 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
883 883 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
884 884 911600dab2ae7a9baff75958b84fe606851ce955
885 885 bundle2-output-bundle: "HG20", 4 parts total
886 bundle2-output-part: "replycaps" 106 bytes payload
886 bundle2-output-part: "replycaps" 147 bytes payload
887 887 bundle2-output-part: "check:heads" streamed payload
888 888 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
889 889 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
890 890 bundle2-input-bundle: with-transaction
891 891 bundle2-input-part: "replycaps" supported
892 bundle2-input-part: total payload size 106
892 bundle2-input-part: total payload size 147
893 893 bundle2-input-part: "check:heads" supported
894 894 bundle2-input-part: total payload size 20
895 895 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
896 896 adding changesets
897 897 add changeset ef1ea85a6374
898 898 add changeset f9cafe1212c8
899 899 add changeset 911600dab2ae
900 900 adding manifests
901 901 adding file changes
902 902 adding foo/Bar/file.txt revisions
903 903 adding foo/file.txt revisions
904 904 adding quux/file.py revisions
905 905 added 3 changesets with 3 changes to 3 files
906 906 calling hook pretxnchangegroup.acl: hgext.acl.hook
907 907 acl: checking access for user "barney"
908 908 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
909 909 bundle2-input-part: total payload size 1606
910 910 bundle2-input-bundle: 3 parts total
911 911 transaction abort!
912 912 rollback completed
913 913 abort: No such file or directory: ../acl.config
914 914 no rollback information available
915 915 0:6675d58eff77
916 916
917 917
918 918 betty is allowed inside foo/ by a acl.config file
919 919
920 920 $ echo '[acl.allow]' >> acl.config
921 921 $ echo 'foo/** = betty' >> acl.config
922 922 $ do_push betty
923 923 Pushing as user betty
924 924 hgrc = """
925 925 [hooks]
926 926 pretxnchangegroup.acl = python:hgext.acl.hook
927 927 [acl]
928 928 sources = push
929 929 [acl.allow]
930 930 foo/** = fred
931 931 [acl.deny]
932 932 foo/bar/** = fred
933 933 foo/Bar/** = fred
934 934 [acl.allow]
935 935 ** = barney
936 936 **/*.txt = wilma
937 937 [acl]
938 938 config = ../acl.config
939 939 """
940 940 acl.config = """
941 941 [acl.allow]
942 942 foo/** = betty
943 943 """
944 944 pushing to ../b
945 945 query 1; heads
946 946 searching for changes
947 947 all remote heads known locally
948 948 listing keys for "phases"
949 949 checking for updated bookmarks
950 950 listing keys for "bookmarks"
951 951 invalid branchheads cache (served): tip differs
952 952 listing keys for "bookmarks"
953 953 3 changesets found
954 954 list of changesets:
955 955 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
956 956 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
957 957 911600dab2ae7a9baff75958b84fe606851ce955
958 958 bundle2-output-bundle: "HG20", 4 parts total
959 bundle2-output-part: "replycaps" 106 bytes payload
959 bundle2-output-part: "replycaps" 147 bytes payload
960 960 bundle2-output-part: "check:heads" streamed payload
961 961 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
962 962 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
963 963 bundle2-input-bundle: with-transaction
964 964 bundle2-input-part: "replycaps" supported
965 bundle2-input-part: total payload size 106
965 bundle2-input-part: total payload size 147
966 966 bundle2-input-part: "check:heads" supported
967 967 bundle2-input-part: total payload size 20
968 968 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
969 969 adding changesets
970 970 add changeset ef1ea85a6374
971 971 add changeset f9cafe1212c8
972 972 add changeset 911600dab2ae
973 973 adding manifests
974 974 adding file changes
975 975 adding foo/Bar/file.txt revisions
976 976 adding foo/file.txt revisions
977 977 adding quux/file.py revisions
978 978 added 3 changesets with 3 changes to 3 files
979 979 calling hook pretxnchangegroup.acl: hgext.acl.hook
980 980 acl: checking access for user "betty"
981 981 acl: acl.allow.branches not enabled
982 982 acl: acl.deny.branches not enabled
983 983 acl: acl.allow enabled, 1 entries for user betty
984 984 acl: acl.deny enabled, 0 entries for user betty
985 985 acl: branch access granted: "ef1ea85a6374" on branch "default"
986 986 acl: path access granted: "ef1ea85a6374"
987 987 acl: branch access granted: "f9cafe1212c8" on branch "default"
988 988 acl: path access granted: "f9cafe1212c8"
989 989 acl: branch access granted: "911600dab2ae" on branch "default"
990 990 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
991 991 bundle2-input-part: total payload size 1606
992 992 bundle2-input-bundle: 3 parts total
993 993 transaction abort!
994 994 rollback completed
995 995 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
996 996 no rollback information available
997 997 0:6675d58eff77
998 998
999 999
1000 1000 acl.config can set only [acl.allow]/[acl.deny]
1001 1001
1002 1002 $ echo '[hooks]' >> acl.config
1003 1003 $ echo 'changegroup.acl = false' >> acl.config
1004 1004 $ do_push barney
1005 1005 Pushing as user barney
1006 1006 hgrc = """
1007 1007 [hooks]
1008 1008 pretxnchangegroup.acl = python:hgext.acl.hook
1009 1009 [acl]
1010 1010 sources = push
1011 1011 [acl.allow]
1012 1012 foo/** = fred
1013 1013 [acl.deny]
1014 1014 foo/bar/** = fred
1015 1015 foo/Bar/** = fred
1016 1016 [acl.allow]
1017 1017 ** = barney
1018 1018 **/*.txt = wilma
1019 1019 [acl]
1020 1020 config = ../acl.config
1021 1021 """
1022 1022 acl.config = """
1023 1023 [acl.allow]
1024 1024 foo/** = betty
1025 1025 [hooks]
1026 1026 changegroup.acl = false
1027 1027 """
1028 1028 pushing to ../b
1029 1029 query 1; heads
1030 1030 searching for changes
1031 1031 all remote heads known locally
1032 1032 listing keys for "phases"
1033 1033 checking for updated bookmarks
1034 1034 listing keys for "bookmarks"
1035 1035 invalid branchheads cache (served): tip differs
1036 1036 listing keys for "bookmarks"
1037 1037 3 changesets found
1038 1038 list of changesets:
1039 1039 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1040 1040 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1041 1041 911600dab2ae7a9baff75958b84fe606851ce955
1042 1042 bundle2-output-bundle: "HG20", 4 parts total
1043 bundle2-output-part: "replycaps" 106 bytes payload
1043 bundle2-output-part: "replycaps" 147 bytes payload
1044 1044 bundle2-output-part: "check:heads" streamed payload
1045 1045 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1046 1046 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1047 1047 bundle2-input-bundle: with-transaction
1048 1048 bundle2-input-part: "replycaps" supported
1049 bundle2-input-part: total payload size 106
1049 bundle2-input-part: total payload size 147
1050 1050 bundle2-input-part: "check:heads" supported
1051 1051 bundle2-input-part: total payload size 20
1052 1052 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1053 1053 adding changesets
1054 1054 add changeset ef1ea85a6374
1055 1055 add changeset f9cafe1212c8
1056 1056 add changeset 911600dab2ae
1057 1057 adding manifests
1058 1058 adding file changes
1059 1059 adding foo/Bar/file.txt revisions
1060 1060 adding foo/file.txt revisions
1061 1061 adding quux/file.py revisions
1062 1062 added 3 changesets with 3 changes to 3 files
1063 1063 calling hook pretxnchangegroup.acl: hgext.acl.hook
1064 1064 acl: checking access for user "barney"
1065 1065 acl: acl.allow.branches not enabled
1066 1066 acl: acl.deny.branches not enabled
1067 1067 acl: acl.allow enabled, 1 entries for user barney
1068 1068 acl: acl.deny enabled, 0 entries for user barney
1069 1069 acl: branch access granted: "ef1ea85a6374" on branch "default"
1070 1070 acl: path access granted: "ef1ea85a6374"
1071 1071 acl: branch access granted: "f9cafe1212c8" on branch "default"
1072 1072 acl: path access granted: "f9cafe1212c8"
1073 1073 acl: branch access granted: "911600dab2ae" on branch "default"
1074 1074 acl: path access granted: "911600dab2ae"
1075 1075 bundle2-input-part: total payload size 1606
1076 1076 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1077 1077 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1078 1078 bundle2-input-bundle: 3 parts total
1079 1079 updating the branch cache
1080 1080 bundle2-output-bundle: "HG20", 2 parts total
1081 1081 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1082 1082 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1083 1083 bundle2-input-bundle: with-transaction
1084 1084 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1085 1085 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1086 1086 bundle2-input-bundle: 1 parts total
1087 1087 listing keys for "phases"
1088 1088 try to push obsolete markers to remote
1089 1089 repository tip rolled back to revision 0 (undo push)
1090 1090 0:6675d58eff77
1091 1091
1092 1092
1093 1093 asterisk
1094 1094
1095 1095 $ init_config
1096 1096
1097 1097 asterisk test
1098 1098
1099 1099 $ echo '[acl.allow]' >> $config
1100 1100 $ echo "** = fred" >> $config
1101 1101
1102 1102 fred is always allowed
1103 1103
1104 1104 $ do_push fred
1105 1105 Pushing as user fred
1106 1106 hgrc = """
1107 1107 [hooks]
1108 1108 pretxnchangegroup.acl = python:hgext.acl.hook
1109 1109 [acl]
1110 1110 sources = push
1111 1111 [extensions]
1112 1112 [acl.allow]
1113 1113 ** = fred
1114 1114 """
1115 1115 pushing to ../b
1116 1116 query 1; heads
1117 1117 searching for changes
1118 1118 all remote heads known locally
1119 1119 listing keys for "phases"
1120 1120 checking for updated bookmarks
1121 1121 listing keys for "bookmarks"
1122 1122 invalid branchheads cache (served): tip differs
1123 1123 listing keys for "bookmarks"
1124 1124 3 changesets found
1125 1125 list of changesets:
1126 1126 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1127 1127 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1128 1128 911600dab2ae7a9baff75958b84fe606851ce955
1129 1129 bundle2-output-bundle: "HG20", 4 parts total
1130 bundle2-output-part: "replycaps" 106 bytes payload
1130 bundle2-output-part: "replycaps" 147 bytes payload
1131 1131 bundle2-output-part: "check:heads" streamed payload
1132 1132 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1133 1133 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1134 1134 bundle2-input-bundle: with-transaction
1135 1135 bundle2-input-part: "replycaps" supported
1136 bundle2-input-part: total payload size 106
1136 bundle2-input-part: total payload size 147
1137 1137 bundle2-input-part: "check:heads" supported
1138 1138 bundle2-input-part: total payload size 20
1139 1139 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1140 1140 adding changesets
1141 1141 add changeset ef1ea85a6374
1142 1142 add changeset f9cafe1212c8
1143 1143 add changeset 911600dab2ae
1144 1144 adding manifests
1145 1145 adding file changes
1146 1146 adding foo/Bar/file.txt revisions
1147 1147 adding foo/file.txt revisions
1148 1148 adding quux/file.py revisions
1149 1149 added 3 changesets with 3 changes to 3 files
1150 1150 calling hook pretxnchangegroup.acl: hgext.acl.hook
1151 1151 acl: checking access for user "fred"
1152 1152 acl: acl.allow.branches not enabled
1153 1153 acl: acl.deny.branches not enabled
1154 1154 acl: acl.allow enabled, 1 entries for user fred
1155 1155 acl: acl.deny not enabled
1156 1156 acl: branch access granted: "ef1ea85a6374" on branch "default"
1157 1157 acl: path access granted: "ef1ea85a6374"
1158 1158 acl: branch access granted: "f9cafe1212c8" on branch "default"
1159 1159 acl: path access granted: "f9cafe1212c8"
1160 1160 acl: branch access granted: "911600dab2ae" on branch "default"
1161 1161 acl: path access granted: "911600dab2ae"
1162 1162 bundle2-input-part: total payload size 1606
1163 1163 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1164 1164 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1165 1165 bundle2-input-bundle: 3 parts total
1166 1166 updating the branch cache
1167 1167 bundle2-output-bundle: "HG20", 2 parts total
1168 1168 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1169 1169 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1170 1170 bundle2-input-bundle: with-transaction
1171 1171 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1172 1172 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1173 1173 bundle2-input-bundle: 1 parts total
1174 1174 listing keys for "phases"
1175 1175 try to push obsolete markers to remote
1176 1176 repository tip rolled back to revision 0 (undo push)
1177 1177 0:6675d58eff77
1178 1178
1179 1179
1180 1180 $ echo '[acl.deny]' >> $config
1181 1181 $ echo "foo/Bar/** = *" >> $config
1182 1182
1183 1183 no one is allowed inside foo/Bar/
1184 1184
1185 1185 $ do_push fred
1186 1186 Pushing as user fred
1187 1187 hgrc = """
1188 1188 [hooks]
1189 1189 pretxnchangegroup.acl = python:hgext.acl.hook
1190 1190 [acl]
1191 1191 sources = push
1192 1192 [extensions]
1193 1193 [acl.allow]
1194 1194 ** = fred
1195 1195 [acl.deny]
1196 1196 foo/Bar/** = *
1197 1197 """
1198 1198 pushing to ../b
1199 1199 query 1; heads
1200 1200 searching for changes
1201 1201 all remote heads known locally
1202 1202 listing keys for "phases"
1203 1203 checking for updated bookmarks
1204 1204 listing keys for "bookmarks"
1205 1205 invalid branchheads cache (served): tip differs
1206 1206 listing keys for "bookmarks"
1207 1207 3 changesets found
1208 1208 list of changesets:
1209 1209 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1210 1210 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1211 1211 911600dab2ae7a9baff75958b84fe606851ce955
1212 1212 bundle2-output-bundle: "HG20", 4 parts total
1213 bundle2-output-part: "replycaps" 106 bytes payload
1213 bundle2-output-part: "replycaps" 147 bytes payload
1214 1214 bundle2-output-part: "check:heads" streamed payload
1215 1215 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1216 1216 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1217 1217 bundle2-input-bundle: with-transaction
1218 1218 bundle2-input-part: "replycaps" supported
1219 bundle2-input-part: total payload size 106
1219 bundle2-input-part: total payload size 147
1220 1220 bundle2-input-part: "check:heads" supported
1221 1221 bundle2-input-part: total payload size 20
1222 1222 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1223 1223 adding changesets
1224 1224 add changeset ef1ea85a6374
1225 1225 add changeset f9cafe1212c8
1226 1226 add changeset 911600dab2ae
1227 1227 adding manifests
1228 1228 adding file changes
1229 1229 adding foo/Bar/file.txt revisions
1230 1230 adding foo/file.txt revisions
1231 1231 adding quux/file.py revisions
1232 1232 added 3 changesets with 3 changes to 3 files
1233 1233 calling hook pretxnchangegroup.acl: hgext.acl.hook
1234 1234 acl: checking access for user "fred"
1235 1235 acl: acl.allow.branches not enabled
1236 1236 acl: acl.deny.branches not enabled
1237 1237 acl: acl.allow enabled, 1 entries for user fred
1238 1238 acl: acl.deny enabled, 1 entries for user fred
1239 1239 acl: branch access granted: "ef1ea85a6374" on branch "default"
1240 1240 acl: path access granted: "ef1ea85a6374"
1241 1241 acl: branch access granted: "f9cafe1212c8" on branch "default"
1242 1242 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1243 1243 bundle2-input-part: total payload size 1606
1244 1244 bundle2-input-bundle: 3 parts total
1245 1245 transaction abort!
1246 1246 rollback completed
1247 1247 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1248 1248 no rollback information available
1249 1249 0:6675d58eff77
1250 1250
1251 1251
1252 1252 Groups
1253 1253
1254 1254 $ init_config
1255 1255
1256 1256 OS-level groups
1257 1257
1258 1258 $ echo '[acl.allow]' >> $config
1259 1259 $ echo "** = @group1" >> $config
1260 1260
1261 1261 @group1 is always allowed
1262 1262
1263 1263 $ do_push fred
1264 1264 Pushing as user fred
1265 1265 hgrc = """
1266 1266 [hooks]
1267 1267 pretxnchangegroup.acl = python:hgext.acl.hook
1268 1268 [acl]
1269 1269 sources = push
1270 1270 [extensions]
1271 1271 [acl.allow]
1272 1272 ** = @group1
1273 1273 """
1274 1274 pushing to ../b
1275 1275 query 1; heads
1276 1276 searching for changes
1277 1277 all remote heads known locally
1278 1278 listing keys for "phases"
1279 1279 checking for updated bookmarks
1280 1280 listing keys for "bookmarks"
1281 1281 invalid branchheads cache (served): tip differs
1282 1282 listing keys for "bookmarks"
1283 1283 3 changesets found
1284 1284 list of changesets:
1285 1285 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1286 1286 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1287 1287 911600dab2ae7a9baff75958b84fe606851ce955
1288 1288 bundle2-output-bundle: "HG20", 4 parts total
1289 bundle2-output-part: "replycaps" 106 bytes payload
1289 bundle2-output-part: "replycaps" 147 bytes payload
1290 1290 bundle2-output-part: "check:heads" streamed payload
1291 1291 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1292 1292 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1293 1293 bundle2-input-bundle: with-transaction
1294 1294 bundle2-input-part: "replycaps" supported
1295 bundle2-input-part: total payload size 106
1295 bundle2-input-part: total payload size 147
1296 1296 bundle2-input-part: "check:heads" supported
1297 1297 bundle2-input-part: total payload size 20
1298 1298 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1299 1299 adding changesets
1300 1300 add changeset ef1ea85a6374
1301 1301 add changeset f9cafe1212c8
1302 1302 add changeset 911600dab2ae
1303 1303 adding manifests
1304 1304 adding file changes
1305 1305 adding foo/Bar/file.txt revisions
1306 1306 adding foo/file.txt revisions
1307 1307 adding quux/file.py revisions
1308 1308 added 3 changesets with 3 changes to 3 files
1309 1309 calling hook pretxnchangegroup.acl: hgext.acl.hook
1310 1310 acl: checking access for user "fred"
1311 1311 acl: acl.allow.branches not enabled
1312 1312 acl: acl.deny.branches not enabled
1313 1313 acl: "group1" not defined in [acl.groups]
1314 1314 acl: acl.allow enabled, 1 entries for user fred
1315 1315 acl: acl.deny not enabled
1316 1316 acl: branch access granted: "ef1ea85a6374" on branch "default"
1317 1317 acl: path access granted: "ef1ea85a6374"
1318 1318 acl: branch access granted: "f9cafe1212c8" on branch "default"
1319 1319 acl: path access granted: "f9cafe1212c8"
1320 1320 acl: branch access granted: "911600dab2ae" on branch "default"
1321 1321 acl: path access granted: "911600dab2ae"
1322 1322 bundle2-input-part: total payload size 1606
1323 1323 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1324 1324 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1325 1325 bundle2-input-bundle: 3 parts total
1326 1326 updating the branch cache
1327 1327 bundle2-output-bundle: "HG20", 2 parts total
1328 1328 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1329 1329 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1330 1330 bundle2-input-bundle: with-transaction
1331 1331 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1332 1332 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1333 1333 bundle2-input-bundle: 1 parts total
1334 1334 listing keys for "phases"
1335 1335 try to push obsolete markers to remote
1336 1336 repository tip rolled back to revision 0 (undo push)
1337 1337 0:6675d58eff77
1338 1338
1339 1339
1340 1340 $ echo '[acl.deny]' >> $config
1341 1341 $ echo "foo/Bar/** = @group1" >> $config
1342 1342
1343 1343 @group is allowed inside anything but foo/Bar/
1344 1344
1345 1345 $ do_push fred
1346 1346 Pushing as user fred
1347 1347 hgrc = """
1348 1348 [hooks]
1349 1349 pretxnchangegroup.acl = python:hgext.acl.hook
1350 1350 [acl]
1351 1351 sources = push
1352 1352 [extensions]
1353 1353 [acl.allow]
1354 1354 ** = @group1
1355 1355 [acl.deny]
1356 1356 foo/Bar/** = @group1
1357 1357 """
1358 1358 pushing to ../b
1359 1359 query 1; heads
1360 1360 searching for changes
1361 1361 all remote heads known locally
1362 1362 listing keys for "phases"
1363 1363 checking for updated bookmarks
1364 1364 listing keys for "bookmarks"
1365 1365 invalid branchheads cache (served): tip differs
1366 1366 listing keys for "bookmarks"
1367 1367 3 changesets found
1368 1368 list of changesets:
1369 1369 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1370 1370 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1371 1371 911600dab2ae7a9baff75958b84fe606851ce955
1372 1372 bundle2-output-bundle: "HG20", 4 parts total
1373 bundle2-output-part: "replycaps" 106 bytes payload
1373 bundle2-output-part: "replycaps" 147 bytes payload
1374 1374 bundle2-output-part: "check:heads" streamed payload
1375 1375 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1376 1376 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1377 1377 bundle2-input-bundle: with-transaction
1378 1378 bundle2-input-part: "replycaps" supported
1379 bundle2-input-part: total payload size 106
1379 bundle2-input-part: total payload size 147
1380 1380 bundle2-input-part: "check:heads" supported
1381 1381 bundle2-input-part: total payload size 20
1382 1382 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1383 1383 adding changesets
1384 1384 add changeset ef1ea85a6374
1385 1385 add changeset f9cafe1212c8
1386 1386 add changeset 911600dab2ae
1387 1387 adding manifests
1388 1388 adding file changes
1389 1389 adding foo/Bar/file.txt revisions
1390 1390 adding foo/file.txt revisions
1391 1391 adding quux/file.py revisions
1392 1392 added 3 changesets with 3 changes to 3 files
1393 1393 calling hook pretxnchangegroup.acl: hgext.acl.hook
1394 1394 acl: checking access for user "fred"
1395 1395 acl: acl.allow.branches not enabled
1396 1396 acl: acl.deny.branches not enabled
1397 1397 acl: "group1" not defined in [acl.groups]
1398 1398 acl: acl.allow enabled, 1 entries for user fred
1399 1399 acl: "group1" not defined in [acl.groups]
1400 1400 acl: acl.deny enabled, 1 entries for user fred
1401 1401 acl: branch access granted: "ef1ea85a6374" on branch "default"
1402 1402 acl: path access granted: "ef1ea85a6374"
1403 1403 acl: branch access granted: "f9cafe1212c8" on branch "default"
1404 1404 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1405 1405 bundle2-input-part: total payload size 1606
1406 1406 bundle2-input-bundle: 3 parts total
1407 1407 transaction abort!
1408 1408 rollback completed
1409 1409 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1410 1410 no rollback information available
1411 1411 0:6675d58eff77
1412 1412
1413 1413
1414 1414 Invalid group
1415 1415
1416 1416 Disable the fakegroups trick to get real failures
1417 1417
1418 1418 $ grep -v fakegroups $config > config.tmp
1419 1419 $ mv config.tmp $config
1420 1420 $ echo '[acl.allow]' >> $config
1421 1421 $ echo "** = @unlikelytoexist" >> $config
1422 1422 $ do_push fred 2>&1 | grep unlikelytoexist
1423 1423 ** = @unlikelytoexist
1424 1424 acl: "unlikelytoexist" not defined in [acl.groups]
1425 1425 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1426 1426 abort: group 'unlikelytoexist' is undefined
1427 1427
1428 1428
1429 1429 Branch acl tests setup
1430 1430
1431 1431 $ init_config
1432 1432 $ cd b
1433 1433 $ hg up
1434 1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1435 1435 $ hg branch foobar
1436 1436 marked working directory as branch foobar
1437 1437 (branches are permanent and global, did you want a bookmark?)
1438 1438 $ hg commit -m 'create foobar'
1439 1439 $ echo 'foo contents' > abc.txt
1440 1440 $ hg add abc.txt
1441 1441 $ hg commit -m 'foobar contents'
1442 1442 $ cd ..
1443 1443 $ hg --cwd a pull ../b
1444 1444 pulling from ../b
1445 1445 searching for changes
1446 1446 adding changesets
1447 1447 adding manifests
1448 1448 adding file changes
1449 1449 added 2 changesets with 1 changes to 1 files (+1 heads)
1450 1450 (run 'hg heads' to see heads)
1451 1451
1452 1452 Create additional changeset on foobar branch
1453 1453
1454 1454 $ cd a
1455 1455 $ hg up -C foobar
1456 1456 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1457 1457 $ echo 'foo contents2' > abc.txt
1458 1458 $ hg commit -m 'foobar contents2'
1459 1459 $ cd ..
1460 1460
1461 1461
1462 1462 No branch acls specified
1463 1463
1464 1464 $ do_push astro
1465 1465 Pushing as user astro
1466 1466 hgrc = """
1467 1467 [hooks]
1468 1468 pretxnchangegroup.acl = python:hgext.acl.hook
1469 1469 [acl]
1470 1470 sources = push
1471 1471 [extensions]
1472 1472 """
1473 1473 pushing to ../b
1474 1474 query 1; heads
1475 1475 searching for changes
1476 1476 all remote heads known locally
1477 1477 listing keys for "phases"
1478 1478 checking for updated bookmarks
1479 1479 listing keys for "bookmarks"
1480 1480 listing keys for "bookmarks"
1481 1481 4 changesets found
1482 1482 list of changesets:
1483 1483 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1484 1484 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1485 1485 911600dab2ae7a9baff75958b84fe606851ce955
1486 1486 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1487 1487 bundle2-output-bundle: "HG20", 5 parts total
1488 bundle2-output-part: "replycaps" 106 bytes payload
1488 bundle2-output-part: "replycaps" 147 bytes payload
1489 1489 bundle2-output-part: "check:heads" streamed payload
1490 1490 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1491 1491 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1492 1492 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1493 1493 bundle2-input-bundle: with-transaction
1494 1494 bundle2-input-part: "replycaps" supported
1495 bundle2-input-part: total payload size 106
1495 bundle2-input-part: total payload size 147
1496 1496 bundle2-input-part: "check:heads" supported
1497 1497 bundle2-input-part: total payload size 20
1498 1498 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1499 1499 adding changesets
1500 1500 add changeset ef1ea85a6374
1501 1501 add changeset f9cafe1212c8
1502 1502 add changeset 911600dab2ae
1503 1503 add changeset e8fc755d4d82
1504 1504 adding manifests
1505 1505 adding file changes
1506 1506 adding abc.txt revisions
1507 1507 adding foo/Bar/file.txt revisions
1508 1508 adding foo/file.txt revisions
1509 1509 adding quux/file.py revisions
1510 1510 added 4 changesets with 4 changes to 4 files (+1 heads)
1511 1511 calling hook pretxnchangegroup.acl: hgext.acl.hook
1512 1512 acl: checking access for user "astro"
1513 1513 acl: acl.allow.branches not enabled
1514 1514 acl: acl.deny.branches not enabled
1515 1515 acl: acl.allow not enabled
1516 1516 acl: acl.deny not enabled
1517 1517 acl: branch access granted: "ef1ea85a6374" on branch "default"
1518 1518 acl: path access granted: "ef1ea85a6374"
1519 1519 acl: branch access granted: "f9cafe1212c8" on branch "default"
1520 1520 acl: path access granted: "f9cafe1212c8"
1521 1521 acl: branch access granted: "911600dab2ae" on branch "default"
1522 1522 acl: path access granted: "911600dab2ae"
1523 1523 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1524 1524 acl: path access granted: "e8fc755d4d82"
1525 1525 bundle2-input-part: total payload size 2101
1526 1526 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1527 1527 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1528 1528 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1529 1529 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1530 1530 bundle2-input-bundle: 4 parts total
1531 1531 updating the branch cache
1532 1532 bundle2-output-bundle: "HG20", 3 parts total
1533 1533 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1534 1534 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1535 1535 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1536 1536 bundle2-input-bundle: with-transaction
1537 1537 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1538 1538 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1539 1539 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1540 1540 bundle2-input-bundle: 2 parts total
1541 1541 listing keys for "phases"
1542 1542 try to push obsolete markers to remote
1543 1543 repository tip rolled back to revision 2 (undo push)
1544 1544 2:fb35475503ef
1545 1545
1546 1546
1547 1547 Branch acl deny test
1548 1548
1549 1549 $ echo "[acl.deny.branches]" >> $config
1550 1550 $ echo "foobar = *" >> $config
1551 1551 $ do_push astro
1552 1552 Pushing as user astro
1553 1553 hgrc = """
1554 1554 [hooks]
1555 1555 pretxnchangegroup.acl = python:hgext.acl.hook
1556 1556 [acl]
1557 1557 sources = push
1558 1558 [extensions]
1559 1559 [acl.deny.branches]
1560 1560 foobar = *
1561 1561 """
1562 1562 pushing to ../b
1563 1563 query 1; heads
1564 1564 searching for changes
1565 1565 all remote heads known locally
1566 1566 listing keys for "phases"
1567 1567 checking for updated bookmarks
1568 1568 listing keys for "bookmarks"
1569 1569 listing keys for "bookmarks"
1570 1570 4 changesets found
1571 1571 list of changesets:
1572 1572 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1573 1573 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1574 1574 911600dab2ae7a9baff75958b84fe606851ce955
1575 1575 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1576 1576 bundle2-output-bundle: "HG20", 5 parts total
1577 bundle2-output-part: "replycaps" 106 bytes payload
1577 bundle2-output-part: "replycaps" 147 bytes payload
1578 1578 bundle2-output-part: "check:heads" streamed payload
1579 1579 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1580 1580 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1581 1581 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1582 1582 bundle2-input-bundle: with-transaction
1583 1583 bundle2-input-part: "replycaps" supported
1584 bundle2-input-part: total payload size 106
1584 bundle2-input-part: total payload size 147
1585 1585 bundle2-input-part: "check:heads" supported
1586 1586 bundle2-input-part: total payload size 20
1587 1587 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1588 1588 adding changesets
1589 1589 add changeset ef1ea85a6374
1590 1590 add changeset f9cafe1212c8
1591 1591 add changeset 911600dab2ae
1592 1592 add changeset e8fc755d4d82
1593 1593 adding manifests
1594 1594 adding file changes
1595 1595 adding abc.txt revisions
1596 1596 adding foo/Bar/file.txt revisions
1597 1597 adding foo/file.txt revisions
1598 1598 adding quux/file.py revisions
1599 1599 added 4 changesets with 4 changes to 4 files (+1 heads)
1600 1600 calling hook pretxnchangegroup.acl: hgext.acl.hook
1601 1601 acl: checking access for user "astro"
1602 1602 acl: acl.allow.branches not enabled
1603 1603 acl: acl.deny.branches enabled, 1 entries for user astro
1604 1604 acl: acl.allow not enabled
1605 1605 acl: acl.deny not enabled
1606 1606 acl: branch access granted: "ef1ea85a6374" on branch "default"
1607 1607 acl: path access granted: "ef1ea85a6374"
1608 1608 acl: branch access granted: "f9cafe1212c8" on branch "default"
1609 1609 acl: path access granted: "f9cafe1212c8"
1610 1610 acl: branch access granted: "911600dab2ae" on branch "default"
1611 1611 acl: path access granted: "911600dab2ae"
1612 1612 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1613 1613 bundle2-input-part: total payload size 2101
1614 1614 bundle2-input-bundle: 4 parts total
1615 1615 transaction abort!
1616 1616 rollback completed
1617 1617 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1618 1618 no rollback information available
1619 1619 2:fb35475503ef
1620 1620
1621 1621
1622 1622 Branch acl empty allow test
1623 1623
1624 1624 $ init_config
1625 1625 $ echo "[acl.allow.branches]" >> $config
1626 1626 $ do_push astro
1627 1627 Pushing as user astro
1628 1628 hgrc = """
1629 1629 [hooks]
1630 1630 pretxnchangegroup.acl = python:hgext.acl.hook
1631 1631 [acl]
1632 1632 sources = push
1633 1633 [extensions]
1634 1634 [acl.allow.branches]
1635 1635 """
1636 1636 pushing to ../b
1637 1637 query 1; heads
1638 1638 searching for changes
1639 1639 all remote heads known locally
1640 1640 listing keys for "phases"
1641 1641 checking for updated bookmarks
1642 1642 listing keys for "bookmarks"
1643 1643 listing keys for "bookmarks"
1644 1644 4 changesets found
1645 1645 list of changesets:
1646 1646 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1647 1647 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1648 1648 911600dab2ae7a9baff75958b84fe606851ce955
1649 1649 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1650 1650 bundle2-output-bundle: "HG20", 5 parts total
1651 bundle2-output-part: "replycaps" 106 bytes payload
1651 bundle2-output-part: "replycaps" 147 bytes payload
1652 1652 bundle2-output-part: "check:heads" streamed payload
1653 1653 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1654 1654 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1655 1655 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1656 1656 bundle2-input-bundle: with-transaction
1657 1657 bundle2-input-part: "replycaps" supported
1658 bundle2-input-part: total payload size 106
1658 bundle2-input-part: total payload size 147
1659 1659 bundle2-input-part: "check:heads" supported
1660 1660 bundle2-input-part: total payload size 20
1661 1661 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1662 1662 adding changesets
1663 1663 add changeset ef1ea85a6374
1664 1664 add changeset f9cafe1212c8
1665 1665 add changeset 911600dab2ae
1666 1666 add changeset e8fc755d4d82
1667 1667 adding manifests
1668 1668 adding file changes
1669 1669 adding abc.txt revisions
1670 1670 adding foo/Bar/file.txt revisions
1671 1671 adding foo/file.txt revisions
1672 1672 adding quux/file.py revisions
1673 1673 added 4 changesets with 4 changes to 4 files (+1 heads)
1674 1674 calling hook pretxnchangegroup.acl: hgext.acl.hook
1675 1675 acl: checking access for user "astro"
1676 1676 acl: acl.allow.branches enabled, 0 entries for user astro
1677 1677 acl: acl.deny.branches not enabled
1678 1678 acl: acl.allow not enabled
1679 1679 acl: acl.deny not enabled
1680 1680 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1681 1681 bundle2-input-part: total payload size 2101
1682 1682 bundle2-input-bundle: 4 parts total
1683 1683 transaction abort!
1684 1684 rollback completed
1685 1685 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1686 1686 no rollback information available
1687 1687 2:fb35475503ef
1688 1688
1689 1689
1690 1690 Branch acl allow other
1691 1691
1692 1692 $ init_config
1693 1693 $ echo "[acl.allow.branches]" >> $config
1694 1694 $ echo "* = george" >> $config
1695 1695 $ do_push astro
1696 1696 Pushing as user astro
1697 1697 hgrc = """
1698 1698 [hooks]
1699 1699 pretxnchangegroup.acl = python:hgext.acl.hook
1700 1700 [acl]
1701 1701 sources = push
1702 1702 [extensions]
1703 1703 [acl.allow.branches]
1704 1704 * = george
1705 1705 """
1706 1706 pushing to ../b
1707 1707 query 1; heads
1708 1708 searching for changes
1709 1709 all remote heads known locally
1710 1710 listing keys for "phases"
1711 1711 checking for updated bookmarks
1712 1712 listing keys for "bookmarks"
1713 1713 listing keys for "bookmarks"
1714 1714 4 changesets found
1715 1715 list of changesets:
1716 1716 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1717 1717 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1718 1718 911600dab2ae7a9baff75958b84fe606851ce955
1719 1719 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1720 1720 bundle2-output-bundle: "HG20", 5 parts total
1721 bundle2-output-part: "replycaps" 106 bytes payload
1721 bundle2-output-part: "replycaps" 147 bytes payload
1722 1722 bundle2-output-part: "check:heads" streamed payload
1723 1723 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1724 1724 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1725 1725 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1726 1726 bundle2-input-bundle: with-transaction
1727 1727 bundle2-input-part: "replycaps" supported
1728 bundle2-input-part: total payload size 106
1728 bundle2-input-part: total payload size 147
1729 1729 bundle2-input-part: "check:heads" supported
1730 1730 bundle2-input-part: total payload size 20
1731 1731 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1732 1732 adding changesets
1733 1733 add changeset ef1ea85a6374
1734 1734 add changeset f9cafe1212c8
1735 1735 add changeset 911600dab2ae
1736 1736 add changeset e8fc755d4d82
1737 1737 adding manifests
1738 1738 adding file changes
1739 1739 adding abc.txt revisions
1740 1740 adding foo/Bar/file.txt revisions
1741 1741 adding foo/file.txt revisions
1742 1742 adding quux/file.py revisions
1743 1743 added 4 changesets with 4 changes to 4 files (+1 heads)
1744 1744 calling hook pretxnchangegroup.acl: hgext.acl.hook
1745 1745 acl: checking access for user "astro"
1746 1746 acl: acl.allow.branches enabled, 0 entries for user astro
1747 1747 acl: acl.deny.branches not enabled
1748 1748 acl: acl.allow not enabled
1749 1749 acl: acl.deny not enabled
1750 1750 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1751 1751 bundle2-input-part: total payload size 2101
1752 1752 bundle2-input-bundle: 4 parts total
1753 1753 transaction abort!
1754 1754 rollback completed
1755 1755 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1756 1756 no rollback information available
1757 1757 2:fb35475503ef
1758 1758
1759 1759 $ do_push george
1760 1760 Pushing as user george
1761 1761 hgrc = """
1762 1762 [hooks]
1763 1763 pretxnchangegroup.acl = python:hgext.acl.hook
1764 1764 [acl]
1765 1765 sources = push
1766 1766 [extensions]
1767 1767 [acl.allow.branches]
1768 1768 * = george
1769 1769 """
1770 1770 pushing to ../b
1771 1771 query 1; heads
1772 1772 searching for changes
1773 1773 all remote heads known locally
1774 1774 listing keys for "phases"
1775 1775 checking for updated bookmarks
1776 1776 listing keys for "bookmarks"
1777 1777 listing keys for "bookmarks"
1778 1778 4 changesets found
1779 1779 list of changesets:
1780 1780 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1781 1781 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1782 1782 911600dab2ae7a9baff75958b84fe606851ce955
1783 1783 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1784 1784 bundle2-output-bundle: "HG20", 5 parts total
1785 bundle2-output-part: "replycaps" 106 bytes payload
1785 bundle2-output-part: "replycaps" 147 bytes payload
1786 1786 bundle2-output-part: "check:heads" streamed payload
1787 1787 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1788 1788 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1789 1789 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1790 1790 bundle2-input-bundle: with-transaction
1791 1791 bundle2-input-part: "replycaps" supported
1792 bundle2-input-part: total payload size 106
1792 bundle2-input-part: total payload size 147
1793 1793 bundle2-input-part: "check:heads" supported
1794 1794 bundle2-input-part: total payload size 20
1795 1795 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1796 1796 adding changesets
1797 1797 add changeset ef1ea85a6374
1798 1798 add changeset f9cafe1212c8
1799 1799 add changeset 911600dab2ae
1800 1800 add changeset e8fc755d4d82
1801 1801 adding manifests
1802 1802 adding file changes
1803 1803 adding abc.txt revisions
1804 1804 adding foo/Bar/file.txt revisions
1805 1805 adding foo/file.txt revisions
1806 1806 adding quux/file.py revisions
1807 1807 added 4 changesets with 4 changes to 4 files (+1 heads)
1808 1808 calling hook pretxnchangegroup.acl: hgext.acl.hook
1809 1809 acl: checking access for user "george"
1810 1810 acl: acl.allow.branches enabled, 1 entries for user george
1811 1811 acl: acl.deny.branches not enabled
1812 1812 acl: acl.allow not enabled
1813 1813 acl: acl.deny not enabled
1814 1814 acl: branch access granted: "ef1ea85a6374" on branch "default"
1815 1815 acl: path access granted: "ef1ea85a6374"
1816 1816 acl: branch access granted: "f9cafe1212c8" on branch "default"
1817 1817 acl: path access granted: "f9cafe1212c8"
1818 1818 acl: branch access granted: "911600dab2ae" on branch "default"
1819 1819 acl: path access granted: "911600dab2ae"
1820 1820 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1821 1821 acl: path access granted: "e8fc755d4d82"
1822 1822 bundle2-input-part: total payload size 2101
1823 1823 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1824 1824 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1825 1825 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1826 1826 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1827 1827 bundle2-input-bundle: 4 parts total
1828 1828 updating the branch cache
1829 1829 bundle2-output-bundle: "HG20", 3 parts total
1830 1830 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1831 1831 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1832 1832 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1833 1833 bundle2-input-bundle: with-transaction
1834 1834 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1835 1835 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1836 1836 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1837 1837 bundle2-input-bundle: 2 parts total
1838 1838 listing keys for "phases"
1839 1839 try to push obsolete markers to remote
1840 1840 repository tip rolled back to revision 2 (undo push)
1841 1841 2:fb35475503ef
1842 1842
1843 1843
1844 1844 Branch acl conflicting allow
1845 1845 asterisk ends up applying to all branches and allowing george to
1846 1846 push foobar into the remote
1847 1847
1848 1848 $ init_config
1849 1849 $ echo "[acl.allow.branches]" >> $config
1850 1850 $ echo "foobar = astro" >> $config
1851 1851 $ echo "* = george" >> $config
1852 1852 $ do_push george
1853 1853 Pushing as user george
1854 1854 hgrc = """
1855 1855 [hooks]
1856 1856 pretxnchangegroup.acl = python:hgext.acl.hook
1857 1857 [acl]
1858 1858 sources = push
1859 1859 [extensions]
1860 1860 [acl.allow.branches]
1861 1861 foobar = astro
1862 1862 * = george
1863 1863 """
1864 1864 pushing to ../b
1865 1865 query 1; heads
1866 1866 searching for changes
1867 1867 all remote heads known locally
1868 1868 listing keys for "phases"
1869 1869 checking for updated bookmarks
1870 1870 listing keys for "bookmarks"
1871 1871 listing keys for "bookmarks"
1872 1872 4 changesets found
1873 1873 list of changesets:
1874 1874 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1875 1875 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1876 1876 911600dab2ae7a9baff75958b84fe606851ce955
1877 1877 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1878 1878 bundle2-output-bundle: "HG20", 5 parts total
1879 bundle2-output-part: "replycaps" 106 bytes payload
1879 bundle2-output-part: "replycaps" 147 bytes payload
1880 1880 bundle2-output-part: "check:heads" streamed payload
1881 1881 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1882 1882 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1883 1883 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1884 1884 bundle2-input-bundle: with-transaction
1885 1885 bundle2-input-part: "replycaps" supported
1886 bundle2-input-part: total payload size 106
1886 bundle2-input-part: total payload size 147
1887 1887 bundle2-input-part: "check:heads" supported
1888 1888 bundle2-input-part: total payload size 20
1889 1889 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1890 1890 adding changesets
1891 1891 add changeset ef1ea85a6374
1892 1892 add changeset f9cafe1212c8
1893 1893 add changeset 911600dab2ae
1894 1894 add changeset e8fc755d4d82
1895 1895 adding manifests
1896 1896 adding file changes
1897 1897 adding abc.txt revisions
1898 1898 adding foo/Bar/file.txt revisions
1899 1899 adding foo/file.txt revisions
1900 1900 adding quux/file.py revisions
1901 1901 added 4 changesets with 4 changes to 4 files (+1 heads)
1902 1902 calling hook pretxnchangegroup.acl: hgext.acl.hook
1903 1903 acl: checking access for user "george"
1904 1904 acl: acl.allow.branches enabled, 1 entries for user george
1905 1905 acl: acl.deny.branches not enabled
1906 1906 acl: acl.allow not enabled
1907 1907 acl: acl.deny not enabled
1908 1908 acl: branch access granted: "ef1ea85a6374" on branch "default"
1909 1909 acl: path access granted: "ef1ea85a6374"
1910 1910 acl: branch access granted: "f9cafe1212c8" on branch "default"
1911 1911 acl: path access granted: "f9cafe1212c8"
1912 1912 acl: branch access granted: "911600dab2ae" on branch "default"
1913 1913 acl: path access granted: "911600dab2ae"
1914 1914 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1915 1915 acl: path access granted: "e8fc755d4d82"
1916 1916 bundle2-input-part: total payload size 2101
1917 1917 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1918 1918 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1919 1919 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1920 1920 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1921 1921 bundle2-input-bundle: 4 parts total
1922 1922 updating the branch cache
1923 1923 bundle2-output-bundle: "HG20", 3 parts total
1924 1924 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1925 1925 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1926 1926 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1927 1927 bundle2-input-bundle: with-transaction
1928 1928 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1929 1929 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1930 1930 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1931 1931 bundle2-input-bundle: 2 parts total
1932 1932 listing keys for "phases"
1933 1933 try to push obsolete markers to remote
1934 1934 repository tip rolled back to revision 2 (undo push)
1935 1935 2:fb35475503ef
1936 1936
1937 1937 Branch acl conflicting deny
1938 1938
1939 1939 $ init_config
1940 1940 $ echo "[acl.deny.branches]" >> $config
1941 1941 $ echo "foobar = astro" >> $config
1942 1942 $ echo "default = astro" >> $config
1943 1943 $ echo "* = george" >> $config
1944 1944 $ do_push george
1945 1945 Pushing as user george
1946 1946 hgrc = """
1947 1947 [hooks]
1948 1948 pretxnchangegroup.acl = python:hgext.acl.hook
1949 1949 [acl]
1950 1950 sources = push
1951 1951 [extensions]
1952 1952 [acl.deny.branches]
1953 1953 foobar = astro
1954 1954 default = astro
1955 1955 * = george
1956 1956 """
1957 1957 pushing to ../b
1958 1958 query 1; heads
1959 1959 searching for changes
1960 1960 all remote heads known locally
1961 1961 listing keys for "phases"
1962 1962 checking for updated bookmarks
1963 1963 listing keys for "bookmarks"
1964 1964 listing keys for "bookmarks"
1965 1965 4 changesets found
1966 1966 list of changesets:
1967 1967 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1968 1968 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1969 1969 911600dab2ae7a9baff75958b84fe606851ce955
1970 1970 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1971 1971 bundle2-output-bundle: "HG20", 5 parts total
1972 bundle2-output-part: "replycaps" 106 bytes payload
1972 bundle2-output-part: "replycaps" 147 bytes payload
1973 1973 bundle2-output-part: "check:heads" streamed payload
1974 1974 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1975 1975 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1976 1976 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1977 1977 bundle2-input-bundle: with-transaction
1978 1978 bundle2-input-part: "replycaps" supported
1979 bundle2-input-part: total payload size 106
1979 bundle2-input-part: total payload size 147
1980 1980 bundle2-input-part: "check:heads" supported
1981 1981 bundle2-input-part: total payload size 20
1982 1982 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1983 1983 adding changesets
1984 1984 add changeset ef1ea85a6374
1985 1985 add changeset f9cafe1212c8
1986 1986 add changeset 911600dab2ae
1987 1987 add changeset e8fc755d4d82
1988 1988 adding manifests
1989 1989 adding file changes
1990 1990 adding abc.txt revisions
1991 1991 adding foo/Bar/file.txt revisions
1992 1992 adding foo/file.txt revisions
1993 1993 adding quux/file.py revisions
1994 1994 added 4 changesets with 4 changes to 4 files (+1 heads)
1995 1995 calling hook pretxnchangegroup.acl: hgext.acl.hook
1996 1996 acl: checking access for user "george"
1997 1997 acl: acl.allow.branches not enabled
1998 1998 acl: acl.deny.branches enabled, 1 entries for user george
1999 1999 acl: acl.allow not enabled
2000 2000 acl: acl.deny not enabled
2001 2001 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2002 2002 bundle2-input-part: total payload size 2101
2003 2003 bundle2-input-bundle: 4 parts total
2004 2004 transaction abort!
2005 2005 rollback completed
2006 2006 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2007 2007 no rollback information available
2008 2008 2:fb35475503ef
2009 2009
2010 2010 User 'astro' must not be denied
2011 2011
2012 2012 $ init_config
2013 2013 $ echo "[acl.deny.branches]" >> $config
2014 2014 $ echo "default = !astro" >> $config
2015 2015 $ do_push astro
2016 2016 Pushing as user astro
2017 2017 hgrc = """
2018 2018 [hooks]
2019 2019 pretxnchangegroup.acl = python:hgext.acl.hook
2020 2020 [acl]
2021 2021 sources = push
2022 2022 [extensions]
2023 2023 [acl.deny.branches]
2024 2024 default = !astro
2025 2025 """
2026 2026 pushing to ../b
2027 2027 query 1; heads
2028 2028 searching for changes
2029 2029 all remote heads known locally
2030 2030 listing keys for "phases"
2031 2031 checking for updated bookmarks
2032 2032 listing keys for "bookmarks"
2033 2033 listing keys for "bookmarks"
2034 2034 4 changesets found
2035 2035 list of changesets:
2036 2036 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2037 2037 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2038 2038 911600dab2ae7a9baff75958b84fe606851ce955
2039 2039 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2040 2040 bundle2-output-bundle: "HG20", 5 parts total
2041 bundle2-output-part: "replycaps" 106 bytes payload
2041 bundle2-output-part: "replycaps" 147 bytes payload
2042 2042 bundle2-output-part: "check:heads" streamed payload
2043 2043 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2044 2044 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2045 2045 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2046 2046 bundle2-input-bundle: with-transaction
2047 2047 bundle2-input-part: "replycaps" supported
2048 bundle2-input-part: total payload size 106
2048 bundle2-input-part: total payload size 147
2049 2049 bundle2-input-part: "check:heads" supported
2050 2050 bundle2-input-part: total payload size 20
2051 2051 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2052 2052 adding changesets
2053 2053 add changeset ef1ea85a6374
2054 2054 add changeset f9cafe1212c8
2055 2055 add changeset 911600dab2ae
2056 2056 add changeset e8fc755d4d82
2057 2057 adding manifests
2058 2058 adding file changes
2059 2059 adding abc.txt revisions
2060 2060 adding foo/Bar/file.txt revisions
2061 2061 adding foo/file.txt revisions
2062 2062 adding quux/file.py revisions
2063 2063 added 4 changesets with 4 changes to 4 files (+1 heads)
2064 2064 calling hook pretxnchangegroup.acl: hgext.acl.hook
2065 2065 acl: checking access for user "astro"
2066 2066 acl: acl.allow.branches not enabled
2067 2067 acl: acl.deny.branches enabled, 0 entries for user astro
2068 2068 acl: acl.allow not enabled
2069 2069 acl: acl.deny not enabled
2070 2070 acl: branch access granted: "ef1ea85a6374" on branch "default"
2071 2071 acl: path access granted: "ef1ea85a6374"
2072 2072 acl: branch access granted: "f9cafe1212c8" on branch "default"
2073 2073 acl: path access granted: "f9cafe1212c8"
2074 2074 acl: branch access granted: "911600dab2ae" on branch "default"
2075 2075 acl: path access granted: "911600dab2ae"
2076 2076 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2077 2077 acl: path access granted: "e8fc755d4d82"
2078 2078 bundle2-input-part: total payload size 2101
2079 2079 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2080 2080 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2081 2081 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2082 2082 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2083 2083 bundle2-input-bundle: 4 parts total
2084 2084 updating the branch cache
2085 2085 bundle2-output-bundle: "HG20", 3 parts total
2086 2086 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2087 2087 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2088 2088 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2089 2089 bundle2-input-bundle: with-transaction
2090 2090 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2091 2091 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2092 2092 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2093 2093 bundle2-input-bundle: 2 parts total
2094 2094 listing keys for "phases"
2095 2095 try to push obsolete markers to remote
2096 2096 repository tip rolled back to revision 2 (undo push)
2097 2097 2:fb35475503ef
2098 2098
2099 2099
2100 2100 Non-astro users must be denied
2101 2101
2102 2102 $ do_push george
2103 2103 Pushing as user george
2104 2104 hgrc = """
2105 2105 [hooks]
2106 2106 pretxnchangegroup.acl = python:hgext.acl.hook
2107 2107 [acl]
2108 2108 sources = push
2109 2109 [extensions]
2110 2110 [acl.deny.branches]
2111 2111 default = !astro
2112 2112 """
2113 2113 pushing to ../b
2114 2114 query 1; heads
2115 2115 searching for changes
2116 2116 all remote heads known locally
2117 2117 listing keys for "phases"
2118 2118 checking for updated bookmarks
2119 2119 listing keys for "bookmarks"
2120 2120 listing keys for "bookmarks"
2121 2121 4 changesets found
2122 2122 list of changesets:
2123 2123 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2124 2124 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2125 2125 911600dab2ae7a9baff75958b84fe606851ce955
2126 2126 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2127 2127 bundle2-output-bundle: "HG20", 5 parts total
2128 bundle2-output-part: "replycaps" 106 bytes payload
2128 bundle2-output-part: "replycaps" 147 bytes payload
2129 2129 bundle2-output-part: "check:heads" streamed payload
2130 2130 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2131 2131 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2132 2132 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2133 2133 bundle2-input-bundle: with-transaction
2134 2134 bundle2-input-part: "replycaps" supported
2135 bundle2-input-part: total payload size 106
2135 bundle2-input-part: total payload size 147
2136 2136 bundle2-input-part: "check:heads" supported
2137 2137 bundle2-input-part: total payload size 20
2138 2138 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2139 2139 adding changesets
2140 2140 add changeset ef1ea85a6374
2141 2141 add changeset f9cafe1212c8
2142 2142 add changeset 911600dab2ae
2143 2143 add changeset e8fc755d4d82
2144 2144 adding manifests
2145 2145 adding file changes
2146 2146 adding abc.txt revisions
2147 2147 adding foo/Bar/file.txt revisions
2148 2148 adding foo/file.txt revisions
2149 2149 adding quux/file.py revisions
2150 2150 added 4 changesets with 4 changes to 4 files (+1 heads)
2151 2151 calling hook pretxnchangegroup.acl: hgext.acl.hook
2152 2152 acl: checking access for user "george"
2153 2153 acl: acl.allow.branches not enabled
2154 2154 acl: acl.deny.branches enabled, 1 entries for user george
2155 2155 acl: acl.allow not enabled
2156 2156 acl: acl.deny not enabled
2157 2157 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2158 2158 bundle2-input-part: total payload size 2101
2159 2159 bundle2-input-bundle: 4 parts total
2160 2160 transaction abort!
2161 2161 rollback completed
2162 2162 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2163 2163 no rollback information available
2164 2164 2:fb35475503ef
2165 2165
2166 2166
@@ -1,130 +1,130 b''
1 1 #require serve
2 2 $ cat << EOF >> $HGRCPATH
3 3 > [experimental]
4 4 > # drop me once bundle2 is the default,
5 5 > # added to get test change early.
6 6 > bundle2-exp = True
7 7 > EOF
8 8
9 9 $ hg init a
10 10 $ cd a
11 11 $ echo a > a
12 12 $ hg ci -Ama -d '1123456789 0'
13 13 adding a
14 14 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
15 15 $ cat hg.pid >> $DAEMON_PIDS
16 16 $ cd ..
17 17 $ tinyproxy.py $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
18 18 $ while [ ! -f proxy.pid ]; do sleep 0; done
19 19 $ cat proxy.pid >> $DAEMON_PIDS
20 20
21 21 url for proxy, stream
22 22
23 23 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
24 24 streaming all changes
25 25 3 files to transfer, 303 bytes of data
26 26 transferred * bytes in * seconds (*/sec) (glob)
27 27 searching for changes
28 28 no changes found
29 29 updating to branch default
30 30 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 31 $ cd b
32 32 $ hg verify
33 33 checking changesets
34 34 checking manifests
35 35 crosschecking files in changesets and manifests
36 36 checking files
37 37 1 files, 1 changesets, 1 total revisions
38 38 $ cd ..
39 39
40 40 url for proxy, pull
41 41
42 42 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
43 43 requesting all changes
44 44 adding changesets
45 45 adding manifests
46 46 adding file changes
47 47 added 1 changesets with 1 changes to 1 files
48 48 updating to branch default
49 49 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 50 $ cd b-pull
51 51 $ hg verify
52 52 checking changesets
53 53 checking manifests
54 54 crosschecking files in changesets and manifests
55 55 checking files
56 56 1 files, 1 changesets, 1 total revisions
57 57 $ cd ..
58 58
59 59 host:port for proxy
60 60
61 61 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
62 62 requesting all changes
63 63 adding changesets
64 64 adding manifests
65 65 adding file changes
66 66 added 1 changesets with 1 changes to 1 files
67 67 updating to branch default
68 68 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 69
70 70 proxy url with user name and password
71 71
72 72 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
73 73 requesting all changes
74 74 adding changesets
75 75 adding manifests
76 76 adding file changes
77 77 added 1 changesets with 1 changes to 1 files
78 78 updating to branch default
79 79 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 80
81 81 url with user name and password
82 82
83 83 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
84 84 requesting all changes
85 85 adding changesets
86 86 adding manifests
87 87 adding file changes
88 88 added 1 changesets with 1 changes to 1 files
89 89 updating to branch default
90 90 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 91
92 92 bad host:port for proxy
93 93
94 94 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
95 95 abort: error: Connection refused
96 96 [255]
97 97
98 98 do not use the proxy if it is in the no list
99 99
100 100 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
101 101 requesting all changes
102 102 adding changesets
103 103 adding manifests
104 104 adding file changes
105 105 added 1 changesets with 1 changes to 1 files
106 106 updating to branch default
107 107 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 108 $ cat proxy.log
109 109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
110 110 * - - [*] "GET http://localhost:$HGPORT/?cmd=branchmap HTTP/1.1" - - (glob)
111 111 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
112 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=83180e7845de420a1bb46896fd5fe05294f8d629&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
114 114 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
115 115 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
116 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
118 118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
119 119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
120 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
122 122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
123 123 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
124 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
126 126 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
127 127 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
128 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629&listkeys=phase%2Cbookmarks (glob)
130 130 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
@@ -1,323 +1,323 b''
1 1 #require serve
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo foo>foo
6 6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
7 7 $ echo foo>foo.d/foo
8 8 $ echo bar>foo.d/bAr.hg.d/BaR
9 9 $ echo bar>foo.d/baR.d.hg/bAR
10 10 $ hg commit -A -m 1
11 11 adding foo
12 12 adding foo.d/bAr.hg.d/BaR
13 13 adding foo.d/baR.d.hg/bAR
14 14 adding foo.d/foo
15 15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
16 16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
17 17
18 18 Test server address cannot be reused
19 19
20 20 #if windows
21 21 $ hg serve -p $HGPORT1 2>&1
22 22 abort: cannot start server at ':$HGPORT1': * (glob)
23 23 [255]
24 24 #else
25 25 $ hg serve -p $HGPORT1 2>&1
26 26 abort: cannot start server at ':$HGPORT1': Address already in use
27 27 [255]
28 28 #endif
29 29 $ cd ..
30 30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
31 31
32 32 clone via stream
33 33
34 34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
35 35 streaming all changes
36 36 6 files to transfer, 606 bytes of data
37 37 transferred * bytes in * seconds (*/sec) (glob)
38 38 searching for changes
39 39 no changes found
40 40 updating to branch default
41 41 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 42 $ hg verify -R copy
43 43 checking changesets
44 44 checking manifests
45 45 crosschecking files in changesets and manifests
46 46 checking files
47 47 4 files, 1 changesets, 4 total revisions
48 48
49 49 try to clone via stream, should use pull instead
50 50
51 51 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
52 52 requesting all changes
53 53 adding changesets
54 54 adding manifests
55 55 adding file changes
56 56 added 1 changesets with 4 changes to 4 files
57 57 updating to branch default
58 58 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
59 59
60 60 clone via pull
61 61
62 62 $ hg clone http://localhost:$HGPORT1/ copy-pull
63 63 requesting all changes
64 64 adding changesets
65 65 adding manifests
66 66 adding file changes
67 67 added 1 changesets with 4 changes to 4 files
68 68 updating to branch default
69 69 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 70 $ hg verify -R copy-pull
71 71 checking changesets
72 72 checking manifests
73 73 crosschecking files in changesets and manifests
74 74 checking files
75 75 4 files, 1 changesets, 4 total revisions
76 76 $ cd test
77 77 $ echo bar > bar
78 78 $ hg commit -A -d '1 0' -m 2
79 79 adding bar
80 80 $ cd ..
81 81
82 82 clone over http with --update
83 83
84 84 $ hg clone http://localhost:$HGPORT1/ updated --update 0
85 85 requesting all changes
86 86 adding changesets
87 87 adding manifests
88 88 adding file changes
89 89 added 2 changesets with 5 changes to 5 files
90 90 updating to branch default
91 91 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 92 $ hg log -r . -R updated
93 93 changeset: 0:8b6053c928fe
94 94 user: test
95 95 date: Thu Jan 01 00:00:00 1970 +0000
96 96 summary: 1
97 97
98 98 $ rm -rf updated
99 99
100 100 incoming via HTTP
101 101
102 102 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
103 103 adding changesets
104 104 adding manifests
105 105 adding file changes
106 106 added 1 changesets with 4 changes to 4 files
107 107 updating to branch default
108 108 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 109 $ cd partial
110 110 $ touch LOCAL
111 111 $ hg ci -qAm LOCAL
112 112 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
113 113 comparing with http://localhost:$HGPORT1/
114 114 searching for changes
115 115 2
116 116 $ cd ..
117 117
118 118 pull
119 119
120 120 $ cd copy-pull
121 121 $ echo '[hooks]' >> .hg/hgrc
122 122 $ echo "changegroup = printenv.py changegroup" >> .hg/hgrc
123 123 $ hg pull
124 124 pulling from http://localhost:$HGPORT1/
125 125 searching for changes
126 126 adding changesets
127 127 adding manifests
128 128 adding file changes
129 129 added 1 changesets with 1 changes to 1 files
130 130 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
131 131 (run 'hg update' to get a working copy)
132 132 $ cd ..
133 133
134 134 clone from invalid URL
135 135
136 136 $ hg clone http://localhost:$HGPORT/bad
137 137 abort: HTTP Error 404: Not Found
138 138 [255]
139 139
140 140 test http authentication
141 141 + use the same server to test server side streaming preference
142 142
143 143 $ cd test
144 144 $ cat << EOT > userpass.py
145 145 > import base64
146 146 > from mercurial.hgweb import common
147 147 > def perform_authentication(hgweb, req, op):
148 148 > auth = req.env.get('HTTP_AUTHORIZATION')
149 149 > if not auth:
150 150 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
151 151 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
152 152 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
153 153 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
154 154 > def extsetup():
155 155 > common.permhooks.insert(0, perform_authentication)
156 156 > EOT
157 157 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
158 158 > --config server.preferuncompressed=True \
159 159 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
160 160 $ cat pid >> $DAEMON_PIDS
161 161
162 162 $ cat << EOF > get_pass.py
163 163 > import getpass
164 164 > def newgetpass(arg):
165 165 > return "pass"
166 166 > getpass.getpass = newgetpass
167 167 > EOF
168 168
169 169 $ hg id http://localhost:$HGPORT2/
170 170 abort: http authorization required for http://localhost:$HGPORT2/
171 171 [255]
172 172 $ hg id http://localhost:$HGPORT2/
173 173 abort: http authorization required for http://localhost:$HGPORT2/
174 174 [255]
175 175 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
176 176 http authorization required for http://localhost:$HGPORT2/
177 177 realm: mercurial
178 178 user: user
179 179 password: 5fed3813f7f5
180 180 $ hg id http://user:pass@localhost:$HGPORT2/
181 181 5fed3813f7f5
182 182 $ echo '[auth]' >> .hg/hgrc
183 183 $ echo 'l.schemes=http' >> .hg/hgrc
184 184 $ echo 'l.prefix=lo' >> .hg/hgrc
185 185 $ echo 'l.username=user' >> .hg/hgrc
186 186 $ echo 'l.password=pass' >> .hg/hgrc
187 187 $ hg id http://localhost:$HGPORT2/
188 188 5fed3813f7f5
189 189 $ hg id http://localhost:$HGPORT2/
190 190 5fed3813f7f5
191 191 $ hg id http://user@localhost:$HGPORT2/
192 192 5fed3813f7f5
193 193 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
194 194 streaming all changes
195 195 7 files to transfer, 916 bytes of data
196 196 transferred * bytes in * seconds (*/sec) (glob)
197 197 searching for changes
198 198 no changes found
199 199 updating to branch default
200 200 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 201 --pull should override server's preferuncompressed
202 202 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
203 203 requesting all changes
204 204 adding changesets
205 205 adding manifests
206 206 adding file changes
207 207 added 2 changesets with 5 changes to 5 files
208 208 updating to branch default
209 209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 210
211 211 $ hg id http://user2@localhost:$HGPORT2/
212 212 abort: http authorization required for http://localhost:$HGPORT2/
213 213 [255]
214 214 $ hg id http://user:pass2@localhost:$HGPORT2/
215 215 abort: HTTP Error 403: no
216 216 [255]
217 217
218 218 $ hg -R dest tag -r tip top
219 219 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
220 220 pushing to http://user:***@localhost:$HGPORT2/
221 221 searching for changes
222 222 remote: adding changesets
223 223 remote: adding manifests
224 224 remote: adding file changes
225 225 remote: added 1 changesets with 1 changes to 1 files
226 226 $ hg rollback -q
227 227
228 228 $ cut -c38- ../access.log
229 229 "GET /?cmd=capabilities HTTP/1.1" 200 -
230 230 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
231 231 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
232 232 "GET /?cmd=capabilities HTTP/1.1" 200 -
233 233 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
234 234 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
235 235 "GET /?cmd=capabilities HTTP/1.1" 200 -
236 236 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
237 237 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
238 238 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
239 239 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
240 240 "GET /?cmd=capabilities HTTP/1.1" 200 -
241 241 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
242 242 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
243 243 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
244 244 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
245 245 "GET /?cmd=capabilities HTTP/1.1" 200 -
246 246 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
247 247 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
248 248 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
249 249 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
250 250 "GET /?cmd=capabilities HTTP/1.1" 200 -
251 251 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
252 252 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
253 253 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
254 254 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
255 255 "GET /?cmd=capabilities HTTP/1.1" 200 -
256 256 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
257 257 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
258 258 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
259 259 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
260 260 "GET /?cmd=capabilities HTTP/1.1" 200 -
261 261 "GET /?cmd=branchmap HTTP/1.1" 200 -
262 262 "GET /?cmd=stream_out HTTP/1.1" 401 -
263 263 "GET /?cmd=stream_out HTTP/1.1" 200 -
264 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%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%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
266 266 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
267 267 "GET /?cmd=capabilities HTTP/1.1" 200 -
268 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%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%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%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
271 271 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
272 272 "GET /?cmd=capabilities HTTP/1.1" 200 -
273 273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
274 274 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
275 275 "GET /?cmd=capabilities HTTP/1.1" 200 -
276 276 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
277 277 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
278 278 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces
279 279 "GET /?cmd=capabilities HTTP/1.1" 200 -
280 280 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872
281 281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases
282 282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
283 283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
284 284 "GET /?cmd=branchmap HTTP/1.1" 200 -
285 285 "GET /?cmd=branchmap HTTP/1.1" 200 -
286 286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
287 287 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365
288 288 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
289 289
290 290 $ cd ..
291 291
292 292 clone of serve with repo in root and unserved subrepo (issue2970)
293 293
294 294 $ hg --cwd test init sub
295 295 $ echo empty > test/sub/empty
296 296 $ hg --cwd test/sub add empty
297 297 $ hg --cwd test/sub commit -qm 'add empty'
298 298 $ hg --cwd test/sub tag -r 0 something
299 299 $ echo sub = sub > test/.hgsub
300 300 $ hg --cwd test add .hgsub
301 301 $ hg --cwd test commit -qm 'add subrepo'
302 302 $ hg clone http://localhost:$HGPORT noslash-clone
303 303 requesting all changes
304 304 adding changesets
305 305 adding manifests
306 306 adding file changes
307 307 added 3 changesets with 7 changes to 7 files
308 308 updating to branch default
309 309 abort: HTTP Error 404: Not Found
310 310 [255]
311 311 $ hg clone http://localhost:$HGPORT/ slash-clone
312 312 requesting all changes
313 313 adding changesets
314 314 adding manifests
315 315 adding file changes
316 316 added 3 changesets with 7 changes to 7 files
317 317 updating to branch default
318 318 abort: HTTP Error 404: Not Found
319 319 [255]
320 320
321 321 check error log
322 322
323 323 $ cat error.log
@@ -1,512 +1,512 b''
1 1 This test is a duplicate of 'test-http.t' feel free to factor out
2 2 parts that are not bundle1/bundle2 specific.
3 3
4 4 $ cat << EOF >> $HGRCPATH
5 5 > [experimental]
6 6 > # This test is dedicated to interaction through old bundle
7 7 > bundle2-exp = False
8 8 > EOF
9 9
10 10
11 11 This test tries to exercise the ssh functionality with a dummy script
12 12
13 13 creating 'remote' repo
14 14
15 15 $ hg init remote
16 16 $ cd remote
17 17 $ echo this > foo
18 18 $ echo this > fooO
19 19 $ hg ci -A -m "init" foo fooO
20 20
21 21 insert a closed branch (issue4428)
22 22
23 23 $ hg up null
24 24 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
25 25 $ hg branch closed
26 26 marked working directory as branch closed
27 27 (branches are permanent and global, did you want a bookmark?)
28 28 $ hg ci -mc0
29 29 $ hg ci --close-branch -mc1
30 30 $ hg up -q default
31 31
32 32 configure for serving
33 33
34 34 $ cat <<EOF > .hg/hgrc
35 35 > [server]
36 36 > uncompressed = True
37 37 >
38 38 > [hooks]
39 39 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
40 40 > EOF
41 41 $ cd ..
42 42
43 43 repo not found error
44 44
45 45 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
46 46 remote: abort: there is no Mercurial repository here (.hg not found)!
47 47 abort: no suitable response from remote hg!
48 48 [255]
49 49
50 50 non-existent absolute path
51 51
52 52 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
53 53 remote: abort: there is no Mercurial repository here (.hg not found)!
54 54 abort: no suitable response from remote hg!
55 55 [255]
56 56
57 57 clone remote via stream
58 58
59 59 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
60 60 streaming all changes
61 61 4 files to transfer, 615 bytes of data
62 62 transferred 615 bytes in * seconds (*) (glob)
63 63 searching for changes
64 64 no changes found
65 65 updating to branch default
66 66 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 67 $ cd local-stream
68 68 $ hg verify
69 69 checking changesets
70 70 checking manifests
71 71 crosschecking files in changesets and manifests
72 72 checking files
73 73 2 files, 3 changesets, 2 total revisions
74 74 $ hg branches
75 75 default 0:1160648e36ce
76 76 $ cd ..
77 77
78 78 clone bookmarks via stream
79 79
80 80 $ hg -R local-stream book mybook
81 81 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
82 82 streaming all changes
83 83 4 files to transfer, 615 bytes of data
84 84 transferred 615 bytes in * seconds (*) (glob)
85 85 searching for changes
86 86 no changes found
87 87 updating to branch default
88 88 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 89 $ cd stream2
90 90 $ hg book
91 91 mybook 0:1160648e36ce
92 92 $ cd ..
93 93 $ rm -rf local-stream stream2
94 94
95 95 clone remote via pull
96 96
97 97 $ hg clone -e dummyssh ssh://user@dummy/remote local
98 98 requesting all changes
99 99 adding changesets
100 100 adding manifests
101 101 adding file changes
102 102 added 3 changesets with 2 changes to 2 files
103 103 updating to branch default
104 104 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 105
106 106 verify
107 107
108 108 $ cd local
109 109 $ hg verify
110 110 checking changesets
111 111 checking manifests
112 112 crosschecking files in changesets and manifests
113 113 checking files
114 114 2 files, 3 changesets, 2 total revisions
115 115 $ echo '[hooks]' >> .hg/hgrc
116 116 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
117 117
118 118 empty default pull
119 119
120 120 $ hg paths
121 121 default = ssh://user@dummy/remote
122 122 $ hg pull -e dummyssh
123 123 pulling from ssh://user@dummy/remote
124 124 searching for changes
125 125 no changes found
126 126
127 127 pull from wrong ssh URL
128 128
129 129 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
130 130 pulling from ssh://user@dummy/doesnotexist
131 131 remote: abort: there is no Mercurial repository here (.hg not found)!
132 132 abort: no suitable response from remote hg!
133 133 [255]
134 134
135 135 local change
136 136
137 137 $ echo bleah > foo
138 138 $ hg ci -m "add"
139 139
140 140 updating rc
141 141
142 142 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
143 143 $ echo "[ui]" >> .hg/hgrc
144 144 $ echo "ssh = dummyssh" >> .hg/hgrc
145 145
146 146 find outgoing
147 147
148 148 $ hg out ssh://user@dummy/remote
149 149 comparing with ssh://user@dummy/remote
150 150 searching for changes
151 151 changeset: 3:a28a9d1a809c
152 152 tag: tip
153 153 parent: 0:1160648e36ce
154 154 user: test
155 155 date: Thu Jan 01 00:00:00 1970 +0000
156 156 summary: add
157 157
158 158
159 159 find incoming on the remote side
160 160
161 161 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
162 162 comparing with ssh://user@dummy/local
163 163 searching for changes
164 164 changeset: 3:a28a9d1a809c
165 165 tag: tip
166 166 parent: 0:1160648e36ce
167 167 user: test
168 168 date: Thu Jan 01 00:00:00 1970 +0000
169 169 summary: add
170 170
171 171
172 172 find incoming on the remote side (using absolute path)
173 173
174 174 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
175 175 comparing with ssh://user@dummy/$TESTTMP/local
176 176 searching for changes
177 177 changeset: 3:a28a9d1a809c
178 178 tag: tip
179 179 parent: 0:1160648e36ce
180 180 user: test
181 181 date: Thu Jan 01 00:00:00 1970 +0000
182 182 summary: add
183 183
184 184
185 185 push
186 186
187 187 $ hg push
188 188 pushing to ssh://user@dummy/remote
189 189 searching for changes
190 190 remote: adding changesets
191 191 remote: adding manifests
192 192 remote: adding file changes
193 193 remote: added 1 changesets with 1 changes to 1 files
194 194 $ cd ../remote
195 195
196 196 check remote tip
197 197
198 198 $ hg tip
199 199 changeset: 3:a28a9d1a809c
200 200 tag: tip
201 201 parent: 0:1160648e36ce
202 202 user: test
203 203 date: Thu Jan 01 00:00:00 1970 +0000
204 204 summary: add
205 205
206 206 $ hg verify
207 207 checking changesets
208 208 checking manifests
209 209 crosschecking files in changesets and manifests
210 210 checking files
211 211 2 files, 4 changesets, 3 total revisions
212 212 $ hg cat -r tip foo
213 213 bleah
214 214 $ echo z > z
215 215 $ hg ci -A -m z z
216 216 created new head
217 217
218 218 test pushkeys and bookmarks
219 219
220 220 $ cd ../local
221 221 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
222 222 bookmarks
223 223 namespaces
224 224 phases
225 225 $ hg book foo -r 0
226 226 $ hg out -B
227 227 comparing with ssh://user@dummy/remote
228 228 searching for changed bookmarks
229 229 foo 1160648e36ce
230 230 $ hg push -B foo
231 231 pushing to ssh://user@dummy/remote
232 232 searching for changes
233 233 no changes found
234 234 exporting bookmark foo
235 235 [1]
236 236 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
237 237 foo 1160648e36cec0054048a7edc4110c6f84fde594
238 238 $ hg book -f foo
239 239 $ hg push --traceback
240 240 pushing to ssh://user@dummy/remote
241 241 searching for changes
242 242 no changes found
243 243 updating bookmark foo
244 244 [1]
245 245 $ hg book -d foo
246 246 $ hg in -B
247 247 comparing with ssh://user@dummy/remote
248 248 searching for changed bookmarks
249 249 foo a28a9d1a809c
250 250 $ hg book -f -r 0 foo
251 251 $ hg pull -B foo
252 252 pulling from ssh://user@dummy/remote
253 253 no changes found
254 254 updating bookmark foo
255 255 $ hg book -d foo
256 256 $ hg push -B foo
257 257 pushing to ssh://user@dummy/remote
258 258 searching for changes
259 259 no changes found
260 260 deleting remote bookmark foo
261 261 [1]
262 262
263 263 a bad, evil hook that prints to stdout
264 264
265 265 $ cat <<EOF > $TESTTMP/badhook
266 266 > import sys
267 267 > sys.stdout.write("KABOOM\n")
268 268 > EOF
269 269
270 270 $ echo '[hooks]' >> ../remote/.hg/hgrc
271 271 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
272 272 $ echo r > r
273 273 $ hg ci -A -m z r
274 274
275 275 push should succeed even though it has an unexpected response
276 276
277 277 $ hg push
278 278 pushing to ssh://user@dummy/remote
279 279 searching for changes
280 280 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
281 281 remote: adding changesets
282 282 remote: adding manifests
283 283 remote: adding file changes
284 284 remote: added 1 changesets with 1 changes to 1 files
285 285 remote: KABOOM
286 286 $ hg -R ../remote heads
287 287 changeset: 5:1383141674ec
288 288 tag: tip
289 289 parent: 3:a28a9d1a809c
290 290 user: test
291 291 date: Thu Jan 01 00:00:00 1970 +0000
292 292 summary: z
293 293
294 294 changeset: 4:6c0482d977a3
295 295 parent: 0:1160648e36ce
296 296 user: test
297 297 date: Thu Jan 01 00:00:00 1970 +0000
298 298 summary: z
299 299
300 300
301 301 clone bookmarks
302 302
303 303 $ hg -R ../remote bookmark test
304 304 $ hg -R ../remote bookmarks
305 305 * test 4:6c0482d977a3
306 306 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
307 307 requesting all changes
308 308 adding changesets
309 309 adding manifests
310 310 adding file changes
311 311 added 6 changesets with 5 changes to 4 files (+1 heads)
312 312 updating to branch default
313 313 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
314 314 $ hg -R local-bookmarks bookmarks
315 315 test 4:6c0482d977a3
316 316
317 317 passwords in ssh urls are not supported
318 318 (we use a glob here because different Python versions give different
319 319 results here)
320 320
321 321 $ hg push ssh://user:erroneouspwd@dummy/remote
322 322 pushing to ssh://user:*@dummy/remote (glob)
323 323 abort: password in URL not supported!
324 324 [255]
325 325
326 326 $ cd ..
327 327
328 328 hide outer repo
329 329 $ hg init
330 330
331 331 Test remote paths with spaces (issue2983):
332 332
333 333 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
334 334 $ touch "$TESTTMP/a repo/test"
335 335 $ hg -R 'a repo' commit -A -m "test"
336 336 adding test
337 337 $ hg -R 'a repo' tag tag
338 338 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
339 339 73649e48688a
340 340
341 341 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
342 342 abort: unknown revision 'noNoNO'!
343 343 [255]
344 344
345 345 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
346 346
347 347 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
348 348 destination directory: a repo
349 349 abort: destination 'a repo' is not empty
350 350 [255]
351 351
352 352 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
353 353 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
354 354 parameters:
355 355
356 356 $ cat > ssh.sh << EOF
357 357 > userhost="\$1"
358 358 > SSH_ORIGINAL_COMMAND="\$2"
359 359 > export SSH_ORIGINAL_COMMAND
360 360 > PYTHONPATH="$PYTHONPATH"
361 361 > export PYTHONPATH
362 362 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
363 363 > EOF
364 364
365 365 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
366 366 73649e48688a
367 367
368 368 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
369 369 remote: Illegal repository "$TESTTMP/a'repo" (glob)
370 370 abort: no suitable response from remote hg!
371 371 [255]
372 372
373 373 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
374 374 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
375 375 abort: no suitable response from remote hg!
376 376 [255]
377 377
378 378 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
379 379 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
380 380 [255]
381 381
382 382 Test hg-ssh in read-only mode:
383 383
384 384 $ cat > ssh.sh << EOF
385 385 > userhost="\$1"
386 386 > SSH_ORIGINAL_COMMAND="\$2"
387 387 > export SSH_ORIGINAL_COMMAND
388 388 > PYTHONPATH="$PYTHONPATH"
389 389 > export PYTHONPATH
390 390 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
391 391 > EOF
392 392
393 393 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
394 394 requesting all changes
395 395 adding changesets
396 396 adding manifests
397 397 adding file changes
398 398 added 6 changesets with 5 changes to 4 files (+1 heads)
399 399 updating to branch default
400 400 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
401 401
402 402 $ cd read-only-local
403 403 $ echo "baz" > bar
404 404 $ hg ci -A -m "unpushable commit" bar
405 405 $ hg push --ssh "sh ../ssh.sh"
406 406 pushing to ssh://user@dummy/*/remote (glob)
407 407 searching for changes
408 408 remote: Permission denied
409 409 remote: abort: pretxnopen.hg-ssh hook failed
410 410 remote: Permission denied
411 411 remote: pushkey-abort: prepushkey.hg-ssh hook failed
412 412 updating 6c0482d977a3 to public failed!
413 413 [1]
414 414
415 415 $ cd ..
416 416
417 417 stderr from remote commands should be printed before stdout from local code (issue4336)
418 418
419 419 $ hg clone remote stderr-ordering
420 420 updating to branch default
421 421 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
422 422 $ cd stderr-ordering
423 423 $ cat >> localwrite.py << EOF
424 424 > from mercurial import exchange, extensions
425 425 >
426 426 > def wrappedpush(orig, repo, *args, **kwargs):
427 427 > res = orig(repo, *args, **kwargs)
428 428 > repo.ui.write('local stdout\n')
429 429 > return res
430 430 >
431 431 > def extsetup(ui):
432 432 > extensions.wrapfunction(exchange, 'push', wrappedpush)
433 433 > EOF
434 434
435 435 $ cat >> .hg/hgrc << EOF
436 436 > [paths]
437 437 > default-push = ssh://user@dummy/remote
438 438 > [ui]
439 439 > ssh = dummyssh
440 440 > [extensions]
441 441 > localwrite = localwrite.py
442 442 > EOF
443 443
444 444 $ echo localwrite > foo
445 445 $ hg commit -m 'testing localwrite'
446 446 $ hg push
447 447 pushing to ssh://user@dummy/remote
448 448 searching for changes
449 449 remote: adding changesets
450 450 remote: adding manifests
451 451 remote: adding file changes
452 452 remote: added 1 changesets with 1 changes to 1 files
453 453 remote: KABOOM
454 454 local stdout
455 455
456 456 debug output
457 457
458 458 $ hg pull --debug ssh://user@dummy/remote
459 459 pulling from ssh://user@dummy/remote
460 460 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
461 461 sending hello command
462 462 sending between command
463 remote: 286
464 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
463 remote: 335
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
465 465 remote: 1
466 466 preparing listkeys for "bookmarks"
467 467 sending listkeys command
468 468 received listkey for "bookmarks": 45 bytes
469 469 query 1; heads
470 470 sending batch command
471 471 searching for changes
472 472 all remote heads known locally
473 473 no changes found
474 474 preparing listkeys for "phases"
475 475 sending listkeys command
476 476 received listkey for "phases": 15 bytes
477 477 checking for updated bookmarks
478 478
479 479 $ cd ..
480 480
481 481 $ cat dummylog
482 482 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
483 483 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
484 484 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
485 485 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
486 486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 488 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
489 489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 490 Got arguments 1:user@dummy 2:hg -R local serve --stdio
491 491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
492 492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 493 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
494 494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 503 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
504 504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 505 Got arguments 1:user@dummy 2:hg init 'a repo'
506 506 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
507 507 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
508 508 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
509 509 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
510 510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
511 511 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:127.0.0.1 (glob)
512 512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
@@ -1,503 +1,503 b''
1 1
2 2 This test tries to exercise the ssh functionality with a dummy script
3 3
4 4 creating 'remote' repo
5 5
6 6 $ hg init remote
7 7 $ cd remote
8 8 $ echo this > foo
9 9 $ echo this > fooO
10 10 $ hg ci -A -m "init" foo fooO
11 11
12 12 insert a closed branch (issue4428)
13 13
14 14 $ hg up null
15 15 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
16 16 $ hg branch closed
17 17 marked working directory as branch closed
18 18 (branches are permanent and global, did you want a bookmark?)
19 19 $ hg ci -mc0
20 20 $ hg ci --close-branch -mc1
21 21 $ hg up -q default
22 22
23 23 configure for serving
24 24
25 25 $ cat <<EOF > .hg/hgrc
26 26 > [server]
27 27 > uncompressed = True
28 28 >
29 29 > [hooks]
30 30 > changegroup = printenv.py changegroup-in-remote 0 ../dummylog
31 31 > EOF
32 32 $ cd ..
33 33
34 34 repo not found error
35 35
36 36 $ hg clone -e dummyssh ssh://user@dummy/nonexistent local
37 37 remote: abort: there is no Mercurial repository here (.hg not found)!
38 38 abort: no suitable response from remote hg!
39 39 [255]
40 40
41 41 non-existent absolute path
42 42
43 43 $ hg clone -e dummyssh ssh://user@dummy//`pwd`/nonexistent local
44 44 remote: abort: there is no Mercurial repository here (.hg not found)!
45 45 abort: no suitable response from remote hg!
46 46 [255]
47 47
48 48 clone remote via stream
49 49
50 50 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/remote local-stream
51 51 streaming all changes
52 52 4 files to transfer, 615 bytes of data
53 53 transferred 615 bytes in * seconds (*) (glob)
54 54 searching for changes
55 55 no changes found
56 56 updating to branch default
57 57 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 58 $ cd local-stream
59 59 $ hg verify
60 60 checking changesets
61 61 checking manifests
62 62 crosschecking files in changesets and manifests
63 63 checking files
64 64 2 files, 3 changesets, 2 total revisions
65 65 $ hg branches
66 66 default 0:1160648e36ce
67 67 $ cd ..
68 68
69 69 clone bookmarks via stream
70 70
71 71 $ hg -R local-stream book mybook
72 72 $ hg clone -e dummyssh --uncompressed ssh://user@dummy/local-stream stream2
73 73 streaming all changes
74 74 4 files to transfer, 615 bytes of data
75 75 transferred 615 bytes in * seconds (*) (glob)
76 76 searching for changes
77 77 no changes found
78 78 updating to branch default
79 79 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 80 $ cd stream2
81 81 $ hg book
82 82 mybook 0:1160648e36ce
83 83 $ cd ..
84 84 $ rm -rf local-stream stream2
85 85
86 86 clone remote via pull
87 87
88 88 $ hg clone -e dummyssh ssh://user@dummy/remote local
89 89 requesting all changes
90 90 adding changesets
91 91 adding manifests
92 92 adding file changes
93 93 added 3 changesets with 2 changes to 2 files
94 94 updating to branch default
95 95 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
96 96
97 97 verify
98 98
99 99 $ cd local
100 100 $ hg verify
101 101 checking changesets
102 102 checking manifests
103 103 crosschecking files in changesets and manifests
104 104 checking files
105 105 2 files, 3 changesets, 2 total revisions
106 106 $ echo '[hooks]' >> .hg/hgrc
107 107 $ echo "changegroup = printenv.py changegroup-in-local 0 ../dummylog" >> .hg/hgrc
108 108
109 109 empty default pull
110 110
111 111 $ hg paths
112 112 default = ssh://user@dummy/remote
113 113 $ hg pull -e dummyssh
114 114 pulling from ssh://user@dummy/remote
115 115 searching for changes
116 116 no changes found
117 117
118 118 pull from wrong ssh URL
119 119
120 120 $ hg pull -e dummyssh ssh://user@dummy/doesnotexist
121 121 pulling from ssh://user@dummy/doesnotexist
122 122 remote: abort: there is no Mercurial repository here (.hg not found)!
123 123 abort: no suitable response from remote hg!
124 124 [255]
125 125
126 126 local change
127 127
128 128 $ echo bleah > foo
129 129 $ hg ci -m "add"
130 130
131 131 updating rc
132 132
133 133 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
134 134 $ echo "[ui]" >> .hg/hgrc
135 135 $ echo "ssh = dummyssh" >> .hg/hgrc
136 136
137 137 find outgoing
138 138
139 139 $ hg out ssh://user@dummy/remote
140 140 comparing with ssh://user@dummy/remote
141 141 searching for changes
142 142 changeset: 3:a28a9d1a809c
143 143 tag: tip
144 144 parent: 0:1160648e36ce
145 145 user: test
146 146 date: Thu Jan 01 00:00:00 1970 +0000
147 147 summary: add
148 148
149 149
150 150 find incoming on the remote side
151 151
152 152 $ hg incoming -R ../remote -e dummyssh ssh://user@dummy/local
153 153 comparing with ssh://user@dummy/local
154 154 searching for changes
155 155 changeset: 3:a28a9d1a809c
156 156 tag: tip
157 157 parent: 0:1160648e36ce
158 158 user: test
159 159 date: Thu Jan 01 00:00:00 1970 +0000
160 160 summary: add
161 161
162 162
163 163 find incoming on the remote side (using absolute path)
164 164
165 165 $ hg incoming -R ../remote -e dummyssh "ssh://user@dummy/`pwd`"
166 166 comparing with ssh://user@dummy/$TESTTMP/local
167 167 searching for changes
168 168 changeset: 3:a28a9d1a809c
169 169 tag: tip
170 170 parent: 0:1160648e36ce
171 171 user: test
172 172 date: Thu Jan 01 00:00:00 1970 +0000
173 173 summary: add
174 174
175 175
176 176 push
177 177
178 178 $ hg push
179 179 pushing to ssh://user@dummy/remote
180 180 searching for changes
181 181 remote: adding changesets
182 182 remote: adding manifests
183 183 remote: adding file changes
184 184 remote: added 1 changesets with 1 changes to 1 files
185 185 $ cd ../remote
186 186
187 187 check remote tip
188 188
189 189 $ hg tip
190 190 changeset: 3:a28a9d1a809c
191 191 tag: tip
192 192 parent: 0:1160648e36ce
193 193 user: test
194 194 date: Thu Jan 01 00:00:00 1970 +0000
195 195 summary: add
196 196
197 197 $ hg verify
198 198 checking changesets
199 199 checking manifests
200 200 crosschecking files in changesets and manifests
201 201 checking files
202 202 2 files, 4 changesets, 3 total revisions
203 203 $ hg cat -r tip foo
204 204 bleah
205 205 $ echo z > z
206 206 $ hg ci -A -m z z
207 207 created new head
208 208
209 209 test pushkeys and bookmarks
210 210
211 211 $ cd ../local
212 212 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote namespaces
213 213 bookmarks
214 214 namespaces
215 215 phases
216 216 $ hg book foo -r 0
217 217 $ hg out -B
218 218 comparing with ssh://user@dummy/remote
219 219 searching for changed bookmarks
220 220 foo 1160648e36ce
221 221 $ hg push -B foo
222 222 pushing to ssh://user@dummy/remote
223 223 searching for changes
224 224 no changes found
225 225 exporting bookmark foo
226 226 [1]
227 227 $ hg debugpushkey --config ui.ssh=dummyssh ssh://user@dummy/remote bookmarks
228 228 foo 1160648e36cec0054048a7edc4110c6f84fde594
229 229 $ hg book -f foo
230 230 $ hg push --traceback
231 231 pushing to ssh://user@dummy/remote
232 232 searching for changes
233 233 no changes found
234 234 updating bookmark foo
235 235 [1]
236 236 $ hg book -d foo
237 237 $ hg in -B
238 238 comparing with ssh://user@dummy/remote
239 239 searching for changed bookmarks
240 240 foo a28a9d1a809c
241 241 $ hg book -f -r 0 foo
242 242 $ hg pull -B foo
243 243 pulling from ssh://user@dummy/remote
244 244 no changes found
245 245 updating bookmark foo
246 246 $ hg book -d foo
247 247 $ hg push -B foo
248 248 pushing to ssh://user@dummy/remote
249 249 searching for changes
250 250 no changes found
251 251 deleting remote bookmark foo
252 252 [1]
253 253
254 254 a bad, evil hook that prints to stdout
255 255
256 256 $ cat <<EOF > $TESTTMP/badhook
257 257 > import sys
258 258 > sys.stdout.write("KABOOM\n")
259 259 > EOF
260 260
261 261 $ echo '[hooks]' >> ../remote/.hg/hgrc
262 262 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
263 263 $ echo r > r
264 264 $ hg ci -A -m z r
265 265
266 266 push should succeed even though it has an unexpected response
267 267
268 268 $ hg push
269 269 pushing to ssh://user@dummy/remote
270 270 searching for changes
271 271 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
272 272 remote: adding changesets
273 273 remote: adding manifests
274 274 remote: adding file changes
275 275 remote: added 1 changesets with 1 changes to 1 files
276 276 remote: KABOOM
277 277 $ hg -R ../remote heads
278 278 changeset: 5:1383141674ec
279 279 tag: tip
280 280 parent: 3:a28a9d1a809c
281 281 user: test
282 282 date: Thu Jan 01 00:00:00 1970 +0000
283 283 summary: z
284 284
285 285 changeset: 4:6c0482d977a3
286 286 parent: 0:1160648e36ce
287 287 user: test
288 288 date: Thu Jan 01 00:00:00 1970 +0000
289 289 summary: z
290 290
291 291
292 292 clone bookmarks
293 293
294 294 $ hg -R ../remote bookmark test
295 295 $ hg -R ../remote bookmarks
296 296 * test 4:6c0482d977a3
297 297 $ hg clone -e dummyssh ssh://user@dummy/remote local-bookmarks
298 298 requesting all changes
299 299 adding changesets
300 300 adding manifests
301 301 adding file changes
302 302 added 6 changesets with 5 changes to 4 files (+1 heads)
303 303 updating to branch default
304 304 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
305 305 $ hg -R local-bookmarks bookmarks
306 306 test 4:6c0482d977a3
307 307
308 308 passwords in ssh urls are not supported
309 309 (we use a glob here because different Python versions give different
310 310 results here)
311 311
312 312 $ hg push ssh://user:erroneouspwd@dummy/remote
313 313 pushing to ssh://user:*@dummy/remote (glob)
314 314 abort: password in URL not supported!
315 315 [255]
316 316
317 317 $ cd ..
318 318
319 319 hide outer repo
320 320 $ hg init
321 321
322 322 Test remote paths with spaces (issue2983):
323 323
324 324 $ hg init --ssh dummyssh "ssh://user@dummy/a repo"
325 325 $ touch "$TESTTMP/a repo/test"
326 326 $ hg -R 'a repo' commit -A -m "test"
327 327 adding test
328 328 $ hg -R 'a repo' tag tag
329 329 $ hg id --ssh dummyssh "ssh://user@dummy/a repo"
330 330 73649e48688a
331 331
332 332 $ hg id --ssh dummyssh "ssh://user@dummy/a repo#noNoNO"
333 333 abort: unknown revision 'noNoNO'!
334 334 [255]
335 335
336 336 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
337 337
338 338 $ hg clone --ssh dummyssh "ssh://user@dummy/a repo"
339 339 destination directory: a repo
340 340 abort: destination 'a repo' is not empty
341 341 [255]
342 342
343 343 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
344 344 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
345 345 parameters:
346 346
347 347 $ cat > ssh.sh << EOF
348 348 > userhost="\$1"
349 349 > SSH_ORIGINAL_COMMAND="\$2"
350 350 > export SSH_ORIGINAL_COMMAND
351 351 > PYTHONPATH="$PYTHONPATH"
352 352 > export PYTHONPATH
353 353 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
354 354 > EOF
355 355
356 356 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
357 357 73649e48688a
358 358
359 359 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
360 360 remote: Illegal repository "$TESTTMP/a'repo" (glob)
361 361 abort: no suitable response from remote hg!
362 362 [255]
363 363
364 364 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
365 365 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
366 366 abort: no suitable response from remote hg!
367 367 [255]
368 368
369 369 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
370 370 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
371 371 [255]
372 372
373 373 Test hg-ssh in read-only mode:
374 374
375 375 $ cat > ssh.sh << EOF
376 376 > userhost="\$1"
377 377 > SSH_ORIGINAL_COMMAND="\$2"
378 378 > export SSH_ORIGINAL_COMMAND
379 379 > PYTHONPATH="$PYTHONPATH"
380 380 > export PYTHONPATH
381 381 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
382 382 > EOF
383 383
384 384 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
385 385 requesting all changes
386 386 adding changesets
387 387 adding manifests
388 388 adding file changes
389 389 added 6 changesets with 5 changes to 4 files (+1 heads)
390 390 updating to branch default
391 391 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
392 392
393 393 $ cd read-only-local
394 394 $ echo "baz" > bar
395 395 $ hg ci -A -m "unpushable commit" bar
396 396 $ hg push --ssh "sh ../ssh.sh"
397 397 pushing to ssh://user@dummy/*/remote (glob)
398 398 searching for changes
399 399 remote: Permission denied
400 400 abort: pretxnopen.hg-ssh hook failed
401 401 [255]
402 402
403 403 $ cd ..
404 404
405 405 stderr from remote commands should be printed before stdout from local code (issue4336)
406 406
407 407 $ hg clone remote stderr-ordering
408 408 updating to branch default
409 409 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
410 410 $ cd stderr-ordering
411 411 $ cat >> localwrite.py << EOF
412 412 > from mercurial import exchange, extensions
413 413 >
414 414 > def wrappedpush(orig, repo, *args, **kwargs):
415 415 > res = orig(repo, *args, **kwargs)
416 416 > repo.ui.write('local stdout\n')
417 417 > return res
418 418 >
419 419 > def extsetup(ui):
420 420 > extensions.wrapfunction(exchange, 'push', wrappedpush)
421 421 > EOF
422 422
423 423 $ cat >> .hg/hgrc << EOF
424 424 > [paths]
425 425 > default-push = ssh://user@dummy/remote
426 426 > [ui]
427 427 > ssh = dummyssh
428 428 > [extensions]
429 429 > localwrite = localwrite.py
430 430 > EOF
431 431
432 432 $ echo localwrite > foo
433 433 $ hg commit -m 'testing localwrite'
434 434 $ hg push
435 435 pushing to ssh://user@dummy/remote
436 436 searching for changes
437 437 remote: adding changesets
438 438 remote: adding manifests
439 439 remote: adding file changes
440 440 remote: added 1 changesets with 1 changes to 1 files
441 441 remote: KABOOM
442 442 local stdout
443 443
444 444 debug output
445 445
446 446 $ hg pull --debug ssh://user@dummy/remote
447 447 pulling from ssh://user@dummy/remote
448 448 running dummyssh user@dummy ('|")hg -R remote serve --stdio('|") (re)
449 449 sending hello command
450 450 sending between command
451 remote: 286
452 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
451 remote: 335
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
453 453 remote: 1
454 454 query 1; heads
455 455 sending batch command
456 456 searching for changes
457 457 all remote heads known locally
458 458 no changes found
459 459 sending getbundle command
460 460 bundle2-input-bundle: with-transaction
461 461 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
462 462 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
463 463 bundle2-input-part: total payload size 45
464 464 bundle2-input-bundle: 1 parts total
465 465 checking for updated bookmarks
466 466 preparing listkeys for "phases"
467 467 sending listkeys command
468 468 received listkey for "phases": 15 bytes
469 469
470 470 $ cd ..
471 471
472 472 $ cat dummylog
473 473 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
474 474 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
475 475 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
476 476 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
477 477 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
478 478 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
479 479 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
480 480 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
481 481 Got arguments 1:user@dummy 2:hg -R local serve --stdio
482 482 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
483 483 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
484 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 485 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
486 486 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
487 487 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 489 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 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 495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 496 Got arguments 1:user@dummy 2:hg init 'a repo'
497 497 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
498 498 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
499 499 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
500 500 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
501 501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 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 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