##// END OF EJS Templates
bundle2: part handler for processing .hgtags fnodes mappings...
Gregory Szorc -
r25401:d2920135 default
parent child Browse files
Show More
@@ -1,1362 +1,1384 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 import changegroup, error
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 1109 'listkeys': (),
1110 1110 'pushkey': (),
1111 1111 'digests': tuple(sorted(util.DIGESTS.keys())),
1112 1112 'remote-changegroup': ('http', 'https'),
1113 'hgtagsfnodes': (),
1113 1114 }
1114 1115
1115 1116 def getrepocaps(repo, allowpushback=False):
1116 1117 """return the bundle2 capabilities for a given repo
1117 1118
1118 1119 Exists to allow extensions (like evolution) to mutate the capabilities.
1119 1120 """
1120 1121 caps = capabilities.copy()
1121 1122 caps['changegroup'] = tuple(sorted(changegroup.packermap.keys()))
1122 1123 if obsolete.isenabled(repo, obsolete.exchangeopt):
1123 1124 supportedformat = tuple('V%i' % v for v in obsolete.formats)
1124 1125 caps['obsmarkers'] = supportedformat
1125 1126 if allowpushback:
1126 1127 caps['pushback'] = ()
1127 1128 return caps
1128 1129
1129 1130 def bundle2caps(remote):
1130 1131 """return the bundle capabilities of a peer as dict"""
1131 1132 raw = remote.capable('bundle2')
1132 1133 if not raw and raw != '':
1133 1134 return {}
1134 1135 capsblob = urllib.unquote(remote.capable('bundle2'))
1135 1136 return decodecaps(capsblob)
1136 1137
1137 1138 def obsmarkersversion(caps):
1138 1139 """extract the list of supported obsmarkers versions from a bundle2caps dict
1139 1140 """
1140 1141 obscaps = caps.get('obsmarkers', ())
1141 1142 return [int(c[1:]) for c in obscaps if c.startswith('V')]
1142 1143
1143 1144 @parthandler('changegroup', ('version',))
1144 1145 def handlechangegroup(op, inpart):
1145 1146 """apply a changegroup part on the repo
1146 1147
1147 1148 This is a very early implementation that will massive rework before being
1148 1149 inflicted to any end-user.
1149 1150 """
1150 1151 # Make sure we trigger a transaction creation
1151 1152 #
1152 1153 # The addchangegroup function will get a transaction object by itself, but
1153 1154 # we need to make sure we trigger the creation of a transaction object used
1154 1155 # for the whole processing scope.
1155 1156 op.gettransaction()
1156 1157 unpackerversion = inpart.params.get('version', '01')
1157 1158 # We should raise an appropriate exception here
1158 1159 unpacker = changegroup.packermap[unpackerversion][1]
1159 1160 cg = unpacker(inpart, 'UN')
1160 1161 # the source and url passed here are overwritten by the one contained in
1161 1162 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1162 1163 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1163 1164 op.records.add('changegroup', {'return': ret})
1164 1165 if op.reply is not None:
1165 1166 # This is definitely not the final form of this
1166 1167 # return. But one need to start somewhere.
1167 1168 part = op.reply.newpart('reply:changegroup', mandatory=False)
1168 1169 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1169 1170 part.addparam('return', '%i' % ret, mandatory=False)
1170 1171 assert not inpart.read()
1171 1172
1172 1173 _remotechangegroupparams = tuple(['url', 'size', 'digests'] +
1173 1174 ['digest:%s' % k for k in util.DIGESTS.keys()])
1174 1175 @parthandler('remote-changegroup', _remotechangegroupparams)
1175 1176 def handleremotechangegroup(op, inpart):
1176 1177 """apply a bundle10 on the repo, given an url and validation information
1177 1178
1178 1179 All the information about the remote bundle to import are given as
1179 1180 parameters. The parameters include:
1180 1181 - url: the url to the bundle10.
1181 1182 - size: the bundle10 file size. It is used to validate what was
1182 1183 retrieved by the client matches the server knowledge about the bundle.
1183 1184 - digests: a space separated list of the digest types provided as
1184 1185 parameters.
1185 1186 - digest:<digest-type>: the hexadecimal representation of the digest with
1186 1187 that name. Like the size, it is used to validate what was retrieved by
1187 1188 the client matches what the server knows about the bundle.
1188 1189
1189 1190 When multiple digest types are given, all of them are checked.
1190 1191 """
1191 1192 try:
1192 1193 raw_url = inpart.params['url']
1193 1194 except KeyError:
1194 1195 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'url')
1195 1196 parsed_url = util.url(raw_url)
1196 1197 if parsed_url.scheme not in capabilities['remote-changegroup']:
1197 1198 raise util.Abort(_('remote-changegroup does not support %s urls') %
1198 1199 parsed_url.scheme)
1199 1200
1200 1201 try:
1201 1202 size = int(inpart.params['size'])
1202 1203 except ValueError:
1203 1204 raise util.Abort(_('remote-changegroup: invalid value for param "%s"')
1204 1205 % 'size')
1205 1206 except KeyError:
1206 1207 raise util.Abort(_('remote-changegroup: missing "%s" param') % 'size')
1207 1208
1208 1209 digests = {}
1209 1210 for typ in inpart.params.get('digests', '').split():
1210 1211 param = 'digest:%s' % typ
1211 1212 try:
1212 1213 value = inpart.params[param]
1213 1214 except KeyError:
1214 1215 raise util.Abort(_('remote-changegroup: missing "%s" param') %
1215 1216 param)
1216 1217 digests[typ] = value
1217 1218
1218 1219 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
1219 1220
1220 1221 # Make sure we trigger a transaction creation
1221 1222 #
1222 1223 # The addchangegroup function will get a transaction object by itself, but
1223 1224 # we need to make sure we trigger the creation of a transaction object used
1224 1225 # for the whole processing scope.
1225 1226 op.gettransaction()
1226 1227 import exchange
1227 1228 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
1228 1229 if not isinstance(cg, changegroup.cg1unpacker):
1229 1230 raise util.Abort(_('%s: not a bundle version 1.0') %
1230 1231 util.hidepassword(raw_url))
1231 1232 ret = changegroup.addchangegroup(op.repo, cg, 'bundle2', 'bundle2')
1232 1233 op.records.add('changegroup', {'return': ret})
1233 1234 if op.reply is not None:
1234 1235 # This is definitely not the final form of this
1235 1236 # return. But one need to start somewhere.
1236 1237 part = op.reply.newpart('reply:changegroup')
1237 1238 part.addparam('in-reply-to', str(inpart.id), mandatory=False)
1238 1239 part.addparam('return', '%i' % ret, mandatory=False)
1239 1240 try:
1240 1241 real_part.validate()
1241 1242 except util.Abort, e:
1242 1243 raise util.Abort(_('bundle at %s is corrupted:\n%s') %
1243 1244 (util.hidepassword(raw_url), str(e)))
1244 1245 assert not inpart.read()
1245 1246
1246 1247 @parthandler('reply:changegroup', ('return', 'in-reply-to'))
1247 1248 def handlereplychangegroup(op, inpart):
1248 1249 ret = int(inpart.params['return'])
1249 1250 replyto = int(inpart.params['in-reply-to'])
1250 1251 op.records.add('changegroup', {'return': ret}, replyto)
1251 1252
1252 1253 @parthandler('check:heads')
1253 1254 def handlecheckheads(op, inpart):
1254 1255 """check that head of the repo did not change
1255 1256
1256 1257 This is used to detect a push race when using unbundle.
1257 1258 This replaces the "heads" argument of unbundle."""
1258 1259 h = inpart.read(20)
1259 1260 heads = []
1260 1261 while len(h) == 20:
1261 1262 heads.append(h)
1262 1263 h = inpart.read(20)
1263 1264 assert not h
1264 1265 if heads != op.repo.heads():
1265 1266 raise error.PushRaced('repository changed while pushing - '
1266 1267 'please try again')
1267 1268
1268 1269 @parthandler('output')
1269 1270 def handleoutput(op, inpart):
1270 1271 """forward output captured on the server to the client"""
1271 1272 for line in inpart.read().splitlines():
1272 1273 op.ui.status(('remote: %s\n' % line))
1273 1274
1274 1275 @parthandler('replycaps')
1275 1276 def handlereplycaps(op, inpart):
1276 1277 """Notify that a reply bundle should be created
1277 1278
1278 1279 The payload contains the capabilities information for the reply"""
1279 1280 caps = decodecaps(inpart.read())
1280 1281 if op.reply is None:
1281 1282 op.reply = bundle20(op.ui, caps)
1282 1283
1283 1284 @parthandler('error:abort', ('message', 'hint'))
1284 1285 def handleerrorabort(op, inpart):
1285 1286 """Used to transmit abort error over the wire"""
1286 1287 raise util.Abort(inpart.params['message'], hint=inpart.params.get('hint'))
1287 1288
1288 1289 @parthandler('error:unsupportedcontent', ('parttype', 'params'))
1289 1290 def handleerrorunsupportedcontent(op, inpart):
1290 1291 """Used to transmit unknown content error over the wire"""
1291 1292 kwargs = {}
1292 1293 parttype = inpart.params.get('parttype')
1293 1294 if parttype is not None:
1294 1295 kwargs['parttype'] = parttype
1295 1296 params = inpart.params.get('params')
1296 1297 if params is not None:
1297 1298 kwargs['params'] = params.split('\0')
1298 1299
1299 1300 raise error.UnsupportedPartError(**kwargs)
1300 1301
1301 1302 @parthandler('error:pushraced', ('message',))
1302 1303 def handleerrorpushraced(op, inpart):
1303 1304 """Used to transmit push race error over the wire"""
1304 1305 raise error.ResponseError(_('push failed:'), inpart.params['message'])
1305 1306
1306 1307 @parthandler('listkeys', ('namespace',))
1307 1308 def handlelistkeys(op, inpart):
1308 1309 """retrieve pushkey namespace content stored in a bundle2"""
1309 1310 namespace = inpart.params['namespace']
1310 1311 r = pushkey.decodekeys(inpart.read())
1311 1312 op.records.add('listkeys', (namespace, r))
1312 1313
1313 1314 @parthandler('pushkey', ('namespace', 'key', 'old', 'new'))
1314 1315 def handlepushkey(op, inpart):
1315 1316 """process a pushkey request"""
1316 1317 dec = pushkey.decode
1317 1318 namespace = dec(inpart.params['namespace'])
1318 1319 key = dec(inpart.params['key'])
1319 1320 old = dec(inpart.params['old'])
1320 1321 new = dec(inpart.params['new'])
1321 1322 ret = op.repo.pushkey(namespace, key, old, new)
1322 1323 record = {'namespace': namespace,
1323 1324 'key': key,
1324 1325 'old': old,
1325 1326 'new': new}
1326 1327 op.records.add('pushkey', record)
1327 1328 if op.reply is not None:
1328 1329 rpart = op.reply.newpart('reply:pushkey')
1329 1330 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1330 1331 rpart.addparam('return', '%i' % ret, mandatory=False)
1331 1332
1332 1333 @parthandler('reply:pushkey', ('return', 'in-reply-to'))
1333 1334 def handlepushkeyreply(op, inpart):
1334 1335 """retrieve the result of a pushkey request"""
1335 1336 ret = int(inpart.params['return'])
1336 1337 partid = int(inpart.params['in-reply-to'])
1337 1338 op.records.add('pushkey', {'return': ret}, partid)
1338 1339
1339 1340 @parthandler('obsmarkers')
1340 1341 def handleobsmarker(op, inpart):
1341 1342 """add a stream of obsmarkers to the repo"""
1342 1343 tr = op.gettransaction()
1343 1344 markerdata = inpart.read()
1344 1345 if op.ui.config('experimental', 'obsmarkers-exchange-debug', False):
1345 1346 op.ui.write(('obsmarker-exchange: %i bytes received\n')
1346 1347 % len(markerdata))
1347 1348 new = op.repo.obsstore.mergemarkers(tr, markerdata)
1348 1349 if new:
1349 1350 op.repo.ui.status(_('%i new obsolescence markers\n') % new)
1350 1351 op.records.add('obsmarkers', {'new': new})
1351 1352 if op.reply is not None:
1352 1353 rpart = op.reply.newpart('reply:obsmarkers')
1353 1354 rpart.addparam('in-reply-to', str(inpart.id), mandatory=False)
1354 1355 rpart.addparam('new', '%i' % new, mandatory=False)
1355 1356
1356 1357
1357 1358 @parthandler('reply:obsmarkers', ('new', 'in-reply-to'))
1358 1359 def handlepushkeyreply(op, inpart):
1359 1360 """retrieve the result of a pushkey request"""
1360 1361 ret = int(inpart.params['new'])
1361 1362 partid = int(inpart.params['in-reply-to'])
1362 1363 op.records.add('obsmarkers', {'new': ret}, partid)
1364
1365 @parthandler('hgtagsfnodes')
1366 def handlehgtagsfnodes(op, inpart):
1367 """Applies .hgtags fnodes cache entries to the local repo.
1368
1369 Payload is pairs of 20 byte changeset nodes and filenodes.
1370 """
1371 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
1372
1373 count = 0
1374 while True:
1375 node = inpart.read(20)
1376 fnode = inpart.read(20)
1377 if len(node) < 20 or len(fnode) < 20:
1378 op.ui.debug('received incomplete .hgtags fnodes data, ignoring\n')
1379 break
1380 cache.setfnode(node, fnode)
1381 count += 1
1382
1383 cache.write()
1384 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" 93 bytes payload
102 bundle2-output-part: "replycaps" 106 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" (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 93
108 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
166 bundle2-output-part: "replycaps" 106 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" (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 93
172 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
233 bundle2-output-part: "replycaps" 106 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" (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 93
239 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
310 bundle2-output-part: "replycaps" 106 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" (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 93
316 bundle2-input-part: total payload size 106
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" 93 bytes payload
375 bundle2-output-part: "replycaps" 106 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" (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 93
381 bundle2-input-part: total payload size 106
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" 93 bytes payload
445 bundle2-output-part: "replycaps" 106 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" (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 93
451 bundle2-input-part: total payload size 106
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" 93 bytes payload
512 bundle2-output-part: "replycaps" 106 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" (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 93
518 bundle2-input-part: total payload size 106
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" 93 bytes payload
584 bundle2-output-part: "replycaps" 106 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" (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 93
590 bundle2-input-part: total payload size 106
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" 93 bytes payload
653 bundle2-output-part: "replycaps" 106 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" (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 93
659 bundle2-input-part: total payload size 106
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" 93 bytes payload
724 bundle2-output-part: "replycaps" 106 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" (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 93
730 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
808 bundle2-output-part: "replycaps" 106 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" (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 93
814 bundle2-input-part: total payload size 106
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" 93 bytes payload
886 bundle2-output-part: "replycaps" 106 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" (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 93
892 bundle2-input-part: total payload size 106
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" 93 bytes payload
959 bundle2-output-part: "replycaps" 106 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" (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 93
965 bundle2-input-part: total payload size 106
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" 93 bytes payload
1043 bundle2-output-part: "replycaps" 106 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" (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 93
1049 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
1130 bundle2-output-part: "replycaps" 106 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" (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 93
1136 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
1213 bundle2-output-part: "replycaps" 106 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" (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 93
1219 bundle2-input-part: total payload size 106
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" 93 bytes payload
1289 bundle2-output-part: "replycaps" 106 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" (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 93
1295 bundle2-input-part: total payload size 106
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" (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" 93 bytes payload
1373 bundle2-output-part: "replycaps" 106 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" (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 93
1379 bundle2-input-part: total payload size 106
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" 93 bytes payload
1488 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1492 1492 bundle2-output-part: "pushkey" (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 93
1495 bundle2-input-part: total payload size 106
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" (params: 4 mandatory) supported
1527 1527 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1528 1528 bundle2-input-part: "pushkey" (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" 93 bytes payload
1577 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1581 1581 bundle2-output-part: "pushkey" (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 93
1584 bundle2-input-part: total payload size 106
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" 93 bytes payload
1651 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1655 1655 bundle2-output-part: "pushkey" (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 93
1658 bundle2-input-part: total payload size 106
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" 93 bytes payload
1721 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1725 1725 bundle2-output-part: "pushkey" (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 93
1728 bundle2-input-part: total payload size 106
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" 93 bytes payload
1785 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1789 1789 bundle2-output-part: "pushkey" (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 93
1792 bundle2-input-part: total payload size 106
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" (params: 4 mandatory) supported
1824 1824 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1825 1825 bundle2-input-part: "pushkey" (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" 93 bytes payload
1879 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1883 1883 bundle2-output-part: "pushkey" (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 93
1886 bundle2-input-part: total payload size 106
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" (params: 4 mandatory) supported
1918 1918 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1919 1919 bundle2-input-part: "pushkey" (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" 93 bytes payload
1972 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
1976 1976 bundle2-output-part: "pushkey" (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 93
1979 bundle2-input-part: total payload size 106
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" 93 bytes payload
2041 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
2045 2045 bundle2-output-part: "pushkey" (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 93
2048 bundle2-input-part: total payload size 106
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" (params: 4 mandatory) supported
2080 2080 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2081 2081 bundle2-input-part: "pushkey" (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" 93 bytes payload
2128 bundle2-output-part: "replycaps" 106 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" (params: 4 mandatory) empty payload
2132 2132 bundle2-output-part: "pushkey" (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 93
2135 bundle2-input-part: total payload size 106
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 $ "$TESTDIR/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%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%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%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%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%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%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%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%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%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%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,330 +1,330 b''
1 1 #require serve
2 2
3 3 $ cat << EOF >> $HGRCPATH
4 4 > [experimental]
5 5 > # drop me once bundle2 is the default,
6 6 > # added to get test change early.
7 7 > bundle2-exp = True
8 8 > EOF
9 9
10 10 $ hg init test
11 11 $ cd test
12 12 $ echo foo>foo
13 13 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
14 14 $ echo foo>foo.d/foo
15 15 $ echo bar>foo.d/bAr.hg.d/BaR
16 16 $ echo bar>foo.d/baR.d.hg/bAR
17 17 $ hg commit -A -m 1
18 18 adding foo
19 19 adding foo.d/bAr.hg.d/BaR
20 20 adding foo.d/baR.d.hg/bAR
21 21 adding foo.d/foo
22 22 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
23 23 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
24 24
25 25 Test server address cannot be reused
26 26
27 27 #if windows
28 28 $ hg serve -p $HGPORT1 2>&1
29 29 abort: cannot start server at ':$HGPORT1': * (glob)
30 30 [255]
31 31 #else
32 32 $ hg serve -p $HGPORT1 2>&1
33 33 abort: cannot start server at ':$HGPORT1': Address already in use
34 34 [255]
35 35 #endif
36 36 $ cd ..
37 37 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
38 38
39 39 clone via stream
40 40
41 41 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
42 42 streaming all changes
43 43 6 files to transfer, 606 bytes of data
44 44 transferred * bytes in * seconds (*/sec) (glob)
45 45 searching for changes
46 46 no changes found
47 47 updating to branch default
48 48 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 49 $ hg verify -R copy
50 50 checking changesets
51 51 checking manifests
52 52 crosschecking files in changesets and manifests
53 53 checking files
54 54 4 files, 1 changesets, 4 total revisions
55 55
56 56 try to clone via stream, should use pull instead
57 57
58 58 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
59 59 requesting all changes
60 60 adding changesets
61 61 adding manifests
62 62 adding file changes
63 63 added 1 changesets with 4 changes to 4 files
64 64 updating to branch default
65 65 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
66 66
67 67 clone via pull
68 68
69 69 $ hg clone http://localhost:$HGPORT1/ copy-pull
70 70 requesting all changes
71 71 adding changesets
72 72 adding manifests
73 73 adding file changes
74 74 added 1 changesets with 4 changes to 4 files
75 75 updating to branch default
76 76 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
77 77 $ hg verify -R copy-pull
78 78 checking changesets
79 79 checking manifests
80 80 crosschecking files in changesets and manifests
81 81 checking files
82 82 4 files, 1 changesets, 4 total revisions
83 83 $ cd test
84 84 $ echo bar > bar
85 85 $ hg commit -A -d '1 0' -m 2
86 86 adding bar
87 87 $ cd ..
88 88
89 89 clone over http with --update
90 90
91 91 $ hg clone http://localhost:$HGPORT1/ updated --update 0
92 92 requesting all changes
93 93 adding changesets
94 94 adding manifests
95 95 adding file changes
96 96 added 2 changesets with 5 changes to 5 files
97 97 updating to branch default
98 98 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 99 $ hg log -r . -R updated
100 100 changeset: 0:8b6053c928fe
101 101 user: test
102 102 date: Thu Jan 01 00:00:00 1970 +0000
103 103 summary: 1
104 104
105 105 $ rm -rf updated
106 106
107 107 incoming via HTTP
108 108
109 109 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
110 110 adding changesets
111 111 adding manifests
112 112 adding file changes
113 113 added 1 changesets with 4 changes to 4 files
114 114 updating to branch default
115 115 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 116 $ cd partial
117 117 $ touch LOCAL
118 118 $ hg ci -qAm LOCAL
119 119 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
120 120 comparing with http://localhost:$HGPORT1/
121 121 searching for changes
122 122 2
123 123 $ cd ..
124 124
125 125 pull
126 126
127 127 $ cd copy-pull
128 128 $ echo '[hooks]' >> .hg/hgrc
129 129 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
130 130 $ hg pull
131 131 pulling from http://localhost:$HGPORT1/
132 132 searching for changes
133 133 adding changesets
134 134 adding manifests
135 135 adding file changes
136 136 added 1 changesets with 1 changes to 1 files
137 137 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
138 138 (run 'hg update' to get a working copy)
139 139 $ cd ..
140 140
141 141 clone from invalid URL
142 142
143 143 $ hg clone http://localhost:$HGPORT/bad
144 144 abort: HTTP Error 404: Not Found
145 145 [255]
146 146
147 147 test http authentication
148 148 + use the same server to test server side streaming preference
149 149
150 150 $ cd test
151 151 $ cat << EOT > userpass.py
152 152 > import base64
153 153 > from mercurial.hgweb import common
154 154 > def perform_authentication(hgweb, req, op):
155 155 > auth = req.env.get('HTTP_AUTHORIZATION')
156 156 > if not auth:
157 157 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
158 158 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
159 159 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
160 160 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
161 161 > def extsetup():
162 162 > common.permhooks.insert(0, perform_authentication)
163 163 > EOT
164 164 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
165 165 > --config server.preferuncompressed=True \
166 166 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
167 167 $ cat pid >> $DAEMON_PIDS
168 168
169 169 $ cat << EOF > get_pass.py
170 170 > import getpass
171 171 > def newgetpass(arg):
172 172 > return "pass"
173 173 > getpass.getpass = newgetpass
174 174 > EOF
175 175
176 176 $ hg id http://localhost:$HGPORT2/
177 177 abort: http authorization required for http://localhost:$HGPORT2/
178 178 [255]
179 179 $ hg id http://localhost:$HGPORT2/
180 180 abort: http authorization required for http://localhost:$HGPORT2/
181 181 [255]
182 182 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
183 183 http authorization required for http://localhost:$HGPORT2/
184 184 realm: mercurial
185 185 user: user
186 186 password: 5fed3813f7f5
187 187 $ hg id http://user:pass@localhost:$HGPORT2/
188 188 5fed3813f7f5
189 189 $ echo '[auth]' >> .hg/hgrc
190 190 $ echo 'l.schemes=http' >> .hg/hgrc
191 191 $ echo 'l.prefix=lo' >> .hg/hgrc
192 192 $ echo 'l.username=user' >> .hg/hgrc
193 193 $ echo 'l.password=pass' >> .hg/hgrc
194 194 $ hg id http://localhost:$HGPORT2/
195 195 5fed3813f7f5
196 196 $ hg id http://localhost:$HGPORT2/
197 197 5fed3813f7f5
198 198 $ hg id http://user@localhost:$HGPORT2/
199 199 5fed3813f7f5
200 200 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
201 201 streaming all changes
202 202 7 files to transfer, 916 bytes of data
203 203 transferred * bytes in * seconds (*/sec) (glob)
204 204 searching for changes
205 205 no changes found
206 206 updating to branch default
207 207 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 208 --pull should override server's preferuncompressed
209 209 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
210 210 requesting all changes
211 211 adding changesets
212 212 adding manifests
213 213 adding file changes
214 214 added 2 changesets with 5 changes to 5 files
215 215 updating to branch default
216 216 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
217 217
218 218 $ hg id http://user2@localhost:$HGPORT2/
219 219 abort: http authorization required for http://localhost:$HGPORT2/
220 220 [255]
221 221 $ hg id http://user:pass2@localhost:$HGPORT2/
222 222 abort: HTTP Error 403: no
223 223 [255]
224 224
225 225 $ hg -R dest tag -r tip top
226 226 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
227 227 pushing to http://user:***@localhost:$HGPORT2/
228 228 searching for changes
229 229 remote: adding changesets
230 230 remote: adding manifests
231 231 remote: adding file changes
232 232 remote: added 1 changesets with 1 changes to 1 files
233 233 $ hg rollback -q
234 234
235 235 $ cut -c38- ../access.log
236 236 "GET /?cmd=capabilities HTTP/1.1" 200 -
237 237 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
238 238 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
239 239 "GET /?cmd=capabilities HTTP/1.1" 200 -
240 240 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
241 241 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
242 242 "GET /?cmd=capabilities HTTP/1.1" 200 -
243 243 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
244 244 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
245 245 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
246 246 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
247 247 "GET /?cmd=capabilities HTTP/1.1" 200 -
248 248 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
249 249 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
250 250 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
251 251 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
252 252 "GET /?cmd=capabilities HTTP/1.1" 200 -
253 253 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
254 254 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
255 255 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
256 256 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
257 257 "GET /?cmd=capabilities HTTP/1.1" 200 -
258 258 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
259 259 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
260 260 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
261 261 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
262 262 "GET /?cmd=capabilities HTTP/1.1" 200 -
263 263 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
264 264 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
265 265 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces
266 266 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
267 267 "GET /?cmd=capabilities HTTP/1.1" 200 -
268 268 "GET /?cmd=branchmap HTTP/1.1" 200 -
269 269 "GET /?cmd=stream_out HTTP/1.1" 401 -
270 270 "GET /?cmd=stream_out HTTP/1.1" 200 -
271 271 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d
272 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
272 "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
273 273 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
274 274 "GET /?cmd=capabilities HTTP/1.1" 200 -
275 275 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D
276 "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
277 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phase%2Cbookmarks
276 "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
277 "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
278 278 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
279 279 "GET /?cmd=capabilities HTTP/1.1" 200 -
280 280 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
281 281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
282 282 "GET /?cmd=capabilities HTTP/1.1" 200 -
283 283 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip
284 284 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces
285 285 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces
286 286 "GET /?cmd=capabilities HTTP/1.1" 200 -
287 287 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872
288 288 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases
289 289 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
290 290 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
291 291 "GET /?cmd=branchmap HTTP/1.1" 200 -
292 292 "GET /?cmd=branchmap HTTP/1.1" 200 -
293 293 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks
294 294 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365
295 295 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases
296 296
297 297 $ cd ..
298 298
299 299 clone of serve with repo in root and unserved subrepo (issue2970)
300 300
301 301 $ hg --cwd test init sub
302 302 $ echo empty > test/sub/empty
303 303 $ hg --cwd test/sub add empty
304 304 $ hg --cwd test/sub commit -qm 'add empty'
305 305 $ hg --cwd test/sub tag -r 0 something
306 306 $ echo sub = sub > test/.hgsub
307 307 $ hg --cwd test add .hgsub
308 308 $ hg --cwd test commit -qm 'add subrepo'
309 309 $ hg clone http://localhost:$HGPORT noslash-clone
310 310 requesting all changes
311 311 adding changesets
312 312 adding manifests
313 313 adding file changes
314 314 added 3 changesets with 7 changes to 7 files
315 315 updating to branch default
316 316 abort: HTTP Error 404: Not Found
317 317 [255]
318 318 $ hg clone http://localhost:$HGPORT/ slash-clone
319 319 requesting all changes
320 320 adding changesets
321 321 adding manifests
322 322 adding file changes
323 323 added 3 changesets with 7 changes to 7 files
324 324 updating to branch default
325 325 abort: HTTP Error 404: Not Found
326 326 [255]
327 327
328 328 check error log
329 329
330 330 $ 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 = python "$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 = python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 = python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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="python \"$TESTDIR/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="python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/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 "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
339 339 73649e48688a
340 340
341 341 $ hg id --ssh "python \"$TESTDIR/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 "python \"$TESTDIR/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 = python "$TESTDIR/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 python "*/dummyssh" user@dummy 'hg -R remote serve --stdio' (glob)
461 461 sending hello command
462 462 sending between command
463 remote: 271
464 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
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
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,510 +1,510 b''
1 1 $ cat << EOF >> $HGRCPATH
2 2 > [experimental]
3 3 > # drop me once bundle2 is the default,
4 4 > # added to get test change early.
5 5 > bundle2-exp = True
6 6 > EOF
7 7
8 8
9 9 This test tries to exercise the ssh functionality with a dummy script
10 10
11 11 creating 'remote' repo
12 12
13 13 $ hg init remote
14 14 $ cd remote
15 15 $ echo this > foo
16 16 $ echo this > fooO
17 17 $ hg ci -A -m "init" foo fooO
18 18
19 19 insert a closed branch (issue4428)
20 20
21 21 $ hg up null
22 22 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
23 23 $ hg branch closed
24 24 marked working directory as branch closed
25 25 (branches are permanent and global, did you want a bookmark?)
26 26 $ hg ci -mc0
27 27 $ hg ci --close-branch -mc1
28 28 $ hg up -q default
29 29
30 30 configure for serving
31 31
32 32 $ cat <<EOF > .hg/hgrc
33 33 > [server]
34 34 > uncompressed = True
35 35 >
36 36 > [hooks]
37 37 > changegroup = python "$TESTDIR/printenv.py" changegroup-in-remote 0 ../dummylog
38 38 > EOF
39 39 $ cd ..
40 40
41 41 repo not found error
42 42
43 43 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/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 non-existent absolute path
49 49
50 50 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
51 51 remote: abort: there is no Mercurial repository here (.hg not found)!
52 52 abort: no suitable response from remote hg!
53 53 [255]
54 54
55 55 clone remote via stream
56 56
57 57 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
58 58 streaming all changes
59 59 4 files to transfer, 615 bytes of data
60 60 transferred 615 bytes in * seconds (*) (glob)
61 61 searching for changes
62 62 no changes found
63 63 updating to branch default
64 64 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
65 65 $ cd local-stream
66 66 $ hg verify
67 67 checking changesets
68 68 checking manifests
69 69 crosschecking files in changesets and manifests
70 70 checking files
71 71 2 files, 3 changesets, 2 total revisions
72 72 $ hg branches
73 73 default 0:1160648e36ce
74 74 $ cd ..
75 75
76 76 clone bookmarks via stream
77 77
78 78 $ hg -R local-stream book mybook
79 79 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
80 80 streaming all changes
81 81 4 files to transfer, 615 bytes of data
82 82 transferred 615 bytes in * seconds (*) (glob)
83 83 searching for changes
84 84 no changes found
85 85 updating to branch default
86 86 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
87 87 $ cd stream2
88 88 $ hg book
89 89 mybook 0:1160648e36ce
90 90 $ cd ..
91 91 $ rm -rf local-stream stream2
92 92
93 93 clone remote via pull
94 94
95 95 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
96 96 requesting all changes
97 97 adding changesets
98 98 adding manifests
99 99 adding file changes
100 100 added 3 changesets with 2 changes to 2 files
101 101 updating to branch default
102 102 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
103 103
104 104 verify
105 105
106 106 $ cd local
107 107 $ hg verify
108 108 checking changesets
109 109 checking manifests
110 110 crosschecking files in changesets and manifests
111 111 checking files
112 112 2 files, 3 changesets, 2 total revisions
113 113 $ echo '[hooks]' >> .hg/hgrc
114 114 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup-in-local 0 ../dummylog" >> .hg/hgrc
115 115
116 116 empty default pull
117 117
118 118 $ hg paths
119 119 default = ssh://user@dummy/remote
120 120 $ hg pull -e "python \"$TESTDIR/dummyssh\""
121 121 pulling from ssh://user@dummy/remote
122 122 searching for changes
123 123 no changes found
124 124
125 125 pull from wrong ssh URL
126 126
127 127 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
128 128 pulling from ssh://user@dummy/doesnotexist
129 129 remote: abort: there is no Mercurial repository here (.hg not found)!
130 130 abort: no suitable response from remote hg!
131 131 [255]
132 132
133 133 local change
134 134
135 135 $ echo bleah > foo
136 136 $ hg ci -m "add"
137 137
138 138 updating rc
139 139
140 140 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
141 141 $ echo "[ui]" >> .hg/hgrc
142 142 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
143 143
144 144 find outgoing
145 145
146 146 $ hg out ssh://user@dummy/remote
147 147 comparing with ssh://user@dummy/remote
148 148 searching for changes
149 149 changeset: 3:a28a9d1a809c
150 150 tag: tip
151 151 parent: 0:1160648e36ce
152 152 user: test
153 153 date: Thu Jan 01 00:00:00 1970 +0000
154 154 summary: add
155 155
156 156
157 157 find incoming on the remote side
158 158
159 159 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
160 160 comparing with ssh://user@dummy/local
161 161 searching for changes
162 162 changeset: 3:a28a9d1a809c
163 163 tag: tip
164 164 parent: 0:1160648e36ce
165 165 user: test
166 166 date: Thu Jan 01 00:00:00 1970 +0000
167 167 summary: add
168 168
169 169
170 170 find incoming on the remote side (using absolute path)
171 171
172 172 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
173 173 comparing with ssh://user@dummy/$TESTTMP/local
174 174 searching for changes
175 175 changeset: 3:a28a9d1a809c
176 176 tag: tip
177 177 parent: 0:1160648e36ce
178 178 user: test
179 179 date: Thu Jan 01 00:00:00 1970 +0000
180 180 summary: add
181 181
182 182
183 183 push
184 184
185 185 $ hg push
186 186 pushing to ssh://user@dummy/remote
187 187 searching for changes
188 188 remote: adding changesets
189 189 remote: adding manifests
190 190 remote: adding file changes
191 191 remote: added 1 changesets with 1 changes to 1 files
192 192 $ cd ../remote
193 193
194 194 check remote tip
195 195
196 196 $ hg tip
197 197 changeset: 3:a28a9d1a809c
198 198 tag: tip
199 199 parent: 0:1160648e36ce
200 200 user: test
201 201 date: Thu Jan 01 00:00:00 1970 +0000
202 202 summary: add
203 203
204 204 $ hg verify
205 205 checking changesets
206 206 checking manifests
207 207 crosschecking files in changesets and manifests
208 208 checking files
209 209 2 files, 4 changesets, 3 total revisions
210 210 $ hg cat -r tip foo
211 211 bleah
212 212 $ echo z > z
213 213 $ hg ci -A -m z z
214 214 created new head
215 215
216 216 test pushkeys and bookmarks
217 217
218 218 $ cd ../local
219 219 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
220 220 bookmarks
221 221 namespaces
222 222 phases
223 223 $ hg book foo -r 0
224 224 $ hg out -B
225 225 comparing with ssh://user@dummy/remote
226 226 searching for changed bookmarks
227 227 foo 1160648e36ce
228 228 $ hg push -B foo
229 229 pushing to ssh://user@dummy/remote
230 230 searching for changes
231 231 no changes found
232 232 exporting bookmark foo
233 233 [1]
234 234 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
235 235 foo 1160648e36cec0054048a7edc4110c6f84fde594
236 236 $ hg book -f foo
237 237 $ hg push --traceback
238 238 pushing to ssh://user@dummy/remote
239 239 searching for changes
240 240 no changes found
241 241 updating bookmark foo
242 242 [1]
243 243 $ hg book -d foo
244 244 $ hg in -B
245 245 comparing with ssh://user@dummy/remote
246 246 searching for changed bookmarks
247 247 foo a28a9d1a809c
248 248 $ hg book -f -r 0 foo
249 249 $ hg pull -B foo
250 250 pulling from ssh://user@dummy/remote
251 251 no changes found
252 252 updating bookmark foo
253 253 $ hg book -d foo
254 254 $ hg push -B foo
255 255 pushing to ssh://user@dummy/remote
256 256 searching for changes
257 257 no changes found
258 258 deleting remote bookmark foo
259 259 [1]
260 260
261 261 a bad, evil hook that prints to stdout
262 262
263 263 $ cat <<EOF > $TESTTMP/badhook
264 264 > import sys
265 265 > sys.stdout.write("KABOOM\n")
266 266 > EOF
267 267
268 268 $ echo '[hooks]' >> ../remote/.hg/hgrc
269 269 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
270 270 $ echo r > r
271 271 $ hg ci -A -m z r
272 272
273 273 push should succeed even though it has an unexpected response
274 274
275 275 $ hg push
276 276 pushing to ssh://user@dummy/remote
277 277 searching for changes
278 278 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
279 279 remote: adding changesets
280 280 remote: adding manifests
281 281 remote: adding file changes
282 282 remote: added 1 changesets with 1 changes to 1 files
283 283 remote: KABOOM
284 284 $ hg -R ../remote heads
285 285 changeset: 5:1383141674ec
286 286 tag: tip
287 287 parent: 3:a28a9d1a809c
288 288 user: test
289 289 date: Thu Jan 01 00:00:00 1970 +0000
290 290 summary: z
291 291
292 292 changeset: 4:6c0482d977a3
293 293 parent: 0:1160648e36ce
294 294 user: test
295 295 date: Thu Jan 01 00:00:00 1970 +0000
296 296 summary: z
297 297
298 298
299 299 clone bookmarks
300 300
301 301 $ hg -R ../remote bookmark test
302 302 $ hg -R ../remote bookmarks
303 303 * test 4:6c0482d977a3
304 304 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
305 305 requesting all changes
306 306 adding changesets
307 307 adding manifests
308 308 adding file changes
309 309 added 6 changesets with 5 changes to 4 files (+1 heads)
310 310 updating to branch default
311 311 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 312 $ hg -R local-bookmarks bookmarks
313 313 test 4:6c0482d977a3
314 314
315 315 passwords in ssh urls are not supported
316 316 (we use a glob here because different Python versions give different
317 317 results here)
318 318
319 319 $ hg push ssh://user:erroneouspwd@dummy/remote
320 320 pushing to ssh://user:*@dummy/remote (glob)
321 321 abort: password in URL not supported!
322 322 [255]
323 323
324 324 $ cd ..
325 325
326 326 hide outer repo
327 327 $ hg init
328 328
329 329 Test remote paths with spaces (issue2983):
330 330
331 331 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
332 332 $ touch "$TESTTMP/a repo/test"
333 333 $ hg -R 'a repo' commit -A -m "test"
334 334 adding test
335 335 $ hg -R 'a repo' tag tag
336 336 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
337 337 73649e48688a
338 338
339 339 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
340 340 abort: unknown revision 'noNoNO'!
341 341 [255]
342 342
343 343 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
344 344
345 345 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
346 346 destination directory: a repo
347 347 abort: destination 'a repo' is not empty
348 348 [255]
349 349
350 350 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
351 351 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
352 352 parameters:
353 353
354 354 $ cat > ssh.sh << EOF
355 355 > userhost="\$1"
356 356 > SSH_ORIGINAL_COMMAND="\$2"
357 357 > export SSH_ORIGINAL_COMMAND
358 358 > PYTHONPATH="$PYTHONPATH"
359 359 > export PYTHONPATH
360 360 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
361 361 > EOF
362 362
363 363 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
364 364 73649e48688a
365 365
366 366 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
367 367 remote: Illegal repository "$TESTTMP/a'repo" (glob)
368 368 abort: no suitable response from remote hg!
369 369 [255]
370 370
371 371 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
372 372 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
373 373 abort: no suitable response from remote hg!
374 374 [255]
375 375
376 376 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
377 377 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
378 378 [255]
379 379
380 380 Test hg-ssh in read-only mode:
381 381
382 382 $ cat > ssh.sh << EOF
383 383 > userhost="\$1"
384 384 > SSH_ORIGINAL_COMMAND="\$2"
385 385 > export SSH_ORIGINAL_COMMAND
386 386 > PYTHONPATH="$PYTHONPATH"
387 387 > export PYTHONPATH
388 388 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
389 389 > EOF
390 390
391 391 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
392 392 requesting all changes
393 393 adding changesets
394 394 adding manifests
395 395 adding file changes
396 396 added 6 changesets with 5 changes to 4 files (+1 heads)
397 397 updating to branch default
398 398 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
399 399
400 400 $ cd read-only-local
401 401 $ echo "baz" > bar
402 402 $ hg ci -A -m "unpushable commit" bar
403 403 $ hg push --ssh "sh ../ssh.sh"
404 404 pushing to ssh://user@dummy/*/remote (glob)
405 405 searching for changes
406 406 abort: pretxnopen.hg-ssh hook failed
407 407 remote: Permission denied
408 408 [255]
409 409
410 410 $ cd ..
411 411
412 412 stderr from remote commands should be printed before stdout from local code (issue4336)
413 413
414 414 $ hg clone remote stderr-ordering
415 415 updating to branch default
416 416 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
417 417 $ cd stderr-ordering
418 418 $ cat >> localwrite.py << EOF
419 419 > from mercurial import exchange, extensions
420 420 >
421 421 > def wrappedpush(orig, repo, *args, **kwargs):
422 422 > res = orig(repo, *args, **kwargs)
423 423 > repo.ui.write('local stdout\n')
424 424 > return res
425 425 >
426 426 > def extsetup(ui):
427 427 > extensions.wrapfunction(exchange, 'push', wrappedpush)
428 428 > EOF
429 429
430 430 $ cat >> .hg/hgrc << EOF
431 431 > [paths]
432 432 > default-push = ssh://user@dummy/remote
433 433 > [ui]
434 434 > ssh = python "$TESTDIR/dummyssh"
435 435 > [extensions]
436 436 > localwrite = localwrite.py
437 437 > EOF
438 438
439 439 $ echo localwrite > foo
440 440 $ hg commit -m 'testing localwrite'
441 441 $ hg push
442 442 pushing to ssh://user@dummy/remote
443 443 searching for changes
444 444 remote: adding changesets
445 445 remote: adding manifests
446 446 remote: adding file changes
447 447 remote: added 1 changesets with 1 changes to 1 files
448 448 remote: KABOOM
449 449 local stdout
450 450
451 451 debug output
452 452
453 453 $ hg pull --debug ssh://user@dummy/remote
454 454 pulling from ssh://user@dummy/remote
455 455 running python "*/dummyssh" user@dummy 'hg -R remote serve --stdio' (glob)
456 456 sending hello command
457 457 sending between command
458 remote: 271
459 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch stream bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN httpheader=1024
458 remote: 286
459 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
460 460 remote: 1
461 461 query 1; heads
462 462 sending batch command
463 463 searching for changes
464 464 all remote heads known locally
465 465 no changes found
466 466 sending getbundle command
467 467 bundle2-input-bundle: with-transaction
468 468 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
469 469 bundle2-input-part: total payload size 45
470 470 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
471 471 bundle2-input-bundle: 1 parts total
472 472 checking for updated bookmarks
473 473 preparing listkeys for "phases"
474 474 sending listkeys command
475 475 received listkey for "phases": 15 bytes
476 476
477 477 $ cd ..
478 478
479 479 $ cat dummylog
480 480 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
481 481 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
482 482 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
483 483 Got arguments 1:user@dummy 2:hg -R local-stream 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 remote serve --stdio
486 486 Got arguments 1:user@dummy 2:hg -R doesnotexist 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 local serve --stdio
489 489 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
490 490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 491 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)
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 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 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)
502 502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 503 Got arguments 1:user@dummy 2:hg init 'a repo'
504 504 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
505 505 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
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 remote serve --stdio
509 509 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)
510 510 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