##// END OF EJS Templates
convert/cvs: do not compare None with int
Benoit Boissinot -
r7472:9d457bb3 default
parent child Browse files
Show More
@@ -1,356 +1,356 b''
1 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
1 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
2
2
3 import os, locale, re, socket, errno
3 import os, locale, re, socket, errno
4 from cStringIO import StringIO
4 from cStringIO import StringIO
5 from mercurial import util
5 from mercurial import util
6 from mercurial.i18n import _
6 from mercurial.i18n import _
7
7
8 from common import NoRepo, commit, converter_source, checktool
8 from common import NoRepo, commit, converter_source, checktool
9 import cvsps
9 import cvsps
10
10
11 class convert_cvs(converter_source):
11 class convert_cvs(converter_source):
12 def __init__(self, ui, path, rev=None):
12 def __init__(self, ui, path, rev=None):
13 super(convert_cvs, self).__init__(ui, path, rev=rev)
13 super(convert_cvs, self).__init__(ui, path, rev=rev)
14
14
15 cvs = os.path.join(path, "CVS")
15 cvs = os.path.join(path, "CVS")
16 if not os.path.exists(cvs):
16 if not os.path.exists(cvs):
17 raise NoRepo("%s does not look like a CVS checkout" % path)
17 raise NoRepo("%s does not look like a CVS checkout" % path)
18
18
19 checktool('cvs')
19 checktool('cvs')
20 self.cmd = ui.config('convert', 'cvsps', 'builtin')
20 self.cmd = ui.config('convert', 'cvsps', 'builtin')
21 cvspsexe = self.cmd.split(None, 1)[0]
21 cvspsexe = self.cmd.split(None, 1)[0]
22 self.builtin = cvspsexe == 'builtin'
22 self.builtin = cvspsexe == 'builtin'
23
23
24 if not self.builtin:
24 if not self.builtin:
25 checktool(cvspsexe)
25 checktool(cvspsexe)
26
26
27 self.changeset = {}
27 self.changeset = {}
28 self.files = {}
28 self.files = {}
29 self.tags = {}
29 self.tags = {}
30 self.lastbranch = {}
30 self.lastbranch = {}
31 self.parent = {}
31 self.parent = {}
32 self.socket = None
32 self.socket = None
33 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
33 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
34 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
34 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
35 self.encoding = locale.getpreferredencoding()
35 self.encoding = locale.getpreferredencoding()
36
36
37 self._parse(ui)
37 self._parse(ui)
38 self._connect()
38 self._connect()
39
39
40 def _parse(self, ui):
40 def _parse(self, ui):
41 if self.changeset:
41 if self.changeset:
42 return
42 return
43
43
44 maxrev = 0
44 maxrev = 0
45 cmd = self.cmd
45 cmd = self.cmd
46 if self.rev:
46 if self.rev:
47 # TODO: handle tags
47 # TODO: handle tags
48 try:
48 try:
49 # patchset number?
49 # patchset number?
50 maxrev = int(self.rev)
50 maxrev = int(self.rev)
51 except ValueError:
51 except ValueError:
52 try:
52 try:
53 # date
53 # date
54 util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S'])
54 util.parsedate(self.rev, ['%Y/%m/%d %H:%M:%S'])
55 cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev)
55 cmd = '%s -d "1970/01/01 00:00:01" -d "%s"' % (cmd, self.rev)
56 except util.Abort:
56 except util.Abort:
57 raise util.Abort(_('revision %s is not a patchset number or date') % self.rev)
57 raise util.Abort(_('revision %s is not a patchset number or date') % self.rev)
58
58
59 d = os.getcwd()
59 d = os.getcwd()
60 try:
60 try:
61 os.chdir(self.path)
61 os.chdir(self.path)
62 id = None
62 id = None
63 state = 0
63 state = 0
64 filerevids = {}
64 filerevids = {}
65
65
66 if self.builtin:
66 if self.builtin:
67 # builtin cvsps code
67 # builtin cvsps code
68 ui.status(_('using builtin cvsps\n'))
68 ui.status(_('using builtin cvsps\n'))
69
69
70 db = cvsps.createlog(ui, cache='update')
70 db = cvsps.createlog(ui, cache='update')
71 db = cvsps.createchangeset(ui, db,
71 db = cvsps.createchangeset(ui, db,
72 fuzz=int(ui.config('convert', 'cvsps.fuzz', 60)),
72 fuzz=int(ui.config('convert', 'cvsps.fuzz', 60)),
73 mergeto=ui.config('convert', 'cvsps.mergeto', None),
73 mergeto=ui.config('convert', 'cvsps.mergeto', None),
74 mergefrom=ui.config('convert', 'cvsps.mergefrom', None))
74 mergefrom=ui.config('convert', 'cvsps.mergefrom', None))
75
75
76 for cs in db:
76 for cs in db:
77 if maxrev and cs.id>maxrev:
77 if maxrev and cs.id>maxrev:
78 break
78 break
79 id = str(cs.id)
79 id = str(cs.id)
80 cs.author = self.recode(cs.author)
80 cs.author = self.recode(cs.author)
81 self.lastbranch[cs.branch] = id
81 self.lastbranch[cs.branch] = id
82 cs.comment = self.recode(cs.comment)
82 cs.comment = self.recode(cs.comment)
83 date = util.datestr(cs.date)
83 date = util.datestr(cs.date)
84 self.tags.update(dict.fromkeys(cs.tags, id))
84 self.tags.update(dict.fromkeys(cs.tags, id))
85
85
86 files = {}
86 files = {}
87 for f in cs.entries:
87 for f in cs.entries:
88 files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
88 files[f.file] = "%s%s" % ('.'.join([str(x) for x in f.revision]),
89 ['', '(DEAD)'][f.dead])
89 ['', '(DEAD)'][f.dead])
90
90
91 # add current commit to set
91 # add current commit to set
92 c = commit(author=cs.author, date=date,
92 c = commit(author=cs.author, date=date,
93 parents=[str(p.id) for p in cs.parents],
93 parents=[str(p.id) for p in cs.parents],
94 desc=cs.comment, branch=cs.branch or '')
94 desc=cs.comment, branch=cs.branch or '')
95 self.changeset[id] = c
95 self.changeset[id] = c
96 self.files[id] = files
96 self.files[id] = files
97 else:
97 else:
98 # external cvsps
98 # external cvsps
99 for l in util.popen(cmd):
99 for l in util.popen(cmd):
100 if state == 0: # header
100 if state == 0: # header
101 if l.startswith("PatchSet"):
101 if l.startswith("PatchSet"):
102 id = l[9:-2]
102 id = l[9:-2]
103 if maxrev and int(id) > maxrev:
103 if maxrev and int(id) > maxrev:
104 # ignore everything
104 # ignore everything
105 state = 3
105 state = 3
106 elif l.startswith("Date:"):
106 elif l.startswith("Date:"):
107 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
107 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
108 date = util.datestr(date)
108 date = util.datestr(date)
109 elif l.startswith("Branch:"):
109 elif l.startswith("Branch:"):
110 branch = l[8:-1]
110 branch = l[8:-1]
111 self.parent[id] = self.lastbranch.get(branch, 'bad')
111 self.parent[id] = self.lastbranch.get(branch, 'bad')
112 self.lastbranch[branch] = id
112 self.lastbranch[branch] = id
113 elif l.startswith("Ancestor branch:"):
113 elif l.startswith("Ancestor branch:"):
114 ancestor = l[17:-1]
114 ancestor = l[17:-1]
115 # figure out the parent later
115 # figure out the parent later
116 self.parent[id] = self.lastbranch[ancestor]
116 self.parent[id] = self.lastbranch[ancestor]
117 elif l.startswith("Author:"):
117 elif l.startswith("Author:"):
118 author = self.recode(l[8:-1])
118 author = self.recode(l[8:-1])
119 elif l.startswith("Tag:") or l.startswith("Tags:"):
119 elif l.startswith("Tag:") or l.startswith("Tags:"):
120 t = l[l.index(':')+1:]
120 t = l[l.index(':')+1:]
121 t = [ut.strip() for ut in t.split(',')]
121 t = [ut.strip() for ut in t.split(',')]
122 if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
122 if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
123 self.tags.update(dict.fromkeys(t, id))
123 self.tags.update(dict.fromkeys(t, id))
124 elif l.startswith("Log:"):
124 elif l.startswith("Log:"):
125 # switch to gathering log
125 # switch to gathering log
126 state = 1
126 state = 1
127 log = ""
127 log = ""
128 elif state == 1: # log
128 elif state == 1: # log
129 if l == "Members: \n":
129 if l == "Members: \n":
130 # switch to gathering members
130 # switch to gathering members
131 files = {}
131 files = {}
132 oldrevs = []
132 oldrevs = []
133 log = self.recode(log[:-1])
133 log = self.recode(log[:-1])
134 state = 2
134 state = 2
135 else:
135 else:
136 # gather log
136 # gather log
137 log += l
137 log += l
138 elif state == 2: # members
138 elif state == 2: # members
139 if l == "\n": # start of next entry
139 if l == "\n": # start of next entry
140 state = 0
140 state = 0
141 p = [self.parent[id]]
141 p = [self.parent[id]]
142 if id == "1":
142 if id == "1":
143 p = []
143 p = []
144 if branch == "HEAD":
144 if branch == "HEAD":
145 branch = ""
145 branch = ""
146 if branch:
146 if branch:
147 latest = None
147 latest = 0
148 # the last changeset that contains a base
148 # the last changeset that contains a base
149 # file is our parent
149 # file is our parent
150 for r in oldrevs:
150 for r in oldrevs:
151 latest = max(filerevids.get(r, None), latest)
151 latest = max(filerevids.get(r, 0), latest)
152 if latest:
152 if latest:
153 p = [latest]
153 p = [latest]
154
154
155 # add current commit to set
155 # add current commit to set
156 c = commit(author=author, date=date, parents=p,
156 c = commit(author=author, date=date, parents=p,
157 desc=log, branch=branch)
157 desc=log, branch=branch)
158 self.changeset[id] = c
158 self.changeset[id] = c
159 self.files[id] = files
159 self.files[id] = files
160 else:
160 else:
161 colon = l.rfind(':')
161 colon = l.rfind(':')
162 file = l[1:colon]
162 file = l[1:colon]
163 rev = l[colon+1:-2]
163 rev = l[colon+1:-2]
164 oldrev, rev = rev.split("->")
164 oldrev, rev = rev.split("->")
165 files[file] = rev
165 files[file] = rev
166
166
167 # save some information for identifying branch points
167 # save some information for identifying branch points
168 oldrevs.append("%s:%s" % (oldrev, file))
168 oldrevs.append("%s:%s" % (oldrev, file))
169 filerevids["%s:%s" % (rev, file)] = id
169 filerevids["%s:%s" % (rev, file)] = id
170 elif state == 3:
170 elif state == 3:
171 # swallow all input
171 # swallow all input
172 continue
172 continue
173
173
174 self.heads = self.lastbranch.values()
174 self.heads = self.lastbranch.values()
175 finally:
175 finally:
176 os.chdir(d)
176 os.chdir(d)
177
177
178 def _connect(self):
178 def _connect(self):
179 root = self.cvsroot
179 root = self.cvsroot
180 conntype = None
180 conntype = None
181 user, host = None, None
181 user, host = None, None
182 cmd = ['cvs', 'server']
182 cmd = ['cvs', 'server']
183
183
184 self.ui.status(_("connecting to %s\n") % root)
184 self.ui.status(_("connecting to %s\n") % root)
185
185
186 if root.startswith(":pserver:"):
186 if root.startswith(":pserver:"):
187 root = root[9:]
187 root = root[9:]
188 m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)',
188 m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)',
189 root)
189 root)
190 if m:
190 if m:
191 conntype = "pserver"
191 conntype = "pserver"
192 user, passw, serv, port, root = m.groups()
192 user, passw, serv, port, root = m.groups()
193 if not user:
193 if not user:
194 user = "anonymous"
194 user = "anonymous"
195 if not port:
195 if not port:
196 port = 2401
196 port = 2401
197 else:
197 else:
198 port = int(port)
198 port = int(port)
199 format0 = ":pserver:%s@%s:%s" % (user, serv, root)
199 format0 = ":pserver:%s@%s:%s" % (user, serv, root)
200 format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root)
200 format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root)
201
201
202 if not passw:
202 if not passw:
203 passw = "A"
203 passw = "A"
204 cvspass = os.path.expanduser("~/.cvspass")
204 cvspass = os.path.expanduser("~/.cvspass")
205 try:
205 try:
206 pf = open(cvspass)
206 pf = open(cvspass)
207 for line in pf.read().splitlines():
207 for line in pf.read().splitlines():
208 part1, part2 = line.split(' ', 1)
208 part1, part2 = line.split(' ', 1)
209 if part1 == '/1':
209 if part1 == '/1':
210 # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
210 # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
211 part1, part2 = part2.split(' ', 1)
211 part1, part2 = part2.split(' ', 1)
212 format = format1
212 format = format1
213 else:
213 else:
214 # :pserver:user@example.com:/cvsroot/foo Ah<Z
214 # :pserver:user@example.com:/cvsroot/foo Ah<Z
215 format = format0
215 format = format0
216 if part1 == format:
216 if part1 == format:
217 passw = part2
217 passw = part2
218 break
218 break
219 pf.close()
219 pf.close()
220 except IOError, inst:
220 except IOError, inst:
221 if inst.errno != errno.ENOENT:
221 if inst.errno != errno.ENOENT:
222 if not getattr(inst, 'filename', None):
222 if not getattr(inst, 'filename', None):
223 inst.filename = cvspass
223 inst.filename = cvspass
224 raise
224 raise
225
225
226 sck = socket.socket()
226 sck = socket.socket()
227 sck.connect((serv, port))
227 sck.connect((serv, port))
228 sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw,
228 sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw,
229 "END AUTH REQUEST", ""]))
229 "END AUTH REQUEST", ""]))
230 if sck.recv(128) != "I LOVE YOU\n":
230 if sck.recv(128) != "I LOVE YOU\n":
231 raise util.Abort(_("CVS pserver authentication failed"))
231 raise util.Abort(_("CVS pserver authentication failed"))
232
232
233 self.writep = self.readp = sck.makefile('r+')
233 self.writep = self.readp = sck.makefile('r+')
234
234
235 if not conntype and root.startswith(":local:"):
235 if not conntype and root.startswith(":local:"):
236 conntype = "local"
236 conntype = "local"
237 root = root[7:]
237 root = root[7:]
238
238
239 if not conntype:
239 if not conntype:
240 # :ext:user@host/home/user/path/to/cvsroot
240 # :ext:user@host/home/user/path/to/cvsroot
241 if root.startswith(":ext:"):
241 if root.startswith(":ext:"):
242 root = root[5:]
242 root = root[5:]
243 m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
243 m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
244 # Do not take Windows path "c:\foo\bar" for a connection strings
244 # Do not take Windows path "c:\foo\bar" for a connection strings
245 if os.path.isdir(root) or not m:
245 if os.path.isdir(root) or not m:
246 conntype = "local"
246 conntype = "local"
247 else:
247 else:
248 conntype = "rsh"
248 conntype = "rsh"
249 user, host, root = m.group(1), m.group(2), m.group(3)
249 user, host, root = m.group(1), m.group(2), m.group(3)
250
250
251 if conntype != "pserver":
251 if conntype != "pserver":
252 if conntype == "rsh":
252 if conntype == "rsh":
253 rsh = os.environ.get("CVS_RSH") or "ssh"
253 rsh = os.environ.get("CVS_RSH") or "ssh"
254 if user:
254 if user:
255 cmd = [rsh, '-l', user, host] + cmd
255 cmd = [rsh, '-l', user, host] + cmd
256 else:
256 else:
257 cmd = [rsh, host] + cmd
257 cmd = [rsh, host] + cmd
258
258
259 # popen2 does not support argument lists under Windows
259 # popen2 does not support argument lists under Windows
260 cmd = [util.shellquote(arg) for arg in cmd]
260 cmd = [util.shellquote(arg) for arg in cmd]
261 cmd = util.quotecommand(' '.join(cmd))
261 cmd = util.quotecommand(' '.join(cmd))
262 self.writep, self.readp = util.popen2(cmd, 'b')
262 self.writep, self.readp = util.popen2(cmd, 'b')
263
263
264 self.realroot = root
264 self.realroot = root
265
265
266 self.writep.write("Root %s\n" % root)
266 self.writep.write("Root %s\n" % root)
267 self.writep.write("Valid-responses ok error Valid-requests Mode"
267 self.writep.write("Valid-responses ok error Valid-requests Mode"
268 " M Mbinary E Checked-in Created Updated"
268 " M Mbinary E Checked-in Created Updated"
269 " Merged Removed\n")
269 " Merged Removed\n")
270 self.writep.write("valid-requests\n")
270 self.writep.write("valid-requests\n")
271 self.writep.flush()
271 self.writep.flush()
272 r = self.readp.readline()
272 r = self.readp.readline()
273 if not r.startswith("Valid-requests"):
273 if not r.startswith("Valid-requests"):
274 raise util.Abort(_("server sucks"))
274 raise util.Abort(_("server sucks"))
275 if "UseUnchanged" in r:
275 if "UseUnchanged" in r:
276 self.writep.write("UseUnchanged\n")
276 self.writep.write("UseUnchanged\n")
277 self.writep.flush()
277 self.writep.flush()
278 r = self.readp.readline()
278 r = self.readp.readline()
279
279
280 def getheads(self):
280 def getheads(self):
281 return self.heads
281 return self.heads
282
282
283 def _getfile(self, name, rev):
283 def _getfile(self, name, rev):
284
284
285 def chunkedread(fp, count):
285 def chunkedread(fp, count):
286 # file-objects returned by socked.makefile() do not handle
286 # file-objects returned by socked.makefile() do not handle
287 # large read() requests very well.
287 # large read() requests very well.
288 chunksize = 65536
288 chunksize = 65536
289 output = StringIO()
289 output = StringIO()
290 while count > 0:
290 while count > 0:
291 data = fp.read(min(count, chunksize))
291 data = fp.read(min(count, chunksize))
292 if not data:
292 if not data:
293 raise util.Abort(_("%d bytes missing from remote file") % count)
293 raise util.Abort(_("%d bytes missing from remote file") % count)
294 count -= len(data)
294 count -= len(data)
295 output.write(data)
295 output.write(data)
296 return output.getvalue()
296 return output.getvalue()
297
297
298 if rev.endswith("(DEAD)"):
298 if rev.endswith("(DEAD)"):
299 raise IOError
299 raise IOError
300
300
301 args = ("-N -P -kk -r %s --" % rev).split()
301 args = ("-N -P -kk -r %s --" % rev).split()
302 args.append(self.cvsrepo + '/' + name)
302 args.append(self.cvsrepo + '/' + name)
303 for x in args:
303 for x in args:
304 self.writep.write("Argument %s\n" % x)
304 self.writep.write("Argument %s\n" % x)
305 self.writep.write("Directory .\n%s\nco\n" % self.realroot)
305 self.writep.write("Directory .\n%s\nco\n" % self.realroot)
306 self.writep.flush()
306 self.writep.flush()
307
307
308 data = ""
308 data = ""
309 while 1:
309 while 1:
310 line = self.readp.readline()
310 line = self.readp.readline()
311 if line.startswith("Created ") or line.startswith("Updated "):
311 if line.startswith("Created ") or line.startswith("Updated "):
312 self.readp.readline() # path
312 self.readp.readline() # path
313 self.readp.readline() # entries
313 self.readp.readline() # entries
314 mode = self.readp.readline()[:-1]
314 mode = self.readp.readline()[:-1]
315 count = int(self.readp.readline()[:-1])
315 count = int(self.readp.readline()[:-1])
316 data = chunkedread(self.readp, count)
316 data = chunkedread(self.readp, count)
317 elif line.startswith(" "):
317 elif line.startswith(" "):
318 data += line[1:]
318 data += line[1:]
319 elif line.startswith("M "):
319 elif line.startswith("M "):
320 pass
320 pass
321 elif line.startswith("Mbinary "):
321 elif line.startswith("Mbinary "):
322 count = int(self.readp.readline()[:-1])
322 count = int(self.readp.readline()[:-1])
323 data = chunkedread(self.readp, count)
323 data = chunkedread(self.readp, count)
324 else:
324 else:
325 if line == "ok\n":
325 if line == "ok\n":
326 return (data, "x" in mode and "x" or "")
326 return (data, "x" in mode and "x" or "")
327 elif line.startswith("E "):
327 elif line.startswith("E "):
328 self.ui.warn(_("cvs server: %s\n") % line[2:])
328 self.ui.warn(_("cvs server: %s\n") % line[2:])
329 elif line.startswith("Remove"):
329 elif line.startswith("Remove"):
330 l = self.readp.readline()
330 l = self.readp.readline()
331 l = self.readp.readline()
331 l = self.readp.readline()
332 if l != "ok\n":
332 if l != "ok\n":
333 raise util.Abort(_("unknown CVS response: %s") % l)
333 raise util.Abort(_("unknown CVS response: %s") % l)
334 else:
334 else:
335 raise util.Abort(_("unknown CVS response: %s") % line)
335 raise util.Abort(_("unknown CVS response: %s") % line)
336
336
337 def getfile(self, file, rev):
337 def getfile(self, file, rev):
338 data, mode = self._getfile(file, rev)
338 data, mode = self._getfile(file, rev)
339 self.modecache[(file, rev)] = mode
339 self.modecache[(file, rev)] = mode
340 return data
340 return data
341
341
342 def getmode(self, file, rev):
342 def getmode(self, file, rev):
343 return self.modecache[(file, rev)]
343 return self.modecache[(file, rev)]
344
344
345 def getchanges(self, rev):
345 def getchanges(self, rev):
346 self.modecache = {}
346 self.modecache = {}
347 return util.sort(self.files[rev].items()), {}
347 return util.sort(self.files[rev].items()), {}
348
348
349 def getcommit(self, rev):
349 def getcommit(self, rev):
350 return self.changeset[rev]
350 return self.changeset[rev]
351
351
352 def gettags(self):
352 def gettags(self):
353 return self.tags
353 return self.tags
354
354
355 def getchangedfiles(self, rev, i):
355 def getchangedfiles(self, rev, i):
356 return util.sort(self.files[rev].keys())
356 return util.sort(self.files[rev].keys())
General Comments 0
You need to be logged in to leave comments. Login now