##// END OF EJS Templates
phase: use a binary phase part to push through bundle2 (BC)...
Boris Feld -
r34837:537de0b1 default
parent child Browse files
Show More
@@ -1,2109 +1,2126
1 1 # exchange.py - utility to exchange data between repos.
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import collections
11 11 import errno
12 12 import hashlib
13 13
14 14 from .i18n import _
15 15 from .node import (
16 16 hex,
17 17 nullid,
18 18 )
19 19 from . import (
20 20 bookmarks as bookmod,
21 21 bundle2,
22 22 changegroup,
23 23 discovery,
24 24 error,
25 25 lock as lockmod,
26 26 obsolete,
27 27 phases,
28 28 pushkey,
29 29 pycompat,
30 30 scmutil,
31 31 sslutil,
32 32 streamclone,
33 33 url as urlmod,
34 34 util,
35 35 )
36 36
37 37 urlerr = util.urlerr
38 38 urlreq = util.urlreq
39 39
40 40 # Maps bundle version human names to changegroup versions.
41 41 _bundlespeccgversions = {'v1': '01',
42 42 'v2': '02',
43 43 'packed1': 's1',
44 44 'bundle2': '02', #legacy
45 45 }
46 46
47 47 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
48 48 _bundlespecv1compengines = {'gzip', 'bzip2', 'none'}
49 49
50 50 def parsebundlespec(repo, spec, strict=True, externalnames=False):
51 51 """Parse a bundle string specification into parts.
52 52
53 53 Bundle specifications denote a well-defined bundle/exchange format.
54 54 The content of a given specification should not change over time in
55 55 order to ensure that bundles produced by a newer version of Mercurial are
56 56 readable from an older version.
57 57
58 58 The string currently has the form:
59 59
60 60 <compression>-<type>[;<parameter0>[;<parameter1>]]
61 61
62 62 Where <compression> is one of the supported compression formats
63 63 and <type> is (currently) a version string. A ";" can follow the type and
64 64 all text afterwards is interpreted as URI encoded, ";" delimited key=value
65 65 pairs.
66 66
67 67 If ``strict`` is True (the default) <compression> is required. Otherwise,
68 68 it is optional.
69 69
70 70 If ``externalnames`` is False (the default), the human-centric names will
71 71 be converted to their internal representation.
72 72
73 73 Returns a 3-tuple of (compression, version, parameters). Compression will
74 74 be ``None`` if not in strict mode and a compression isn't defined.
75 75
76 76 An ``InvalidBundleSpecification`` is raised when the specification is
77 77 not syntactically well formed.
78 78
79 79 An ``UnsupportedBundleSpecification`` is raised when the compression or
80 80 bundle type/version is not recognized.
81 81
82 82 Note: this function will likely eventually return a more complex data
83 83 structure, including bundle2 part information.
84 84 """
85 85 def parseparams(s):
86 86 if ';' not in s:
87 87 return s, {}
88 88
89 89 params = {}
90 90 version, paramstr = s.split(';', 1)
91 91
92 92 for p in paramstr.split(';'):
93 93 if '=' not in p:
94 94 raise error.InvalidBundleSpecification(
95 95 _('invalid bundle specification: '
96 96 'missing "=" in parameter: %s') % p)
97 97
98 98 key, value = p.split('=', 1)
99 99 key = urlreq.unquote(key)
100 100 value = urlreq.unquote(value)
101 101 params[key] = value
102 102
103 103 return version, params
104 104
105 105
106 106 if strict and '-' not in spec:
107 107 raise error.InvalidBundleSpecification(
108 108 _('invalid bundle specification; '
109 109 'must be prefixed with compression: %s') % spec)
110 110
111 111 if '-' in spec:
112 112 compression, version = spec.split('-', 1)
113 113
114 114 if compression not in util.compengines.supportedbundlenames:
115 115 raise error.UnsupportedBundleSpecification(
116 116 _('%s compression is not supported') % compression)
117 117
118 118 version, params = parseparams(version)
119 119
120 120 if version not in _bundlespeccgversions:
121 121 raise error.UnsupportedBundleSpecification(
122 122 _('%s is not a recognized bundle version') % version)
123 123 else:
124 124 # Value could be just the compression or just the version, in which
125 125 # case some defaults are assumed (but only when not in strict mode).
126 126 assert not strict
127 127
128 128 spec, params = parseparams(spec)
129 129
130 130 if spec in util.compengines.supportedbundlenames:
131 131 compression = spec
132 132 version = 'v1'
133 133 # Generaldelta repos require v2.
134 134 if 'generaldelta' in repo.requirements:
135 135 version = 'v2'
136 136 # Modern compression engines require v2.
137 137 if compression not in _bundlespecv1compengines:
138 138 version = 'v2'
139 139 elif spec in _bundlespeccgversions:
140 140 if spec == 'packed1':
141 141 compression = 'none'
142 142 else:
143 143 compression = 'bzip2'
144 144 version = spec
145 145 else:
146 146 raise error.UnsupportedBundleSpecification(
147 147 _('%s is not a recognized bundle specification') % spec)
148 148
149 149 # Bundle version 1 only supports a known set of compression engines.
150 150 if version == 'v1' and compression not in _bundlespecv1compengines:
151 151 raise error.UnsupportedBundleSpecification(
152 152 _('compression engine %s is not supported on v1 bundles') %
153 153 compression)
154 154
155 155 # The specification for packed1 can optionally declare the data formats
156 156 # required to apply it. If we see this metadata, compare against what the
157 157 # repo supports and error if the bundle isn't compatible.
158 158 if version == 'packed1' and 'requirements' in params:
159 159 requirements = set(params['requirements'].split(','))
160 160 missingreqs = requirements - repo.supportedformats
161 161 if missingreqs:
162 162 raise error.UnsupportedBundleSpecification(
163 163 _('missing support for repository features: %s') %
164 164 ', '.join(sorted(missingreqs)))
165 165
166 166 if not externalnames:
167 167 engine = util.compengines.forbundlename(compression)
168 168 compression = engine.bundletype()[1]
169 169 version = _bundlespeccgversions[version]
170 170 return compression, version, params
171 171
172 172 def readbundle(ui, fh, fname, vfs=None):
173 173 header = changegroup.readexactly(fh, 4)
174 174
175 175 alg = None
176 176 if not fname:
177 177 fname = "stream"
178 178 if not header.startswith('HG') and header.startswith('\0'):
179 179 fh = changegroup.headerlessfixup(fh, header)
180 180 header = "HG10"
181 181 alg = 'UN'
182 182 elif vfs:
183 183 fname = vfs.join(fname)
184 184
185 185 magic, version = header[0:2], header[2:4]
186 186
187 187 if magic != 'HG':
188 188 raise error.Abort(_('%s: not a Mercurial bundle') % fname)
189 189 if version == '10':
190 190 if alg is None:
191 191 alg = changegroup.readexactly(fh, 2)
192 192 return changegroup.cg1unpacker(fh, alg)
193 193 elif version.startswith('2'):
194 194 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
195 195 elif version == 'S1':
196 196 return streamclone.streamcloneapplier(fh)
197 197 else:
198 198 raise error.Abort(_('%s: unknown bundle version %s') % (fname, version))
199 199
200 200 def getbundlespec(ui, fh):
201 201 """Infer the bundlespec from a bundle file handle.
202 202
203 203 The input file handle is seeked and the original seek position is not
204 204 restored.
205 205 """
206 206 def speccompression(alg):
207 207 try:
208 208 return util.compengines.forbundletype(alg).bundletype()[0]
209 209 except KeyError:
210 210 return None
211 211
212 212 b = readbundle(ui, fh, None)
213 213 if isinstance(b, changegroup.cg1unpacker):
214 214 alg = b._type
215 215 if alg == '_truncatedBZ':
216 216 alg = 'BZ'
217 217 comp = speccompression(alg)
218 218 if not comp:
219 219 raise error.Abort(_('unknown compression algorithm: %s') % alg)
220 220 return '%s-v1' % comp
221 221 elif isinstance(b, bundle2.unbundle20):
222 222 if 'Compression' in b.params:
223 223 comp = speccompression(b.params['Compression'])
224 224 if not comp:
225 225 raise error.Abort(_('unknown compression algorithm: %s') % comp)
226 226 else:
227 227 comp = 'none'
228 228
229 229 version = None
230 230 for part in b.iterparts():
231 231 if part.type == 'changegroup':
232 232 version = part.params['version']
233 233 if version in ('01', '02'):
234 234 version = 'v2'
235 235 else:
236 236 raise error.Abort(_('changegroup version %s does not have '
237 237 'a known bundlespec') % version,
238 238 hint=_('try upgrading your Mercurial '
239 239 'client'))
240 240
241 241 if not version:
242 242 raise error.Abort(_('could not identify changegroup version in '
243 243 'bundle'))
244 244
245 245 return '%s-%s' % (comp, version)
246 246 elif isinstance(b, streamclone.streamcloneapplier):
247 247 requirements = streamclone.readbundle1header(fh)[2]
248 248 params = 'requirements=%s' % ','.join(sorted(requirements))
249 249 return 'none-packed1;%s' % urlreq.quote(params)
250 250 else:
251 251 raise error.Abort(_('unknown bundle type: %s') % b)
252 252
253 253 def _computeoutgoing(repo, heads, common):
254 254 """Computes which revs are outgoing given a set of common
255 255 and a set of heads.
256 256
257 257 This is a separate function so extensions can have access to
258 258 the logic.
259 259
260 260 Returns a discovery.outgoing object.
261 261 """
262 262 cl = repo.changelog
263 263 if common:
264 264 hasnode = cl.hasnode
265 265 common = [n for n in common if hasnode(n)]
266 266 else:
267 267 common = [nullid]
268 268 if not heads:
269 269 heads = cl.heads()
270 270 return discovery.outgoing(repo, common, heads)
271 271
272 272 def _forcebundle1(op):
273 273 """return true if a pull/push must use bundle1
274 274
275 275 This function is used to allow testing of the older bundle version"""
276 276 ui = op.repo.ui
277 277 forcebundle1 = False
278 278 # The goal is this config is to allow developer to choose the bundle
279 279 # version used during exchanged. This is especially handy during test.
280 280 # Value is a list of bundle version to be picked from, highest version
281 281 # should be used.
282 282 #
283 283 # developer config: devel.legacy.exchange
284 284 exchange = ui.configlist('devel', 'legacy.exchange')
285 285 forcebundle1 = 'bundle2' not in exchange and 'bundle1' in exchange
286 286 return forcebundle1 or not op.remote.capable('bundle2')
287 287
288 288 class pushoperation(object):
289 289 """A object that represent a single push operation
290 290
291 291 Its purpose is to carry push related state and very common operations.
292 292
293 293 A new pushoperation should be created at the beginning of each push and
294 294 discarded afterward.
295 295 """
296 296
297 297 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
298 298 bookmarks=(), pushvars=None):
299 299 # repo we push from
300 300 self.repo = repo
301 301 self.ui = repo.ui
302 302 # repo we push to
303 303 self.remote = remote
304 304 # force option provided
305 305 self.force = force
306 306 # revs to be pushed (None is "all")
307 307 self.revs = revs
308 308 # bookmark explicitly pushed
309 309 self.bookmarks = bookmarks
310 310 # allow push of new branch
311 311 self.newbranch = newbranch
312 312 # step already performed
313 313 # (used to check what steps have been already performed through bundle2)
314 314 self.stepsdone = set()
315 315 # Integer version of the changegroup push result
316 316 # - None means nothing to push
317 317 # - 0 means HTTP error
318 318 # - 1 means we pushed and remote head count is unchanged *or*
319 319 # we have outgoing changesets but refused to push
320 320 # - other values as described by addchangegroup()
321 321 self.cgresult = None
322 322 # Boolean value for the bookmark push
323 323 self.bkresult = None
324 324 # discover.outgoing object (contains common and outgoing data)
325 325 self.outgoing = None
326 326 # all remote topological heads before the push
327 327 self.remoteheads = None
328 328 # Details of the remote branch pre and post push
329 329 #
330 330 # mapping: {'branch': ([remoteheads],
331 331 # [newheads],
332 332 # [unsyncedheads],
333 333 # [discardedheads])}
334 334 # - branch: the branch name
335 335 # - remoteheads: the list of remote heads known locally
336 336 # None if the branch is new
337 337 # - newheads: the new remote heads (known locally) with outgoing pushed
338 338 # - unsyncedheads: the list of remote heads unknown locally.
339 339 # - discardedheads: the list of remote heads made obsolete by the push
340 340 self.pushbranchmap = None
341 341 # testable as a boolean indicating if any nodes are missing locally.
342 342 self.incoming = None
343 343 # summary of the remote phase situation
344 344 self.remotephases = None
345 345 # phases changes that must be pushed along side the changesets
346 346 self.outdatedphases = None
347 347 # phases changes that must be pushed if changeset push fails
348 348 self.fallbackoutdatedphases = None
349 349 # outgoing obsmarkers
350 350 self.outobsmarkers = set()
351 351 # outgoing bookmarks
352 352 self.outbookmarks = []
353 353 # transaction manager
354 354 self.trmanager = None
355 355 # map { pushkey partid -> callback handling failure}
356 356 # used to handle exception from mandatory pushkey part failure
357 357 self.pkfailcb = {}
358 358 # an iterable of pushvars or None
359 359 self.pushvars = pushvars
360 360
361 361 @util.propertycache
362 362 def futureheads(self):
363 363 """future remote heads if the changeset push succeeds"""
364 364 return self.outgoing.missingheads
365 365
366 366 @util.propertycache
367 367 def fallbackheads(self):
368 368 """future remote heads if the changeset push fails"""
369 369 if self.revs is None:
370 370 # not target to push, all common are relevant
371 371 return self.outgoing.commonheads
372 372 unfi = self.repo.unfiltered()
373 373 # I want cheads = heads(::missingheads and ::commonheads)
374 374 # (missingheads is revs with secret changeset filtered out)
375 375 #
376 376 # This can be expressed as:
377 377 # cheads = ( (missingheads and ::commonheads)
378 378 # + (commonheads and ::missingheads))"
379 379 # )
380 380 #
381 381 # while trying to push we already computed the following:
382 382 # common = (::commonheads)
383 383 # missing = ((commonheads::missingheads) - commonheads)
384 384 #
385 385 # We can pick:
386 386 # * missingheads part of common (::commonheads)
387 387 common = self.outgoing.common
388 388 nm = self.repo.changelog.nodemap
389 389 cheads = [node for node in self.revs if nm[node] in common]
390 390 # and
391 391 # * commonheads parents on missing
392 392 revset = unfi.set('%ln and parents(roots(%ln))',
393 393 self.outgoing.commonheads,
394 394 self.outgoing.missing)
395 395 cheads.extend(c.node() for c in revset)
396 396 return cheads
397 397
398 398 @property
399 399 def commonheads(self):
400 400 """set of all common heads after changeset bundle push"""
401 401 if self.cgresult:
402 402 return self.futureheads
403 403 else:
404 404 return self.fallbackheads
405 405
406 406 # mapping of message used when pushing bookmark
407 407 bookmsgmap = {'update': (_("updating bookmark %s\n"),
408 408 _('updating bookmark %s failed!\n')),
409 409 'export': (_("exporting bookmark %s\n"),
410 410 _('exporting bookmark %s failed!\n')),
411 411 'delete': (_("deleting remote bookmark %s\n"),
412 412 _('deleting remote bookmark %s failed!\n')),
413 413 }
414 414
415 415
416 416 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=(),
417 417 opargs=None):
418 418 '''Push outgoing changesets (limited by revs) from a local
419 419 repository to remote. Return an integer:
420 420 - None means nothing to push
421 421 - 0 means HTTP error
422 422 - 1 means we pushed and remote head count is unchanged *or*
423 423 we have outgoing changesets but refused to push
424 424 - other values as described by addchangegroup()
425 425 '''
426 426 if opargs is None:
427 427 opargs = {}
428 428 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks,
429 429 **pycompat.strkwargs(opargs))
430 430 if pushop.remote.local():
431 431 missing = (set(pushop.repo.requirements)
432 432 - pushop.remote.local().supported)
433 433 if missing:
434 434 msg = _("required features are not"
435 435 " supported in the destination:"
436 436 " %s") % (', '.join(sorted(missing)))
437 437 raise error.Abort(msg)
438 438
439 439 if not pushop.remote.canpush():
440 440 raise error.Abort(_("destination does not support push"))
441 441
442 442 if not pushop.remote.capable('unbundle'):
443 443 raise error.Abort(_('cannot push: destination does not support the '
444 444 'unbundle wire protocol command'))
445 445
446 446 # get lock as we might write phase data
447 447 wlock = lock = None
448 448 try:
449 449 # bundle2 push may receive a reply bundle touching bookmarks or other
450 450 # things requiring the wlock. Take it now to ensure proper ordering.
451 451 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
452 452 if (not _forcebundle1(pushop)) and maypushback:
453 453 wlock = pushop.repo.wlock()
454 454 lock = pushop.repo.lock()
455 455 pushop.trmanager = transactionmanager(pushop.repo,
456 456 'push-response',
457 457 pushop.remote.url())
458 458 except IOError as err:
459 459 if err.errno != errno.EACCES:
460 460 raise
461 461 # source repo cannot be locked.
462 462 # We do not abort the push, but just disable the local phase
463 463 # synchronisation.
464 464 msg = 'cannot lock source repository: %s\n' % err
465 465 pushop.ui.debug(msg)
466 466
467 467 with wlock or util.nullcontextmanager(), \
468 468 lock or util.nullcontextmanager(), \
469 469 pushop.trmanager or util.nullcontextmanager():
470 470 pushop.repo.checkpush(pushop)
471 471 _pushdiscovery(pushop)
472 472 if not _forcebundle1(pushop):
473 473 _pushbundle2(pushop)
474 474 _pushchangeset(pushop)
475 475 _pushsyncphase(pushop)
476 476 _pushobsolete(pushop)
477 477 _pushbookmark(pushop)
478 478
479 479 return pushop
480 480
481 481 # list of steps to perform discovery before push
482 482 pushdiscoveryorder = []
483 483
484 484 # Mapping between step name and function
485 485 #
486 486 # This exists to help extensions wrap steps if necessary
487 487 pushdiscoverymapping = {}
488 488
489 489 def pushdiscovery(stepname):
490 490 """decorator for function performing discovery before push
491 491
492 492 The function is added to the step -> function mapping and appended to the
493 493 list of steps. Beware that decorated function will be added in order (this
494 494 may matter).
495 495
496 496 You can only use this decorator for a new step, if you want to wrap a step
497 497 from an extension, change the pushdiscovery dictionary directly."""
498 498 def dec(func):
499 499 assert stepname not in pushdiscoverymapping
500 500 pushdiscoverymapping[stepname] = func
501 501 pushdiscoveryorder.append(stepname)
502 502 return func
503 503 return dec
504 504
505 505 def _pushdiscovery(pushop):
506 506 """Run all discovery steps"""
507 507 for stepname in pushdiscoveryorder:
508 508 step = pushdiscoverymapping[stepname]
509 509 step(pushop)
510 510
511 511 @pushdiscovery('changeset')
512 512 def _pushdiscoverychangeset(pushop):
513 513 """discover the changeset that need to be pushed"""
514 514 fci = discovery.findcommonincoming
515 515 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
516 516 common, inc, remoteheads = commoninc
517 517 fco = discovery.findcommonoutgoing
518 518 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
519 519 commoninc=commoninc, force=pushop.force)
520 520 pushop.outgoing = outgoing
521 521 pushop.remoteheads = remoteheads
522 522 pushop.incoming = inc
523 523
524 524 @pushdiscovery('phase')
525 525 def _pushdiscoveryphase(pushop):
526 526 """discover the phase that needs to be pushed
527 527
528 528 (computed for both success and failure case for changesets push)"""
529 529 outgoing = pushop.outgoing
530 530 unfi = pushop.repo.unfiltered()
531 531 remotephases = pushop.remote.listkeys('phases')
532 532 if (pushop.ui.configbool('ui', '_usedassubrepo')
533 533 and remotephases # server supports phases
534 534 and not pushop.outgoing.missing # no changesets to be pushed
535 535 and remotephases.get('publishing', False)):
536 536 # When:
537 537 # - this is a subrepo push
538 538 # - and remote support phase
539 539 # - and no changeset are to be pushed
540 540 # - and remote is publishing
541 541 # We may be in issue 3781 case!
542 542 # We drop the possible phase synchronisation done by
543 543 # courtesy to publish changesets possibly locally draft
544 544 # on the remote.
545 545 pushop.outdatedphases = []
546 546 pushop.fallbackoutdatedphases = []
547 547 return
548 548
549 549 pushop.remotephases = phases.remotephasessummary(pushop.repo,
550 550 pushop.fallbackheads,
551 551 remotephases)
552 552 droots = pushop.remotephases.draftroots
553 553
554 554 extracond = ''
555 555 if not pushop.remotephases.publishing:
556 556 extracond = ' and public()'
557 557 revset = 'heads((%%ln::%%ln) %s)' % extracond
558 558 # Get the list of all revs draft on remote by public here.
559 559 # XXX Beware that revset break if droots is not strictly
560 560 # XXX root we may want to ensure it is but it is costly
561 561 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
562 562 if not outgoing.missing:
563 563 future = fallback
564 564 else:
565 565 # adds changeset we are going to push as draft
566 566 #
567 567 # should not be necessary for publishing server, but because of an
568 568 # issue fixed in xxxxx we have to do it anyway.
569 569 fdroots = list(unfi.set('roots(%ln + %ln::)',
570 570 outgoing.missing, droots))
571 571 fdroots = [f.node() for f in fdroots]
572 572 future = list(unfi.set(revset, fdroots, pushop.futureheads))
573 573 pushop.outdatedphases = future
574 574 pushop.fallbackoutdatedphases = fallback
575 575
576 576 @pushdiscovery('obsmarker')
577 577 def _pushdiscoveryobsmarkers(pushop):
578 578 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
579 579 and pushop.repo.obsstore
580 580 and 'obsolete' in pushop.remote.listkeys('namespaces')):
581 581 repo = pushop.repo
582 582 # very naive computation, that can be quite expensive on big repo.
583 583 # However: evolution is currently slow on them anyway.
584 584 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
585 585 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
586 586
587 587 @pushdiscovery('bookmarks')
588 588 def _pushdiscoverybookmarks(pushop):
589 589 ui = pushop.ui
590 590 repo = pushop.repo.unfiltered()
591 591 remote = pushop.remote
592 592 ui.debug("checking for updated bookmarks\n")
593 593 ancestors = ()
594 594 if pushop.revs:
595 595 revnums = map(repo.changelog.rev, pushop.revs)
596 596 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
597 597 remotebookmark = remote.listkeys('bookmarks')
598 598
599 599 explicit = set([repo._bookmarks.expandname(bookmark)
600 600 for bookmark in pushop.bookmarks])
601 601
602 602 remotebookmark = bookmod.unhexlifybookmarks(remotebookmark)
603 603 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
604 604
605 605 def safehex(x):
606 606 if x is None:
607 607 return x
608 608 return hex(x)
609 609
610 610 def hexifycompbookmarks(bookmarks):
611 611 for b, scid, dcid in bookmarks:
612 612 yield b, safehex(scid), safehex(dcid)
613 613
614 614 comp = [hexifycompbookmarks(marks) for marks in comp]
615 615 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
616 616
617 617 for b, scid, dcid in advsrc:
618 618 if b in explicit:
619 619 explicit.remove(b)
620 620 if not ancestors or repo[scid].rev() in ancestors:
621 621 pushop.outbookmarks.append((b, dcid, scid))
622 622 # search added bookmark
623 623 for b, scid, dcid in addsrc:
624 624 if b in explicit:
625 625 explicit.remove(b)
626 626 pushop.outbookmarks.append((b, '', scid))
627 627 # search for overwritten bookmark
628 628 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
629 629 if b in explicit:
630 630 explicit.remove(b)
631 631 pushop.outbookmarks.append((b, dcid, scid))
632 632 # search for bookmark to delete
633 633 for b, scid, dcid in adddst:
634 634 if b in explicit:
635 635 explicit.remove(b)
636 636 # treat as "deleted locally"
637 637 pushop.outbookmarks.append((b, dcid, ''))
638 638 # identical bookmarks shouldn't get reported
639 639 for b, scid, dcid in same:
640 640 if b in explicit:
641 641 explicit.remove(b)
642 642
643 643 if explicit:
644 644 explicit = sorted(explicit)
645 645 # we should probably list all of them
646 646 ui.warn(_('bookmark %s does not exist on the local '
647 647 'or remote repository!\n') % explicit[0])
648 648 pushop.bkresult = 2
649 649
650 650 pushop.outbookmarks.sort()
651 651
652 652 def _pushcheckoutgoing(pushop):
653 653 outgoing = pushop.outgoing
654 654 unfi = pushop.repo.unfiltered()
655 655 if not outgoing.missing:
656 656 # nothing to push
657 657 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
658 658 return False
659 659 # something to push
660 660 if not pushop.force:
661 661 # if repo.obsstore == False --> no obsolete
662 662 # then, save the iteration
663 663 if unfi.obsstore:
664 664 # this message are here for 80 char limit reason
665 665 mso = _("push includes obsolete changeset: %s!")
666 666 mspd = _("push includes phase-divergent changeset: %s!")
667 667 mscd = _("push includes content-divergent changeset: %s!")
668 668 mst = {"orphan": _("push includes orphan changeset: %s!"),
669 669 "phase-divergent": mspd,
670 670 "content-divergent": mscd}
671 671 # If we are to push if there is at least one
672 672 # obsolete or unstable changeset in missing, at
673 673 # least one of the missinghead will be obsolete or
674 674 # unstable. So checking heads only is ok
675 675 for node in outgoing.missingheads:
676 676 ctx = unfi[node]
677 677 if ctx.obsolete():
678 678 raise error.Abort(mso % ctx)
679 679 elif ctx.isunstable():
680 680 # TODO print more than one instability in the abort
681 681 # message
682 682 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
683 683
684 684 discovery.checkheads(pushop)
685 685 return True
686 686
687 687 # List of names of steps to perform for an outgoing bundle2, order matters.
688 688 b2partsgenorder = []
689 689
690 690 # Mapping between step name and function
691 691 #
692 692 # This exists to help extensions wrap steps if necessary
693 693 b2partsgenmapping = {}
694 694
695 695 def b2partsgenerator(stepname, idx=None):
696 696 """decorator for function generating bundle2 part
697 697
698 698 The function is added to the step -> function mapping and appended to the
699 699 list of steps. Beware that decorated functions will be added in order
700 700 (this may matter).
701 701
702 702 You can only use this decorator for new steps, if you want to wrap a step
703 703 from an extension, attack the b2partsgenmapping dictionary directly."""
704 704 def dec(func):
705 705 assert stepname not in b2partsgenmapping
706 706 b2partsgenmapping[stepname] = func
707 707 if idx is None:
708 708 b2partsgenorder.append(stepname)
709 709 else:
710 710 b2partsgenorder.insert(idx, stepname)
711 711 return func
712 712 return dec
713 713
714 714 def _pushb2ctxcheckheads(pushop, bundler):
715 715 """Generate race condition checking parts
716 716
717 717 Exists as an independent function to aid extensions
718 718 """
719 719 # * 'force' do not check for push race,
720 720 # * if we don't push anything, there are nothing to check.
721 721 if not pushop.force and pushop.outgoing.missingheads:
722 722 allowunrelated = 'related' in bundler.capabilities.get('checkheads', ())
723 723 emptyremote = pushop.pushbranchmap is None
724 724 if not allowunrelated or emptyremote:
725 725 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
726 726 else:
727 727 affected = set()
728 728 for branch, heads in pushop.pushbranchmap.iteritems():
729 729 remoteheads, newheads, unsyncedheads, discardedheads = heads
730 730 if remoteheads is not None:
731 731 remote = set(remoteheads)
732 732 affected |= set(discardedheads) & remote
733 733 affected |= remote - set(newheads)
734 734 if affected:
735 735 data = iter(sorted(affected))
736 736 bundler.newpart('check:updated-heads', data=data)
737 737
738 738 def _pushing(pushop):
739 739 """return True if we are pushing anything"""
740 740 return bool(pushop.outgoing.missing
741 741 or pushop.outdatedphases
742 742 or pushop.outobsmarkers
743 743 or pushop.outbookmarks)
744 744
745 745 @b2partsgenerator('check-phases')
746 746 def _pushb2checkphases(pushop, bundler):
747 747 """insert phase move checking"""
748 748 if not _pushing(pushop) or pushop.force:
749 749 return
750 750 b2caps = bundle2.bundle2caps(pushop.remote)
751 751 hasphaseheads = 'heads' in b2caps.get('phases', ())
752 752 if pushop.remotephases is not None and hasphaseheads:
753 753 # check that the remote phase has not changed
754 754 checks = [[] for p in phases.allphases]
755 755 checks[phases.public].extend(pushop.remotephases.publicheads)
756 756 checks[phases.draft].extend(pushop.remotephases.draftroots)
757 757 if any(checks):
758 758 for nodes in checks:
759 759 nodes.sort()
760 760 checkdata = phases.binaryencode(checks)
761 761 bundler.newpart('check:phases', data=checkdata)
762 762
763 763 @b2partsgenerator('changeset')
764 764 def _pushb2ctx(pushop, bundler):
765 765 """handle changegroup push through bundle2
766 766
767 767 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
768 768 """
769 769 if 'changesets' in pushop.stepsdone:
770 770 return
771 771 pushop.stepsdone.add('changesets')
772 772 # Send known heads to the server for race detection.
773 773 if not _pushcheckoutgoing(pushop):
774 774 return
775 775 pushop.repo.prepushoutgoinghooks(pushop)
776 776
777 777 _pushb2ctxcheckheads(pushop, bundler)
778 778
779 779 b2caps = bundle2.bundle2caps(pushop.remote)
780 780 version = '01'
781 781 cgversions = b2caps.get('changegroup')
782 782 if cgversions: # 3.1 and 3.2 ship with an empty value
783 783 cgversions = [v for v in cgversions
784 784 if v in changegroup.supportedoutgoingversions(
785 785 pushop.repo)]
786 786 if not cgversions:
787 787 raise ValueError(_('no common changegroup version'))
788 788 version = max(cgversions)
789 789 cgstream = changegroup.makestream(pushop.repo, pushop.outgoing, version,
790 790 'push')
791 791 cgpart = bundler.newpart('changegroup', data=cgstream)
792 792 if cgversions:
793 793 cgpart.addparam('version', version)
794 794 if 'treemanifest' in pushop.repo.requirements:
795 795 cgpart.addparam('treemanifest', '1')
796 796 def handlereply(op):
797 797 """extract addchangegroup returns from server reply"""
798 798 cgreplies = op.records.getreplies(cgpart.id)
799 799 assert len(cgreplies['changegroup']) == 1
800 800 pushop.cgresult = cgreplies['changegroup'][0]['return']
801 801 return handlereply
802 802
803 803 @b2partsgenerator('phase')
804 804 def _pushb2phases(pushop, bundler):
805 805 """handle phase push through bundle2"""
806 806 if 'phases' in pushop.stepsdone:
807 807 return
808 808 b2caps = bundle2.bundle2caps(pushop.remote)
809 if 'pushkey' in b2caps:
809 ui = pushop.repo.ui
810
811 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
812 haspushkey = 'pushkey' in b2caps
813 hasphaseheads = 'heads' in b2caps.get('phases', ())
814
815 if hasphaseheads and not legacyphase:
816 _pushb2phaseheads(pushop, bundler)
817 elif haspushkey:
810 818 _pushb2phasespushkey(pushop, bundler)
811 819
820 def _pushb2phaseheads(pushop, bundler):
821 """push phase information through a bundle2 - binary part"""
822 pushop.stepsdone.add('phases')
823 if pushop.outdatedphases:
824 updates = [[] for p in phases.allphases]
825 updates[0].extend(h.node() for h in pushop.outdatedphases)
826 phasedata = phases.binaryencode(updates)
827 bundler.newpart('phase-heads', data=phasedata)
828
812 829 def _pushb2phasespushkey(pushop, bundler):
813 830 """push phase information through a bundle2 - pushkey part"""
814 831 pushop.stepsdone.add('phases')
815 832 part2node = []
816 833
817 834 def handlefailure(pushop, exc):
818 835 targetid = int(exc.partid)
819 836 for partid, node in part2node:
820 837 if partid == targetid:
821 838 raise error.Abort(_('updating %s to public failed') % node)
822 839
823 840 enc = pushkey.encode
824 841 for newremotehead in pushop.outdatedphases:
825 842 part = bundler.newpart('pushkey')
826 843 part.addparam('namespace', enc('phases'))
827 844 part.addparam('key', enc(newremotehead.hex()))
828 845 part.addparam('old', enc('%d' % phases.draft))
829 846 part.addparam('new', enc('%d' % phases.public))
830 847 part2node.append((part.id, newremotehead))
831 848 pushop.pkfailcb[part.id] = handlefailure
832 849
833 850 def handlereply(op):
834 851 for partid, node in part2node:
835 852 partrep = op.records.getreplies(partid)
836 853 results = partrep['pushkey']
837 854 assert len(results) <= 1
838 855 msg = None
839 856 if not results:
840 857 msg = _('server ignored update of %s to public!\n') % node
841 858 elif not int(results[0]['return']):
842 859 msg = _('updating %s to public failed!\n') % node
843 860 if msg is not None:
844 861 pushop.ui.warn(msg)
845 862 return handlereply
846 863
847 864 @b2partsgenerator('obsmarkers')
848 865 def _pushb2obsmarkers(pushop, bundler):
849 866 if 'obsmarkers' in pushop.stepsdone:
850 867 return
851 868 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
852 869 if obsolete.commonversion(remoteversions) is None:
853 870 return
854 871 pushop.stepsdone.add('obsmarkers')
855 872 if pushop.outobsmarkers:
856 873 markers = sorted(pushop.outobsmarkers)
857 874 bundle2.buildobsmarkerspart(bundler, markers)
858 875
859 876 @b2partsgenerator('bookmarks')
860 877 def _pushb2bookmarks(pushop, bundler):
861 878 """handle bookmark push through bundle2"""
862 879 if 'bookmarks' in pushop.stepsdone:
863 880 return
864 881 b2caps = bundle2.bundle2caps(pushop.remote)
865 882 if 'pushkey' not in b2caps:
866 883 return
867 884 pushop.stepsdone.add('bookmarks')
868 885 part2book = []
869 886 enc = pushkey.encode
870 887
871 888 def handlefailure(pushop, exc):
872 889 targetid = int(exc.partid)
873 890 for partid, book, action in part2book:
874 891 if partid == targetid:
875 892 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
876 893 # we should not be called for part we did not generated
877 894 assert False
878 895
879 896 for book, old, new in pushop.outbookmarks:
880 897 part = bundler.newpart('pushkey')
881 898 part.addparam('namespace', enc('bookmarks'))
882 899 part.addparam('key', enc(book))
883 900 part.addparam('old', enc(old))
884 901 part.addparam('new', enc(new))
885 902 action = 'update'
886 903 if not old:
887 904 action = 'export'
888 905 elif not new:
889 906 action = 'delete'
890 907 part2book.append((part.id, book, action))
891 908 pushop.pkfailcb[part.id] = handlefailure
892 909
893 910 def handlereply(op):
894 911 ui = pushop.ui
895 912 for partid, book, action in part2book:
896 913 partrep = op.records.getreplies(partid)
897 914 results = partrep['pushkey']
898 915 assert len(results) <= 1
899 916 if not results:
900 917 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
901 918 else:
902 919 ret = int(results[0]['return'])
903 920 if ret:
904 921 ui.status(bookmsgmap[action][0] % book)
905 922 else:
906 923 ui.warn(bookmsgmap[action][1] % book)
907 924 if pushop.bkresult is not None:
908 925 pushop.bkresult = 1
909 926 return handlereply
910 927
911 928 @b2partsgenerator('pushvars', idx=0)
912 929 def _getbundlesendvars(pushop, bundler):
913 930 '''send shellvars via bundle2'''
914 931 pushvars = pushop.pushvars
915 932 if pushvars:
916 933 shellvars = {}
917 934 for raw in pushvars:
918 935 if '=' not in raw:
919 936 msg = ("unable to parse variable '%s', should follow "
920 937 "'KEY=VALUE' or 'KEY=' format")
921 938 raise error.Abort(msg % raw)
922 939 k, v = raw.split('=', 1)
923 940 shellvars[k] = v
924 941
925 942 part = bundler.newpart('pushvars')
926 943
927 944 for key, value in shellvars.iteritems():
928 945 part.addparam(key, value, mandatory=False)
929 946
930 947 def _pushbundle2(pushop):
931 948 """push data to the remote using bundle2
932 949
933 950 The only currently supported type of data is changegroup but this will
934 951 evolve in the future."""
935 952 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
936 953 pushback = (pushop.trmanager
937 954 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
938 955
939 956 # create reply capability
940 957 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
941 958 allowpushback=pushback))
942 959 bundler.newpart('replycaps', data=capsblob)
943 960 replyhandlers = []
944 961 for partgenname in b2partsgenorder:
945 962 partgen = b2partsgenmapping[partgenname]
946 963 ret = partgen(pushop, bundler)
947 964 if callable(ret):
948 965 replyhandlers.append(ret)
949 966 # do not push if nothing to push
950 967 if bundler.nbparts <= 1:
951 968 return
952 969 stream = util.chunkbuffer(bundler.getchunks())
953 970 try:
954 971 try:
955 972 reply = pushop.remote.unbundle(
956 973 stream, ['force'], pushop.remote.url())
957 974 except error.BundleValueError as exc:
958 975 raise error.Abort(_('missing support for %s') % exc)
959 976 try:
960 977 trgetter = None
961 978 if pushback:
962 979 trgetter = pushop.trmanager.transaction
963 980 op = bundle2.processbundle(pushop.repo, reply, trgetter)
964 981 except error.BundleValueError as exc:
965 982 raise error.Abort(_('missing support for %s') % exc)
966 983 except bundle2.AbortFromPart as exc:
967 984 pushop.ui.status(_('remote: %s\n') % exc)
968 985 if exc.hint is not None:
969 986 pushop.ui.status(_('remote: %s\n') % ('(%s)' % exc.hint))
970 987 raise error.Abort(_('push failed on remote'))
971 988 except error.PushkeyFailed as exc:
972 989 partid = int(exc.partid)
973 990 if partid not in pushop.pkfailcb:
974 991 raise
975 992 pushop.pkfailcb[partid](pushop, exc)
976 993 for rephand in replyhandlers:
977 994 rephand(op)
978 995
979 996 def _pushchangeset(pushop):
980 997 """Make the actual push of changeset bundle to remote repo"""
981 998 if 'changesets' in pushop.stepsdone:
982 999 return
983 1000 pushop.stepsdone.add('changesets')
984 1001 if not _pushcheckoutgoing(pushop):
985 1002 return
986 1003
987 1004 # Should have verified this in push().
988 1005 assert pushop.remote.capable('unbundle')
989 1006
990 1007 pushop.repo.prepushoutgoinghooks(pushop)
991 1008 outgoing = pushop.outgoing
992 1009 # TODO: get bundlecaps from remote
993 1010 bundlecaps = None
994 1011 # create a changegroup from local
995 1012 if pushop.revs is None and not (outgoing.excluded
996 1013 or pushop.repo.changelog.filteredrevs):
997 1014 # push everything,
998 1015 # use the fast path, no race possible on push
999 1016 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01', 'push',
1000 1017 fastpath=True, bundlecaps=bundlecaps)
1001 1018 else:
1002 1019 cg = changegroup.makechangegroup(pushop.repo, outgoing, '01',
1003 1020 'push', bundlecaps=bundlecaps)
1004 1021
1005 1022 # apply changegroup to remote
1006 1023 # local repo finds heads on server, finds out what
1007 1024 # revs it must push. once revs transferred, if server
1008 1025 # finds it has different heads (someone else won
1009 1026 # commit/push race), server aborts.
1010 1027 if pushop.force:
1011 1028 remoteheads = ['force']
1012 1029 else:
1013 1030 remoteheads = pushop.remoteheads
1014 1031 # ssh: return remote's addchangegroup()
1015 1032 # http: return remote's addchangegroup() or 0 for error
1016 1033 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
1017 1034 pushop.repo.url())
1018 1035
1019 1036 def _pushsyncphase(pushop):
1020 1037 """synchronise phase information locally and remotely"""
1021 1038 cheads = pushop.commonheads
1022 1039 # even when we don't push, exchanging phase data is useful
1023 1040 remotephases = pushop.remote.listkeys('phases')
1024 1041 if (pushop.ui.configbool('ui', '_usedassubrepo')
1025 1042 and remotephases # server supports phases
1026 1043 and pushop.cgresult is None # nothing was pushed
1027 1044 and remotephases.get('publishing', False)):
1028 1045 # When:
1029 1046 # - this is a subrepo push
1030 1047 # - and remote support phase
1031 1048 # - and no changeset was pushed
1032 1049 # - and remote is publishing
1033 1050 # We may be in issue 3871 case!
1034 1051 # We drop the possible phase synchronisation done by
1035 1052 # courtesy to publish changesets possibly locally draft
1036 1053 # on the remote.
1037 1054 remotephases = {'publishing': 'True'}
1038 1055 if not remotephases: # old server or public only reply from non-publishing
1039 1056 _localphasemove(pushop, cheads)
1040 1057 # don't push any phase data as there is nothing to push
1041 1058 else:
1042 1059 ana = phases.analyzeremotephases(pushop.repo, cheads,
1043 1060 remotephases)
1044 1061 pheads, droots = ana
1045 1062 ### Apply remote phase on local
1046 1063 if remotephases.get('publishing', False):
1047 1064 _localphasemove(pushop, cheads)
1048 1065 else: # publish = False
1049 1066 _localphasemove(pushop, pheads)
1050 1067 _localphasemove(pushop, cheads, phases.draft)
1051 1068 ### Apply local phase on remote
1052 1069
1053 1070 if pushop.cgresult:
1054 1071 if 'phases' in pushop.stepsdone:
1055 1072 # phases already pushed though bundle2
1056 1073 return
1057 1074 outdated = pushop.outdatedphases
1058 1075 else:
1059 1076 outdated = pushop.fallbackoutdatedphases
1060 1077
1061 1078 pushop.stepsdone.add('phases')
1062 1079
1063 1080 # filter heads already turned public by the push
1064 1081 outdated = [c for c in outdated if c.node() not in pheads]
1065 1082 # fallback to independent pushkey command
1066 1083 for newremotehead in outdated:
1067 1084 r = pushop.remote.pushkey('phases',
1068 1085 newremotehead.hex(),
1069 1086 str(phases.draft),
1070 1087 str(phases.public))
1071 1088 if not r:
1072 1089 pushop.ui.warn(_('updating %s to public failed!\n')
1073 1090 % newremotehead)
1074 1091
1075 1092 def _localphasemove(pushop, nodes, phase=phases.public):
1076 1093 """move <nodes> to <phase> in the local source repo"""
1077 1094 if pushop.trmanager:
1078 1095 phases.advanceboundary(pushop.repo,
1079 1096 pushop.trmanager.transaction(),
1080 1097 phase,
1081 1098 nodes)
1082 1099 else:
1083 1100 # repo is not locked, do not change any phases!
1084 1101 # Informs the user that phases should have been moved when
1085 1102 # applicable.
1086 1103 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1087 1104 phasestr = phases.phasenames[phase]
1088 1105 if actualmoves:
1089 1106 pushop.ui.status(_('cannot lock source repo, skipping '
1090 1107 'local %s phase update\n') % phasestr)
1091 1108
1092 1109 def _pushobsolete(pushop):
1093 1110 """utility function to push obsolete markers to a remote"""
1094 1111 if 'obsmarkers' in pushop.stepsdone:
1095 1112 return
1096 1113 repo = pushop.repo
1097 1114 remote = pushop.remote
1098 1115 pushop.stepsdone.add('obsmarkers')
1099 1116 if pushop.outobsmarkers:
1100 1117 pushop.ui.debug('try to push obsolete markers to remote\n')
1101 1118 rslts = []
1102 1119 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
1103 1120 for key in sorted(remotedata, reverse=True):
1104 1121 # reverse sort to ensure we end with dump0
1105 1122 data = remotedata[key]
1106 1123 rslts.append(remote.pushkey('obsolete', key, '', data))
1107 1124 if [r for r in rslts if not r]:
1108 1125 msg = _('failed to push some obsolete markers!\n')
1109 1126 repo.ui.warn(msg)
1110 1127
1111 1128 def _pushbookmark(pushop):
1112 1129 """Update bookmark position on remote"""
1113 1130 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
1114 1131 return
1115 1132 pushop.stepsdone.add('bookmarks')
1116 1133 ui = pushop.ui
1117 1134 remote = pushop.remote
1118 1135
1119 1136 for b, old, new in pushop.outbookmarks:
1120 1137 action = 'update'
1121 1138 if not old:
1122 1139 action = 'export'
1123 1140 elif not new:
1124 1141 action = 'delete'
1125 1142 if remote.pushkey('bookmarks', b, old, new):
1126 1143 ui.status(bookmsgmap[action][0] % b)
1127 1144 else:
1128 1145 ui.warn(bookmsgmap[action][1] % b)
1129 1146 # discovery can have set the value form invalid entry
1130 1147 if pushop.bkresult is not None:
1131 1148 pushop.bkresult = 1
1132 1149
1133 1150 class pulloperation(object):
1134 1151 """A object that represent a single pull operation
1135 1152
1136 1153 It purpose is to carry pull related state and very common operation.
1137 1154
1138 1155 A new should be created at the beginning of each pull and discarded
1139 1156 afterward.
1140 1157 """
1141 1158
1142 1159 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
1143 1160 remotebookmarks=None, streamclonerequested=None):
1144 1161 # repo we pull into
1145 1162 self.repo = repo
1146 1163 # repo we pull from
1147 1164 self.remote = remote
1148 1165 # revision we try to pull (None is "all")
1149 1166 self.heads = heads
1150 1167 # bookmark pulled explicitly
1151 1168 self.explicitbookmarks = [repo._bookmarks.expandname(bookmark)
1152 1169 for bookmark in bookmarks]
1153 1170 # do we force pull?
1154 1171 self.force = force
1155 1172 # whether a streaming clone was requested
1156 1173 self.streamclonerequested = streamclonerequested
1157 1174 # transaction manager
1158 1175 self.trmanager = None
1159 1176 # set of common changeset between local and remote before pull
1160 1177 self.common = None
1161 1178 # set of pulled head
1162 1179 self.rheads = None
1163 1180 # list of missing changeset to fetch remotely
1164 1181 self.fetch = None
1165 1182 # remote bookmarks data
1166 1183 self.remotebookmarks = remotebookmarks
1167 1184 # result of changegroup pulling (used as return code by pull)
1168 1185 self.cgresult = None
1169 1186 # list of step already done
1170 1187 self.stepsdone = set()
1171 1188 # Whether we attempted a clone from pre-generated bundles.
1172 1189 self.clonebundleattempted = False
1173 1190
1174 1191 @util.propertycache
1175 1192 def pulledsubset(self):
1176 1193 """heads of the set of changeset target by the pull"""
1177 1194 # compute target subset
1178 1195 if self.heads is None:
1179 1196 # We pulled every thing possible
1180 1197 # sync on everything common
1181 1198 c = set(self.common)
1182 1199 ret = list(self.common)
1183 1200 for n in self.rheads:
1184 1201 if n not in c:
1185 1202 ret.append(n)
1186 1203 return ret
1187 1204 else:
1188 1205 # We pulled a specific subset
1189 1206 # sync on this subset
1190 1207 return self.heads
1191 1208
1192 1209 @util.propertycache
1193 1210 def canusebundle2(self):
1194 1211 return not _forcebundle1(self)
1195 1212
1196 1213 @util.propertycache
1197 1214 def remotebundle2caps(self):
1198 1215 return bundle2.bundle2caps(self.remote)
1199 1216
1200 1217 def gettransaction(self):
1201 1218 # deprecated; talk to trmanager directly
1202 1219 return self.trmanager.transaction()
1203 1220
1204 1221 class transactionmanager(util.transactional):
1205 1222 """An object to manage the life cycle of a transaction
1206 1223
1207 1224 It creates the transaction on demand and calls the appropriate hooks when
1208 1225 closing the transaction."""
1209 1226 def __init__(self, repo, source, url):
1210 1227 self.repo = repo
1211 1228 self.source = source
1212 1229 self.url = url
1213 1230 self._tr = None
1214 1231
1215 1232 def transaction(self):
1216 1233 """Return an open transaction object, constructing if necessary"""
1217 1234 if not self._tr:
1218 1235 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
1219 1236 self._tr = self.repo.transaction(trname)
1220 1237 self._tr.hookargs['source'] = self.source
1221 1238 self._tr.hookargs['url'] = self.url
1222 1239 return self._tr
1223 1240
1224 1241 def close(self):
1225 1242 """close transaction if created"""
1226 1243 if self._tr is not None:
1227 1244 self._tr.close()
1228 1245
1229 1246 def release(self):
1230 1247 """release transaction if created"""
1231 1248 if self._tr is not None:
1232 1249 self._tr.release()
1233 1250
1234 1251 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None,
1235 1252 streamclonerequested=None):
1236 1253 """Fetch repository data from a remote.
1237 1254
1238 1255 This is the main function used to retrieve data from a remote repository.
1239 1256
1240 1257 ``repo`` is the local repository to clone into.
1241 1258 ``remote`` is a peer instance.
1242 1259 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1243 1260 default) means to pull everything from the remote.
1244 1261 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1245 1262 default, all remote bookmarks are pulled.
1246 1263 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1247 1264 initialization.
1248 1265 ``streamclonerequested`` is a boolean indicating whether a "streaming
1249 1266 clone" is requested. A "streaming clone" is essentially a raw file copy
1250 1267 of revlogs from the server. This only works when the local repository is
1251 1268 empty. The default value of ``None`` means to respect the server
1252 1269 configuration for preferring stream clones.
1253 1270
1254 1271 Returns the ``pulloperation`` created for this pull.
1255 1272 """
1256 1273 if opargs is None:
1257 1274 opargs = {}
1258 1275 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
1259 1276 streamclonerequested=streamclonerequested, **opargs)
1260 1277
1261 1278 peerlocal = pullop.remote.local()
1262 1279 if peerlocal:
1263 1280 missing = set(peerlocal.requirements) - pullop.repo.supported
1264 1281 if missing:
1265 1282 msg = _("required features are not"
1266 1283 " supported in the destination:"
1267 1284 " %s") % (', '.join(sorted(missing)))
1268 1285 raise error.Abort(msg)
1269 1286
1270 1287 wlock = lock = None
1271 1288 try:
1272 1289 wlock = pullop.repo.wlock()
1273 1290 lock = pullop.repo.lock()
1274 1291 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
1275 1292 # This should ideally be in _pullbundle2(). However, it needs to run
1276 1293 # before discovery to avoid extra work.
1277 1294 _maybeapplyclonebundle(pullop)
1278 1295 streamclone.maybeperformlegacystreamclone(pullop)
1279 1296 _pulldiscovery(pullop)
1280 1297 if pullop.canusebundle2:
1281 1298 _pullbundle2(pullop)
1282 1299 _pullchangeset(pullop)
1283 1300 _pullphase(pullop)
1284 1301 _pullbookmarks(pullop)
1285 1302 _pullobsolete(pullop)
1286 1303 pullop.trmanager.close()
1287 1304 finally:
1288 1305 lockmod.release(pullop.trmanager, lock, wlock)
1289 1306
1290 1307 return pullop
1291 1308
1292 1309 # list of steps to perform discovery before pull
1293 1310 pulldiscoveryorder = []
1294 1311
1295 1312 # Mapping between step name and function
1296 1313 #
1297 1314 # This exists to help extensions wrap steps if necessary
1298 1315 pulldiscoverymapping = {}
1299 1316
1300 1317 def pulldiscovery(stepname):
1301 1318 """decorator for function performing discovery before pull
1302 1319
1303 1320 The function is added to the step -> function mapping and appended to the
1304 1321 list of steps. Beware that decorated function will be added in order (this
1305 1322 may matter).
1306 1323
1307 1324 You can only use this decorator for a new step, if you want to wrap a step
1308 1325 from an extension, change the pulldiscovery dictionary directly."""
1309 1326 def dec(func):
1310 1327 assert stepname not in pulldiscoverymapping
1311 1328 pulldiscoverymapping[stepname] = func
1312 1329 pulldiscoveryorder.append(stepname)
1313 1330 return func
1314 1331 return dec
1315 1332
1316 1333 def _pulldiscovery(pullop):
1317 1334 """Run all discovery steps"""
1318 1335 for stepname in pulldiscoveryorder:
1319 1336 step = pulldiscoverymapping[stepname]
1320 1337 step(pullop)
1321 1338
1322 1339 @pulldiscovery('b1:bookmarks')
1323 1340 def _pullbookmarkbundle1(pullop):
1324 1341 """fetch bookmark data in bundle1 case
1325 1342
1326 1343 If not using bundle2, we have to fetch bookmarks before changeset
1327 1344 discovery to reduce the chance and impact of race conditions."""
1328 1345 if pullop.remotebookmarks is not None:
1329 1346 return
1330 1347 if pullop.canusebundle2 and 'listkeys' in pullop.remotebundle2caps:
1331 1348 # all known bundle2 servers now support listkeys, but lets be nice with
1332 1349 # new implementation.
1333 1350 return
1334 1351 pullop.remotebookmarks = pullop.remote.listkeys('bookmarks')
1335 1352
1336 1353
1337 1354 @pulldiscovery('changegroup')
1338 1355 def _pulldiscoverychangegroup(pullop):
1339 1356 """discovery phase for the pull
1340 1357
1341 1358 Current handle changeset discovery only, will change handle all discovery
1342 1359 at some point."""
1343 1360 tmp = discovery.findcommonincoming(pullop.repo,
1344 1361 pullop.remote,
1345 1362 heads=pullop.heads,
1346 1363 force=pullop.force)
1347 1364 common, fetch, rheads = tmp
1348 1365 nm = pullop.repo.unfiltered().changelog.nodemap
1349 1366 if fetch and rheads:
1350 1367 # If a remote heads is filtered locally, put in back in common.
1351 1368 #
1352 1369 # This is a hackish solution to catch most of "common but locally
1353 1370 # hidden situation". We do not performs discovery on unfiltered
1354 1371 # repository because it end up doing a pathological amount of round
1355 1372 # trip for w huge amount of changeset we do not care about.
1356 1373 #
1357 1374 # If a set of such "common but filtered" changeset exist on the server
1358 1375 # but are not including a remote heads, we'll not be able to detect it,
1359 1376 scommon = set(common)
1360 1377 for n in rheads:
1361 1378 if n in nm:
1362 1379 if n not in scommon:
1363 1380 common.append(n)
1364 1381 if set(rheads).issubset(set(common)):
1365 1382 fetch = []
1366 1383 pullop.common = common
1367 1384 pullop.fetch = fetch
1368 1385 pullop.rheads = rheads
1369 1386
1370 1387 def _pullbundle2(pullop):
1371 1388 """pull data using bundle2
1372 1389
1373 1390 For now, the only supported data are changegroup."""
1374 1391 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
1375 1392
1376 1393 # At the moment we don't do stream clones over bundle2. If that is
1377 1394 # implemented then here's where the check for that will go.
1378 1395 streaming = False
1379 1396
1380 1397 # pulling changegroup
1381 1398 pullop.stepsdone.add('changegroup')
1382 1399
1383 1400 kwargs['common'] = pullop.common
1384 1401 kwargs['heads'] = pullop.heads or pullop.rheads
1385 1402 kwargs['cg'] = pullop.fetch
1386 1403
1387 1404 ui = pullop.repo.ui
1388 1405 legacyphase = 'phases' in ui.configlist('devel', 'legacy.exchange')
1389 1406 hasbinaryphase = 'heads' in pullop.remotebundle2caps.get('phases', ())
1390 1407 if (not legacyphase and hasbinaryphase):
1391 1408 kwargs['phases'] = True
1392 1409 pullop.stepsdone.add('phases')
1393 1410
1394 1411 if 'listkeys' in pullop.remotebundle2caps:
1395 1412 if 'phases' not in pullop.stepsdone:
1396 1413 kwargs['listkeys'] = ['phases']
1397 1414 if pullop.remotebookmarks is None:
1398 1415 # make sure to always includes bookmark data when migrating
1399 1416 # `hg incoming --bundle` to using this function.
1400 1417 kwargs.setdefault('listkeys', []).append('bookmarks')
1401 1418
1402 1419 # If this is a full pull / clone and the server supports the clone bundles
1403 1420 # feature, tell the server whether we attempted a clone bundle. The
1404 1421 # presence of this flag indicates the client supports clone bundles. This
1405 1422 # will enable the server to treat clients that support clone bundles
1406 1423 # differently from those that don't.
1407 1424 if (pullop.remote.capable('clonebundles')
1408 1425 and pullop.heads is None and list(pullop.common) == [nullid]):
1409 1426 kwargs['cbattempted'] = pullop.clonebundleattempted
1410 1427
1411 1428 if streaming:
1412 1429 pullop.repo.ui.status(_('streaming all changes\n'))
1413 1430 elif not pullop.fetch:
1414 1431 pullop.repo.ui.status(_("no changes found\n"))
1415 1432 pullop.cgresult = 0
1416 1433 else:
1417 1434 if pullop.heads is None and list(pullop.common) == [nullid]:
1418 1435 pullop.repo.ui.status(_("requesting all changes\n"))
1419 1436 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1420 1437 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
1421 1438 if obsolete.commonversion(remoteversions) is not None:
1422 1439 kwargs['obsmarkers'] = True
1423 1440 pullop.stepsdone.add('obsmarkers')
1424 1441 _pullbundle2extraprepare(pullop, kwargs)
1425 1442 bundle = pullop.remote.getbundle('pull', **pycompat.strkwargs(kwargs))
1426 1443 try:
1427 1444 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
1428 1445 except bundle2.AbortFromPart as exc:
1429 1446 pullop.repo.ui.status(_('remote: abort: %s\n') % exc)
1430 1447 raise error.Abort(_('pull failed on remote'), hint=exc.hint)
1431 1448 except error.BundleValueError as exc:
1432 1449 raise error.Abort(_('missing support for %s') % exc)
1433 1450
1434 1451 if pullop.fetch:
1435 1452 pullop.cgresult = bundle2.combinechangegroupresults(op)
1436 1453
1437 1454 # processing phases change
1438 1455 for namespace, value in op.records['listkeys']:
1439 1456 if namespace == 'phases':
1440 1457 _pullapplyphases(pullop, value)
1441 1458
1442 1459 # processing bookmark update
1443 1460 for namespace, value in op.records['listkeys']:
1444 1461 if namespace == 'bookmarks':
1445 1462 pullop.remotebookmarks = value
1446 1463
1447 1464 # bookmark data were either already there or pulled in the bundle
1448 1465 if pullop.remotebookmarks is not None:
1449 1466 _pullbookmarks(pullop)
1450 1467
1451 1468 def _pullbundle2extraprepare(pullop, kwargs):
1452 1469 """hook function so that extensions can extend the getbundle call"""
1453 1470
1454 1471 def _pullchangeset(pullop):
1455 1472 """pull changeset from unbundle into the local repo"""
1456 1473 # We delay the open of the transaction as late as possible so we
1457 1474 # don't open transaction for nothing or you break future useful
1458 1475 # rollback call
1459 1476 if 'changegroup' in pullop.stepsdone:
1460 1477 return
1461 1478 pullop.stepsdone.add('changegroup')
1462 1479 if not pullop.fetch:
1463 1480 pullop.repo.ui.status(_("no changes found\n"))
1464 1481 pullop.cgresult = 0
1465 1482 return
1466 1483 tr = pullop.gettransaction()
1467 1484 if pullop.heads is None and list(pullop.common) == [nullid]:
1468 1485 pullop.repo.ui.status(_("requesting all changes\n"))
1469 1486 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1470 1487 # issue1320, avoid a race if remote changed after discovery
1471 1488 pullop.heads = pullop.rheads
1472 1489
1473 1490 if pullop.remote.capable('getbundle'):
1474 1491 # TODO: get bundlecaps from remote
1475 1492 cg = pullop.remote.getbundle('pull', common=pullop.common,
1476 1493 heads=pullop.heads or pullop.rheads)
1477 1494 elif pullop.heads is None:
1478 1495 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1479 1496 elif not pullop.remote.capable('changegroupsubset'):
1480 1497 raise error.Abort(_("partial pull cannot be done because "
1481 1498 "other repository doesn't support "
1482 1499 "changegroupsubset."))
1483 1500 else:
1484 1501 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1485 1502 bundleop = bundle2.applybundle(pullop.repo, cg, tr, 'pull',
1486 1503 pullop.remote.url())
1487 1504 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
1488 1505
1489 1506 def _pullphase(pullop):
1490 1507 # Get remote phases data from remote
1491 1508 if 'phases' in pullop.stepsdone:
1492 1509 return
1493 1510 remotephases = pullop.remote.listkeys('phases')
1494 1511 _pullapplyphases(pullop, remotephases)
1495 1512
1496 1513 def _pullapplyphases(pullop, remotephases):
1497 1514 """apply phase movement from observed remote state"""
1498 1515 if 'phases' in pullop.stepsdone:
1499 1516 return
1500 1517 pullop.stepsdone.add('phases')
1501 1518 publishing = bool(remotephases.get('publishing', False))
1502 1519 if remotephases and not publishing:
1503 1520 # remote is new and non-publishing
1504 1521 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1505 1522 pullop.pulledsubset,
1506 1523 remotephases)
1507 1524 dheads = pullop.pulledsubset
1508 1525 else:
1509 1526 # Remote is old or publishing all common changesets
1510 1527 # should be seen as public
1511 1528 pheads = pullop.pulledsubset
1512 1529 dheads = []
1513 1530 unfi = pullop.repo.unfiltered()
1514 1531 phase = unfi._phasecache.phase
1515 1532 rev = unfi.changelog.nodemap.get
1516 1533 public = phases.public
1517 1534 draft = phases.draft
1518 1535
1519 1536 # exclude changesets already public locally and update the others
1520 1537 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1521 1538 if pheads:
1522 1539 tr = pullop.gettransaction()
1523 1540 phases.advanceboundary(pullop.repo, tr, public, pheads)
1524 1541
1525 1542 # exclude changesets already draft locally and update the others
1526 1543 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1527 1544 if dheads:
1528 1545 tr = pullop.gettransaction()
1529 1546 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1530 1547
1531 1548 def _pullbookmarks(pullop):
1532 1549 """process the remote bookmark information to update the local one"""
1533 1550 if 'bookmarks' in pullop.stepsdone:
1534 1551 return
1535 1552 pullop.stepsdone.add('bookmarks')
1536 1553 repo = pullop.repo
1537 1554 remotebookmarks = pullop.remotebookmarks
1538 1555 remotebookmarks = bookmod.unhexlifybookmarks(remotebookmarks)
1539 1556 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1540 1557 pullop.remote.url(),
1541 1558 pullop.gettransaction,
1542 1559 explicit=pullop.explicitbookmarks)
1543 1560
1544 1561 def _pullobsolete(pullop):
1545 1562 """utility function to pull obsolete markers from a remote
1546 1563
1547 1564 The `gettransaction` is function that return the pull transaction, creating
1548 1565 one if necessary. We return the transaction to inform the calling code that
1549 1566 a new transaction have been created (when applicable).
1550 1567
1551 1568 Exists mostly to allow overriding for experimentation purpose"""
1552 1569 if 'obsmarkers' in pullop.stepsdone:
1553 1570 return
1554 1571 pullop.stepsdone.add('obsmarkers')
1555 1572 tr = None
1556 1573 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1557 1574 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1558 1575 remoteobs = pullop.remote.listkeys('obsolete')
1559 1576 if 'dump0' in remoteobs:
1560 1577 tr = pullop.gettransaction()
1561 1578 markers = []
1562 1579 for key in sorted(remoteobs, reverse=True):
1563 1580 if key.startswith('dump'):
1564 1581 data = util.b85decode(remoteobs[key])
1565 1582 version, newmarks = obsolete._readmarkers(data)
1566 1583 markers += newmarks
1567 1584 if markers:
1568 1585 pullop.repo.obsstore.add(tr, markers)
1569 1586 pullop.repo.invalidatevolatilesets()
1570 1587 return tr
1571 1588
1572 1589 def caps20to10(repo):
1573 1590 """return a set with appropriate options to use bundle20 during getbundle"""
1574 1591 caps = {'HG20'}
1575 1592 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1576 1593 caps.add('bundle2=' + urlreq.quote(capsblob))
1577 1594 return caps
1578 1595
1579 1596 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1580 1597 getbundle2partsorder = []
1581 1598
1582 1599 # Mapping between step name and function
1583 1600 #
1584 1601 # This exists to help extensions wrap steps if necessary
1585 1602 getbundle2partsmapping = {}
1586 1603
1587 1604 def getbundle2partsgenerator(stepname, idx=None):
1588 1605 """decorator for function generating bundle2 part for getbundle
1589 1606
1590 1607 The function is added to the step -> function mapping and appended to the
1591 1608 list of steps. Beware that decorated functions will be added in order
1592 1609 (this may matter).
1593 1610
1594 1611 You can only use this decorator for new steps, if you want to wrap a step
1595 1612 from an extension, attack the getbundle2partsmapping dictionary directly."""
1596 1613 def dec(func):
1597 1614 assert stepname not in getbundle2partsmapping
1598 1615 getbundle2partsmapping[stepname] = func
1599 1616 if idx is None:
1600 1617 getbundle2partsorder.append(stepname)
1601 1618 else:
1602 1619 getbundle2partsorder.insert(idx, stepname)
1603 1620 return func
1604 1621 return dec
1605 1622
1606 1623 def bundle2requested(bundlecaps):
1607 1624 if bundlecaps is not None:
1608 1625 return any(cap.startswith('HG2') for cap in bundlecaps)
1609 1626 return False
1610 1627
1611 1628 def getbundlechunks(repo, source, heads=None, common=None, bundlecaps=None,
1612 1629 **kwargs):
1613 1630 """Return chunks constituting a bundle's raw data.
1614 1631
1615 1632 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1616 1633 passed.
1617 1634
1618 1635 Returns an iterator over raw chunks (of varying sizes).
1619 1636 """
1620 1637 kwargs = pycompat.byteskwargs(kwargs)
1621 1638 usebundle2 = bundle2requested(bundlecaps)
1622 1639 # bundle10 case
1623 1640 if not usebundle2:
1624 1641 if bundlecaps and not kwargs.get('cg', True):
1625 1642 raise ValueError(_('request for bundle10 must include changegroup'))
1626 1643
1627 1644 if kwargs:
1628 1645 raise ValueError(_('unsupported getbundle arguments: %s')
1629 1646 % ', '.join(sorted(kwargs.keys())))
1630 1647 outgoing = _computeoutgoing(repo, heads, common)
1631 1648 return changegroup.makestream(repo, outgoing, '01', source,
1632 1649 bundlecaps=bundlecaps)
1633 1650
1634 1651 # bundle20 case
1635 1652 b2caps = {}
1636 1653 for bcaps in bundlecaps:
1637 1654 if bcaps.startswith('bundle2='):
1638 1655 blob = urlreq.unquote(bcaps[len('bundle2='):])
1639 1656 b2caps.update(bundle2.decodecaps(blob))
1640 1657 bundler = bundle2.bundle20(repo.ui, b2caps)
1641 1658
1642 1659 kwargs['heads'] = heads
1643 1660 kwargs['common'] = common
1644 1661
1645 1662 for name in getbundle2partsorder:
1646 1663 func = getbundle2partsmapping[name]
1647 1664 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1648 1665 **pycompat.strkwargs(kwargs))
1649 1666
1650 1667 return bundler.getchunks()
1651 1668
1652 1669 @getbundle2partsgenerator('changegroup')
1653 1670 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1654 1671 b2caps=None, heads=None, common=None, **kwargs):
1655 1672 """add a changegroup part to the requested bundle"""
1656 1673 cgstream = None
1657 1674 if kwargs.get('cg', True):
1658 1675 # build changegroup bundle here.
1659 1676 version = '01'
1660 1677 cgversions = b2caps.get('changegroup')
1661 1678 if cgversions: # 3.1 and 3.2 ship with an empty value
1662 1679 cgversions = [v for v in cgversions
1663 1680 if v in changegroup.supportedoutgoingversions(repo)]
1664 1681 if not cgversions:
1665 1682 raise ValueError(_('no common changegroup version'))
1666 1683 version = max(cgversions)
1667 1684 outgoing = _computeoutgoing(repo, heads, common)
1668 1685 if outgoing.missing:
1669 1686 cgstream = changegroup.makestream(repo, outgoing, version, source,
1670 1687 bundlecaps=bundlecaps)
1671 1688
1672 1689 if cgstream:
1673 1690 part = bundler.newpart('changegroup', data=cgstream)
1674 1691 if cgversions:
1675 1692 part.addparam('version', version)
1676 1693 part.addparam('nbchanges', '%d' % len(outgoing.missing),
1677 1694 mandatory=False)
1678 1695 if 'treemanifest' in repo.requirements:
1679 1696 part.addparam('treemanifest', '1')
1680 1697
1681 1698 @getbundle2partsgenerator('listkeys')
1682 1699 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1683 1700 b2caps=None, **kwargs):
1684 1701 """add parts containing listkeys namespaces to the requested bundle"""
1685 1702 listkeys = kwargs.get('listkeys', ())
1686 1703 for namespace in listkeys:
1687 1704 part = bundler.newpart('listkeys')
1688 1705 part.addparam('namespace', namespace)
1689 1706 keys = repo.listkeys(namespace).items()
1690 1707 part.data = pushkey.encodekeys(keys)
1691 1708
1692 1709 @getbundle2partsgenerator('obsmarkers')
1693 1710 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1694 1711 b2caps=None, heads=None, **kwargs):
1695 1712 """add an obsolescence markers part to the requested bundle"""
1696 1713 if kwargs.get('obsmarkers', False):
1697 1714 if heads is None:
1698 1715 heads = repo.heads()
1699 1716 subset = [c.node() for c in repo.set('::%ln', heads)]
1700 1717 markers = repo.obsstore.relevantmarkers(subset)
1701 1718 markers = sorted(markers)
1702 1719 bundle2.buildobsmarkerspart(bundler, markers)
1703 1720
1704 1721 @getbundle2partsgenerator('phases')
1705 1722 def _getbundlephasespart(bundler, repo, source, bundlecaps=None,
1706 1723 b2caps=None, heads=None, **kwargs):
1707 1724 """add phase heads part to the requested bundle"""
1708 1725 if kwargs.get('phases', False):
1709 1726 if not 'heads' in b2caps.get('phases'):
1710 1727 raise ValueError(_('no common phases exchange method'))
1711 1728 if heads is None:
1712 1729 heads = repo.heads()
1713 1730
1714 1731 headsbyphase = collections.defaultdict(set)
1715 1732 if repo.publishing():
1716 1733 headsbyphase[phases.public] = heads
1717 1734 else:
1718 1735 # find the appropriate heads to move
1719 1736
1720 1737 phase = repo._phasecache.phase
1721 1738 node = repo.changelog.node
1722 1739 rev = repo.changelog.rev
1723 1740 for h in heads:
1724 1741 headsbyphase[phase(repo, rev(h))].add(h)
1725 1742 seenphases = list(headsbyphase.keys())
1726 1743
1727 1744 # We do not handle anything but public and draft phase for now)
1728 1745 if seenphases:
1729 1746 assert max(seenphases) <= phases.draft
1730 1747
1731 1748 # if client is pulling non-public changesets, we need to find
1732 1749 # intermediate public heads.
1733 1750 draftheads = headsbyphase.get(phases.draft, set())
1734 1751 if draftheads:
1735 1752 publicheads = headsbyphase.get(phases.public, set())
1736 1753
1737 1754 revset = 'heads(only(%ln, %ln) and public())'
1738 1755 extraheads = repo.revs(revset, draftheads, publicheads)
1739 1756 for r in extraheads:
1740 1757 headsbyphase[phases.public].add(node(r))
1741 1758
1742 1759 # transform data in a format used by the encoding function
1743 1760 phasemapping = []
1744 1761 for phase in phases.allphases:
1745 1762 phasemapping.append(sorted(headsbyphase[phase]))
1746 1763
1747 1764 # generate the actual part
1748 1765 phasedata = phases.binaryencode(phasemapping)
1749 1766 bundler.newpart('phase-heads', data=phasedata)
1750 1767
1751 1768 @getbundle2partsgenerator('hgtagsfnodes')
1752 1769 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
1753 1770 b2caps=None, heads=None, common=None,
1754 1771 **kwargs):
1755 1772 """Transfer the .hgtags filenodes mapping.
1756 1773
1757 1774 Only values for heads in this bundle will be transferred.
1758 1775
1759 1776 The part data consists of pairs of 20 byte changeset node and .hgtags
1760 1777 filenodes raw values.
1761 1778 """
1762 1779 # Don't send unless:
1763 1780 # - changeset are being exchanged,
1764 1781 # - the client supports it.
1765 1782 if not (kwargs.get('cg', True) and 'hgtagsfnodes' in b2caps):
1766 1783 return
1767 1784
1768 1785 outgoing = _computeoutgoing(repo, heads, common)
1769 1786 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
1770 1787
1771 1788 def _getbookmarks(repo, **kwargs):
1772 1789 """Returns bookmark to node mapping.
1773 1790
1774 1791 This function is primarily used to generate `bookmarks` bundle2 part.
1775 1792 It is a separate function in order to make it easy to wrap it
1776 1793 in extensions. Passing `kwargs` to the function makes it easy to
1777 1794 add new parameters in extensions.
1778 1795 """
1779 1796
1780 1797 return dict(bookmod.listbinbookmarks(repo))
1781 1798
1782 1799 def check_heads(repo, their_heads, context):
1783 1800 """check if the heads of a repo have been modified
1784 1801
1785 1802 Used by peer for unbundling.
1786 1803 """
1787 1804 heads = repo.heads()
1788 1805 heads_hash = hashlib.sha1(''.join(sorted(heads))).digest()
1789 1806 if not (their_heads == ['force'] or their_heads == heads or
1790 1807 their_heads == ['hashed', heads_hash]):
1791 1808 # someone else committed/pushed/unbundled while we
1792 1809 # were transferring data
1793 1810 raise error.PushRaced('repository changed while %s - '
1794 1811 'please try again' % context)
1795 1812
1796 1813 def unbundle(repo, cg, heads, source, url):
1797 1814 """Apply a bundle to a repo.
1798 1815
1799 1816 this function makes sure the repo is locked during the application and have
1800 1817 mechanism to check that no push race occurred between the creation of the
1801 1818 bundle and its application.
1802 1819
1803 1820 If the push was raced as PushRaced exception is raised."""
1804 1821 r = 0
1805 1822 # need a transaction when processing a bundle2 stream
1806 1823 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
1807 1824 lockandtr = [None, None, None]
1808 1825 recordout = None
1809 1826 # quick fix for output mismatch with bundle2 in 3.4
1810 1827 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture')
1811 1828 if url.startswith('remote:http:') or url.startswith('remote:https:'):
1812 1829 captureoutput = True
1813 1830 try:
1814 1831 # note: outside bundle1, 'heads' is expected to be empty and this
1815 1832 # 'check_heads' call wil be a no-op
1816 1833 check_heads(repo, heads, 'uploading changes')
1817 1834 # push can proceed
1818 1835 if not isinstance(cg, bundle2.unbundle20):
1819 1836 # legacy case: bundle1 (changegroup 01)
1820 1837 txnname = "\n".join([source, util.hidepassword(url)])
1821 1838 with repo.lock(), repo.transaction(txnname) as tr:
1822 1839 op = bundle2.applybundle(repo, cg, tr, source, url)
1823 1840 r = bundle2.combinechangegroupresults(op)
1824 1841 else:
1825 1842 r = None
1826 1843 try:
1827 1844 def gettransaction():
1828 1845 if not lockandtr[2]:
1829 1846 lockandtr[0] = repo.wlock()
1830 1847 lockandtr[1] = repo.lock()
1831 1848 lockandtr[2] = repo.transaction(source)
1832 1849 lockandtr[2].hookargs['source'] = source
1833 1850 lockandtr[2].hookargs['url'] = url
1834 1851 lockandtr[2].hookargs['bundle2'] = '1'
1835 1852 return lockandtr[2]
1836 1853
1837 1854 # Do greedy locking by default until we're satisfied with lazy
1838 1855 # locking.
1839 1856 if not repo.ui.configbool('experimental', 'bundle2lazylocking'):
1840 1857 gettransaction()
1841 1858
1842 1859 op = bundle2.bundleoperation(repo, gettransaction,
1843 1860 captureoutput=captureoutput)
1844 1861 try:
1845 1862 op = bundle2.processbundle(repo, cg, op=op)
1846 1863 finally:
1847 1864 r = op.reply
1848 1865 if captureoutput and r is not None:
1849 1866 repo.ui.pushbuffer(error=True, subproc=True)
1850 1867 def recordout(output):
1851 1868 r.newpart('output', data=output, mandatory=False)
1852 1869 if lockandtr[2] is not None:
1853 1870 lockandtr[2].close()
1854 1871 except BaseException as exc:
1855 1872 exc.duringunbundle2 = True
1856 1873 if captureoutput and r is not None:
1857 1874 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1858 1875 def recordout(output):
1859 1876 part = bundle2.bundlepart('output', data=output,
1860 1877 mandatory=False)
1861 1878 parts.append(part)
1862 1879 raise
1863 1880 finally:
1864 1881 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
1865 1882 if recordout is not None:
1866 1883 recordout(repo.ui.popbuffer())
1867 1884 return r
1868 1885
1869 1886 def _maybeapplyclonebundle(pullop):
1870 1887 """Apply a clone bundle from a remote, if possible."""
1871 1888
1872 1889 repo = pullop.repo
1873 1890 remote = pullop.remote
1874 1891
1875 1892 if not repo.ui.configbool('ui', 'clonebundles'):
1876 1893 return
1877 1894
1878 1895 # Only run if local repo is empty.
1879 1896 if len(repo):
1880 1897 return
1881 1898
1882 1899 if pullop.heads:
1883 1900 return
1884 1901
1885 1902 if not remote.capable('clonebundles'):
1886 1903 return
1887 1904
1888 1905 res = remote._call('clonebundles')
1889 1906
1890 1907 # If we call the wire protocol command, that's good enough to record the
1891 1908 # attempt.
1892 1909 pullop.clonebundleattempted = True
1893 1910
1894 1911 entries = parseclonebundlesmanifest(repo, res)
1895 1912 if not entries:
1896 1913 repo.ui.note(_('no clone bundles available on remote; '
1897 1914 'falling back to regular clone\n'))
1898 1915 return
1899 1916
1900 1917 entries = filterclonebundleentries(
1901 1918 repo, entries, streamclonerequested=pullop.streamclonerequested)
1902 1919
1903 1920 if not entries:
1904 1921 # There is a thundering herd concern here. However, if a server
1905 1922 # operator doesn't advertise bundles appropriate for its clients,
1906 1923 # they deserve what's coming. Furthermore, from a client's
1907 1924 # perspective, no automatic fallback would mean not being able to
1908 1925 # clone!
1909 1926 repo.ui.warn(_('no compatible clone bundles available on server; '
1910 1927 'falling back to regular clone\n'))
1911 1928 repo.ui.warn(_('(you may want to report this to the server '
1912 1929 'operator)\n'))
1913 1930 return
1914 1931
1915 1932 entries = sortclonebundleentries(repo.ui, entries)
1916 1933
1917 1934 url = entries[0]['URL']
1918 1935 repo.ui.status(_('applying clone bundle from %s\n') % url)
1919 1936 if trypullbundlefromurl(repo.ui, repo, url):
1920 1937 repo.ui.status(_('finished applying clone bundle\n'))
1921 1938 # Bundle failed.
1922 1939 #
1923 1940 # We abort by default to avoid the thundering herd of
1924 1941 # clients flooding a server that was expecting expensive
1925 1942 # clone load to be offloaded.
1926 1943 elif repo.ui.configbool('ui', 'clonebundlefallback'):
1927 1944 repo.ui.warn(_('falling back to normal clone\n'))
1928 1945 else:
1929 1946 raise error.Abort(_('error applying bundle'),
1930 1947 hint=_('if this error persists, consider contacting '
1931 1948 'the server operator or disable clone '
1932 1949 'bundles via '
1933 1950 '"--config ui.clonebundles=false"'))
1934 1951
1935 1952 def parseclonebundlesmanifest(repo, s):
1936 1953 """Parses the raw text of a clone bundles manifest.
1937 1954
1938 1955 Returns a list of dicts. The dicts have a ``URL`` key corresponding
1939 1956 to the URL and other keys are the attributes for the entry.
1940 1957 """
1941 1958 m = []
1942 1959 for line in s.splitlines():
1943 1960 fields = line.split()
1944 1961 if not fields:
1945 1962 continue
1946 1963 attrs = {'URL': fields[0]}
1947 1964 for rawattr in fields[1:]:
1948 1965 key, value = rawattr.split('=', 1)
1949 1966 key = urlreq.unquote(key)
1950 1967 value = urlreq.unquote(value)
1951 1968 attrs[key] = value
1952 1969
1953 1970 # Parse BUNDLESPEC into components. This makes client-side
1954 1971 # preferences easier to specify since you can prefer a single
1955 1972 # component of the BUNDLESPEC.
1956 1973 if key == 'BUNDLESPEC':
1957 1974 try:
1958 1975 comp, version, params = parsebundlespec(repo, value,
1959 1976 externalnames=True)
1960 1977 attrs['COMPRESSION'] = comp
1961 1978 attrs['VERSION'] = version
1962 1979 except error.InvalidBundleSpecification:
1963 1980 pass
1964 1981 except error.UnsupportedBundleSpecification:
1965 1982 pass
1966 1983
1967 1984 m.append(attrs)
1968 1985
1969 1986 return m
1970 1987
1971 1988 def filterclonebundleentries(repo, entries, streamclonerequested=False):
1972 1989 """Remove incompatible clone bundle manifest entries.
1973 1990
1974 1991 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
1975 1992 and returns a new list consisting of only the entries that this client
1976 1993 should be able to apply.
1977 1994
1978 1995 There is no guarantee we'll be able to apply all returned entries because
1979 1996 the metadata we use to filter on may be missing or wrong.
1980 1997 """
1981 1998 newentries = []
1982 1999 for entry in entries:
1983 2000 spec = entry.get('BUNDLESPEC')
1984 2001 if spec:
1985 2002 try:
1986 2003 comp, version, params = parsebundlespec(repo, spec, strict=True)
1987 2004
1988 2005 # If a stream clone was requested, filter out non-streamclone
1989 2006 # entries.
1990 2007 if streamclonerequested and (comp != 'UN' or version != 's1'):
1991 2008 repo.ui.debug('filtering %s because not a stream clone\n' %
1992 2009 entry['URL'])
1993 2010 continue
1994 2011
1995 2012 except error.InvalidBundleSpecification as e:
1996 2013 repo.ui.debug(str(e) + '\n')
1997 2014 continue
1998 2015 except error.UnsupportedBundleSpecification as e:
1999 2016 repo.ui.debug('filtering %s because unsupported bundle '
2000 2017 'spec: %s\n' % (entry['URL'], str(e)))
2001 2018 continue
2002 2019 # If we don't have a spec and requested a stream clone, we don't know
2003 2020 # what the entry is so don't attempt to apply it.
2004 2021 elif streamclonerequested:
2005 2022 repo.ui.debug('filtering %s because cannot determine if a stream '
2006 2023 'clone bundle\n' % entry['URL'])
2007 2024 continue
2008 2025
2009 2026 if 'REQUIRESNI' in entry and not sslutil.hassni:
2010 2027 repo.ui.debug('filtering %s because SNI not supported\n' %
2011 2028 entry['URL'])
2012 2029 continue
2013 2030
2014 2031 newentries.append(entry)
2015 2032
2016 2033 return newentries
2017 2034
2018 2035 class clonebundleentry(object):
2019 2036 """Represents an item in a clone bundles manifest.
2020 2037
2021 2038 This rich class is needed to support sorting since sorted() in Python 3
2022 2039 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
2023 2040 won't work.
2024 2041 """
2025 2042
2026 2043 def __init__(self, value, prefers):
2027 2044 self.value = value
2028 2045 self.prefers = prefers
2029 2046
2030 2047 def _cmp(self, other):
2031 2048 for prefkey, prefvalue in self.prefers:
2032 2049 avalue = self.value.get(prefkey)
2033 2050 bvalue = other.value.get(prefkey)
2034 2051
2035 2052 # Special case for b missing attribute and a matches exactly.
2036 2053 if avalue is not None and bvalue is None and avalue == prefvalue:
2037 2054 return -1
2038 2055
2039 2056 # Special case for a missing attribute and b matches exactly.
2040 2057 if bvalue is not None and avalue is None and bvalue == prefvalue:
2041 2058 return 1
2042 2059
2043 2060 # We can't compare unless attribute present on both.
2044 2061 if avalue is None or bvalue is None:
2045 2062 continue
2046 2063
2047 2064 # Same values should fall back to next attribute.
2048 2065 if avalue == bvalue:
2049 2066 continue
2050 2067
2051 2068 # Exact matches come first.
2052 2069 if avalue == prefvalue:
2053 2070 return -1
2054 2071 if bvalue == prefvalue:
2055 2072 return 1
2056 2073
2057 2074 # Fall back to next attribute.
2058 2075 continue
2059 2076
2060 2077 # If we got here we couldn't sort by attributes and prefers. Fall
2061 2078 # back to index order.
2062 2079 return 0
2063 2080
2064 2081 def __lt__(self, other):
2065 2082 return self._cmp(other) < 0
2066 2083
2067 2084 def __gt__(self, other):
2068 2085 return self._cmp(other) > 0
2069 2086
2070 2087 def __eq__(self, other):
2071 2088 return self._cmp(other) == 0
2072 2089
2073 2090 def __le__(self, other):
2074 2091 return self._cmp(other) <= 0
2075 2092
2076 2093 def __ge__(self, other):
2077 2094 return self._cmp(other) >= 0
2078 2095
2079 2096 def __ne__(self, other):
2080 2097 return self._cmp(other) != 0
2081 2098
2082 2099 def sortclonebundleentries(ui, entries):
2083 2100 prefers = ui.configlist('ui', 'clonebundleprefers')
2084 2101 if not prefers:
2085 2102 return list(entries)
2086 2103
2087 2104 prefers = [p.split('=', 1) for p in prefers]
2088 2105
2089 2106 items = sorted(clonebundleentry(v, prefers) for v in entries)
2090 2107 return [i.value for i in items]
2091 2108
2092 2109 def trypullbundlefromurl(ui, repo, url):
2093 2110 """Attempt to apply a bundle from a URL."""
2094 2111 with repo.lock(), repo.transaction('bundleurl') as tr:
2095 2112 try:
2096 2113 fh = urlmod.open(ui, url)
2097 2114 cg = readbundle(ui, fh, 'stream')
2098 2115
2099 2116 if isinstance(cg, streamclone.streamcloneapplier):
2100 2117 cg.apply(repo)
2101 2118 else:
2102 2119 bundle2.applybundle(repo, cg, tr, 'clonebundles', url)
2103 2120 return True
2104 2121 except urlerr.httperror as e:
2105 2122 ui.warn(_('HTTP error fetching bundle: %s\n') % str(e))
2106 2123 except urlerr.urlerror as e:
2107 2124 ui.warn(_('error fetching bundle: %s\n') % e.reason)
2108 2125
2109 2126 return False
@@ -1,2214 +1,2183
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 $ hg init a
48 48 $ cd a
49 49 $ mkdir foo foo/Bar quux
50 50 $ echo 'in foo' > foo/file.txt
51 51 $ echo 'in foo/Bar' > foo/Bar/file.txt
52 52 $ echo 'in quux' > quux/file.py
53 53 $ hg add -q
54 54 $ hg ci -m 'add files' -d '1000000 0'
55 55 $ echo >> foo/file.txt
56 56 $ hg ci -m 'change foo/file' -d '1000001 0'
57 57 $ echo >> foo/Bar/file.txt
58 58 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
59 59 $ echo >> quux/file.py
60 60 $ hg ci -m 'change quux/file' -d '1000003 0'
61 61 $ hg tip --quiet
62 62 3:911600dab2ae
63 63
64 64 $ cd ..
65 65 $ hg clone -r 0 a b
66 66 adding changesets
67 67 adding manifests
68 68 adding file changes
69 69 added 1 changesets with 3 changes to 3 files
70 70 new changesets 6675d58eff77
71 71 updating to branch default
72 72 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 73
74 74 $ config=b/.hg/hgrc
75 75
76 76 Extension disabled for lack of a hook
77 77
78 78 $ do_push fred
79 79 Pushing as user fred
80 80 hgrc = """
81 81 """
82 82 pushing to ../b
83 83 query 1; heads
84 84 searching for changes
85 85 all remote heads known locally
86 86 listing keys for "phases"
87 87 checking for updated bookmarks
88 88 listing keys for "bookmarks"
89 89 listing keys for "bookmarks"
90 90 3 changesets found
91 91 list of changesets:
92 92 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
93 93 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
94 94 911600dab2ae7a9baff75958b84fe606851ce955
95 95 bundle2-output-bundle: "HG20", 5 parts total
96 96 bundle2-output-part: "replycaps" 168 bytes payload
97 97 bundle2-output-part: "check:phases" 24 bytes payload
98 98 bundle2-output-part: "check:heads" streamed payload
99 99 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
100 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
100 bundle2-output-part: "phase-heads" 24 bytes payload
101 101 bundle2-input-bundle: with-transaction
102 102 bundle2-input-part: "replycaps" supported
103 103 bundle2-input-part: total payload size 168
104 104 bundle2-input-part: "check:phases" supported
105 105 bundle2-input-part: total payload size 24
106 106 bundle2-input-part: "check:heads" supported
107 107 bundle2-input-part: total payload size 20
108 108 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
109 109 adding changesets
110 110 add changeset ef1ea85a6374
111 111 add changeset f9cafe1212c8
112 112 add changeset 911600dab2ae
113 113 adding manifests
114 114 adding file changes
115 115 adding foo/Bar/file.txt revisions
116 116 adding foo/file.txt revisions
117 117 adding quux/file.py revisions
118 118 added 3 changesets with 3 changes to 3 files
119 119 bundle2-input-part: total payload size 1553
120 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
121 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
120 bundle2-input-part: "phase-heads" supported
121 bundle2-input-part: total payload size 24
122 122 bundle2-input-bundle: 4 parts total
123 123 updating the branch cache
124 bundle2-output-bundle: "HG20", 2 parts total
124 bundle2-output-bundle: "HG20", 1 parts total
125 125 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
126 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
127 126 bundle2-input-bundle: no-transaction
128 127 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
129 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
130 bundle2-input-bundle: 1 parts total
128 bundle2-input-bundle: 0 parts total
131 129 listing keys for "phases"
132 130 repository tip rolled back to revision 0 (undo push)
133 131 0:6675d58eff77
134 132
135 133
136 134 $ echo '[hooks]' >> $config
137 135 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
138 136
139 137 Extension disabled for lack of acl.sources
140 138
141 139 $ do_push fred
142 140 Pushing as user fred
143 141 hgrc = """
144 142 [hooks]
145 143 pretxnchangegroup.acl = python:hgext.acl.hook
146 144 """
147 145 pushing to ../b
148 146 query 1; heads
149 147 searching for changes
150 148 all remote heads known locally
151 149 listing keys for "phases"
152 150 checking for updated bookmarks
153 151 listing keys for "bookmarks"
154 152 listing keys for "bookmarks"
155 153 3 changesets found
156 154 list of changesets:
157 155 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
158 156 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
159 157 911600dab2ae7a9baff75958b84fe606851ce955
160 158 bundle2-output-bundle: "HG20", 5 parts total
161 159 bundle2-output-part: "replycaps" 168 bytes payload
162 160 bundle2-output-part: "check:phases" 24 bytes payload
163 161 bundle2-output-part: "check:heads" streamed payload
164 162 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
165 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
163 bundle2-output-part: "phase-heads" 24 bytes payload
166 164 bundle2-input-bundle: with-transaction
167 165 bundle2-input-part: "replycaps" supported
168 166 bundle2-input-part: total payload size 168
169 167 bundle2-input-part: "check:phases" supported
170 168 bundle2-input-part: total payload size 24
171 169 bundle2-input-part: "check:heads" supported
172 170 bundle2-input-part: total payload size 20
173 171 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
174 172 adding changesets
175 173 add changeset ef1ea85a6374
176 174 add changeset f9cafe1212c8
177 175 add changeset 911600dab2ae
178 176 adding manifests
179 177 adding file changes
180 178 adding foo/Bar/file.txt revisions
181 179 adding foo/file.txt revisions
182 180 adding quux/file.py revisions
183 181 added 3 changesets with 3 changes to 3 files
184 182 calling hook pretxnchangegroup.acl: hgext.acl.hook
185 183 acl: changes have source "push" - skipping
186 184 bundle2-input-part: total payload size 1553
187 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
188 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
185 bundle2-input-part: "phase-heads" supported
186 bundle2-input-part: total payload size 24
189 187 bundle2-input-bundle: 4 parts total
190 188 updating the branch cache
191 bundle2-output-bundle: "HG20", 2 parts total
189 bundle2-output-bundle: "HG20", 1 parts total
192 190 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
193 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
194 191 bundle2-input-bundle: no-transaction
195 192 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
196 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
197 bundle2-input-bundle: 1 parts total
193 bundle2-input-bundle: 0 parts total
198 194 listing keys for "phases"
199 195 repository tip rolled back to revision 0 (undo push)
200 196 0:6675d58eff77
201 197
202 198
203 199 No [acl.allow]/[acl.deny]
204 200
205 201 $ echo '[acl]' >> $config
206 202 $ echo 'sources = push' >> $config
207 203 $ do_push fred
208 204 Pushing as user fred
209 205 hgrc = """
210 206 [hooks]
211 207 pretxnchangegroup.acl = python:hgext.acl.hook
212 208 [acl]
213 209 sources = push
214 210 """
215 211 pushing to ../b
216 212 query 1; heads
217 213 searching for changes
218 214 all remote heads known locally
219 215 listing keys for "phases"
220 216 checking for updated bookmarks
221 217 listing keys for "bookmarks"
222 218 listing keys for "bookmarks"
223 219 3 changesets found
224 220 list of changesets:
225 221 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
226 222 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
227 223 911600dab2ae7a9baff75958b84fe606851ce955
228 224 bundle2-output-bundle: "HG20", 5 parts total
229 225 bundle2-output-part: "replycaps" 168 bytes payload
230 226 bundle2-output-part: "check:phases" 24 bytes payload
231 227 bundle2-output-part: "check:heads" streamed payload
232 228 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
233 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
229 bundle2-output-part: "phase-heads" 24 bytes payload
234 230 bundle2-input-bundle: with-transaction
235 231 bundle2-input-part: "replycaps" supported
236 232 bundle2-input-part: total payload size 168
237 233 bundle2-input-part: "check:phases" supported
238 234 bundle2-input-part: total payload size 24
239 235 bundle2-input-part: "check:heads" supported
240 236 bundle2-input-part: total payload size 20
241 237 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
242 238 adding changesets
243 239 add changeset ef1ea85a6374
244 240 add changeset f9cafe1212c8
245 241 add changeset 911600dab2ae
246 242 adding manifests
247 243 adding file changes
248 244 adding foo/Bar/file.txt revisions
249 245 adding foo/file.txt revisions
250 246 adding quux/file.py revisions
251 247 added 3 changesets with 3 changes to 3 files
252 248 calling hook pretxnchangegroup.acl: hgext.acl.hook
253 249 acl: checking access for user "fred"
254 250 acl: acl.allow.branches not enabled
255 251 acl: acl.deny.branches not enabled
256 252 acl: acl.allow not enabled
257 253 acl: acl.deny not enabled
258 254 acl: branch access granted: "ef1ea85a6374" on branch "default"
259 255 acl: path access granted: "ef1ea85a6374"
260 256 acl: branch access granted: "f9cafe1212c8" on branch "default"
261 257 acl: path access granted: "f9cafe1212c8"
262 258 acl: branch access granted: "911600dab2ae" on branch "default"
263 259 acl: path access granted: "911600dab2ae"
264 260 bundle2-input-part: total payload size 1553
265 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
266 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
261 bundle2-input-part: "phase-heads" supported
262 bundle2-input-part: total payload size 24
267 263 bundle2-input-bundle: 4 parts total
268 264 updating the branch cache
269 bundle2-output-bundle: "HG20", 2 parts total
265 bundle2-output-bundle: "HG20", 1 parts total
270 266 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
271 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
272 267 bundle2-input-bundle: no-transaction
273 268 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
274 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
275 bundle2-input-bundle: 1 parts total
269 bundle2-input-bundle: 0 parts total
276 270 listing keys for "phases"
277 271 repository tip rolled back to revision 0 (undo push)
278 272 0:6675d58eff77
279 273
280 274
281 275 Empty [acl.allow]
282 276
283 277 $ echo '[acl.allow]' >> $config
284 278 $ do_push fred
285 279 Pushing as user fred
286 280 hgrc = """
287 281 [hooks]
288 282 pretxnchangegroup.acl = python:hgext.acl.hook
289 283 [acl]
290 284 sources = push
291 285 [acl.allow]
292 286 """
293 287 pushing to ../b
294 288 query 1; heads
295 289 searching for changes
296 290 all remote heads known locally
297 291 listing keys for "phases"
298 292 checking for updated bookmarks
299 293 listing keys for "bookmarks"
300 294 listing keys for "bookmarks"
301 295 3 changesets found
302 296 list of changesets:
303 297 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
304 298 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
305 299 911600dab2ae7a9baff75958b84fe606851ce955
306 300 bundle2-output-bundle: "HG20", 5 parts total
307 301 bundle2-output-part: "replycaps" 168 bytes payload
308 302 bundle2-output-part: "check:phases" 24 bytes payload
309 303 bundle2-output-part: "check:heads" streamed payload
310 304 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
311 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
305 bundle2-output-part: "phase-heads" 24 bytes payload
312 306 bundle2-input-bundle: with-transaction
313 307 bundle2-input-part: "replycaps" supported
314 308 bundle2-input-part: total payload size 168
315 309 bundle2-input-part: "check:phases" supported
316 310 bundle2-input-part: total payload size 24
317 311 bundle2-input-part: "check:heads" supported
318 312 bundle2-input-part: total payload size 20
319 313 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
320 314 adding changesets
321 315 add changeset ef1ea85a6374
322 316 add changeset f9cafe1212c8
323 317 add changeset 911600dab2ae
324 318 adding manifests
325 319 adding file changes
326 320 adding foo/Bar/file.txt revisions
327 321 adding foo/file.txt revisions
328 322 adding quux/file.py revisions
329 323 added 3 changesets with 3 changes to 3 files
330 324 calling hook pretxnchangegroup.acl: hgext.acl.hook
331 325 acl: checking access for user "fred"
332 326 acl: acl.allow.branches not enabled
333 327 acl: acl.deny.branches not enabled
334 328 acl: acl.allow enabled, 0 entries for user fred
335 329 acl: acl.deny not enabled
336 330 acl: branch access granted: "ef1ea85a6374" on branch "default"
337 331 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
338 332 bundle2-input-part: total payload size 1553
333 bundle2-input-part: total payload size 24
339 334 bundle2-input-bundle: 4 parts total
340 335 transaction abort!
341 336 rollback completed
342 337 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
343 338 no rollback information available
344 339 0:6675d58eff77
345 340
346 341
347 342 fred is allowed inside foo/
348 343
349 344 $ echo 'foo/** = fred' >> $config
350 345 $ do_push fred
351 346 Pushing as user fred
352 347 hgrc = """
353 348 [hooks]
354 349 pretxnchangegroup.acl = python:hgext.acl.hook
355 350 [acl]
356 351 sources = push
357 352 [acl.allow]
358 353 foo/** = fred
359 354 """
360 355 pushing to ../b
361 356 query 1; heads
362 357 searching for changes
363 358 all remote heads known locally
364 359 listing keys for "phases"
365 360 checking for updated bookmarks
366 361 listing keys for "bookmarks"
367 362 listing keys for "bookmarks"
368 363 3 changesets found
369 364 list of changesets:
370 365 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
371 366 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
372 367 911600dab2ae7a9baff75958b84fe606851ce955
373 368 bundle2-output-bundle: "HG20", 5 parts total
374 369 bundle2-output-part: "replycaps" 168 bytes payload
375 370 bundle2-output-part: "check:phases" 24 bytes payload
376 371 bundle2-output-part: "check:heads" streamed payload
377 372 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
378 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
373 bundle2-output-part: "phase-heads" 24 bytes payload
379 374 bundle2-input-bundle: with-transaction
380 375 bundle2-input-part: "replycaps" supported
381 376 bundle2-input-part: total payload size 168
382 377 bundle2-input-part: "check:phases" supported
383 378 bundle2-input-part: total payload size 24
384 379 bundle2-input-part: "check:heads" supported
385 380 bundle2-input-part: total payload size 20
386 381 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
387 382 adding changesets
388 383 add changeset ef1ea85a6374
389 384 add changeset f9cafe1212c8
390 385 add changeset 911600dab2ae
391 386 adding manifests
392 387 adding file changes
393 388 adding foo/Bar/file.txt revisions
394 389 adding foo/file.txt revisions
395 390 adding quux/file.py revisions
396 391 added 3 changesets with 3 changes to 3 files
397 392 calling hook pretxnchangegroup.acl: hgext.acl.hook
398 393 acl: checking access for user "fred"
399 394 acl: acl.allow.branches not enabled
400 395 acl: acl.deny.branches not enabled
401 396 acl: acl.allow enabled, 1 entries for user fred
402 397 acl: acl.deny not enabled
403 398 acl: branch access granted: "ef1ea85a6374" on branch "default"
404 399 acl: path access granted: "ef1ea85a6374"
405 400 acl: branch access granted: "f9cafe1212c8" on branch "default"
406 401 acl: path access granted: "f9cafe1212c8"
407 402 acl: branch access granted: "911600dab2ae" on branch "default"
408 403 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
409 404 bundle2-input-part: total payload size 1553
405 bundle2-input-part: total payload size 24
410 406 bundle2-input-bundle: 4 parts total
411 407 transaction abort!
412 408 rollback completed
413 409 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
414 410 no rollback information available
415 411 0:6675d58eff77
416 412
417 413
418 414 Empty [acl.deny]
419 415
420 416 $ echo '[acl.deny]' >> $config
421 417 $ do_push barney
422 418 Pushing as user barney
423 419 hgrc = """
424 420 [hooks]
425 421 pretxnchangegroup.acl = python:hgext.acl.hook
426 422 [acl]
427 423 sources = push
428 424 [acl.allow]
429 425 foo/** = fred
430 426 [acl.deny]
431 427 """
432 428 pushing to ../b
433 429 query 1; heads
434 430 searching for changes
435 431 all remote heads known locally
436 432 listing keys for "phases"
437 433 checking for updated bookmarks
438 434 listing keys for "bookmarks"
439 435 listing keys for "bookmarks"
440 436 3 changesets found
441 437 list of changesets:
442 438 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
443 439 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
444 440 911600dab2ae7a9baff75958b84fe606851ce955
445 441 bundle2-output-bundle: "HG20", 5 parts total
446 442 bundle2-output-part: "replycaps" 168 bytes payload
447 443 bundle2-output-part: "check:phases" 24 bytes payload
448 444 bundle2-output-part: "check:heads" streamed payload
449 445 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
450 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
446 bundle2-output-part: "phase-heads" 24 bytes payload
451 447 bundle2-input-bundle: with-transaction
452 448 bundle2-input-part: "replycaps" supported
453 449 bundle2-input-part: total payload size 168
454 450 bundle2-input-part: "check:phases" supported
455 451 bundle2-input-part: total payload size 24
456 452 bundle2-input-part: "check:heads" supported
457 453 bundle2-input-part: total payload size 20
458 454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
459 455 adding changesets
460 456 add changeset ef1ea85a6374
461 457 add changeset f9cafe1212c8
462 458 add changeset 911600dab2ae
463 459 adding manifests
464 460 adding file changes
465 461 adding foo/Bar/file.txt revisions
466 462 adding foo/file.txt revisions
467 463 adding quux/file.py revisions
468 464 added 3 changesets with 3 changes to 3 files
469 465 calling hook pretxnchangegroup.acl: hgext.acl.hook
470 466 acl: checking access for user "barney"
471 467 acl: acl.allow.branches not enabled
472 468 acl: acl.deny.branches not enabled
473 469 acl: acl.allow enabled, 0 entries for user barney
474 470 acl: acl.deny enabled, 0 entries for user barney
475 471 acl: branch access granted: "ef1ea85a6374" on branch "default"
476 472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
477 473 bundle2-input-part: total payload size 1553
474 bundle2-input-part: total payload size 24
478 475 bundle2-input-bundle: 4 parts total
479 476 transaction abort!
480 477 rollback completed
481 478 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
482 479 no rollback information available
483 480 0:6675d58eff77
484 481
485 482
486 483 fred is allowed inside foo/, but not foo/bar/ (case matters)
487 484
488 485 $ echo 'foo/bar/** = fred' >> $config
489 486 $ do_push fred
490 487 Pushing as user fred
491 488 hgrc = """
492 489 [hooks]
493 490 pretxnchangegroup.acl = python:hgext.acl.hook
494 491 [acl]
495 492 sources = push
496 493 [acl.allow]
497 494 foo/** = fred
498 495 [acl.deny]
499 496 foo/bar/** = fred
500 497 """
501 498 pushing to ../b
502 499 query 1; heads
503 500 searching for changes
504 501 all remote heads known locally
505 502 listing keys for "phases"
506 503 checking for updated bookmarks
507 504 listing keys for "bookmarks"
508 505 listing keys for "bookmarks"
509 506 3 changesets found
510 507 list of changesets:
511 508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
512 509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
513 510 911600dab2ae7a9baff75958b84fe606851ce955
514 511 bundle2-output-bundle: "HG20", 5 parts total
515 512 bundle2-output-part: "replycaps" 168 bytes payload
516 513 bundle2-output-part: "check:phases" 24 bytes payload
517 514 bundle2-output-part: "check:heads" streamed payload
518 515 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
519 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
516 bundle2-output-part: "phase-heads" 24 bytes payload
520 517 bundle2-input-bundle: with-transaction
521 518 bundle2-input-part: "replycaps" supported
522 519 bundle2-input-part: total payload size 168
523 520 bundle2-input-part: "check:phases" supported
524 521 bundle2-input-part: total payload size 24
525 522 bundle2-input-part: "check:heads" supported
526 523 bundle2-input-part: total payload size 20
527 524 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
528 525 adding changesets
529 526 add changeset ef1ea85a6374
530 527 add changeset f9cafe1212c8
531 528 add changeset 911600dab2ae
532 529 adding manifests
533 530 adding file changes
534 531 adding foo/Bar/file.txt revisions
535 532 adding foo/file.txt revisions
536 533 adding quux/file.py revisions
537 534 added 3 changesets with 3 changes to 3 files
538 535 calling hook pretxnchangegroup.acl: hgext.acl.hook
539 536 acl: checking access for user "fred"
540 537 acl: acl.allow.branches not enabled
541 538 acl: acl.deny.branches not enabled
542 539 acl: acl.allow enabled, 1 entries for user fred
543 540 acl: acl.deny enabled, 1 entries for user fred
544 541 acl: branch access granted: "ef1ea85a6374" on branch "default"
545 542 acl: path access granted: "ef1ea85a6374"
546 543 acl: branch access granted: "f9cafe1212c8" on branch "default"
547 544 acl: path access granted: "f9cafe1212c8"
548 545 acl: branch access granted: "911600dab2ae" on branch "default"
549 546 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
550 547 bundle2-input-part: total payload size 1553
548 bundle2-input-part: total payload size 24
551 549 bundle2-input-bundle: 4 parts total
552 550 transaction abort!
553 551 rollback completed
554 552 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
555 553 no rollback information available
556 554 0:6675d58eff77
557 555
558 556
559 557 fred is allowed inside foo/, but not foo/Bar/
560 558
561 559 $ echo 'foo/Bar/** = fred' >> $config
562 560 $ do_push fred
563 561 Pushing as user fred
564 562 hgrc = """
565 563 [hooks]
566 564 pretxnchangegroup.acl = python:hgext.acl.hook
567 565 [acl]
568 566 sources = push
569 567 [acl.allow]
570 568 foo/** = fred
571 569 [acl.deny]
572 570 foo/bar/** = fred
573 571 foo/Bar/** = fred
574 572 """
575 573 pushing to ../b
576 574 query 1; heads
577 575 searching for changes
578 576 all remote heads known locally
579 577 listing keys for "phases"
580 578 checking for updated bookmarks
581 579 listing keys for "bookmarks"
582 580 listing keys for "bookmarks"
583 581 3 changesets found
584 582 list of changesets:
585 583 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
586 584 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
587 585 911600dab2ae7a9baff75958b84fe606851ce955
588 586 bundle2-output-bundle: "HG20", 5 parts total
589 587 bundle2-output-part: "replycaps" 168 bytes payload
590 588 bundle2-output-part: "check:phases" 24 bytes payload
591 589 bundle2-output-part: "check:heads" streamed payload
592 590 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
593 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
591 bundle2-output-part: "phase-heads" 24 bytes payload
594 592 bundle2-input-bundle: with-transaction
595 593 bundle2-input-part: "replycaps" supported
596 594 bundle2-input-part: total payload size 168
597 595 bundle2-input-part: "check:phases" supported
598 596 bundle2-input-part: total payload size 24
599 597 bundle2-input-part: "check:heads" supported
600 598 bundle2-input-part: total payload size 20
601 599 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
602 600 adding changesets
603 601 add changeset ef1ea85a6374
604 602 add changeset f9cafe1212c8
605 603 add changeset 911600dab2ae
606 604 adding manifests
607 605 adding file changes
608 606 adding foo/Bar/file.txt revisions
609 607 adding foo/file.txt revisions
610 608 adding quux/file.py revisions
611 609 added 3 changesets with 3 changes to 3 files
612 610 calling hook pretxnchangegroup.acl: hgext.acl.hook
613 611 acl: checking access for user "fred"
614 612 acl: acl.allow.branches not enabled
615 613 acl: acl.deny.branches not enabled
616 614 acl: acl.allow enabled, 1 entries for user fred
617 615 acl: acl.deny enabled, 2 entries for user fred
618 616 acl: branch access granted: "ef1ea85a6374" on branch "default"
619 617 acl: path access granted: "ef1ea85a6374"
620 618 acl: branch access granted: "f9cafe1212c8" on branch "default"
621 619 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
622 620 bundle2-input-part: total payload size 1553
621 bundle2-input-part: total payload size 24
623 622 bundle2-input-bundle: 4 parts total
624 623 transaction abort!
625 624 rollback completed
626 625 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
627 626 no rollback information available
628 627 0:6675d58eff77
629 628
630 629
631 630 $ echo 'barney is not mentioned => not allowed anywhere'
632 631 barney is not mentioned => not allowed anywhere
633 632 $ do_push barney
634 633 Pushing as user barney
635 634 hgrc = """
636 635 [hooks]
637 636 pretxnchangegroup.acl = python:hgext.acl.hook
638 637 [acl]
639 638 sources = push
640 639 [acl.allow]
641 640 foo/** = fred
642 641 [acl.deny]
643 642 foo/bar/** = fred
644 643 foo/Bar/** = fred
645 644 """
646 645 pushing to ../b
647 646 query 1; heads
648 647 searching for changes
649 648 all remote heads known locally
650 649 listing keys for "phases"
651 650 checking for updated bookmarks
652 651 listing keys for "bookmarks"
653 652 listing keys for "bookmarks"
654 653 3 changesets found
655 654 list of changesets:
656 655 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
657 656 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
658 657 911600dab2ae7a9baff75958b84fe606851ce955
659 658 bundle2-output-bundle: "HG20", 5 parts total
660 659 bundle2-output-part: "replycaps" 168 bytes payload
661 660 bundle2-output-part: "check:phases" 24 bytes payload
662 661 bundle2-output-part: "check:heads" streamed payload
663 662 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
664 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
663 bundle2-output-part: "phase-heads" 24 bytes payload
665 664 bundle2-input-bundle: with-transaction
666 665 bundle2-input-part: "replycaps" supported
667 666 bundle2-input-part: total payload size 168
668 667 bundle2-input-part: "check:phases" supported
669 668 bundle2-input-part: total payload size 24
670 669 bundle2-input-part: "check:heads" supported
671 670 bundle2-input-part: total payload size 20
672 671 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
673 672 adding changesets
674 673 add changeset ef1ea85a6374
675 674 add changeset f9cafe1212c8
676 675 add changeset 911600dab2ae
677 676 adding manifests
678 677 adding file changes
679 678 adding foo/Bar/file.txt revisions
680 679 adding foo/file.txt revisions
681 680 adding quux/file.py revisions
682 681 added 3 changesets with 3 changes to 3 files
683 682 calling hook pretxnchangegroup.acl: hgext.acl.hook
684 683 acl: checking access for user "barney"
685 684 acl: acl.allow.branches not enabled
686 685 acl: acl.deny.branches not enabled
687 686 acl: acl.allow enabled, 0 entries for user barney
688 687 acl: acl.deny enabled, 0 entries for user barney
689 688 acl: branch access granted: "ef1ea85a6374" on branch "default"
690 689 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
691 690 bundle2-input-part: total payload size 1553
691 bundle2-input-part: total payload size 24
692 692 bundle2-input-bundle: 4 parts total
693 693 transaction abort!
694 694 rollback completed
695 695 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
696 696 no rollback information available
697 697 0:6675d58eff77
698 698
699 699
700 700 barney is allowed everywhere
701 701
702 702 $ echo '[acl.allow]' >> $config
703 703 $ echo '** = barney' >> $config
704 704 $ do_push barney
705 705 Pushing as user barney
706 706 hgrc = """
707 707 [hooks]
708 708 pretxnchangegroup.acl = python:hgext.acl.hook
709 709 [acl]
710 710 sources = push
711 711 [acl.allow]
712 712 foo/** = fred
713 713 [acl.deny]
714 714 foo/bar/** = fred
715 715 foo/Bar/** = fred
716 716 [acl.allow]
717 717 ** = barney
718 718 """
719 719 pushing to ../b
720 720 query 1; heads
721 721 searching for changes
722 722 all remote heads known locally
723 723 listing keys for "phases"
724 724 checking for updated bookmarks
725 725 listing keys for "bookmarks"
726 726 listing keys for "bookmarks"
727 727 3 changesets found
728 728 list of changesets:
729 729 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
730 730 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
731 731 911600dab2ae7a9baff75958b84fe606851ce955
732 732 bundle2-output-bundle: "HG20", 5 parts total
733 733 bundle2-output-part: "replycaps" 168 bytes payload
734 734 bundle2-output-part: "check:phases" 24 bytes payload
735 735 bundle2-output-part: "check:heads" streamed payload
736 736 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
737 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
737 bundle2-output-part: "phase-heads" 24 bytes payload
738 738 bundle2-input-bundle: with-transaction
739 739 bundle2-input-part: "replycaps" supported
740 740 bundle2-input-part: total payload size 168
741 741 bundle2-input-part: "check:phases" supported
742 742 bundle2-input-part: total payload size 24
743 743 bundle2-input-part: "check:heads" supported
744 744 bundle2-input-part: total payload size 20
745 745 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
746 746 adding changesets
747 747 add changeset ef1ea85a6374
748 748 add changeset f9cafe1212c8
749 749 add changeset 911600dab2ae
750 750 adding manifests
751 751 adding file changes
752 752 adding foo/Bar/file.txt revisions
753 753 adding foo/file.txt revisions
754 754 adding quux/file.py revisions
755 755 added 3 changesets with 3 changes to 3 files
756 756 calling hook pretxnchangegroup.acl: hgext.acl.hook
757 757 acl: checking access for user "barney"
758 758 acl: acl.allow.branches not enabled
759 759 acl: acl.deny.branches not enabled
760 760 acl: acl.allow enabled, 1 entries for user barney
761 761 acl: acl.deny enabled, 0 entries for user barney
762 762 acl: branch access granted: "ef1ea85a6374" on branch "default"
763 763 acl: path access granted: "ef1ea85a6374"
764 764 acl: branch access granted: "f9cafe1212c8" on branch "default"
765 765 acl: path access granted: "f9cafe1212c8"
766 766 acl: branch access granted: "911600dab2ae" on branch "default"
767 767 acl: path access granted: "911600dab2ae"
768 768 bundle2-input-part: total payload size 1553
769 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
770 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
769 bundle2-input-part: "phase-heads" supported
770 bundle2-input-part: total payload size 24
771 771 bundle2-input-bundle: 4 parts total
772 772 updating the branch cache
773 bundle2-output-bundle: "HG20", 2 parts total
773 bundle2-output-bundle: "HG20", 1 parts total
774 774 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
775 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
776 775 bundle2-input-bundle: no-transaction
777 776 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
778 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
779 bundle2-input-bundle: 1 parts total
777 bundle2-input-bundle: 0 parts total
780 778 listing keys for "phases"
781 779 repository tip rolled back to revision 0 (undo push)
782 780 0:6675d58eff77
783 781
784 782
785 783 wilma can change files with a .txt extension
786 784
787 785 $ echo '**/*.txt = wilma' >> $config
788 786 $ do_push wilma
789 787 Pushing as user wilma
790 788 hgrc = """
791 789 [hooks]
792 790 pretxnchangegroup.acl = python:hgext.acl.hook
793 791 [acl]
794 792 sources = push
795 793 [acl.allow]
796 794 foo/** = fred
797 795 [acl.deny]
798 796 foo/bar/** = fred
799 797 foo/Bar/** = fred
800 798 [acl.allow]
801 799 ** = barney
802 800 **/*.txt = wilma
803 801 """
804 802 pushing to ../b
805 803 query 1; heads
806 804 searching for changes
807 805 all remote heads known locally
808 806 listing keys for "phases"
809 807 checking for updated bookmarks
810 808 listing keys for "bookmarks"
811 809 listing keys for "bookmarks"
812 810 3 changesets found
813 811 list of changesets:
814 812 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
815 813 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
816 814 911600dab2ae7a9baff75958b84fe606851ce955
817 815 bundle2-output-bundle: "HG20", 5 parts total
818 816 bundle2-output-part: "replycaps" 168 bytes payload
819 817 bundle2-output-part: "check:phases" 24 bytes payload
820 818 bundle2-output-part: "check:heads" streamed payload
821 819 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
822 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
820 bundle2-output-part: "phase-heads" 24 bytes payload
823 821 bundle2-input-bundle: with-transaction
824 822 bundle2-input-part: "replycaps" supported
825 823 bundle2-input-part: total payload size 168
826 824 bundle2-input-part: "check:phases" supported
827 825 bundle2-input-part: total payload size 24
828 826 bundle2-input-part: "check:heads" supported
829 827 bundle2-input-part: total payload size 20
830 828 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
831 829 adding changesets
832 830 add changeset ef1ea85a6374
833 831 add changeset f9cafe1212c8
834 832 add changeset 911600dab2ae
835 833 adding manifests
836 834 adding file changes
837 835 adding foo/Bar/file.txt revisions
838 836 adding foo/file.txt revisions
839 837 adding quux/file.py revisions
840 838 added 3 changesets with 3 changes to 3 files
841 839 calling hook pretxnchangegroup.acl: hgext.acl.hook
842 840 acl: checking access for user "wilma"
843 841 acl: acl.allow.branches not enabled
844 842 acl: acl.deny.branches not enabled
845 843 acl: acl.allow enabled, 1 entries for user wilma
846 844 acl: acl.deny enabled, 0 entries for user wilma
847 845 acl: branch access granted: "ef1ea85a6374" on branch "default"
848 846 acl: path access granted: "ef1ea85a6374"
849 847 acl: branch access granted: "f9cafe1212c8" on branch "default"
850 848 acl: path access granted: "f9cafe1212c8"
851 849 acl: branch access granted: "911600dab2ae" on branch "default"
852 850 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
853 851 bundle2-input-part: total payload size 1553
852 bundle2-input-part: total payload size 24
854 853 bundle2-input-bundle: 4 parts total
855 854 transaction abort!
856 855 rollback completed
857 856 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
858 857 no rollback information available
859 858 0:6675d58eff77
860 859
861 860
862 861 file specified by acl.config does not exist
863 862
864 863 $ echo '[acl]' >> $config
865 864 $ echo 'config = ../acl.config' >> $config
866 865 $ do_push barney
867 866 Pushing as user barney
868 867 hgrc = """
869 868 [hooks]
870 869 pretxnchangegroup.acl = python:hgext.acl.hook
871 870 [acl]
872 871 sources = push
873 872 [acl.allow]
874 873 foo/** = fred
875 874 [acl.deny]
876 875 foo/bar/** = fred
877 876 foo/Bar/** = fred
878 877 [acl.allow]
879 878 ** = barney
880 879 **/*.txt = wilma
881 880 [acl]
882 881 config = ../acl.config
883 882 """
884 883 pushing to ../b
885 884 query 1; heads
886 885 searching for changes
887 886 all remote heads known locally
888 887 listing keys for "phases"
889 888 checking for updated bookmarks
890 889 listing keys for "bookmarks"
891 890 listing keys for "bookmarks"
892 891 3 changesets found
893 892 list of changesets:
894 893 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
895 894 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
896 895 911600dab2ae7a9baff75958b84fe606851ce955
897 896 bundle2-output-bundle: "HG20", 5 parts total
898 897 bundle2-output-part: "replycaps" 168 bytes payload
899 898 bundle2-output-part: "check:phases" 24 bytes payload
900 899 bundle2-output-part: "check:heads" streamed payload
901 900 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
902 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
901 bundle2-output-part: "phase-heads" 24 bytes payload
903 902 bundle2-input-bundle: with-transaction
904 903 bundle2-input-part: "replycaps" supported
905 904 bundle2-input-part: total payload size 168
906 905 bundle2-input-part: "check:phases" supported
907 906 bundle2-input-part: total payload size 24
908 907 bundle2-input-part: "check:heads" supported
909 908 bundle2-input-part: total payload size 20
910 909 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
911 910 adding changesets
912 911 add changeset ef1ea85a6374
913 912 add changeset f9cafe1212c8
914 913 add changeset 911600dab2ae
915 914 adding manifests
916 915 adding file changes
917 916 adding foo/Bar/file.txt revisions
918 917 adding foo/file.txt revisions
919 918 adding quux/file.py revisions
920 919 added 3 changesets with 3 changes to 3 files
921 920 calling hook pretxnchangegroup.acl: hgext.acl.hook
922 921 acl: checking access for user "barney"
923 922 error: pretxnchangegroup.acl hook raised an exception: [Errno *] * (glob)
924 923 bundle2-input-part: total payload size 1553
924 bundle2-input-part: total payload size 24
925 925 bundle2-input-bundle: 4 parts total
926 926 transaction abort!
927 927 rollback completed
928 928 abort: No such file or directory: ../acl.config
929 929 no rollback information available
930 930 0:6675d58eff77
931 931
932 932
933 933 betty is allowed inside foo/ by a acl.config file
934 934
935 935 $ echo '[acl.allow]' >> acl.config
936 936 $ echo 'foo/** = betty' >> acl.config
937 937 $ do_push betty
938 938 Pushing as user betty
939 939 hgrc = """
940 940 [hooks]
941 941 pretxnchangegroup.acl = python:hgext.acl.hook
942 942 [acl]
943 943 sources = push
944 944 [acl.allow]
945 945 foo/** = fred
946 946 [acl.deny]
947 947 foo/bar/** = fred
948 948 foo/Bar/** = fred
949 949 [acl.allow]
950 950 ** = barney
951 951 **/*.txt = wilma
952 952 [acl]
953 953 config = ../acl.config
954 954 """
955 955 acl.config = """
956 956 [acl.allow]
957 957 foo/** = betty
958 958 """
959 959 pushing to ../b
960 960 query 1; heads
961 961 searching for changes
962 962 all remote heads known locally
963 963 listing keys for "phases"
964 964 checking for updated bookmarks
965 965 listing keys for "bookmarks"
966 966 listing keys for "bookmarks"
967 967 3 changesets found
968 968 list of changesets:
969 969 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
970 970 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
971 971 911600dab2ae7a9baff75958b84fe606851ce955
972 972 bundle2-output-bundle: "HG20", 5 parts total
973 973 bundle2-output-part: "replycaps" 168 bytes payload
974 974 bundle2-output-part: "check:phases" 24 bytes payload
975 975 bundle2-output-part: "check:heads" streamed payload
976 976 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
977 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
977 bundle2-output-part: "phase-heads" 24 bytes payload
978 978 bundle2-input-bundle: with-transaction
979 979 bundle2-input-part: "replycaps" supported
980 980 bundle2-input-part: total payload size 168
981 981 bundle2-input-part: "check:phases" supported
982 982 bundle2-input-part: total payload size 24
983 983 bundle2-input-part: "check:heads" supported
984 984 bundle2-input-part: total payload size 20
985 985 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
986 986 adding changesets
987 987 add changeset ef1ea85a6374
988 988 add changeset f9cafe1212c8
989 989 add changeset 911600dab2ae
990 990 adding manifests
991 991 adding file changes
992 992 adding foo/Bar/file.txt revisions
993 993 adding foo/file.txt revisions
994 994 adding quux/file.py revisions
995 995 added 3 changesets with 3 changes to 3 files
996 996 calling hook pretxnchangegroup.acl: hgext.acl.hook
997 997 acl: checking access for user "betty"
998 998 acl: acl.allow.branches not enabled
999 999 acl: acl.deny.branches not enabled
1000 1000 acl: acl.allow enabled, 1 entries for user betty
1001 1001 acl: acl.deny enabled, 0 entries for user betty
1002 1002 acl: branch access granted: "ef1ea85a6374" on branch "default"
1003 1003 acl: path access granted: "ef1ea85a6374"
1004 1004 acl: branch access granted: "f9cafe1212c8" on branch "default"
1005 1005 acl: path access granted: "f9cafe1212c8"
1006 1006 acl: branch access granted: "911600dab2ae" on branch "default"
1007 1007 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1008 1008 bundle2-input-part: total payload size 1553
1009 bundle2-input-part: total payload size 24
1009 1010 bundle2-input-bundle: 4 parts total
1010 1011 transaction abort!
1011 1012 rollback completed
1012 1013 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
1013 1014 no rollback information available
1014 1015 0:6675d58eff77
1015 1016
1016 1017
1017 1018 acl.config can set only [acl.allow]/[acl.deny]
1018 1019
1019 1020 $ echo '[hooks]' >> acl.config
1020 1021 $ echo 'changegroup.acl = false' >> acl.config
1021 1022 $ do_push barney
1022 1023 Pushing as user barney
1023 1024 hgrc = """
1024 1025 [hooks]
1025 1026 pretxnchangegroup.acl = python:hgext.acl.hook
1026 1027 [acl]
1027 1028 sources = push
1028 1029 [acl.allow]
1029 1030 foo/** = fred
1030 1031 [acl.deny]
1031 1032 foo/bar/** = fred
1032 1033 foo/Bar/** = fred
1033 1034 [acl.allow]
1034 1035 ** = barney
1035 1036 **/*.txt = wilma
1036 1037 [acl]
1037 1038 config = ../acl.config
1038 1039 """
1039 1040 acl.config = """
1040 1041 [acl.allow]
1041 1042 foo/** = betty
1042 1043 [hooks]
1043 1044 changegroup.acl = false
1044 1045 """
1045 1046 pushing to ../b
1046 1047 query 1; heads
1047 1048 searching for changes
1048 1049 all remote heads known locally
1049 1050 listing keys for "phases"
1050 1051 checking for updated bookmarks
1051 1052 listing keys for "bookmarks"
1052 1053 listing keys for "bookmarks"
1053 1054 3 changesets found
1054 1055 list of changesets:
1055 1056 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1056 1057 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1057 1058 911600dab2ae7a9baff75958b84fe606851ce955
1058 1059 bundle2-output-bundle: "HG20", 5 parts total
1059 1060 bundle2-output-part: "replycaps" 168 bytes payload
1060 1061 bundle2-output-part: "check:phases" 24 bytes payload
1061 1062 bundle2-output-part: "check:heads" streamed payload
1062 1063 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1063 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1064 bundle2-output-part: "phase-heads" 24 bytes payload
1064 1065 bundle2-input-bundle: with-transaction
1065 1066 bundle2-input-part: "replycaps" supported
1066 1067 bundle2-input-part: total payload size 168
1067 1068 bundle2-input-part: "check:phases" supported
1068 1069 bundle2-input-part: total payload size 24
1069 1070 bundle2-input-part: "check:heads" supported
1070 1071 bundle2-input-part: total payload size 20
1071 1072 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1072 1073 adding changesets
1073 1074 add changeset ef1ea85a6374
1074 1075 add changeset f9cafe1212c8
1075 1076 add changeset 911600dab2ae
1076 1077 adding manifests
1077 1078 adding file changes
1078 1079 adding foo/Bar/file.txt revisions
1079 1080 adding foo/file.txt revisions
1080 1081 adding quux/file.py revisions
1081 1082 added 3 changesets with 3 changes to 3 files
1082 1083 calling hook pretxnchangegroup.acl: hgext.acl.hook
1083 1084 acl: checking access for user "barney"
1084 1085 acl: acl.allow.branches not enabled
1085 1086 acl: acl.deny.branches not enabled
1086 1087 acl: acl.allow enabled, 1 entries for user barney
1087 1088 acl: acl.deny enabled, 0 entries for user barney
1088 1089 acl: branch access granted: "ef1ea85a6374" on branch "default"
1089 1090 acl: path access granted: "ef1ea85a6374"
1090 1091 acl: branch access granted: "f9cafe1212c8" on branch "default"
1091 1092 acl: path access granted: "f9cafe1212c8"
1092 1093 acl: branch access granted: "911600dab2ae" on branch "default"
1093 1094 acl: path access granted: "911600dab2ae"
1094 1095 bundle2-input-part: total payload size 1553
1095 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1096 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1096 bundle2-input-part: "phase-heads" supported
1097 bundle2-input-part: total payload size 24
1097 1098 bundle2-input-bundle: 4 parts total
1098 1099 updating the branch cache
1099 bundle2-output-bundle: "HG20", 2 parts total
1100 bundle2-output-bundle: "HG20", 1 parts total
1100 1101 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1101 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1102 1102 bundle2-input-bundle: no-transaction
1103 1103 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1104 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1105 bundle2-input-bundle: 1 parts total
1104 bundle2-input-bundle: 0 parts total
1106 1105 listing keys for "phases"
1107 1106 repository tip rolled back to revision 0 (undo push)
1108 1107 0:6675d58eff77
1109 1108
1110 1109
1111 1110 asterisk
1112 1111
1113 1112 $ init_config
1114 1113
1115 1114 asterisk test
1116 1115
1117 1116 $ echo '[acl.allow]' >> $config
1118 1117 $ echo "** = fred" >> $config
1119 1118
1120 1119 fred is always allowed
1121 1120
1122 1121 $ do_push fred
1123 1122 Pushing as user fred
1124 1123 hgrc = """
1125 1124 [hooks]
1126 1125 pretxnchangegroup.acl = python:hgext.acl.hook
1127 1126 [acl]
1128 1127 sources = push
1129 1128 [extensions]
1130 1129 [acl.allow]
1131 1130 ** = fred
1132 1131 """
1133 1132 pushing to ../b
1134 1133 query 1; heads
1135 1134 searching for changes
1136 1135 all remote heads known locally
1137 1136 listing keys for "phases"
1138 1137 checking for updated bookmarks
1139 1138 listing keys for "bookmarks"
1140 1139 listing keys for "bookmarks"
1141 1140 3 changesets found
1142 1141 list of changesets:
1143 1142 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1144 1143 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1145 1144 911600dab2ae7a9baff75958b84fe606851ce955
1146 1145 bundle2-output-bundle: "HG20", 5 parts total
1147 1146 bundle2-output-part: "replycaps" 168 bytes payload
1148 1147 bundle2-output-part: "check:phases" 24 bytes payload
1149 1148 bundle2-output-part: "check:heads" streamed payload
1150 1149 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1151 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1150 bundle2-output-part: "phase-heads" 24 bytes payload
1152 1151 bundle2-input-bundle: with-transaction
1153 1152 bundle2-input-part: "replycaps" supported
1154 1153 bundle2-input-part: total payload size 168
1155 1154 bundle2-input-part: "check:phases" supported
1156 1155 bundle2-input-part: total payload size 24
1157 1156 bundle2-input-part: "check:heads" supported
1158 1157 bundle2-input-part: total payload size 20
1159 1158 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1160 1159 adding changesets
1161 1160 add changeset ef1ea85a6374
1162 1161 add changeset f9cafe1212c8
1163 1162 add changeset 911600dab2ae
1164 1163 adding manifests
1165 1164 adding file changes
1166 1165 adding foo/Bar/file.txt revisions
1167 1166 adding foo/file.txt revisions
1168 1167 adding quux/file.py revisions
1169 1168 added 3 changesets with 3 changes to 3 files
1170 1169 calling hook pretxnchangegroup.acl: hgext.acl.hook
1171 1170 acl: checking access for user "fred"
1172 1171 acl: acl.allow.branches not enabled
1173 1172 acl: acl.deny.branches not enabled
1174 1173 acl: acl.allow enabled, 1 entries for user fred
1175 1174 acl: acl.deny not enabled
1176 1175 acl: branch access granted: "ef1ea85a6374" on branch "default"
1177 1176 acl: path access granted: "ef1ea85a6374"
1178 1177 acl: branch access granted: "f9cafe1212c8" on branch "default"
1179 1178 acl: path access granted: "f9cafe1212c8"
1180 1179 acl: branch access granted: "911600dab2ae" on branch "default"
1181 1180 acl: path access granted: "911600dab2ae"
1182 1181 bundle2-input-part: total payload size 1553
1183 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1184 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1182 bundle2-input-part: "phase-heads" supported
1183 bundle2-input-part: total payload size 24
1185 1184 bundle2-input-bundle: 4 parts total
1186 1185 updating the branch cache
1187 bundle2-output-bundle: "HG20", 2 parts total
1186 bundle2-output-bundle: "HG20", 1 parts total
1188 1187 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1189 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1190 1188 bundle2-input-bundle: no-transaction
1191 1189 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1192 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1193 bundle2-input-bundle: 1 parts total
1190 bundle2-input-bundle: 0 parts total
1194 1191 listing keys for "phases"
1195 1192 repository tip rolled back to revision 0 (undo push)
1196 1193 0:6675d58eff77
1197 1194
1198 1195
1199 1196 $ echo '[acl.deny]' >> $config
1200 1197 $ echo "foo/Bar/** = *" >> $config
1201 1198
1202 1199 no one is allowed inside foo/Bar/
1203 1200
1204 1201 $ do_push fred
1205 1202 Pushing as user fred
1206 1203 hgrc = """
1207 1204 [hooks]
1208 1205 pretxnchangegroup.acl = python:hgext.acl.hook
1209 1206 [acl]
1210 1207 sources = push
1211 1208 [extensions]
1212 1209 [acl.allow]
1213 1210 ** = fred
1214 1211 [acl.deny]
1215 1212 foo/Bar/** = *
1216 1213 """
1217 1214 pushing to ../b
1218 1215 query 1; heads
1219 1216 searching for changes
1220 1217 all remote heads known locally
1221 1218 listing keys for "phases"
1222 1219 checking for updated bookmarks
1223 1220 listing keys for "bookmarks"
1224 1221 listing keys for "bookmarks"
1225 1222 3 changesets found
1226 1223 list of changesets:
1227 1224 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1228 1225 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1229 1226 911600dab2ae7a9baff75958b84fe606851ce955
1230 1227 bundle2-output-bundle: "HG20", 5 parts total
1231 1228 bundle2-output-part: "replycaps" 168 bytes payload
1232 1229 bundle2-output-part: "check:phases" 24 bytes payload
1233 1230 bundle2-output-part: "check:heads" streamed payload
1234 1231 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1235 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1232 bundle2-output-part: "phase-heads" 24 bytes payload
1236 1233 bundle2-input-bundle: with-transaction
1237 1234 bundle2-input-part: "replycaps" supported
1238 1235 bundle2-input-part: total payload size 168
1239 1236 bundle2-input-part: "check:phases" supported
1240 1237 bundle2-input-part: total payload size 24
1241 1238 bundle2-input-part: "check:heads" supported
1242 1239 bundle2-input-part: total payload size 20
1243 1240 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1244 1241 adding changesets
1245 1242 add changeset ef1ea85a6374
1246 1243 add changeset f9cafe1212c8
1247 1244 add changeset 911600dab2ae
1248 1245 adding manifests
1249 1246 adding file changes
1250 1247 adding foo/Bar/file.txt revisions
1251 1248 adding foo/file.txt revisions
1252 1249 adding quux/file.py revisions
1253 1250 added 3 changesets with 3 changes to 3 files
1254 1251 calling hook pretxnchangegroup.acl: hgext.acl.hook
1255 1252 acl: checking access for user "fred"
1256 1253 acl: acl.allow.branches not enabled
1257 1254 acl: acl.deny.branches not enabled
1258 1255 acl: acl.allow enabled, 1 entries for user fred
1259 1256 acl: acl.deny enabled, 1 entries for user fred
1260 1257 acl: branch access granted: "ef1ea85a6374" on branch "default"
1261 1258 acl: path access granted: "ef1ea85a6374"
1262 1259 acl: branch access granted: "f9cafe1212c8" on branch "default"
1263 1260 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1264 1261 bundle2-input-part: total payload size 1553
1262 bundle2-input-part: total payload size 24
1265 1263 bundle2-input-bundle: 4 parts total
1266 1264 transaction abort!
1267 1265 rollback completed
1268 1266 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1269 1267 no rollback information available
1270 1268 0:6675d58eff77
1271 1269
1272 1270
1273 1271 Groups
1274 1272
1275 1273 $ init_config
1276 1274
1277 1275 OS-level groups
1278 1276
1279 1277 $ echo '[acl.allow]' >> $config
1280 1278 $ echo "** = @group1" >> $config
1281 1279
1282 1280 @group1 is always allowed
1283 1281
1284 1282 $ do_push fred
1285 1283 Pushing as user fred
1286 1284 hgrc = """
1287 1285 [hooks]
1288 1286 pretxnchangegroup.acl = python:hgext.acl.hook
1289 1287 [acl]
1290 1288 sources = push
1291 1289 [extensions]
1292 1290 [acl.allow]
1293 1291 ** = @group1
1294 1292 """
1295 1293 pushing to ../b
1296 1294 query 1; heads
1297 1295 searching for changes
1298 1296 all remote heads known locally
1299 1297 listing keys for "phases"
1300 1298 checking for updated bookmarks
1301 1299 listing keys for "bookmarks"
1302 1300 listing keys for "bookmarks"
1303 1301 3 changesets found
1304 1302 list of changesets:
1305 1303 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1306 1304 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1307 1305 911600dab2ae7a9baff75958b84fe606851ce955
1308 1306 bundle2-output-bundle: "HG20", 5 parts total
1309 1307 bundle2-output-part: "replycaps" 168 bytes payload
1310 1308 bundle2-output-part: "check:phases" 24 bytes payload
1311 1309 bundle2-output-part: "check:heads" streamed payload
1312 1310 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1313 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1311 bundle2-output-part: "phase-heads" 24 bytes payload
1314 1312 bundle2-input-bundle: with-transaction
1315 1313 bundle2-input-part: "replycaps" supported
1316 1314 bundle2-input-part: total payload size 168
1317 1315 bundle2-input-part: "check:phases" supported
1318 1316 bundle2-input-part: total payload size 24
1319 1317 bundle2-input-part: "check:heads" supported
1320 1318 bundle2-input-part: total payload size 20
1321 1319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1322 1320 adding changesets
1323 1321 add changeset ef1ea85a6374
1324 1322 add changeset f9cafe1212c8
1325 1323 add changeset 911600dab2ae
1326 1324 adding manifests
1327 1325 adding file changes
1328 1326 adding foo/Bar/file.txt revisions
1329 1327 adding foo/file.txt revisions
1330 1328 adding quux/file.py revisions
1331 1329 added 3 changesets with 3 changes to 3 files
1332 1330 calling hook pretxnchangegroup.acl: hgext.acl.hook
1333 1331 acl: checking access for user "fred"
1334 1332 acl: acl.allow.branches not enabled
1335 1333 acl: acl.deny.branches not enabled
1336 1334 acl: "group1" not defined in [acl.groups]
1337 1335 acl: acl.allow enabled, 1 entries for user fred
1338 1336 acl: acl.deny not enabled
1339 1337 acl: branch access granted: "ef1ea85a6374" on branch "default"
1340 1338 acl: path access granted: "ef1ea85a6374"
1341 1339 acl: branch access granted: "f9cafe1212c8" on branch "default"
1342 1340 acl: path access granted: "f9cafe1212c8"
1343 1341 acl: branch access granted: "911600dab2ae" on branch "default"
1344 1342 acl: path access granted: "911600dab2ae"
1345 1343 bundle2-input-part: total payload size 1553
1346 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1347 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1344 bundle2-input-part: "phase-heads" supported
1345 bundle2-input-part: total payload size 24
1348 1346 bundle2-input-bundle: 4 parts total
1349 1347 updating the branch cache
1350 bundle2-output-bundle: "HG20", 2 parts total
1348 bundle2-output-bundle: "HG20", 1 parts total
1351 1349 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1352 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1353 1350 bundle2-input-bundle: no-transaction
1354 1351 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1355 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1356 bundle2-input-bundle: 1 parts total
1352 bundle2-input-bundle: 0 parts total
1357 1353 listing keys for "phases"
1358 1354 repository tip rolled back to revision 0 (undo push)
1359 1355 0:6675d58eff77
1360 1356
1361 1357
1362 1358 $ echo '[acl.deny]' >> $config
1363 1359 $ echo "foo/Bar/** = @group1" >> $config
1364 1360
1365 1361 @group is allowed inside anything but foo/Bar/
1366 1362
1367 1363 $ do_push fred
1368 1364 Pushing as user fred
1369 1365 hgrc = """
1370 1366 [hooks]
1371 1367 pretxnchangegroup.acl = python:hgext.acl.hook
1372 1368 [acl]
1373 1369 sources = push
1374 1370 [extensions]
1375 1371 [acl.allow]
1376 1372 ** = @group1
1377 1373 [acl.deny]
1378 1374 foo/Bar/** = @group1
1379 1375 """
1380 1376 pushing to ../b
1381 1377 query 1; heads
1382 1378 searching for changes
1383 1379 all remote heads known locally
1384 1380 listing keys for "phases"
1385 1381 checking for updated bookmarks
1386 1382 listing keys for "bookmarks"
1387 1383 listing keys for "bookmarks"
1388 1384 3 changesets found
1389 1385 list of changesets:
1390 1386 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1391 1387 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1392 1388 911600dab2ae7a9baff75958b84fe606851ce955
1393 1389 bundle2-output-bundle: "HG20", 5 parts total
1394 1390 bundle2-output-part: "replycaps" 168 bytes payload
1395 1391 bundle2-output-part: "check:phases" 24 bytes payload
1396 1392 bundle2-output-part: "check:heads" streamed payload
1397 1393 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1398 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1394 bundle2-output-part: "phase-heads" 24 bytes payload
1399 1395 bundle2-input-bundle: with-transaction
1400 1396 bundle2-input-part: "replycaps" supported
1401 1397 bundle2-input-part: total payload size 168
1402 1398 bundle2-input-part: "check:phases" supported
1403 1399 bundle2-input-part: total payload size 24
1404 1400 bundle2-input-part: "check:heads" supported
1405 1401 bundle2-input-part: total payload size 20
1406 1402 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1407 1403 adding changesets
1408 1404 add changeset ef1ea85a6374
1409 1405 add changeset f9cafe1212c8
1410 1406 add changeset 911600dab2ae
1411 1407 adding manifests
1412 1408 adding file changes
1413 1409 adding foo/Bar/file.txt revisions
1414 1410 adding foo/file.txt revisions
1415 1411 adding quux/file.py revisions
1416 1412 added 3 changesets with 3 changes to 3 files
1417 1413 calling hook pretxnchangegroup.acl: hgext.acl.hook
1418 1414 acl: checking access for user "fred"
1419 1415 acl: acl.allow.branches not enabled
1420 1416 acl: acl.deny.branches not enabled
1421 1417 acl: "group1" not defined in [acl.groups]
1422 1418 acl: acl.allow enabled, 1 entries for user fred
1423 1419 acl: "group1" not defined in [acl.groups]
1424 1420 acl: acl.deny enabled, 1 entries for user fred
1425 1421 acl: branch access granted: "ef1ea85a6374" on branch "default"
1426 1422 acl: path access granted: "ef1ea85a6374"
1427 1423 acl: branch access granted: "f9cafe1212c8" on branch "default"
1428 1424 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1429 1425 bundle2-input-part: total payload size 1553
1426 bundle2-input-part: total payload size 24
1430 1427 bundle2-input-bundle: 4 parts total
1431 1428 transaction abort!
1432 1429 rollback completed
1433 1430 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1434 1431 no rollback information available
1435 1432 0:6675d58eff77
1436 1433
1437 1434
1438 1435 Invalid group
1439 1436
1440 1437 Disable the fakegroups trick to get real failures
1441 1438
1442 1439 $ grep -v fakegroups $config > config.tmp
1443 1440 $ mv config.tmp $config
1444 1441 $ echo '[acl.allow]' >> $config
1445 1442 $ echo "** = @unlikelytoexist" >> $config
1446 1443 $ do_push fred 2>&1 | grep unlikelytoexist
1447 1444 ** = @unlikelytoexist
1448 1445 acl: "unlikelytoexist" not defined in [acl.groups]
1449 1446 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1450 1447 abort: group 'unlikelytoexist' is undefined
1451 1448
1452 1449
1453 1450 Branch acl tests setup
1454 1451
1455 1452 $ init_config
1456 1453 $ cd b
1457 1454 $ hg up
1458 1455 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1459 1456 $ hg branch foobar
1460 1457 marked working directory as branch foobar
1461 1458 (branches are permanent and global, did you want a bookmark?)
1462 1459 $ hg commit -m 'create foobar'
1463 1460 $ echo 'foo contents' > abc.txt
1464 1461 $ hg add abc.txt
1465 1462 $ hg commit -m 'foobar contents'
1466 1463 $ cd ..
1467 1464 $ hg --cwd a pull ../b
1468 1465 pulling from ../b
1469 1466 searching for changes
1470 1467 adding changesets
1471 1468 adding manifests
1472 1469 adding file changes
1473 1470 added 2 changesets with 1 changes to 1 files (+1 heads)
1474 1471 new changesets 81fbf4469322:fb35475503ef
1475 1472 (run 'hg heads' to see heads)
1476 1473
1477 1474 Create additional changeset on foobar branch
1478 1475
1479 1476 $ cd a
1480 1477 $ hg up -C foobar
1481 1478 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1482 1479 $ echo 'foo contents2' > abc.txt
1483 1480 $ hg commit -m 'foobar contents2'
1484 1481 $ cd ..
1485 1482
1486 1483
1487 1484 No branch acls specified
1488 1485
1489 1486 $ do_push astro
1490 1487 Pushing as user astro
1491 1488 hgrc = """
1492 1489 [hooks]
1493 1490 pretxnchangegroup.acl = python:hgext.acl.hook
1494 1491 [acl]
1495 1492 sources = push
1496 1493 [extensions]
1497 1494 """
1498 1495 pushing to ../b
1499 1496 query 1; heads
1500 1497 searching for changes
1501 1498 all remote heads known locally
1502 1499 listing keys for "phases"
1503 1500 checking for updated bookmarks
1504 1501 listing keys for "bookmarks"
1505 1502 listing keys for "bookmarks"
1506 1503 4 changesets found
1507 1504 list of changesets:
1508 1505 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1509 1506 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1510 1507 911600dab2ae7a9baff75958b84fe606851ce955
1511 1508 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1512 bundle2-output-bundle: "HG20", 6 parts total
1509 bundle2-output-bundle: "HG20", 5 parts total
1513 1510 bundle2-output-part: "replycaps" 168 bytes payload
1514 1511 bundle2-output-part: "check:phases" 48 bytes payload
1515 1512 bundle2-output-part: "check:heads" streamed payload
1516 1513 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1517 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1518 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1514 bundle2-output-part: "phase-heads" 48 bytes payload
1519 1515 bundle2-input-bundle: with-transaction
1520 1516 bundle2-input-part: "replycaps" supported
1521 1517 bundle2-input-part: total payload size 168
1522 1518 bundle2-input-part: "check:phases" supported
1523 1519 bundle2-input-part: total payload size 48
1524 1520 bundle2-input-part: "check:heads" supported
1525 1521 bundle2-input-part: total payload size 20
1526 1522 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1527 1523 adding changesets
1528 1524 add changeset ef1ea85a6374
1529 1525 add changeset f9cafe1212c8
1530 1526 add changeset 911600dab2ae
1531 1527 add changeset e8fc755d4d82
1532 1528 adding manifests
1533 1529 adding file changes
1534 1530 adding abc.txt revisions
1535 1531 adding foo/Bar/file.txt revisions
1536 1532 adding foo/file.txt revisions
1537 1533 adding quux/file.py revisions
1538 1534 added 4 changesets with 4 changes to 4 files (+1 heads)
1539 1535 calling hook pretxnchangegroup.acl: hgext.acl.hook
1540 1536 acl: checking access for user "astro"
1541 1537 acl: acl.allow.branches not enabled
1542 1538 acl: acl.deny.branches not enabled
1543 1539 acl: acl.allow not enabled
1544 1540 acl: acl.deny not enabled
1545 1541 acl: branch access granted: "ef1ea85a6374" on branch "default"
1546 1542 acl: path access granted: "ef1ea85a6374"
1547 1543 acl: branch access granted: "f9cafe1212c8" on branch "default"
1548 1544 acl: path access granted: "f9cafe1212c8"
1549 1545 acl: branch access granted: "911600dab2ae" on branch "default"
1550 1546 acl: path access granted: "911600dab2ae"
1551 1547 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1552 1548 acl: path access granted: "e8fc755d4d82"
1553 1549 bundle2-input-part: total payload size 2068
1554 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1555 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1556 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1557 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1558 bundle2-input-bundle: 5 parts total
1550 bundle2-input-part: "phase-heads" supported
1551 bundle2-input-part: total payload size 48
1552 bundle2-input-bundle: 4 parts total
1559 1553 updating the branch cache
1560 bundle2-output-bundle: "HG20", 3 parts total
1554 bundle2-output-bundle: "HG20", 1 parts total
1561 1555 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1562 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1563 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1564 1556 bundle2-input-bundle: no-transaction
1565 1557 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1566 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1567 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1568 bundle2-input-bundle: 2 parts total
1558 bundle2-input-bundle: 0 parts total
1569 1559 listing keys for "phases"
1570 1560 repository tip rolled back to revision 2 (undo push)
1571 1561 2:fb35475503ef
1572 1562
1573 1563
1574 1564 Branch acl deny test
1575 1565
1576 1566 $ echo "[acl.deny.branches]" >> $config
1577 1567 $ echo "foobar = *" >> $config
1578 1568 $ do_push astro
1579 1569 Pushing as user astro
1580 1570 hgrc = """
1581 1571 [hooks]
1582 1572 pretxnchangegroup.acl = python:hgext.acl.hook
1583 1573 [acl]
1584 1574 sources = push
1585 1575 [extensions]
1586 1576 [acl.deny.branches]
1587 1577 foobar = *
1588 1578 """
1589 1579 pushing to ../b
1590 1580 query 1; heads
1591 1581 searching for changes
1592 1582 all remote heads known locally
1593 1583 listing keys for "phases"
1594 1584 checking for updated bookmarks
1595 1585 listing keys for "bookmarks"
1596 1586 listing keys for "bookmarks"
1597 1587 4 changesets found
1598 1588 list of changesets:
1599 1589 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1600 1590 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1601 1591 911600dab2ae7a9baff75958b84fe606851ce955
1602 1592 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1603 bundle2-output-bundle: "HG20", 6 parts total
1593 bundle2-output-bundle: "HG20", 5 parts total
1604 1594 bundle2-output-part: "replycaps" 168 bytes payload
1605 1595 bundle2-output-part: "check:phases" 48 bytes payload
1606 1596 bundle2-output-part: "check:heads" streamed payload
1607 1597 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1608 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1609 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1598 bundle2-output-part: "phase-heads" 48 bytes payload
1610 1599 bundle2-input-bundle: with-transaction
1611 1600 bundle2-input-part: "replycaps" supported
1612 1601 bundle2-input-part: total payload size 168
1613 1602 bundle2-input-part: "check:phases" supported
1614 1603 bundle2-input-part: total payload size 48
1615 1604 bundle2-input-part: "check:heads" supported
1616 1605 bundle2-input-part: total payload size 20
1617 1606 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1618 1607 adding changesets
1619 1608 add changeset ef1ea85a6374
1620 1609 add changeset f9cafe1212c8
1621 1610 add changeset 911600dab2ae
1622 1611 add changeset e8fc755d4d82
1623 1612 adding manifests
1624 1613 adding file changes
1625 1614 adding abc.txt revisions
1626 1615 adding foo/Bar/file.txt revisions
1627 1616 adding foo/file.txt revisions
1628 1617 adding quux/file.py revisions
1629 1618 added 4 changesets with 4 changes to 4 files (+1 heads)
1630 1619 calling hook pretxnchangegroup.acl: hgext.acl.hook
1631 1620 acl: checking access for user "astro"
1632 1621 acl: acl.allow.branches not enabled
1633 1622 acl: acl.deny.branches enabled, 1 entries for user astro
1634 1623 acl: acl.allow not enabled
1635 1624 acl: acl.deny not enabled
1636 1625 acl: branch access granted: "ef1ea85a6374" on branch "default"
1637 1626 acl: path access granted: "ef1ea85a6374"
1638 1627 acl: branch access granted: "f9cafe1212c8" on branch "default"
1639 1628 acl: path access granted: "f9cafe1212c8"
1640 1629 acl: branch access granted: "911600dab2ae" on branch "default"
1641 1630 acl: path access granted: "911600dab2ae"
1642 1631 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1643 1632 bundle2-input-part: total payload size 2068
1644 bundle2-input-bundle: 5 parts total
1633 bundle2-input-part: total payload size 48
1634 bundle2-input-bundle: 4 parts total
1645 1635 transaction abort!
1646 1636 rollback completed
1647 1637 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1648 1638 no rollback information available
1649 1639 2:fb35475503ef
1650 1640
1651 1641
1652 1642 Branch acl empty allow test
1653 1643
1654 1644 $ init_config
1655 1645 $ echo "[acl.allow.branches]" >> $config
1656 1646 $ do_push astro
1657 1647 Pushing as user astro
1658 1648 hgrc = """
1659 1649 [hooks]
1660 1650 pretxnchangegroup.acl = python:hgext.acl.hook
1661 1651 [acl]
1662 1652 sources = push
1663 1653 [extensions]
1664 1654 [acl.allow.branches]
1665 1655 """
1666 1656 pushing to ../b
1667 1657 query 1; heads
1668 1658 searching for changes
1669 1659 all remote heads known locally
1670 1660 listing keys for "phases"
1671 1661 checking for updated bookmarks
1672 1662 listing keys for "bookmarks"
1673 1663 listing keys for "bookmarks"
1674 1664 4 changesets found
1675 1665 list of changesets:
1676 1666 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1677 1667 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1678 1668 911600dab2ae7a9baff75958b84fe606851ce955
1679 1669 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1680 bundle2-output-bundle: "HG20", 6 parts total
1670 bundle2-output-bundle: "HG20", 5 parts total
1681 1671 bundle2-output-part: "replycaps" 168 bytes payload
1682 1672 bundle2-output-part: "check:phases" 48 bytes payload
1683 1673 bundle2-output-part: "check:heads" streamed payload
1684 1674 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1685 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1686 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1675 bundle2-output-part: "phase-heads" 48 bytes payload
1687 1676 bundle2-input-bundle: with-transaction
1688 1677 bundle2-input-part: "replycaps" supported
1689 1678 bundle2-input-part: total payload size 168
1690 1679 bundle2-input-part: "check:phases" supported
1691 1680 bundle2-input-part: total payload size 48
1692 1681 bundle2-input-part: "check:heads" supported
1693 1682 bundle2-input-part: total payload size 20
1694 1683 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1695 1684 adding changesets
1696 1685 add changeset ef1ea85a6374
1697 1686 add changeset f9cafe1212c8
1698 1687 add changeset 911600dab2ae
1699 1688 add changeset e8fc755d4d82
1700 1689 adding manifests
1701 1690 adding file changes
1702 1691 adding abc.txt revisions
1703 1692 adding foo/Bar/file.txt revisions
1704 1693 adding foo/file.txt revisions
1705 1694 adding quux/file.py revisions
1706 1695 added 4 changesets with 4 changes to 4 files (+1 heads)
1707 1696 calling hook pretxnchangegroup.acl: hgext.acl.hook
1708 1697 acl: checking access for user "astro"
1709 1698 acl: acl.allow.branches enabled, 0 entries for user astro
1710 1699 acl: acl.deny.branches not enabled
1711 1700 acl: acl.allow not enabled
1712 1701 acl: acl.deny not enabled
1713 1702 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1714 1703 bundle2-input-part: total payload size 2068
1715 bundle2-input-bundle: 5 parts total
1704 bundle2-input-part: total payload size 48
1705 bundle2-input-bundle: 4 parts total
1716 1706 transaction abort!
1717 1707 rollback completed
1718 1708 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1719 1709 no rollback information available
1720 1710 2:fb35475503ef
1721 1711
1722 1712
1723 1713 Branch acl allow other
1724 1714
1725 1715 $ init_config
1726 1716 $ echo "[acl.allow.branches]" >> $config
1727 1717 $ echo "* = george" >> $config
1728 1718 $ do_push astro
1729 1719 Pushing as user astro
1730 1720 hgrc = """
1731 1721 [hooks]
1732 1722 pretxnchangegroup.acl = python:hgext.acl.hook
1733 1723 [acl]
1734 1724 sources = push
1735 1725 [extensions]
1736 1726 [acl.allow.branches]
1737 1727 * = george
1738 1728 """
1739 1729 pushing to ../b
1740 1730 query 1; heads
1741 1731 searching for changes
1742 1732 all remote heads known locally
1743 1733 listing keys for "phases"
1744 1734 checking for updated bookmarks
1745 1735 listing keys for "bookmarks"
1746 1736 listing keys for "bookmarks"
1747 1737 4 changesets found
1748 1738 list of changesets:
1749 1739 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1750 1740 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1751 1741 911600dab2ae7a9baff75958b84fe606851ce955
1752 1742 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1753 bundle2-output-bundle: "HG20", 6 parts total
1743 bundle2-output-bundle: "HG20", 5 parts total
1754 1744 bundle2-output-part: "replycaps" 168 bytes payload
1755 1745 bundle2-output-part: "check:phases" 48 bytes payload
1756 1746 bundle2-output-part: "check:heads" streamed payload
1757 1747 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1758 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1759 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1748 bundle2-output-part: "phase-heads" 48 bytes payload
1760 1749 bundle2-input-bundle: with-transaction
1761 1750 bundle2-input-part: "replycaps" supported
1762 1751 bundle2-input-part: total payload size 168
1763 1752 bundle2-input-part: "check:phases" supported
1764 1753 bundle2-input-part: total payload size 48
1765 1754 bundle2-input-part: "check:heads" supported
1766 1755 bundle2-input-part: total payload size 20
1767 1756 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1768 1757 adding changesets
1769 1758 add changeset ef1ea85a6374
1770 1759 add changeset f9cafe1212c8
1771 1760 add changeset 911600dab2ae
1772 1761 add changeset e8fc755d4d82
1773 1762 adding manifests
1774 1763 adding file changes
1775 1764 adding abc.txt revisions
1776 1765 adding foo/Bar/file.txt revisions
1777 1766 adding foo/file.txt revisions
1778 1767 adding quux/file.py revisions
1779 1768 added 4 changesets with 4 changes to 4 files (+1 heads)
1780 1769 calling hook pretxnchangegroup.acl: hgext.acl.hook
1781 1770 acl: checking access for user "astro"
1782 1771 acl: acl.allow.branches enabled, 0 entries for user astro
1783 1772 acl: acl.deny.branches not enabled
1784 1773 acl: acl.allow not enabled
1785 1774 acl: acl.deny not enabled
1786 1775 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1787 1776 bundle2-input-part: total payload size 2068
1788 bundle2-input-bundle: 5 parts total
1777 bundle2-input-part: total payload size 48
1778 bundle2-input-bundle: 4 parts total
1789 1779 transaction abort!
1790 1780 rollback completed
1791 1781 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1792 1782 no rollback information available
1793 1783 2:fb35475503ef
1794 1784
1795 1785 $ do_push george
1796 1786 Pushing as user george
1797 1787 hgrc = """
1798 1788 [hooks]
1799 1789 pretxnchangegroup.acl = python:hgext.acl.hook
1800 1790 [acl]
1801 1791 sources = push
1802 1792 [extensions]
1803 1793 [acl.allow.branches]
1804 1794 * = george
1805 1795 """
1806 1796 pushing to ../b
1807 1797 query 1; heads
1808 1798 searching for changes
1809 1799 all remote heads known locally
1810 1800 listing keys for "phases"
1811 1801 checking for updated bookmarks
1812 1802 listing keys for "bookmarks"
1813 1803 listing keys for "bookmarks"
1814 1804 4 changesets found
1815 1805 list of changesets:
1816 1806 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1817 1807 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1818 1808 911600dab2ae7a9baff75958b84fe606851ce955
1819 1809 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1820 bundle2-output-bundle: "HG20", 6 parts total
1810 bundle2-output-bundle: "HG20", 5 parts total
1821 1811 bundle2-output-part: "replycaps" 168 bytes payload
1822 1812 bundle2-output-part: "check:phases" 48 bytes payload
1823 1813 bundle2-output-part: "check:heads" streamed payload
1824 1814 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1825 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1826 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1815 bundle2-output-part: "phase-heads" 48 bytes payload
1827 1816 bundle2-input-bundle: with-transaction
1828 1817 bundle2-input-part: "replycaps" supported
1829 1818 bundle2-input-part: total payload size 168
1830 1819 bundle2-input-part: "check:phases" supported
1831 1820 bundle2-input-part: total payload size 48
1832 1821 bundle2-input-part: "check:heads" supported
1833 1822 bundle2-input-part: total payload size 20
1834 1823 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1835 1824 adding changesets
1836 1825 add changeset ef1ea85a6374
1837 1826 add changeset f9cafe1212c8
1838 1827 add changeset 911600dab2ae
1839 1828 add changeset e8fc755d4d82
1840 1829 adding manifests
1841 1830 adding file changes
1842 1831 adding abc.txt revisions
1843 1832 adding foo/Bar/file.txt revisions
1844 1833 adding foo/file.txt revisions
1845 1834 adding quux/file.py revisions
1846 1835 added 4 changesets with 4 changes to 4 files (+1 heads)
1847 1836 calling hook pretxnchangegroup.acl: hgext.acl.hook
1848 1837 acl: checking access for user "george"
1849 1838 acl: acl.allow.branches enabled, 1 entries for user george
1850 1839 acl: acl.deny.branches not enabled
1851 1840 acl: acl.allow not enabled
1852 1841 acl: acl.deny not enabled
1853 1842 acl: branch access granted: "ef1ea85a6374" on branch "default"
1854 1843 acl: path access granted: "ef1ea85a6374"
1855 1844 acl: branch access granted: "f9cafe1212c8" on branch "default"
1856 1845 acl: path access granted: "f9cafe1212c8"
1857 1846 acl: branch access granted: "911600dab2ae" on branch "default"
1858 1847 acl: path access granted: "911600dab2ae"
1859 1848 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1860 1849 acl: path access granted: "e8fc755d4d82"
1861 1850 bundle2-input-part: total payload size 2068
1862 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1863 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1864 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1865 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1866 bundle2-input-bundle: 5 parts total
1851 bundle2-input-part: "phase-heads" supported
1852 bundle2-input-part: total payload size 48
1853 bundle2-input-bundle: 4 parts total
1867 1854 updating the branch cache
1868 bundle2-output-bundle: "HG20", 3 parts total
1855 bundle2-output-bundle: "HG20", 1 parts total
1869 1856 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1870 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1871 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1872 1857 bundle2-input-bundle: no-transaction
1873 1858 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1874 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1875 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1876 bundle2-input-bundle: 2 parts total
1859 bundle2-input-bundle: 0 parts total
1877 1860 listing keys for "phases"
1878 1861 repository tip rolled back to revision 2 (undo push)
1879 1862 2:fb35475503ef
1880 1863
1881 1864
1882 1865 Branch acl conflicting allow
1883 1866 asterisk ends up applying to all branches and allowing george to
1884 1867 push foobar into the remote
1885 1868
1886 1869 $ init_config
1887 1870 $ echo "[acl.allow.branches]" >> $config
1888 1871 $ echo "foobar = astro" >> $config
1889 1872 $ echo "* = george" >> $config
1890 1873 $ do_push george
1891 1874 Pushing as user george
1892 1875 hgrc = """
1893 1876 [hooks]
1894 1877 pretxnchangegroup.acl = python:hgext.acl.hook
1895 1878 [acl]
1896 1879 sources = push
1897 1880 [extensions]
1898 1881 [acl.allow.branches]
1899 1882 foobar = astro
1900 1883 * = george
1901 1884 """
1902 1885 pushing to ../b
1903 1886 query 1; heads
1904 1887 searching for changes
1905 1888 all remote heads known locally
1906 1889 listing keys for "phases"
1907 1890 checking for updated bookmarks
1908 1891 listing keys for "bookmarks"
1909 1892 listing keys for "bookmarks"
1910 1893 4 changesets found
1911 1894 list of changesets:
1912 1895 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1913 1896 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1914 1897 911600dab2ae7a9baff75958b84fe606851ce955
1915 1898 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1916 bundle2-output-bundle: "HG20", 6 parts total
1899 bundle2-output-bundle: "HG20", 5 parts total
1917 1900 bundle2-output-part: "replycaps" 168 bytes payload
1918 1901 bundle2-output-part: "check:phases" 48 bytes payload
1919 1902 bundle2-output-part: "check:heads" streamed payload
1920 1903 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1921 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1922 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1904 bundle2-output-part: "phase-heads" 48 bytes payload
1923 1905 bundle2-input-bundle: with-transaction
1924 1906 bundle2-input-part: "replycaps" supported
1925 1907 bundle2-input-part: total payload size 168
1926 1908 bundle2-input-part: "check:phases" supported
1927 1909 bundle2-input-part: total payload size 48
1928 1910 bundle2-input-part: "check:heads" supported
1929 1911 bundle2-input-part: total payload size 20
1930 1912 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1931 1913 adding changesets
1932 1914 add changeset ef1ea85a6374
1933 1915 add changeset f9cafe1212c8
1934 1916 add changeset 911600dab2ae
1935 1917 add changeset e8fc755d4d82
1936 1918 adding manifests
1937 1919 adding file changes
1938 1920 adding abc.txt revisions
1939 1921 adding foo/Bar/file.txt revisions
1940 1922 adding foo/file.txt revisions
1941 1923 adding quux/file.py revisions
1942 1924 added 4 changesets with 4 changes to 4 files (+1 heads)
1943 1925 calling hook pretxnchangegroup.acl: hgext.acl.hook
1944 1926 acl: checking access for user "george"
1945 1927 acl: acl.allow.branches enabled, 1 entries for user george
1946 1928 acl: acl.deny.branches not enabled
1947 1929 acl: acl.allow not enabled
1948 1930 acl: acl.deny not enabled
1949 1931 acl: branch access granted: "ef1ea85a6374" on branch "default"
1950 1932 acl: path access granted: "ef1ea85a6374"
1951 1933 acl: branch access granted: "f9cafe1212c8" on branch "default"
1952 1934 acl: path access granted: "f9cafe1212c8"
1953 1935 acl: branch access granted: "911600dab2ae" on branch "default"
1954 1936 acl: path access granted: "911600dab2ae"
1955 1937 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1956 1938 acl: path access granted: "e8fc755d4d82"
1957 1939 bundle2-input-part: total payload size 2068
1958 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1959 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1960 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1961 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1962 bundle2-input-bundle: 5 parts total
1940 bundle2-input-part: "phase-heads" supported
1941 bundle2-input-part: total payload size 48
1942 bundle2-input-bundle: 4 parts total
1963 1943 updating the branch cache
1964 bundle2-output-bundle: "HG20", 3 parts total
1944 bundle2-output-bundle: "HG20", 1 parts total
1965 1945 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1966 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1967 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1968 1946 bundle2-input-bundle: no-transaction
1969 1947 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1970 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1971 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1972 bundle2-input-bundle: 2 parts total
1948 bundle2-input-bundle: 0 parts total
1973 1949 listing keys for "phases"
1974 1950 repository tip rolled back to revision 2 (undo push)
1975 1951 2:fb35475503ef
1976 1952
1977 1953 Branch acl conflicting deny
1978 1954
1979 1955 $ init_config
1980 1956 $ echo "[acl.deny.branches]" >> $config
1981 1957 $ echo "foobar = astro" >> $config
1982 1958 $ echo "default = astro" >> $config
1983 1959 $ echo "* = george" >> $config
1984 1960 $ do_push george
1985 1961 Pushing as user george
1986 1962 hgrc = """
1987 1963 [hooks]
1988 1964 pretxnchangegroup.acl = python:hgext.acl.hook
1989 1965 [acl]
1990 1966 sources = push
1991 1967 [extensions]
1992 1968 [acl.deny.branches]
1993 1969 foobar = astro
1994 1970 default = astro
1995 1971 * = george
1996 1972 """
1997 1973 pushing to ../b
1998 1974 query 1; heads
1999 1975 searching for changes
2000 1976 all remote heads known locally
2001 1977 listing keys for "phases"
2002 1978 checking for updated bookmarks
2003 1979 listing keys for "bookmarks"
2004 1980 listing keys for "bookmarks"
2005 1981 4 changesets found
2006 1982 list of changesets:
2007 1983 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2008 1984 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2009 1985 911600dab2ae7a9baff75958b84fe606851ce955
2010 1986 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2011 bundle2-output-bundle: "HG20", 6 parts total
1987 bundle2-output-bundle: "HG20", 5 parts total
2012 1988 bundle2-output-part: "replycaps" 168 bytes payload
2013 1989 bundle2-output-part: "check:phases" 48 bytes payload
2014 1990 bundle2-output-part: "check:heads" streamed payload
2015 1991 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2016 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2017 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1992 bundle2-output-part: "phase-heads" 48 bytes payload
2018 1993 bundle2-input-bundle: with-transaction
2019 1994 bundle2-input-part: "replycaps" supported
2020 1995 bundle2-input-part: total payload size 168
2021 1996 bundle2-input-part: "check:phases" supported
2022 1997 bundle2-input-part: total payload size 48
2023 1998 bundle2-input-part: "check:heads" supported
2024 1999 bundle2-input-part: total payload size 20
2025 2000 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2026 2001 adding changesets
2027 2002 add changeset ef1ea85a6374
2028 2003 add changeset f9cafe1212c8
2029 2004 add changeset 911600dab2ae
2030 2005 add changeset e8fc755d4d82
2031 2006 adding manifests
2032 2007 adding file changes
2033 2008 adding abc.txt revisions
2034 2009 adding foo/Bar/file.txt revisions
2035 2010 adding foo/file.txt revisions
2036 2011 adding quux/file.py revisions
2037 2012 added 4 changesets with 4 changes to 4 files (+1 heads)
2038 2013 calling hook pretxnchangegroup.acl: hgext.acl.hook
2039 2014 acl: checking access for user "george"
2040 2015 acl: acl.allow.branches not enabled
2041 2016 acl: acl.deny.branches enabled, 1 entries for user george
2042 2017 acl: acl.allow not enabled
2043 2018 acl: acl.deny not enabled
2044 2019 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2045 2020 bundle2-input-part: total payload size 2068
2046 bundle2-input-bundle: 5 parts total
2021 bundle2-input-part: total payload size 48
2022 bundle2-input-bundle: 4 parts total
2047 2023 transaction abort!
2048 2024 rollback completed
2049 2025 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2050 2026 no rollback information available
2051 2027 2:fb35475503ef
2052 2028
2053 2029 User 'astro' must not be denied
2054 2030
2055 2031 $ init_config
2056 2032 $ echo "[acl.deny.branches]" >> $config
2057 2033 $ echo "default = !astro" >> $config
2058 2034 $ do_push astro
2059 2035 Pushing as user astro
2060 2036 hgrc = """
2061 2037 [hooks]
2062 2038 pretxnchangegroup.acl = python:hgext.acl.hook
2063 2039 [acl]
2064 2040 sources = push
2065 2041 [extensions]
2066 2042 [acl.deny.branches]
2067 2043 default = !astro
2068 2044 """
2069 2045 pushing to ../b
2070 2046 query 1; heads
2071 2047 searching for changes
2072 2048 all remote heads known locally
2073 2049 listing keys for "phases"
2074 2050 checking for updated bookmarks
2075 2051 listing keys for "bookmarks"
2076 2052 listing keys for "bookmarks"
2077 2053 4 changesets found
2078 2054 list of changesets:
2079 2055 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2080 2056 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2081 2057 911600dab2ae7a9baff75958b84fe606851ce955
2082 2058 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2083 bundle2-output-bundle: "HG20", 6 parts total
2059 bundle2-output-bundle: "HG20", 5 parts total
2084 2060 bundle2-output-part: "replycaps" 168 bytes payload
2085 2061 bundle2-output-part: "check:phases" 48 bytes payload
2086 2062 bundle2-output-part: "check:heads" streamed payload
2087 2063 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2088 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2089 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2064 bundle2-output-part: "phase-heads" 48 bytes payload
2090 2065 bundle2-input-bundle: with-transaction
2091 2066 bundle2-input-part: "replycaps" supported
2092 2067 bundle2-input-part: total payload size 168
2093 2068 bundle2-input-part: "check:phases" supported
2094 2069 bundle2-input-part: total payload size 48
2095 2070 bundle2-input-part: "check:heads" supported
2096 2071 bundle2-input-part: total payload size 20
2097 2072 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2098 2073 adding changesets
2099 2074 add changeset ef1ea85a6374
2100 2075 add changeset f9cafe1212c8
2101 2076 add changeset 911600dab2ae
2102 2077 add changeset e8fc755d4d82
2103 2078 adding manifests
2104 2079 adding file changes
2105 2080 adding abc.txt revisions
2106 2081 adding foo/Bar/file.txt revisions
2107 2082 adding foo/file.txt revisions
2108 2083 adding quux/file.py revisions
2109 2084 added 4 changesets with 4 changes to 4 files (+1 heads)
2110 2085 calling hook pretxnchangegroup.acl: hgext.acl.hook
2111 2086 acl: checking access for user "astro"
2112 2087 acl: acl.allow.branches not enabled
2113 2088 acl: acl.deny.branches enabled, 0 entries for user astro
2114 2089 acl: acl.allow not enabled
2115 2090 acl: acl.deny not enabled
2116 2091 acl: branch access granted: "ef1ea85a6374" on branch "default"
2117 2092 acl: path access granted: "ef1ea85a6374"
2118 2093 acl: branch access granted: "f9cafe1212c8" on branch "default"
2119 2094 acl: path access granted: "f9cafe1212c8"
2120 2095 acl: branch access granted: "911600dab2ae" on branch "default"
2121 2096 acl: path access granted: "911600dab2ae"
2122 2097 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2123 2098 acl: path access granted: "e8fc755d4d82"
2124 2099 bundle2-input-part: total payload size 2068
2125 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2126 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2127 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2128 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2129 bundle2-input-bundle: 5 parts total
2100 bundle2-input-part: "phase-heads" supported
2101 bundle2-input-part: total payload size 48
2102 bundle2-input-bundle: 4 parts total
2130 2103 updating the branch cache
2131 bundle2-output-bundle: "HG20", 3 parts total
2104 bundle2-output-bundle: "HG20", 1 parts total
2132 2105 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2133 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2134 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2135 2106 bundle2-input-bundle: no-transaction
2136 2107 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2137 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2138 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2139 bundle2-input-bundle: 2 parts total
2108 bundle2-input-bundle: 0 parts total
2140 2109 listing keys for "phases"
2141 2110 repository tip rolled back to revision 2 (undo push)
2142 2111 2:fb35475503ef
2143 2112
2144 2113
2145 2114 Non-astro users must be denied
2146 2115
2147 2116 $ do_push george
2148 2117 Pushing as user george
2149 2118 hgrc = """
2150 2119 [hooks]
2151 2120 pretxnchangegroup.acl = python:hgext.acl.hook
2152 2121 [acl]
2153 2122 sources = push
2154 2123 [extensions]
2155 2124 [acl.deny.branches]
2156 2125 default = !astro
2157 2126 """
2158 2127 pushing to ../b
2159 2128 query 1; heads
2160 2129 searching for changes
2161 2130 all remote heads known locally
2162 2131 listing keys for "phases"
2163 2132 checking for updated bookmarks
2164 2133 listing keys for "bookmarks"
2165 2134 listing keys for "bookmarks"
2166 2135 4 changesets found
2167 2136 list of changesets:
2168 2137 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2169 2138 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2170 2139 911600dab2ae7a9baff75958b84fe606851ce955
2171 2140 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2172 bundle2-output-bundle: "HG20", 6 parts total
2141 bundle2-output-bundle: "HG20", 5 parts total
2173 2142 bundle2-output-part: "replycaps" 168 bytes payload
2174 2143 bundle2-output-part: "check:phases" 48 bytes payload
2175 2144 bundle2-output-part: "check:heads" streamed payload
2176 2145 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2177 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2178 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2146 bundle2-output-part: "phase-heads" 48 bytes payload
2179 2147 bundle2-input-bundle: with-transaction
2180 2148 bundle2-input-part: "replycaps" supported
2181 2149 bundle2-input-part: total payload size 168
2182 2150 bundle2-input-part: "check:phases" supported
2183 2151 bundle2-input-part: total payload size 48
2184 2152 bundle2-input-part: "check:heads" supported
2185 2153 bundle2-input-part: total payload size 20
2186 2154 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2187 2155 adding changesets
2188 2156 add changeset ef1ea85a6374
2189 2157 add changeset f9cafe1212c8
2190 2158 add changeset 911600dab2ae
2191 2159 add changeset e8fc755d4d82
2192 2160 adding manifests
2193 2161 adding file changes
2194 2162 adding abc.txt revisions
2195 2163 adding foo/Bar/file.txt revisions
2196 2164 adding foo/file.txt revisions
2197 2165 adding quux/file.py revisions
2198 2166 added 4 changesets with 4 changes to 4 files (+1 heads)
2199 2167 calling hook pretxnchangegroup.acl: hgext.acl.hook
2200 2168 acl: checking access for user "george"
2201 2169 acl: acl.allow.branches not enabled
2202 2170 acl: acl.deny.branches enabled, 1 entries for user george
2203 2171 acl: acl.allow not enabled
2204 2172 acl: acl.deny not enabled
2205 2173 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2206 2174 bundle2-input-part: total payload size 2068
2207 bundle2-input-bundle: 5 parts total
2175 bundle2-input-part: total payload size 48
2176 bundle2-input-bundle: 4 parts total
2208 2177 transaction abort!
2209 2178 rollback completed
2210 2179 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2211 2180 no rollback information available
2212 2181 2:fb35475503ef
2213 2182
2214 2183
@@ -1,1153 +1,1147
1 1 Test exchange of common information using bundle2
2 2
3 3
4 4 $ getmainid() {
5 5 > hg -R main log --template '{node}\n' --rev "$1"
6 6 > }
7 7
8 8 enable obsolescence
9 9
10 10 $ cp $HGRCPATH $TESTTMP/hgrc.orig
11 11 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
12 12 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
13 13 > hg debuglock
14 14 > EOF
15 15
16 16 $ cat >> $HGRCPATH << EOF
17 17 > [experimental]
18 18 > stabilization=createmarkers,exchange
19 19 > bundle2-output-capture=True
20 20 > [ui]
21 21 > ssh="$PYTHON" "$TESTDIR/dummyssh"
22 22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 23 > [web]
24 24 > push_ssl = false
25 25 > allow_push = *
26 26 > [phases]
27 27 > publish=False
28 28 > [hooks]
29 29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
30 30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
31 31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
32 32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
33 33 > EOF
34 34
35 35 The extension requires a repo (currently unused)
36 36
37 37 $ hg init main
38 38 $ cd main
39 39 $ touch a
40 40 $ hg add a
41 41 $ hg commit -m 'a'
42 42 pre-close-tip:3903775176ed draft
43 43 postclose-tip:3903775176ed draft
44 44 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
45 45
46 46 $ hg unbundle $TESTDIR/bundles/rebase.hg
47 47 adding changesets
48 48 adding manifests
49 49 adding file changes
50 50 added 8 changesets with 7 changes to 7 files (+3 heads)
51 51 pre-close-tip:02de42196ebe draft
52 52 new changesets cd010b8cd998:02de42196ebe
53 53 postclose-tip:02de42196ebe draft
54 54 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:$ID$ HG_TXNNAME=unbundle
55 55 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
56 56 (run 'hg heads' to see heads, 'hg merge' to merge)
57 57
58 58 $ cd ..
59 59
60 60 Real world exchange
61 61 =====================
62 62
63 63 Add more obsolescence information
64 64
65 65 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
66 66 pre-close-tip:02de42196ebe draft
67 67 postclose-tip:02de42196ebe draft
68 68 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
69 69 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
70 70 pre-close-tip:02de42196ebe draft
71 71 postclose-tip:02de42196ebe draft
72 72 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
73 73
74 74 clone --pull
75 75
76 76 $ hg -R main phase --public cd010b8cd998
77 77 pre-close-tip:02de42196ebe draft
78 78 postclose-tip:02de42196ebe draft
79 79 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
80 80 $ hg clone main other --pull --rev 9520eea781bc
81 81 adding changesets
82 82 adding manifests
83 83 adding file changes
84 84 added 2 changesets with 2 changes to 2 files
85 85 1 new obsolescence markers
86 86 pre-close-tip:9520eea781bc draft
87 87 new changesets cd010b8cd998:9520eea781bc
88 88 postclose-tip:9520eea781bc draft
89 89 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
90 90 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
91 91 updating to branch default
92 92 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 93 $ hg -R other log -G
94 94 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
95 95 |
96 96 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
97 97
98 98 $ hg -R other debugobsolete
99 99 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
100 100
101 101 pull
102 102
103 103 $ hg -R main phase --public 9520eea781bc
104 104 pre-close-tip:02de42196ebe draft
105 105 postclose-tip:02de42196ebe draft
106 106 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
107 107 $ hg -R other pull -r 24b6387c8c8c
108 108 pulling from $TESTTMP/main (glob)
109 109 searching for changes
110 110 adding changesets
111 111 adding manifests
112 112 adding file changes
113 113 added 1 changesets with 1 changes to 1 files (+1 heads)
114 114 1 new obsolescence markers
115 115 pre-close-tip:24b6387c8c8c draft
116 116 new changesets 24b6387c8c8c
117 117 postclose-tip:24b6387c8c8c draft
118 118 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
119 119 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
120 120 (run 'hg heads' to see heads, 'hg merge' to merge)
121 121 $ hg -R other log -G
122 122 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
123 123 |
124 124 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
125 125 |/
126 126 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
127 127
128 128 $ hg -R other debugobsolete
129 129 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
130 130 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
131 131
132 132 pull empty (with phase movement)
133 133
134 134 $ hg -R main phase --public 24b6387c8c8c
135 135 pre-close-tip:02de42196ebe draft
136 136 postclose-tip:02de42196ebe draft
137 137 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
138 138 $ hg -R other pull -r 24b6387c8c8c
139 139 pulling from $TESTTMP/main (glob)
140 140 no changes found
141 141 pre-close-tip:24b6387c8c8c public
142 142 postclose-tip:24b6387c8c8c public
143 143 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
144 144 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
145 145 $ hg -R other log -G
146 146 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
147 147 |
148 148 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
149 149 |/
150 150 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
151 151
152 152 $ hg -R other debugobsolete
153 153 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
154 154 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
155 155
156 156 pull empty
157 157
158 158 $ hg -R other pull -r 24b6387c8c8c
159 159 pulling from $TESTTMP/main (glob)
160 160 no changes found
161 161 pre-close-tip:24b6387c8c8c public
162 162 postclose-tip:24b6387c8c8c public
163 163 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
164 164 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
165 165 $ hg -R other log -G
166 166 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
167 167 |
168 168 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
169 169 |/
170 170 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
171 171
172 172 $ hg -R other debugobsolete
173 173 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
174 174 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
175 175
176 176 add extra data to test their exchange during push
177 177
178 178 $ hg -R main bookmark --rev eea13746799a book_eea1
179 179 pre-close-tip:02de42196ebe draft
180 180 postclose-tip:02de42196ebe draft
181 181 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
182 182 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
183 183 pre-close-tip:02de42196ebe draft
184 184 postclose-tip:02de42196ebe draft
185 185 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
186 186 $ hg -R main bookmark --rev 02de42196ebe book_02de
187 187 pre-close-tip:02de42196ebe draft book_02de
188 188 postclose-tip:02de42196ebe draft book_02de
189 189 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
190 190 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
191 191 pre-close-tip:02de42196ebe draft book_02de
192 192 postclose-tip:02de42196ebe draft book_02de
193 193 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
194 194 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
195 195 pre-close-tip:02de42196ebe draft book_02de
196 196 postclose-tip:02de42196ebe draft book_02de
197 197 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
198 198 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
199 199 pre-close-tip:02de42196ebe draft book_02de
200 200 postclose-tip:02de42196ebe draft book_02de
201 201 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
202 202 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
203 203 pre-close-tip:02de42196ebe draft book_02de
204 204 postclose-tip:02de42196ebe draft book_02de
205 205 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
206 206 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
207 207 pre-close-tip:02de42196ebe draft book_02de
208 208 postclose-tip:02de42196ebe draft book_02de
209 209 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
210 210 $ hg -R main bookmark --rev 32af7686d403 book_32af
211 211 pre-close-tip:02de42196ebe draft book_02de
212 212 postclose-tip:02de42196ebe draft book_02de
213 213 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
214 214 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
215 215 pre-close-tip:02de42196ebe draft book_02de
216 216 postclose-tip:02de42196ebe draft book_02de
217 217 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
218 218
219 219 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
220 220 pre-close-tip:24b6387c8c8c public
221 221 postclose-tip:24b6387c8c8c public
222 222 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
223 223 $ hg -R other bookmark --rev cd010b8cd998 book_02de
224 224 pre-close-tip:24b6387c8c8c public
225 225 postclose-tip:24b6387c8c8c public
226 226 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
227 227 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
228 228 pre-close-tip:24b6387c8c8c public
229 229 postclose-tip:24b6387c8c8c public
230 230 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
231 231 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
232 232 pre-close-tip:24b6387c8c8c public
233 233 postclose-tip:24b6387c8c8c public
234 234 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
235 235 $ hg -R other bookmark --rev cd010b8cd998 book_32af
236 236 pre-close-tip:24b6387c8c8c public
237 237 postclose-tip:24b6387c8c8c public
238 238 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
239 239
240 240 $ hg -R main phase --public eea13746799a
241 241 pre-close-tip:02de42196ebe draft book_02de
242 242 postclose-tip:02de42196ebe draft book_02de
243 243 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
244 244
245 245 push
246 246 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
247 247 pushing to other
248 248 searching for changes
249 249 remote: adding changesets
250 250 remote: adding manifests
251 251 remote: adding file changes
252 252 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
253 253 remote: 1 new obsolescence markers
254 254 remote: pre-close-tip:eea13746799a public book_eea1
255 remote: pushkey: lock state after "phases"
256 remote: lock: free
257 remote: wlock: free
258 255 remote: pushkey: lock state after "bookmarks"
259 256 remote: lock: free
260 257 remote: wlock: free
261 258 remote: postclose-tip:eea13746799a public book_eea1
262 259 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/other
263 260 updating bookmark book_eea1
264 261 pre-close-tip:02de42196ebe draft book_02de
265 262 postclose-tip:02de42196ebe draft book_02de
266 263 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
267 264 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
268 265 $ hg -R other log -G
269 266 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
270 267 |\
271 268 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
272 269 | |
273 270 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
274 271 |/
275 272 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
276 273
277 274 $ hg -R other debugobsolete
278 275 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
279 276 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
280 277 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
281 278
282 279 pull over ssh
283 280
284 281 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
285 282 pulling from ssh://user@dummy/main
286 283 searching for changes
287 284 adding changesets
288 285 adding manifests
289 286 adding file changes
290 287 added 1 changesets with 1 changes to 1 files (+1 heads)
291 288 1 new obsolescence markers
292 289 updating bookmark book_02de
293 290 pre-close-tip:02de42196ebe draft book_02de
294 291 new changesets 02de42196ebe
295 292 postclose-tip:02de42196ebe draft book_02de
296 293 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
297 294 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
298 295 (run 'hg heads' to see heads, 'hg merge' to merge)
299 296 $ hg -R other debugobsolete
300 297 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
301 298 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
302 299 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
303 300 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
304 301
305 302 pull over http
306 303
307 304 $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log
308 305 $ cat main.pid >> $DAEMON_PIDS
309 306
310 307 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
311 308 pulling from http://localhost:$HGPORT/
312 309 searching for changes
313 310 adding changesets
314 311 adding manifests
315 312 adding file changes
316 313 added 1 changesets with 1 changes to 1 files (+1 heads)
317 314 1 new obsolescence markers
318 315 updating bookmark book_42cc
319 316 pre-close-tip:42ccdea3bb16 draft book_42cc
320 317 new changesets 42ccdea3bb16
321 318 postclose-tip:42ccdea3bb16 draft book_42cc
322 319 txnclose hook: HG_BOOKMARK_MOVED=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
323 320 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
324 321 (run 'hg heads .' to see heads, 'hg merge' to merge)
325 322 $ cat main-error.log
326 323 $ hg -R other debugobsolete
327 324 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
328 325 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
329 326 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
330 327 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
331 328 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
332 329
333 330 push over ssh
334 331
335 332 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
336 333 pushing to ssh://user@dummy/other
337 334 searching for changes
338 335 remote: adding changesets
339 336 remote: adding manifests
340 337 remote: adding file changes
341 338 remote: added 1 changesets with 1 changes to 1 files
342 339 remote: 1 new obsolescence markers
343 340 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
344 341 remote: pushkey: lock state after "bookmarks"
345 342 remote: lock: free
346 343 remote: wlock: free
347 344 remote: postclose-tip:5fddd98957c8 draft book_5fdd
348 345 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:ssh:$LOCALIP
349 346 updating bookmark book_5fdd
350 347 pre-close-tip:02de42196ebe draft book_02de
351 348 postclose-tip:02de42196ebe draft book_02de
352 349 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
353 350 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
354 351 $ hg -R other log -G
355 352 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
356 353 |
357 354 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
358 355 |
359 356 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
360 357 | |
361 358 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
362 359 | |/|
363 360 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
364 361 |/ /
365 362 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
366 363 |/
367 364 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
368 365
369 366 $ hg -R other debugobsolete
370 367 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
371 368 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
372 369 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
373 370 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
374 371 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
375 372 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
376 373
377 374 push over http
378 375
379 376 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
380 377 $ cat other.pid >> $DAEMON_PIDS
381 378
382 379 $ hg -R main phase --public 32af7686d403
383 380 pre-close-tip:02de42196ebe draft book_02de
384 381 postclose-tip:02de42196ebe draft book_02de
385 382 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
386 383 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
387 384 pushing to http://localhost:$HGPORT2/
388 385 searching for changes
389 386 remote: adding changesets
390 387 remote: adding manifests
391 388 remote: adding file changes
392 389 remote: added 1 changesets with 1 changes to 1 files
393 390 remote: 1 new obsolescence markers
394 391 remote: pre-close-tip:32af7686d403 public book_32af
395 remote: pushkey: lock state after "phases"
396 remote: lock: free
397 remote: wlock: free
398 392 remote: pushkey: lock state after "bookmarks"
399 393 remote: lock: free
400 394 remote: wlock: free
401 395 remote: postclose-tip:32af7686d403 public book_32af
402 396 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:http:$LOCALIP: (glob)
403 397 updating bookmark book_32af
404 398 pre-close-tip:02de42196ebe draft book_02de
405 399 postclose-tip:02de42196ebe draft book_02de
406 400 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
407 401 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
408 402 $ cat other-error.log
409 403
410 404 Check final content.
411 405
412 406 $ hg -R other log -G
413 407 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
414 408 |
415 409 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
416 410 |
417 411 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
418 412 |
419 413 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
420 414 | |
421 415 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
422 416 | |/|
423 417 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
424 418 |/ /
425 419 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
426 420 |/
427 421 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
428 422
429 423 $ hg -R other debugobsolete
430 424 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
431 425 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
432 426 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
433 427 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
434 428 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
435 429 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
436 430 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
437 431
438 432 (check that no 'pending' files remain)
439 433
440 434 $ ls -1 other/.hg/bookmarks*
441 435 other/.hg/bookmarks
442 436 $ ls -1 other/.hg/store/phaseroots*
443 437 other/.hg/store/phaseroots
444 438 $ ls -1 other/.hg/store/00changelog.i*
445 439 other/.hg/store/00changelog.i
446 440
447 441 Error Handling
448 442 ==============
449 443
450 444 Check that errors are properly returned to the client during push.
451 445
452 446 Setting up
453 447
454 448 $ cat > failpush.py << EOF
455 449 > """A small extension that makes push fails when using bundle2
456 450 >
457 451 > used to test error handling in bundle2
458 452 > """
459 453 >
460 454 > from mercurial import error
461 455 > from mercurial import bundle2
462 456 > from mercurial import exchange
463 457 > from mercurial import extensions
464 458 > from mercurial import registrar
465 459 > cmdtable = {}
466 460 > command = registrar.command(cmdtable)
467 461 >
468 462 > configtable = {}
469 463 > configitem = registrar.configitem(configtable)
470 464 > configitem('failpush', 'reason',
471 465 > default=None,
472 466 > )
473 467 >
474 468 > def _pushbundle2failpart(pushop, bundler):
475 469 > reason = pushop.ui.config('failpush', 'reason')
476 470 > part = None
477 471 > if reason == 'abort':
478 472 > bundler.newpart('test:abort')
479 473 > if reason == 'unknown':
480 474 > bundler.newpart('test:unknown')
481 475 > if reason == 'race':
482 476 > # 20 Bytes of crap
483 477 > bundler.newpart('check:heads', data='01234567890123456789')
484 478 >
485 479 > @bundle2.parthandler("test:abort")
486 480 > def handleabort(op, part):
487 481 > raise error.Abort('Abandon ship!', hint="don't panic")
488 482 >
489 483 > def uisetup(ui):
490 484 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
491 485 > exchange.b2partsgenorder.insert(0, 'failpart')
492 486 >
493 487 > EOF
494 488
495 489 $ cd main
496 490 $ hg up tip
497 491 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
498 492 $ echo 'I' > I
499 493 $ hg add I
500 494 $ hg ci -m 'I'
501 495 pre-close-tip:e7ec4e813ba6 draft
502 496 postclose-tip:e7ec4e813ba6 draft
503 497 txnclose hook: HG_HOOKNAME=txnclose.env HG_HOOKTYPE=txnclose HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
504 498 $ hg id
505 499 e7ec4e813ba6 tip
506 500 $ cd ..
507 501
508 502 $ cat << EOF >> $HGRCPATH
509 503 > [extensions]
510 504 > failpush=$TESTTMP/failpush.py
511 505 > EOF
512 506
513 507 $ killdaemons.py
514 508 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
515 509 $ cat other.pid >> $DAEMON_PIDS
516 510
517 511 Doing the actual push: Abort error
518 512
519 513 $ cat << EOF >> $HGRCPATH
520 514 > [failpush]
521 515 > reason = abort
522 516 > EOF
523 517
524 518 $ hg -R main push other -r e7ec4e813ba6
525 519 pushing to other
526 520 searching for changes
527 521 abort: Abandon ship!
528 522 (don't panic)
529 523 [255]
530 524
531 525 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
532 526 pushing to ssh://user@dummy/other
533 527 searching for changes
534 528 remote: Abandon ship!
535 529 remote: (don't panic)
536 530 abort: push failed on remote
537 531 [255]
538 532
539 533 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
540 534 pushing to http://localhost:$HGPORT2/
541 535 searching for changes
542 536 remote: Abandon ship!
543 537 remote: (don't panic)
544 538 abort: push failed on remote
545 539 [255]
546 540
547 541
548 542 Doing the actual push: unknown mandatory parts
549 543
550 544 $ cat << EOF >> $HGRCPATH
551 545 > [failpush]
552 546 > reason = unknown
553 547 > EOF
554 548
555 549 $ hg -R main push other -r e7ec4e813ba6
556 550 pushing to other
557 551 searching for changes
558 552 abort: missing support for test:unknown
559 553 [255]
560 554
561 555 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
562 556 pushing to ssh://user@dummy/other
563 557 searching for changes
564 558 abort: missing support for test:unknown
565 559 [255]
566 560
567 561 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
568 562 pushing to http://localhost:$HGPORT2/
569 563 searching for changes
570 564 abort: missing support for test:unknown
571 565 [255]
572 566
573 567 Doing the actual push: race
574 568
575 569 $ cat << EOF >> $HGRCPATH
576 570 > [failpush]
577 571 > reason = race
578 572 > EOF
579 573
580 574 $ hg -R main push other -r e7ec4e813ba6
581 575 pushing to other
582 576 searching for changes
583 577 abort: push failed:
584 578 'repository changed while pushing - please try again'
585 579 [255]
586 580
587 581 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
588 582 pushing to ssh://user@dummy/other
589 583 searching for changes
590 584 abort: push failed:
591 585 'repository changed while pushing - please try again'
592 586 [255]
593 587
594 588 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
595 589 pushing to http://localhost:$HGPORT2/
596 590 searching for changes
597 591 abort: push failed:
598 592 'repository changed while pushing - please try again'
599 593 [255]
600 594
601 595 Doing the actual push: hook abort
602 596
603 597 $ cat << EOF >> $HGRCPATH
604 598 > [failpush]
605 599 > reason =
606 600 > [hooks]
607 601 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
608 602 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
609 603 > EOF
610 604
611 605 $ killdaemons.py
612 606 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
613 607 $ cat other.pid >> $DAEMON_PIDS
614 608
615 609 $ hg -R main push other -r e7ec4e813ba6
616 610 pushing to other
617 611 searching for changes
618 612 remote: adding changesets
619 613 remote: adding manifests
620 614 remote: adding file changes
621 615 remote: added 1 changesets with 1 changes to 1 files
622 616 remote: pre-close-tip:e7ec4e813ba6 draft
623 617 remote: You shall not pass!
624 618 remote: transaction abort!
625 619 remote: Cleaning up the mess...
626 620 remote: rollback completed
627 621 abort: pretxnclose.failpush hook exited with status 1
628 622 [255]
629 623
630 624 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
631 625 pushing to ssh://user@dummy/other
632 626 searching for changes
633 627 remote: adding changesets
634 628 remote: adding manifests
635 629 remote: adding file changes
636 630 remote: added 1 changesets with 1 changes to 1 files
637 631 remote: pre-close-tip:e7ec4e813ba6 draft
638 632 remote: You shall not pass!
639 633 remote: transaction abort!
640 634 remote: Cleaning up the mess...
641 635 remote: rollback completed
642 636 remote: pretxnclose.failpush hook exited with status 1
643 637 abort: push failed on remote
644 638 [255]
645 639
646 640 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
647 641 pushing to http://localhost:$HGPORT2/
648 642 searching for changes
649 643 remote: adding changesets
650 644 remote: adding manifests
651 645 remote: adding file changes
652 646 remote: added 1 changesets with 1 changes to 1 files
653 647 remote: pre-close-tip:e7ec4e813ba6 draft
654 648 remote: You shall not pass!
655 649 remote: transaction abort!
656 650 remote: Cleaning up the mess...
657 651 remote: rollback completed
658 652 remote: pretxnclose.failpush hook exited with status 1
659 653 abort: push failed on remote
660 654 [255]
661 655
662 656 (check that no 'pending' files remain)
663 657
664 658 $ ls -1 other/.hg/bookmarks*
665 659 other/.hg/bookmarks
666 660 $ ls -1 other/.hg/store/phaseroots*
667 661 other/.hg/store/phaseroots
668 662 $ ls -1 other/.hg/store/00changelog.i*
669 663 other/.hg/store/00changelog.i
670 664
671 665 Check error from hook during the unbundling process itself
672 666
673 667 $ cat << EOF >> $HGRCPATH
674 668 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
675 669 > EOF
676 670 $ killdaemons.py # reload http config
677 671 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
678 672 $ cat other.pid >> $DAEMON_PIDS
679 673
680 674 $ hg -R main push other -r e7ec4e813ba6
681 675 pushing to other
682 676 searching for changes
683 677 remote: adding changesets
684 678 remote: adding manifests
685 679 remote: adding file changes
686 680 remote: added 1 changesets with 1 changes to 1 files
687 681 remote: Fail early!
688 682 remote: transaction abort!
689 683 remote: Cleaning up the mess...
690 684 remote: rollback completed
691 685 abort: pretxnchangegroup hook exited with status 1
692 686 [255]
693 687 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
694 688 pushing to ssh://user@dummy/other
695 689 searching for changes
696 690 remote: adding changesets
697 691 remote: adding manifests
698 692 remote: adding file changes
699 693 remote: added 1 changesets with 1 changes to 1 files
700 694 remote: Fail early!
701 695 remote: transaction abort!
702 696 remote: Cleaning up the mess...
703 697 remote: rollback completed
704 698 remote: pretxnchangegroup hook exited with status 1
705 699 abort: push failed on remote
706 700 [255]
707 701 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
708 702 pushing to http://localhost:$HGPORT2/
709 703 searching for changes
710 704 remote: adding changesets
711 705 remote: adding manifests
712 706 remote: adding file changes
713 707 remote: added 1 changesets with 1 changes to 1 files
714 708 remote: Fail early!
715 709 remote: transaction abort!
716 710 remote: Cleaning up the mess...
717 711 remote: rollback completed
718 712 remote: pretxnchangegroup hook exited with status 1
719 713 abort: push failed on remote
720 714 [255]
721 715
722 716 Check output capture control.
723 717
724 718 (should be still forced for http, disabled for local and ssh)
725 719
726 720 $ cat >> $HGRCPATH << EOF
727 721 > [experimental]
728 722 > bundle2-output-capture=False
729 723 > EOF
730 724
731 725 $ hg -R main push other -r e7ec4e813ba6
732 726 pushing to other
733 727 searching for changes
734 728 adding changesets
735 729 adding manifests
736 730 adding file changes
737 731 added 1 changesets with 1 changes to 1 files
738 732 Fail early!
739 733 transaction abort!
740 734 Cleaning up the mess...
741 735 rollback completed
742 736 abort: pretxnchangegroup hook exited with status 1
743 737 [255]
744 738 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
745 739 pushing to ssh://user@dummy/other
746 740 searching for changes
747 741 remote: adding changesets
748 742 remote: adding manifests
749 743 remote: adding file changes
750 744 remote: added 1 changesets with 1 changes to 1 files
751 745 remote: Fail early!
752 746 remote: transaction abort!
753 747 remote: Cleaning up the mess...
754 748 remote: rollback completed
755 749 remote: pretxnchangegroup hook exited with status 1
756 750 abort: push failed on remote
757 751 [255]
758 752 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
759 753 pushing to http://localhost:$HGPORT2/
760 754 searching for changes
761 755 remote: adding changesets
762 756 remote: adding manifests
763 757 remote: adding file changes
764 758 remote: added 1 changesets with 1 changes to 1 files
765 759 remote: Fail early!
766 760 remote: transaction abort!
767 761 remote: Cleaning up the mess...
768 762 remote: rollback completed
769 763 remote: pretxnchangegroup hook exited with status 1
770 764 abort: push failed on remote
771 765 [255]
772 766
773 767 Check abort from mandatory pushkey
774 768
775 769 $ cat > mandatorypart.py << EOF
776 770 > from mercurial import exchange
777 771 > from mercurial import pushkey
778 772 > from mercurial import node
779 773 > from mercurial import error
780 774 > @exchange.b2partsgenerator('failingpuskey')
781 775 > def addfailingpushey(pushop, bundler):
782 776 > enc = pushkey.encode
783 777 > part = bundler.newpart('pushkey')
784 778 > part.addparam('namespace', enc('phases'))
785 779 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
786 780 > part.addparam('old', enc(str(0))) # successful update
787 781 > part.addparam('new', enc(str(0)))
788 782 > def fail(pushop, exc):
789 783 > raise error.Abort('Correct phase push failed (because hooks)')
790 784 > pushop.pkfailcb[part.id] = fail
791 785 > EOF
792 786 $ cat >> $HGRCPATH << EOF
793 787 > [hooks]
794 788 > pretxnchangegroup=
795 789 > pretxnclose.failpush=
796 790 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
797 791 > [extensions]
798 792 > mandatorypart=$TESTTMP/mandatorypart.py
799 793 > EOF
800 794 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
801 795 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
802 796 $ cat other.pid >> $DAEMON_PIDS
803 797
804 798 (Failure from a hook)
805 799
806 800 $ hg -R main push other -r e7ec4e813ba6
807 801 pushing to other
808 802 searching for changes
809 803 adding changesets
810 804 adding manifests
811 805 adding file changes
812 806 added 1 changesets with 1 changes to 1 files
813 807 do not push the key !
814 808 pushkey-abort: prepushkey.failpush hook exited with status 1
815 809 transaction abort!
816 810 Cleaning up the mess...
817 811 rollback completed
818 812 abort: Correct phase push failed (because hooks)
819 813 [255]
820 814 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
821 815 pushing to ssh://user@dummy/other
822 816 searching for changes
823 817 remote: adding changesets
824 818 remote: adding manifests
825 819 remote: adding file changes
826 820 remote: added 1 changesets with 1 changes to 1 files
827 821 remote: do not push the key !
828 822 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
829 823 remote: transaction abort!
830 824 remote: Cleaning up the mess...
831 825 remote: rollback completed
832 826 abort: Correct phase push failed (because hooks)
833 827 [255]
834 828 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
835 829 pushing to http://localhost:$HGPORT2/
836 830 searching for changes
837 831 remote: adding changesets
838 832 remote: adding manifests
839 833 remote: adding file changes
840 834 remote: added 1 changesets with 1 changes to 1 files
841 835 remote: do not push the key !
842 836 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
843 837 remote: transaction abort!
844 838 remote: Cleaning up the mess...
845 839 remote: rollback completed
846 840 abort: Correct phase push failed (because hooks)
847 841 [255]
848 842
849 843 (Failure from a the pushkey)
850 844
851 845 $ cat > mandatorypart.py << EOF
852 846 > from mercurial import exchange
853 847 > from mercurial import pushkey
854 848 > from mercurial import node
855 849 > from mercurial import error
856 850 > @exchange.b2partsgenerator('failingpuskey')
857 851 > def addfailingpushey(pushop, bundler):
858 852 > enc = pushkey.encode
859 853 > part = bundler.newpart('pushkey')
860 854 > part.addparam('namespace', enc('phases'))
861 855 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
862 856 > part.addparam('old', enc(str(4))) # will fail
863 857 > part.addparam('new', enc(str(3)))
864 858 > def fail(pushop, exc):
865 859 > raise error.Abort('Clown phase push failed')
866 860 > pushop.pkfailcb[part.id] = fail
867 861 > EOF
868 862 $ cat >> $HGRCPATH << EOF
869 863 > [hooks]
870 864 > prepushkey.failpush =
871 865 > EOF
872 866 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
873 867 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
874 868 $ cat other.pid >> $DAEMON_PIDS
875 869
876 870 $ hg -R main push other -r e7ec4e813ba6
877 871 pushing to other
878 872 searching for changes
879 873 adding changesets
880 874 adding manifests
881 875 adding file changes
882 876 added 1 changesets with 1 changes to 1 files
883 877 transaction abort!
884 878 Cleaning up the mess...
885 879 rollback completed
886 880 pushkey: lock state after "phases"
887 881 lock: free
888 882 wlock: free
889 883 abort: Clown phase push failed
890 884 [255]
891 885 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
892 886 pushing to ssh://user@dummy/other
893 887 searching for changes
894 888 remote: adding changesets
895 889 remote: adding manifests
896 890 remote: adding file changes
897 891 remote: added 1 changesets with 1 changes to 1 files
898 892 remote: transaction abort!
899 893 remote: Cleaning up the mess...
900 894 remote: rollback completed
901 895 remote: pushkey: lock state after "phases"
902 896 remote: lock: free
903 897 remote: wlock: free
904 898 abort: Clown phase push failed
905 899 [255]
906 900 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
907 901 pushing to http://localhost:$HGPORT2/
908 902 searching for changes
909 903 remote: adding changesets
910 904 remote: adding manifests
911 905 remote: adding file changes
912 906 remote: added 1 changesets with 1 changes to 1 files
913 907 remote: transaction abort!
914 908 remote: Cleaning up the mess...
915 909 remote: rollback completed
916 910 remote: pushkey: lock state after "phases"
917 911 remote: lock: free
918 912 remote: wlock: free
919 913 abort: Clown phase push failed
920 914 [255]
921 915
922 916 Test lazily acquiring the lock during unbundle
923 917 $ cp $TESTTMP/hgrc.orig $HGRCPATH
924 918 $ cat >> $HGRCPATH <<EOF
925 919 > [ui]
926 920 > ssh="$PYTHON" "$TESTDIR/dummyssh"
927 921 > EOF
928 922
929 923 $ cat >> $TESTTMP/locktester.py <<EOF
930 924 > import os
931 925 > from mercurial import extensions, bundle2, util
932 926 > def checklock(orig, repo, *args, **kwargs):
933 927 > if repo.svfs.lexists("lock"):
934 928 > raise util.Abort("Lock should not be taken")
935 929 > return orig(repo, *args, **kwargs)
936 930 > def extsetup(ui):
937 931 > extensions.wrapfunction(bundle2, 'processbundle', checklock)
938 932 > EOF
939 933
940 934 $ hg init lazylock
941 935 $ cat >> lazylock/.hg/hgrc <<EOF
942 936 > [extensions]
943 937 > locktester=$TESTTMP/locktester.py
944 938 > EOF
945 939
946 940 $ hg clone -q ssh://user@dummy/lazylock lazylockclient
947 941 $ cd lazylockclient
948 942 $ touch a && hg ci -Aqm a
949 943 $ hg push
950 944 pushing to ssh://user@dummy/lazylock
951 945 searching for changes
952 946 remote: Lock should not be taken
953 947 abort: push failed on remote
954 948 [255]
955 949
956 950 $ cat >> ../lazylock/.hg/hgrc <<EOF
957 951 > [experimental]
958 952 > bundle2lazylocking=True
959 953 > EOF
960 954 $ hg push
961 955 pushing to ssh://user@dummy/lazylock
962 956 searching for changes
963 957 remote: adding changesets
964 958 remote: adding manifests
965 959 remote: adding file changes
966 960 remote: added 1 changesets with 1 changes to 1 files
967 961
968 962 $ cd ..
969 963
970 964 Servers can disable bundle1 for clone/pull operations
971 965
972 966 $ killdaemons.py
973 967 $ hg init bundle2onlyserver
974 968 $ cd bundle2onlyserver
975 969 $ cat > .hg/hgrc << EOF
976 970 > [server]
977 971 > bundle1.pull = false
978 972 > EOF
979 973
980 974 $ touch foo
981 975 $ hg -q commit -A -m initial
982 976
983 977 $ hg serve -p $HGPORT -d --pid-file=hg.pid
984 978 $ cat hg.pid >> $DAEMON_PIDS
985 979
986 980 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
987 981 requesting all changes
988 982 abort: remote error:
989 983 incompatible Mercurial client; bundle2 required
990 984 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
991 985 [255]
992 986 $ killdaemons.py
993 987 $ cd ..
994 988
995 989 bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled
996 990
997 991 $ hg --config format.usegeneraldelta=false init notgdserver
998 992 $ cd notgdserver
999 993 $ cat > .hg/hgrc << EOF
1000 994 > [server]
1001 995 > bundle1gd.pull = false
1002 996 > EOF
1003 997
1004 998 $ touch foo
1005 999 $ hg -q commit -A -m initial
1006 1000 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1007 1001 $ cat hg.pid >> $DAEMON_PIDS
1008 1002
1009 1003 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1
1010 1004 requesting all changes
1011 1005 adding changesets
1012 1006 adding manifests
1013 1007 adding file changes
1014 1008 added 1 changesets with 1 changes to 1 files
1015 1009 new changesets 96ee1d7354c4
1016 1010 updating to branch default
1017 1011 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1018 1012
1019 1013 $ killdaemons.py
1020 1014 $ cd ../bundle2onlyserver
1021 1015
1022 1016 bundle1 pull can be disabled for generaldelta repos only
1023 1017
1024 1018 $ cat > .hg/hgrc << EOF
1025 1019 > [server]
1026 1020 > bundle1gd.pull = false
1027 1021 > EOF
1028 1022
1029 1023 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1030 1024 $ cat hg.pid >> $DAEMON_PIDS
1031 1025 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1032 1026 requesting all changes
1033 1027 abort: remote error:
1034 1028 incompatible Mercurial client; bundle2 required
1035 1029 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1036 1030 [255]
1037 1031
1038 1032 $ killdaemons.py
1039 1033
1040 1034 Verify the global server.bundle1 option works
1041 1035
1042 1036 $ cd ..
1043 1037 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1044 1038 > [server]
1045 1039 > bundle1 = false
1046 1040 > EOF
1047 1041 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1048 1042 $ cat hg.pid >> $DAEMON_PIDS
1049 1043 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2
1050 1044 requesting all changes
1051 1045 abort: remote error:
1052 1046 incompatible Mercurial client; bundle2 required
1053 1047 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1054 1048 [255]
1055 1049 $ killdaemons.py
1056 1050
1057 1051 $ hg --config devel.legacy.exchange=bundle1 clone ssh://user@dummy/bundle2onlyserver not-bundle2-ssh
1058 1052 requesting all changes
1059 1053 adding changesets
1060 1054 remote: abort: incompatible Mercurial client; bundle2 required
1061 1055 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1062 1056 transaction abort!
1063 1057 rollback completed
1064 1058 abort: stream ended unexpectedly (got 0 bytes, expected 4)
1065 1059 [255]
1066 1060
1067 1061 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1068 1062 > [server]
1069 1063 > bundle1gd = false
1070 1064 > EOF
1071 1065 $ hg serve -R bundle2onlyserver -p $HGPORT -d --pid-file=hg.pid
1072 1066 $ cat hg.pid >> $DAEMON_PIDS
1073 1067
1074 1068 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1075 1069 requesting all changes
1076 1070 abort: remote error:
1077 1071 incompatible Mercurial client; bundle2 required
1078 1072 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1079 1073 [255]
1080 1074
1081 1075 $ killdaemons.py
1082 1076
1083 1077 $ cd notgdserver
1084 1078 $ cat > .hg/hgrc << EOF
1085 1079 > [server]
1086 1080 > bundle1gd = false
1087 1081 > EOF
1088 1082 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1089 1083 $ cat hg.pid >> $DAEMON_PIDS
1090 1084
1091 1085 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2
1092 1086 requesting all changes
1093 1087 adding changesets
1094 1088 adding manifests
1095 1089 adding file changes
1096 1090 added 1 changesets with 1 changes to 1 files
1097 1091 new changesets 96ee1d7354c4
1098 1092 updating to branch default
1099 1093 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1100 1094
1101 1095 $ killdaemons.py
1102 1096 $ cd ../bundle2onlyserver
1103 1097
1104 1098 Verify bundle1 pushes can be disabled
1105 1099
1106 1100 $ cat > .hg/hgrc << EOF
1107 1101 > [server]
1108 1102 > bundle1.push = false
1109 1103 > [web]
1110 1104 > allow_push = *
1111 1105 > push_ssl = false
1112 1106 > EOF
1113 1107
1114 1108 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log
1115 1109 $ cat hg.pid >> $DAEMON_PIDS
1116 1110 $ cd ..
1117 1111
1118 1112 $ hg clone http://localhost:$HGPORT bundle2-only
1119 1113 requesting all changes
1120 1114 adding changesets
1121 1115 adding manifests
1122 1116 adding file changes
1123 1117 added 1 changesets with 1 changes to 1 files
1124 1118 new changesets 96ee1d7354c4
1125 1119 updating to branch default
1126 1120 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1127 1121 $ cd bundle2-only
1128 1122 $ echo commit > foo
1129 1123 $ hg commit -m commit
1130 1124 $ hg --config devel.legacy.exchange=bundle1 push
1131 1125 pushing to http://localhost:$HGPORT/
1132 1126 searching for changes
1133 1127 abort: remote error:
1134 1128 incompatible Mercurial client; bundle2 required
1135 1129 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1136 1130 [255]
1137 1131
1138 1132 (also check with ssh)
1139 1133
1140 1134 $ hg --config devel.legacy.exchange=bundle1 push ssh://user@dummy/bundle2onlyserver
1141 1135 pushing to ssh://user@dummy/bundle2onlyserver
1142 1136 searching for changes
1143 1137 remote: abort: incompatible Mercurial client; bundle2 required
1144 1138 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1145 1139 [1]
1146 1140
1147 1141 $ hg push
1148 1142 pushing to http://localhost:$HGPORT/
1149 1143 searching for changes
1150 1144 remote: adding changesets
1151 1145 remote: adding manifests
1152 1146 remote: adding file changes
1153 1147 remote: added 1 changesets with 1 changes to 1 files
@@ -1,198 +1,198
1 1 #require killdaemons
2 2
3 3 $ hg init test
4 4 $ cd test
5 5 $ echo a > a
6 6 $ hg ci -Ama
7 7 adding a
8 8 $ cd ..
9 9 $ hg clone test test2
10 10 updating to branch default
11 11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 12 $ cd test2
13 13 $ echo a >> a
14 14 $ hg ci -mb
15 15 $ req() {
16 16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
17 17 > cat hg.pid >> $DAEMON_PIDS
18 18 > hg --cwd ../test2 push http://localhost:$HGPORT/
19 19 > exitstatus=$?
20 20 > killdaemons.py
21 21 > echo % serve errors
22 22 > cat errors.log
23 23 > return $exitstatus
24 24 > }
25 25 $ cd ../test
26 26
27 27 expect ssl error
28 28
29 29 $ req
30 30 pushing to http://localhost:$HGPORT/
31 31 searching for changes
32 32 abort: HTTP Error 403: ssl required
33 33 % serve errors
34 34 [255]
35 35
36 36 expect authorization error
37 37
38 38 $ echo '[web]' > .hg/hgrc
39 39 $ echo 'push_ssl = false' >> .hg/hgrc
40 40 $ req
41 41 pushing to http://localhost:$HGPORT/
42 42 searching for changes
43 43 abort: authorization failed
44 44 % serve errors
45 45 [255]
46 46
47 47 expect authorization error: must have authorized user
48 48
49 49 $ echo 'allow_push = unperson' >> .hg/hgrc
50 50 $ req
51 51 pushing to http://localhost:$HGPORT/
52 52 searching for changes
53 53 abort: authorization failed
54 54 % serve errors
55 55 [255]
56 56
57 57 expect success
58 58
59 59 $ cat >> .hg/hgrc <<EOF
60 60 > allow_push = *
61 61 > [hooks]
62 62 > changegroup = sh -c "printenv.py changegroup 0"
63 63 > pushkey = sh -c "printenv.py pushkey 0"
64 64 > txnclose-phase.test = echo "phase-move: \$HG_NODE: \$HG_OLDPHASE -> \$HG_PHASE"
65 65 > EOF
66 66 $ req
67 67 pushing to http://localhost:$HGPORT/
68 68 searching for changes
69 69 remote: adding changesets
70 70 remote: adding manifests
71 71 remote: adding file changes
72 72 remote: added 1 changesets with 1 changes to 1 files
73 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
74 73 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
75 74 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
76 75 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
77 76 % serve errors
78 77 $ hg rollback
79 78 repository tip rolled back to revision 0 (undo serve)
80 79
81 80 expect success, server lacks the httpheader capability
82 81
83 82 $ CAP=httpheader
84 83 $ . "$TESTDIR/notcapable"
85 84 $ req
86 85 pushing to http://localhost:$HGPORT/
87 86 searching for changes
88 87 remote: adding changesets
89 88 remote: adding manifests
90 89 remote: adding file changes
91 90 remote: added 1 changesets with 1 changes to 1 files
92 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
93 91 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
94 92 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
95 93 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
96 94 % serve errors
97 95 $ hg rollback
98 96 repository tip rolled back to revision 0 (undo serve)
99 97
100 98 expect success, server lacks the unbundlehash capability
101 99
102 100 $ CAP=unbundlehash
103 101 $ . "$TESTDIR/notcapable"
104 102 $ req
105 103 pushing to http://localhost:$HGPORT/
106 104 searching for changes
107 105 remote: adding changesets
108 106 remote: adding manifests
109 107 remote: adding file changes
110 108 remote: added 1 changesets with 1 changes to 1 files
111 remote: pushkey hook: HG_HOOKNAME=pushkey HG_HOOKTYPE=pushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
112 109 remote: phase-move: cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b: 1 -> 0
113 110 remote: phase-move: ba677d0156c1196c1a699fa53f390dcfc3ce3872: -> 0
114 111 remote: changegroup hook: HG_BUNDLE2=1 HG_HOOKNAME=changegroup HG_HOOKTYPE=changegroup HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
115 112 % serve errors
116 113 $ hg rollback
117 114 repository tip rolled back to revision 0 (undo serve)
118 115
119 116 expect push success, phase change failure
120 117
121 118 $ cat > .hg/hgrc <<EOF
122 119 > [web]
123 120 > push_ssl = false
124 121 > allow_push = *
125 122 > [hooks]
126 123 > prepushkey = sh -c "printenv.py prepushkey 1"
124 > [devel]
125 > legacy.exchange=phases
127 126 > EOF
128 127 $ req
129 128 pushing to http://localhost:$HGPORT/
130 129 searching for changes
131 130 remote: adding changesets
132 131 remote: adding manifests
133 132 remote: adding file changes
134 133 remote: added 1 changesets with 1 changes to 1 files
135 134 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
136 135 remote: pushkey-abort: prepushkey hook exited with status 1
137 136 remote: transaction abort!
138 137 remote: rollback completed
139 138 abort: updating ba677d0156c1 to public failed
140 139 % serve errors
141 140 [255]
142 141
143 142 expect phase change success
144 143
145 144 $ cat >> .hg/hgrc <<EOF
146 145 > prepushkey = sh -c "printenv.py prepushkey 0"
146 > [devel]
147 > legacy.exchange=
147 148 > EOF
148 149 $ req
149 150 pushing to http://localhost:$HGPORT/
150 151 searching for changes
151 152 remote: adding changesets
152 153 remote: adding manifests
153 154 remote: adding file changes
154 155 remote: added 1 changesets with 1 changes to 1 files
155 remote: prepushkey hook: HG_BUNDLE2=1 HG_HOOKNAME=prepushkey HG_HOOKTYPE=prepushkey HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP: (glob)
156 156 % serve errors
157 157 $ hg rollback
158 158 repository tip rolled back to revision 0 (undo serve)
159 159
160 160 expect authorization error: all users denied
161 161
162 162 $ echo '[web]' > .hg/hgrc
163 163 $ echo 'push_ssl = false' >> .hg/hgrc
164 164 $ echo 'deny_push = *' >> .hg/hgrc
165 165 $ req
166 166 pushing to http://localhost:$HGPORT/
167 167 searching for changes
168 168 abort: authorization failed
169 169 % serve errors
170 170 [255]
171 171
172 172 expect authorization error: some users denied, users must be authenticated
173 173
174 174 $ echo 'deny_push = unperson' >> .hg/hgrc
175 175 $ req
176 176 pushing to http://localhost:$HGPORT/
177 177 searching for changes
178 178 abort: authorization failed
179 179 % serve errors
180 180 [255]
181 181
182 182 $ cat > .hg/hgrc <<EOF
183 183 > [web]
184 184 > push_ssl = false
185 185 > allow_push = *
186 186 > [experimental]
187 187 > httppostargs=true
188 188 > EOF
189 189 $ req
190 190 pushing to http://localhost:$HGPORT/
191 191 searching for changes
192 192 remote: adding changesets
193 193 remote: adding manifests
194 194 remote: adding file changes
195 195 remote: added 1 changesets with 1 changes to 1 files
196 196 % serve errors
197 197
198 198 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now