Mercurial > hg-stable
changeset 4589:451e91ed535e
convert extension: Add support for username mapping
Allows mapping usernames to new ones during conversion process.
- Use -A option for first import
- Then at the end of the conversion process and if the destination
repo supports authorfile attribute, author map content is copied
to the file pointed by the authorfile call.
- On incremental conversions w/o any -A option specified, the
destination authorfile, if any, gets read automatically.
EG: This allows mapping unix system usernames used in CVS accounts
to a more typical "Firstname Lastname <address@server.org>" pair.
author | Edouard Gomez <ed.gomez@free.fr> |
---|---|
date | Thu, 14 Jun 2007 23:25:55 +0200 |
parents | 9855939d0c82 |
children | 80fb4ec512b5 |
files | hgext/convert/__init__.py hgext/convert/common.py hgext/convert/hg.py |
diffstat | 3 files changed, 65 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/hgext/convert/__init__.py Thu Jun 14 23:25:55 2007 +0200 +++ b/hgext/convert/__init__.py Thu Jun 14 23:25:55 2007 +0200 @@ -37,6 +37,8 @@ self.commitcache = {} self.mapfile = mapfile self.mapfilefd = None + self.authors = {} + self.writeauthors = False self.map = {} try: @@ -48,6 +50,14 @@ except IOError: pass + # Read first the dst author map if any + if hasattr(self.dest, 'authorfile'): + self.readauthormap(self.dest.authorfile()) + # Extend/Override with new author map if necessary + if 'authors' in opts: + self.readauthormap(opts.get('authors')) + self.writeauthors = True + def walktree(self, heads): visit = heads known = {} @@ -131,6 +141,39 @@ self.mapfilefd.write("%s %s\n" % (src, dst)) self.mapfilefd.flush() + def writeauthormap(self): + if self.writeauthors == True and len(self.authors) > 0 and hasattr(self.dest, 'authorfile'): + authorfile = self.dest.authorfile() + self.ui.status('Writing author map file %s\n' % authorfile) + ofile = open(authorfile, 'w+') + for author in self.authors: + ofile.write("%s=%s\n" % (author, self.authors[author])) + ofile.close() + + def readauthormap(self, authorfile): + try: + afile = open(authorfile, 'r') + for line in afile: + try: + srcauthor = line.split('=')[0].strip() + dstauthor = line.split('=')[1].strip() + if srcauthor in self.authors and dstauthor != self.authors[srcauthor]: + self.ui.status( + 'Overriding mapping for author %s, was %s, will be %s\n' + % (srcauthor, self.authors[srcauthor], dstauthor)) + else: + self.ui.debug('Mapping author %s to %s\n' + % (srcauthor, dstauthor)) + self.authors[srcauthor] = dstauthor + + except IndexError: + self.ui.warn( + 'Ignoring bad line in author file map %s: %s\n' + % (authorfile, line)) + afile.close() + except IOError: + self.ui.warn('Error reading author file map %s.\n' % authorfile) + def copy(self, rev): c = self.commitcache[rev] files = self.source.getchanges(rev) @@ -165,6 +208,9 @@ desc = self.commitcache[c].desc if "\n" in desc: desc = desc.splitlines()[0] + author = self.commitcache[c].author + author = self.authors.get(author, author) + self.commitcache[c].author = author self.ui.status("%d %s\n" % (num, desc)) self.copy(c) @@ -181,6 +227,8 @@ # one so we don't end up with extra tag heads if nrev: self.mapentry(c, nrev) + + self.writeauthormap() finally: self.cleanup() @@ -204,12 +252,17 @@ The <mapfile> is a simple text file that maps each source commit ID to the destination ID for that revision, like so: - <source ID> <destination ID> If the file doesn't exist, it's automatically created. It's updated on each commit copied, so convert-repo can be interrupted and can be run repeatedly to copy new commits. + + The [username mapping] file is a simple text file that maps each source + commit author to a destination commit author. It is handy for source SCMs + that use unix logins to identify authors (eg: CVS). One line per author + mapping and the line format is: + srcauthor=whatever string you want ''' srcc = converter(ui, src) @@ -257,6 +310,7 @@ cmdtable = { "convert": (_convert, - [('', 'datesort', None, 'try to sort changesets by date')], + [('A', 'authors', '', 'username mapping filename'), + ('', 'datesort', None, 'try to sort changesets by date')], 'hg convert [OPTION]... SOURCE [DEST [MAPFILE]]'), }
--- a/hgext/convert/common.py Thu Jun 14 23:25:55 2007 +0200 +++ b/hgext/convert/common.py Thu Jun 14 23:25:55 2007 +0200 @@ -62,6 +62,12 @@ 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.""" + raise NotImplementedError() + def putfile(self, f, e, data): """Put file for next putcommit(). f: path to file
--- a/hgext/convert/hg.py Thu Jun 14 23:25:55 2007 +0200 +++ b/hgext/convert/hg.py Thu Jun 14 23:25:55 2007 +0200 @@ -17,6 +17,9 @@ def mapfile(self): return os.path.join(self.path, ".hg", "shamap") + def authorfile(self): + return os.path.join(self.path, ".hg", "authormap") + def getheads(self): h = self.repo.changelog.heads() return [ hg.hex(x) for x in h ]