convert: look up copies in getchanges instead of getcommit
svn: defer path expansion until getchanges to reduce latency, as well as memory
usage when converting incrementally.
# common code for the convert extension
class NoRepo(Exception): pass
class commit(object):
def __init__(self, author, date, desc, parents, branch=None, rev=None):
self.author = author
self.date = date
self.desc = desc
self.parents = parents
self.branch = branch
self.rev = rev
class converter_source(object):
"""Conversion source interface"""
def __init__(self, ui, path, rev=None):
"""Initialize conversion source (or raise NoRepo("message")
exception if path is not a valid repository)"""
self.ui = ui
self.path = path
self.rev = rev
self.encoding = 'utf-8'
def setrevmap(self, revmap):
"""set the map of already-converted revisions"""
pass
def getheads(self):
"""Return a list of this repository's heads"""
raise NotImplementedError()
def getfile(self, name, rev):
"""Return file contents as a string"""
raise NotImplementedError()
def getmode(self, name, rev):
"""Return file mode, eg. '', 'x', or 'l'"""
raise NotImplementedError()
def getchanges(self, version):
"""Returns a tuple of (files, copies)
Files is a sorted list of (filename, id) tuples for all files changed
in version, where id is the source revision id of the file.
copies is a dictionary of dest: source
"""
raise NotImplementedError()
def getcommit(self, version):
"""Return the commit object for version"""
raise NotImplementedError()
def gettags(self):
"""Return the tags as a dictionary of name: revision"""
raise NotImplementedError()
def recode(self, s, encoding=None):
if not encoding:
encoding = self.encoding or 'utf-8'
try:
return s.decode(encoding).encode("utf-8")
except:
try:
return s.decode("latin-1").encode("utf-8")
except:
return s.decode(encoding, "replace").encode("utf-8")
class converter_sink(object):
"""Conversion sink (target) interface"""
def __init__(self, ui, path):
"""Initialize conversion sink (or raise NoRepo("message")
exception if path is not a valid repository)"""
raise NotImplementedError()
def getheads(self):
"""Return a list of this repository's heads"""
raise NotImplementedError()
def revmapfile(self):
"""Path to a file that will contain lines
source_rev_id sink_rev_id
mapping equivalent revision identifiers for each system."""
raise NotImplementedError()
def authorfile(self):
"""Path to a file that will contain lines
srcauthor=dstauthor
mapping equivalent authors identifiers for each system."""
return None
def putfile(self, f, e, data):
"""Put file for next putcommit().
f: path to file
e: '', 'x', or 'l' (regular file, executable, or symlink)
data: file contents"""
raise NotImplementedError()
def delfile(self, f):
"""Delete file for next putcommit().
f: path to file"""
raise NotImplementedError()
def putcommit(self, files, parents, commit):
"""Create a revision with all changed files listed in 'files'
and having listed parents. 'commit' is a commit object containing
at a minimum the author, date, and message for this changeset.
Called after putfile() and delfile() calls. Note that the sink
repository is not told to update itself to a particular revision
(or even what that revision would be) before it receives the
file data."""
raise NotImplementedError()
def puttags(self, tags):
"""Put tags into sink.
tags: {tagname: sink_rev_id, ...}"""
raise NotImplementedError()