Mercurial > hg
comparison mercurial/changegroup.py @ 27867:7ced54ebf972
with: use context manager for transaction in changegroup apply
(This needs some line wrapping due to the additional indent level. -mpm)
author | Bryan O'Sullivan <bryano@fb.com> |
---|---|
date | Fri, 15 Jan 2016 13:14:50 -0800 |
parents | a09f143daaf4 |
children | da5f23362517 |
comparison
equal
deleted
inserted
replaced
27866:f54bf1f41566 | 27867:7ced54ebf972 |
---|---|
321 def revmap(x): | 321 def revmap(x): |
322 return cl.rev(x) | 322 return cl.rev(x) |
323 | 323 |
324 changesets = files = revisions = 0 | 324 changesets = files = revisions = 0 |
325 | 325 |
326 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)])) | |
327 try: | 326 try: |
328 # The transaction could have been created before and already | 327 with repo.transaction("\n".join([srctype, |
329 # carries source information. In this case we use the top | 328 util.hidepassword(url)])) as tr: |
330 # level data. We overwrite the argument because we need to use | 329 # The transaction could have been created before and already |
331 # the top level value (if they exist) in this function. | 330 # carries source information. In this case we use the top |
332 srctype = tr.hookargs.setdefault('source', srctype) | 331 # level data. We overwrite the argument because we need to use |
333 url = tr.hookargs.setdefault('url', url) | 332 # the top level value (if they exist) in this function. |
334 repo.hook('prechangegroup', throw=True, **tr.hookargs) | 333 srctype = tr.hookargs.setdefault('source', srctype) |
335 | 334 url = tr.hookargs.setdefault('url', url) |
336 # write changelog data to temp files so concurrent readers | 335 repo.hook('prechangegroup', throw=True, **tr.hookargs) |
337 # will not see an inconsistent view | 336 |
338 cl = repo.changelog | 337 # write changelog data to temp files so concurrent readers |
339 cl.delayupdate(tr) | 338 # will not see an inconsistent view |
340 oldheads = cl.heads() | 339 cl = repo.changelog |
341 | 340 cl.delayupdate(tr) |
342 trp = weakref.proxy(tr) | 341 oldheads = cl.heads() |
343 # pull off the changeset group | 342 |
344 repo.ui.status(_("adding changesets\n")) | 343 trp = weakref.proxy(tr) |
345 clstart = len(cl) | 344 # pull off the changeset group |
346 class prog(object): | 345 repo.ui.status(_("adding changesets\n")) |
347 def __init__(self, step, total): | 346 clstart = len(cl) |
348 self._step = step | 347 class prog(object): |
349 self._total = total | 348 def __init__(self, step, total): |
350 self._count = 1 | 349 self._step = step |
351 def __call__(self): | 350 self._total = total |
352 repo.ui.progress(self._step, self._count, unit=_('chunks'), | 351 self._count = 1 |
353 total=self._total) | 352 def __call__(self): |
354 self._count += 1 | 353 repo.ui.progress(self._step, self._count, |
355 self.callback = prog(_('changesets'), expectedtotal) | 354 unit=_('chunks'), total=self._total) |
356 | 355 self._count += 1 |
357 efiles = set() | 356 self.callback = prog(_('changesets'), expectedtotal) |
358 def onchangelog(cl, node): | 357 |
359 efiles.update(cl.read(node)[3]) | 358 efiles = set() |
360 | 359 def onchangelog(cl, node): |
361 self.changelogheader() | 360 efiles.update(cl.read(node)[3]) |
362 srccontent = cl.addgroup(self, csmap, trp, | 361 |
363 addrevisioncb=onchangelog) | 362 self.changelogheader() |
364 efiles = len(efiles) | 363 srccontent = cl.addgroup(self, csmap, trp, |
365 | 364 addrevisioncb=onchangelog) |
366 if not (srccontent or emptyok): | 365 efiles = len(efiles) |
367 raise error.Abort(_("received changelog group is empty")) | 366 |
368 clend = len(cl) | 367 if not (srccontent or emptyok): |
369 changesets = clend - clstart | 368 raise error.Abort(_("received changelog group is empty")) |
370 repo.ui.progress(_('changesets'), None) | 369 clend = len(cl) |
371 | 370 changesets = clend - clstart |
372 # pull off the manifest group | 371 repo.ui.progress(_('changesets'), None) |
373 repo.ui.status(_("adding manifests\n")) | 372 |
374 self._unpackmanifests(repo, revmap, trp, prog, changesets) | 373 # pull off the manifest group |
375 | 374 repo.ui.status(_("adding manifests\n")) |
376 needfiles = {} | 375 self._unpackmanifests(repo, revmap, trp, prog, changesets) |
377 if repo.ui.configbool('server', 'validate', default=False): | 376 |
378 # validate incoming csets have their manifests | 377 needfiles = {} |
379 for cset in xrange(clstart, clend): | 378 if repo.ui.configbool('server', 'validate', default=False): |
380 mfnode = repo.changelog.read(repo.changelog.node(cset))[0] | 379 # validate incoming csets have their manifests |
381 mfest = repo.manifest.readdelta(mfnode) | 380 for cset in xrange(clstart, clend): |
382 # store file nodes we must see | 381 mfnode = repo.changelog.read( |
383 for f, n in mfest.iteritems(): | 382 repo.changelog.node(cset))[0] |
384 needfiles.setdefault(f, set()).add(n) | 383 mfest = repo.manifest.readdelta(mfnode) |
385 | 384 # store file nodes we must see |
386 # process the files | 385 for f, n in mfest.iteritems(): |
387 repo.ui.status(_("adding file changes\n")) | 386 needfiles.setdefault(f, set()).add(n) |
388 self.callback = None | 387 |
389 pr = prog(_('files'), efiles) | 388 # process the files |
390 newrevs, newfiles = _addchangegroupfiles( | 389 repo.ui.status(_("adding file changes\n")) |
391 repo, self, revmap, trp, pr, needfiles) | 390 self.callback = None |
392 revisions += newrevs | 391 pr = prog(_('files'), efiles) |
393 files += newfiles | 392 newrevs, newfiles = _addchangegroupfiles( |
394 | 393 repo, self, revmap, trp, pr, needfiles) |
395 dh = 0 | 394 revisions += newrevs |
396 if oldheads: | 395 files += newfiles |
397 heads = cl.heads() | 396 |
398 dh = len(heads) - len(oldheads) | 397 dh = 0 |
399 for h in heads: | 398 if oldheads: |
400 if h not in oldheads and repo[h].closesbranch(): | 399 heads = cl.heads() |
401 dh -= 1 | 400 dh = len(heads) - len(oldheads) |
402 htext = "" | 401 for h in heads: |
403 if dh: | 402 if h not in oldheads and repo[h].closesbranch(): |
404 htext = _(" (%+d heads)") % dh | 403 dh -= 1 |
405 | 404 htext = "" |
406 repo.ui.status(_("added %d changesets" | 405 if dh: |
407 " with %d changes to %d files%s\n") | 406 htext = _(" (%+d heads)") % dh |
408 % (changesets, revisions, files, htext)) | 407 |
409 repo.invalidatevolatilesets() | 408 repo.ui.status(_("added %d changesets" |
410 | 409 " with %d changes to %d files%s\n") |
411 if changesets > 0: | 410 % (changesets, revisions, files, htext)) |
412 if 'node' not in tr.hookargs: | 411 repo.invalidatevolatilesets() |
413 tr.hookargs['node'] = hex(cl.node(clstart)) | 412 |
414 tr.hookargs['node_last'] = hex(cl.node(clend - 1)) | 413 if changesets > 0: |
415 hookargs = dict(tr.hookargs) | 414 if 'node' not in tr.hookargs: |
416 else: | 415 tr.hookargs['node'] = hex(cl.node(clstart)) |
417 hookargs = dict(tr.hookargs) | 416 tr.hookargs['node_last'] = hex(cl.node(clend - 1)) |
418 hookargs['node'] = hex(cl.node(clstart)) | 417 hookargs = dict(tr.hookargs) |
419 hookargs['node_last'] = hex(cl.node(clend - 1)) | 418 else: |
420 repo.hook('pretxnchangegroup', throw=True, **hookargs) | 419 hookargs = dict(tr.hookargs) |
421 | 420 hookargs['node'] = hex(cl.node(clstart)) |
422 added = [cl.node(r) for r in xrange(clstart, clend)] | 421 hookargs['node_last'] = hex(cl.node(clend - 1)) |
423 publishing = repo.publishing() | 422 repo.hook('pretxnchangegroup', throw=True, **hookargs) |
424 if srctype in ('push', 'serve'): | 423 |
425 # Old servers can not push the boundary themselves. | 424 added = [cl.node(r) for r in xrange(clstart, clend)] |
426 # New servers won't push the boundary if changeset already | 425 publishing = repo.publishing() |
427 # exists locally as secret | 426 if srctype in ('push', 'serve'): |
428 # | 427 # Old servers can not push the boundary themselves. |
429 # We should not use added here but the list of all change in | 428 # New servers won't push the boundary if changeset already |
430 # the bundle | 429 # exists locally as secret |
431 if publishing: | 430 # |
432 phases.advanceboundary(repo, tr, phases.public, srccontent) | 431 # We should not use added here but the list of all change in |
433 else: | 432 # the bundle |
434 # Those changesets have been pushed from the outside, their | 433 if publishing: |
435 # phases are going to be pushed alongside. Therefor | 434 phases.advanceboundary(repo, tr, phases.public, |
436 # `targetphase` is ignored. | 435 srccontent) |
437 phases.advanceboundary(repo, tr, phases.draft, srccontent) | 436 else: |
438 phases.retractboundary(repo, tr, phases.draft, added) | 437 # Those changesets have been pushed from the |
439 elif srctype != 'strip': | 438 # outside, their phases are going to be pushed |
440 # publishing only alter behavior during push | 439 # alongside. Therefor `targetphase` is |
441 # | 440 # ignored. |
442 # strip should not touch boundary at all | 441 phases.advanceboundary(repo, tr, phases.draft, |
443 phases.retractboundary(repo, tr, targetphase, added) | 442 srccontent) |
444 | 443 phases.retractboundary(repo, tr, phases.draft, added) |
445 if changesets > 0: | 444 elif srctype != 'strip': |
446 if srctype != 'strip': | 445 # publishing only alter behavior during push |
447 # During strip, branchcache is invalid but coming call to | 446 # |
448 # `destroyed` will repair it. | 447 # strip should not touch boundary at all |
449 # In other case we can safely update cache on disk. | 448 phases.retractboundary(repo, tr, targetphase, added) |
450 branchmap.updatecache(repo.filtered('served')) | 449 |
451 | 450 if changesets > 0: |
452 def runhooks(): | 451 if srctype != 'strip': |
453 # These hooks run when the lock releases, not when the | 452 # During strip, branchcache is invalid but |
454 # transaction closes. So it's possible for the changelog | 453 # coming call to `destroyed` will repair it. |
455 # to have changed since we last saw it. | 454 # In other case we can safely update cache on |
456 if clstart >= len(repo): | 455 # disk. |
457 return | 456 branchmap.updatecache(repo.filtered('served')) |
458 | 457 |
459 # forcefully update the on-disk branch cache | 458 def runhooks(): |
460 repo.ui.debug("updating the branch cache\n") | 459 # These hooks run when the lock releases, not when the |
461 repo.hook("changegroup", **hookargs) | 460 # transaction closes. So it's possible for the changelog |
462 | 461 # to have changed since we last saw it. |
463 for n in added: | 462 if clstart >= len(repo): |
464 args = hookargs.copy() | 463 return |
465 args['node'] = hex(n) | 464 |
466 del args['node_last'] | 465 # forcefully update the on-disk branch cache |
467 repo.hook("incoming", **args) | 466 repo.ui.debug("updating the branch cache\n") |
468 | 467 repo.hook("changegroup", **hookargs) |
469 newheads = [h for h in repo.heads() if h not in oldheads] | 468 |
470 repo.ui.log("incoming", | 469 for n in added: |
471 "%s incoming changes - new heads: %s\n", | 470 args = hookargs.copy() |
472 len(added), | 471 args['node'] = hex(n) |
473 ', '.join([hex(c[:6]) for c in newheads])) | 472 del args['node_last'] |
474 | 473 repo.hook("incoming", **args) |
475 tr.addpostclose('changegroup-runhooks-%020i' % clstart, | 474 |
476 lambda tr: repo._afterlock(runhooks)) | 475 newheads = [h for h in repo.heads() |
477 | 476 if h not in oldheads] |
478 tr.close() | 477 repo.ui.log("incoming", |
479 | 478 "%s incoming changes - new heads: %s\n", |
479 len(added), | |
480 ', '.join([hex(c[:6]) for c in newheads])) | |
481 | |
482 tr.addpostclose('changegroup-runhooks-%020i' % clstart, | |
483 lambda tr: repo._afterlock(runhooks)) | |
480 finally: | 484 finally: |
481 tr.release() | |
482 repo.ui.flush() | 485 repo.ui.flush() |
483 # never return 0 here: | 486 # never return 0 here: |
484 if dh < 0: | 487 if dh < 0: |
485 return dh - 1 | 488 return dh - 1 |
486 else: | 489 else: |