comparison hgext/fastannotate/commands.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 4aa72cdf616f
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
32 command = registrar.command(cmdtable) 32 command = registrar.command(cmdtable)
33 33
34 34
35 def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts): 35 def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts):
36 """generate paths matching given patterns""" 36 """generate paths matching given patterns"""
37 perfhack = repo.ui.configbool('fastannotate', 'perfhack') 37 perfhack = repo.ui.configbool(b'fastannotate', b'perfhack')
38 38
39 # disable perfhack if: 39 # disable perfhack if:
40 # a) any walkopt is used 40 # a) any walkopt is used
41 # b) if we treat pats as plain file names, some of them do not have 41 # b) if we treat pats as plain file names, some of them do not have
42 # corresponding linelog files 42 # corresponding linelog files
43 if perfhack: 43 if perfhack:
44 # cwd related to reporoot 44 # cwd related to reporoot
45 reporoot = os.path.dirname(repo.path) 45 reporoot = os.path.dirname(repo.path)
46 reldir = os.path.relpath(encoding.getcwd(), reporoot) 46 reldir = os.path.relpath(encoding.getcwd(), reporoot)
47 if reldir == '.': 47 if reldir == b'.':
48 reldir = '' 48 reldir = b''
49 if any(opts.get(o[1]) for o in commands.walkopts): # a) 49 if any(opts.get(o[1]) for o in commands.walkopts): # a)
50 perfhack = False 50 perfhack = False
51 else: # b) 51 else: # b)
52 relpats = [ 52 relpats = [
53 os.path.relpath(p, reporoot) if os.path.isabs(p) else p 53 os.path.relpath(p, reporoot) if os.path.isabs(p) else p
54 for p in pats 54 for p in pats
55 ] 55 ]
56 # disable perfhack on '..' since it allows escaping from the repo 56 # disable perfhack on '..' since it allows escaping from the repo
57 if any( 57 if any(
58 ( 58 (
59 '..' in f 59 b'..' in f
60 or not os.path.isfile( 60 or not os.path.isfile(
61 facontext.pathhelper(repo, f, aopts).linelogpath 61 facontext.pathhelper(repo, f, aopts).linelogpath
62 ) 62 )
63 ) 63 )
64 for f in relpats 64 for f in relpats
71 for p in relpats: 71 for p in relpats:
72 yield os.path.join(reldir, p) 72 yield os.path.join(reldir, p)
73 else: 73 else:
74 74
75 def bad(x, y): 75 def bad(x, y):
76 raise error.Abort("%s: %s" % (x, y)) 76 raise error.Abort(b"%s: %s" % (x, y))
77 77
78 ctx = scmutil.revsingle(repo, rev) 78 ctx = scmutil.revsingle(repo, rev)
79 m = scmutil.match(ctx, pats, opts, badfn=bad) 79 m = scmutil.match(ctx, pats, opts, badfn=bad)
80 for p in ctx.walk(m): 80 for p in ctx.walk(m):
81 yield p 81 yield p
82 82
83 83
84 fastannotatecommandargs = { 84 fastannotatecommandargs = {
85 r'options': [ 85 r'options': [
86 ('r', 'rev', '.', _('annotate the specified revision'), _('REV')), 86 (b'r', b'rev', b'.', _(b'annotate the specified revision'), _(b'REV')),
87 ('u', 'user', None, _('list the author (long with -v)')), 87 (b'u', b'user', None, _(b'list the author (long with -v)')),
88 ('f', 'file', None, _('list the filename')), 88 (b'f', b'file', None, _(b'list the filename')),
89 ('d', 'date', None, _('list the date (short with -q)')), 89 (b'd', b'date', None, _(b'list the date (short with -q)')),
90 ('n', 'number', None, _('list the revision number (default)')), 90 (b'n', b'number', None, _(b'list the revision number (default)')),
91 ('c', 'changeset', None, _('list the changeset')), 91 (b'c', b'changeset', None, _(b'list the changeset')),
92 ( 92 (
93 'l', 93 b'l',
94 'line-number', 94 b'line-number',
95 None, 95 None,
96 _('show line number at the first ' 'appearance'), 96 _(b'show line number at the first ' b'appearance'),
97 ), 97 ),
98 ('e', 'deleted', None, _('show deleted lines (slow) (EXPERIMENTAL)')), 98 (
99 ('', 'no-content', None, _('do not show file content (EXPERIMENTAL)')), 99 b'e',
100 ('', 'no-follow', None, _("don't follow copies and renames")), 100 b'deleted',
101 ( 101 None,
102 '', 102 _(b'show deleted lines (slow) (EXPERIMENTAL)'),
103 'linear', 103 ),
104 (
105 b'',
106 b'no-content',
107 None,
108 _(b'do not show file content (EXPERIMENTAL)'),
109 ),
110 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
111 (
112 b'',
113 b'linear',
104 None, 114 None,
105 _( 115 _(
106 'enforce linear history, ignore second parent ' 116 b'enforce linear history, ignore second parent '
107 'of merges (EXPERIMENTAL)' 117 b'of merges (EXPERIMENTAL)'
108 ), 118 ),
109 ), 119 ),
110 ('', 'long-hash', None, _('show long changeset hash (EXPERIMENTAL)')), 120 (
111 ( 121 b'',
112 '', 122 b'long-hash',
113 'rebuild', 123 None,
114 None, 124 _(b'show long changeset hash (EXPERIMENTAL)'),
115 _('rebuild cache even if it exists ' '(EXPERIMENTAL)'), 125 ),
126 (
127 b'',
128 b'rebuild',
129 None,
130 _(b'rebuild cache even if it exists ' b'(EXPERIMENTAL)'),
116 ), 131 ),
117 ] 132 ]
118 + commands.diffwsopts 133 + commands.diffwsopts
119 + commands.walkopts 134 + commands.walkopts
120 + commands.formatteropts, 135 + commands.formatteropts,
121 r'synopsis': _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), 136 r'synopsis': _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
122 r'inferrepo': True, 137 r'inferrepo': True,
123 } 138 }
124 139
125 140
126 def fastannotate(ui, repo, *pats, **opts): 141 def fastannotate(ui, repo, *pats, **opts):
153 repo, avoid --linear, --no-follow, or any diff options. As the server 168 repo, avoid --linear, --no-follow, or any diff options. As the server
154 won't be able to populate annotate cache when non-default options 169 won't be able to populate annotate cache when non-default options
155 affecting results are used. 170 affecting results are used.
156 """ 171 """
157 if not pats: 172 if not pats:
158 raise error.Abort(_('at least one filename or pattern is required')) 173 raise error.Abort(_(b'at least one filename or pattern is required'))
159 174
160 # performance hack: filtered repo can be slow. unfilter by default. 175 # performance hack: filtered repo can be slow. unfilter by default.
161 if ui.configbool('fastannotate', 'unfilteredrepo'): 176 if ui.configbool(b'fastannotate', b'unfilteredrepo'):
162 repo = repo.unfiltered() 177 repo = repo.unfiltered()
163 178
164 opts = pycompat.byteskwargs(opts) 179 opts = pycompat.byteskwargs(opts)
165 180
166 rev = opts.get('rev', '.') 181 rev = opts.get(b'rev', b'.')
167 rebuild = opts.get('rebuild', False) 182 rebuild = opts.get(b'rebuild', False)
168 183
169 diffopts = patch.difffeatureopts( 184 diffopts = patch.difffeatureopts(
170 ui, opts, section='annotate', whitespace=True 185 ui, opts, section=b'annotate', whitespace=True
171 ) 186 )
172 aopts = facontext.annotateopts( 187 aopts = facontext.annotateopts(
173 diffopts=diffopts, 188 diffopts=diffopts,
174 followmerge=not opts.get('linear', False), 189 followmerge=not opts.get(b'linear', False),
175 followrename=not opts.get('no_follow', False), 190 followrename=not opts.get(b'no_follow', False),
176 ) 191 )
177 192
178 if not any( 193 if not any(
179 opts.get(s) for s in ['user', 'date', 'file', 'number', 'changeset'] 194 opts.get(s)
195 for s in [b'user', b'date', b'file', b'number', b'changeset']
180 ): 196 ):
181 # default 'number' for compatibility. but fastannotate is more 197 # default 'number' for compatibility. but fastannotate is more
182 # efficient with "changeset", "line-number" and "no-content". 198 # efficient with "changeset", "line-number" and "no-content".
183 for name in ui.configlist('fastannotate', 'defaultformat', ['number']): 199 for name in ui.configlist(
200 b'fastannotate', b'defaultformat', [b'number']
201 ):
184 opts[name] = True 202 opts[name] = True
185 203
186 ui.pager('fastannotate') 204 ui.pager(b'fastannotate')
187 template = opts.get('template') 205 template = opts.get(b'template')
188 if template == 'json': 206 if template == b'json':
189 formatter = faformatter.jsonformatter(ui, repo, opts) 207 formatter = faformatter.jsonformatter(ui, repo, opts)
190 else: 208 else:
191 formatter = faformatter.defaultformatter(ui, repo, opts) 209 formatter = faformatter.defaultformatter(ui, repo, opts)
192 showdeleted = opts.get('deleted', False) 210 showdeleted = opts.get(b'deleted', False)
193 showlines = not bool(opts.get('no_content')) 211 showlines = not bool(opts.get(b'no_content'))
194 showpath = opts.get('file', False) 212 showpath = opts.get(b'file', False)
195 213
196 # find the head of the main (master) branch 214 # find the head of the main (master) branch
197 master = ui.config('fastannotate', 'mainbranch') or rev 215 master = ui.config(b'fastannotate', b'mainbranch') or rev
198 216
199 # paths will be used for prefetching and the real annotating 217 # paths will be used for prefetching and the real annotating
200 paths = list(_matchpaths(repo, rev, pats, opts, aopts)) 218 paths = list(_matchpaths(repo, rev, pats, opts, aopts))
201 219
202 # for client, prefetch from the server 220 # for client, prefetch from the server
203 if util.safehasattr(repo, 'prefetchfastannotate'): 221 if util.safehasattr(repo, b'prefetchfastannotate'):
204 repo.prefetchfastannotate(paths) 222 repo.prefetchfastannotate(paths)
205 223
206 for path in paths: 224 for path in paths:
207 result = lines = existinglines = None 225 result = lines = existinglines = None
208 while True: 226 while True:
236 formatter.end() 254 formatter.end()
237 255
238 256
239 _newopts = set() 257 _newopts = set()
240 _knownopts = { 258 _knownopts = {
241 opt[1].replace('-', '_') 259 opt[1].replace(b'-', b'_')
242 for opt in (fastannotatecommandargs[r'options'] + commands.globalopts) 260 for opt in (fastannotatecommandargs[r'options'] + commands.globalopts)
243 } 261 }
244 262
245 263
246 def _annotatewrapper(orig, ui, repo, *pats, **opts): 264 def _annotatewrapper(orig, ui, repo, *pats, **opts):
247 """used by wrapdefault""" 265 """used by wrapdefault"""
248 # we need this hack until the obsstore has 0.0 seconds perf impact 266 # we need this hack until the obsstore has 0.0 seconds perf impact
249 if ui.configbool('fastannotate', 'unfilteredrepo'): 267 if ui.configbool(b'fastannotate', b'unfilteredrepo'):
250 repo = repo.unfiltered() 268 repo = repo.unfiltered()
251 269
252 # treat the file as text (skip the isbinary check) 270 # treat the file as text (skip the isbinary check)
253 if ui.configbool('fastannotate', 'forcetext'): 271 if ui.configbool(b'fastannotate', b'forcetext'):
254 opts[r'text'] = True 272 opts[r'text'] = True
255 273
256 # check if we need to do prefetch (client-side) 274 # check if we need to do prefetch (client-side)
257 rev = opts.get(r'rev') 275 rev = opts.get(r'rev')
258 if util.safehasattr(repo, 'prefetchfastannotate') and rev is not None: 276 if util.safehasattr(repo, b'prefetchfastannotate') and rev is not None:
259 paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) 277 paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts)))
260 repo.prefetchfastannotate(paths) 278 repo.prefetchfastannotate(paths)
261 279
262 return orig(ui, repo, *pats, **opts) 280 return orig(ui, repo, *pats, **opts)
263 281
264 282
265 def registercommand(): 283 def registercommand():
266 """register the fastannotate command""" 284 """register the fastannotate command"""
267 name = 'fastannotate|fastblame|fa' 285 name = b'fastannotate|fastblame|fa'
268 command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate) 286 command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate)
269 287
270 288
271 def wrapdefault(): 289 def wrapdefault():
272 """wrap the default annotate command, to be aware of the protocol""" 290 """wrap the default annotate command, to be aware of the protocol"""
273 extensions.wrapcommand(commands.table, 'annotate', _annotatewrapper) 291 extensions.wrapcommand(commands.table, b'annotate', _annotatewrapper)
274 292
275 293
276 @command( 294 @command(
277 'debugbuildannotatecache', 295 b'debugbuildannotatecache',
278 [('r', 'rev', '', _('build up to the specific revision'), _('REV'))] 296 [(b'r', b'rev', b'', _(b'build up to the specific revision'), _(b'REV'))]
279 + commands.walkopts, 297 + commands.walkopts,
280 _('[-r REV] FILE...'), 298 _(b'[-r REV] FILE...'),
281 ) 299 )
282 def debugbuildannotatecache(ui, repo, *pats, **opts): 300 def debugbuildannotatecache(ui, repo, *pats, **opts):
283 """incrementally build fastannotate cache up to REV for specified files 301 """incrementally build fastannotate cache up to REV for specified files
284 302
285 If REV is not specified, use the config 'fastannotate.mainbranch'. 303 If REV is not specified, use the config 'fastannotate.mainbranch'.
289 307
290 The annotate cache will be built using the default diff and follow 308 The annotate cache will be built using the default diff and follow
291 options and lives in '.hg/fastannotate/default'. 309 options and lives in '.hg/fastannotate/default'.
292 """ 310 """
293 opts = pycompat.byteskwargs(opts) 311 opts = pycompat.byteskwargs(opts)
294 rev = opts.get('REV') or ui.config('fastannotate', 'mainbranch') 312 rev = opts.get(b'REV') or ui.config(b'fastannotate', b'mainbranch')
295 if not rev: 313 if not rev:
296 raise error.Abort( 314 raise error.Abort(
297 _('you need to provide a revision'), 315 _(b'you need to provide a revision'),
298 hint=_('set fastannotate.mainbranch or use --rev'), 316 hint=_(b'set fastannotate.mainbranch or use --rev'),
299 ) 317 )
300 if ui.configbool('fastannotate', 'unfilteredrepo'): 318 if ui.configbool(b'fastannotate', b'unfilteredrepo'):
301 repo = repo.unfiltered() 319 repo = repo.unfiltered()
302 ctx = scmutil.revsingle(repo, rev) 320 ctx = scmutil.revsingle(repo, rev)
303 m = scmutil.match(ctx, pats, opts) 321 m = scmutil.match(ctx, pats, opts)
304 paths = list(ctx.walk(m)) 322 paths = list(ctx.walk(m))
305 if util.safehasattr(repo, 'prefetchfastannotate'): 323 if util.safehasattr(repo, b'prefetchfastannotate'):
306 # client 324 # client
307 if opts.get('REV'): 325 if opts.get(b'REV'):
308 raise error.Abort(_('--rev cannot be used for client')) 326 raise error.Abort(_(b'--rev cannot be used for client'))
309 repo.prefetchfastannotate(paths) 327 repo.prefetchfastannotate(paths)
310 else: 328 else:
311 # server, or full repo 329 # server, or full repo
312 progress = ui.makeprogress(_('building'), total=len(paths)) 330 progress = ui.makeprogress(_(b'building'), total=len(paths))
313 for i, path in enumerate(paths): 331 for i, path in enumerate(paths):
314 progress.update(i) 332 progress.update(i)
315 with facontext.annotatecontext(repo, path) as actx: 333 with facontext.annotatecontext(repo, path) as actx:
316 try: 334 try:
317 if actx.isuptodate(rev): 335 if actx.isuptodate(rev):
319 actx.annotate(rev, rev) 337 actx.annotate(rev, rev)
320 except (faerror.CannotReuseError, faerror.CorruptedFileError): 338 except (faerror.CannotReuseError, faerror.CorruptedFileError):
321 # the cache is broken (could happen with renaming so the 339 # the cache is broken (could happen with renaming so the
322 # file history gets invalidated). rebuild and try again. 340 # file history gets invalidated). rebuild and try again.
323 ui.debug( 341 ui.debug(
324 'fastannotate: %s: rebuilding broken cache\n' % path 342 b'fastannotate: %s: rebuilding broken cache\n' % path
325 ) 343 )
326 actx.rebuild() 344 actx.rebuild()
327 try: 345 try:
328 actx.annotate(rev, rev) 346 actx.annotate(rev, rev)
329 except Exception as ex: 347 except Exception as ex:
330 # possibly a bug, but should not stop us from building 348 # possibly a bug, but should not stop us from building
331 # cache for other files. 349 # cache for other files.
332 ui.warn( 350 ui.warn(
333 _( 351 _(
334 'fastannotate: %s: failed to ' 352 b'fastannotate: %s: failed to '
335 'build cache: %r\n' 353 b'build cache: %r\n'
336 ) 354 )
337 % (path, ex) 355 % (path, ex)
338 ) 356 )
339 progress.complete() 357 progress.complete()