comparison hgext/convert/p4.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children be8552f25cab
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
22 22
23 from . import common 23 from . import common
24 24
25 25
26 def loaditer(f): 26 def loaditer(f):
27 "Yield the dictionary objects generated by p4" 27 b"Yield the dictionary objects generated by p4"
28 try: 28 try:
29 while True: 29 while True:
30 d = marshal.load(f) 30 d = marshal.load(f)
31 if not d: 31 if not d:
32 break 32 break
42 >>> decodefilename(b'portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid') 42 >>> decodefilename(b'portable-net45%252Bnetcore45%252Bwp8%252BMonoAndroid')
43 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid' 43 'portable-net45%2Bnetcore45%2Bwp8%2BMonoAndroid'
44 >>> decodefilename(b'//Depot/Directory/%2525/%2523/%23%40.%2A') 44 >>> decodefilename(b'//Depot/Directory/%2525/%2523/%23%40.%2A')
45 '//Depot/Directory/%25/%23/#@.*' 45 '//Depot/Directory/%25/%23/#@.*'
46 """ 46 """
47 replacements = [('%2A', '*'), ('%23', '#'), ('%40', '@'), ('%25', '%')] 47 replacements = [
48 (b'%2A', b'*'),
49 (b'%23', b'#'),
50 (b'%40', b'@'),
51 (b'%25', b'%'),
52 ]
48 for k, v in replacements: 53 for k, v in replacements:
49 filename = filename.replace(k, v) 54 filename = filename.replace(k, v)
50 return filename 55 return filename
51 56
52 57
55 # avoid import cycle 60 # avoid import cycle
56 from . import convcmd 61 from . import convcmd
57 62
58 super(p4_source, self).__init__(ui, repotype, path, revs=revs) 63 super(p4_source, self).__init__(ui, repotype, path, revs=revs)
59 64
60 if "/" in path and not path.startswith('//'): 65 if b"/" in path and not path.startswith(b'//'):
61 raise common.NoRepo( 66 raise common.NoRepo(
62 _('%s does not look like a P4 repository') % path 67 _(b'%s does not look like a P4 repository') % path
63 ) 68 )
64 69
65 common.checktool('p4', abort=False) 70 common.checktool(b'p4', abort=False)
66 71
67 self.revmap = {} 72 self.revmap = {}
68 self.encoding = self.ui.config( 73 self.encoding = self.ui.config(
69 'convert', 'p4.encoding', convcmd.orig_encoding 74 b'convert', b'p4.encoding', convcmd.orig_encoding
70 ) 75 )
71 self.re_type = re.compile( 76 self.re_type = re.compile(
72 br"([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)" 77 br"([a-z]+)?(text|binary|symlink|apple|resource|unicode|utf\d+)"
73 br"(\+\w+)?$" 78 br"(\+\w+)?$"
74 ) 79 )
78 ) 83 )
79 self.re_keywords_old = re.compile(br"\$(Id|Header):[^$\n]*\$") 84 self.re_keywords_old = re.compile(br"\$(Id|Header):[^$\n]*\$")
80 85
81 if revs and len(revs) > 1: 86 if revs and len(revs) > 1:
82 raise error.Abort( 87 raise error.Abort(
83 _("p4 source does not support specifying " "multiple revisions") 88 _(
89 b"p4 source does not support specifying "
90 b"multiple revisions"
91 )
84 ) 92 )
85 93
86 def setrevmap(self, revmap): 94 def setrevmap(self, revmap):
87 """Sets the parsed revmap dictionary. 95 """Sets the parsed revmap dictionary.
88 96
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)
149 # list with depot pathnames, longest first 157 # list with depot pathnames, longest first
150 vieworder = views.keys() 158 vieworder = views.keys()
151 vieworder.sort(key=len, reverse=True) 159 vieworder.sort(key=len, reverse=True)
152 160
153 # handle revision limiting 161 # handle revision limiting
154 startrev = self.ui.config('convert', 'p4.startrev') 162 startrev = self.ui.config(b'convert', b'p4.startrev')
155 163
156 # now read the full changelists to get the list of file revisions 164 # now read the full changelists to get the list of file revisions
157 ui.status(_('collecting p4 changelists\n')) 165 ui.status(_(b'collecting p4 changelists\n'))
158 lastid = None 166 lastid = None
159 for change in p4changes: 167 for change in p4changes:
160 if startrev and int(change) < int(startrev): 168 if startrev and int(change) < int(startrev):
161 continue 169 continue
162 if self.revs and int(change) > int(self.revs[0]): 170 if self.revs and int(change) > int(self.revs[0]):
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:
233 241
234 if copiedfilename: 242 if copiedfilename:
235 copies[filename] = copiedfilename 243 copies[filename] = copiedfilename
236 else: 244 else:
237 ui.warn( 245 ui.warn(
238 _("cannot find source for copied file: %s@%s\n") 246 _(b"cannot find source for copied file: %s@%s\n")
239 % (filename, change) 247 % (filename, change)
240 ) 248 )
241 249
242 changeset[change] = c 250 changeset[change] = c
243 files_map[change] = files 251 files_map[change] = files
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