##// END OF EJS Templates
merge with crew
merge with crew

File last commit:

r6318:30898807 default
r6420:626a8e39 merge default
Show More
cvs.py
315 lines | 11.7 KiB | text/x-python | PythonLexer
Brendan Cully
Split convert extension into common and repository type modules
r4536 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
import os, locale, re, socket
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
Patrick Mezard
convert: fail if an external required tool is not found
r5497 from common import NoRepo, commit, converter_source, checktool
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
Eric Hopper
convert: Add convert.cvsps option to set up an alternate cvsps command line.
r6318 self.cmd = ui.config('convert', 'cvsps', 'cvsps -A -u --cvs-direct -q')
cvspsexe = self.cmd.split(None, 1)[0]
for tool in (cvspsexe, 'cvs'):
Patrick Mezard
convert: fail if an external required tool is not found
r5497 checktool(tool)
Brendan Cully
Split convert extension into common and repository type modules
r4536 self.changeset = {}
self.files = {}
self.tags = {}
self.lastbranch = {}
self.parent = {}
self.socket = None
self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
self.encoding = locale.getpreferredencoding()
self._parse()
self._connect()
def _parse(self):
if self.changeset:
return
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:
raise util.Abort('revision %s is not a patchset number or date' % self.rev)
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 = {}
Patrick Mezard
Fix Windows os.popen bug with interleaved stdout/stderr output...
r5481 for l in util.popen(cmd):
Brendan Cully
Split convert extension into common and repository type modules
r4536 if state == 0: # header
if l.startswith("PatchSet"):
id = l[9:-2]
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 if maxrev and int(id) > maxrev:
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # ignore everything
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 state = 3
Brendan Cully
Split convert extension into common and repository type modules
r4536 elif l.startswith("Date"):
date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
date = util.datestr(date)
elif l.startswith("Branch"):
branch = l[8:-1]
self.parent[id] = self.lastbranch.get(branch, 'bad')
self.lastbranch[branch] = id
elif l.startswith("Ancestor branch"):
ancestor = l[17:-1]
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # figure out the parent later
Matt Mackall
convert: try to be smarter about CVS branching...
r6077 self.parent[id] = self.lastbranch[ancestor]
Brendan Cully
Split convert extension into common and repository type modules
r4536 elif l.startswith("Author"):
author = self.recode(l[8:-1])
Eric Hopper
convert: handle new cvsps with Tags: and multiple tags.
r4698 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))
Brendan Cully
Split convert extension into common and repository type modules
r4536 elif l.startswith("Log:"):
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # switch to gathering log
Brendan Cully
Split convert extension into common and repository type modules
r4536 state = 1
log = ""
elif state == 1: # log
if l == "Members: \n":
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # switch to gathering members
Brendan Cully
Split convert extension into common and repository type modules
r4536 files = {}
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 oldrevs = []
Brendan Cully
Split convert extension into common and repository type modules
r4536 log = self.recode(log[:-1])
state = 2
else:
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # gather log
Brendan Cully
Split convert extension into common and repository type modules
r4536 log += l
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 elif state == 2: # members
if l == "\n": # start of next entry
Brendan Cully
Split convert extension into common and repository type modules
r4536 state = 0
p = [self.parent[id]]
if id == "1":
p = []
if branch == "HEAD":
branch = ""
Matt Mackall
convert: try to be smarter about CVS branching...
r6077 if branch:
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 latest = None
# the last changeset that contains a base
# file is our parent
for r in oldrevs:
Matt Mackall
convert: try to be smarter about CVS branching...
r6077 latest = max(filerevids.get(r, None), latest)
if latest:
p = [latest]
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
# add current commit to set
Brendan Cully
Split convert extension into common and repository type modules
r4536 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]
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 oldrev, rev = rev.split("->")
Brendan Cully
Split convert extension into common and repository type modules
r4536 files[file] = rev
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920
# save some information for identifying branch points
oldrevs.append("%s:%s" % (oldrev, file))
filerevids["%s:%s" % (rev, file)] = id
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 elif state == 3:
Thomas Arendsen Hein
CVS convert: Find correct parent for new branch (issue704)...
r5920 # swallow all input
Brendan Cully
convert: add -r argument specifying latest revision to convert
r4760 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']
self.ui.status("connecting to %s\n" % root)
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"
pf = open(os.path.join(os.environ["HOME"], ".cvspass"))
Thomas Arendsen Hein
CVS import: Support new-style .cvspass-file format....
r5082 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
Brendan Cully
Split convert extension into common and repository type modules
r4536 break
pf.close()
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":
Brendan Cully
convert: raise Abort instead of NoRepo when CVS pserver auth fails....
r5182 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))
self.writep, self.readp = os.popen2(cmd, 'b')
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"):
raise util.Abort("server sucks")
if "UseUnchanged" in r:
self.writep.write("UseUnchanged\n")
self.writep.flush()
r = self.readp.readline()
def getheads(self):
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:
raise util.Abort("%d bytes missing from remote file" % count)
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 "):
self.ui.warn("cvs server: %s\n" % line[2:])
elif line.startswith("Remove"):
l = self.readp.readline()
l = self.readp.readline()
if l != "ok\n":
raise util.Abort("unknown CVS response: %s" % l)
else:
raise util.Abort("unknown CVS response: %s" % line)
def getfile(self, file, rev):
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):
self.modecache = {}
files = self.files[rev]
cl = files.items()
cl.sort()
Brendan Cully
convert: look up copies in getchanges instead of getcommit...
r5121 return (cl, {})
Brendan Cully
Split convert extension into common and repository type modules
r4536
def getcommit(self, rev):
return self.changeset[rev]
def gettags(self):
return self.tags
Alexis S. L. Carvalho
convert_cvs: add --filemap support
r5381
def getchangedfiles(self, rev, i):
files = self.files[rev].keys()
files.sort()
return files