##// END OF EJS Templates
tests: fix test-parseindex2 on Python 3...
tests: fix test-parseindex2 on Python 3 parsers.versionerrortext is a sysstr, but it's only ever used in this test on the Python side, so I'm okay to just handle it like this. Differential Revision: https://phab.mercurial-scm.org/D3622

File last commit:

r37676:34758397 default
r38106:3de58f50 default
Show More
cvs.py
301 lines | 10.6 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 _
timeless
convert: cvs use absolute_import
r28413 from mercurial import (
encoding,
error,
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 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
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
Brendan Cully
Split convert extension into common and repository type modules
r4536 cvs = os.path.join(path, "CVS")
if not os.path.exists(cvs):
Martin Geisler
convert: mark strings for translation
r10939 raise NoRepo(_("%s does not look like a CVS checkout") % path)
Brendan Cully
Split convert extension into common and repository type modules
r4536
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 checktool('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
convert: open all files in binary mode...
r36149 self.cvsroot = open(os.path.join(cvs, "Root"), 'rb').read()[:-1]
self.cvsrepo = open(os.path.join(cvs, "Repository"), '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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('cvs source does not support specifying '
Durham Goode
convert: add support for specifying multiple revs...
r25748 'multiple revs'))
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('revision %s is not a patchset number')
Durham Goode
convert: add support for specifying multiple revs...
r25748 % self.revs[0])
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 d = pycompat.getcwd()
Brendan Cully
Split convert extension into common and repository type modules
r4536 try:
os.chdir(self.path)
id = None
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 cache = 'update'
Boris Feld
configitems: register the 'convert.cvsps.cache' config...
r34152 if not self.ui.configbool('convert', 'cvsps.cache'):
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 cache = None
db = cvsps.createlog(self.ui, cache=cache)
db = cvsps.createchangeset(self.ui, db,
Boris Feld
configitems: register the 'convert.cvsps.fuzz' config
r34153 fuzz=int(self.ui.config('convert', 'cvsps.fuzz')),
Boris Feld
configitems: register the 'convert.cvsps.mergeto' config
r34155 mergeto=self.ui.config('convert', 'cvsps.mergeto'),
Boris Feld
configitems: register the 'convert.cvsps.mergefrom' config
r34154 mergefrom=self.ui.config('convert', 'cvsps.mergefrom'))
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
Pulkit Goyal
py3: use b"%d" instead of str() to convert integers to bytes...
r37676 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)
Julian Cowley
convert: add config option to use the local time zone...
r17974 if self.ui.configbool('convert', 'localtimezone'):
cs.date = makedatetimestamp(cs.date[0])
Boris Feld
util: extract all date-related utils in utils/dateutil module...
r36625 date = dateutil.datestr(cs.date, '%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:
Pulkit Goyal
py3: use b"%d" instead of str() to convert integers to bytes...
r37676 files[f.file] = "%s%s" % ('.'.join([(b"%d" % x)
Matt Mackall
many, many trivial check-code fixups
r10282 for x in f.revision]),
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 ['', '(DEAD)'][f.dead])
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
c = commit(author=cs.author, date=date,
Pulkit Goyal
py3: use b"%d" instead of str() to convert integers to bytes...
r37676 parents=[(b"%d" % p.id) for p in cs.parents],
Patrick Mezard
convert/cvs: stop supporting external cvsps
r9543 desc=cs.comment, branch=cs.branch or '')
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
cmd = ['cvs', 'server']
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.status(_("connecting to %s\n") % root)
Brendan Cully
Split convert extension into common and repository type modules
r4536
if root.startswith(":pserver:"):
root = root[9:]
m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)',
root)
if m:
conntype = "pserver"
user, passw, serv, port, root = m.groups()
if not user:
user = "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)
format0 = ":pserver:%s@%s:%s" % (user, serv, root)
format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root)
Brendan Cully
Split convert extension into common and repository type modules
r4536
if not passw:
passw = "A"
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 cvspass = os.path.expanduser("~/.cvspass")
Thomas Arendsen Hein
Improvement to 14ce129cfcd: Use try/except and pass filename on errors...
r7444 try:
Augie Fackler
convert: open all files in binary mode...
r36149 pf = open(cvspass, 'rb')
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 for line in pf.read().splitlines():
part1, part2 = line.split(' ', 1)
Brodie Rao
cleanup: eradicate long lines
r16683 # /1 :pserver:user@example.com:2401/cvsroot/foo
# Ah<Z
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 if part1 == '/1':
part1, part2 = part2.split(' ', 1)
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))
sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw,
"END AUTH REQUEST", ""]))
if sck.recv(128) != "I LOVE YOU\n":
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("CVS pserver authentication failed"))
Brendan Cully
Split convert extension into common and repository type modules
r4536
self.writep = self.readp = sck.makefile('r+')
if not conntype and root.startswith(":local:"):
conntype = "local"
root = root[7:]
if not conntype:
# :ext:user@host/home/user/path/to/cvsroot
if root.startswith(":ext:"):
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:
Brendan Cully
Split convert extension into common and repository type modules
r4536 conntype = "local"
else:
conntype = "rsh"
user, host, root = m.group(1), m.group(2), m.group(3)
if conntype != "pserver":
if conntype == "rsh":
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 5 of 5)
r30638 rsh = encoding.environ.get("CVS_RSH") or "ssh"
Brendan Cully
Split convert extension into common and repository type modules
r4536 if user:
cmd = [rsh, '-l', user, host] + cmd
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]
cmd = procutil.quotecommand(' '.join(cmd))
self.writep, self.readp = procutil.popen2(cmd)
Brendan Cully
Split convert extension into common and repository type modules
r4536
self.realroot = root
self.writep.write("Root %s\n" % root)
self.writep.write("Valid-responses ok error Valid-requests Mode"
" M Mbinary E Checked-in Created Updated"
" Merged Removed\n")
self.writep.write("valid-requests\n")
self.writep.flush()
r = self.readp.readline()
if not r.startswith("Valid-requests"):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('unexpected response from CVS server '
Matt Mackall
many, many trivial check-code fixups
r10282 '(expected "Valid-requests", but got %r)')
Greg Ward
convert/cvs: improve error message on unexpected server output.
r9095 % r)
Brendan Cully
Split convert extension into common and repository type modules
r4536 if "UseUnchanged" in r:
self.writep.write("UseUnchanged\n")
self.writep.flush()
r = self.readp.readline()
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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("%d bytes missing from remote file")
Matt Mackall
many, many trivial check-code fixups
r10282 % count)
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()
Brendan Cully
Split convert extension into common and repository type modules
r4536 if rev.endswith("(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
args = ("-N -P -kk -r %s --" % rev).split()
Patrick Mezard
convert: fix remote cvs file paths separator
r5305 args.append(self.cvsrepo + '/' + name)
Brendan Cully
Split convert extension into common and repository type modules
r4536 for x in args:
self.writep.write("Argument %s\n" % x)
self.writep.write("Directory .\n%s\nco\n" % self.realroot)
self.writep.flush()
data = ""
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()
if line.startswith("Created ") or line.startswith("Updated "):
self.readp.readline() # path
self.readp.readline() # entries
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)
Brendan Cully
Split convert extension into common and repository type modules
r4536 elif line.startswith(" "):
data += line[1:]
elif line.startswith("M "):
pass
elif line.startswith("Mbinary "):
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:
if line == "ok\n":
Mads Kiilerich
convert.cvs: Initialize state variable and abort on cvs error...
r10800 if mode is None:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('malformed response from CVS'))
Brendan Cully
Split convert extension into common and repository type modules
r4536 return (data, "x" in mode and "x" or "")
elif line.startswith("E "):
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 self.ui.warn(_("cvs server: %s\n") % line[2:])
Brendan Cully
Split convert extension into common and repository type modules
r4536 elif line.startswith("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:
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_("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:
timeless@mozdev.org
grammar: use does instead of do where appropriate
r26779 raise error.Abort(_("convert from cvs does not support --full"))
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self._parse()
Mads Kiilerich
convert: optimize convert of files that are unmodified from p2 in merges...
r24395 return sorted(self.files[rev].iteritems()), {}, 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])