##// END OF EJS Templates
rust-core: updated copyright notice...
rust-core: updated copyright notice The intention here is to put an email address that actually works (I did have full personal copyrights with my former affiliation). It is also an opportunity to acknowledge that I've not been the only one to work on this file. Differential Revision: https://phab.mercurial-scm.org/D7781

File last commit:

r43375:649d3ac3 default
r44455:cb2e2b09 default
Show More
cvs.py
335 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:]
Augie Fackler
formatting: blacken the codebase...
r43346 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])