##// END OF EJS Templates
patch: turn patch.diff() into a generator...
patch: turn patch.diff() into a generator This should even be a little faster than passing in an fp argument.

File last commit:

r7106:4674706b default
r7308:b6f5490e default
Show More
cvs.py
349 lines | 13.5 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
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'
if not self.builtin:
checktool(cvspsexe)
Patrick Mezard
convert: fail if an external required tool is not found
r5497
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()
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690
self._parse(ui)
Brendan Cully
Split convert extension into common and repository type modules
r4536 self._connect()
Frank Kingswood
convert: cvs.py - Allow user to use built-in CVS changeset code....
r6690 def _parse(self, ui):
Brendan Cully
Split convert extension into common and repository type modules
r4536 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:
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
ui.status(_('using builtin cvsps\n'))
db = cvsps.createlog(ui, cache='update')
db = cvsps.createchangeset(ui, db,
fuzz=int(ui.config('convert', 'cvsps.fuzz', 60)),
mergeto=ui.config('convert', 'cvsps.mergeto', None),
mergefrom=ui.config('convert', 'cvsps.mergefrom', None))
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
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]
# figure out the parent later
self.parent[id] = self.lastbranch[ancestor]
elif l.startswith("Author"):
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:
latest = None
# the last changeset that contains a base
# file is our parent
for r in oldrevs:
latest = max(filerevids.get(r, None), latest)
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"
Martin OConnor
Bug:1201 hg convert on CVS working copy produces Traceback...
r6813 pf = open(os.path.expanduser("~/.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":
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))
Dirkjan Ochtman
python2.6: use subprocess if available
r7106 self.writep, self.readp = util.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"):
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_("server sucks"))
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):
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"):
l = self.readp.readline()
l = self.readp.readline()
if l != "ok\n":
Martin Geisler
i18n: mark strings for translation in convert extension
r6956 raise util.Abort(_("unknown CVS response: %s") % l)
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):
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 = {}
Matt Mackall
util: add sort helper
r6762 return util.sort(self.files[rev].items()), {}
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):
Matt Mackall
util: add sort helper
r6762 return util.sort(self.files[rev].keys())