##// END OF EJS Templates
convert: avoid interpreting Windows path as CVS connection strings....
Patrick Mezard -
r5304:b85f7cc1 default
parent child Browse files
Show More
@@ -1,252 +1,253 b''
1 1 # CVS conversion code inspired by hg-cvs-import and git-cvsimport
2 2
3 3 import os, locale, re, socket
4 4 from mercurial import util
5 5
6 6 from common import NoRepo, commit, converter_source
7 7
8 8 class convert_cvs(converter_source):
9 9 def __init__(self, ui, path):
10 10 self.path = path
11 11 self.ui = ui
12 12 cvs = os.path.join(path, "CVS")
13 13 if not os.path.exists(cvs):
14 14 raise NoRepo("couldn't open CVS repo %s" % path)
15 15
16 16 self.changeset = {}
17 17 self.files = {}
18 18 self.tags = {}
19 19 self.lastbranch = {}
20 20 self.parent = {}
21 21 self.socket = None
22 22 self.cvsroot = file(os.path.join(cvs, "Root")).read()[:-1]
23 23 self.cvsrepo = file(os.path.join(cvs, "Repository")).read()[:-1]
24 24 self.encoding = locale.getpreferredencoding()
25 25 self._parse()
26 26 self._connect()
27 27
28 28 def _parse(self):
29 29 if self.changeset:
30 30 return
31 31
32 32 d = os.getcwd()
33 33 try:
34 34 os.chdir(self.path)
35 35 id = None
36 36 state = 0
37 37 for l in os.popen("cvsps -A -u --cvs-direct -q"):
38 38 if state == 0: # header
39 39 if l.startswith("PatchSet"):
40 40 id = l[9:-2]
41 41 elif l.startswith("Date"):
42 42 date = util.parsedate(l[6:-1], ["%Y/%m/%d %H:%M:%S"])
43 43 date = util.datestr(date)
44 44 elif l.startswith("Branch"):
45 45 branch = l[8:-1]
46 46 self.parent[id] = self.lastbranch.get(branch, 'bad')
47 47 self.lastbranch[branch] = id
48 48 elif l.startswith("Ancestor branch"):
49 49 ancestor = l[17:-1]
50 50 self.parent[id] = self.lastbranch[ancestor]
51 51 elif l.startswith("Author"):
52 52 author = self.recode(l[8:-1])
53 53 elif l.startswith("Tag:") or l.startswith("Tags:"):
54 54 t = l[l.index(':')+1:]
55 55 t = [ut.strip() for ut in t.split(',')]
56 56 if (len(t) > 1) or (t[0] and (t[0] != "(none)")):
57 57 self.tags.update(dict.fromkeys(t, id))
58 58 elif l.startswith("Log:"):
59 59 state = 1
60 60 log = ""
61 61 elif state == 1: # log
62 62 if l == "Members: \n":
63 63 files = {}
64 64 log = self.recode(log[:-1])
65 65 if log.isspace():
66 66 log = "*** empty log message ***\n"
67 67 state = 2
68 68 else:
69 69 log += l
70 70 elif state == 2:
71 71 if l == "\n": #
72 72 state = 0
73 73 p = [self.parent[id]]
74 74 if id == "1":
75 75 p = []
76 76 if branch == "HEAD":
77 77 branch = ""
78 78 c = commit(author=author, date=date, parents=p,
79 79 desc=log, branch=branch)
80 80 self.changeset[id] = c
81 81 self.files[id] = files
82 82 else:
83 83 colon = l.rfind(':')
84 84 file = l[1:colon]
85 85 rev = l[colon+1:-2]
86 86 rev = rev.split("->")[1]
87 87 files[file] = rev
88 88
89 89 self.heads = self.lastbranch.values()
90 90 finally:
91 91 os.chdir(d)
92 92
93 93 def _connect(self):
94 94 root = self.cvsroot
95 95 conntype = None
96 96 user, host = None, None
97 97 cmd = ['cvs', 'server']
98 98
99 99 self.ui.status("connecting to %s\n" % root)
100 100
101 101 if root.startswith(":pserver:"):
102 102 root = root[9:]
103 103 m = re.match(r'(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?(.*)',
104 104 root)
105 105 if m:
106 106 conntype = "pserver"
107 107 user, passw, serv, port, root = m.groups()
108 108 if not user:
109 109 user = "anonymous"
110 110 if not port:
111 111 port = 2401
112 112 else:
113 113 port = int(port)
114 114 format0 = ":pserver:%s@%s:%s" % (user, serv, root)
115 115 format1 = ":pserver:%s@%s:%d%s" % (user, serv, port, root)
116 116
117 117 if not passw:
118 118 passw = "A"
119 119 pf = open(os.path.join(os.environ["HOME"], ".cvspass"))
120 120 for line in pf.read().splitlines():
121 121 part1, part2 = line.split(' ', 1)
122 122 if part1 == '/1':
123 123 # /1 :pserver:user@example.com:2401/cvsroot/foo Ah<Z
124 124 part1, part2 = part2.split(' ', 1)
125 125 format = format1
126 126 else:
127 127 # :pserver:user@example.com:/cvsroot/foo Ah<Z
128 128 format = format0
129 129 if part1 == format:
130 130 passw = part2
131 131 break
132 132 pf.close()
133 133
134 134 sck = socket.socket()
135 135 sck.connect((serv, port))
136 136 sck.send("\n".join(["BEGIN AUTH REQUEST", root, user, passw,
137 137 "END AUTH REQUEST", ""]))
138 138 if sck.recv(128) != "I LOVE YOU\n":
139 139 raise NoRepo("CVS pserver authentication failed")
140 140
141 141 self.writep = self.readp = sck.makefile('r+')
142 142
143 143 if not conntype and root.startswith(":local:"):
144 144 conntype = "local"
145 145 root = root[7:]
146 146
147 147 if not conntype:
148 148 # :ext:user@host/home/user/path/to/cvsroot
149 149 if root.startswith(":ext:"):
150 150 root = root[5:]
151 151 m = re.match(r'(?:([^@:/]+)@)?([^:/]+):?(.*)', root)
152 if not m:
152 # Do not take Windows path "c:\foo\bar" for a connection strings
153 if os.path.isdir(root) or not m:
153 154 conntype = "local"
154 155 else:
155 156 conntype = "rsh"
156 157 user, host, root = m.group(1), m.group(2), m.group(3)
157 158
158 159 if conntype != "pserver":
159 160 if conntype == "rsh":
160 161 rsh = os.environ.get("CVS_RSH" or "rsh")
161 162 if user:
162 163 cmd = [rsh, '-l', user, host] + cmd
163 164 else:
164 165 cmd = [rsh, host] + cmd
165 166
166 167 # popen2 does not support argument lists under Windows
167 168 cmd = [util.shellquote(arg) for arg in cmd]
168 169 cmd = util.quotecommand(' '.join(cmd))
169 170 self.writep, self.readp = os.popen2(cmd, 'b')
170 171
171 172 self.realroot = root
172 173
173 174 self.writep.write("Root %s\n" % root)
174 175 self.writep.write("Valid-responses ok error Valid-requests Mode"
175 176 " M Mbinary E Checked-in Created Updated"
176 177 " Merged Removed\n")
177 178 self.writep.write("valid-requests\n")
178 179 self.writep.flush()
179 180 r = self.readp.readline()
180 181 if not r.startswith("Valid-requests"):
181 182 raise util.Abort("server sucks")
182 183 if "UseUnchanged" in r:
183 184 self.writep.write("UseUnchanged\n")
184 185 self.writep.flush()
185 186 r = self.readp.readline()
186 187
187 188 def getheads(self):
188 189 return self.heads
189 190
190 191 def _getfile(self, name, rev):
191 192 if rev.endswith("(DEAD)"):
192 193 raise IOError
193 194
194 195 args = ("-N -P -kk -r %s --" % rev).split()
195 196 args.append(os.path.join(self.cvsrepo, name))
196 197 for x in args:
197 198 self.writep.write("Argument %s\n" % x)
198 199 self.writep.write("Directory .\n%s\nco\n" % self.realroot)
199 200 self.writep.flush()
200 201
201 202 data = ""
202 203 while 1:
203 204 line = self.readp.readline()
204 205 if line.startswith("Created ") or line.startswith("Updated "):
205 206 self.readp.readline() # path
206 207 self.readp.readline() # entries
207 208 mode = self.readp.readline()[:-1]
208 209 count = int(self.readp.readline()[:-1])
209 210 data = self.readp.read(count)
210 211 elif line.startswith(" "):
211 212 data += line[1:]
212 213 elif line.startswith("M "):
213 214 pass
214 215 elif line.startswith("Mbinary "):
215 216 count = int(self.readp.readline()[:-1])
216 217 data = self.readp.read(count)
217 218 else:
218 219 if line == "ok\n":
219 220 return (data, "x" in mode and "x" or "")
220 221 elif line.startswith("E "):
221 222 self.ui.warn("cvs server: %s\n" % line[2:])
222 223 elif line.startswith("Remove"):
223 224 l = self.readp.readline()
224 225 l = self.readp.readline()
225 226 if l != "ok\n":
226 227 raise util.Abort("unknown CVS response: %s" % l)
227 228 else:
228 229 raise util.Abort("unknown CVS response: %s" % line)
229 230
230 231 def getfile(self, file, rev):
231 232 data, mode = self._getfile(file, rev)
232 233 self.modecache[(file, rev)] = mode
233 234 return data
234 235
235 236 def getmode(self, file, rev):
236 237 return self.modecache[(file, rev)]
237 238
238 239 def getchanges(self, rev):
239 240 self.modecache = {}
240 241 files = self.files[rev]
241 242 cl = files.items()
242 243 cl.sort()
243 244 return cl
244 245
245 246 def recode(self, text):
246 247 return text.decode(self.encoding, "replace").encode("utf-8")
247 248
248 249 def getcommit(self, rev):
249 250 return self.changeset[rev]
250 251
251 252 def gettags(self):
252 253 return self.tags
General Comments 0
You need to be logged in to leave comments. Login now