##// END OF EJS Templates
phases: abort the whole push if phases fail to update (BC)...
Pierre-Yves David -
r25502:bd41c193 default
parent child Browse files
Show More
@@ -1,1565 +1,1574 b''
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 import time
9 9 from i18n import _
10 10 from node import hex, nullid
11 11 import errno, urllib
12 12 import util, scmutil, changegroup, base85, error, store
13 13 import discovery, phases, obsolete, bookmarks as bookmod, bundle2, pushkey
14 14 import lock as lockmod
15 15 import tags
16 16
17 17 def readbundle(ui, fh, fname, vfs=None):
18 18 header = changegroup.readexactly(fh, 4)
19 19
20 20 alg = None
21 21 if not fname:
22 22 fname = "stream"
23 23 if not header.startswith('HG') and header.startswith('\0'):
24 24 fh = changegroup.headerlessfixup(fh, header)
25 25 header = "HG10"
26 26 alg = 'UN'
27 27 elif vfs:
28 28 fname = vfs.join(fname)
29 29
30 30 magic, version = header[0:2], header[2:4]
31 31
32 32 if magic != 'HG':
33 33 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
34 34 if version == '10':
35 35 if alg is None:
36 36 alg = changegroup.readexactly(fh, 2)
37 37 return changegroup.cg1unpacker(fh, alg)
38 38 elif version.startswith('2'):
39 39 return bundle2.getunbundler(ui, fh, header=magic + version)
40 40 else:
41 41 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
42 42
43 43 def buildobsmarkerspart(bundler, markers):
44 44 """add an obsmarker part to the bundler with <markers>
45 45
46 46 No part is created if markers is empty.
47 47 Raises ValueError if the bundler doesn't support any known obsmarker format.
48 48 """
49 49 if markers:
50 50 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
51 51 version = obsolete.commonversion(remoteversions)
52 52 if version is None:
53 53 raise ValueError('bundler do not support common obsmarker format')
54 54 stream = obsolete.encodemarkers(markers, True, version=version)
55 55 return bundler.newpart('obsmarkers', data=stream)
56 56 return None
57 57
58 58 def _canusebundle2(op):
59 59 """return true if a pull/push can use bundle2
60 60
61 61 Feel free to nuke this function when we drop the experimental option"""
62 62 return (op.repo.ui.configbool('experimental', 'bundle2-exp', True)
63 63 and op.remote.capable('bundle2'))
64 64
65 65
66 66 class pushoperation(object):
67 67 """A object that represent a single push operation
68 68
69 69 It purpose is to carry push related state and very common operation.
70 70
71 71 A new should be created at the beginning of each push and discarded
72 72 afterward.
73 73 """
74 74
75 75 def __init__(self, repo, remote, force=False, revs=None, newbranch=False,
76 76 bookmarks=()):
77 77 # repo we push from
78 78 self.repo = repo
79 79 self.ui = repo.ui
80 80 # repo we push to
81 81 self.remote = remote
82 82 # force option provided
83 83 self.force = force
84 84 # revs to be pushed (None is "all")
85 85 self.revs = revs
86 86 # bookmark explicitly pushed
87 87 self.bookmarks = bookmarks
88 88 # allow push of new branch
89 89 self.newbranch = newbranch
90 90 # did a local lock get acquired?
91 91 self.locallocked = None
92 92 # step already performed
93 93 # (used to check what steps have been already performed through bundle2)
94 94 self.stepsdone = set()
95 95 # Integer version of the changegroup push result
96 96 # - None means nothing to push
97 97 # - 0 means HTTP error
98 98 # - 1 means we pushed and remote head count is unchanged *or*
99 99 # we have outgoing changesets but refused to push
100 100 # - other values as described by addchangegroup()
101 101 self.cgresult = None
102 102 # Boolean value for the bookmark push
103 103 self.bkresult = None
104 104 # discover.outgoing object (contains common and outgoing data)
105 105 self.outgoing = None
106 106 # all remote heads before the push
107 107 self.remoteheads = None
108 108 # testable as a boolean indicating if any nodes are missing locally.
109 109 self.incoming = None
110 110 # phases changes that must be pushed along side the changesets
111 111 self.outdatedphases = None
112 112 # phases changes that must be pushed if changeset push fails
113 113 self.fallbackoutdatedphases = None
114 114 # outgoing obsmarkers
115 115 self.outobsmarkers = set()
116 116 # outgoing bookmarks
117 117 self.outbookmarks = []
118 118 # transaction manager
119 119 self.trmanager = None
120 120 # map { pushkey partid -> callback handling failure}
121 121 # used to handle exception from mandatory pushkey part failure
122 122 self.pkfailcb = {}
123 123
124 124 @util.propertycache
125 125 def futureheads(self):
126 126 """future remote heads if the changeset push succeeds"""
127 127 return self.outgoing.missingheads
128 128
129 129 @util.propertycache
130 130 def fallbackheads(self):
131 131 """future remote heads if the changeset push fails"""
132 132 if self.revs is None:
133 133 # not target to push, all common are relevant
134 134 return self.outgoing.commonheads
135 135 unfi = self.repo.unfiltered()
136 136 # I want cheads = heads(::missingheads and ::commonheads)
137 137 # (missingheads is revs with secret changeset filtered out)
138 138 #
139 139 # This can be expressed as:
140 140 # cheads = ( (missingheads and ::commonheads)
141 141 # + (commonheads and ::missingheads))"
142 142 # )
143 143 #
144 144 # while trying to push we already computed the following:
145 145 # common = (::commonheads)
146 146 # missing = ((commonheads::missingheads) - commonheads)
147 147 #
148 148 # We can pick:
149 149 # * missingheads part of common (::commonheads)
150 150 common = set(self.outgoing.common)
151 151 nm = self.repo.changelog.nodemap
152 152 cheads = [node for node in self.revs if nm[node] in common]
153 153 # and
154 154 # * commonheads parents on missing
155 155 revset = unfi.set('%ln and parents(roots(%ln))',
156 156 self.outgoing.commonheads,
157 157 self.outgoing.missing)
158 158 cheads.extend(c.node() for c in revset)
159 159 return cheads
160 160
161 161 @property
162 162 def commonheads(self):
163 163 """set of all common heads after changeset bundle push"""
164 164 if self.cgresult:
165 165 return self.futureheads
166 166 else:
167 167 return self.fallbackheads
168 168
169 169 # mapping of message used when pushing bookmark
170 170 bookmsgmap = {'update': (_("updating bookmark %s\n"),
171 171 _('updating bookmark %s failed!\n')),
172 172 'export': (_("exporting bookmark %s\n"),
173 173 _('exporting bookmark %s failed!\n')),
174 174 'delete': (_("deleting remote bookmark %s\n"),
175 175 _('deleting remote bookmark %s failed!\n')),
176 176 }
177 177
178 178
179 179 def push(repo, remote, force=False, revs=None, newbranch=False, bookmarks=()):
180 180 '''Push outgoing changesets (limited by revs) from a local
181 181 repository to remote. Return an integer:
182 182 - None means nothing to push
183 183 - 0 means HTTP error
184 184 - 1 means we pushed and remote head count is unchanged *or*
185 185 we have outgoing changesets but refused to push
186 186 - other values as described by addchangegroup()
187 187 '''
188 188 pushop = pushoperation(repo, remote, force, revs, newbranch, bookmarks)
189 189 if pushop.remote.local():
190 190 missing = (set(pushop.repo.requirements)
191 191 - pushop.remote.local().supported)
192 192 if missing:
193 193 msg = _("required features are not"
194 194 " supported in the destination:"
195 195 " %s") % (', '.join(sorted(missing)))
196 196 raise util.Abort(msg)
197 197
198 198 # there are two ways to push to remote repo:
199 199 #
200 200 # addchangegroup assumes local user can lock remote
201 201 # repo (local filesystem, old ssh servers).
202 202 #
203 203 # unbundle assumes local user cannot lock remote repo (new ssh
204 204 # servers, http servers).
205 205
206 206 if not pushop.remote.canpush():
207 207 raise util.Abort(_("destination does not support push"))
208 208 # get local lock as we might write phase data
209 209 localwlock = locallock = None
210 210 try:
211 211 # bundle2 push may receive a reply bundle touching bookmarks or other
212 212 # things requiring the wlock. Take it now to ensure proper ordering.
213 213 maypushback = pushop.ui.configbool('experimental', 'bundle2.pushback')
214 214 if _canusebundle2(pushop) and maypushback:
215 215 localwlock = pushop.repo.wlock()
216 216 locallock = pushop.repo.lock()
217 217 pushop.locallocked = True
218 218 except IOError, err:
219 219 pushop.locallocked = False
220 220 if err.errno != errno.EACCES:
221 221 raise
222 222 # source repo cannot be locked.
223 223 # We do not abort the push, but just disable the local phase
224 224 # synchronisation.
225 225 msg = 'cannot lock source repository: %s\n' % err
226 226 pushop.ui.debug(msg)
227 227 try:
228 228 if pushop.locallocked:
229 229 pushop.trmanager = transactionmanager(repo,
230 230 'push-response',
231 231 pushop.remote.url())
232 232 pushop.repo.checkpush(pushop)
233 233 lock = None
234 234 unbundle = pushop.remote.capable('unbundle')
235 235 if not unbundle:
236 236 lock = pushop.remote.lock()
237 237 try:
238 238 _pushdiscovery(pushop)
239 239 if _canusebundle2(pushop):
240 240 _pushbundle2(pushop)
241 241 _pushchangeset(pushop)
242 242 _pushsyncphase(pushop)
243 243 _pushobsolete(pushop)
244 244 _pushbookmark(pushop)
245 245 finally:
246 246 if lock is not None:
247 247 lock.release()
248 248 if pushop.trmanager:
249 249 pushop.trmanager.close()
250 250 finally:
251 251 if pushop.trmanager:
252 252 pushop.trmanager.release()
253 253 if locallock is not None:
254 254 locallock.release()
255 255 if localwlock is not None:
256 256 localwlock.release()
257 257
258 258 return pushop
259 259
260 260 # list of steps to perform discovery before push
261 261 pushdiscoveryorder = []
262 262
263 263 # Mapping between step name and function
264 264 #
265 265 # This exists to help extensions wrap steps if necessary
266 266 pushdiscoverymapping = {}
267 267
268 268 def pushdiscovery(stepname):
269 269 """decorator for function performing discovery before push
270 270
271 271 The function is added to the step -> function mapping and appended to the
272 272 list of steps. Beware that decorated function will be added in order (this
273 273 may matter).
274 274
275 275 You can only use this decorator for a new step, if you want to wrap a step
276 276 from an extension, change the pushdiscovery dictionary directly."""
277 277 def dec(func):
278 278 assert stepname not in pushdiscoverymapping
279 279 pushdiscoverymapping[stepname] = func
280 280 pushdiscoveryorder.append(stepname)
281 281 return func
282 282 return dec
283 283
284 284 def _pushdiscovery(pushop):
285 285 """Run all discovery steps"""
286 286 for stepname in pushdiscoveryorder:
287 287 step = pushdiscoverymapping[stepname]
288 288 step(pushop)
289 289
290 290 @pushdiscovery('changeset')
291 291 def _pushdiscoverychangeset(pushop):
292 292 """discover the changeset that need to be pushed"""
293 293 fci = discovery.findcommonincoming
294 294 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
295 295 common, inc, remoteheads = commoninc
296 296 fco = discovery.findcommonoutgoing
297 297 outgoing = fco(pushop.repo, pushop.remote, onlyheads=pushop.revs,
298 298 commoninc=commoninc, force=pushop.force)
299 299 pushop.outgoing = outgoing
300 300 pushop.remoteheads = remoteheads
301 301 pushop.incoming = inc
302 302
303 303 @pushdiscovery('phase')
304 304 def _pushdiscoveryphase(pushop):
305 305 """discover the phase that needs to be pushed
306 306
307 307 (computed for both success and failure case for changesets push)"""
308 308 outgoing = pushop.outgoing
309 309 unfi = pushop.repo.unfiltered()
310 310 remotephases = pushop.remote.listkeys('phases')
311 311 publishing = remotephases.get('publishing', False)
312 312 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
313 313 and remotephases # server supports phases
314 314 and not pushop.outgoing.missing # no changesets to be pushed
315 315 and publishing):
316 316 # When:
317 317 # - this is a subrepo push
318 318 # - and remote support phase
319 319 # - and no changeset are to be pushed
320 320 # - and remote is publishing
321 321 # We may be in issue 3871 case!
322 322 # We drop the possible phase synchronisation done by
323 323 # courtesy to publish changesets possibly locally draft
324 324 # on the remote.
325 325 remotephases = {'publishing': 'True'}
326 326 ana = phases.analyzeremotephases(pushop.repo,
327 327 pushop.fallbackheads,
328 328 remotephases)
329 329 pheads, droots = ana
330 330 extracond = ''
331 331 if not publishing:
332 332 extracond = ' and public()'
333 333 revset = 'heads((%%ln::%%ln) %s)' % extracond
334 334 # Get the list of all revs draft on remote by public here.
335 335 # XXX Beware that revset break if droots is not strictly
336 336 # XXX root we may want to ensure it is but it is costly
337 337 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
338 338 if not outgoing.missing:
339 339 future = fallback
340 340 else:
341 341 # adds changeset we are going to push as draft
342 342 #
343 343 # should not be necessary for publishing server, but because of an
344 344 # issue fixed in xxxxx we have to do it anyway.
345 345 fdroots = list(unfi.set('roots(%ln + %ln::)',
346 346 outgoing.missing, droots))
347 347 fdroots = [f.node() for f in fdroots]
348 348 future = list(unfi.set(revset, fdroots, pushop.futureheads))
349 349 pushop.outdatedphases = future
350 350 pushop.fallbackoutdatedphases = fallback
351 351
352 352 @pushdiscovery('obsmarker')
353 353 def _pushdiscoveryobsmarkers(pushop):
354 354 if (obsolete.isenabled(pushop.repo, obsolete.exchangeopt)
355 355 and pushop.repo.obsstore
356 356 and 'obsolete' in pushop.remote.listkeys('namespaces')):
357 357 repo = pushop.repo
358 358 # very naive computation, that can be quite expensive on big repo.
359 359 # However: evolution is currently slow on them anyway.
360 360 nodes = (c.node() for c in repo.set('::%ln', pushop.futureheads))
361 361 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
362 362
363 363 @pushdiscovery('bookmarks')
364 364 def _pushdiscoverybookmarks(pushop):
365 365 ui = pushop.ui
366 366 repo = pushop.repo.unfiltered()
367 367 remote = pushop.remote
368 368 ui.debug("checking for updated bookmarks\n")
369 369 ancestors = ()
370 370 if pushop.revs:
371 371 revnums = map(repo.changelog.rev, pushop.revs)
372 372 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
373 373 remotebookmark = remote.listkeys('bookmarks')
374 374
375 375 explicit = set(pushop.bookmarks)
376 376
377 377 comp = bookmod.compare(repo, repo._bookmarks, remotebookmark, srchex=hex)
378 378 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
379 379 for b, scid, dcid in advsrc:
380 380 if b in explicit:
381 381 explicit.remove(b)
382 382 if not ancestors or repo[scid].rev() in ancestors:
383 383 pushop.outbookmarks.append((b, dcid, scid))
384 384 # search added bookmark
385 385 for b, scid, dcid in addsrc:
386 386 if b in explicit:
387 387 explicit.remove(b)
388 388 pushop.outbookmarks.append((b, '', scid))
389 389 # search for overwritten bookmark
390 390 for b, scid, dcid in advdst + diverge + differ:
391 391 if b in explicit:
392 392 explicit.remove(b)
393 393 pushop.outbookmarks.append((b, dcid, scid))
394 394 # search for bookmark to delete
395 395 for b, scid, dcid in adddst:
396 396 if b in explicit:
397 397 explicit.remove(b)
398 398 # treat as "deleted locally"
399 399 pushop.outbookmarks.append((b, dcid, ''))
400 400 # identical bookmarks shouldn't get reported
401 401 for b, scid, dcid in same:
402 402 if b in explicit:
403 403 explicit.remove(b)
404 404
405 405 if explicit:
406 406 explicit = sorted(explicit)
407 407 # we should probably list all of them
408 408 ui.warn(_('bookmark %s does not exist on the local '
409 409 'or remote repository!\n') % explicit[0])
410 410 pushop.bkresult = 2
411 411
412 412 pushop.outbookmarks.sort()
413 413
414 414 def _pushcheckoutgoing(pushop):
415 415 outgoing = pushop.outgoing
416 416 unfi = pushop.repo.unfiltered()
417 417 if not outgoing.missing:
418 418 # nothing to push
419 419 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
420 420 return False
421 421 # something to push
422 422 if not pushop.force:
423 423 # if repo.obsstore == False --> no obsolete
424 424 # then, save the iteration
425 425 if unfi.obsstore:
426 426 # this message are here for 80 char limit reason
427 427 mso = _("push includes obsolete changeset: %s!")
428 428 mst = {"unstable": _("push includes unstable changeset: %s!"),
429 429 "bumped": _("push includes bumped changeset: %s!"),
430 430 "divergent": _("push includes divergent changeset: %s!")}
431 431 # If we are to push if there is at least one
432 432 # obsolete or unstable changeset in missing, at
433 433 # least one of the missinghead will be obsolete or
434 434 # unstable. So checking heads only is ok
435 435 for node in outgoing.missingheads:
436 436 ctx = unfi[node]
437 437 if ctx.obsolete():
438 438 raise util.Abort(mso % ctx)
439 439 elif ctx.troubled():
440 440 raise util.Abort(mst[ctx.troubles()[0]] % ctx)
441 441 newbm = pushop.ui.configlist('bookmarks', 'pushing')
442 442 discovery.checkheads(unfi, pushop.remote, outgoing,
443 443 pushop.remoteheads,
444 444 pushop.newbranch,
445 445 bool(pushop.incoming),
446 446 newbm)
447 447 return True
448 448
449 449 # List of names of steps to perform for an outgoing bundle2, order matters.
450 450 b2partsgenorder = []
451 451
452 452 # Mapping between step name and function
453 453 #
454 454 # This exists to help extensions wrap steps if necessary
455 455 b2partsgenmapping = {}
456 456
457 457 def b2partsgenerator(stepname, idx=None):
458 458 """decorator for function generating bundle2 part
459 459
460 460 The function is added to the step -> function mapping and appended to the
461 461 list of steps. Beware that decorated functions will be added in order
462 462 (this may matter).
463 463
464 464 You can only use this decorator for new steps, if you want to wrap a step
465 465 from an extension, attack the b2partsgenmapping dictionary directly."""
466 466 def dec(func):
467 467 assert stepname not in b2partsgenmapping
468 468 b2partsgenmapping[stepname] = func
469 469 if idx is None:
470 470 b2partsgenorder.append(stepname)
471 471 else:
472 472 b2partsgenorder.insert(idx, stepname)
473 473 return func
474 474 return dec
475 475
476 476 @b2partsgenerator('changeset')
477 477 def _pushb2ctx(pushop, bundler):
478 478 """handle changegroup push through bundle2
479 479
480 480 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
481 481 """
482 482 if 'changesets' in pushop.stepsdone:
483 483 return
484 484 pushop.stepsdone.add('changesets')
485 485 # Send known heads to the server for race detection.
486 486 if not _pushcheckoutgoing(pushop):
487 487 return
488 488 pushop.repo.prepushoutgoinghooks(pushop.repo,
489 489 pushop.remote,
490 490 pushop.outgoing)
491 491 if not pushop.force:
492 492 bundler.newpart('check:heads', data=iter(pushop.remoteheads))
493 493 b2caps = bundle2.bundle2caps(pushop.remote)
494 494 version = None
495 495 cgversions = b2caps.get('changegroup')
496 496 if not cgversions: # 3.1 and 3.2 ship with an empty value
497 497 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
498 498 pushop.outgoing)
499 499 else:
500 500 cgversions = [v for v in cgversions if v in changegroup.packermap]
501 501 if not cgversions:
502 502 raise ValueError(_('no common changegroup version'))
503 503 version = max(cgversions)
504 504 cg = changegroup.getlocalchangegroupraw(pushop.repo, 'push',
505 505 pushop.outgoing,
506 506 version=version)
507 507 cgpart = bundler.newpart('changegroup', data=cg)
508 508 if version is not None:
509 509 cgpart.addparam('version', version)
510 510 def handlereply(op):
511 511 """extract addchangegroup returns from server reply"""
512 512 cgreplies = op.records.getreplies(cgpart.id)
513 513 assert len(cgreplies['changegroup']) == 1
514 514 pushop.cgresult = cgreplies['changegroup'][0]['return']
515 515 return handlereply
516 516
517 517 @b2partsgenerator('phase')
518 518 def _pushb2phases(pushop, bundler):
519 519 """handle phase push through bundle2"""
520 520 if 'phases' in pushop.stepsdone:
521 521 return
522 522 b2caps = bundle2.bundle2caps(pushop.remote)
523 523 if not 'pushkey' in b2caps:
524 524 return
525 525 pushop.stepsdone.add('phases')
526 526 part2node = []
527
528 def handlefailure(pushop, exc):
529 targetid = int(exc.partid)
530 for partid, node in part2node:
531 if partid == targetid:
532 raise error.Abort(_('updating %s to public failed') % node)
533
527 534 enc = pushkey.encode
528 535 for newremotehead in pushop.outdatedphases:
529 part = bundler.newpart('pushkey', mandatory=False)
536 part = bundler.newpart('pushkey')
530 537 part.addparam('namespace', enc('phases'))
531 538 part.addparam('key', enc(newremotehead.hex()))
532 539 part.addparam('old', enc(str(phases.draft)))
533 540 part.addparam('new', enc(str(phases.public)))
534 541 part2node.append((part.id, newremotehead))
542 pushop.pkfailcb[part.id] = handlefailure
543
535 544 def handlereply(op):
536 545 for partid, node in part2node:
537 546 partrep = op.records.getreplies(partid)
538 547 results = partrep['pushkey']
539 548 assert len(results) <= 1
540 549 msg = None
541 550 if not results:
542 551 msg = _('server ignored update of %s to public!\n') % node
543 552 elif not int(results[0]['return']):
544 553 msg = _('updating %s to public failed!\n') % node
545 554 if msg is not None:
546 555 pushop.ui.warn(msg)
547 556 return handlereply
548 557
549 558 @b2partsgenerator('obsmarkers')
550 559 def _pushb2obsmarkers(pushop, bundler):
551 560 if 'obsmarkers' in pushop.stepsdone:
552 561 return
553 562 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
554 563 if obsolete.commonversion(remoteversions) is None:
555 564 return
556 565 pushop.stepsdone.add('obsmarkers')
557 566 if pushop.outobsmarkers:
558 567 markers = sorted(pushop.outobsmarkers)
559 568 buildobsmarkerspart(bundler, markers)
560 569
561 570 @b2partsgenerator('bookmarks')
562 571 def _pushb2bookmarks(pushop, bundler):
563 572 """handle phase push through bundle2"""
564 573 if 'bookmarks' in pushop.stepsdone:
565 574 return
566 575 b2caps = bundle2.bundle2caps(pushop.remote)
567 576 if 'pushkey' not in b2caps:
568 577 return
569 578 pushop.stepsdone.add('bookmarks')
570 579 part2book = []
571 580 enc = pushkey.encode
572 581
573 582 def handlefailure(pushop, exc):
574 583 targetid = int(exc.partid)
575 584 for partid, book, action in part2book:
576 585 if partid == targetid:
577 586 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
578 587 # we should not be called for part we did not generated
579 588 assert False
580 589
581 590 for book, old, new in pushop.outbookmarks:
582 591 part = bundler.newpart('pushkey')
583 592 part.addparam('namespace', enc('bookmarks'))
584 593 part.addparam('key', enc(book))
585 594 part.addparam('old', enc(old))
586 595 part.addparam('new', enc(new))
587 596 action = 'update'
588 597 if not old:
589 598 action = 'export'
590 599 elif not new:
591 600 action = 'delete'
592 601 part2book.append((part.id, book, action))
593 602 pushop.pkfailcb[part.id] = handlefailure
594 603
595 604 def handlereply(op):
596 605 ui = pushop.ui
597 606 for partid, book, action in part2book:
598 607 partrep = op.records.getreplies(partid)
599 608 results = partrep['pushkey']
600 609 assert len(results) <= 1
601 610 if not results:
602 611 pushop.ui.warn(_('server ignored bookmark %s update\n') % book)
603 612 else:
604 613 ret = int(results[0]['return'])
605 614 if ret:
606 615 ui.status(bookmsgmap[action][0] % book)
607 616 else:
608 617 ui.warn(bookmsgmap[action][1] % book)
609 618 if pushop.bkresult is not None:
610 619 pushop.bkresult = 1
611 620 return handlereply
612 621
613 622
614 623 def _pushbundle2(pushop):
615 624 """push data to the remote using bundle2
616 625
617 626 The only currently supported type of data is changegroup but this will
618 627 evolve in the future."""
619 628 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
620 629 pushback = (pushop.trmanager
621 630 and pushop.ui.configbool('experimental', 'bundle2.pushback'))
622 631
623 632 # create reply capability
624 633 capsblob = bundle2.encodecaps(bundle2.getrepocaps(pushop.repo,
625 634 allowpushback=pushback))
626 635 bundler.newpart('replycaps', data=capsblob)
627 636 replyhandlers = []
628 637 for partgenname in b2partsgenorder:
629 638 partgen = b2partsgenmapping[partgenname]
630 639 ret = partgen(pushop, bundler)
631 640 if callable(ret):
632 641 replyhandlers.append(ret)
633 642 # do not push if nothing to push
634 643 if bundler.nbparts <= 1:
635 644 return
636 645 stream = util.chunkbuffer(bundler.getchunks())
637 646 try:
638 647 try:
639 648 reply = pushop.remote.unbundle(stream, ['force'], 'push')
640 649 except error.BundleValueError, exc:
641 650 raise util.Abort('missing support for %s' % exc)
642 651 try:
643 652 trgetter = None
644 653 if pushback:
645 654 trgetter = pushop.trmanager.transaction
646 655 op = bundle2.processbundle(pushop.repo, reply, trgetter)
647 656 except error.BundleValueError, exc:
648 657 raise util.Abort('missing support for %s' % exc)
649 658 except error.PushkeyFailed, exc:
650 659 partid = int(exc.partid)
651 660 if partid not in pushop.pkfailcb:
652 661 raise
653 662 pushop.pkfailcb[partid](pushop, exc)
654 663 for rephand in replyhandlers:
655 664 rephand(op)
656 665
657 666 def _pushchangeset(pushop):
658 667 """Make the actual push of changeset bundle to remote repo"""
659 668 if 'changesets' in pushop.stepsdone:
660 669 return
661 670 pushop.stepsdone.add('changesets')
662 671 if not _pushcheckoutgoing(pushop):
663 672 return
664 673 pushop.repo.prepushoutgoinghooks(pushop.repo,
665 674 pushop.remote,
666 675 pushop.outgoing)
667 676 outgoing = pushop.outgoing
668 677 unbundle = pushop.remote.capable('unbundle')
669 678 # TODO: get bundlecaps from remote
670 679 bundlecaps = None
671 680 # create a changegroup from local
672 681 if pushop.revs is None and not (outgoing.excluded
673 682 or pushop.repo.changelog.filteredrevs):
674 683 # push everything,
675 684 # use the fast path, no race possible on push
676 685 bundler = changegroup.cg1packer(pushop.repo, bundlecaps)
677 686 cg = changegroup.getsubset(pushop.repo,
678 687 outgoing,
679 688 bundler,
680 689 'push',
681 690 fastpath=True)
682 691 else:
683 692 cg = changegroup.getlocalchangegroup(pushop.repo, 'push', outgoing,
684 693 bundlecaps)
685 694
686 695 # apply changegroup to remote
687 696 if unbundle:
688 697 # local repo finds heads on server, finds out what
689 698 # revs it must push. once revs transferred, if server
690 699 # finds it has different heads (someone else won
691 700 # commit/push race), server aborts.
692 701 if pushop.force:
693 702 remoteheads = ['force']
694 703 else:
695 704 remoteheads = pushop.remoteheads
696 705 # ssh: return remote's addchangegroup()
697 706 # http: return remote's addchangegroup() or 0 for error
698 707 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads,
699 708 pushop.repo.url())
700 709 else:
701 710 # we return an integer indicating remote head count
702 711 # change
703 712 pushop.cgresult = pushop.remote.addchangegroup(cg, 'push',
704 713 pushop.repo.url())
705 714
706 715 def _pushsyncphase(pushop):
707 716 """synchronise phase information locally and remotely"""
708 717 cheads = pushop.commonheads
709 718 # even when we don't push, exchanging phase data is useful
710 719 remotephases = pushop.remote.listkeys('phases')
711 720 if (pushop.ui.configbool('ui', '_usedassubrepo', False)
712 721 and remotephases # server supports phases
713 722 and pushop.cgresult is None # nothing was pushed
714 723 and remotephases.get('publishing', False)):
715 724 # When:
716 725 # - this is a subrepo push
717 726 # - and remote support phase
718 727 # - and no changeset was pushed
719 728 # - and remote is publishing
720 729 # We may be in issue 3871 case!
721 730 # We drop the possible phase synchronisation done by
722 731 # courtesy to publish changesets possibly locally draft
723 732 # on the remote.
724 733 remotephases = {'publishing': 'True'}
725 734 if not remotephases: # old server or public only reply from non-publishing
726 735 _localphasemove(pushop, cheads)
727 736 # don't push any phase data as there is nothing to push
728 737 else:
729 738 ana = phases.analyzeremotephases(pushop.repo, cheads,
730 739 remotephases)
731 740 pheads, droots = ana
732 741 ### Apply remote phase on local
733 742 if remotephases.get('publishing', False):
734 743 _localphasemove(pushop, cheads)
735 744 else: # publish = False
736 745 _localphasemove(pushop, pheads)
737 746 _localphasemove(pushop, cheads, phases.draft)
738 747 ### Apply local phase on remote
739 748
740 749 if pushop.cgresult:
741 750 if 'phases' in pushop.stepsdone:
742 751 # phases already pushed though bundle2
743 752 return
744 753 outdated = pushop.outdatedphases
745 754 else:
746 755 outdated = pushop.fallbackoutdatedphases
747 756
748 757 pushop.stepsdone.add('phases')
749 758
750 759 # filter heads already turned public by the push
751 760 outdated = [c for c in outdated if c.node() not in pheads]
752 761 # fallback to independent pushkey command
753 762 for newremotehead in outdated:
754 763 r = pushop.remote.pushkey('phases',
755 764 newremotehead.hex(),
756 765 str(phases.draft),
757 766 str(phases.public))
758 767 if not r:
759 768 pushop.ui.warn(_('updating %s to public failed!\n')
760 769 % newremotehead)
761 770
762 771 def _localphasemove(pushop, nodes, phase=phases.public):
763 772 """move <nodes> to <phase> in the local source repo"""
764 773 if pushop.trmanager:
765 774 phases.advanceboundary(pushop.repo,
766 775 pushop.trmanager.transaction(),
767 776 phase,
768 777 nodes)
769 778 else:
770 779 # repo is not locked, do not change any phases!
771 780 # Informs the user that phases should have been moved when
772 781 # applicable.
773 782 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
774 783 phasestr = phases.phasenames[phase]
775 784 if actualmoves:
776 785 pushop.ui.status(_('cannot lock source repo, skipping '
777 786 'local %s phase update\n') % phasestr)
778 787
779 788 def _pushobsolete(pushop):
780 789 """utility function to push obsolete markers to a remote"""
781 790 if 'obsmarkers' in pushop.stepsdone:
782 791 return
783 792 pushop.ui.debug('try to push obsolete markers to remote\n')
784 793 repo = pushop.repo
785 794 remote = pushop.remote
786 795 pushop.stepsdone.add('obsmarkers')
787 796 if pushop.outobsmarkers:
788 797 rslts = []
789 798 remotedata = obsolete._pushkeyescape(sorted(pushop.outobsmarkers))
790 799 for key in sorted(remotedata, reverse=True):
791 800 # reverse sort to ensure we end with dump0
792 801 data = remotedata[key]
793 802 rslts.append(remote.pushkey('obsolete', key, '', data))
794 803 if [r for r in rslts if not r]:
795 804 msg = _('failed to push some obsolete markers!\n')
796 805 repo.ui.warn(msg)
797 806
798 807 def _pushbookmark(pushop):
799 808 """Update bookmark position on remote"""
800 809 if pushop.cgresult == 0 or 'bookmarks' in pushop.stepsdone:
801 810 return
802 811 pushop.stepsdone.add('bookmarks')
803 812 ui = pushop.ui
804 813 remote = pushop.remote
805 814
806 815 for b, old, new in pushop.outbookmarks:
807 816 action = 'update'
808 817 if not old:
809 818 action = 'export'
810 819 elif not new:
811 820 action = 'delete'
812 821 if remote.pushkey('bookmarks', b, old, new):
813 822 ui.status(bookmsgmap[action][0] % b)
814 823 else:
815 824 ui.warn(bookmsgmap[action][1] % b)
816 825 # discovery can have set the value form invalid entry
817 826 if pushop.bkresult is not None:
818 827 pushop.bkresult = 1
819 828
820 829 class pulloperation(object):
821 830 """A object that represent a single pull operation
822 831
823 832 It purpose is to carry pull related state and very common operation.
824 833
825 834 A new should be created at the beginning of each pull and discarded
826 835 afterward.
827 836 """
828 837
829 838 def __init__(self, repo, remote, heads=None, force=False, bookmarks=(),
830 839 remotebookmarks=None):
831 840 # repo we pull into
832 841 self.repo = repo
833 842 # repo we pull from
834 843 self.remote = remote
835 844 # revision we try to pull (None is "all")
836 845 self.heads = heads
837 846 # bookmark pulled explicitly
838 847 self.explicitbookmarks = bookmarks
839 848 # do we force pull?
840 849 self.force = force
841 850 # transaction manager
842 851 self.trmanager = None
843 852 # set of common changeset between local and remote before pull
844 853 self.common = None
845 854 # set of pulled head
846 855 self.rheads = None
847 856 # list of missing changeset to fetch remotely
848 857 self.fetch = None
849 858 # remote bookmarks data
850 859 self.remotebookmarks = remotebookmarks
851 860 # result of changegroup pulling (used as return code by pull)
852 861 self.cgresult = None
853 862 # list of step already done
854 863 self.stepsdone = set()
855 864
856 865 @util.propertycache
857 866 def pulledsubset(self):
858 867 """heads of the set of changeset target by the pull"""
859 868 # compute target subset
860 869 if self.heads is None:
861 870 # We pulled every thing possible
862 871 # sync on everything common
863 872 c = set(self.common)
864 873 ret = list(self.common)
865 874 for n in self.rheads:
866 875 if n not in c:
867 876 ret.append(n)
868 877 return ret
869 878 else:
870 879 # We pulled a specific subset
871 880 # sync on this subset
872 881 return self.heads
873 882
874 883 def gettransaction(self):
875 884 # deprecated; talk to trmanager directly
876 885 return self.trmanager.transaction()
877 886
878 887 class transactionmanager(object):
879 888 """An object to manage the life cycle of a transaction
880 889
881 890 It creates the transaction on demand and calls the appropriate hooks when
882 891 closing the transaction."""
883 892 def __init__(self, repo, source, url):
884 893 self.repo = repo
885 894 self.source = source
886 895 self.url = url
887 896 self._tr = None
888 897
889 898 def transaction(self):
890 899 """Return an open transaction object, constructing if necessary"""
891 900 if not self._tr:
892 901 trname = '%s\n%s' % (self.source, util.hidepassword(self.url))
893 902 self._tr = self.repo.transaction(trname)
894 903 self._tr.hookargs['source'] = self.source
895 904 self._tr.hookargs['url'] = self.url
896 905 return self._tr
897 906
898 907 def close(self):
899 908 """close transaction if created"""
900 909 if self._tr is not None:
901 910 self._tr.close()
902 911
903 912 def release(self):
904 913 """release transaction if created"""
905 914 if self._tr is not None:
906 915 self._tr.release()
907 916
908 917 def pull(repo, remote, heads=None, force=False, bookmarks=(), opargs=None):
909 918 if opargs is None:
910 919 opargs = {}
911 920 pullop = pulloperation(repo, remote, heads, force, bookmarks=bookmarks,
912 921 **opargs)
913 922 if pullop.remote.local():
914 923 missing = set(pullop.remote.requirements) - pullop.repo.supported
915 924 if missing:
916 925 msg = _("required features are not"
917 926 " supported in the destination:"
918 927 " %s") % (', '.join(sorted(missing)))
919 928 raise util.Abort(msg)
920 929
921 930 lock = pullop.repo.lock()
922 931 try:
923 932 pullop.trmanager = transactionmanager(repo, 'pull', remote.url())
924 933 _pulldiscovery(pullop)
925 934 if _canusebundle2(pullop):
926 935 _pullbundle2(pullop)
927 936 _pullchangeset(pullop)
928 937 _pullphase(pullop)
929 938 _pullbookmarks(pullop)
930 939 _pullobsolete(pullop)
931 940 pullop.trmanager.close()
932 941 finally:
933 942 pullop.trmanager.release()
934 943 lock.release()
935 944
936 945 return pullop
937 946
938 947 # list of steps to perform discovery before pull
939 948 pulldiscoveryorder = []
940 949
941 950 # Mapping between step name and function
942 951 #
943 952 # This exists to help extensions wrap steps if necessary
944 953 pulldiscoverymapping = {}
945 954
946 955 def pulldiscovery(stepname):
947 956 """decorator for function performing discovery before pull
948 957
949 958 The function is added to the step -> function mapping and appended to the
950 959 list of steps. Beware that decorated function will be added in order (this
951 960 may matter).
952 961
953 962 You can only use this decorator for a new step, if you want to wrap a step
954 963 from an extension, change the pulldiscovery dictionary directly."""
955 964 def dec(func):
956 965 assert stepname not in pulldiscoverymapping
957 966 pulldiscoverymapping[stepname] = func
958 967 pulldiscoveryorder.append(stepname)
959 968 return func
960 969 return dec
961 970
962 971 def _pulldiscovery(pullop):
963 972 """Run all discovery steps"""
964 973 for stepname in pulldiscoveryorder:
965 974 step = pulldiscoverymapping[stepname]
966 975 step(pullop)
967 976
968 977 @pulldiscovery('b1:bookmarks')
969 978 def _pullbookmarkbundle1(pullop):
970 979 """fetch bookmark data in bundle1 case
971 980
972 981 If not using bundle2, we have to fetch bookmarks before changeset
973 982 discovery to reduce the chance and impact of race conditions."""
974 983 if pullop.remotebookmarks is not None:
975 984 return
976 985 if (_canusebundle2(pullop)
977 986 and 'listkeys' in bundle2.bundle2caps(pullop.remote)):
978 987 # all known bundle2 servers now support listkeys, but lets be nice with
979 988 # new implementation.
980 989 return
981 990 pullop.remotebookmarks = pullop.remote.listkeys('bookmarks')
982 991
983 992
984 993 @pulldiscovery('changegroup')
985 994 def _pulldiscoverychangegroup(pullop):
986 995 """discovery phase for the pull
987 996
988 997 Current handle changeset discovery only, will change handle all discovery
989 998 at some point."""
990 999 tmp = discovery.findcommonincoming(pullop.repo,
991 1000 pullop.remote,
992 1001 heads=pullop.heads,
993 1002 force=pullop.force)
994 1003 common, fetch, rheads = tmp
995 1004 nm = pullop.repo.unfiltered().changelog.nodemap
996 1005 if fetch and rheads:
997 1006 # If a remote heads in filtered locally, lets drop it from the unknown
998 1007 # remote heads and put in back in common.
999 1008 #
1000 1009 # This is a hackish solution to catch most of "common but locally
1001 1010 # hidden situation". We do not performs discovery on unfiltered
1002 1011 # repository because it end up doing a pathological amount of round
1003 1012 # trip for w huge amount of changeset we do not care about.
1004 1013 #
1005 1014 # If a set of such "common but filtered" changeset exist on the server
1006 1015 # but are not including a remote heads, we'll not be able to detect it,
1007 1016 scommon = set(common)
1008 1017 filteredrheads = []
1009 1018 for n in rheads:
1010 1019 if n in nm:
1011 1020 if n not in scommon:
1012 1021 common.append(n)
1013 1022 else:
1014 1023 filteredrheads.append(n)
1015 1024 if not filteredrheads:
1016 1025 fetch = []
1017 1026 rheads = filteredrheads
1018 1027 pullop.common = common
1019 1028 pullop.fetch = fetch
1020 1029 pullop.rheads = rheads
1021 1030
1022 1031 def _pullbundle2(pullop):
1023 1032 """pull data using bundle2
1024 1033
1025 1034 For now, the only supported data are changegroup."""
1026 1035 remotecaps = bundle2.bundle2caps(pullop.remote)
1027 1036 kwargs = {'bundlecaps': caps20to10(pullop.repo)}
1028 1037 # pulling changegroup
1029 1038 pullop.stepsdone.add('changegroup')
1030 1039
1031 1040 kwargs['common'] = pullop.common
1032 1041 kwargs['heads'] = pullop.heads or pullop.rheads
1033 1042 kwargs['cg'] = pullop.fetch
1034 1043 if 'listkeys' in remotecaps:
1035 1044 kwargs['listkeys'] = ['phase']
1036 1045 if pullop.remotebookmarks is None:
1037 1046 # make sure to always includes bookmark data when migrating
1038 1047 # `hg incoming --bundle` to using this function.
1039 1048 kwargs['listkeys'].append('bookmarks')
1040 1049 if not pullop.fetch:
1041 1050 pullop.repo.ui.status(_("no changes found\n"))
1042 1051 pullop.cgresult = 0
1043 1052 else:
1044 1053 if pullop.heads is None and list(pullop.common) == [nullid]:
1045 1054 pullop.repo.ui.status(_("requesting all changes\n"))
1046 1055 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1047 1056 remoteversions = bundle2.obsmarkersversion(remotecaps)
1048 1057 if obsolete.commonversion(remoteversions) is not None:
1049 1058 kwargs['obsmarkers'] = True
1050 1059 pullop.stepsdone.add('obsmarkers')
1051 1060 _pullbundle2extraprepare(pullop, kwargs)
1052 1061 bundle = pullop.remote.getbundle('pull', **kwargs)
1053 1062 try:
1054 1063 op = bundle2.processbundle(pullop.repo, bundle, pullop.gettransaction)
1055 1064 except error.BundleValueError, exc:
1056 1065 raise util.Abort('missing support for %s' % exc)
1057 1066
1058 1067 if pullop.fetch:
1059 1068 results = [cg['return'] for cg in op.records['changegroup']]
1060 1069 pullop.cgresult = changegroup.combineresults(results)
1061 1070
1062 1071 # processing phases change
1063 1072 for namespace, value in op.records['listkeys']:
1064 1073 if namespace == 'phases':
1065 1074 _pullapplyphases(pullop, value)
1066 1075
1067 1076 # processing bookmark update
1068 1077 for namespace, value in op.records['listkeys']:
1069 1078 if namespace == 'bookmarks':
1070 1079 pullop.remotebookmarks = value
1071 1080
1072 1081 # bookmark data were either already there or pulled in the bundle
1073 1082 if pullop.remotebookmarks is not None:
1074 1083 _pullbookmarks(pullop)
1075 1084
1076 1085 def _pullbundle2extraprepare(pullop, kwargs):
1077 1086 """hook function so that extensions can extend the getbundle call"""
1078 1087 pass
1079 1088
1080 1089 def _pullchangeset(pullop):
1081 1090 """pull changeset from unbundle into the local repo"""
1082 1091 # We delay the open of the transaction as late as possible so we
1083 1092 # don't open transaction for nothing or you break future useful
1084 1093 # rollback call
1085 1094 if 'changegroup' in pullop.stepsdone:
1086 1095 return
1087 1096 pullop.stepsdone.add('changegroup')
1088 1097 if not pullop.fetch:
1089 1098 pullop.repo.ui.status(_("no changes found\n"))
1090 1099 pullop.cgresult = 0
1091 1100 return
1092 1101 pullop.gettransaction()
1093 1102 if pullop.heads is None and list(pullop.common) == [nullid]:
1094 1103 pullop.repo.ui.status(_("requesting all changes\n"))
1095 1104 elif pullop.heads is None and pullop.remote.capable('changegroupsubset'):
1096 1105 # issue1320, avoid a race if remote changed after discovery
1097 1106 pullop.heads = pullop.rheads
1098 1107
1099 1108 if pullop.remote.capable('getbundle'):
1100 1109 # TODO: get bundlecaps from remote
1101 1110 cg = pullop.remote.getbundle('pull', common=pullop.common,
1102 1111 heads=pullop.heads or pullop.rheads)
1103 1112 elif pullop.heads is None:
1104 1113 cg = pullop.remote.changegroup(pullop.fetch, 'pull')
1105 1114 elif not pullop.remote.capable('changegroupsubset'):
1106 1115 raise util.Abort(_("partial pull cannot be done because "
1107 1116 "other repository doesn't support "
1108 1117 "changegroupsubset."))
1109 1118 else:
1110 1119 cg = pullop.remote.changegroupsubset(pullop.fetch, pullop.heads, 'pull')
1111 1120 pullop.cgresult = changegroup.addchangegroup(pullop.repo, cg, 'pull',
1112 1121 pullop.remote.url())
1113 1122
1114 1123 def _pullphase(pullop):
1115 1124 # Get remote phases data from remote
1116 1125 if 'phases' in pullop.stepsdone:
1117 1126 return
1118 1127 remotephases = pullop.remote.listkeys('phases')
1119 1128 _pullapplyphases(pullop, remotephases)
1120 1129
1121 1130 def _pullapplyphases(pullop, remotephases):
1122 1131 """apply phase movement from observed remote state"""
1123 1132 if 'phases' in pullop.stepsdone:
1124 1133 return
1125 1134 pullop.stepsdone.add('phases')
1126 1135 publishing = bool(remotephases.get('publishing', False))
1127 1136 if remotephases and not publishing:
1128 1137 # remote is new and unpublishing
1129 1138 pheads, _dr = phases.analyzeremotephases(pullop.repo,
1130 1139 pullop.pulledsubset,
1131 1140 remotephases)
1132 1141 dheads = pullop.pulledsubset
1133 1142 else:
1134 1143 # Remote is old or publishing all common changesets
1135 1144 # should be seen as public
1136 1145 pheads = pullop.pulledsubset
1137 1146 dheads = []
1138 1147 unfi = pullop.repo.unfiltered()
1139 1148 phase = unfi._phasecache.phase
1140 1149 rev = unfi.changelog.nodemap.get
1141 1150 public = phases.public
1142 1151 draft = phases.draft
1143 1152
1144 1153 # exclude changesets already public locally and update the others
1145 1154 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
1146 1155 if pheads:
1147 1156 tr = pullop.gettransaction()
1148 1157 phases.advanceboundary(pullop.repo, tr, public, pheads)
1149 1158
1150 1159 # exclude changesets already draft locally and update the others
1151 1160 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
1152 1161 if dheads:
1153 1162 tr = pullop.gettransaction()
1154 1163 phases.advanceboundary(pullop.repo, tr, draft, dheads)
1155 1164
1156 1165 def _pullbookmarks(pullop):
1157 1166 """process the remote bookmark information to update the local one"""
1158 1167 if 'bookmarks' in pullop.stepsdone:
1159 1168 return
1160 1169 pullop.stepsdone.add('bookmarks')
1161 1170 repo = pullop.repo
1162 1171 remotebookmarks = pullop.remotebookmarks
1163 1172 bookmod.updatefromremote(repo.ui, repo, remotebookmarks,
1164 1173 pullop.remote.url(),
1165 1174 pullop.gettransaction,
1166 1175 explicit=pullop.explicitbookmarks)
1167 1176
1168 1177 def _pullobsolete(pullop):
1169 1178 """utility function to pull obsolete markers from a remote
1170 1179
1171 1180 The `gettransaction` is function that return the pull transaction, creating
1172 1181 one if necessary. We return the transaction to inform the calling code that
1173 1182 a new transaction have been created (when applicable).
1174 1183
1175 1184 Exists mostly to allow overriding for experimentation purpose"""
1176 1185 if 'obsmarkers' in pullop.stepsdone:
1177 1186 return
1178 1187 pullop.stepsdone.add('obsmarkers')
1179 1188 tr = None
1180 1189 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
1181 1190 pullop.repo.ui.debug('fetching remote obsolete markers\n')
1182 1191 remoteobs = pullop.remote.listkeys('obsolete')
1183 1192 if 'dump0' in remoteobs:
1184 1193 tr = pullop.gettransaction()
1185 1194 for key in sorted(remoteobs, reverse=True):
1186 1195 if key.startswith('dump'):
1187 1196 data = base85.b85decode(remoteobs[key])
1188 1197 pullop.repo.obsstore.mergemarkers(tr, data)
1189 1198 pullop.repo.invalidatevolatilesets()
1190 1199 return tr
1191 1200
1192 1201 def caps20to10(repo):
1193 1202 """return a set with appropriate options to use bundle20 during getbundle"""
1194 1203 caps = set(['HG20'])
1195 1204 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo))
1196 1205 caps.add('bundle2=' + urllib.quote(capsblob))
1197 1206 return caps
1198 1207
1199 1208 # List of names of steps to perform for a bundle2 for getbundle, order matters.
1200 1209 getbundle2partsorder = []
1201 1210
1202 1211 # Mapping between step name and function
1203 1212 #
1204 1213 # This exists to help extensions wrap steps if necessary
1205 1214 getbundle2partsmapping = {}
1206 1215
1207 1216 def getbundle2partsgenerator(stepname, idx=None):
1208 1217 """decorator for function generating bundle2 part for getbundle
1209 1218
1210 1219 The function is added to the step -> function mapping and appended to the
1211 1220 list of steps. Beware that decorated functions will be added in order
1212 1221 (this may matter).
1213 1222
1214 1223 You can only use this decorator for new steps, if you want to wrap a step
1215 1224 from an extension, attack the getbundle2partsmapping dictionary directly."""
1216 1225 def dec(func):
1217 1226 assert stepname not in getbundle2partsmapping
1218 1227 getbundle2partsmapping[stepname] = func
1219 1228 if idx is None:
1220 1229 getbundle2partsorder.append(stepname)
1221 1230 else:
1222 1231 getbundle2partsorder.insert(idx, stepname)
1223 1232 return func
1224 1233 return dec
1225 1234
1226 1235 def getbundle(repo, source, heads=None, common=None, bundlecaps=None,
1227 1236 **kwargs):
1228 1237 """return a full bundle (with potentially multiple kind of parts)
1229 1238
1230 1239 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
1231 1240 passed. For now, the bundle can contain only changegroup, but this will
1232 1241 changes when more part type will be available for bundle2.
1233 1242
1234 1243 This is different from changegroup.getchangegroup that only returns an HG10
1235 1244 changegroup bundle. They may eventually get reunited in the future when we
1236 1245 have a clearer idea of the API we what to query different data.
1237 1246
1238 1247 The implementation is at a very early stage and will get massive rework
1239 1248 when the API of bundle is refined.
1240 1249 """
1241 1250 # bundle10 case
1242 1251 usebundle2 = False
1243 1252 if bundlecaps is not None:
1244 1253 usebundle2 = any((cap.startswith('HG2') for cap in bundlecaps))
1245 1254 if not usebundle2:
1246 1255 if bundlecaps and not kwargs.get('cg', True):
1247 1256 raise ValueError(_('request for bundle10 must include changegroup'))
1248 1257
1249 1258 if kwargs:
1250 1259 raise ValueError(_('unsupported getbundle arguments: %s')
1251 1260 % ', '.join(sorted(kwargs.keys())))
1252 1261 return changegroup.getchangegroup(repo, source, heads=heads,
1253 1262 common=common, bundlecaps=bundlecaps)
1254 1263
1255 1264 # bundle20 case
1256 1265 b2caps = {}
1257 1266 for bcaps in bundlecaps:
1258 1267 if bcaps.startswith('bundle2='):
1259 1268 blob = urllib.unquote(bcaps[len('bundle2='):])
1260 1269 b2caps.update(bundle2.decodecaps(blob))
1261 1270 bundler = bundle2.bundle20(repo.ui, b2caps)
1262 1271
1263 1272 kwargs['heads'] = heads
1264 1273 kwargs['common'] = common
1265 1274
1266 1275 for name in getbundle2partsorder:
1267 1276 func = getbundle2partsmapping[name]
1268 1277 func(bundler, repo, source, bundlecaps=bundlecaps, b2caps=b2caps,
1269 1278 **kwargs)
1270 1279
1271 1280 return util.chunkbuffer(bundler.getchunks())
1272 1281
1273 1282 @getbundle2partsgenerator('changegroup')
1274 1283 def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
1275 1284 b2caps=None, heads=None, common=None, **kwargs):
1276 1285 """add a changegroup part to the requested bundle"""
1277 1286 cg = None
1278 1287 if kwargs.get('cg', True):
1279 1288 # build changegroup bundle here.
1280 1289 version = None
1281 1290 cgversions = b2caps.get('changegroup')
1282 1291 if not cgversions: # 3.1 and 3.2 ship with an empty value
1283 1292 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1284 1293 common=common,
1285 1294 bundlecaps=bundlecaps)
1286 1295 else:
1287 1296 cgversions = [v for v in cgversions if v in changegroup.packermap]
1288 1297 if not cgversions:
1289 1298 raise ValueError(_('no common changegroup version'))
1290 1299 version = max(cgversions)
1291 1300 cg = changegroup.getchangegroupraw(repo, source, heads=heads,
1292 1301 common=common,
1293 1302 bundlecaps=bundlecaps,
1294 1303 version=version)
1295 1304
1296 1305 if cg:
1297 1306 part = bundler.newpart('changegroup', data=cg)
1298 1307 if version is not None:
1299 1308 part.addparam('version', version)
1300 1309
1301 1310 @getbundle2partsgenerator('listkeys')
1302 1311 def _getbundlelistkeysparts(bundler, repo, source, bundlecaps=None,
1303 1312 b2caps=None, **kwargs):
1304 1313 """add parts containing listkeys namespaces to the requested bundle"""
1305 1314 listkeys = kwargs.get('listkeys', ())
1306 1315 for namespace in listkeys:
1307 1316 part = bundler.newpart('listkeys')
1308 1317 part.addparam('namespace', namespace)
1309 1318 keys = repo.listkeys(namespace).items()
1310 1319 part.data = pushkey.encodekeys(keys)
1311 1320
1312 1321 @getbundle2partsgenerator('obsmarkers')
1313 1322 def _getbundleobsmarkerpart(bundler, repo, source, bundlecaps=None,
1314 1323 b2caps=None, heads=None, **kwargs):
1315 1324 """add an obsolescence markers part to the requested bundle"""
1316 1325 if kwargs.get('obsmarkers', False):
1317 1326 if heads is None:
1318 1327 heads = repo.heads()
1319 1328 subset = [c.node() for c in repo.set('::%ln', heads)]
1320 1329 markers = repo.obsstore.relevantmarkers(subset)
1321 1330 markers = sorted(markers)
1322 1331 buildobsmarkerspart(bundler, markers)
1323 1332
1324 1333 @getbundle2partsgenerator('hgtagsfnodes')
1325 1334 def _getbundletagsfnodes(bundler, repo, source, bundlecaps=None,
1326 1335 b2caps=None, heads=None, common=None,
1327 1336 **kwargs):
1328 1337 """Transfer the .hgtags filenodes mapping.
1329 1338
1330 1339 Only values for heads in this bundle will be transferred.
1331 1340
1332 1341 The part data consists of pairs of 20 byte changeset node and .hgtags
1333 1342 filenodes raw values.
1334 1343 """
1335 1344 # Don't send unless:
1336 1345 # - changeset are being exchanged,
1337 1346 # - the client supports it.
1338 1347 if not (kwargs.get('cg', True) and 'hgtagsfnodes' in b2caps):
1339 1348 return
1340 1349
1341 1350 outgoing = changegroup.computeoutgoing(repo, heads, common)
1342 1351
1343 1352 if not outgoing.missingheads:
1344 1353 return
1345 1354
1346 1355 cache = tags.hgtagsfnodescache(repo.unfiltered())
1347 1356 chunks = []
1348 1357
1349 1358 # .hgtags fnodes are only relevant for head changesets. While we could
1350 1359 # transfer values for all known nodes, there will likely be little to
1351 1360 # no benefit.
1352 1361 #
1353 1362 # We don't bother using a generator to produce output data because
1354 1363 # a) we only have 40 bytes per head and even esoteric numbers of heads
1355 1364 # consume little memory (1M heads is 40MB) b) we don't want to send the
1356 1365 # part if we don't have entries and knowing if we have entries requires
1357 1366 # cache lookups.
1358 1367 for node in outgoing.missingheads:
1359 1368 # Don't compute missing, as this may slow down serving.
1360 1369 fnode = cache.getfnode(node, computemissing=False)
1361 1370 if fnode is not None:
1362 1371 chunks.extend([node, fnode])
1363 1372
1364 1373 if chunks:
1365 1374 bundler.newpart('hgtagsfnodes', data=''.join(chunks))
1366 1375
1367 1376 def check_heads(repo, their_heads, context):
1368 1377 """check if the heads of a repo have been modified
1369 1378
1370 1379 Used by peer for unbundling.
1371 1380 """
1372 1381 heads = repo.heads()
1373 1382 heads_hash = util.sha1(''.join(sorted(heads))).digest()
1374 1383 if not (their_heads == ['force'] or their_heads == heads or
1375 1384 their_heads == ['hashed', heads_hash]):
1376 1385 # someone else committed/pushed/unbundled while we
1377 1386 # were transferring data
1378 1387 raise error.PushRaced('repository changed while %s - '
1379 1388 'please try again' % context)
1380 1389
1381 1390 def unbundle(repo, cg, heads, source, url):
1382 1391 """Apply a bundle to a repo.
1383 1392
1384 1393 this function makes sure the repo is locked during the application and have
1385 1394 mechanism to check that no push race occurred between the creation of the
1386 1395 bundle and its application.
1387 1396
1388 1397 If the push was raced as PushRaced exception is raised."""
1389 1398 r = 0
1390 1399 # need a transaction when processing a bundle2 stream
1391 1400 wlock = lock = tr = None
1392 1401 recordout = None
1393 1402 # quick fix for output mismatch with bundle2 in 3.4
1394 1403 captureoutput = repo.ui.configbool('experimental', 'bundle2-output-capture',
1395 1404 False)
1396 1405 if url.startswith('remote:http:') or url.startswith('remote:https:'):
1397 1406 captureoutput = True
1398 1407 try:
1399 1408 check_heads(repo, heads, 'uploading changes')
1400 1409 # push can proceed
1401 1410 if util.safehasattr(cg, 'params'):
1402 1411 r = None
1403 1412 try:
1404 1413 wlock = repo.wlock()
1405 1414 lock = repo.lock()
1406 1415 tr = repo.transaction(source)
1407 1416 tr.hookargs['source'] = source
1408 1417 tr.hookargs['url'] = url
1409 1418 tr.hookargs['bundle2'] = '1'
1410 1419 op = bundle2.bundleoperation(repo, lambda: tr,
1411 1420 captureoutput=captureoutput)
1412 1421 try:
1413 1422 r = bundle2.processbundle(repo, cg, op=op)
1414 1423 finally:
1415 1424 r = op.reply
1416 1425 if captureoutput and r is not None:
1417 1426 repo.ui.pushbuffer(error=True, subproc=True)
1418 1427 def recordout(output):
1419 1428 r.newpart('output', data=output, mandatory=False)
1420 1429 tr.close()
1421 1430 except BaseException, exc:
1422 1431 exc.duringunbundle2 = True
1423 1432 if captureoutput and r is not None:
1424 1433 parts = exc._bundle2salvagedoutput = r.salvageoutput()
1425 1434 def recordout(output):
1426 1435 part = bundle2.bundlepart('output', data=output,
1427 1436 mandatory=False)
1428 1437 parts.append(part)
1429 1438 raise
1430 1439 else:
1431 1440 lock = repo.lock()
1432 1441 r = changegroup.addchangegroup(repo, cg, source, url)
1433 1442 finally:
1434 1443 lockmod.release(tr, lock, wlock)
1435 1444 if recordout is not None:
1436 1445 recordout(repo.ui.popbuffer())
1437 1446 return r
1438 1447
1439 1448 # This is it's own function so extensions can override it.
1440 1449 def _walkstreamfiles(repo):
1441 1450 return repo.store.walk()
1442 1451
1443 1452 def generatestreamclone(repo):
1444 1453 """Emit content for a streaming clone.
1445 1454
1446 1455 This is a generator of raw chunks that constitute a streaming clone.
1447 1456
1448 1457 The stream begins with a line of 2 space-delimited integers containing the
1449 1458 number of entries and total bytes size.
1450 1459
1451 1460 Next, are N entries for each file being transferred. Each file entry starts
1452 1461 as a line with the file name and integer size delimited by a null byte.
1453 1462 The raw file data follows. Following the raw file data is the next file
1454 1463 entry, or EOF.
1455 1464
1456 1465 When used on the wire protocol, an additional line indicating protocol
1457 1466 success will be prepended to the stream. This function is not responsible
1458 1467 for adding it.
1459 1468
1460 1469 This function will obtain a repository lock to ensure a consistent view of
1461 1470 the store is captured. It therefore may raise LockError.
1462 1471 """
1463 1472 entries = []
1464 1473 total_bytes = 0
1465 1474 # Get consistent snapshot of repo, lock during scan.
1466 1475 lock = repo.lock()
1467 1476 try:
1468 1477 repo.ui.debug('scanning\n')
1469 1478 for name, ename, size in _walkstreamfiles(repo):
1470 1479 if size:
1471 1480 entries.append((name, size))
1472 1481 total_bytes += size
1473 1482 finally:
1474 1483 lock.release()
1475 1484
1476 1485 repo.ui.debug('%d files, %d bytes to transfer\n' %
1477 1486 (len(entries), total_bytes))
1478 1487 yield '%d %d\n' % (len(entries), total_bytes)
1479 1488
1480 1489 sopener = repo.svfs
1481 1490 oldaudit = sopener.mustaudit
1482 1491 debugflag = repo.ui.debugflag
1483 1492 sopener.mustaudit = False
1484 1493
1485 1494 try:
1486 1495 for name, size in entries:
1487 1496 if debugflag:
1488 1497 repo.ui.debug('sending %s (%d bytes)\n' % (name, size))
1489 1498 # partially encode name over the wire for backwards compat
1490 1499 yield '%s\0%d\n' % (store.encodedir(name), size)
1491 1500 if size <= 65536:
1492 1501 fp = sopener(name)
1493 1502 try:
1494 1503 data = fp.read(size)
1495 1504 finally:
1496 1505 fp.close()
1497 1506 yield data
1498 1507 else:
1499 1508 for chunk in util.filechunkiter(sopener(name), limit=size):
1500 1509 yield chunk
1501 1510 finally:
1502 1511 sopener.mustaudit = oldaudit
1503 1512
1504 1513 def consumestreamclone(repo, fp):
1505 1514 """Apply the contents from a streaming clone file.
1506 1515
1507 1516 This takes the output from "streamout" and applies it to the specified
1508 1517 repository.
1509 1518
1510 1519 Like "streamout," the status line added by the wire protocol is not handled
1511 1520 by this function.
1512 1521 """
1513 1522 lock = repo.lock()
1514 1523 try:
1515 1524 repo.ui.status(_('streaming all changes\n'))
1516 1525 l = fp.readline()
1517 1526 try:
1518 1527 total_files, total_bytes = map(int, l.split(' ', 1))
1519 1528 except (ValueError, TypeError):
1520 1529 raise error.ResponseError(
1521 1530 _('unexpected response from remote server:'), l)
1522 1531 repo.ui.status(_('%d files to transfer, %s of data\n') %
1523 1532 (total_files, util.bytecount(total_bytes)))
1524 1533 handled_bytes = 0
1525 1534 repo.ui.progress(_('clone'), 0, total=total_bytes)
1526 1535 start = time.time()
1527 1536
1528 1537 tr = repo.transaction(_('clone'))
1529 1538 try:
1530 1539 for i in xrange(total_files):
1531 1540 # XXX doesn't support '\n' or '\r' in filenames
1532 1541 l = fp.readline()
1533 1542 try:
1534 1543 name, size = l.split('\0', 1)
1535 1544 size = int(size)
1536 1545 except (ValueError, TypeError):
1537 1546 raise error.ResponseError(
1538 1547 _('unexpected response from remote server:'), l)
1539 1548 if repo.ui.debugflag:
1540 1549 repo.ui.debug('adding %s (%s)\n' %
1541 1550 (name, util.bytecount(size)))
1542 1551 # for backwards compat, name was partially encoded
1543 1552 ofp = repo.svfs(store.decodedir(name), 'w')
1544 1553 for chunk in util.filechunkiter(fp, limit=size):
1545 1554 handled_bytes += len(chunk)
1546 1555 repo.ui.progress(_('clone'), handled_bytes,
1547 1556 total=total_bytes)
1548 1557 ofp.write(chunk)
1549 1558 ofp.close()
1550 1559 tr.close()
1551 1560 finally:
1552 1561 tr.release()
1553 1562
1554 1563 # Writing straight to files circumvented the inmemory caches
1555 1564 repo.invalidate()
1556 1565
1557 1566 elapsed = time.time() - start
1558 1567 if elapsed <= 0:
1559 1568 elapsed = 0.001
1560 1569 repo.ui.progress(_('clone'), None)
1561 1570 repo.ui.status(_('transferred %s in %.1f seconds (%s/sec)\n') %
1562 1571 (util.bytecount(total_bytes), elapsed,
1563 1572 util.bytecount(total_bytes / elapsed)))
1564 1573 finally:
1565 1574 lock.release()
@@ -1,2166 +1,2166 b''
1 1 > do_push()
2 2 > {
3 3 > user=$1
4 4 > shift
5 5 > echo "Pushing as user $user"
6 6 > echo 'hgrc = """'
7 7 > sed -n '/\[[ha]/,$p' b/.hg/hgrc | grep -v fakegroups.py
8 8 > echo '"""'
9 9 > if test -f acl.config; then
10 10 > echo 'acl.config = """'
11 11 > cat acl.config
12 12 > echo '"""'
13 13 > fi
14 14 > # On AIX /etc/profile sets LOGNAME read-only. So
15 15 > # LOGNAME=$user hg --cws a --debug push ../b
16 16 > # fails with "This variable is read only."
17 17 > # Use env to work around this.
18 18 > env LOGNAME=$user hg --cwd a --debug push ../b
19 19 > hg --cwd b rollback
20 20 > hg --cwd b --quiet tip
21 21 > echo
22 22 > }
23 23
24 24 > init_config()
25 25 > {
26 26 > cat > fakegroups.py <<EOF
27 27 > from hgext import acl
28 28 > def fakegetusers(ui, group):
29 29 > try:
30 30 > return acl._getusersorig(ui, group)
31 31 > except:
32 32 > return ["fred", "betty"]
33 33 > acl._getusersorig = acl._getusers
34 34 > acl._getusers = fakegetusers
35 35 > EOF
36 36 > rm -f acl.config
37 37 > cat > $config <<EOF
38 38 > [hooks]
39 39 > pretxnchangegroup.acl = python:hgext.acl.hook
40 40 > [acl]
41 41 > sources = push
42 42 > [extensions]
43 43 > f=`pwd`/fakegroups.py
44 44 > EOF
45 45 > }
46 46
47 47 $ cat << EOF >> $HGRCPATH
48 48 > [experimental]
49 49 > # drop me once bundle2 is the default,
50 50 > # added to get test change early.
51 51 > bundle2-exp = True
52 52 > EOF
53 53
54 54 $ hg init a
55 55 $ cd a
56 56 $ mkdir foo foo/Bar quux
57 57 $ echo 'in foo' > foo/file.txt
58 58 $ echo 'in foo/Bar' > foo/Bar/file.txt
59 59 $ echo 'in quux' > quux/file.py
60 60 $ hg add -q
61 61 $ hg ci -m 'add files' -d '1000000 0'
62 62 $ echo >> foo/file.txt
63 63 $ hg ci -m 'change foo/file' -d '1000001 0'
64 64 $ echo >> foo/Bar/file.txt
65 65 $ hg ci -m 'change foo/Bar/file' -d '1000002 0'
66 66 $ echo >> quux/file.py
67 67 $ hg ci -m 'change quux/file' -d '1000003 0'
68 68 $ hg tip --quiet
69 69 3:911600dab2ae
70 70
71 71 $ cd ..
72 72 $ hg clone -r 0 a b
73 73 adding changesets
74 74 adding manifests
75 75 adding file changes
76 76 added 1 changesets with 3 changes to 3 files
77 77 updating to branch default
78 78 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 79
80 80 $ config=b/.hg/hgrc
81 81
82 82 Extension disabled for lack of a hook
83 83
84 84 $ do_push fred
85 85 Pushing as user fred
86 86 hgrc = """
87 87 """
88 88 pushing to ../b
89 89 query 1; heads
90 90 searching for changes
91 91 all remote heads known locally
92 92 listing keys for "phases"
93 93 checking for updated bookmarks
94 94 listing keys for "bookmarks"
95 95 listing keys for "bookmarks"
96 96 3 changesets found
97 97 list of changesets:
98 98 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
99 99 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
100 100 911600dab2ae7a9baff75958b84fe606851ce955
101 101 bundle2-output-bundle: "HG20", 4 parts total
102 102 bundle2-output-part: "replycaps" 155 bytes payload
103 103 bundle2-output-part: "check:heads" streamed payload
104 104 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
105 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
105 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
106 106 bundle2-input-bundle: with-transaction
107 107 bundle2-input-part: "replycaps" supported
108 108 bundle2-input-part: total payload size 155
109 109 bundle2-input-part: "check:heads" supported
110 110 bundle2-input-part: total payload size 20
111 111 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
112 112 adding changesets
113 113 add changeset ef1ea85a6374
114 114 add changeset f9cafe1212c8
115 115 add changeset 911600dab2ae
116 116 adding manifests
117 117 adding file changes
118 118 adding foo/Bar/file.txt revisions
119 119 adding foo/file.txt revisions
120 120 adding quux/file.py revisions
121 121 added 3 changesets with 3 changes to 3 files
122 122 bundle2-input-part: total payload size 1606
123 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
123 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
124 124 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
125 125 bundle2-input-bundle: 3 parts total
126 126 updating the branch cache
127 127 bundle2-output-bundle: "HG20", 2 parts total
128 128 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
129 129 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
130 130 bundle2-input-bundle: with-transaction
131 131 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
132 132 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
133 133 bundle2-input-bundle: 1 parts total
134 134 listing keys for "phases"
135 135 try to push obsolete markers to remote
136 136 repository tip rolled back to revision 0 (undo push)
137 137 0:6675d58eff77
138 138
139 139
140 140 $ echo '[hooks]' >> $config
141 141 $ echo 'pretxnchangegroup.acl = python:hgext.acl.hook' >> $config
142 142
143 143 Extension disabled for lack of acl.sources
144 144
145 145 $ do_push fred
146 146 Pushing as user fred
147 147 hgrc = """
148 148 [hooks]
149 149 pretxnchangegroup.acl = python:hgext.acl.hook
150 150 """
151 151 pushing to ../b
152 152 query 1; heads
153 153 searching for changes
154 154 all remote heads known locally
155 155 listing keys for "phases"
156 156 checking for updated bookmarks
157 157 listing keys for "bookmarks"
158 158 invalid branchheads cache (served): tip differs
159 159 listing keys for "bookmarks"
160 160 3 changesets found
161 161 list of changesets:
162 162 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
163 163 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
164 164 911600dab2ae7a9baff75958b84fe606851ce955
165 165 bundle2-output-bundle: "HG20", 4 parts total
166 166 bundle2-output-part: "replycaps" 155 bytes payload
167 167 bundle2-output-part: "check:heads" streamed payload
168 168 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
169 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
169 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
170 170 bundle2-input-bundle: with-transaction
171 171 bundle2-input-part: "replycaps" supported
172 172 bundle2-input-part: total payload size 155
173 173 bundle2-input-part: "check:heads" supported
174 174 bundle2-input-part: total payload size 20
175 175 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
176 176 adding changesets
177 177 add changeset ef1ea85a6374
178 178 add changeset f9cafe1212c8
179 179 add changeset 911600dab2ae
180 180 adding manifests
181 181 adding file changes
182 182 adding foo/Bar/file.txt revisions
183 183 adding foo/file.txt revisions
184 184 adding quux/file.py revisions
185 185 added 3 changesets with 3 changes to 3 files
186 186 calling hook pretxnchangegroup.acl: hgext.acl.hook
187 187 acl: changes have source "push" - skipping
188 188 bundle2-input-part: total payload size 1606
189 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
189 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
190 190 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
191 191 bundle2-input-bundle: 3 parts total
192 192 updating the branch cache
193 193 bundle2-output-bundle: "HG20", 2 parts total
194 194 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
195 195 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
196 196 bundle2-input-bundle: with-transaction
197 197 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
198 198 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
199 199 bundle2-input-bundle: 1 parts total
200 200 listing keys for "phases"
201 201 try to push obsolete markers to remote
202 202 repository tip rolled back to revision 0 (undo push)
203 203 0:6675d58eff77
204 204
205 205
206 206 No [acl.allow]/[acl.deny]
207 207
208 208 $ echo '[acl]' >> $config
209 209 $ echo 'sources = push' >> $config
210 210 $ do_push fred
211 211 Pushing as user fred
212 212 hgrc = """
213 213 [hooks]
214 214 pretxnchangegroup.acl = python:hgext.acl.hook
215 215 [acl]
216 216 sources = push
217 217 """
218 218 pushing to ../b
219 219 query 1; heads
220 220 searching for changes
221 221 all remote heads known locally
222 222 listing keys for "phases"
223 223 checking for updated bookmarks
224 224 listing keys for "bookmarks"
225 225 invalid branchheads cache (served): tip differs
226 226 listing keys for "bookmarks"
227 227 3 changesets found
228 228 list of changesets:
229 229 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
230 230 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
231 231 911600dab2ae7a9baff75958b84fe606851ce955
232 232 bundle2-output-bundle: "HG20", 4 parts total
233 233 bundle2-output-part: "replycaps" 155 bytes payload
234 234 bundle2-output-part: "check:heads" streamed payload
235 235 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
236 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
236 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
237 237 bundle2-input-bundle: with-transaction
238 238 bundle2-input-part: "replycaps" supported
239 239 bundle2-input-part: total payload size 155
240 240 bundle2-input-part: "check:heads" supported
241 241 bundle2-input-part: total payload size 20
242 242 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
243 243 adding changesets
244 244 add changeset ef1ea85a6374
245 245 add changeset f9cafe1212c8
246 246 add changeset 911600dab2ae
247 247 adding manifests
248 248 adding file changes
249 249 adding foo/Bar/file.txt revisions
250 250 adding foo/file.txt revisions
251 251 adding quux/file.py revisions
252 252 added 3 changesets with 3 changes to 3 files
253 253 calling hook pretxnchangegroup.acl: hgext.acl.hook
254 254 acl: checking access for user "fred"
255 255 acl: acl.allow.branches not enabled
256 256 acl: acl.deny.branches not enabled
257 257 acl: acl.allow not enabled
258 258 acl: acl.deny not enabled
259 259 acl: branch access granted: "ef1ea85a6374" on branch "default"
260 260 acl: path access granted: "ef1ea85a6374"
261 261 acl: branch access granted: "f9cafe1212c8" on branch "default"
262 262 acl: path access granted: "f9cafe1212c8"
263 263 acl: branch access granted: "911600dab2ae" on branch "default"
264 264 acl: path access granted: "911600dab2ae"
265 265 bundle2-input-part: total payload size 1606
266 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
266 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
267 267 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
268 268 bundle2-input-bundle: 3 parts total
269 269 updating the branch cache
270 270 bundle2-output-bundle: "HG20", 2 parts total
271 271 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
272 272 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
273 273 bundle2-input-bundle: with-transaction
274 274 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
275 275 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
276 276 bundle2-input-bundle: 1 parts total
277 277 listing keys for "phases"
278 278 try to push obsolete markers to remote
279 279 repository tip rolled back to revision 0 (undo push)
280 280 0:6675d58eff77
281 281
282 282
283 283 Empty [acl.allow]
284 284
285 285 $ echo '[acl.allow]' >> $config
286 286 $ do_push fred
287 287 Pushing as user fred
288 288 hgrc = """
289 289 [hooks]
290 290 pretxnchangegroup.acl = python:hgext.acl.hook
291 291 [acl]
292 292 sources = push
293 293 [acl.allow]
294 294 """
295 295 pushing to ../b
296 296 query 1; heads
297 297 searching for changes
298 298 all remote heads known locally
299 299 listing keys for "phases"
300 300 checking for updated bookmarks
301 301 listing keys for "bookmarks"
302 302 invalid branchheads cache (served): tip differs
303 303 listing keys for "bookmarks"
304 304 3 changesets found
305 305 list of changesets:
306 306 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
307 307 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
308 308 911600dab2ae7a9baff75958b84fe606851ce955
309 309 bundle2-output-bundle: "HG20", 4 parts total
310 310 bundle2-output-part: "replycaps" 155 bytes payload
311 311 bundle2-output-part: "check:heads" streamed payload
312 312 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
313 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
313 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
314 314 bundle2-input-bundle: with-transaction
315 315 bundle2-input-part: "replycaps" supported
316 316 bundle2-input-part: total payload size 155
317 317 bundle2-input-part: "check:heads" supported
318 318 bundle2-input-part: total payload size 20
319 319 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
320 320 adding changesets
321 321 add changeset ef1ea85a6374
322 322 add changeset f9cafe1212c8
323 323 add changeset 911600dab2ae
324 324 adding manifests
325 325 adding file changes
326 326 adding foo/Bar/file.txt revisions
327 327 adding foo/file.txt revisions
328 328 adding quux/file.py revisions
329 329 added 3 changesets with 3 changes to 3 files
330 330 calling hook pretxnchangegroup.acl: hgext.acl.hook
331 331 acl: checking access for user "fred"
332 332 acl: acl.allow.branches not enabled
333 333 acl: acl.deny.branches not enabled
334 334 acl: acl.allow enabled, 0 entries for user fred
335 335 acl: acl.deny not enabled
336 336 acl: branch access granted: "ef1ea85a6374" on branch "default"
337 337 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
338 338 bundle2-input-part: total payload size 1606
339 339 bundle2-input-bundle: 3 parts total
340 340 transaction abort!
341 341 rollback completed
342 342 abort: acl: user "fred" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
343 343 no rollback information available
344 344 0:6675d58eff77
345 345
346 346
347 347 fred is allowed inside foo/
348 348
349 349 $ echo 'foo/** = fred' >> $config
350 350 $ do_push fred
351 351 Pushing as user fred
352 352 hgrc = """
353 353 [hooks]
354 354 pretxnchangegroup.acl = python:hgext.acl.hook
355 355 [acl]
356 356 sources = push
357 357 [acl.allow]
358 358 foo/** = fred
359 359 """
360 360 pushing to ../b
361 361 query 1; heads
362 362 searching for changes
363 363 all remote heads known locally
364 364 listing keys for "phases"
365 365 checking for updated bookmarks
366 366 listing keys for "bookmarks"
367 367 invalid branchheads cache (served): tip differs
368 368 listing keys for "bookmarks"
369 369 3 changesets found
370 370 list of changesets:
371 371 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
372 372 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
373 373 911600dab2ae7a9baff75958b84fe606851ce955
374 374 bundle2-output-bundle: "HG20", 4 parts total
375 375 bundle2-output-part: "replycaps" 155 bytes payload
376 376 bundle2-output-part: "check:heads" streamed payload
377 377 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
378 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
378 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
379 379 bundle2-input-bundle: with-transaction
380 380 bundle2-input-part: "replycaps" supported
381 381 bundle2-input-part: total payload size 155
382 382 bundle2-input-part: "check:heads" supported
383 383 bundle2-input-part: total payload size 20
384 384 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
385 385 adding changesets
386 386 add changeset ef1ea85a6374
387 387 add changeset f9cafe1212c8
388 388 add changeset 911600dab2ae
389 389 adding manifests
390 390 adding file changes
391 391 adding foo/Bar/file.txt revisions
392 392 adding foo/file.txt revisions
393 393 adding quux/file.py revisions
394 394 added 3 changesets with 3 changes to 3 files
395 395 calling hook pretxnchangegroup.acl: hgext.acl.hook
396 396 acl: checking access for user "fred"
397 397 acl: acl.allow.branches not enabled
398 398 acl: acl.deny.branches not enabled
399 399 acl: acl.allow enabled, 1 entries for user fred
400 400 acl: acl.deny not enabled
401 401 acl: branch access granted: "ef1ea85a6374" on branch "default"
402 402 acl: path access granted: "ef1ea85a6374"
403 403 acl: branch access granted: "f9cafe1212c8" on branch "default"
404 404 acl: path access granted: "f9cafe1212c8"
405 405 acl: branch access granted: "911600dab2ae" on branch "default"
406 406 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
407 407 bundle2-input-part: total payload size 1606
408 408 bundle2-input-bundle: 3 parts total
409 409 transaction abort!
410 410 rollback completed
411 411 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
412 412 no rollback information available
413 413 0:6675d58eff77
414 414
415 415
416 416 Empty [acl.deny]
417 417
418 418 $ echo '[acl.deny]' >> $config
419 419 $ do_push barney
420 420 Pushing as user barney
421 421 hgrc = """
422 422 [hooks]
423 423 pretxnchangegroup.acl = python:hgext.acl.hook
424 424 [acl]
425 425 sources = push
426 426 [acl.allow]
427 427 foo/** = fred
428 428 [acl.deny]
429 429 """
430 430 pushing to ../b
431 431 query 1; heads
432 432 searching for changes
433 433 all remote heads known locally
434 434 listing keys for "phases"
435 435 checking for updated bookmarks
436 436 listing keys for "bookmarks"
437 437 invalid branchheads cache (served): tip differs
438 438 listing keys for "bookmarks"
439 439 3 changesets found
440 440 list of changesets:
441 441 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
442 442 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
443 443 911600dab2ae7a9baff75958b84fe606851ce955
444 444 bundle2-output-bundle: "HG20", 4 parts total
445 445 bundle2-output-part: "replycaps" 155 bytes payload
446 446 bundle2-output-part: "check:heads" streamed payload
447 447 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
448 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
448 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
449 449 bundle2-input-bundle: with-transaction
450 450 bundle2-input-part: "replycaps" supported
451 451 bundle2-input-part: total payload size 155
452 452 bundle2-input-part: "check:heads" supported
453 453 bundle2-input-part: total payload size 20
454 454 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
455 455 adding changesets
456 456 add changeset ef1ea85a6374
457 457 add changeset f9cafe1212c8
458 458 add changeset 911600dab2ae
459 459 adding manifests
460 460 adding file changes
461 461 adding foo/Bar/file.txt revisions
462 462 adding foo/file.txt revisions
463 463 adding quux/file.py revisions
464 464 added 3 changesets with 3 changes to 3 files
465 465 calling hook pretxnchangegroup.acl: hgext.acl.hook
466 466 acl: checking access for user "barney"
467 467 acl: acl.allow.branches not enabled
468 468 acl: acl.deny.branches not enabled
469 469 acl: acl.allow enabled, 0 entries for user barney
470 470 acl: acl.deny enabled, 0 entries for user barney
471 471 acl: branch access granted: "ef1ea85a6374" on branch "default"
472 472 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
473 473 bundle2-input-part: total payload size 1606
474 474 bundle2-input-bundle: 3 parts total
475 475 transaction abort!
476 476 rollback completed
477 477 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
478 478 no rollback information available
479 479 0:6675d58eff77
480 480
481 481
482 482 fred is allowed inside foo/, but not foo/bar/ (case matters)
483 483
484 484 $ echo 'foo/bar/** = fred' >> $config
485 485 $ do_push fred
486 486 Pushing as user fred
487 487 hgrc = """
488 488 [hooks]
489 489 pretxnchangegroup.acl = python:hgext.acl.hook
490 490 [acl]
491 491 sources = push
492 492 [acl.allow]
493 493 foo/** = fred
494 494 [acl.deny]
495 495 foo/bar/** = fred
496 496 """
497 497 pushing to ../b
498 498 query 1; heads
499 499 searching for changes
500 500 all remote heads known locally
501 501 listing keys for "phases"
502 502 checking for updated bookmarks
503 503 listing keys for "bookmarks"
504 504 invalid branchheads cache (served): tip differs
505 505 listing keys for "bookmarks"
506 506 3 changesets found
507 507 list of changesets:
508 508 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
509 509 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
510 510 911600dab2ae7a9baff75958b84fe606851ce955
511 511 bundle2-output-bundle: "HG20", 4 parts total
512 512 bundle2-output-part: "replycaps" 155 bytes payload
513 513 bundle2-output-part: "check:heads" streamed payload
514 514 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
515 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
515 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
516 516 bundle2-input-bundle: with-transaction
517 517 bundle2-input-part: "replycaps" supported
518 518 bundle2-input-part: total payload size 155
519 519 bundle2-input-part: "check:heads" supported
520 520 bundle2-input-part: total payload size 20
521 521 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
522 522 adding changesets
523 523 add changeset ef1ea85a6374
524 524 add changeset f9cafe1212c8
525 525 add changeset 911600dab2ae
526 526 adding manifests
527 527 adding file changes
528 528 adding foo/Bar/file.txt revisions
529 529 adding foo/file.txt revisions
530 530 adding quux/file.py revisions
531 531 added 3 changesets with 3 changes to 3 files
532 532 calling hook pretxnchangegroup.acl: hgext.acl.hook
533 533 acl: checking access for user "fred"
534 534 acl: acl.allow.branches not enabled
535 535 acl: acl.deny.branches not enabled
536 536 acl: acl.allow enabled, 1 entries for user fred
537 537 acl: acl.deny enabled, 1 entries for user fred
538 538 acl: branch access granted: "ef1ea85a6374" on branch "default"
539 539 acl: path access granted: "ef1ea85a6374"
540 540 acl: branch access granted: "f9cafe1212c8" on branch "default"
541 541 acl: path access granted: "f9cafe1212c8"
542 542 acl: branch access granted: "911600dab2ae" on branch "default"
543 543 error: pretxnchangegroup.acl hook failed: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
544 544 bundle2-input-part: total payload size 1606
545 545 bundle2-input-bundle: 3 parts total
546 546 transaction abort!
547 547 rollback completed
548 548 abort: acl: user "fred" not allowed on "quux/file.py" (changeset "911600dab2ae")
549 549 no rollback information available
550 550 0:6675d58eff77
551 551
552 552
553 553 fred is allowed inside foo/, but not foo/Bar/
554 554
555 555 $ echo 'foo/Bar/** = fred' >> $config
556 556 $ do_push fred
557 557 Pushing as user fred
558 558 hgrc = """
559 559 [hooks]
560 560 pretxnchangegroup.acl = python:hgext.acl.hook
561 561 [acl]
562 562 sources = push
563 563 [acl.allow]
564 564 foo/** = fred
565 565 [acl.deny]
566 566 foo/bar/** = fred
567 567 foo/Bar/** = fred
568 568 """
569 569 pushing to ../b
570 570 query 1; heads
571 571 searching for changes
572 572 all remote heads known locally
573 573 listing keys for "phases"
574 574 checking for updated bookmarks
575 575 listing keys for "bookmarks"
576 576 invalid branchheads cache (served): tip differs
577 577 listing keys for "bookmarks"
578 578 3 changesets found
579 579 list of changesets:
580 580 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
581 581 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
582 582 911600dab2ae7a9baff75958b84fe606851ce955
583 583 bundle2-output-bundle: "HG20", 4 parts total
584 584 bundle2-output-part: "replycaps" 155 bytes payload
585 585 bundle2-output-part: "check:heads" streamed payload
586 586 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
587 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
587 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
588 588 bundle2-input-bundle: with-transaction
589 589 bundle2-input-part: "replycaps" supported
590 590 bundle2-input-part: total payload size 155
591 591 bundle2-input-part: "check:heads" supported
592 592 bundle2-input-part: total payload size 20
593 593 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
594 594 adding changesets
595 595 add changeset ef1ea85a6374
596 596 add changeset f9cafe1212c8
597 597 add changeset 911600dab2ae
598 598 adding manifests
599 599 adding file changes
600 600 adding foo/Bar/file.txt revisions
601 601 adding foo/file.txt revisions
602 602 adding quux/file.py revisions
603 603 added 3 changesets with 3 changes to 3 files
604 604 calling hook pretxnchangegroup.acl: hgext.acl.hook
605 605 acl: checking access for user "fred"
606 606 acl: acl.allow.branches not enabled
607 607 acl: acl.deny.branches not enabled
608 608 acl: acl.allow enabled, 1 entries for user fred
609 609 acl: acl.deny enabled, 2 entries for user fred
610 610 acl: branch access granted: "ef1ea85a6374" on branch "default"
611 611 acl: path access granted: "ef1ea85a6374"
612 612 acl: branch access granted: "f9cafe1212c8" on branch "default"
613 613 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
614 614 bundle2-input-part: total payload size 1606
615 615 bundle2-input-bundle: 3 parts total
616 616 transaction abort!
617 617 rollback completed
618 618 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
619 619 no rollback information available
620 620 0:6675d58eff77
621 621
622 622
623 623 $ echo 'barney is not mentioned => not allowed anywhere'
624 624 barney is not mentioned => not allowed anywhere
625 625 $ do_push barney
626 626 Pushing as user barney
627 627 hgrc = """
628 628 [hooks]
629 629 pretxnchangegroup.acl = python:hgext.acl.hook
630 630 [acl]
631 631 sources = push
632 632 [acl.allow]
633 633 foo/** = fred
634 634 [acl.deny]
635 635 foo/bar/** = fred
636 636 foo/Bar/** = fred
637 637 """
638 638 pushing to ../b
639 639 query 1; heads
640 640 searching for changes
641 641 all remote heads known locally
642 642 listing keys for "phases"
643 643 checking for updated bookmarks
644 644 listing keys for "bookmarks"
645 645 invalid branchheads cache (served): tip differs
646 646 listing keys for "bookmarks"
647 647 3 changesets found
648 648 list of changesets:
649 649 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
650 650 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
651 651 911600dab2ae7a9baff75958b84fe606851ce955
652 652 bundle2-output-bundle: "HG20", 4 parts total
653 653 bundle2-output-part: "replycaps" 155 bytes payload
654 654 bundle2-output-part: "check:heads" streamed payload
655 655 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
656 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
656 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
657 657 bundle2-input-bundle: with-transaction
658 658 bundle2-input-part: "replycaps" supported
659 659 bundle2-input-part: total payload size 155
660 660 bundle2-input-part: "check:heads" supported
661 661 bundle2-input-part: total payload size 20
662 662 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
663 663 adding changesets
664 664 add changeset ef1ea85a6374
665 665 add changeset f9cafe1212c8
666 666 add changeset 911600dab2ae
667 667 adding manifests
668 668 adding file changes
669 669 adding foo/Bar/file.txt revisions
670 670 adding foo/file.txt revisions
671 671 adding quux/file.py revisions
672 672 added 3 changesets with 3 changes to 3 files
673 673 calling hook pretxnchangegroup.acl: hgext.acl.hook
674 674 acl: checking access for user "barney"
675 675 acl: acl.allow.branches not enabled
676 676 acl: acl.deny.branches not enabled
677 677 acl: acl.allow enabled, 0 entries for user barney
678 678 acl: acl.deny enabled, 0 entries for user barney
679 679 acl: branch access granted: "ef1ea85a6374" on branch "default"
680 680 error: pretxnchangegroup.acl hook failed: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
681 681 bundle2-input-part: total payload size 1606
682 682 bundle2-input-bundle: 3 parts total
683 683 transaction abort!
684 684 rollback completed
685 685 abort: acl: user "barney" not allowed on "foo/file.txt" (changeset "ef1ea85a6374")
686 686 no rollback information available
687 687 0:6675d58eff77
688 688
689 689
690 690 barney is allowed everywhere
691 691
692 692 $ echo '[acl.allow]' >> $config
693 693 $ echo '** = barney' >> $config
694 694 $ do_push barney
695 695 Pushing as user barney
696 696 hgrc = """
697 697 [hooks]
698 698 pretxnchangegroup.acl = python:hgext.acl.hook
699 699 [acl]
700 700 sources = push
701 701 [acl.allow]
702 702 foo/** = fred
703 703 [acl.deny]
704 704 foo/bar/** = fred
705 705 foo/Bar/** = fred
706 706 [acl.allow]
707 707 ** = barney
708 708 """
709 709 pushing to ../b
710 710 query 1; heads
711 711 searching for changes
712 712 all remote heads known locally
713 713 listing keys for "phases"
714 714 checking for updated bookmarks
715 715 listing keys for "bookmarks"
716 716 invalid branchheads cache (served): tip differs
717 717 listing keys for "bookmarks"
718 718 3 changesets found
719 719 list of changesets:
720 720 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
721 721 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
722 722 911600dab2ae7a9baff75958b84fe606851ce955
723 723 bundle2-output-bundle: "HG20", 4 parts total
724 724 bundle2-output-part: "replycaps" 155 bytes payload
725 725 bundle2-output-part: "check:heads" streamed payload
726 726 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
727 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
727 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
728 728 bundle2-input-bundle: with-transaction
729 729 bundle2-input-part: "replycaps" supported
730 730 bundle2-input-part: total payload size 155
731 731 bundle2-input-part: "check:heads" supported
732 732 bundle2-input-part: total payload size 20
733 733 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
734 734 adding changesets
735 735 add changeset ef1ea85a6374
736 736 add changeset f9cafe1212c8
737 737 add changeset 911600dab2ae
738 738 adding manifests
739 739 adding file changes
740 740 adding foo/Bar/file.txt revisions
741 741 adding foo/file.txt revisions
742 742 adding quux/file.py revisions
743 743 added 3 changesets with 3 changes to 3 files
744 744 calling hook pretxnchangegroup.acl: hgext.acl.hook
745 745 acl: checking access for user "barney"
746 746 acl: acl.allow.branches not enabled
747 747 acl: acl.deny.branches not enabled
748 748 acl: acl.allow enabled, 1 entries for user barney
749 749 acl: acl.deny enabled, 0 entries for user barney
750 750 acl: branch access granted: "ef1ea85a6374" on branch "default"
751 751 acl: path access granted: "ef1ea85a6374"
752 752 acl: branch access granted: "f9cafe1212c8" on branch "default"
753 753 acl: path access granted: "f9cafe1212c8"
754 754 acl: branch access granted: "911600dab2ae" on branch "default"
755 755 acl: path access granted: "911600dab2ae"
756 756 bundle2-input-part: total payload size 1606
757 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
757 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
758 758 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
759 759 bundle2-input-bundle: 3 parts total
760 760 updating the branch cache
761 761 bundle2-output-bundle: "HG20", 2 parts total
762 762 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
763 763 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
764 764 bundle2-input-bundle: with-transaction
765 765 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
766 766 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
767 767 bundle2-input-bundle: 1 parts total
768 768 listing keys for "phases"
769 769 try to push obsolete markers to remote
770 770 repository tip rolled back to revision 0 (undo push)
771 771 0:6675d58eff77
772 772
773 773
774 774 wilma can change files with a .txt extension
775 775
776 776 $ echo '**/*.txt = wilma' >> $config
777 777 $ do_push wilma
778 778 Pushing as user wilma
779 779 hgrc = """
780 780 [hooks]
781 781 pretxnchangegroup.acl = python:hgext.acl.hook
782 782 [acl]
783 783 sources = push
784 784 [acl.allow]
785 785 foo/** = fred
786 786 [acl.deny]
787 787 foo/bar/** = fred
788 788 foo/Bar/** = fred
789 789 [acl.allow]
790 790 ** = barney
791 791 **/*.txt = wilma
792 792 """
793 793 pushing to ../b
794 794 query 1; heads
795 795 searching for changes
796 796 all remote heads known locally
797 797 listing keys for "phases"
798 798 checking for updated bookmarks
799 799 listing keys for "bookmarks"
800 800 invalid branchheads cache (served): tip differs
801 801 listing keys for "bookmarks"
802 802 3 changesets found
803 803 list of changesets:
804 804 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
805 805 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
806 806 911600dab2ae7a9baff75958b84fe606851ce955
807 807 bundle2-output-bundle: "HG20", 4 parts total
808 808 bundle2-output-part: "replycaps" 155 bytes payload
809 809 bundle2-output-part: "check:heads" streamed payload
810 810 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
811 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
811 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
812 812 bundle2-input-bundle: with-transaction
813 813 bundle2-input-part: "replycaps" supported
814 814 bundle2-input-part: total payload size 155
815 815 bundle2-input-part: "check:heads" supported
816 816 bundle2-input-part: total payload size 20
817 817 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
818 818 adding changesets
819 819 add changeset ef1ea85a6374
820 820 add changeset f9cafe1212c8
821 821 add changeset 911600dab2ae
822 822 adding manifests
823 823 adding file changes
824 824 adding foo/Bar/file.txt revisions
825 825 adding foo/file.txt revisions
826 826 adding quux/file.py revisions
827 827 added 3 changesets with 3 changes to 3 files
828 828 calling hook pretxnchangegroup.acl: hgext.acl.hook
829 829 acl: checking access for user "wilma"
830 830 acl: acl.allow.branches not enabled
831 831 acl: acl.deny.branches not enabled
832 832 acl: acl.allow enabled, 1 entries for user wilma
833 833 acl: acl.deny enabled, 0 entries for user wilma
834 834 acl: branch access granted: "ef1ea85a6374" on branch "default"
835 835 acl: path access granted: "ef1ea85a6374"
836 836 acl: branch access granted: "f9cafe1212c8" on branch "default"
837 837 acl: path access granted: "f9cafe1212c8"
838 838 acl: branch access granted: "911600dab2ae" on branch "default"
839 839 error: pretxnchangegroup.acl hook failed: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
840 840 bundle2-input-part: total payload size 1606
841 841 bundle2-input-bundle: 3 parts total
842 842 transaction abort!
843 843 rollback completed
844 844 abort: acl: user "wilma" not allowed on "quux/file.py" (changeset "911600dab2ae")
845 845 no rollback information available
846 846 0:6675d58eff77
847 847
848 848
849 849 file specified by acl.config does not exist
850 850
851 851 $ echo '[acl]' >> $config
852 852 $ echo 'config = ../acl.config' >> $config
853 853 $ do_push barney
854 854 Pushing as user barney
855 855 hgrc = """
856 856 [hooks]
857 857 pretxnchangegroup.acl = python:hgext.acl.hook
858 858 [acl]
859 859 sources = push
860 860 [acl.allow]
861 861 foo/** = fred
862 862 [acl.deny]
863 863 foo/bar/** = fred
864 864 foo/Bar/** = fred
865 865 [acl.allow]
866 866 ** = barney
867 867 **/*.txt = wilma
868 868 [acl]
869 869 config = ../acl.config
870 870 """
871 871 pushing to ../b
872 872 query 1; heads
873 873 searching for changes
874 874 all remote heads known locally
875 875 listing keys for "phases"
876 876 checking for updated bookmarks
877 877 listing keys for "bookmarks"
878 878 invalid branchheads cache (served): tip differs
879 879 listing keys for "bookmarks"
880 880 3 changesets found
881 881 list of changesets:
882 882 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
883 883 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
884 884 911600dab2ae7a9baff75958b84fe606851ce955
885 885 bundle2-output-bundle: "HG20", 4 parts total
886 886 bundle2-output-part: "replycaps" 155 bytes payload
887 887 bundle2-output-part: "check:heads" streamed payload
888 888 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
889 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
889 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
890 890 bundle2-input-bundle: with-transaction
891 891 bundle2-input-part: "replycaps" supported
892 892 bundle2-input-part: total payload size 155
893 893 bundle2-input-part: "check:heads" supported
894 894 bundle2-input-part: total payload size 20
895 895 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
896 896 adding changesets
897 897 add changeset ef1ea85a6374
898 898 add changeset f9cafe1212c8
899 899 add changeset 911600dab2ae
900 900 adding manifests
901 901 adding file changes
902 902 adding foo/Bar/file.txt revisions
903 903 adding foo/file.txt revisions
904 904 adding quux/file.py revisions
905 905 added 3 changesets with 3 changes to 3 files
906 906 calling hook pretxnchangegroup.acl: hgext.acl.hook
907 907 acl: checking access for user "barney"
908 908 error: pretxnchangegroup.acl hook raised an exception: [Errno 2] No such file or directory: '../acl.config'
909 909 bundle2-input-part: total payload size 1606
910 910 bundle2-input-bundle: 3 parts total
911 911 transaction abort!
912 912 rollback completed
913 913 abort: No such file or directory: ../acl.config
914 914 no rollback information available
915 915 0:6675d58eff77
916 916
917 917
918 918 betty is allowed inside foo/ by a acl.config file
919 919
920 920 $ echo '[acl.allow]' >> acl.config
921 921 $ echo 'foo/** = betty' >> acl.config
922 922 $ do_push betty
923 923 Pushing as user betty
924 924 hgrc = """
925 925 [hooks]
926 926 pretxnchangegroup.acl = python:hgext.acl.hook
927 927 [acl]
928 928 sources = push
929 929 [acl.allow]
930 930 foo/** = fred
931 931 [acl.deny]
932 932 foo/bar/** = fred
933 933 foo/Bar/** = fred
934 934 [acl.allow]
935 935 ** = barney
936 936 **/*.txt = wilma
937 937 [acl]
938 938 config = ../acl.config
939 939 """
940 940 acl.config = """
941 941 [acl.allow]
942 942 foo/** = betty
943 943 """
944 944 pushing to ../b
945 945 query 1; heads
946 946 searching for changes
947 947 all remote heads known locally
948 948 listing keys for "phases"
949 949 checking for updated bookmarks
950 950 listing keys for "bookmarks"
951 951 invalid branchheads cache (served): tip differs
952 952 listing keys for "bookmarks"
953 953 3 changesets found
954 954 list of changesets:
955 955 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
956 956 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
957 957 911600dab2ae7a9baff75958b84fe606851ce955
958 958 bundle2-output-bundle: "HG20", 4 parts total
959 959 bundle2-output-part: "replycaps" 155 bytes payload
960 960 bundle2-output-part: "check:heads" streamed payload
961 961 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
962 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
962 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
963 963 bundle2-input-bundle: with-transaction
964 964 bundle2-input-part: "replycaps" supported
965 965 bundle2-input-part: total payload size 155
966 966 bundle2-input-part: "check:heads" supported
967 967 bundle2-input-part: total payload size 20
968 968 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
969 969 adding changesets
970 970 add changeset ef1ea85a6374
971 971 add changeset f9cafe1212c8
972 972 add changeset 911600dab2ae
973 973 adding manifests
974 974 adding file changes
975 975 adding foo/Bar/file.txt revisions
976 976 adding foo/file.txt revisions
977 977 adding quux/file.py revisions
978 978 added 3 changesets with 3 changes to 3 files
979 979 calling hook pretxnchangegroup.acl: hgext.acl.hook
980 980 acl: checking access for user "betty"
981 981 acl: acl.allow.branches not enabled
982 982 acl: acl.deny.branches not enabled
983 983 acl: acl.allow enabled, 1 entries for user betty
984 984 acl: acl.deny enabled, 0 entries for user betty
985 985 acl: branch access granted: "ef1ea85a6374" on branch "default"
986 986 acl: path access granted: "ef1ea85a6374"
987 987 acl: branch access granted: "f9cafe1212c8" on branch "default"
988 988 acl: path access granted: "f9cafe1212c8"
989 989 acl: branch access granted: "911600dab2ae" on branch "default"
990 990 error: pretxnchangegroup.acl hook failed: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
991 991 bundle2-input-part: total payload size 1606
992 992 bundle2-input-bundle: 3 parts total
993 993 transaction abort!
994 994 rollback completed
995 995 abort: acl: user "betty" not allowed on "quux/file.py" (changeset "911600dab2ae")
996 996 no rollback information available
997 997 0:6675d58eff77
998 998
999 999
1000 1000 acl.config can set only [acl.allow]/[acl.deny]
1001 1001
1002 1002 $ echo '[hooks]' >> acl.config
1003 1003 $ echo 'changegroup.acl = false' >> acl.config
1004 1004 $ do_push barney
1005 1005 Pushing as user barney
1006 1006 hgrc = """
1007 1007 [hooks]
1008 1008 pretxnchangegroup.acl = python:hgext.acl.hook
1009 1009 [acl]
1010 1010 sources = push
1011 1011 [acl.allow]
1012 1012 foo/** = fred
1013 1013 [acl.deny]
1014 1014 foo/bar/** = fred
1015 1015 foo/Bar/** = fred
1016 1016 [acl.allow]
1017 1017 ** = barney
1018 1018 **/*.txt = wilma
1019 1019 [acl]
1020 1020 config = ../acl.config
1021 1021 """
1022 1022 acl.config = """
1023 1023 [acl.allow]
1024 1024 foo/** = betty
1025 1025 [hooks]
1026 1026 changegroup.acl = false
1027 1027 """
1028 1028 pushing to ../b
1029 1029 query 1; heads
1030 1030 searching for changes
1031 1031 all remote heads known locally
1032 1032 listing keys for "phases"
1033 1033 checking for updated bookmarks
1034 1034 listing keys for "bookmarks"
1035 1035 invalid branchheads cache (served): tip differs
1036 1036 listing keys for "bookmarks"
1037 1037 3 changesets found
1038 1038 list of changesets:
1039 1039 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1040 1040 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1041 1041 911600dab2ae7a9baff75958b84fe606851ce955
1042 1042 bundle2-output-bundle: "HG20", 4 parts total
1043 1043 bundle2-output-part: "replycaps" 155 bytes payload
1044 1044 bundle2-output-part: "check:heads" streamed payload
1045 1045 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1046 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1046 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1047 1047 bundle2-input-bundle: with-transaction
1048 1048 bundle2-input-part: "replycaps" supported
1049 1049 bundle2-input-part: total payload size 155
1050 1050 bundle2-input-part: "check:heads" supported
1051 1051 bundle2-input-part: total payload size 20
1052 1052 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1053 1053 adding changesets
1054 1054 add changeset ef1ea85a6374
1055 1055 add changeset f9cafe1212c8
1056 1056 add changeset 911600dab2ae
1057 1057 adding manifests
1058 1058 adding file changes
1059 1059 adding foo/Bar/file.txt revisions
1060 1060 adding foo/file.txt revisions
1061 1061 adding quux/file.py revisions
1062 1062 added 3 changesets with 3 changes to 3 files
1063 1063 calling hook pretxnchangegroup.acl: hgext.acl.hook
1064 1064 acl: checking access for user "barney"
1065 1065 acl: acl.allow.branches not enabled
1066 1066 acl: acl.deny.branches not enabled
1067 1067 acl: acl.allow enabled, 1 entries for user barney
1068 1068 acl: acl.deny enabled, 0 entries for user barney
1069 1069 acl: branch access granted: "ef1ea85a6374" on branch "default"
1070 1070 acl: path access granted: "ef1ea85a6374"
1071 1071 acl: branch access granted: "f9cafe1212c8" on branch "default"
1072 1072 acl: path access granted: "f9cafe1212c8"
1073 1073 acl: branch access granted: "911600dab2ae" on branch "default"
1074 1074 acl: path access granted: "911600dab2ae"
1075 1075 bundle2-input-part: total payload size 1606
1076 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1076 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1077 1077 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1078 1078 bundle2-input-bundle: 3 parts total
1079 1079 updating the branch cache
1080 1080 bundle2-output-bundle: "HG20", 2 parts total
1081 1081 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1082 1082 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1083 1083 bundle2-input-bundle: with-transaction
1084 1084 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1085 1085 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1086 1086 bundle2-input-bundle: 1 parts total
1087 1087 listing keys for "phases"
1088 1088 try to push obsolete markers to remote
1089 1089 repository tip rolled back to revision 0 (undo push)
1090 1090 0:6675d58eff77
1091 1091
1092 1092
1093 1093 asterisk
1094 1094
1095 1095 $ init_config
1096 1096
1097 1097 asterisk test
1098 1098
1099 1099 $ echo '[acl.allow]' >> $config
1100 1100 $ echo "** = fred" >> $config
1101 1101
1102 1102 fred is always allowed
1103 1103
1104 1104 $ do_push fred
1105 1105 Pushing as user fred
1106 1106 hgrc = """
1107 1107 [hooks]
1108 1108 pretxnchangegroup.acl = python:hgext.acl.hook
1109 1109 [acl]
1110 1110 sources = push
1111 1111 [extensions]
1112 1112 [acl.allow]
1113 1113 ** = fred
1114 1114 """
1115 1115 pushing to ../b
1116 1116 query 1; heads
1117 1117 searching for changes
1118 1118 all remote heads known locally
1119 1119 listing keys for "phases"
1120 1120 checking for updated bookmarks
1121 1121 listing keys for "bookmarks"
1122 1122 invalid branchheads cache (served): tip differs
1123 1123 listing keys for "bookmarks"
1124 1124 3 changesets found
1125 1125 list of changesets:
1126 1126 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1127 1127 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1128 1128 911600dab2ae7a9baff75958b84fe606851ce955
1129 1129 bundle2-output-bundle: "HG20", 4 parts total
1130 1130 bundle2-output-part: "replycaps" 155 bytes payload
1131 1131 bundle2-output-part: "check:heads" streamed payload
1132 1132 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1133 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1133 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1134 1134 bundle2-input-bundle: with-transaction
1135 1135 bundle2-input-part: "replycaps" supported
1136 1136 bundle2-input-part: total payload size 155
1137 1137 bundle2-input-part: "check:heads" supported
1138 1138 bundle2-input-part: total payload size 20
1139 1139 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1140 1140 adding changesets
1141 1141 add changeset ef1ea85a6374
1142 1142 add changeset f9cafe1212c8
1143 1143 add changeset 911600dab2ae
1144 1144 adding manifests
1145 1145 adding file changes
1146 1146 adding foo/Bar/file.txt revisions
1147 1147 adding foo/file.txt revisions
1148 1148 adding quux/file.py revisions
1149 1149 added 3 changesets with 3 changes to 3 files
1150 1150 calling hook pretxnchangegroup.acl: hgext.acl.hook
1151 1151 acl: checking access for user "fred"
1152 1152 acl: acl.allow.branches not enabled
1153 1153 acl: acl.deny.branches not enabled
1154 1154 acl: acl.allow enabled, 1 entries for user fred
1155 1155 acl: acl.deny not enabled
1156 1156 acl: branch access granted: "ef1ea85a6374" on branch "default"
1157 1157 acl: path access granted: "ef1ea85a6374"
1158 1158 acl: branch access granted: "f9cafe1212c8" on branch "default"
1159 1159 acl: path access granted: "f9cafe1212c8"
1160 1160 acl: branch access granted: "911600dab2ae" on branch "default"
1161 1161 acl: path access granted: "911600dab2ae"
1162 1162 bundle2-input-part: total payload size 1606
1163 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1163 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1164 1164 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1165 1165 bundle2-input-bundle: 3 parts total
1166 1166 updating the branch cache
1167 1167 bundle2-output-bundle: "HG20", 2 parts total
1168 1168 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1169 1169 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1170 1170 bundle2-input-bundle: with-transaction
1171 1171 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1172 1172 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1173 1173 bundle2-input-bundle: 1 parts total
1174 1174 listing keys for "phases"
1175 1175 try to push obsolete markers to remote
1176 1176 repository tip rolled back to revision 0 (undo push)
1177 1177 0:6675d58eff77
1178 1178
1179 1179
1180 1180 $ echo '[acl.deny]' >> $config
1181 1181 $ echo "foo/Bar/** = *" >> $config
1182 1182
1183 1183 no one is allowed inside foo/Bar/
1184 1184
1185 1185 $ do_push fred
1186 1186 Pushing as user fred
1187 1187 hgrc = """
1188 1188 [hooks]
1189 1189 pretxnchangegroup.acl = python:hgext.acl.hook
1190 1190 [acl]
1191 1191 sources = push
1192 1192 [extensions]
1193 1193 [acl.allow]
1194 1194 ** = fred
1195 1195 [acl.deny]
1196 1196 foo/Bar/** = *
1197 1197 """
1198 1198 pushing to ../b
1199 1199 query 1; heads
1200 1200 searching for changes
1201 1201 all remote heads known locally
1202 1202 listing keys for "phases"
1203 1203 checking for updated bookmarks
1204 1204 listing keys for "bookmarks"
1205 1205 invalid branchheads cache (served): tip differs
1206 1206 listing keys for "bookmarks"
1207 1207 3 changesets found
1208 1208 list of changesets:
1209 1209 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1210 1210 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1211 1211 911600dab2ae7a9baff75958b84fe606851ce955
1212 1212 bundle2-output-bundle: "HG20", 4 parts total
1213 1213 bundle2-output-part: "replycaps" 155 bytes payload
1214 1214 bundle2-output-part: "check:heads" streamed payload
1215 1215 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1216 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1216 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1217 1217 bundle2-input-bundle: with-transaction
1218 1218 bundle2-input-part: "replycaps" supported
1219 1219 bundle2-input-part: total payload size 155
1220 1220 bundle2-input-part: "check:heads" supported
1221 1221 bundle2-input-part: total payload size 20
1222 1222 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1223 1223 adding changesets
1224 1224 add changeset ef1ea85a6374
1225 1225 add changeset f9cafe1212c8
1226 1226 add changeset 911600dab2ae
1227 1227 adding manifests
1228 1228 adding file changes
1229 1229 adding foo/Bar/file.txt revisions
1230 1230 adding foo/file.txt revisions
1231 1231 adding quux/file.py revisions
1232 1232 added 3 changesets with 3 changes to 3 files
1233 1233 calling hook pretxnchangegroup.acl: hgext.acl.hook
1234 1234 acl: checking access for user "fred"
1235 1235 acl: acl.allow.branches not enabled
1236 1236 acl: acl.deny.branches not enabled
1237 1237 acl: acl.allow enabled, 1 entries for user fred
1238 1238 acl: acl.deny enabled, 1 entries for user fred
1239 1239 acl: branch access granted: "ef1ea85a6374" on branch "default"
1240 1240 acl: path access granted: "ef1ea85a6374"
1241 1241 acl: branch access granted: "f9cafe1212c8" on branch "default"
1242 1242 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1243 1243 bundle2-input-part: total payload size 1606
1244 1244 bundle2-input-bundle: 3 parts total
1245 1245 transaction abort!
1246 1246 rollback completed
1247 1247 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1248 1248 no rollback information available
1249 1249 0:6675d58eff77
1250 1250
1251 1251
1252 1252 Groups
1253 1253
1254 1254 $ init_config
1255 1255
1256 1256 OS-level groups
1257 1257
1258 1258 $ echo '[acl.allow]' >> $config
1259 1259 $ echo "** = @group1" >> $config
1260 1260
1261 1261 @group1 is always allowed
1262 1262
1263 1263 $ do_push fred
1264 1264 Pushing as user fred
1265 1265 hgrc = """
1266 1266 [hooks]
1267 1267 pretxnchangegroup.acl = python:hgext.acl.hook
1268 1268 [acl]
1269 1269 sources = push
1270 1270 [extensions]
1271 1271 [acl.allow]
1272 1272 ** = @group1
1273 1273 """
1274 1274 pushing to ../b
1275 1275 query 1; heads
1276 1276 searching for changes
1277 1277 all remote heads known locally
1278 1278 listing keys for "phases"
1279 1279 checking for updated bookmarks
1280 1280 listing keys for "bookmarks"
1281 1281 invalid branchheads cache (served): tip differs
1282 1282 listing keys for "bookmarks"
1283 1283 3 changesets found
1284 1284 list of changesets:
1285 1285 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1286 1286 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1287 1287 911600dab2ae7a9baff75958b84fe606851ce955
1288 1288 bundle2-output-bundle: "HG20", 4 parts total
1289 1289 bundle2-output-part: "replycaps" 155 bytes payload
1290 1290 bundle2-output-part: "check:heads" streamed payload
1291 1291 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1292 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1292 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1293 1293 bundle2-input-bundle: with-transaction
1294 1294 bundle2-input-part: "replycaps" supported
1295 1295 bundle2-input-part: total payload size 155
1296 1296 bundle2-input-part: "check:heads" supported
1297 1297 bundle2-input-part: total payload size 20
1298 1298 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1299 1299 adding changesets
1300 1300 add changeset ef1ea85a6374
1301 1301 add changeset f9cafe1212c8
1302 1302 add changeset 911600dab2ae
1303 1303 adding manifests
1304 1304 adding file changes
1305 1305 adding foo/Bar/file.txt revisions
1306 1306 adding foo/file.txt revisions
1307 1307 adding quux/file.py revisions
1308 1308 added 3 changesets with 3 changes to 3 files
1309 1309 calling hook pretxnchangegroup.acl: hgext.acl.hook
1310 1310 acl: checking access for user "fred"
1311 1311 acl: acl.allow.branches not enabled
1312 1312 acl: acl.deny.branches not enabled
1313 1313 acl: "group1" not defined in [acl.groups]
1314 1314 acl: acl.allow enabled, 1 entries for user fred
1315 1315 acl: acl.deny not enabled
1316 1316 acl: branch access granted: "ef1ea85a6374" on branch "default"
1317 1317 acl: path access granted: "ef1ea85a6374"
1318 1318 acl: branch access granted: "f9cafe1212c8" on branch "default"
1319 1319 acl: path access granted: "f9cafe1212c8"
1320 1320 acl: branch access granted: "911600dab2ae" on branch "default"
1321 1321 acl: path access granted: "911600dab2ae"
1322 1322 bundle2-input-part: total payload size 1606
1323 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1323 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1324 1324 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1325 1325 bundle2-input-bundle: 3 parts total
1326 1326 updating the branch cache
1327 1327 bundle2-output-bundle: "HG20", 2 parts total
1328 1328 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1329 1329 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1330 1330 bundle2-input-bundle: with-transaction
1331 1331 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1332 1332 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1333 1333 bundle2-input-bundle: 1 parts total
1334 1334 listing keys for "phases"
1335 1335 try to push obsolete markers to remote
1336 1336 repository tip rolled back to revision 0 (undo push)
1337 1337 0:6675d58eff77
1338 1338
1339 1339
1340 1340 $ echo '[acl.deny]' >> $config
1341 1341 $ echo "foo/Bar/** = @group1" >> $config
1342 1342
1343 1343 @group is allowed inside anything but foo/Bar/
1344 1344
1345 1345 $ do_push fred
1346 1346 Pushing as user fred
1347 1347 hgrc = """
1348 1348 [hooks]
1349 1349 pretxnchangegroup.acl = python:hgext.acl.hook
1350 1350 [acl]
1351 1351 sources = push
1352 1352 [extensions]
1353 1353 [acl.allow]
1354 1354 ** = @group1
1355 1355 [acl.deny]
1356 1356 foo/Bar/** = @group1
1357 1357 """
1358 1358 pushing to ../b
1359 1359 query 1; heads
1360 1360 searching for changes
1361 1361 all remote heads known locally
1362 1362 listing keys for "phases"
1363 1363 checking for updated bookmarks
1364 1364 listing keys for "bookmarks"
1365 1365 invalid branchheads cache (served): tip differs
1366 1366 listing keys for "bookmarks"
1367 1367 3 changesets found
1368 1368 list of changesets:
1369 1369 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1370 1370 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1371 1371 911600dab2ae7a9baff75958b84fe606851ce955
1372 1372 bundle2-output-bundle: "HG20", 4 parts total
1373 1373 bundle2-output-part: "replycaps" 155 bytes payload
1374 1374 bundle2-output-part: "check:heads" streamed payload
1375 1375 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1376 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1376 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1377 1377 bundle2-input-bundle: with-transaction
1378 1378 bundle2-input-part: "replycaps" supported
1379 1379 bundle2-input-part: total payload size 155
1380 1380 bundle2-input-part: "check:heads" supported
1381 1381 bundle2-input-part: total payload size 20
1382 1382 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1383 1383 adding changesets
1384 1384 add changeset ef1ea85a6374
1385 1385 add changeset f9cafe1212c8
1386 1386 add changeset 911600dab2ae
1387 1387 adding manifests
1388 1388 adding file changes
1389 1389 adding foo/Bar/file.txt revisions
1390 1390 adding foo/file.txt revisions
1391 1391 adding quux/file.py revisions
1392 1392 added 3 changesets with 3 changes to 3 files
1393 1393 calling hook pretxnchangegroup.acl: hgext.acl.hook
1394 1394 acl: checking access for user "fred"
1395 1395 acl: acl.allow.branches not enabled
1396 1396 acl: acl.deny.branches not enabled
1397 1397 acl: "group1" not defined in [acl.groups]
1398 1398 acl: acl.allow enabled, 1 entries for user fred
1399 1399 acl: "group1" not defined in [acl.groups]
1400 1400 acl: acl.deny enabled, 1 entries for user fred
1401 1401 acl: branch access granted: "ef1ea85a6374" on branch "default"
1402 1402 acl: path access granted: "ef1ea85a6374"
1403 1403 acl: branch access granted: "f9cafe1212c8" on branch "default"
1404 1404 error: pretxnchangegroup.acl hook failed: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1405 1405 bundle2-input-part: total payload size 1606
1406 1406 bundle2-input-bundle: 3 parts total
1407 1407 transaction abort!
1408 1408 rollback completed
1409 1409 abort: acl: user "fred" denied on "foo/Bar/file.txt" (changeset "f9cafe1212c8")
1410 1410 no rollback information available
1411 1411 0:6675d58eff77
1412 1412
1413 1413
1414 1414 Invalid group
1415 1415
1416 1416 Disable the fakegroups trick to get real failures
1417 1417
1418 1418 $ grep -v fakegroups $config > config.tmp
1419 1419 $ mv config.tmp $config
1420 1420 $ echo '[acl.allow]' >> $config
1421 1421 $ echo "** = @unlikelytoexist" >> $config
1422 1422 $ do_push fred 2>&1 | grep unlikelytoexist
1423 1423 ** = @unlikelytoexist
1424 1424 acl: "unlikelytoexist" not defined in [acl.groups]
1425 1425 error: pretxnchangegroup.acl hook failed: group 'unlikelytoexist' is undefined
1426 1426 abort: group 'unlikelytoexist' is undefined
1427 1427
1428 1428
1429 1429 Branch acl tests setup
1430 1430
1431 1431 $ init_config
1432 1432 $ cd b
1433 1433 $ hg up
1434 1434 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1435 1435 $ hg branch foobar
1436 1436 marked working directory as branch foobar
1437 1437 (branches are permanent and global, did you want a bookmark?)
1438 1438 $ hg commit -m 'create foobar'
1439 1439 $ echo 'foo contents' > abc.txt
1440 1440 $ hg add abc.txt
1441 1441 $ hg commit -m 'foobar contents'
1442 1442 $ cd ..
1443 1443 $ hg --cwd a pull ../b
1444 1444 pulling from ../b
1445 1445 searching for changes
1446 1446 adding changesets
1447 1447 adding manifests
1448 1448 adding file changes
1449 1449 added 2 changesets with 1 changes to 1 files (+1 heads)
1450 1450 (run 'hg heads' to see heads)
1451 1451
1452 1452 Create additional changeset on foobar branch
1453 1453
1454 1454 $ cd a
1455 1455 $ hg up -C foobar
1456 1456 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
1457 1457 $ echo 'foo contents2' > abc.txt
1458 1458 $ hg commit -m 'foobar contents2'
1459 1459 $ cd ..
1460 1460
1461 1461
1462 1462 No branch acls specified
1463 1463
1464 1464 $ do_push astro
1465 1465 Pushing as user astro
1466 1466 hgrc = """
1467 1467 [hooks]
1468 1468 pretxnchangegroup.acl = python:hgext.acl.hook
1469 1469 [acl]
1470 1470 sources = push
1471 1471 [extensions]
1472 1472 """
1473 1473 pushing to ../b
1474 1474 query 1; heads
1475 1475 searching for changes
1476 1476 all remote heads known locally
1477 1477 listing keys for "phases"
1478 1478 checking for updated bookmarks
1479 1479 listing keys for "bookmarks"
1480 1480 listing keys for "bookmarks"
1481 1481 4 changesets found
1482 1482 list of changesets:
1483 1483 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1484 1484 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1485 1485 911600dab2ae7a9baff75958b84fe606851ce955
1486 1486 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1487 1487 bundle2-output-bundle: "HG20", 5 parts total
1488 1488 bundle2-output-part: "replycaps" 155 bytes payload
1489 1489 bundle2-output-part: "check:heads" streamed payload
1490 1490 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1491 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1492 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1491 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1492 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1493 1493 bundle2-input-bundle: with-transaction
1494 1494 bundle2-input-part: "replycaps" supported
1495 1495 bundle2-input-part: total payload size 155
1496 1496 bundle2-input-part: "check:heads" supported
1497 1497 bundle2-input-part: total payload size 20
1498 1498 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1499 1499 adding changesets
1500 1500 add changeset ef1ea85a6374
1501 1501 add changeset f9cafe1212c8
1502 1502 add changeset 911600dab2ae
1503 1503 add changeset e8fc755d4d82
1504 1504 adding manifests
1505 1505 adding file changes
1506 1506 adding abc.txt revisions
1507 1507 adding foo/Bar/file.txt revisions
1508 1508 adding foo/file.txt revisions
1509 1509 adding quux/file.py revisions
1510 1510 added 4 changesets with 4 changes to 4 files (+1 heads)
1511 1511 calling hook pretxnchangegroup.acl: hgext.acl.hook
1512 1512 acl: checking access for user "astro"
1513 1513 acl: acl.allow.branches not enabled
1514 1514 acl: acl.deny.branches not enabled
1515 1515 acl: acl.allow not enabled
1516 1516 acl: acl.deny not enabled
1517 1517 acl: branch access granted: "ef1ea85a6374" on branch "default"
1518 1518 acl: path access granted: "ef1ea85a6374"
1519 1519 acl: branch access granted: "f9cafe1212c8" on branch "default"
1520 1520 acl: path access granted: "f9cafe1212c8"
1521 1521 acl: branch access granted: "911600dab2ae" on branch "default"
1522 1522 acl: path access granted: "911600dab2ae"
1523 1523 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1524 1524 acl: path access granted: "e8fc755d4d82"
1525 1525 bundle2-input-part: total payload size 2101
1526 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1526 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1527 1527 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1528 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1528 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1529 1529 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1530 1530 bundle2-input-bundle: 4 parts total
1531 1531 updating the branch cache
1532 1532 bundle2-output-bundle: "HG20", 3 parts total
1533 1533 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1534 1534 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1535 1535 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1536 1536 bundle2-input-bundle: with-transaction
1537 1537 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1538 1538 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1539 1539 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1540 1540 bundle2-input-bundle: 2 parts total
1541 1541 listing keys for "phases"
1542 1542 try to push obsolete markers to remote
1543 1543 repository tip rolled back to revision 2 (undo push)
1544 1544 2:fb35475503ef
1545 1545
1546 1546
1547 1547 Branch acl deny test
1548 1548
1549 1549 $ echo "[acl.deny.branches]" >> $config
1550 1550 $ echo "foobar = *" >> $config
1551 1551 $ do_push astro
1552 1552 Pushing as user astro
1553 1553 hgrc = """
1554 1554 [hooks]
1555 1555 pretxnchangegroup.acl = python:hgext.acl.hook
1556 1556 [acl]
1557 1557 sources = push
1558 1558 [extensions]
1559 1559 [acl.deny.branches]
1560 1560 foobar = *
1561 1561 """
1562 1562 pushing to ../b
1563 1563 query 1; heads
1564 1564 searching for changes
1565 1565 all remote heads known locally
1566 1566 listing keys for "phases"
1567 1567 checking for updated bookmarks
1568 1568 listing keys for "bookmarks"
1569 1569 listing keys for "bookmarks"
1570 1570 4 changesets found
1571 1571 list of changesets:
1572 1572 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1573 1573 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1574 1574 911600dab2ae7a9baff75958b84fe606851ce955
1575 1575 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1576 1576 bundle2-output-bundle: "HG20", 5 parts total
1577 1577 bundle2-output-part: "replycaps" 155 bytes payload
1578 1578 bundle2-output-part: "check:heads" streamed payload
1579 1579 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1580 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1581 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1580 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1581 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1582 1582 bundle2-input-bundle: with-transaction
1583 1583 bundle2-input-part: "replycaps" supported
1584 1584 bundle2-input-part: total payload size 155
1585 1585 bundle2-input-part: "check:heads" supported
1586 1586 bundle2-input-part: total payload size 20
1587 1587 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1588 1588 adding changesets
1589 1589 add changeset ef1ea85a6374
1590 1590 add changeset f9cafe1212c8
1591 1591 add changeset 911600dab2ae
1592 1592 add changeset e8fc755d4d82
1593 1593 adding manifests
1594 1594 adding file changes
1595 1595 adding abc.txt revisions
1596 1596 adding foo/Bar/file.txt revisions
1597 1597 adding foo/file.txt revisions
1598 1598 adding quux/file.py revisions
1599 1599 added 4 changesets with 4 changes to 4 files (+1 heads)
1600 1600 calling hook pretxnchangegroup.acl: hgext.acl.hook
1601 1601 acl: checking access for user "astro"
1602 1602 acl: acl.allow.branches not enabled
1603 1603 acl: acl.deny.branches enabled, 1 entries for user astro
1604 1604 acl: acl.allow not enabled
1605 1605 acl: acl.deny not enabled
1606 1606 acl: branch access granted: "ef1ea85a6374" on branch "default"
1607 1607 acl: path access granted: "ef1ea85a6374"
1608 1608 acl: branch access granted: "f9cafe1212c8" on branch "default"
1609 1609 acl: path access granted: "f9cafe1212c8"
1610 1610 acl: branch access granted: "911600dab2ae" on branch "default"
1611 1611 acl: path access granted: "911600dab2ae"
1612 1612 error: pretxnchangegroup.acl hook failed: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1613 1613 bundle2-input-part: total payload size 2101
1614 1614 bundle2-input-bundle: 4 parts total
1615 1615 transaction abort!
1616 1616 rollback completed
1617 1617 abort: acl: user "astro" denied on branch "foobar" (changeset "e8fc755d4d82")
1618 1618 no rollback information available
1619 1619 2:fb35475503ef
1620 1620
1621 1621
1622 1622 Branch acl empty allow test
1623 1623
1624 1624 $ init_config
1625 1625 $ echo "[acl.allow.branches]" >> $config
1626 1626 $ do_push astro
1627 1627 Pushing as user astro
1628 1628 hgrc = """
1629 1629 [hooks]
1630 1630 pretxnchangegroup.acl = python:hgext.acl.hook
1631 1631 [acl]
1632 1632 sources = push
1633 1633 [extensions]
1634 1634 [acl.allow.branches]
1635 1635 """
1636 1636 pushing to ../b
1637 1637 query 1; heads
1638 1638 searching for changes
1639 1639 all remote heads known locally
1640 1640 listing keys for "phases"
1641 1641 checking for updated bookmarks
1642 1642 listing keys for "bookmarks"
1643 1643 listing keys for "bookmarks"
1644 1644 4 changesets found
1645 1645 list of changesets:
1646 1646 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1647 1647 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1648 1648 911600dab2ae7a9baff75958b84fe606851ce955
1649 1649 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1650 1650 bundle2-output-bundle: "HG20", 5 parts total
1651 1651 bundle2-output-part: "replycaps" 155 bytes payload
1652 1652 bundle2-output-part: "check:heads" streamed payload
1653 1653 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1654 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1655 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1654 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1655 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1656 1656 bundle2-input-bundle: with-transaction
1657 1657 bundle2-input-part: "replycaps" supported
1658 1658 bundle2-input-part: total payload size 155
1659 1659 bundle2-input-part: "check:heads" supported
1660 1660 bundle2-input-part: total payload size 20
1661 1661 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1662 1662 adding changesets
1663 1663 add changeset ef1ea85a6374
1664 1664 add changeset f9cafe1212c8
1665 1665 add changeset 911600dab2ae
1666 1666 add changeset e8fc755d4d82
1667 1667 adding manifests
1668 1668 adding file changes
1669 1669 adding abc.txt revisions
1670 1670 adding foo/Bar/file.txt revisions
1671 1671 adding foo/file.txt revisions
1672 1672 adding quux/file.py revisions
1673 1673 added 4 changesets with 4 changes to 4 files (+1 heads)
1674 1674 calling hook pretxnchangegroup.acl: hgext.acl.hook
1675 1675 acl: checking access for user "astro"
1676 1676 acl: acl.allow.branches enabled, 0 entries for user astro
1677 1677 acl: acl.deny.branches not enabled
1678 1678 acl: acl.allow not enabled
1679 1679 acl: acl.deny not enabled
1680 1680 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1681 1681 bundle2-input-part: total payload size 2101
1682 1682 bundle2-input-bundle: 4 parts total
1683 1683 transaction abort!
1684 1684 rollback completed
1685 1685 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1686 1686 no rollback information available
1687 1687 2:fb35475503ef
1688 1688
1689 1689
1690 1690 Branch acl allow other
1691 1691
1692 1692 $ init_config
1693 1693 $ echo "[acl.allow.branches]" >> $config
1694 1694 $ echo "* = george" >> $config
1695 1695 $ do_push astro
1696 1696 Pushing as user astro
1697 1697 hgrc = """
1698 1698 [hooks]
1699 1699 pretxnchangegroup.acl = python:hgext.acl.hook
1700 1700 [acl]
1701 1701 sources = push
1702 1702 [extensions]
1703 1703 [acl.allow.branches]
1704 1704 * = george
1705 1705 """
1706 1706 pushing to ../b
1707 1707 query 1; heads
1708 1708 searching for changes
1709 1709 all remote heads known locally
1710 1710 listing keys for "phases"
1711 1711 checking for updated bookmarks
1712 1712 listing keys for "bookmarks"
1713 1713 listing keys for "bookmarks"
1714 1714 4 changesets found
1715 1715 list of changesets:
1716 1716 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1717 1717 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1718 1718 911600dab2ae7a9baff75958b84fe606851ce955
1719 1719 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1720 1720 bundle2-output-bundle: "HG20", 5 parts total
1721 1721 bundle2-output-part: "replycaps" 155 bytes payload
1722 1722 bundle2-output-part: "check:heads" streamed payload
1723 1723 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1724 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1725 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1724 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1725 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1726 1726 bundle2-input-bundle: with-transaction
1727 1727 bundle2-input-part: "replycaps" supported
1728 1728 bundle2-input-part: total payload size 155
1729 1729 bundle2-input-part: "check:heads" supported
1730 1730 bundle2-input-part: total payload size 20
1731 1731 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1732 1732 adding changesets
1733 1733 add changeset ef1ea85a6374
1734 1734 add changeset f9cafe1212c8
1735 1735 add changeset 911600dab2ae
1736 1736 add changeset e8fc755d4d82
1737 1737 adding manifests
1738 1738 adding file changes
1739 1739 adding abc.txt revisions
1740 1740 adding foo/Bar/file.txt revisions
1741 1741 adding foo/file.txt revisions
1742 1742 adding quux/file.py revisions
1743 1743 added 4 changesets with 4 changes to 4 files (+1 heads)
1744 1744 calling hook pretxnchangegroup.acl: hgext.acl.hook
1745 1745 acl: checking access for user "astro"
1746 1746 acl: acl.allow.branches enabled, 0 entries for user astro
1747 1747 acl: acl.deny.branches not enabled
1748 1748 acl: acl.allow not enabled
1749 1749 acl: acl.deny not enabled
1750 1750 error: pretxnchangegroup.acl hook failed: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1751 1751 bundle2-input-part: total payload size 2101
1752 1752 bundle2-input-bundle: 4 parts total
1753 1753 transaction abort!
1754 1754 rollback completed
1755 1755 abort: acl: user "astro" not allowed on branch "default" (changeset "ef1ea85a6374")
1756 1756 no rollback information available
1757 1757 2:fb35475503ef
1758 1758
1759 1759 $ do_push george
1760 1760 Pushing as user george
1761 1761 hgrc = """
1762 1762 [hooks]
1763 1763 pretxnchangegroup.acl = python:hgext.acl.hook
1764 1764 [acl]
1765 1765 sources = push
1766 1766 [extensions]
1767 1767 [acl.allow.branches]
1768 1768 * = george
1769 1769 """
1770 1770 pushing to ../b
1771 1771 query 1; heads
1772 1772 searching for changes
1773 1773 all remote heads known locally
1774 1774 listing keys for "phases"
1775 1775 checking for updated bookmarks
1776 1776 listing keys for "bookmarks"
1777 1777 listing keys for "bookmarks"
1778 1778 4 changesets found
1779 1779 list of changesets:
1780 1780 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1781 1781 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1782 1782 911600dab2ae7a9baff75958b84fe606851ce955
1783 1783 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1784 1784 bundle2-output-bundle: "HG20", 5 parts total
1785 1785 bundle2-output-part: "replycaps" 155 bytes payload
1786 1786 bundle2-output-part: "check:heads" streamed payload
1787 1787 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1788 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1789 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1788 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1789 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1790 1790 bundle2-input-bundle: with-transaction
1791 1791 bundle2-input-part: "replycaps" supported
1792 1792 bundle2-input-part: total payload size 155
1793 1793 bundle2-input-part: "check:heads" supported
1794 1794 bundle2-input-part: total payload size 20
1795 1795 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1796 1796 adding changesets
1797 1797 add changeset ef1ea85a6374
1798 1798 add changeset f9cafe1212c8
1799 1799 add changeset 911600dab2ae
1800 1800 add changeset e8fc755d4d82
1801 1801 adding manifests
1802 1802 adding file changes
1803 1803 adding abc.txt revisions
1804 1804 adding foo/Bar/file.txt revisions
1805 1805 adding foo/file.txt revisions
1806 1806 adding quux/file.py revisions
1807 1807 added 4 changesets with 4 changes to 4 files (+1 heads)
1808 1808 calling hook pretxnchangegroup.acl: hgext.acl.hook
1809 1809 acl: checking access for user "george"
1810 1810 acl: acl.allow.branches enabled, 1 entries for user george
1811 1811 acl: acl.deny.branches not enabled
1812 1812 acl: acl.allow not enabled
1813 1813 acl: acl.deny not enabled
1814 1814 acl: branch access granted: "ef1ea85a6374" on branch "default"
1815 1815 acl: path access granted: "ef1ea85a6374"
1816 1816 acl: branch access granted: "f9cafe1212c8" on branch "default"
1817 1817 acl: path access granted: "f9cafe1212c8"
1818 1818 acl: branch access granted: "911600dab2ae" on branch "default"
1819 1819 acl: path access granted: "911600dab2ae"
1820 1820 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1821 1821 acl: path access granted: "e8fc755d4d82"
1822 1822 bundle2-input-part: total payload size 2101
1823 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1823 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1824 1824 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1825 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1825 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1826 1826 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1827 1827 bundle2-input-bundle: 4 parts total
1828 1828 updating the branch cache
1829 1829 bundle2-output-bundle: "HG20", 3 parts total
1830 1830 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1831 1831 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1832 1832 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1833 1833 bundle2-input-bundle: with-transaction
1834 1834 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1835 1835 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1836 1836 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1837 1837 bundle2-input-bundle: 2 parts total
1838 1838 listing keys for "phases"
1839 1839 try to push obsolete markers to remote
1840 1840 repository tip rolled back to revision 2 (undo push)
1841 1841 2:fb35475503ef
1842 1842
1843 1843
1844 1844 Branch acl conflicting allow
1845 1845 asterisk ends up applying to all branches and allowing george to
1846 1846 push foobar into the remote
1847 1847
1848 1848 $ init_config
1849 1849 $ echo "[acl.allow.branches]" >> $config
1850 1850 $ echo "foobar = astro" >> $config
1851 1851 $ echo "* = george" >> $config
1852 1852 $ do_push george
1853 1853 Pushing as user george
1854 1854 hgrc = """
1855 1855 [hooks]
1856 1856 pretxnchangegroup.acl = python:hgext.acl.hook
1857 1857 [acl]
1858 1858 sources = push
1859 1859 [extensions]
1860 1860 [acl.allow.branches]
1861 1861 foobar = astro
1862 1862 * = george
1863 1863 """
1864 1864 pushing to ../b
1865 1865 query 1; heads
1866 1866 searching for changes
1867 1867 all remote heads known locally
1868 1868 listing keys for "phases"
1869 1869 checking for updated bookmarks
1870 1870 listing keys for "bookmarks"
1871 1871 listing keys for "bookmarks"
1872 1872 4 changesets found
1873 1873 list of changesets:
1874 1874 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1875 1875 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1876 1876 911600dab2ae7a9baff75958b84fe606851ce955
1877 1877 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1878 1878 bundle2-output-bundle: "HG20", 5 parts total
1879 1879 bundle2-output-part: "replycaps" 155 bytes payload
1880 1880 bundle2-output-part: "check:heads" streamed payload
1881 1881 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1882 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1883 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1882 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1883 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1884 1884 bundle2-input-bundle: with-transaction
1885 1885 bundle2-input-part: "replycaps" supported
1886 1886 bundle2-input-part: total payload size 155
1887 1887 bundle2-input-part: "check:heads" supported
1888 1888 bundle2-input-part: total payload size 20
1889 1889 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1890 1890 adding changesets
1891 1891 add changeset ef1ea85a6374
1892 1892 add changeset f9cafe1212c8
1893 1893 add changeset 911600dab2ae
1894 1894 add changeset e8fc755d4d82
1895 1895 adding manifests
1896 1896 adding file changes
1897 1897 adding abc.txt revisions
1898 1898 adding foo/Bar/file.txt revisions
1899 1899 adding foo/file.txt revisions
1900 1900 adding quux/file.py revisions
1901 1901 added 4 changesets with 4 changes to 4 files (+1 heads)
1902 1902 calling hook pretxnchangegroup.acl: hgext.acl.hook
1903 1903 acl: checking access for user "george"
1904 1904 acl: acl.allow.branches enabled, 1 entries for user george
1905 1905 acl: acl.deny.branches not enabled
1906 1906 acl: acl.allow not enabled
1907 1907 acl: acl.deny not enabled
1908 1908 acl: branch access granted: "ef1ea85a6374" on branch "default"
1909 1909 acl: path access granted: "ef1ea85a6374"
1910 1910 acl: branch access granted: "f9cafe1212c8" on branch "default"
1911 1911 acl: path access granted: "f9cafe1212c8"
1912 1912 acl: branch access granted: "911600dab2ae" on branch "default"
1913 1913 acl: path access granted: "911600dab2ae"
1914 1914 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
1915 1915 acl: path access granted: "e8fc755d4d82"
1916 1916 bundle2-input-part: total payload size 2101
1917 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1917 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1918 1918 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
1919 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
1919 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
1920 1920 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
1921 1921 bundle2-input-bundle: 4 parts total
1922 1922 updating the branch cache
1923 1923 bundle2-output-bundle: "HG20", 3 parts total
1924 1924 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
1925 1925 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1926 1926 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
1927 1927 bundle2-input-bundle: with-transaction
1928 1928 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
1929 1929 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1930 1930 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
1931 1931 bundle2-input-bundle: 2 parts total
1932 1932 listing keys for "phases"
1933 1933 try to push obsolete markers to remote
1934 1934 repository tip rolled back to revision 2 (undo push)
1935 1935 2:fb35475503ef
1936 1936
1937 1937 Branch acl conflicting deny
1938 1938
1939 1939 $ init_config
1940 1940 $ echo "[acl.deny.branches]" >> $config
1941 1941 $ echo "foobar = astro" >> $config
1942 1942 $ echo "default = astro" >> $config
1943 1943 $ echo "* = george" >> $config
1944 1944 $ do_push george
1945 1945 Pushing as user george
1946 1946 hgrc = """
1947 1947 [hooks]
1948 1948 pretxnchangegroup.acl = python:hgext.acl.hook
1949 1949 [acl]
1950 1950 sources = push
1951 1951 [extensions]
1952 1952 [acl.deny.branches]
1953 1953 foobar = astro
1954 1954 default = astro
1955 1955 * = george
1956 1956 """
1957 1957 pushing to ../b
1958 1958 query 1; heads
1959 1959 searching for changes
1960 1960 all remote heads known locally
1961 1961 listing keys for "phases"
1962 1962 checking for updated bookmarks
1963 1963 listing keys for "bookmarks"
1964 1964 listing keys for "bookmarks"
1965 1965 4 changesets found
1966 1966 list of changesets:
1967 1967 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
1968 1968 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
1969 1969 911600dab2ae7a9baff75958b84fe606851ce955
1970 1970 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
1971 1971 bundle2-output-bundle: "HG20", 5 parts total
1972 1972 bundle2-output-part: "replycaps" 155 bytes payload
1973 1973 bundle2-output-part: "check:heads" streamed payload
1974 1974 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
1975 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1976 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
1975 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1976 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
1977 1977 bundle2-input-bundle: with-transaction
1978 1978 bundle2-input-part: "replycaps" supported
1979 1979 bundle2-input-part: total payload size 155
1980 1980 bundle2-input-part: "check:heads" supported
1981 1981 bundle2-input-part: total payload size 20
1982 1982 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
1983 1983 adding changesets
1984 1984 add changeset ef1ea85a6374
1985 1985 add changeset f9cafe1212c8
1986 1986 add changeset 911600dab2ae
1987 1987 add changeset e8fc755d4d82
1988 1988 adding manifests
1989 1989 adding file changes
1990 1990 adding abc.txt revisions
1991 1991 adding foo/Bar/file.txt revisions
1992 1992 adding foo/file.txt revisions
1993 1993 adding quux/file.py revisions
1994 1994 added 4 changesets with 4 changes to 4 files (+1 heads)
1995 1995 calling hook pretxnchangegroup.acl: hgext.acl.hook
1996 1996 acl: checking access for user "george"
1997 1997 acl: acl.allow.branches not enabled
1998 1998 acl: acl.deny.branches enabled, 1 entries for user george
1999 1999 acl: acl.allow not enabled
2000 2000 acl: acl.deny not enabled
2001 2001 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2002 2002 bundle2-input-part: total payload size 2101
2003 2003 bundle2-input-bundle: 4 parts total
2004 2004 transaction abort!
2005 2005 rollback completed
2006 2006 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2007 2007 no rollback information available
2008 2008 2:fb35475503ef
2009 2009
2010 2010 User 'astro' must not be denied
2011 2011
2012 2012 $ init_config
2013 2013 $ echo "[acl.deny.branches]" >> $config
2014 2014 $ echo "default = !astro" >> $config
2015 2015 $ do_push astro
2016 2016 Pushing as user astro
2017 2017 hgrc = """
2018 2018 [hooks]
2019 2019 pretxnchangegroup.acl = python:hgext.acl.hook
2020 2020 [acl]
2021 2021 sources = push
2022 2022 [extensions]
2023 2023 [acl.deny.branches]
2024 2024 default = !astro
2025 2025 """
2026 2026 pushing to ../b
2027 2027 query 1; heads
2028 2028 searching for changes
2029 2029 all remote heads known locally
2030 2030 listing keys for "phases"
2031 2031 checking for updated bookmarks
2032 2032 listing keys for "bookmarks"
2033 2033 listing keys for "bookmarks"
2034 2034 4 changesets found
2035 2035 list of changesets:
2036 2036 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2037 2037 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2038 2038 911600dab2ae7a9baff75958b84fe606851ce955
2039 2039 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2040 2040 bundle2-output-bundle: "HG20", 5 parts total
2041 2041 bundle2-output-part: "replycaps" 155 bytes payload
2042 2042 bundle2-output-part: "check:heads" streamed payload
2043 2043 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2044 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2045 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2044 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2045 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2046 2046 bundle2-input-bundle: with-transaction
2047 2047 bundle2-input-part: "replycaps" supported
2048 2048 bundle2-input-part: total payload size 155
2049 2049 bundle2-input-part: "check:heads" supported
2050 2050 bundle2-input-part: total payload size 20
2051 2051 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2052 2052 adding changesets
2053 2053 add changeset ef1ea85a6374
2054 2054 add changeset f9cafe1212c8
2055 2055 add changeset 911600dab2ae
2056 2056 add changeset e8fc755d4d82
2057 2057 adding manifests
2058 2058 adding file changes
2059 2059 adding abc.txt revisions
2060 2060 adding foo/Bar/file.txt revisions
2061 2061 adding foo/file.txt revisions
2062 2062 adding quux/file.py revisions
2063 2063 added 4 changesets with 4 changes to 4 files (+1 heads)
2064 2064 calling hook pretxnchangegroup.acl: hgext.acl.hook
2065 2065 acl: checking access for user "astro"
2066 2066 acl: acl.allow.branches not enabled
2067 2067 acl: acl.deny.branches enabled, 0 entries for user astro
2068 2068 acl: acl.allow not enabled
2069 2069 acl: acl.deny not enabled
2070 2070 acl: branch access granted: "ef1ea85a6374" on branch "default"
2071 2071 acl: path access granted: "ef1ea85a6374"
2072 2072 acl: branch access granted: "f9cafe1212c8" on branch "default"
2073 2073 acl: path access granted: "f9cafe1212c8"
2074 2074 acl: branch access granted: "911600dab2ae" on branch "default"
2075 2075 acl: path access granted: "911600dab2ae"
2076 2076 acl: branch access granted: "e8fc755d4d82" on branch "foobar"
2077 2077 acl: path access granted: "e8fc755d4d82"
2078 2078 bundle2-input-part: total payload size 2101
2079 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2079 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2080 2080 pushing key for "phases:911600dab2ae7a9baff75958b84fe606851ce955"
2081 bundle2-input-part: "pushkey" (advisory) (params: 4 mandatory) supported
2081 bundle2-input-part: "pushkey" (params: 4 mandatory) supported
2082 2082 pushing key for "phases:e8fc755d4d8217ee5b0c2bb41558c40d43b92c01"
2083 2083 bundle2-input-bundle: 4 parts total
2084 2084 updating the branch cache
2085 2085 bundle2-output-bundle: "HG20", 3 parts total
2086 2086 bundle2-output-part: "reply:changegroup" (advisory) (params: 0 advisory) empty payload
2087 2087 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2088 2088 bundle2-output-part: "reply:pushkey" (params: 0 advisory) empty payload
2089 2089 bundle2-input-bundle: with-transaction
2090 2090 bundle2-input-part: "reply:changegroup" (advisory) (params: 0 advisory) supported
2091 2091 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2092 2092 bundle2-input-part: "reply:pushkey" (params: 0 advisory) supported
2093 2093 bundle2-input-bundle: 2 parts total
2094 2094 listing keys for "phases"
2095 2095 try to push obsolete markers to remote
2096 2096 repository tip rolled back to revision 2 (undo push)
2097 2097 2:fb35475503ef
2098 2098
2099 2099
2100 2100 Non-astro users must be denied
2101 2101
2102 2102 $ do_push george
2103 2103 Pushing as user george
2104 2104 hgrc = """
2105 2105 [hooks]
2106 2106 pretxnchangegroup.acl = python:hgext.acl.hook
2107 2107 [acl]
2108 2108 sources = push
2109 2109 [extensions]
2110 2110 [acl.deny.branches]
2111 2111 default = !astro
2112 2112 """
2113 2113 pushing to ../b
2114 2114 query 1; heads
2115 2115 searching for changes
2116 2116 all remote heads known locally
2117 2117 listing keys for "phases"
2118 2118 checking for updated bookmarks
2119 2119 listing keys for "bookmarks"
2120 2120 listing keys for "bookmarks"
2121 2121 4 changesets found
2122 2122 list of changesets:
2123 2123 ef1ea85a6374b77d6da9dcda9541f498f2d17df7
2124 2124 f9cafe1212c8c6fa1120d14a556e18cc44ff8bdd
2125 2125 911600dab2ae7a9baff75958b84fe606851ce955
2126 2126 e8fc755d4d8217ee5b0c2bb41558c40d43b92c01
2127 2127 bundle2-output-bundle: "HG20", 5 parts total
2128 2128 bundle2-output-part: "replycaps" 155 bytes payload
2129 2129 bundle2-output-part: "check:heads" streamed payload
2130 2130 bundle2-output-part: "changegroup" (params: 1 mandatory) streamed payload
2131 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2132 bundle2-output-part: "pushkey" (advisory) (params: 4 mandatory) empty payload
2131 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2132 bundle2-output-part: "pushkey" (params: 4 mandatory) empty payload
2133 2133 bundle2-input-bundle: with-transaction
2134 2134 bundle2-input-part: "replycaps" supported
2135 2135 bundle2-input-part: total payload size 155
2136 2136 bundle2-input-part: "check:heads" supported
2137 2137 bundle2-input-part: total payload size 20
2138 2138 bundle2-input-part: "changegroup" (params: 1 mandatory) supported
2139 2139 adding changesets
2140 2140 add changeset ef1ea85a6374
2141 2141 add changeset f9cafe1212c8
2142 2142 add changeset 911600dab2ae
2143 2143 add changeset e8fc755d4d82
2144 2144 adding manifests
2145 2145 adding file changes
2146 2146 adding abc.txt revisions
2147 2147 adding foo/Bar/file.txt revisions
2148 2148 adding foo/file.txt revisions
2149 2149 adding quux/file.py revisions
2150 2150 added 4 changesets with 4 changes to 4 files (+1 heads)
2151 2151 calling hook pretxnchangegroup.acl: hgext.acl.hook
2152 2152 acl: checking access for user "george"
2153 2153 acl: acl.allow.branches not enabled
2154 2154 acl: acl.deny.branches enabled, 1 entries for user george
2155 2155 acl: acl.allow not enabled
2156 2156 acl: acl.deny not enabled
2157 2157 error: pretxnchangegroup.acl hook failed: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2158 2158 bundle2-input-part: total payload size 2101
2159 2159 bundle2-input-bundle: 4 parts total
2160 2160 transaction abort!
2161 2161 rollback completed
2162 2162 abort: acl: user "george" denied on branch "default" (changeset "ef1ea85a6374")
2163 2163 no rollback information available
2164 2164 2:fb35475503ef
2165 2165
2166 2166
@@ -1,165 +1,171 b''
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 $ echo 'allow_push = *' >> .hg/hgrc
60 60 $ echo '[hooks]' >> .hg/hgrc
61 61 $ echo "changegroup = printenv.py changegroup 0" >> .hg/hgrc
62 62 $ echo "pushkey = printenv.py pushkey 0" >> .hg/hgrc
63 63 $ req
64 64 pushing to http://localhost:$HGPORT/
65 65 searching for changes
66 66 remote: adding changesets
67 67 remote: adding manifests
68 68 remote: adding file changes
69 69 remote: added 1 changesets with 1 changes to 1 files
70 70 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
71 71 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
72 72 % serve errors
73 73 $ hg rollback
74 74 repository tip rolled back to revision 0 (undo serve)
75 75
76 76 expect success, server lacks the httpheader capability
77 77
78 78 $ CAP=httpheader
79 79 $ . "$TESTDIR/notcapable"
80 80 $ req
81 81 pushing to http://localhost:$HGPORT/
82 82 searching for changes
83 83 remote: adding changesets
84 84 remote: adding manifests
85 85 remote: adding file changes
86 86 remote: added 1 changesets with 1 changes to 1 files
87 87 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
88 88 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
89 89 % serve errors
90 90 $ hg rollback
91 91 repository tip rolled back to revision 0 (undo serve)
92 92
93 93 expect success, server lacks the unbundlehash capability
94 94
95 95 $ CAP=unbundlehash
96 96 $ . "$TESTDIR/notcapable"
97 97 $ req
98 98 pushing to http://localhost:$HGPORT/
99 99 searching for changes
100 100 remote: adding changesets
101 101 remote: adding manifests
102 102 remote: adding file changes
103 103 remote: added 1 changesets with 1 changes to 1 files
104 104 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
105 105 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
106 106 % serve errors
107 107 $ hg rollback
108 108 repository tip rolled back to revision 0 (undo serve)
109 109
110 110 expect push success, phase change failure
111 111
112 112 $ cat > .hg/hgrc <<EOF
113 113 > [web]
114 114 > push_ssl = false
115 115 > allow_push = *
116 116 > [hooks]
117 117 > prepushkey = printenv.py prepushkey 1
118 118 > EOF
119 119 $ req
120 120 pushing to http://localhost:$HGPORT/
121 121 searching for changes
122 122 remote: adding changesets
123 123 remote: adding manifests
124 124 remote: adding file changes
125 125 remote: added 1 changesets with 1 changes to 1 files
126 126 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
127 127 remote: pushkey-abort: prepushkey hook exited with status 1
128 updating ba677d0156c1 to public failed!
128 remote: transaction abort!
129 remote: rollback completed
130 abort: updating ba677d0156c1 to public failed
129 131 % serve errors
132 [255]
130 133
131 134 expect phase change success
132 135
133 136 $ echo "prepushkey = printenv.py prepushkey 0" >> .hg/hgrc
134 137 $ req
135 138 pushing to http://localhost:$HGPORT/
136 139 searching for changes
137 no changes found
140 remote: adding changesets
141 remote: adding manifests
142 remote: adding file changes
143 remote: added 1 changesets with 1 changes to 1 files
144 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:127.0.0.1: (glob)
138 145 % serve errors
139 [1]
140 146 $ hg rollback
141 147 repository tip rolled back to revision 0 (undo serve)
142 148
143 149 expect authorization error: all users denied
144 150
145 151 $ echo '[web]' > .hg/hgrc
146 152 $ echo 'push_ssl = false' >> .hg/hgrc
147 153 $ echo 'deny_push = *' >> .hg/hgrc
148 154 $ req
149 155 pushing to http://localhost:$HGPORT/
150 156 searching for changes
151 157 abort: authorization failed
152 158 % serve errors
153 159 [255]
154 160
155 161 expect authorization error: some users denied, users must be authenticated
156 162
157 163 $ echo 'deny_push = unperson' >> .hg/hgrc
158 164 $ req
159 165 pushing to http://localhost:$HGPORT/
160 166 searching for changes
161 167 abort: authorization failed
162 168 % serve errors
163 169 [255]
164 170
165 171 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now