95 imports if a revmap is provided. |
103 imports if a revmap is provided. |
96 """ |
104 """ |
97 self.revmap = revmap |
105 self.revmap = revmap |
98 |
106 |
99 def _parse_view(self, path): |
107 def _parse_view(self, path): |
100 "Read changes affecting the path" |
108 b"Read changes affecting the path" |
101 cmd = 'p4 -G changes -s submitted %s' % procutil.shellquote(path) |
109 cmd = b'p4 -G changes -s submitted %s' % procutil.shellquote(path) |
102 stdout = procutil.popen(cmd, mode='rb') |
110 stdout = procutil.popen(cmd, mode=b'rb') |
103 p4changes = {} |
111 p4changes = {} |
104 for d in loaditer(stdout): |
112 for d in loaditer(stdout): |
105 c = d.get("change", None) |
113 c = d.get(b"change", None) |
106 if c: |
114 if c: |
107 p4changes[c] = True |
115 p4changes[c] = True |
108 return p4changes |
116 return p4changes |
109 |
117 |
110 def _parse(self, ui, path): |
118 def _parse(self, ui, path): |
111 "Prepare list of P4 filenames and revisions to import" |
119 b"Prepare list of P4 filenames and revisions to import" |
112 p4changes = {} |
120 p4changes = {} |
113 changeset = {} |
121 changeset = {} |
114 files_map = {} |
122 files_map = {} |
115 copies_map = {} |
123 copies_map = {} |
116 localname = {} |
124 localname = {} |
117 depotname = {} |
125 depotname = {} |
118 heads = [] |
126 heads = [] |
119 |
127 |
120 ui.status(_('reading p4 views\n')) |
128 ui.status(_(b'reading p4 views\n')) |
121 |
129 |
122 # read client spec or view |
130 # read client spec or view |
123 if "/" in path: |
131 if b"/" in path: |
124 p4changes.update(self._parse_view(path)) |
132 p4changes.update(self._parse_view(path)) |
125 if path.startswith("//") and path.endswith("/..."): |
133 if path.startswith(b"//") and path.endswith(b"/..."): |
126 views = {path[:-3]: ""} |
134 views = {path[:-3]: b""} |
127 else: |
135 else: |
128 views = {"//": ""} |
136 views = {b"//": b""} |
129 else: |
137 else: |
130 cmd = 'p4 -G client -o %s' % procutil.shellquote(path) |
138 cmd = b'p4 -G client -o %s' % procutil.shellquote(path) |
131 clientspec = marshal.load(procutil.popen(cmd, mode='rb')) |
139 clientspec = marshal.load(procutil.popen(cmd, mode=b'rb')) |
132 |
140 |
133 views = {} |
141 views = {} |
134 for client in clientspec: |
142 for client in clientspec: |
135 if client.startswith("View"): |
143 if client.startswith(b"View"): |
136 sview, cview = clientspec[client].split() |
144 sview, cview = clientspec[client].split() |
137 p4changes.update(self._parse_view(sview)) |
145 p4changes.update(self._parse_view(sview)) |
138 if sview.endswith("...") and cview.endswith("..."): |
146 if sview.endswith(b"...") and cview.endswith(b"..."): |
139 sview = sview[:-3] |
147 sview = sview[:-3] |
140 cview = cview[:-3] |
148 cview = cview[:-3] |
141 cview = cview[2:] |
149 cview = cview[2:] |
142 cview = cview[cview.find("/") + 1 :] |
150 cview = cview[cview.find(b"/") + 1 :] |
143 views[sview] = cview |
151 views[sview] = cview |
144 |
152 |
145 # list of changes that affect our source files |
153 # list of changes that affect our source files |
146 p4changes = p4changes.keys() |
154 p4changes = p4changes.keys() |
147 p4changes.sort(key=int) |
155 p4changes.sort(key=int) |
174 d = self._fetch_revision(change) |
182 d = self._fetch_revision(change) |
175 c = self._construct_commit(d, parents) |
183 c = self._construct_commit(d, parents) |
176 |
184 |
177 descarr = c.desc.splitlines(True) |
185 descarr = c.desc.splitlines(True) |
178 if len(descarr) > 0: |
186 if len(descarr) > 0: |
179 shortdesc = descarr[0].rstrip('\r\n') |
187 shortdesc = descarr[0].rstrip(b'\r\n') |
180 else: |
188 else: |
181 shortdesc = '**empty changelist description**' |
189 shortdesc = b'**empty changelist description**' |
182 |
190 |
183 t = '%s %s' % (c.rev, repr(shortdesc)[1:-1]) |
191 t = b'%s %s' % (c.rev, repr(shortdesc)[1:-1]) |
184 ui.status(stringutil.ellipsis(t, 80) + '\n') |
192 ui.status(stringutil.ellipsis(t, 80) + b'\n') |
185 |
193 |
186 files = [] |
194 files = [] |
187 copies = {} |
195 copies = {} |
188 copiedfiles = [] |
196 copiedfiles = [] |
189 i = 0 |
197 i = 0 |
190 while ("depotFile%d" % i) in d and ("rev%d" % i) in d: |
198 while (b"depotFile%d" % i) in d and (b"rev%d" % i) in d: |
191 oldname = d["depotFile%d" % i] |
199 oldname = d[b"depotFile%d" % i] |
192 filename = None |
200 filename = None |
193 for v in vieworder: |
201 for v in vieworder: |
194 if oldname.lower().startswith(v.lower()): |
202 if oldname.lower().startswith(v.lower()): |
195 filename = decodefilename(views[v] + oldname[len(v) :]) |
203 filename = decodefilename(views[v] + oldname[len(v) :]) |
196 break |
204 break |
197 if filename: |
205 if filename: |
198 files.append((filename, d["rev%d" % i])) |
206 files.append((filename, d[b"rev%d" % i])) |
199 depotname[filename] = oldname |
207 depotname[filename] = oldname |
200 if d.get("action%d" % i) == "move/add": |
208 if d.get(b"action%d" % i) == b"move/add": |
201 copiedfiles.append(filename) |
209 copiedfiles.append(filename) |
202 localname[oldname] = filename |
210 localname[oldname] = filename |
203 i += 1 |
211 i += 1 |
204 |
212 |
205 # Collect information about copied files |
213 # Collect information about copied files |
206 for filename in copiedfiles: |
214 for filename in copiedfiles: |
207 oldname = depotname[filename] |
215 oldname = depotname[filename] |
208 |
216 |
209 flcmd = 'p4 -G filelog %s' % procutil.shellquote(oldname) |
217 flcmd = b'p4 -G filelog %s' % procutil.shellquote(oldname) |
210 flstdout = procutil.popen(flcmd, mode='rb') |
218 flstdout = procutil.popen(flcmd, mode=b'rb') |
211 |
219 |
212 copiedfilename = None |
220 copiedfilename = None |
213 for d in loaditer(flstdout): |
221 for d in loaditer(flstdout): |
214 copiedoldname = None |
222 copiedoldname = None |
215 |
223 |
216 i = 0 |
224 i = 0 |
217 while ("change%d" % i) in d: |
225 while (b"change%d" % i) in d: |
218 if ( |
226 if ( |
219 d["change%d" % i] == change |
227 d[b"change%d" % i] == change |
220 and d["action%d" % i] == "move/add" |
228 and d[b"action%d" % i] == b"move/add" |
221 ): |
229 ): |
222 j = 0 |
230 j = 0 |
223 while ("file%d,%d" % (i, j)) in d: |
231 while (b"file%d,%d" % (i, j)) in d: |
224 if d["how%d,%d" % (i, j)] == "moved from": |
232 if d[b"how%d,%d" % (i, j)] == b"moved from": |
225 copiedoldname = d["file%d,%d" % (i, j)] |
233 copiedoldname = d[b"file%d,%d" % (i, j)] |
226 break |
234 break |
227 j += 1 |
235 j += 1 |
228 i += 1 |
236 i += 1 |
229 |
237 |
230 if copiedoldname and copiedoldname in localname: |
238 if copiedoldname and copiedoldname in localname: |
246 |
254 |
247 if lastid and len(changeset) > 0: |
255 if lastid and len(changeset) > 0: |
248 heads = [lastid] |
256 heads = [lastid] |
249 |
257 |
250 return { |
258 return { |
251 'changeset': changeset, |
259 b'changeset': changeset, |
252 'files': files_map, |
260 b'files': files_map, |
253 'copies': copies_map, |
261 b'copies': copies_map, |
254 'heads': heads, |
262 b'heads': heads, |
255 'depotname': depotname, |
263 b'depotname': depotname, |
256 } |
264 } |
257 |
265 |
258 @util.propertycache |
266 @util.propertycache |
259 def _parse_once(self): |
267 def _parse_once(self): |
260 return self._parse(self.ui, self.path) |
268 return self._parse(self.ui, self.path) |
261 |
269 |
262 @util.propertycache |
270 @util.propertycache |
263 def copies(self): |
271 def copies(self): |
264 return self._parse_once['copies'] |
272 return self._parse_once[b'copies'] |
265 |
273 |
266 @util.propertycache |
274 @util.propertycache |
267 def files(self): |
275 def files(self): |
268 return self._parse_once['files'] |
276 return self._parse_once[b'files'] |
269 |
277 |
270 @util.propertycache |
278 @util.propertycache |
271 def changeset(self): |
279 def changeset(self): |
272 return self._parse_once['changeset'] |
280 return self._parse_once[b'changeset'] |
273 |
281 |
274 @util.propertycache |
282 @util.propertycache |
275 def heads(self): |
283 def heads(self): |
276 return self._parse_once['heads'] |
284 return self._parse_once[b'heads'] |
277 |
285 |
278 @util.propertycache |
286 @util.propertycache |
279 def depotname(self): |
287 def depotname(self): |
280 return self._parse_once['depotname'] |
288 return self._parse_once[b'depotname'] |
281 |
289 |
282 def getheads(self): |
290 def getheads(self): |
283 return self.heads |
291 return self.heads |
284 |
292 |
285 def getfile(self, name, rev): |
293 def getfile(self, name, rev): |
286 cmd = 'p4 -G print %s' % procutil.shellquote( |
294 cmd = b'p4 -G print %s' % procutil.shellquote( |
287 "%s#%s" % (self.depotname[name], rev) |
295 b"%s#%s" % (self.depotname[name], rev) |
288 ) |
296 ) |
289 |
297 |
290 lasterror = None |
298 lasterror = None |
291 while True: |
299 while True: |
292 stdout = procutil.popen(cmd, mode='rb') |
300 stdout = procutil.popen(cmd, mode=b'rb') |
293 |
301 |
294 mode = None |
302 mode = None |
295 contents = [] |
303 contents = [] |
296 keywords = None |
304 keywords = None |
297 |
305 |
298 for d in loaditer(stdout): |
306 for d in loaditer(stdout): |
299 code = d["code"] |
307 code = d[b"code"] |
300 data = d.get("data") |
308 data = d.get(b"data") |
301 |
309 |
302 if code == "error": |
310 if code == b"error": |
303 # if this is the first time error happened |
311 # if this is the first time error happened |
304 # re-attempt getting the file |
312 # re-attempt getting the file |
305 if not lasterror: |
313 if not lasterror: |
306 lasterror = IOError(d["generic"], data) |
314 lasterror = IOError(d[b"generic"], data) |
307 # this will exit inner-most for-loop |
315 # this will exit inner-most for-loop |
308 break |
316 break |
309 else: |
317 else: |
310 raise lasterror |
318 raise lasterror |
311 |
319 |
312 elif code == "stat": |
320 elif code == b"stat": |
313 action = d.get("action") |
321 action = d.get(b"action") |
314 if action in ["purge", "delete", "move/delete"]: |
322 if action in [b"purge", b"delete", b"move/delete"]: |
315 return None, None |
323 return None, None |
316 p4type = self.re_type.match(d["type"]) |
324 p4type = self.re_type.match(d[b"type"]) |
317 if p4type: |
325 if p4type: |
318 mode = "" |
326 mode = b"" |
319 flags = (p4type.group(1) or "") + ( |
327 flags = (p4type.group(1) or b"") + ( |
320 p4type.group(3) or "" |
328 p4type.group(3) or b"" |
321 ) |
329 ) |
322 if "x" in flags: |
330 if b"x" in flags: |
323 mode = "x" |
331 mode = b"x" |
324 if p4type.group(2) == "symlink": |
332 if p4type.group(2) == b"symlink": |
325 mode = "l" |
333 mode = b"l" |
326 if "ko" in flags: |
334 if b"ko" in flags: |
327 keywords = self.re_keywords_old |
335 keywords = self.re_keywords_old |
328 elif "k" in flags: |
336 elif b"k" in flags: |
329 keywords = self.re_keywords |
337 keywords = self.re_keywords |
330 |
338 |
331 elif code == "text" or code == "binary": |
339 elif code == b"text" or code == b"binary": |
332 contents.append(data) |
340 contents.append(data) |
333 |
341 |
334 lasterror = None |
342 lasterror = None |
335 |
343 |
336 if not lasterror: |
344 if not lasterror: |
337 break |
345 break |
338 |
346 |
339 if mode is None: |
347 if mode is None: |
340 return None, None |
348 return None, None |
341 |
349 |
342 contents = ''.join(contents) |
350 contents = b''.join(contents) |
343 |
351 |
344 if keywords: |
352 if keywords: |
345 contents = keywords.sub("$\\1$", contents) |
353 contents = keywords.sub(b"$\\1$", contents) |
346 if mode == "l" and contents.endswith("\n"): |
354 if mode == b"l" and contents.endswith(b"\n"): |
347 contents = contents[:-1] |
355 contents = contents[:-1] |
348 |
356 |
349 return contents, mode |
357 return contents, mode |
350 |
358 |
351 def getchanges(self, rev, full): |
359 def getchanges(self, rev, full): |
352 if full: |
360 if full: |
353 raise error.Abort(_("convert from p4 does not support --full")) |
361 raise error.Abort(_(b"convert from p4 does not support --full")) |
354 return self.files[rev], self.copies[rev], set() |
362 return self.files[rev], self.copies[rev], set() |
355 |
363 |
356 def _construct_commit(self, obj, parents=None): |
364 def _construct_commit(self, obj, parents=None): |
357 """ |
365 """ |
358 Constructs a common.commit object from an unmarshalled |
366 Constructs a common.commit object from an unmarshalled |
359 `p4 describe` output |
367 `p4 describe` output |
360 """ |
368 """ |
361 desc = self.recode(obj.get("desc", "")) |
369 desc = self.recode(obj.get(b"desc", b"")) |
362 date = (int(obj["time"]), 0) # timezone not set |
370 date = (int(obj[b"time"]), 0) # timezone not set |
363 if parents is None: |
371 if parents is None: |
364 parents = [] |
372 parents = [] |
365 |
373 |
366 return common.commit( |
374 return common.commit( |
367 author=self.recode(obj["user"]), |
375 author=self.recode(obj[b"user"]), |
368 date=dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2'), |
376 date=dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2'), |
369 parents=parents, |
377 parents=parents, |
370 desc=desc, |
378 desc=desc, |
371 branch=None, |
379 branch=None, |
372 rev=obj['change'], |
380 rev=obj[b'change'], |
373 extra={"p4": obj['change'], "convert_revision": obj['change']}, |
381 extra={b"p4": obj[b'change'], b"convert_revision": obj[b'change']}, |
374 ) |
382 ) |
375 |
383 |
376 def _fetch_revision(self, rev): |
384 def _fetch_revision(self, rev): |
377 """Return an output of `p4 describe` including author, commit date as |
385 """Return an output of `p4 describe` including author, commit date as |
378 a dictionary.""" |
386 a dictionary.""" |
379 cmd = "p4 -G describe -s %s" % rev |
387 cmd = b"p4 -G describe -s %s" % rev |
380 stdout = procutil.popen(cmd, mode='rb') |
388 stdout = procutil.popen(cmd, mode=b'rb') |
381 return marshal.load(stdout) |
389 return marshal.load(stdout) |
382 |
390 |
383 def getcommit(self, rev): |
391 def getcommit(self, rev): |
384 if rev in self.changeset: |
392 if rev in self.changeset: |
385 return self.changeset[rev] |
393 return self.changeset[rev] |
386 elif rev in self.revmap: |
394 elif rev in self.revmap: |
387 d = self._fetch_revision(rev) |
395 d = self._fetch_revision(rev) |
388 return self._construct_commit(d, parents=None) |
396 return self._construct_commit(d, parents=None) |
389 raise error.Abort( |
397 raise error.Abort( |
390 _("cannot find %s in the revmap or parsed changesets") % rev |
398 _(b"cannot find %s in the revmap or parsed changesets") % rev |
391 ) |
399 ) |
392 |
400 |
393 def gettags(self): |
401 def gettags(self): |
394 return {} |
402 return {} |
395 |
403 |