##// END OF EJS Templates
tests: update test-debugcommands.t stack trace checks for python3.9...
tests: update test-debugcommands.t stack trace checks for python3.9 Python 3.9 prints a complete filepath in more cases, so we need to handle that in our test output. Since we don't really care *that* much about the specific path formatting here, just use globbing. Differential Revision: https://phab.mercurial-scm.org/D8329

File last commit:

r44473:6d3b67a8 default
r45098:a7b7a67b default
Show More
cvs.py
333 lines | 11.2 KiB | text/x-python | PythonLexer
Martin Geisler
convert: add copyright and license headers to back-ends
r8250 # cvs.py: CVS conversion code inspired by hg-cvs-import and git-cvsimport
#
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
#
# This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
timeless
convert: cvs use absolute_import
r28413 from __future__ import absolute_import
Brendan Cully
Split convert extension into common and repository type modules
r4536
timeless
convert: cvs use absolute_import
r28413 import errno
import os
import re
import socket
Yuya Nishihara
py3: move up symbol imports to enforce import-checker rules...
r29205 from mercurial.i18n import _
Gregory Szorc
py3: manually import getattr where it is needed...
r43359 from mercurial.pycompat import (
getattr,
open,
)
timeless
convert: cvs use absolute_import
r28413 from mercurial import (
encoding,
error,
Gregory Szorc
py3: define and use pycompat.iteritems() for hgext/...
r43375 pycompat,
timeless
convert: cvs use absolute_import
r28413 util,
)
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 from mercurial.utils import (
dateutil,
procutil,
)
Brendan Cully
Split convert extension into common and repository type modules
r4536
timeless
convert: cvs use absolute_import
r28413 from . import (
common,
cvsps,
)
timeless
pycompat: switch to util.stringio for py3 compat
r28861 stringio = util.stringio
timeless
convert: cvs use absolute_import
r28413 checktool = common.checktool
commit = common.commit
converter_source = common.converter_source
makedatetimestamp = common.makedatetimestamp
NoRepo = common.NoRepo
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: blacken the codebase...
r43346
Brendan Cully
Split convert extension into common and repository type modules
r4536 class convert_cvs(converter_source):
Matt Harbison
convert: save an indicator of the repo type for sources and sinks...
r35168 def __init__(self, ui, repotype, path, revs=None):
super(convert_cvs, self).__init__(ui, repotype, path, revs=revs)
Brendan Cully
convert: call superclass init from engine init functions
r4807
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cvs = os.path.join(path, b"CVS")
Brendan Cully
Split convert extension into common and repository type modules
r4536 if not os.path.exists(cvs):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise NoRepo(_(b"%s does not look like a CVS checkout") % path)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 checktool(b'cvs')
Patrick Mezard
convert: fail if an external required tool is not found
r5497
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self.changeset = None
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.files = {}
self.tags = {}
self.lastbranch = {}
self.socket = None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.cvsroot = open(os.path.join(cvs, b"Root"), b'rb').read()[:-1]
self.cvsrepo = open(os.path.join(cvs, b"Repository"), b'rb').read()[:-1]
Brodie Rao
convert: use encoding.encoding instead of locale.getpreferredencoding()...
r11987 self.encoding = encoding.encoding
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
Brendan Cully
Split convert extension into common and repository type modules
r4536 self._connect()
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 def _parse(self):
if self.changeset is not None:
Brendan Cully
Split convert extension into common and repository type modules
r4536 return
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self.changeset = {}
Brendan Cully
Split convert extension into common and repository type modules
r4536
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 maxrev = 0
Durham Goode
convert: add support for specifying multiple revs...
r25748 if self.revs:
if len(self.revs) > 1:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(
b'cvs source does not support specifying '
b'multiple revs'
)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 # TODO: handle tags
try:
# patchset number?
Durham Goode
convert: add support for specifying multiple revs...
r25748 maxrev = int(self.revs[0])
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 except ValueError:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'revision %s is not a patchset number') % self.revs[0]
Augie Fackler
formatting: blacken the codebase...
r43346 )
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760
Matt Harbison
py3: rename pycompat.getcwd() to encoding.getcwd() (API)...
r39843 d = encoding.getcwd()
Brendan Cully
Split convert extension into common and repository type modules
r4536 try:
os.chdir(self.path)
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cache = b'update'
if not self.ui.configbool(b'convert', b'cvsps.cache'):
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 cache = None
db = cvsps.createlog(self.ui, cache=cache)
Augie Fackler
formatting: blacken the codebase...
r43346 db = cvsps.createchangeset(
self.ui,
db,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 fuzz=int(self.ui.config(b'convert', b'cvsps.fuzz')),
mergeto=self.ui.config(b'convert', b'cvsps.mergeto'),
mergefrom=self.ui.config(b'convert', b'cvsps.mergefrom'),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 for cs in db:
Matt Mackall
many, many trivial check-code fixups
r10282 if maxrev and cs.id > maxrev:
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 break
Augie Fackler
formatting: blacken the codebase...
r43346 id = b"%d" % cs.id
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 cs.author = self.recode(cs.author)
self.lastbranch[cs.branch] = id
cs.comment = self.recode(cs.comment)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if self.ui.configbool(b'convert', b'localtimezone'):
Julian Cowley
convert: add config option to use the local time zone...
r17974 cs.date = makedatetimestamp(cs.date[0])
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 date = dateutil.datestr(cs.date, b'%Y-%m-%d %H:%M:%S %1%2')
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 self.tags.update(dict.fromkeys(cs.tags, id))
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 files = {}
for f in cs.entries:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 files[f.file] = b"%s%s" % (
b'.'.join([(b"%d" % x) for x in f.revision]),
[b'', b'(DEAD)'][f.dead],
Augie Fackler
formatting: blacken the codebase...
r43346 )
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 # add current commit to set
Augie Fackler
formatting: blacken the codebase...
r43346 c = commit(
author=cs.author,
date=date,
parents=[(b"%d" % p.id) for p in cs.parents],
desc=cs.comment,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 branch=cs.branch or b'',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 self.changeset[id] = c
self.files[id] = files
Brendan Cully
Split convert extension into common and repository type modules
r4536
self.heads = self.lastbranch.values()
finally:
os.chdir(d)
def _connect(self):
root = self.cvsroot
conntype = None
user, host = None, None
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd = [b'cvs', b'server']
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.ui.status(_(b"connecting to %s\n") % root)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if root.startswith(b":pserver:"):
Brendan Cully
Split convert extension into common and repository type modules
r4536 root = root[9:]
Matt Harbison
cleanup: drop redundant character escapes from `[]` character sets...
r44473 m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:/]*)(?::(\d*))?(.*)', root)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if m:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 conntype = b"pserver"
Brendan Cully
Split convert extension into common and repository type modules
r4536 user, passw, serv, port, root = m.groups()
if not user:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 user = b"anonymous"
Thomas Arendsen Hein
CVS import: Support new-style .cvspass-file format....
r5082 if not port:
port = 2401
Brendan Cully
Split convert extension into common and repository type modules
r4536 else:
Thomas Arendsen Hein
CVS import: Support new-style .cvspass-file format....
r5082 port = int(port)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 format0 = b":pserver:%s@%s:%s" % (user, serv, root)
format1 = b":pserver:%s@%s:%d%s" % (user, serv, port, root)
Brendan Cully
Split convert extension into common and repository type modules
r4536
if not passw:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 passw = b"A"
cvspass = os.path.expanduser(b"~/.cvspass")
Thomas Arendsen Hein
Improvement to 14ce129cfcd: Use try/except and pass filename on errors...
r7444 try:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 pf = open(cvspass, b'rb')
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 for line in pf.read().splitlines():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 part1, part2 = line.split(b' ', 1)
Brodie Rao
cleanup: eradicate long lines
r16683 # /1 :pserver:user@example.com:2401/cvsroot/foo
# Ah<Z
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if part1 == b'/1':
part1, part2 = part2.split(b' ', 1)
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 format = format1
Brodie Rao
cleanup: eradicate long lines
r16683 # :pserver:user@example.com:/cvsroot/foo Ah<Z
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 else:
format = format0
if part1 == format:
passw = part2
break
pf.close()
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Thomas Arendsen Hein
Improvement to 14ce129cfcd: Use try/except and pass filename on errors...
r7444 if inst.errno != errno.ENOENT:
if not getattr(inst, 'filename', None):
inst.filename = cvspass
raise
Brendan Cully
Split convert extension into common and repository type modules
r4536
sck = socket.socket()
sck.connect((serv, port))
Augie Fackler
formatting: blacken the codebase...
r43346 sck.send(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"\n".join(
Augie Fackler
formatting: blacken the codebase...
r43346 [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"BEGIN AUTH REQUEST",
Augie Fackler
formatting: blacken the codebase...
r43346 root,
user,
passw,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"END AUTH REQUEST",
b"",
Augie Fackler
formatting: blacken the codebase...
r43346 ]
)
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if sck.recv(128) != b"I LOVE YOU\n":
raise error.Abort(_(b"CVS pserver authentication failed"))
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.writep = self.readp = sck.makefile(b'r+')
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not conntype and root.startswith(b":local:"):
conntype = b"local"
Brendan Cully
Split convert extension into common and repository type modules
r4536 root = root[7:]
if not conntype:
# :ext:user@host/home/user/path/to/cvsroot
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if root.startswith(b":ext:"):
Brendan Cully
Split convert extension into common and repository type modules
r4536 root = root[5:]
Pulkit Goyal
py3: make sure regexes are bytes...
r36411 m = re.match(br'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
Patrick Mezard
convert: avoid interpreting Windows path as CVS connection strings....
r5304 # Do not take Windows path "c:\foo\bar" for a connection strings
if os.path.isdir(root) or not m:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 conntype = b"local"
Brendan Cully
Split convert extension into common and repository type modules
r4536 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 conntype = b"rsh"
Brendan Cully
Split convert extension into common and repository type modules
r4536 user, host, root = m.group(1), m.group(2), m.group(3)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if conntype != b"pserver":
if conntype == b"rsh":
rsh = encoding.environ.get(b"CVS_RSH") or b"ssh"
Brendan Cully
Split convert extension into common and repository type modules
r4536 if user:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd = [rsh, b'-l', user, host] + cmd
Brendan Cully
Split convert extension into common and repository type modules
r4536 else:
cmd = [rsh, host] + cmd
Patrick Mezard
convert: call popen2 in binary mode, with a command string.
r5303 # popen2 does not support argument lists under Windows
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 cmd = [procutil.shellquote(arg) for arg in cmd]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmd = procutil.quotecommand(b' '.join(cmd))
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 self.writep, self.readp = procutil.popen2(cmd)
Brendan Cully
Split convert extension into common and repository type modules
r4536
self.realroot = root
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.writep.write(b"Root %s\n" % root)
Augie Fackler
formatting: blacken the codebase...
r43346 self.writep.write(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"Valid-responses ok error Valid-requests Mode"
b" M Mbinary E Checked-in Created Updated"
b" Merged Removed\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.writep.write(b"valid-requests\n")
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.writep.flush()
r = self.readp.readline()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not r.startswith(b"Valid-requests"):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'unexpected response from CVS server '
b'(expected "Valid-requests", but got %r)'
Augie Fackler
formatting: blacken the codebase...
r43346 )
% r
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b"UseUnchanged" in r:
self.writep.write(b"UseUnchanged\n")
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.writep.flush()
Martin von Zweigbergk
cleanup: delete lots of unused local variables...
r41401 self.readp.readline()
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getheads(self):
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Brendan Cully
Split convert extension into common and repository type modules
r4536 return self.heads
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 def getfile(self, name, rev):
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 def chunkedread(fp, count):
Mads Kiilerich
fix trivial spelling errors
r17424 # file-objects returned by socket.makefile() do not handle
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 # large read() requests very well.
chunksize = 65536
timeless
pycompat: switch to util.stringio for py3 compat
r28861 output = stringio()
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 while count > 0:
data = fp.read(min(count, chunksize))
if not data:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"%d bytes missing from remote file") % count
Augie Fackler
formatting: blacken the codebase...
r43346 )
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 count -= len(data)
output.write(data)
return output.getvalue()
Patrick Mezard
convert: merge sources getmode() into getfile()
r11134 self._parse()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if rev.endswith(b"(DEAD)"):
Mads Kiilerich
convert: use None value for missing files instead of overloading IOError...
r22296 return None, None
Brendan Cully
Split convert extension into common and repository type modules
r4536
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 args = (b"-N -P -kk -r %s --" % rev).split()
args.append(self.cvsrepo + b'/' + name)
Brendan Cully
Split convert extension into common and repository type modules
r4536 for x in args:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 self.writep.write(b"Argument %s\n" % x)
self.writep.write(b"Directory .\n%s\nco\n" % self.realroot)
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.writep.flush()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 data = b""
Mads Kiilerich
convert.cvs: Initialize state variable and abort on cvs error...
r10800 mode = None
Martin Geisler
check-code: flag 0/1 used as constant Boolean expression
r14494 while True:
Brendan Cully
Split convert extension into common and repository type modules
r4536 line = self.readp.readline()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if line.startswith(b"Created ") or line.startswith(b"Updated "):
Augie Fackler
formatting: blacken the codebase...
r43346 self.readp.readline() # path
self.readp.readline() # entries
Brendan Cully
Split convert extension into common and repository type modules
r4536 mode = self.readp.readline()[:-1]
count = int(self.readp.readline()[:-1])
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 data = chunkedread(self.readp, count)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif line.startswith(b" "):
Brendan Cully
Split convert extension into common and repository type modules
r4536 data += line[1:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif line.startswith(b"M "):
Brendan Cully
Split convert extension into common and repository type modules
r4536 pass
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif line.startswith(b"Mbinary "):
Brendan Cully
Split convert extension into common and repository type modules
r4536 count = int(self.readp.readline()[:-1])
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 data = chunkedread(self.readp, count)
Brendan Cully
Split convert extension into common and repository type modules
r4536 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if line == b"ok\n":
Mads Kiilerich
convert.cvs: Initialize state variable and abort on cvs error...
r10800 if mode is None:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'malformed response from CVS'))
return (data, b"x" in mode and b"x" or b"")
elif line.startswith(b"E "):
self.ui.warn(_(b"cvs server: %s\n") % line[2:])
elif line.startswith(b"Remove"):
Peter Arrenbrecht
cleanup: drop variables for unused return values...
r7874 self.readp.readline()
Brendan Cully
Split convert extension into common and repository type modules
r4536 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"unknown CVS response: %s") % line)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Mads Kiilerich
convert: introduce --full for converting all files...
r22300 def getchanges(self, rev, full):
if full:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b"convert from cvs does not support --full"))
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Gregory Szorc
py3: define and use pycompat.iteritems() for hgext/...
r43375 return sorted(pycompat.iteritems(self.files[rev])), {}, set()
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getcommit(self, rev):
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Brendan Cully
Split convert extension into common and repository type modules
r4536 return self.changeset[rev]
def gettags(self):
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Brendan Cully
Split convert extension into common and repository type modules
r4536 return self.tags
Alexis S. L. Carvalho
convert_cvs: add --filemap support
r5381
def getchangedfiles(self, rev, i):
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Matt Mackall
replace util.sort with sorted built-in...
r8209 return sorted(self.files[rev])