comparison mercurial/changegroup.py @ 20933:d3775db748a0

localrepo: move the addchangegroup method in changegroup module This is a gratuitous code move aimed at reducing the localrepo bloatness. The method had few callers, not enough to be kept in local repo.
author Pierre-Yves David <pierre-yves.david@fb.com>
date Tue, 01 Apr 2014 15:27:53 -0700
parents 0ac83e4e4f7c
children 3737e653dcbe
comparison
equal deleted inserted replaced
20932:0ac83e4e4f7c 20933:d3775db748a0
3 # Copyright 2006 Matt Mackall <mpm@selenic.com> 3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 # 4 #
5 # This software may be used and distributed according to the terms of the 5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version. 6 # GNU General Public License version 2 or any later version.
7 7
8 import weakref
8 from i18n import _ 9 from i18n import _
9 from node import nullrev, nullid, hex 10 from node import nullrev, nullid, hex, short
10 import mdiff, util, dagutil 11 import mdiff, util, dagutil
11 import struct, os, bz2, zlib, tempfile 12 import struct, os, bz2, zlib, tempfile
12 import discovery, error 13 import discovery, error, phases, branchmap
13 14
14 _BUNDLE10_DELTA_HEADER = "20s20s20s20s" 15 _BUNDLE10_DELTA_HEADER = "20s20s20s20s"
15 16
16 def readexactly(stream, n): 17 def readexactly(stream, n):
17 '''read n bytes from stream.read and abort if less was available''' 18 '''read n bytes from stream.read and abort if less was available'''
552 raise util.Abort( 553 raise util.Abort(
553 _('missing file data for %s:%s - run hg verify') % 554 _('missing file data for %s:%s - run hg verify') %
554 (f, hex(n))) 555 (f, hex(n)))
555 556
556 return revisions, files 557 return revisions, files
558
559 def addchangegroup(repo, source, srctype, url, emptyok=False):
560 """Add the changegroup returned by source.read() to this repo.
561 srctype is a string like 'push', 'pull', or 'unbundle'. url is
562 the URL of the repo where this changegroup is coming from.
563
564 Return an integer summarizing the change to this repo:
565 - nothing changed or no source: 0
566 - more heads than before: 1+added heads (2..n)
567 - fewer heads than before: -1-removed heads (-2..-n)
568 - number of heads stays the same: 1
569 """
570 repo = repo.unfiltered()
571 def csmap(x):
572 repo.ui.debug("add changeset %s\n" % short(x))
573 return len(cl)
574
575 def revmap(x):
576 return cl.rev(x)
577
578 if not source:
579 return 0
580
581 repo.hook('prechangegroup', throw=True, source=srctype, url=url)
582
583 changesets = files = revisions = 0
584 efiles = set()
585
586 # write changelog data to temp files so concurrent readers will not see
587 # inconsistent view
588 cl = repo.changelog
589 cl.delayupdate()
590 oldheads = cl.heads()
591
592 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
593 try:
594 trp = weakref.proxy(tr)
595 # pull off the changeset group
596 repo.ui.status(_("adding changesets\n"))
597 clstart = len(cl)
598 class prog(object):
599 step = _('changesets')
600 count = 1
601 ui = repo.ui
602 total = None
603 def __call__(repo):
604 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
605 total=repo.total)
606 repo.count += 1
607 pr = prog()
608 source.callback = pr
609
610 source.changelogheader()
611 srccontent = cl.addgroup(source, csmap, trp)
612 if not (srccontent or emptyok):
613 raise util.Abort(_("received changelog group is empty"))
614 clend = len(cl)
615 changesets = clend - clstart
616 for c in xrange(clstart, clend):
617 efiles.update(repo[c].files())
618 efiles = len(efiles)
619 repo.ui.progress(_('changesets'), None)
620
621 # pull off the manifest group
622 repo.ui.status(_("adding manifests\n"))
623 pr.step = _('manifests')
624 pr.count = 1
625 pr.total = changesets # manifests <= changesets
626 # no need to check for empty manifest group here:
627 # if the result of the merge of 1 and 2 is the same in 3 and 4,
628 # no new manifest will be created and the manifest group will
629 # be empty during the pull
630 source.manifestheader()
631 repo.manifest.addgroup(source, revmap, trp)
632 repo.ui.progress(_('manifests'), None)
633
634 needfiles = {}
635 if repo.ui.configbool('server', 'validate', default=False):
636 # validate incoming csets have their manifests
637 for cset in xrange(clstart, clend):
638 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
639 mfest = repo.manifest.readdelta(mfest)
640 # store file nodes we must see
641 for f, n in mfest.iteritems():
642 needfiles.setdefault(f, set()).add(n)
643
644 # process the files
645 repo.ui.status(_("adding file changes\n"))
646 pr.step = _('files')
647 pr.count = 1
648 pr.total = efiles
649 source.callback = None
650
651 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
652 needfiles)
653 revisions += newrevs
654 files += newfiles
655
656 dh = 0
657 if oldheads:
658 heads = cl.heads()
659 dh = len(heads) - len(oldheads)
660 for h in heads:
661 if h not in oldheads and repo[h].closesbranch():
662 dh -= 1
663 htext = ""
664 if dh:
665 htext = _(" (%+d heads)") % dh
666
667 repo.ui.status(_("added %d changesets"
668 " with %d changes to %d files%s\n")
669 % (changesets, revisions, files, htext))
670 repo.invalidatevolatilesets()
671
672 if changesets > 0:
673 p = lambda: cl.writepending() and repo.root or ""
674 repo.hook('pretxnchangegroup', throw=True,
675 node=hex(cl.node(clstart)), source=srctype,
676 url=url, pending=p)
677
678 added = [cl.node(r) for r in xrange(clstart, clend)]
679 publishing = repo.ui.configbool('phases', 'publish', True)
680 if srctype == 'push':
681 # Old servers can not push the boundary themselves.
682 # New servers won't push the boundary if changeset already
683 # exists locally as secret
684 #
685 # We should not use added here but the list of all change in
686 # the bundle
687 if publishing:
688 phases.advanceboundary(repo, phases.public, srccontent)
689 else:
690 phases.advanceboundary(repo, phases.draft, srccontent)
691 phases.retractboundary(repo, phases.draft, added)
692 elif srctype != 'strip':
693 # publishing only alter behavior during push
694 #
695 # strip should not touch boundary at all
696 phases.retractboundary(repo, phases.draft, added)
697
698 # make changelog see real files again
699 cl.finalize(trp)
700
701 tr.close()
702
703 if changesets > 0:
704 if srctype != 'strip':
705 # During strip, branchcache is invalid but coming call to
706 # `destroyed` will repair it.
707 # In other case we can safely update cache on disk.
708 branchmap.updatecache(repo.filtered('served'))
709 def runhooks():
710 # These hooks run when the lock releases, not when the
711 # transaction closes. So it's possible for the changelog
712 # to have changed since we last saw it.
713 if clstart >= len(repo):
714 return
715
716 # forcefully update the on-disk branch cache
717 repo.ui.debug("updating the branch cache\n")
718 repo.hook("changegroup", node=hex(cl.node(clstart)),
719 source=srctype, url=url)
720
721 for n in added:
722 repo.hook("incoming", node=hex(n), source=srctype,
723 url=url)
724
725 newheads = [h for h in repo.heads() if h not in oldheads]
726 repo.ui.log("incoming",
727 "%s incoming changes - new heads: %s\n",
728 len(added),
729 ', '.join([hex(c[:6]) for c in newheads]))
730 repo._afterlock(runhooks)
731
732 finally:
733 tr.release()
734 # never return 0 here:
735 if dh < 0:
736 return dh - 1
737 else:
738 return dh + 1