##// END OF EJS Templates
typing: add trivial type hints to the convert extension's common modules...
Matt Harbison -
r52578:0eb515c7 default
parent child Browse files
Show More
@@ -11,6 +11,13 b' import pickle'
11 import re
11 import re
12 import shlex
12 import shlex
13 import subprocess
13 import subprocess
14 import typing
15
16 from typing import (
17 Any,
18 AnyStr,
19 Optional,
20 )
14
21
15 from mercurial.i18n import _
22 from mercurial.i18n import _
16 from mercurial.pycompat import open
23 from mercurial.pycompat import open
@@ -26,9 +33,28 b' from mercurial.utils import ('
26 procutil,
33 procutil,
27 )
34 )
28
35
36 if typing.TYPE_CHECKING:
37 from typing import (
38 overload,
39 )
40 from mercurial import (
41 ui as uimod,
42 )
43
29 propertycache = util.propertycache
44 propertycache = util.propertycache
30
45
31
46
47 if typing.TYPE_CHECKING:
48
49 @overload
50 def _encodeornone(d: str) -> bytes:
51 pass
52
53 @overload
54 def _encodeornone(d: None) -> None:
55 pass
56
57
32 def _encodeornone(d):
58 def _encodeornone(d):
33 if d is None:
59 if d is None:
34 return
60 return
@@ -36,7 +62,7 b' def _encodeornone(d):'
36
62
37
63
38 class _shlexpy3proxy:
64 class _shlexpy3proxy:
39 def __init__(self, l):
65 def __init__(self, l: shlex.shlex) -> None:
40 self._l = l
66 self._l = l
41
67
42 def __iter__(self):
68 def __iter__(self):
@@ -50,11 +76,16 b' class _shlexpy3proxy:'
50 return self._l.infile or b'<unknown>'
76 return self._l.infile or b'<unknown>'
51
77
52 @property
78 @property
53 def lineno(self):
79 def lineno(self) -> int:
54 return self._l.lineno
80 return self._l.lineno
55
81
56
82
57 def shlexer(data=None, filepath=None, wordchars=None, whitespace=None):
83 def shlexer(
84 data=None,
85 filepath: Optional[str] = None,
86 wordchars: Optional[bytes] = None,
87 whitespace: Optional[bytes] = None,
88 ):
58 if data is None:
89 if data is None:
59 data = open(filepath, b'r', encoding='latin1')
90 data = open(filepath, b'r', encoding='latin1')
60 else:
91 else:
@@ -72,8 +103,8 b' def shlexer(data=None, filepath=None, wo'
72 return _shlexpy3proxy(l)
103 return _shlexpy3proxy(l)
73
104
74
105
75 def encodeargs(args):
106 def encodeargs(args: Any) -> bytes:
76 def encodearg(s):
107 def encodearg(s: bytes) -> bytes:
77 lines = base64.encodebytes(s)
108 lines = base64.encodebytes(s)
78 lines = [l.splitlines()[0] for l in pycompat.iterbytestr(lines)]
109 lines = [l.splitlines()[0] for l in pycompat.iterbytestr(lines)]
79 return b''.join(lines)
110 return b''.join(lines)
@@ -82,7 +113,7 b' def encodeargs(args):'
82 return encodearg(s)
113 return encodearg(s)
83
114
84
115
85 def decodeargs(s):
116 def decodeargs(s: bytes) -> Any:
86 s = base64.decodebytes(s)
117 s = base64.decodebytes(s)
87 return pickle.loads(s)
118 return pickle.loads(s)
88
119
@@ -91,7 +122,9 b' class MissingTool(Exception):'
91 pass
122 pass
92
123
93
124
94 def checktool(exe, name=None, abort=True):
125 def checktool(
126 exe: bytes, name: Optional[bytes] = None, abort: bool = True
127 ) -> None:
95 name = name or exe
128 name = name or exe
96 if not procutil.findexe(exe):
129 if not procutil.findexe(exe):
97 if abort:
130 if abort:
@@ -105,25 +138,25 b' class NoRepo(Exception):'
105 pass
138 pass
106
139
107
140
108 SKIPREV = b'SKIP'
141 SKIPREV: bytes = b'SKIP'
109
142
110
143
111 class commit:
144 class commit:
112 def __init__(
145 def __init__(
113 self,
146 self,
114 author,
147 author: bytes,
115 date,
148 date: bytes,
116 desc,
149 desc: bytes,
117 parents,
150 parents,
118 branch=None,
151 branch: Optional[bytes] = None,
119 rev=None,
152 rev=None,
120 extra=None,
153 extra=None,
121 sortkey=None,
154 sortkey=None,
122 saverev=True,
155 saverev=True,
123 phase=phases.draft,
156 phase: int = phases.draft,
124 optparents=None,
157 optparents=None,
125 ctx=None,
158 ctx=None,
126 ):
159 ) -> None:
127 self.author = author or b'unknown'
160 self.author = author or b'unknown'
128 self.date = date or b'0 0'
161 self.date = date or b'0 0'
129 self.desc = desc
162 self.desc = desc
@@ -141,7 +174,13 b' class commit:'
141 class converter_source:
174 class converter_source:
142 """Conversion source interface"""
175 """Conversion source interface"""
143
176
144 def __init__(self, ui, repotype, path=None, revs=None):
177 def __init__(
178 self,
179 ui: "uimod.ui",
180 repotype: bytes,
181 path: Optional[bytes] = None,
182 revs=None,
183 ) -> None:
145 """Initialize conversion source (or raise NoRepo("message")
184 """Initialize conversion source (or raise NoRepo("message")
146 exception if path is not a valid repository)"""
185 exception if path is not a valid repository)"""
147 self.ui = ui
186 self.ui = ui
@@ -151,7 +190,9 b' class converter_source:'
151
190
152 self.encoding = b'utf-8'
191 self.encoding = b'utf-8'
153
192
154 def checkhexformat(self, revstr, mapname=b'splicemap'):
193 def checkhexformat(
194 self, revstr: bytes, mapname: bytes = b'splicemap'
195 ) -> None:
155 """fails if revstr is not a 40 byte hex. mercurial and git both uses
196 """fails if revstr is not a 40 byte hex. mercurial and git both uses
156 such format for their revision numbering
197 such format for their revision numbering
157 """
198 """
@@ -161,10 +202,10 b' class converter_source:'
161 % (mapname, revstr)
202 % (mapname, revstr)
162 )
203 )
163
204
164 def before(self):
205 def before(self) -> None:
165 pass
206 pass
166
207
167 def after(self):
208 def after(self) -> None:
168 pass
209 pass
169
210
170 def targetfilebelongstosource(self, targetfilename):
211 def targetfilebelongstosource(self, targetfilename):
@@ -223,7 +264,7 b' class converter_source:'
223 """
264 """
224 raise NotImplementedError
265 raise NotImplementedError
225
266
226 def recode(self, s, encoding=None):
267 def recode(self, s: AnyStr, encoding: Optional[bytes] = None) -> bytes:
227 if not encoding:
268 if not encoding:
228 encoding = self.encoding or b'utf-8'
269 encoding = self.encoding or b'utf-8'
229
270
@@ -252,17 +293,17 b' class converter_source:'
252 """
293 """
253 raise NotImplementedError
294 raise NotImplementedError
254
295
255 def converted(self, rev, sinkrev):
296 def converted(self, rev, sinkrev) -> None:
256 '''Notify the source that a revision has been converted.'''
297 '''Notify the source that a revision has been converted.'''
257
298
258 def hasnativeorder(self):
299 def hasnativeorder(self) -> bool:
259 """Return true if this source has a meaningful, native revision
300 """Return true if this source has a meaningful, native revision
260 order. For instance, Mercurial revisions are store sequentially
301 order. For instance, Mercurial revisions are store sequentially
261 while there is no such global ordering with Darcs.
302 while there is no such global ordering with Darcs.
262 """
303 """
263 return False
304 return False
264
305
265 def hasnativeclose(self):
306 def hasnativeclose(self) -> bool:
266 """Return true if this source has ability to close branch."""
307 """Return true if this source has ability to close branch."""
267 return False
308 return False
268
309
@@ -280,7 +321,7 b' class converter_source:'
280 """
321 """
281 return {}
322 return {}
282
323
283 def checkrevformat(self, revstr, mapname=b'splicemap'):
324 def checkrevformat(self, revstr, mapname: bytes = b'splicemap') -> bool:
284 """revstr is a string that describes a revision in the given
325 """revstr is a string that describes a revision in the given
285 source control system. Return true if revstr has correct
326 source control system. Return true if revstr has correct
286 format.
327 format.
@@ -291,7 +332,7 b' class converter_source:'
291 class converter_sink:
332 class converter_sink:
292 """Conversion sink (target) interface"""
333 """Conversion sink (target) interface"""
293
334
294 def __init__(self, ui, repotype, path):
335 def __init__(self, ui: "uimod.ui", repotype: bytes, path: bytes) -> None:
295 """Initialize conversion sink (or raise NoRepo("message")
336 """Initialize conversion sink (or raise NoRepo("message")
296 exception if path is not a valid repository)
337 exception if path is not a valid repository)
297
338
@@ -359,10 +400,10 b' class converter_sink:'
359 filter empty revisions.
400 filter empty revisions.
360 """
401 """
361
402
362 def before(self):
403 def before(self) -> None:
363 pass
404 pass
364
405
365 def after(self):
406 def after(self) -> None:
366 pass
407 pass
367
408
368 def putbookmarks(self, bookmarks):
409 def putbookmarks(self, bookmarks):
@@ -385,17 +426,17 b' class converter_sink:'
385
426
386
427
387 class commandline:
428 class commandline:
388 def __init__(self, ui, command):
429 def __init__(self, ui: "uimod.ui", command: bytes) -> None:
389 self.ui = ui
430 self.ui = ui
390 self.command = command
431 self.command = command
391
432
392 def prerun(self):
433 def prerun(self) -> None:
393 pass
434 pass
394
435
395 def postrun(self):
436 def postrun(self) -> None:
396 pass
437 pass
397
438
398 def _cmdline(self, cmd, *args, **kwargs):
439 def _cmdline(self, cmd: bytes, *args: bytes, **kwargs) -> bytes:
399 kwargs = pycompat.byteskwargs(kwargs)
440 kwargs = pycompat.byteskwargs(kwargs)
400 cmdline = [self.command, cmd] + list(args)
441 cmdline = [self.command, cmd] + list(args)
401 for k, v in kwargs.items():
442 for k, v in kwargs.items():
@@ -416,7 +457,7 b' class commandline:'
416 cmdline = b' '.join(cmdline)
457 cmdline = b' '.join(cmdline)
417 return cmdline
458 return cmdline
418
459
419 def _run(self, cmd, *args, **kwargs):
460 def _run(self, cmd: bytes, *args: bytes, **kwargs):
420 def popen(cmdline):
461 def popen(cmdline):
421 p = subprocess.Popen(
462 p = subprocess.Popen(
422 procutil.tonativestr(cmdline),
463 procutil.tonativestr(cmdline),
@@ -429,13 +470,13 b' class commandline:'
429
470
430 return self._dorun(popen, cmd, *args, **kwargs)
471 return self._dorun(popen, cmd, *args, **kwargs)
431
472
432 def _run2(self, cmd, *args, **kwargs):
473 def _run2(self, cmd: bytes, *args: bytes, **kwargs):
433 return self._dorun(procutil.popen2, cmd, *args, **kwargs)
474 return self._dorun(procutil.popen2, cmd, *args, **kwargs)
434
475
435 def _run3(self, cmd, *args, **kwargs):
476 def _run3(self, cmd: bytes, *args: bytes, **kwargs):
436 return self._dorun(procutil.popen3, cmd, *args, **kwargs)
477 return self._dorun(procutil.popen3, cmd, *args, **kwargs)
437
478
438 def _dorun(self, openfunc, cmd, *args, **kwargs):
479 def _dorun(self, openfunc, cmd: bytes, *args: bytes, **kwargs):
439 cmdline = self._cmdline(cmd, *args, **kwargs)
480 cmdline = self._cmdline(cmd, *args, **kwargs)
440 self.ui.debug(b'running: %s\n' % (cmdline,))
481 self.ui.debug(b'running: %s\n' % (cmdline,))
441 self.prerun()
482 self.prerun()
@@ -444,20 +485,20 b' class commandline:'
444 finally:
485 finally:
445 self.postrun()
486 self.postrun()
446
487
447 def run(self, cmd, *args, **kwargs):
488 def run(self, cmd: bytes, *args: bytes, **kwargs):
448 p = self._run(cmd, *args, **kwargs)
489 p = self._run(cmd, *args, **kwargs)
449 output = p.communicate()[0]
490 output = p.communicate()[0]
450 self.ui.debug(output)
491 self.ui.debug(output)
451 return output, p.returncode
492 return output, p.returncode
452
493
453 def runlines(self, cmd, *args, **kwargs):
494 def runlines(self, cmd: bytes, *args: bytes, **kwargs):
454 p = self._run(cmd, *args, **kwargs)
495 p = self._run(cmd, *args, **kwargs)
455 output = p.stdout.readlines()
496 output = p.stdout.readlines()
456 p.wait()
497 p.wait()
457 self.ui.debug(b''.join(output))
498 self.ui.debug(b''.join(output))
458 return output, p.returncode
499 return output, p.returncode
459
500
460 def checkexit(self, status, output=b''):
501 def checkexit(self, status, output: bytes = b'') -> None:
461 if status:
502 if status:
462 if output:
503 if output:
463 self.ui.warn(_(b'%s error:\n') % self.command)
504 self.ui.warn(_(b'%s error:\n') % self.command)
@@ -465,12 +506,12 b' class commandline:'
465 msg = procutil.explainexit(status)
506 msg = procutil.explainexit(status)
466 raise error.Abort(b'%s %s' % (self.command, msg))
507 raise error.Abort(b'%s %s' % (self.command, msg))
467
508
468 def run0(self, cmd, *args, **kwargs):
509 def run0(self, cmd: bytes, *args: bytes, **kwargs):
469 output, status = self.run(cmd, *args, **kwargs)
510 output, status = self.run(cmd, *args, **kwargs)
470 self.checkexit(status, output)
511 self.checkexit(status, output)
471 return output
512 return output
472
513
473 def runlines0(self, cmd, *args, **kwargs):
514 def runlines0(self, cmd: bytes, *args: bytes, **kwargs):
474 output, status = self.runlines(cmd, *args, **kwargs)
515 output, status = self.runlines(cmd, *args, **kwargs)
475 self.checkexit(status, b''.join(output))
516 self.checkexit(status, b''.join(output))
476 return output
517 return output
@@ -493,7 +534,7 b' class commandline:'
493 # (and make happy Windows shells while doing this).
534 # (and make happy Windows shells while doing this).
494 return argmax // 2 - 1
535 return argmax // 2 - 1
495
536
496 def _limit_arglist(self, arglist, cmd, *args, **kwargs):
537 def _limit_arglist(self, arglist, cmd: bytes, *args: bytes, **kwargs):
497 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
538 cmdlen = len(self._cmdline(cmd, *args, **kwargs))
498 limit = self.argmax - cmdlen
539 limit = self.argmax - cmdlen
499 numbytes = 0
540 numbytes = 0
@@ -510,13 +551,13 b' class commandline:'
510 if fl:
551 if fl:
511 yield fl
552 yield fl
512
553
513 def xargs(self, arglist, cmd, *args, **kwargs):
554 def xargs(self, arglist, cmd: bytes, *args: bytes, **kwargs):
514 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
555 for l in self._limit_arglist(arglist, cmd, *args, **kwargs):
515 self.run0(cmd, *(list(args) + l), **kwargs)
556 self.run0(cmd, *(list(args) + l), **kwargs)
516
557
517
558
518 class mapfile(dict):
559 class mapfile(dict):
519 def __init__(self, ui, path):
560 def __init__(self, ui: "uimod.ui", path: bytes) -> None:
520 super(mapfile, self).__init__()
561 super(mapfile, self).__init__()
521 self.ui = ui
562 self.ui = ui
522 self.path = path
563 self.path = path
@@ -524,7 +565,7 b' class mapfile(dict):'
524 self.order = []
565 self.order = []
525 self._read()
566 self._read()
526
567
527 def _read(self):
568 def _read(self) -> None:
528 if not self.path:
569 if not self.path:
529 return
570 return
530 try:
571 try:
@@ -548,7 +589,7 b' class mapfile(dict):'
548 super(mapfile, self).__setitem__(key, value)
589 super(mapfile, self).__setitem__(key, value)
549 fp.close()
590 fp.close()
550
591
551 def __setitem__(self, key, value):
592 def __setitem__(self, key, value) -> None:
552 if self.fp is None:
593 if self.fp is None:
553 try:
594 try:
554 self.fp = open(self.path, b'ab')
595 self.fp = open(self.path, b'ab')
@@ -561,7 +602,7 b' class mapfile(dict):'
561 self.fp.flush()
602 self.fp.flush()
562 super(mapfile, self).__setitem__(key, value)
603 super(mapfile, self).__setitem__(key, value)
563
604
564 def close(self):
605 def close(self) -> None:
565 if self.fp:
606 if self.fp:
566 self.fp.close()
607 self.fp.close()
567 self.fp = None
608 self.fp = None
@@ -9,6 +9,14 b' import collections'
9 import heapq
9 import heapq
10 import os
10 import os
11 import shutil
11 import shutil
12 import typing
13
14 from typing import (
15 AnyStr,
16 Mapping,
17 Optional,
18 Union,
19 )
12
20
13 from mercurial.i18n import _
21 from mercurial.i18n import _
14 from mercurial.pycompat import open
22 from mercurial.pycompat import open
@@ -36,6 +44,11 b' from . import ('
36 subversion,
44 subversion,
37 )
45 )
38
46
47 if typing.TYPE_CHECKING:
48 from mercurial import (
49 ui as uimod,
50 )
51
39 mapfile = common.mapfile
52 mapfile = common.mapfile
40 MissingTool = common.MissingTool
53 MissingTool = common.MissingTool
41 NoRepo = common.NoRepo
54 NoRepo = common.NoRepo
@@ -53,10 +66,10 b' p4_source = p4.p4_source'
53 svn_sink = subversion.svn_sink
66 svn_sink = subversion.svn_sink
54 svn_source = subversion.svn_source
67 svn_source = subversion.svn_source
55
68
56 orig_encoding = b'ascii'
69 orig_encoding: bytes = b'ascii'
57
70
58
71
59 def readauthormap(ui, authorfile, authors=None):
72 def readauthormap(ui: "uimod.ui", authorfile, authors=None):
60 if authors is None:
73 if authors is None:
61 authors = {}
74 authors = {}
62 with open(authorfile, b'rb') as afile:
75 with open(authorfile, b'rb') as afile:
@@ -86,7 +99,7 b' def readauthormap(ui, authorfile, author'
86 return authors
99 return authors
87
100
88
101
89 def recode(s):
102 def recode(s: AnyStr) -> bytes:
90 if isinstance(s, str):
103 if isinstance(s, str):
91 return s.encode(pycompat.sysstr(orig_encoding), 'replace')
104 return s.encode(pycompat.sysstr(orig_encoding), 'replace')
92 else:
105 else:
@@ -95,7 +108,7 b' def recode(s):'
95 )
108 )
96
109
97
110
98 def mapbranch(branch, branchmap):
111 def mapbranch(branch: bytes, branchmap: Mapping[bytes, bytes]) -> bytes:
99 """
112 """
100 >>> bmap = {b'default': b'branch1'}
113 >>> bmap = {b'default': b'branch1'}
101 >>> for i in [b'', None]:
114 >>> for i in [b'', None]:
@@ -147,7 +160,7 b' sink_converters = ['
147 ]
160 ]
148
161
149
162
150 def convertsource(ui, path, type, revs):
163 def convertsource(ui: "uimod.ui", path: bytes, type: bytes, revs):
151 exceptions = []
164 exceptions = []
152 if type and type not in [s[0] for s in source_converters]:
165 if type and type not in [s[0] for s in source_converters]:
153 raise error.Abort(_(b'%s: invalid source repository type') % type)
166 raise error.Abort(_(b'%s: invalid source repository type') % type)
@@ -163,7 +176,9 b' def convertsource(ui, path, type, revs):'
163 raise error.Abort(_(b'%s: missing or unsupported repository') % path)
176 raise error.Abort(_(b'%s: missing or unsupported repository') % path)
164
177
165
178
166 def convertsink(ui, path, type):
179 def convertsink(
180 ui: "uimod.ui", path: bytes, type: bytes
181 ) -> Union[hgconvert.mercurial_sink, subversion.svn_sink]:
167 if type and type not in [s[0] for s in sink_converters]:
182 if type and type not in [s[0] for s in sink_converters]:
168 raise error.Abort(_(b'%s: invalid destination repository type') % type)
183 raise error.Abort(_(b'%s: invalid destination repository type') % type)
169 for name, sink in sink_converters:
184 for name, sink in sink_converters:
@@ -178,7 +193,9 b' def convertsink(ui, path, type):'
178
193
179
194
180 class progresssource:
195 class progresssource:
181 def __init__(self, ui, source, filecount):
196 def __init__(
197 self, ui: "uimod.ui", source, filecount: Optional[int]
198 ) -> None:
182 self.ui = ui
199 self.ui = ui
183 self.source = source
200 self.source = source
184 self.progress = ui.makeprogress(
201 self.progress = ui.makeprogress(
@@ -253,7 +270,7 b' class keysorter:'
253
270
254
271
255 class converter:
272 class converter:
256 def __init__(self, ui, source, dest, revmapfile, opts):
273 def __init__(self, ui: "uimod.ui", source, dest, revmapfile, opts) -> None:
257
274
258 self.source = source
275 self.source = source
259 self.dest = dest
276 self.dest = dest
@@ -280,7 +297,7 b' class converter:'
280 self.splicemap = self.parsesplicemap(opts.get(b'splicemap'))
297 self.splicemap = self.parsesplicemap(opts.get(b'splicemap'))
281 self.branchmap = mapfile(ui, opts.get(b'branchmap'))
298 self.branchmap = mapfile(ui, opts.get(b'branchmap'))
282
299
283 def parsesplicemap(self, path):
300 def parsesplicemap(self, path: bytes):
284 """check and validate the splicemap format and
301 """check and validate the splicemap format and
285 return a child/parents dictionary.
302 return a child/parents dictionary.
286 Format checking has two parts.
303 Format checking has two parts.
@@ -356,7 +373,7 b' class converter:'
356
373
357 return parents
374 return parents
358
375
359 def mergesplicemap(self, parents, splicemap):
376 def mergesplicemap(self, parents, splicemap) -> None:
360 """A splicemap redefines child/parent relationships. Check the
377 """A splicemap redefines child/parent relationships. Check the
361 map contains valid revision identifiers and merge the new
378 map contains valid revision identifiers and merge the new
362 links in the source graph.
379 links in the source graph.
@@ -488,7 +505,7 b' class converter:'
488
505
489 return s
506 return s
490
507
491 def writeauthormap(self):
508 def writeauthormap(self) -> None:
492 authorfile = self.authorfile
509 authorfile = self.authorfile
493 if authorfile:
510 if authorfile:
494 self.ui.status(_(b'writing author map file %s\n') % authorfile)
511 self.ui.status(_(b'writing author map file %s\n') % authorfile)
@@ -501,7 +518,7 b' class converter:'
501 )
518 )
502 ofile.close()
519 ofile.close()
503
520
504 def readauthormap(self, authorfile):
521 def readauthormap(self, authorfile) -> None:
505 self.authors = readauthormap(self.ui, authorfile, self.authors)
522 self.authors = readauthormap(self.ui, authorfile, self.authors)
506
523
507 def cachecommit(self, rev):
524 def cachecommit(self, rev):
@@ -511,7 +528,7 b' class converter:'
511 self.commitcache[rev] = commit
528 self.commitcache[rev] = commit
512 return commit
529 return commit
513
530
514 def copy(self, rev):
531 def copy(self, rev) -> None:
515 commit = self.commitcache[rev]
532 commit = self.commitcache[rev]
516 full = self.opts.get(b'full')
533 full = self.opts.get(b'full')
517 changes = self.source.getchanges(rev, full)
534 changes = self.source.getchanges(rev, full)
@@ -563,7 +580,7 b' class converter:'
563 self.source.converted(rev, newnode)
580 self.source.converted(rev, newnode)
564 self.map[rev] = newnode
581 self.map[rev] = newnode
565
582
566 def convert(self, sortmode):
583 def convert(self, sortmode) -> None:
567 try:
584 try:
568 self.source.before()
585 self.source.before()
569 self.dest.before()
586 self.dest.before()
@@ -628,7 +645,7 b' class converter:'
628 finally:
645 finally:
629 self.cleanup()
646 self.cleanup()
630
647
631 def cleanup(self):
648 def cleanup(self) -> None:
632 try:
649 try:
633 self.dest.after()
650 self.dest.after()
634 finally:
651 finally:
@@ -636,7 +653,9 b' class converter:'
636 self.map.close()
653 self.map.close()
637
654
638
655
639 def convert(ui, src, dest=None, revmapfile=None, **opts):
656 def convert(
657 ui: "uimod.ui", src, dest: Optional[bytes] = None, revmapfile=None, **opts
658 ) -> None:
640 opts = pycompat.byteskwargs(opts)
659 opts = pycompat.byteskwargs(opts)
641 global orig_encoding
660 global orig_encoding
642 orig_encoding = encoding.encoding
661 orig_encoding = encoding.encoding
@@ -6,6 +6,17 b''
6
6
7
7
8 import posixpath
8 import posixpath
9 import typing
10
11 from typing import (
12 Iterator,
13 Mapping,
14 MutableMapping,
15 Optional,
16 Set,
17 Tuple,
18 overload,
19 )
9
20
10 from mercurial.i18n import _
21 from mercurial.i18n import _
11 from mercurial import (
22 from mercurial import (
@@ -14,10 +25,15 b' from mercurial import ('
14 )
25 )
15 from . import common
26 from . import common
16
27
28 if typing.TYPE_CHECKING:
29 from mercurial import (
30 ui as uimod,
31 )
32
17 SKIPREV = common.SKIPREV
33 SKIPREV = common.SKIPREV
18
34
19
35
20 def rpairs(path):
36 def rpairs(path: bytes) -> Iterator[Tuple[bytes, bytes]]:
21 """Yield tuples with path split at '/', starting with the full path.
37 """Yield tuples with path split at '/', starting with the full path.
22 No leading, trailing or double '/', please.
38 No leading, trailing or double '/', please.
23 >>> for x in rpairs(b'foo/bar/baz'): print(x)
39 >>> for x in rpairs(b'foo/bar/baz'): print(x)
@@ -33,6 +49,17 b' def rpairs(path):'
33 yield b'.', path
49 yield b'.', path
34
50
35
51
52 if typing.TYPE_CHECKING:
53
54 @overload
55 def normalize(path: bytes) -> bytes:
56 pass
57
58 @overload
59 def normalize(path: None) -> None:
60 pass
61
62
36 def normalize(path):
63 def normalize(path):
37 """We use posixpath.normpath to support cross-platform path format.
64 """We use posixpath.normpath to support cross-platform path format.
38 However, it doesn't handle None input. So we wrap it up."""
65 However, it doesn't handle None input. So we wrap it up."""
@@ -46,7 +73,10 b' class filemapper:'
46 A name can be mapped to itself, a new name, or None (omit from new
73 A name can be mapped to itself, a new name, or None (omit from new
47 repository)."""
74 repository)."""
48
75
49 def __init__(self, ui, path=None):
76 rename: MutableMapping[bytes, bytes]
77 targetprefixes: Optional[Set[bytes]]
78
79 def __init__(self, ui: "uimod.ui", path=None) -> None:
50 self.ui = ui
80 self.ui = ui
51 self.include = {}
81 self.include = {}
52 self.exclude = {}
82 self.exclude = {}
@@ -56,10 +86,11 b' class filemapper:'
56 if self.parse(path):
86 if self.parse(path):
57 raise error.Abort(_(b'errors in filemap'))
87 raise error.Abort(_(b'errors in filemap'))
58
88
59 def parse(self, path):
89 # TODO: cmd==b'source' case breaks if ``path``is str
90 def parse(self, path) -> int:
60 errs = 0
91 errs = 0
61
92
62 def check(name, mapping, listname):
93 def check(name: bytes, mapping, listname: bytes):
63 if not name:
94 if not name:
64 self.ui.warn(
95 self.ui.warn(
65 _(b'%s:%d: path to %s is missing\n')
96 _(b'%s:%d: path to %s is missing\n')
@@ -110,7 +141,9 b' class filemapper:'
110 cmd = lex.get_token()
141 cmd = lex.get_token()
111 return errs
142 return errs
112
143
113 def lookup(self, name, mapping):
144 def lookup(
145 self, name: bytes, mapping: Mapping[bytes, bytes]
146 ) -> Tuple[bytes, bytes, bytes]:
114 name = normalize(name)
147 name = normalize(name)
115 for pre, suf in rpairs(name):
148 for pre, suf in rpairs(name):
116 try:
149 try:
@@ -119,7 +152,7 b' class filemapper:'
119 pass
152 pass
120 return b'', name, b''
153 return b'', name, b''
121
154
122 def istargetfile(self, filename):
155 def istargetfile(self, filename: bytes) -> bool:
123 """Return true if the given target filename is covered as a destination
156 """Return true if the given target filename is covered as a destination
124 of the filemap. This is useful for identifying what parts of the target
157 of the filemap. This is useful for identifying what parts of the target
125 repo belong to the source repo and what parts don't."""
158 repo belong to the source repo and what parts don't."""
@@ -143,7 +176,7 b' class filemapper:'
143 return True
176 return True
144 return False
177 return False
145
178
146 def __call__(self, name):
179 def __call__(self, name: bytes) -> Optional[bytes]:
147 if self.include:
180 if self.include:
148 inc = self.lookup(name, self.include)[0]
181 inc = self.lookup(name, self.include)[0]
149 else:
182 else:
@@ -165,7 +198,7 b' class filemapper:'
165 return newpre
198 return newpre
166 return name
199 return name
167
200
168 def active(self):
201 def active(self) -> bool:
169 return bool(self.include or self.exclude or self.rename)
202 return bool(self.include or self.exclude or self.rename)
170
203
171
204
@@ -185,7 +218,7 b' class filemapper:'
185
218
186
219
187 class filemap_source(common.converter_source):
220 class filemap_source(common.converter_source):
188 def __init__(self, ui, baseconverter, filemap):
221 def __init__(self, ui: "uimod.ui", baseconverter, filemap) -> None:
189 super(filemap_source, self).__init__(ui, baseconverter.repotype)
222 super(filemap_source, self).__init__(ui, baseconverter.repotype)
190 self.base = baseconverter
223 self.base = baseconverter
191 self.filemapper = filemapper(ui, filemap)
224 self.filemapper = filemapper(ui, filemap)
@@ -206,10 +239,10 b' class filemap_source(common.converter_so'
206 b'convert', b'ignoreancestorcheck'
239 b'convert', b'ignoreancestorcheck'
207 )
240 )
208
241
209 def before(self):
242 def before(self) -> None:
210 self.base.before()
243 self.base.before()
211
244
212 def after(self):
245 def after(self) -> None:
213 self.base.after()
246 self.base.after()
214
247
215 def setrevmap(self, revmap):
248 def setrevmap(self, revmap):
@@ -243,7 +276,7 b' class filemap_source(common.converter_so'
243 self.convertedorder = converted
276 self.convertedorder = converted
244 return self.base.setrevmap(revmap)
277 return self.base.setrevmap(revmap)
245
278
246 def rebuild(self):
279 def rebuild(self) -> bool:
247 if self._rebuilt:
280 if self._rebuilt:
248 return True
281 return True
249 self._rebuilt = True
282 self._rebuilt = True
@@ -276,7 +309,7 b' class filemap_source(common.converter_so'
276 def getheads(self):
309 def getheads(self):
277 return self.base.getheads()
310 return self.base.getheads()
278
311
279 def getcommit(self, rev):
312 def getcommit(self, rev: bytes):
280 # We want to save a reference to the commit objects to be able
313 # We want to save a reference to the commit objects to be able
281 # to rewrite their parents later on.
314 # to rewrite their parents later on.
282 c = self.commits[rev] = self.base.getcommit(rev)
315 c = self.commits[rev] = self.base.getcommit(rev)
@@ -292,7 +325,7 b' class filemap_source(common.converter_so'
292 return self.commits[rev]
325 return self.commits[rev]
293 return self.base.getcommit(rev)
326 return self.base.getcommit(rev)
294
327
295 def _discard(self, *revs):
328 def _discard(self, *revs) -> None:
296 for r in revs:
329 for r in revs:
297 if r is None:
330 if r is None:
298 continue
331 continue
@@ -304,7 +337,7 b' class filemap_source(common.converter_so'
304 if self._rebuilt:
337 if self._rebuilt:
305 del self.children[r]
338 del self.children[r]
306
339
307 def wanted(self, rev, i):
340 def wanted(self, rev, i) -> bool:
308 # Return True if we're directly interested in rev.
341 # Return True if we're directly interested in rev.
309 #
342 #
310 # i is an index selecting one of the parents of rev (if rev
343 # i is an index selecting one of the parents of rev (if rev
@@ -332,7 +365,7 b' class filemap_source(common.converter_so'
332 # doesn't consider it significant, and this revision should be dropped.
365 # doesn't consider it significant, and this revision should be dropped.
333 return not files and b'close' not in self.commits[rev].extra
366 return not files and b'close' not in self.commits[rev].extra
334
367
335 def mark_not_wanted(self, rev, p):
368 def mark_not_wanted(self, rev, p) -> None:
336 # Mark rev as not interesting and update data structures.
369 # Mark rev as not interesting and update data structures.
337
370
338 if p is None:
371 if p is None:
@@ -347,7 +380,7 b' class filemap_source(common.converter_so'
347 self.parentmap[rev] = self.parentmap[p]
380 self.parentmap[rev] = self.parentmap[p]
348 self.wantedancestors[rev] = self.wantedancestors[p]
381 self.wantedancestors[rev] = self.wantedancestors[p]
349
382
350 def mark_wanted(self, rev, parents):
383 def mark_wanted(self, rev, parents) -> None:
351 # Mark rev ss wanted and update data structures.
384 # Mark rev ss wanted and update data structures.
352
385
353 # rev will be in the restricted graph, so children of rev in
386 # rev will be in the restricted graph, so children of rev in
@@ -474,7 +507,7 b' class filemap_source(common.converter_so'
474
507
475 return files, ncopies, ncleanp2
508 return files, ncopies, ncleanp2
476
509
477 def targetfilebelongstosource(self, targetfilename):
510 def targetfilebelongstosource(self, targetfilename: bytes) -> bool:
478 return self.filemapper.istargetfile(targetfilename)
511 return self.filemapper.istargetfile(targetfilename)
479
512
480 def getfile(self, name, rev):
513 def getfile(self, name, rev):
@@ -484,7 +517,7 b' class filemap_source(common.converter_so'
484 def gettags(self):
517 def gettags(self):
485 return self.base.gettags()
518 return self.base.gettags()
486
519
487 def hasnativeorder(self):
520 def hasnativeorder(self) -> bool:
488 return self.base.hasnativeorder()
521 return self.base.hasnativeorder()
489
522
490 def lookuprev(self, rev):
523 def lookuprev(self, rev):
General Comments 0
You need to be logged in to leave comments. Login now