##// END OF EJS Templates
Dummy-merge with c655432c2c24 (issue1860)
Dummy-merge with c655432c2c24 (issue1860)

File last commit:

r9543:56a5f805 default
r9601:11ace572 merge default
Show More
cvs.py
372 lines | 14.5 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
# GNU General Public License version 2, incorporated herein by reference.
Brendan Cully
Split convert extension into common and repository type modules
r4536
Thomas Arendsen Hein
Improvement to 14ce129cfcd: Use try/except and pass filename on errors...
r7444 import os, locale, re, socket, errno
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 from cStringIO import StringIO
Brendan Cully
Split convert extension into common and repository type modules
r4536 from mercurial import util
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 from mercurial.i18n import _
Brendan Cully
Split convert extension into common and repository type modules
r4536
Patrick Mezard
convert: fail if an external required tool is not found
r5497 from common import NoRepo, commit, converter_source, checktool
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 import cvsps
Brendan Cully
Split convert extension into common and repository type modules
r4536
class convert_cvs(converter_source):
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 def __init__(self, ui, path, rev=None):
Brendan Cully
convert: call superclass init from engine init functions
r4807 super(convert_cvs, self).__init__(ui, path, rev=rev)
Brendan Cully
Split convert extension into common and repository type modules
r4536 cvs = os.path.join(path, "CVS")
if not os.path.exists(cvs):
Alexis S. L. Carvalho
convert: display all errors if we couldn't open the source repo...
r5521 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: make built-in cvsps the default...
r7101 self.cmd = ui.config('convert', 'cvsps', 'builtin')
Eric Hopper
convert: Add convert.cvsps option to set up an alternate cvsps command line.
r6318 cvspsexe = self.cmd.split(None, 1)[0]
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 self.builtin = cvspsexe == 'builtin'
Patrick Mezard
convert: deprecate external cvsps, to be removed in 1.4
r8598 if not self.builtin:
ui.warn(_('warning: support for external cvsps is deprecated and '
'will be removed in Mercurial 1.4\n'))
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
if not self.builtin:
checktool(cvspsexe)
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.parent = {}
self.socket = None
Alejandro Santos
compat: use open() instead of file() everywhere
r9031 self.cvsroot = open(os.path.join(cvs, "Root")).read()[:-1]
self.cvsrepo = open(os.path.join(cvs, "Repository")).read()[:-1]
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.encoding = locale.getpreferredencoding()
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
Eric Hopper
convert: Add convert.cvsps option to set up an alternate cvsps command line.
r6318 cmd = self.cmd
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 if self.rev:
# TODO: handle tags
try:
# patchset number?
maxrev = int(self.rev)
except ValueError:
try:
# date
util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S'])
Patrick Mezard
Merge with crew-stable
r5308 cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev)
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 except util.Abort:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_('revision %s is not a patchset number or date') % self.rev)
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760
Brendan Cully
Split convert extension into common and repository type modules
r4536 d = os.getcwd()
try:
os.chdir(self.path)
id = None
state = 0
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 filerevids = {}
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
if self.builtin:
# builtin cvsps code
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 self.ui.status(_('using builtin cvsps\n'))
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
Patrick Mezard
convert/cvs: add an option to disable remote log caching...
r8169 cache = 'update'
if not self.ui.configbool('convert', 'cvsps.cache', True):
cache = None
db = cvsps.createlog(self.ui, cache=cache)
Patrick Mezard
convert/cvs: delay CVS log parsing after initialization (issue1581/2)...
r8048 db = cvsps.createchangeset(self.ui, db,
fuzz=int(self.ui.config('convert', 'cvsps.fuzz', 60)),
mergeto=self.ui.config('convert', 'cvsps.mergeto', None),
mergefrom=self.ui.config('convert', 'cvsps.mergefrom', None))
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
for cs in db:
if maxrev and cs.id>maxrev:
break
id = str(cs.id)
cs.author = self.recode(cs.author)
self.lastbranch[cs.branch] = id
cs.comment = self.recode(cs.comment)
date = util.datestr(cs.date)
self.tags.update(dict.fromkeys(cs.tags, id))
files = {}
for f in cs.entries:
files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
['', '(DEAD)'][f.dead])
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 # add current commit to set
c = commit(author=cs.author, date=date,
parents=[str(p.id) for p in cs.parents],
desc=cs.comment, branch=cs.branch or '')
self.changeset[id] = c
self.files[id] = files
else:
# external cvsps
for l in util.popen(cmd):
if state == 0: # header
if l.startswith("PatchSet"):
id = l[9:-2]
if maxrev and int(id) > maxrev:
# ignore everything
state = 3
Mads Kiilerich
convert cvs: Fix branch name parsing...
r7441 elif l.startswith("Date:"):
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
date = util.datestr(date)
Mads Kiilerich
convert cvs: Fix branch name parsing...
r7441 elif l.startswith("Branch:"):
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 branch = l[8:-1]
self.parent[id] = self.lastbranch.get(branch, 'bad')
self.lastbranch[branch] = id
Mads Kiilerich
convert cvs: Fix branch name parsing...
r7441 elif l.startswith("Ancestor branch:"):
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 ancestor = l[17:-1]
# figure out the parent later
self.parent[id] = self.lastbranch[ancestor]
Mads Kiilerich
convert cvs: Fix branch name parsing...
r7441 elif l.startswith("Author:"):
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 author = self.recode(l[8:-1])
elif l.startswith("Tag:") or l.startswith("Tags:"):
t = l[l.index(':')+1:]
t = [ut.strip() for ut in t.split(',')]
if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
self.tags.update(dict.fromkeys(t, id))
elif l.startswith("Log:"):
# switch to gathering log
state = 1
log = ""
elif state == 1: # log
if l == "Members: \n":
# switch to gathering members
files = {}
oldrevs = []
log = self.recode(log[:-1])
state = 2
else:
# gather log
log += l
elif state == 2: # members
if l == "\n": # start of next entry
state = 0
p = [self.parent[id]]
if id == "1":
p = []
if branch == "HEAD":
branch = ""
if branch:
Benoit Boissinot
convert/cvs: do not compare None with int
r7472 latest = 0
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 # the last changeset that contains a base
# file is our parent
for r in oldrevs:
Benoit Boissinot
convert/cvs: do not compare None with int
r7472 latest = max(filerevids.get(r, 0), latest)
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 if latest:
p = [latest]
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 # add current commit to set
c = commit(author=author, date=date, parents=p,
desc=log, branch=branch)
self.changeset[id] = c
self.files[id] = files
else:
colon = l.rfind(':')
file = l[1:colon]
rev = l[colon+1:-2]
oldrev, rev = rev.split("->")
files[file] = rev
# save some information for identifying branch points
oldrevs.append("%s:%s" % (oldrev, file))
filerevids["%s:%s" % (rev, file)] = id
elif state == 3:
# swallow all input
continue
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:
Edouard Gomez
convert: check existence of ~/.cvspass before reading it
r7442 pf = open(cvspass)
for line in pf.read().splitlines():
part1, part2 = line.split(' ', 1)
if part1 == '/1':
# /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
part1, part2 = part2.split(' ', 1)
format = format1
else:
# :pserver:user@example.com:/cvsroot/foo Ah<Z
format = format0
if part1 == format:
passw = part2
break
pf.close()
Thomas Arendsen Hein
Improvement to 14ce129cfcd: Use try/except and pass filename on errors...
r7444 except IOError, inst:
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":
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.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:]
m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', 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":
Kostantinos Koukopoulos
convert should use default value when CVS_RSH is not set, that value...
r5860 rsh = os.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
cmd = [util.shellquote(arg) for arg in cmd]
cmd = util.quotecommand(' '.join(cmd))
Martin Geisler
util: remove ignored mode argument in popen[23]
r8339 self.writep, self.readp = util.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"):
Greg Ward
convert/cvs: improve error message on unexpected server output.
r9095 raise util.Abort(_("unexpected response from CVS server "
"(expected \"Valid-requests\", but got %r)")
% 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
def _getfile(self, name, rev):
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539
def chunkedread(fp, count):
# file-objects returned by socked.makefile() do not handle
# large read() requests very well.
chunksize = 65536
output = StringIO()
while count > 0:
data = fp.read(min(count, chunksize))
if not data:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_("%d bytes missing from remote file") % count)
Patrick Mezard
convert: read CVS files in chunks (issue 800)...
r5539 count -= len(data)
output.write(data)
return output.getvalue()
Brendan Cully
Split convert extension into common and repository type modules
r4536 if rev.endswith("(DEAD)"):
raise IOError
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 = ""
while 1:
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":
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:
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_("unknown CVS response: %s") % line)
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getfile(self, file, 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 data, mode = self._getfile(file, rev)
self.modecache[(file, rev)] = mode
return data
def getmode(self, file, rev):
return self.modecache[(file, rev)]
def getchanges(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 self.modecache = {}
Matt Mackall
replace util.sort with sorted built-in...
r8209 return sorted(self.files[rev].iteritems()), {}
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])