##// END OF EJS Templates
changegroup: migrate addchangegroup() to forward to cg?unpacker.apply()...
Augie Fackler -
r26695:1121fced default
parent child Browse files
Show More
@@ -267,6 +267,198 b' class cg1unpacker(object):'
267 pos = next
267 pos = next
268 yield closechunk()
268 yield closechunk()
269
269
270 def apply(self, repo, srctype, url, emptyok=False,
271 targetphase=phases.draft, expectedtotal=None):
272 """Add the changegroup returned by source.read() to this repo.
273 srctype is a string like 'push', 'pull', or 'unbundle'. url is
274 the URL of the repo where this changegroup is coming from.
275
276 Return an integer summarizing the change to this repo:
277 - nothing changed or no source: 0
278 - more heads than before: 1+added heads (2..n)
279 - fewer heads than before: -1-removed heads (-2..-n)
280 - number of heads stays the same: 1
281 """
282 repo = repo.unfiltered()
283 def csmap(x):
284 repo.ui.debug("add changeset %s\n" % short(x))
285 return len(cl)
286
287 def revmap(x):
288 return cl.rev(x)
289
290 changesets = files = revisions = 0
291
292 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
293 # The transaction could have been created before and already
294 # carries source information. In this case we use the top
295 # level data. We overwrite the argument because we need to use
296 # the top level value (if they exist) in this function.
297 srctype = tr.hookargs.setdefault('source', srctype)
298 url = tr.hookargs.setdefault('url', url)
299
300 # write changelog data to temp files so concurrent readers will not see
301 # inconsistent view
302 cl = repo.changelog
303 cl.delayupdate(tr)
304 oldheads = cl.heads()
305 try:
306 repo.hook('prechangegroup', throw=True, **tr.hookargs)
307
308 trp = weakref.proxy(tr)
309 # pull off the changeset group
310 repo.ui.status(_("adding changesets\n"))
311 clstart = len(cl)
312 class prog(object):
313 def __init__(self, step, total):
314 self._step = step
315 self._total = total
316 self._count = 1
317 def __call__(self):
318 repo.ui.progress(self._step, self._count, unit=_('chunks'),
319 total=self._total)
320 self._count += 1
321 self.callback = prog(_('changesets'), expectedtotal)
322
323 efiles = set()
324 def onchangelog(cl, node):
325 efiles.update(cl.read(node)[3])
326
327 self.changelogheader()
328 srccontent = cl.addgroup(self, csmap, trp,
329 addrevisioncb=onchangelog)
330 efiles = len(efiles)
331
332 if not (srccontent or emptyok):
333 raise error.Abort(_("received changelog group is empty"))
334 clend = len(cl)
335 changesets = clend - clstart
336 repo.ui.progress(_('changesets'), None)
337
338 # pull off the manifest group
339 repo.ui.status(_("adding manifests\n"))
340 # manifests <= changesets
341 self.callback = prog(_('manifests'), changesets)
342 # no need to check for empty manifest group here:
343 # if the result of the merge of 1 and 2 is the same in 3 and 4,
344 # no new manifest will be created and the manifest group will
345 # be empty during the pull
346 self.manifestheader()
347 repo.manifest.addgroup(self, revmap, trp)
348 repo.ui.progress(_('manifests'), None)
349
350 needfiles = {}
351 if repo.ui.configbool('server', 'validate', default=False):
352 # validate incoming csets have their manifests
353 for cset in xrange(clstart, clend):
354 mfnode = repo.changelog.read(repo.changelog.node(cset))[0]
355 mfest = repo.manifest.readdelta(mfnode)
356 # store file nodes we must see
357 for f, n in mfest.iteritems():
358 needfiles.setdefault(f, set()).add(n)
359
360 # process the files
361 repo.ui.status(_("adding file changes\n"))
362 self.callback = None
363 pr = prog(_('files'), efiles)
364 newrevs, newfiles = addchangegroupfiles(repo, self, revmap, trp, pr,
365 needfiles)
366 revisions += newrevs
367 files += newfiles
368
369 dh = 0
370 if oldheads:
371 heads = cl.heads()
372 dh = len(heads) - len(oldheads)
373 for h in heads:
374 if h not in oldheads and repo[h].closesbranch():
375 dh -= 1
376 htext = ""
377 if dh:
378 htext = _(" (%+d heads)") % dh
379
380 repo.ui.status(_("added %d changesets"
381 " with %d changes to %d files%s\n")
382 % (changesets, revisions, files, htext))
383 repo.invalidatevolatilesets()
384
385 if changesets > 0:
386 p = lambda: tr.writepending() and repo.root or ""
387 if 'node' not in tr.hookargs:
388 tr.hookargs['node'] = hex(cl.node(clstart))
389 hookargs = dict(tr.hookargs)
390 else:
391 hookargs = dict(tr.hookargs)
392 hookargs['node'] = hex(cl.node(clstart))
393 repo.hook('pretxnchangegroup', throw=True, pending=p,
394 **hookargs)
395
396 added = [cl.node(r) for r in xrange(clstart, clend)]
397 publishing = repo.publishing()
398 if srctype in ('push', 'serve'):
399 # Old servers can not push the boundary themselves.
400 # New servers won't push the boundary if changeset already
401 # exists locally as secret
402 #
403 # We should not use added here but the list of all change in
404 # the bundle
405 if publishing:
406 phases.advanceboundary(repo, tr, phases.public, srccontent)
407 else:
408 # Those changesets have been pushed from the outside, their
409 # phases are going to be pushed alongside. Therefor
410 # `targetphase` is ignored.
411 phases.advanceboundary(repo, tr, phases.draft, srccontent)
412 phases.retractboundary(repo, tr, phases.draft, added)
413 elif srctype != 'strip':
414 # publishing only alter behavior during push
415 #
416 # strip should not touch boundary at all
417 phases.retractboundary(repo, tr, targetphase, added)
418
419 if changesets > 0:
420 if srctype != 'strip':
421 # During strip, branchcache is invalid but coming call to
422 # `destroyed` will repair it.
423 # In other case we can safely update cache on disk.
424 branchmap.updatecache(repo.filtered('served'))
425
426 def runhooks():
427 # These hooks run when the lock releases, not when the
428 # transaction closes. So it's possible for the changelog
429 # to have changed since we last saw it.
430 if clstart >= len(repo):
431 return
432
433 # forcefully update the on-disk branch cache
434 repo.ui.debug("updating the branch cache\n")
435 repo.hook("changegroup", **hookargs)
436
437 for n in added:
438 args = hookargs.copy()
439 args['node'] = hex(n)
440 repo.hook("incoming", **args)
441
442 newheads = [h for h in repo.heads() if h not in oldheads]
443 repo.ui.log("incoming",
444 "%s incoming changes - new heads: %s\n",
445 len(added),
446 ', '.join([hex(c[:6]) for c in newheads]))
447
448 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
449 lambda tr: repo._afterlock(runhooks))
450
451 tr.close()
452
453 finally:
454 tr.release()
455 repo.ui.flush()
456 # never return 0 here:
457 if dh < 0:
458 return dh - 1
459 else:
460 return dh + 1
461
270 class cg2unpacker(cg1unpacker):
462 class cg2unpacker(cg1unpacker):
271 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
463 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
272 deltaheadersize = struct.calcsize(deltaheader)
464 deltaheadersize = struct.calcsize(deltaheader)
@@ -720,194 +912,9 b' def addchangegroupfiles(repo, source, re'
720
912
721 def addchangegroup(repo, source, srctype, url, emptyok=False,
913 def addchangegroup(repo, source, srctype, url, emptyok=False,
722 targetphase=phases.draft, expectedtotal=None):
914 targetphase=phases.draft, expectedtotal=None):
723 """Add the changegroup returned by source.read() to this repo.
915 """Legacy forwarding method to cg?unpacker.apply() to be removed soon."""
724 srctype is a string like 'push', 'pull', or 'unbundle'. url is
725 the URL of the repo where this changegroup is coming from.
726
727 Return an integer summarizing the change to this repo:
728 - nothing changed or no source: 0
729 - more heads than before: 1+added heads (2..n)
730 - fewer heads than before: -1-removed heads (-2..-n)
731 - number of heads stays the same: 1
732 """
733 if not source:
916 if not source:
734 return 0
917 return 0
735
918
736 repo = repo.unfiltered()
919 return source.apply(repo, srctype, url, emptyok=emptyok,
737 def csmap(x):
920 targetphase=targetphase, expectedtotal=expectedtotal)
738 repo.ui.debug("add changeset %s\n" % short(x))
739 return len(cl)
740
741 def revmap(x):
742 return cl.rev(x)
743
744 changesets = files = revisions = 0
745
746 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
747 # The transaction could have been created before and already carries source
748 # information. In this case we use the top level data. We overwrite the
749 # argument because we need to use the top level value (if they exist) in
750 # this function.
751 srctype = tr.hookargs.setdefault('source', srctype)
752 url = tr.hookargs.setdefault('url', url)
753
754 # write changelog data to temp files so concurrent readers will not see
755 # inconsistent view
756 cl = repo.changelog
757 cl.delayupdate(tr)
758 oldheads = cl.heads()
759 try:
760 repo.hook('prechangegroup', throw=True, **tr.hookargs)
761
762 trp = weakref.proxy(tr)
763 # pull off the changeset group
764 repo.ui.status(_("adding changesets\n"))
765 clstart = len(cl)
766 class prog(object):
767 def __init__(self, step, total):
768 self._step = step
769 self._total = total
770 self._count = 1
771 def __call__(self):
772 repo.ui.progress(self._step, self._count, unit=_('chunks'),
773 total=self._total)
774 self._count += 1
775 source.callback = prog(_('changesets'), expectedtotal)
776
777 efiles = set()
778 def onchangelog(cl, node):
779 efiles.update(cl.read(node)[3])
780
781 source.changelogheader()
782 srccontent = cl.addgroup(source, csmap, trp,
783 addrevisioncb=onchangelog)
784 efiles = len(efiles)
785
786 if not (srccontent or emptyok):
787 raise error.Abort(_("received changelog group is empty"))
788 clend = len(cl)
789 changesets = clend - clstart
790 repo.ui.progress(_('changesets'), None)
791
792 # pull off the manifest group
793 repo.ui.status(_("adding manifests\n"))
794 # manifests <= changesets
795 source.callback = prog(_('manifests'), changesets)
796 # no need to check for empty manifest group here:
797 # if the result of the merge of 1 and 2 is the same in 3 and 4,
798 # no new manifest will be created and the manifest group will
799 # be empty during the pull
800 source.manifestheader()
801 repo.manifest.addgroup(source, revmap, trp)
802 repo.ui.progress(_('manifests'), None)
803
804 needfiles = {}
805 if repo.ui.configbool('server', 'validate', default=False):
806 # validate incoming csets have their manifests
807 for cset in xrange(clstart, clend):
808 mfnode = repo.changelog.read(repo.changelog.node(cset))[0]
809 mfest = repo.manifest.readdelta(mfnode)
810 # store file nodes we must see
811 for f, n in mfest.iteritems():
812 needfiles.setdefault(f, set()).add(n)
813
814 # process the files
815 repo.ui.status(_("adding file changes\n"))
816 source.callback = None
817 pr = prog(_('files'), efiles)
818 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
819 needfiles)
820 revisions += newrevs
821 files += newfiles
822
823 dh = 0
824 if oldheads:
825 heads = cl.heads()
826 dh = len(heads) - len(oldheads)
827 for h in heads:
828 if h not in oldheads and repo[h].closesbranch():
829 dh -= 1
830 htext = ""
831 if dh:
832 htext = _(" (%+d heads)") % dh
833
834 repo.ui.status(_("added %d changesets"
835 " with %d changes to %d files%s\n")
836 % (changesets, revisions, files, htext))
837 repo.invalidatevolatilesets()
838
839 if changesets > 0:
840 p = lambda: tr.writepending() and repo.root or ""
841 if 'node' not in tr.hookargs:
842 tr.hookargs['node'] = hex(cl.node(clstart))
843 hookargs = dict(tr.hookargs)
844 else:
845 hookargs = dict(tr.hookargs)
846 hookargs['node'] = hex(cl.node(clstart))
847 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
848
849 added = [cl.node(r) for r in xrange(clstart, clend)]
850 publishing = repo.publishing()
851 if srctype in ('push', 'serve'):
852 # Old servers can not push the boundary themselves.
853 # New servers won't push the boundary if changeset already
854 # exists locally as secret
855 #
856 # We should not use added here but the list of all change in
857 # the bundle
858 if publishing:
859 phases.advanceboundary(repo, tr, phases.public, srccontent)
860 else:
861 # Those changesets have been pushed from the outside, their
862 # phases are going to be pushed alongside. Therefor
863 # `targetphase` is ignored.
864 phases.advanceboundary(repo, tr, phases.draft, srccontent)
865 phases.retractboundary(repo, tr, phases.draft, added)
866 elif srctype != 'strip':
867 # publishing only alter behavior during push
868 #
869 # strip should not touch boundary at all
870 phases.retractboundary(repo, tr, targetphase, added)
871
872 if changesets > 0:
873 if srctype != 'strip':
874 # During strip, branchcache is invalid but coming call to
875 # `destroyed` will repair it.
876 # In other case we can safely update cache on disk.
877 branchmap.updatecache(repo.filtered('served'))
878
879 def runhooks():
880 # These hooks run when the lock releases, not when the
881 # transaction closes. So it's possible for the changelog
882 # to have changed since we last saw it.
883 if clstart >= len(repo):
884 return
885
886 # forcefully update the on-disk branch cache
887 repo.ui.debug("updating the branch cache\n")
888 repo.hook("changegroup", **hookargs)
889
890 for n in added:
891 args = hookargs.copy()
892 args['node'] = hex(n)
893 repo.hook("incoming", **args)
894
895 newheads = [h for h in repo.heads() if h not in oldheads]
896 repo.ui.log("incoming",
897 "%s incoming changes - new heads: %s\n",
898 len(added),
899 ', '.join([hex(c[:6]) for c in newheads]))
900
901 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
902 lambda tr: repo._afterlock(runhooks))
903
904 tr.close()
905
906 finally:
907 tr.release()
908 repo.ui.flush()
909 # never return 0 here:
910 if dh < 0:
911 return dh - 1
912 else:
913 return dh + 1
General Comments 0
You need to be logged in to leave comments. Login now