Mercurial > hg > mercurial-crew-with-dirclash
view hgext/convert/common.py @ 5377:756a43a30e34
convert: readd --filemap
To handle merges correctly, this revision adds a filemap_source class
that wraps a converter_source and does the work necessary to calculate
the subgraph we're interested in.
The wrapped converter_source must provide a new getchangedfiles method
that, given a revision rev, and an index N, returns the list of files
that are different in rev and its Nth parent.
The implementation depends on the ability to skip some revisions and to
change the parents field of the commit objects that we returned earlier.
To make the conversion restartable, we assume the revisons in the
revmapfile are topologically sorted.
author | Alexis S. L. Carvalho <alexis@cecm.usp.br> |
---|---|
date | Thu, 04 Oct 2007 23:21:37 -0300 |
parents | e710874247d1 |
children | 8a2915f57dfc |
line wrap: on
line source
# common code for the convert extension import base64 import cPickle as pickle def encodeargs(args): def encodearg(s): lines = base64.encodestring(s) lines = [l.splitlines()[0] for l in lines] return ''.join(lines) s = pickle.dumps(args) return encodearg(s) def decodeargs(s): s = base64.decodestring(s) return pickle.loads(s) class NoRepo(Exception): pass SKIPREV = 'hg-convert-skipped-revision' 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 before(self): pass def after(self): pass def setrevmap(self, revmap, order): """set the map of already-converted revisions order is a list with the keys from revmap in the order they appear in the revision map file.""" 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' if isinstance(s, unicode): return s.encode("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") def getchangedfiles(self, rev, i): """Return the files changed by rev compared to parent[i]. i is an index selecting one of the parents of rev. The return value should be the list of files that are different in rev and this parent. If rev has no parents, i is None. This function is only needed to support --filemap """ raise NotImplementedError() 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() def setbranch(self, branch, pbranch, parents): """Set the current branch name. Called before the first putfile on the branch. branch: branch name for subsequent commits pbranch: branch name of parent commit parents: destination revisions of parent""" pass