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