Changeset - 6354556781ef
[Not reviewed]
beta
0 1 0
Mads Kiilerich - 13 years ago 2013-02-27 01:26:38
madski@unity3d.com
update unionrepo for Mercurial 2.5.1
1 file changed with 46 insertions and 19 deletions:
0 comments (0 inline, 0 general)
rhodecode/lib/unionrepo.py
Show inline comments
 
# unionrepo.py - repository class for viewing union of repositories
 
# unionrepo.py - repository class for viewing union of repository changesets
 
#
 
# Derived from Mercurial 2.5 bundlerepo.py
 
# Derived from bundlerepo.py
 
# Copyright 2006, 2007 Benoit Boissinot <bboissin@gmail.com>
 
# Copyright 2013 Unity Technologies, Mads Kiilerich <madski@unity3d.com>
 
#
 
# This software may be used and distributed according to the terms of the
 
# GNU General Public License version 2 or any later version.
 

	
 
"""Repository class for in-memory pull of one local repository to another.
 
"""Repository class for "in-memory pull" of one local repository to another,
 
allowing operations like diff and log with revsets.
 
"""
 

	
 
import os
 
from mercurial.node import nullid
 
from mercurial import util, mdiff
 
from mercurial.i18n import _
 
from mercurial import util, mdiff, cmdutil, scmutil
 
from mercurial import localrepo, changelog, manifest, filelog, revlog
 

	
 
class unionrevlog(revlog.revlog):
 
    def __init__(self, opener, indexfile, revlog2, linkmapper):
 
        # How it works:
 
        # To retrieve a revision, we just need to know the node id so we can
 
        # look it up in revlog2.
 
        #
 
        # basemap is indexed with revisions coming from the second revlog.
 
        #
 
        # To differentiate a rev in the second revlog from a rev in the revlog,
 
        # we check revision against basemap.
 
        # we check revision against repotiprev.
 
        opener = scmutil.readonlyvfs(opener)
 
        revlog.revlog.__init__(self, opener, indexfile)
 
        self.revlog2 = revlog2
 

	
 
        self.basemap = {} # mapping rev that is in revlog2 to ... nothing
 
        n = len(self)
 
        self.repotiprev = n - 1
 
        self.bundlerevs = set() # used by 'bundle()' revset expression
 
        for rev2 in self.revlog2:
 
            rev = self.revlog2.index[rev2]
 
            # rev numbers - in revlog2, very different from self.rev
 
            _start, _csize, _rsize, _base, linkrev, p1rev, p2rev, node = rev
 

	
 
            if linkmapper is None: # link is to same revlog
 
                assert linkrev == rev2 # we never link back
 
                link = n
 
            else: # rev must be mapped from repo2 cl to unified cl by linkmapper
 
                link = linkmapper(linkrev)
 

	
 
            if node in self.nodemap:
 
                # this happens for for the common revlog revisions
 
                # this happens for the common revlog revisions
 
                self.bundlerevs.add(self.nodemap[node])
 
                continue
 

	
 
            p1node = self.revlog2.node(p1rev)
 
            p2node = self.revlog2.node(p2rev)
 

	
 
            e = (None, None, None, None,
 
                 link, self.rev(p1node), self.rev(p2node), node)
 
            self.basemap[n] = None
 
            self.index.insert(-1, e)
 
            self.nodemap[node] = n
 
            self.bundlerevs.add(n)
 
            n += 1
 

	
 
    def _chunk(self, rev):
 
        if rev not in self.basemap:
 
        if rev <= self.repotiprev:
 
            return revlog.revlog._chunk(self, rev)
 
        return self.revlog2._chunk(self.node(rev))
 

	
 
    def revdiff(self, rev1, rev2):
 
        """return or calculate a delta between two revisions"""
 
        if rev1 in self.basemap and rev2 in self.basemap:
 
        if rev1 > self.repotiprev and rev2 > self.repotiprev:
 
            return self.revlog2.revdiff(
 
                self.revlog2.rev(self.node(rev1)),
 
                self.revlog2.rev(self.node(rev2)))
 
        elif rev1 not in self.basemap and rev2 not in self.basemap:
 
        elif rev1 <= self.repotiprev and rev2 <= self.repotiprev:
 
            return revlog.revlog.revdiff(self, rev1, rev2)
 

	
 
        return mdiff.textdiff(self.revision(self.node(rev1)),
 
                              self.revision(self.node(rev2)))
 

	
 
    def revision(self, nodeorrev):
 
        """return an uncompressed revision of a given node or revision
 
        number.
 
        """
 
        if isinstance(nodeorrev, int):
 
            rev = nodeorrev
 
            node = self.node(rev)
 
        else:
 
            node = nodeorrev
 
            rev = self.rev(node)
 

	
 
        if node == nullid:
 
            return ""
 

	
 
        if rev in self.basemap:
 
        if rev > self.repotiprev:
 
            text = self.revlog2.revision(node)
 
            self._cache = (node, rev, text)
 
        else:
 
            text = revlog.revlog.revision(self, rev)
 
            # already cached
 
        return text
 

	
 
    def addrevision(self, text, transaction, link, p1=None, p2=None, d=None):
 
        raise NotImplementedError
 
    def addgroup(self, revs, linkmapper, transaction):
 
        raise NotImplementedError
 
    def strip(self, rev, minlink):
 
@@ -135,47 +136,73 @@ class unionpeer(localrepo.localpeer):
 
    def canpush(self):
 
        return False
 

	
 
class unionrepository(localrepo.localrepository):
 
    def __init__(self, ui, path, path2):
 
        localrepo.localrepository.__init__(self, ui, path)
 
        self.ui.setconfig('phases', 'publish', False)
 

	
 
        self._url = 'union:%s+%s' % (util.expandpath(path),
 
                                     util.expandpath(path2))
 
        self.repo2 = localrepo.localrepository(ui, path2)
 

	
 
    @util.propertycache
 
    @localrepo.unfilteredpropertycache
 
    def changelog(self):
 
        return unionchangelog(self.sopener, self.repo2.sopener)
 

	
 
    def _clrev(self, rev2):
 
        """map from repo2 changelog rev to temporary rev in self.changelog"""
 
        node = self.repo2.changelog.node(rev2)
 
        return self.changelog.rev(node)
 

	
 
    @util.propertycache
 
    @localrepo.unfilteredpropertycache
 
    def manifest(self):
 
        return unionmanifest(self.sopener, self.repo2.sopener,
 
                             self._clrev)
 

	
 
    def url(self):
 
        return self._url
 

	
 
    def file(self, f):
 
        return unionfilelog(self.sopener, f, self.repo2.sopener,
 
                            self._clrev, self)
 

	
 
    def close(self):
 
        self.repo2.close()
 

	
 
    def cancopy(self):
 
        return False
 

	
 
    def peer(self):
 
        return unionpeer(self)
 

	
 
    def getcwd(self):
 
        return os.getcwd() # always outside the repo
 

	
 
def instance(ui, path, create):
 
    u = util.url(path)
 
    assert u.scheme == 'union'
 
    repopath, repopath2 = u.path.split("+", 1)
 
    if create:
 
        raise util.Abort(_('cannot create new union repository'))
 
    parentpath = ui.config("bundle", "mainreporoot", "")
 
    if not parentpath:
 
        # try to find the correct path to the working directory repo
 
        parentpath = cmdutil.findrepo(os.getcwd())
 
        if parentpath is None:
 
            parentpath = ''
 
    if parentpath:
 
        # Try to make the full path relative so we get a nice, short URL.
 
        # In particular, we don't want temp dir names in test outputs.
 
        cwd = os.getcwd()
 
        if parentpath == cwd:
 
            parentpath = ''
 
        else:
 
            cwd = os.path.join(cwd,'')
 
            if parentpath.startswith(cwd):
 
                parentpath = parentpath[len(cwd):]
 
    if path.startswith('union:'):
 
        s = path.split(":", 1)[1].split("+", 1)
 
        if len(s) == 1:
 
            repopath, repopath2 = parentpath, s[0]
 
        else:
 
            repopath, repopath2 = s
 
    else:
 
        repopath, repopath2 = parentpath, path
 
    return unionrepository(ui, repopath, repopath2)
0 comments (0 inline, 0 general)