Mercurial > hg > hg-git
view hggit/overlay.py @ 557:4f4ab2d89375
gitrepo: initial support for listkeys
This changeset adds test coverage for comparing "hg outgoing -B" in normal
Mercurial usage with Hg-Git usage. This didn't match, since previously, gitrepo
didn't provide a meaningful listkeys implementation. Now, it does.
gitrepo now has access to a GitHandler when a localrepo is available. This
handler is used to access the information needed to implement listkeys for
namespaces (currently, only bookmarks) and bookmarks.
A couple of other tests were testing "divergent bookmark" scenarios. These
tests have been updated to filter out the divergent bookmark output, as it isn't
consistent across the supported Mercurial versions.
author | David M. Carr <david@carrclan.us> |
---|---|
date | Thu, 25 Oct 2012 20:49:08 -0400 |
parents | ac16efd25cc4 |
children | a24c2f90a3dd |
line wrap: on
line source
# overlay classes for repositories # unifies access to unimported git objects and committed hg objects # designed to support incoming # # incomplete, implemented on demand from mercurial import context from mercurial.node import bin, hex, nullid class overlaymanifest(object): def __init__(self, repo, sha): self.repo = repo self.tree = repo.handler.git.get_object(sha) self._map = None self._flagmap = None def withflags(self): self.load() return set([path for path, flag in self._flagmap.iteritems() if flag & 020100]) def copy(self): return overlaymanifest(self.repo, self.tree.id) def keys(self): self.load() return self._map.keys() def flags(self, path): self.load() def hgflag(gitflag): if gitflag & 0100: return 'x' elif gitflag & 020000: return 'l' else: return '' return hgflag(self._flagmap[path]) def load(self): if self._map is not None: return self._map = {} self._flagmap = {} def addtree(tree, dirname): for entry in tree.iteritems(): if entry.mode & 040000: # expand directory subtree = self.repo.handler.git.get_object(entry.sha) addtree(subtree, dirname + entry.path + '/') else: path = dirname + entry.path self._map[path] = bin(entry.sha) self._flagmap[path] = entry.mode addtree(self.tree, '') def __iter__(self): self.load() return self._map.__iter__() def __getitem__(self, path): self.load() return self._map[path] def __delitem__(self, path): del self._map[path] class overlayfilectx(object): def __init__(self, repo, path, fileid=None): self.repo = repo self._path = path self.fileid = fileid # this is a hack to skip copy detection def ancestors(self): return [self, self] def rev(self): return -1 def path(self): return self._path def filelog(self): return self.fileid def data(self): blob = self.repo.handler.git.get_object(self.fileid) return blob.data class overlaychangectx(context.changectx): def __init__(self, repo, sha): self.repo = repo self.commit = repo.handler.git.get_object(sha) def node(self): return bin(self.commit.id) def rev(self): return self.repo.rev(bin(self.commit.id)) def date(self): return self.commit.author_time, self.commit.author_timezone def branch(self): return 'default' def user(self): return self.commit.author def files(self): return [] def extra(self): return {} def description(self): return self.commit.message def parents(self): return [overlaychangectx(self.repo, sha) for sha in self.commit.parents] def manifestnode(self): return bin(self.commit.tree) def hex(self): return self.commit.id def tags(self): return [] def bookmarks(self): return [] def manifest(self): return overlaymanifest(self.repo, self.commit.tree) def filectx(self, path, filelog=None): mf = self.manifest() return overlayfilectx(self.repo, path, mf[path]) def flags(self, path): mf = self.manifest() return mf.flags(path) def __nonzero__(self): return True class overlayrevlog(object): def __init__(self, repo, base): self.repo = repo self.base = base def parents(self, n): gitrev = self.repo.revmap.get(n) if not gitrev: # we've reached a revision we have return self.base.parents(n) commit = self.repo.handler.git.get_object(n) def gitorhg(n): hn = self.repo.handler.map_hg_get(hex(n)) if hn is not None: return bin(hn) return n # currently ignores the octopus p1 = gitorhg(bin(commit.parents[0])) if len(commit.parents) > 1: p2 = gitorhg(bin(commit.parents[1])) else: p2 = nullid return [p1, p2] def parentrevs(self, rev): return [self.rev(p) for p in self.parents(self.node(rev))] def node(self, rev): gitnode = self.repo.nodemap.get(rev) if gitnode is None: return self.base.node(rev) return gitnode def rev(self, n): gitrev = self.repo.revmap.get(n) if gitrev is None: return self.base.rev(n) return gitrev def nodesbetween(self, nodelist, revs): # this is called by pre-1.9 incoming with the nodelist we returned from # getremotechanges. Just return it back. return [nodelist] def __len__(self): return len(self.repo.handler.repo) + len(self.repo.revmap) class overlayrepo(object): def __init__(self, handler, commits, refs): self.handler = handler self.changelog = overlayrevlog(self, handler.repo.changelog) self.manifest = overlayrevlog(self, handler.repo.manifest) # for incoming -p self.root = handler.repo.root self.getcwd = handler.repo.getcwd self.status = handler.repo.status self.ui = handler.repo.ui self.revmap = None self.nodemap = None self.refmap = None self.tagmap = None self._makemaps(commits, refs) def __getitem__(self, n): if n not in self.revmap: return self.handler.repo[n] return overlaychangectx(self, n) def node(self, n): """Returns an Hg or Git hash for the specified Git hash""" if bin(n) in self.revmap: return n return self.handler.map_hg_get(n) def nodebookmarks(self, n): return self.refmap.get(n, []) def nodetags(self, n): return self.tagmap.get(n, []) def rev(self, n): return self.revmap[n] def filectx(self, path, fileid=None): return overlayfilectx(self, path, fileid=fileid) def _makemaps(self, commits, refs): baserev = self.handler.repo['tip'].rev() self.revmap = {} self.nodemap = {} for i, n in enumerate(commits): rev = baserev + i + 1 self.revmap[n] = rev self.nodemap[rev] = n self.refmap = {} self.tagmap = {} for ref in refs: if ref.startswith('refs/heads/'): refname = ref[11:] self.refmap.setdefault(bin(refs[ref]), []).append(refname) elif ref.startswith('refs/tags/'): tagname = ref[10:] self.tagmap.setdefault(bin(refs[ref]), []).append(tagname)