comparison hgext/fastannotate/commands.py @ 43076:2372284d9457

formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:45:02 -0400
parents 566daffc607d
children 687b865b95ad
comparison
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
29 ) 29 )
30 30
31 cmdtable = {} 31 cmdtable = {}
32 command = registrar.command(cmdtable) 32 command = registrar.command(cmdtable)
33 33
34
34 def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts): 35 def _matchpaths(repo, rev, pats, opts, aopts=facontext.defaultopts):
35 """generate paths matching given patterns""" 36 """generate paths matching given patterns"""
36 perfhack = repo.ui.configbool('fastannotate', 'perfhack') 37 perfhack = repo.ui.configbool('fastannotate', 'perfhack')
37 38
38 # disable perfhack if: 39 # disable perfhack if:
43 # cwd related to reporoot 44 # cwd related to reporoot
44 reporoot = os.path.dirname(repo.path) 45 reporoot = os.path.dirname(repo.path)
45 reldir = os.path.relpath(encoding.getcwd(), reporoot) 46 reldir = os.path.relpath(encoding.getcwd(), reporoot)
46 if reldir == '.': 47 if reldir == '.':
47 reldir = '' 48 reldir = ''
48 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)
49 perfhack = False 50 perfhack = False
50 else: # b) 51 else: # b)
51 relpats = [os.path.relpath(p, reporoot) if os.path.isabs(p) else p 52 relpats = [
52 for p in pats] 53 os.path.relpath(p, reporoot) if os.path.isabs(p) else p
54 for p in pats
55 ]
53 # disable perfhack on '..' since it allows escaping from the repo 56 # disable perfhack on '..' since it allows escaping from the repo
54 if any(('..' in f or 57 if any(
55 not os.path.isfile( 58 (
56 facontext.pathhelper(repo, f, aopts).linelogpath)) 59 '..' in f
57 for f in relpats): 60 or not os.path.isfile(
61 facontext.pathhelper(repo, f, aopts).linelogpath
62 )
63 )
64 for f in relpats
65 ):
58 perfhack = False 66 perfhack = False
59 67
60 # perfhack: emit paths directory without checking with manifest 68 # perfhack: emit paths directory without checking with manifest
61 # this can be incorrect if the rev dos not have file. 69 # this can be incorrect if the rev dos not have file.
62 if perfhack: 70 if perfhack:
63 for p in relpats: 71 for p in relpats:
64 yield os.path.join(reldir, p) 72 yield os.path.join(reldir, p)
65 else: 73 else:
74
66 def bad(x, y): 75 def bad(x, y):
67 raise error.Abort("%s: %s" % (x, y)) 76 raise error.Abort("%s: %s" % (x, y))
77
68 ctx = scmutil.revsingle(repo, rev) 78 ctx = scmutil.revsingle(repo, rev)
69 m = scmutil.match(ctx, pats, opts, badfn=bad) 79 m = scmutil.match(ctx, pats, opts, badfn=bad)
70 for p in ctx.walk(m): 80 for p in ctx.walk(m):
71 yield p 81 yield p
82
72 83
73 fastannotatecommandargs = { 84 fastannotatecommandargs = {
74 r'options': [ 85 r'options': [
75 ('r', 'rev', '.', _('annotate the specified revision'), _('REV')), 86 ('r', 'rev', '.', _('annotate the specified revision'), _('REV')),
76 ('u', 'user', None, _('list the author (long with -v)')), 87 ('u', 'user', None, _('list the author (long with -v)')),
77 ('f', 'file', None, _('list the filename')), 88 ('f', 'file', None, _('list the filename')),
78 ('d', 'date', None, _('list the date (short with -q)')), 89 ('d', 'date', None, _('list the date (short with -q)')),
79 ('n', 'number', None, _('list the revision number (default)')), 90 ('n', 'number', None, _('list the revision number (default)')),
80 ('c', 'changeset', None, _('list the changeset')), 91 ('c', 'changeset', None, _('list the changeset')),
81 ('l', 'line-number', None, _('show line number at the first ' 92 (
82 'appearance')), 93 'l',
94 'line-number',
95 None,
96 _('show line number at the first ' 'appearance'),
97 ),
83 ('e', 'deleted', None, _('show deleted lines (slow) (EXPERIMENTAL)')), 98 ('e', 'deleted', None, _('show deleted lines (slow) (EXPERIMENTAL)')),
84 ('', 'no-content', None, _('do not show file content (EXPERIMENTAL)')), 99 ('', 'no-content', None, _('do not show file content (EXPERIMENTAL)')),
85 ('', 'no-follow', None, _("don't follow copies and renames")), 100 ('', 'no-follow', None, _("don't follow copies and renames")),
86 ('', 'linear', None, _('enforce linear history, ignore second parent ' 101 (
87 'of merges (EXPERIMENTAL)')), 102 '',
103 'linear',
104 None,
105 _(
106 'enforce linear history, ignore second parent '
107 'of merges (EXPERIMENTAL)'
108 ),
109 ),
88 ('', 'long-hash', None, _('show long changeset hash (EXPERIMENTAL)')), 110 ('', 'long-hash', None, _('show long changeset hash (EXPERIMENTAL)')),
89 ('', 'rebuild', None, _('rebuild cache even if it exists ' 111 (
90 '(EXPERIMENTAL)')), 112 '',
91 ] + commands.diffwsopts + commands.walkopts + commands.formatteropts, 113 'rebuild',
114 None,
115 _('rebuild cache even if it exists ' '(EXPERIMENTAL)'),
116 ),
117 ]
118 + commands.diffwsopts
119 + commands.walkopts
120 + commands.formatteropts,
92 r'synopsis': _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'), 121 r'synopsis': _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
93 r'inferrepo': True, 122 r'inferrepo': True,
94 } 123 }
124
95 125
96 def fastannotate(ui, repo, *pats, **opts): 126 def fastannotate(ui, repo, *pats, **opts):
97 """show changeset information by line for each file 127 """show changeset information by line for each file
98 128
99 List changes in files, showing the revision id responsible for each line. 129 List changes in files, showing the revision id responsible for each line.
134 opts = pycompat.byteskwargs(opts) 164 opts = pycompat.byteskwargs(opts)
135 165
136 rev = opts.get('rev', '.') 166 rev = opts.get('rev', '.')
137 rebuild = opts.get('rebuild', False) 167 rebuild = opts.get('rebuild', False)
138 168
139 diffopts = patch.difffeatureopts(ui, opts, section='annotate', 169 diffopts = patch.difffeatureopts(
140 whitespace=True) 170 ui, opts, section='annotate', whitespace=True
171 )
141 aopts = facontext.annotateopts( 172 aopts = facontext.annotateopts(
142 diffopts=diffopts, 173 diffopts=diffopts,
143 followmerge=not opts.get('linear', False), 174 followmerge=not opts.get('linear', False),
144 followrename=not opts.get('no_follow', False)) 175 followrename=not opts.get('no_follow', False),
145 176 )
146 if not any(opts.get(s) 177
147 for s in ['user', 'date', 'file', 'number', 'changeset']): 178 if not any(
179 opts.get(s) for s in ['user', 'date', 'file', 'number', 'changeset']
180 ):
148 # default 'number' for compatibility. but fastannotate is more 181 # default 'number' for compatibility. but fastannotate is more
149 # efficient with "changeset", "line-number" and "no-content". 182 # efficient with "changeset", "line-number" and "no-content".
150 for name in ui.configlist('fastannotate', 'defaultformat', ['number']): 183 for name in ui.configlist('fastannotate', 'defaultformat', ['number']):
151 opts[name] = True 184 opts[name] = True
152 185
173 for path in paths: 206 for path in paths:
174 result = lines = existinglines = None 207 result = lines = existinglines = None
175 while True: 208 while True:
176 try: 209 try:
177 with facontext.annotatecontext(repo, path, aopts, rebuild) as a: 210 with facontext.annotatecontext(repo, path, aopts, rebuild) as a:
178 result = a.annotate(rev, master=master, showpath=showpath, 211 result = a.annotate(
179 showlines=(showlines and 212 rev,
180 not showdeleted)) 213 master=master,
214 showpath=showpath,
215 showlines=(showlines and not showdeleted),
216 )
181 if showdeleted: 217 if showdeleted:
182 existinglines = set((l[0], l[1]) for l in result) 218 existinglines = set((l[0], l[1]) for l in result)
183 result = a.annotatealllines( 219 result = a.annotatealllines(
184 rev, showpath=showpath, showlines=showlines) 220 rev, showpath=showpath, showlines=showlines
221 )
185 break 222 break
186 except (faerror.CannotReuseError, faerror.CorruptedFileError): 223 except (faerror.CannotReuseError, faerror.CorruptedFileError):
187 # happens if master moves backwards, or the file was deleted 224 # happens if master moves backwards, or the file was deleted
188 # and readded, or renamed to an existing name, or corrupted. 225 # and readded, or renamed to an existing name, or corrupted.
189 if rebuild: # give up since we have tried rebuild already 226 if rebuild: # give up since we have tried rebuild already
190 raise 227 raise
191 else: # try a second time rebuilding the cache (slow) 228 else: # try a second time rebuilding the cache (slow)
192 rebuild = True 229 rebuild = True
193 continue 230 continue
194 231
195 if showlines: 232 if showlines:
196 result, lines = result 233 result, lines = result
197 234
198 formatter.write(result, lines, existinglines=existinglines) 235 formatter.write(result, lines, existinglines=existinglines)
199 formatter.end() 236 formatter.end()
200 237
238
201 _newopts = set() 239 _newopts = set()
202 _knownopts = {opt[1].replace('-', '_') for opt in 240 _knownopts = {
203 (fastannotatecommandargs[r'options'] + commands.globalopts)} 241 opt[1].replace('-', '_')
242 for opt in (fastannotatecommandargs[r'options'] + commands.globalopts)
243 }
244
204 245
205 def _annotatewrapper(orig, ui, repo, *pats, **opts): 246 def _annotatewrapper(orig, ui, repo, *pats, **opts):
206 """used by wrapdefault""" 247 """used by wrapdefault"""
207 # we need this hack until the obsstore has 0.0 seconds perf impact 248 # we need this hack until the obsstore has 0.0 seconds perf impact
208 if ui.configbool('fastannotate', 'unfilteredrepo'): 249 if ui.configbool('fastannotate', 'unfilteredrepo'):
218 paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts))) 259 paths = list(_matchpaths(repo, rev, pats, pycompat.byteskwargs(opts)))
219 repo.prefetchfastannotate(paths) 260 repo.prefetchfastannotate(paths)
220 261
221 return orig(ui, repo, *pats, **opts) 262 return orig(ui, repo, *pats, **opts)
222 263
264
223 def registercommand(): 265 def registercommand():
224 """register the fastannotate command""" 266 """register the fastannotate command"""
225 name = 'fastannotate|fastblame|fa' 267 name = 'fastannotate|fastblame|fa'
226 command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate) 268 command(name, helpbasic=True, **fastannotatecommandargs)(fastannotate)
227 269
270
228 def wrapdefault(): 271 def wrapdefault():
229 """wrap the default annotate command, to be aware of the protocol""" 272 """wrap the default annotate command, to be aware of the protocol"""
230 extensions.wrapcommand(commands.table, 'annotate', _annotatewrapper) 273 extensions.wrapcommand(commands.table, 'annotate', _annotatewrapper)
231 274
232 @command('debugbuildannotatecache', 275
233 [('r', 'rev', '', _('build up to the specific revision'), _('REV')) 276 @command(
234 ] + commands.walkopts, 277 'debugbuildannotatecache',
235 _('[-r REV] FILE...')) 278 [('r', 'rev', '', _('build up to the specific revision'), _('REV'))]
279 + commands.walkopts,
280 _('[-r REV] FILE...'),
281 )
236 def debugbuildannotatecache(ui, repo, *pats, **opts): 282 def debugbuildannotatecache(ui, repo, *pats, **opts):
237 """incrementally build fastannotate cache up to REV for specified files 283 """incrementally build fastannotate cache up to REV for specified files
238 284
239 If REV is not specified, use the config 'fastannotate.mainbranch'. 285 If REV is not specified, use the config 'fastannotate.mainbranch'.
240 286
245 options and lives in '.hg/fastannotate/default'. 291 options and lives in '.hg/fastannotate/default'.
246 """ 292 """
247 opts = pycompat.byteskwargs(opts) 293 opts = pycompat.byteskwargs(opts)
248 rev = opts.get('REV') or ui.config('fastannotate', 'mainbranch') 294 rev = opts.get('REV') or ui.config('fastannotate', 'mainbranch')
249 if not rev: 295 if not rev:
250 raise error.Abort(_('you need to provide a revision'), 296 raise error.Abort(
251 hint=_('set fastannotate.mainbranch or use --rev')) 297 _('you need to provide a revision'),
298 hint=_('set fastannotate.mainbranch or use --rev'),
299 )
252 if ui.configbool('fastannotate', 'unfilteredrepo'): 300 if ui.configbool('fastannotate', 'unfilteredrepo'):
253 repo = repo.unfiltered() 301 repo = repo.unfiltered()
254 ctx = scmutil.revsingle(repo, rev) 302 ctx = scmutil.revsingle(repo, rev)
255 m = scmutil.match(ctx, pats, opts) 303 m = scmutil.match(ctx, pats, opts)
256 paths = list(ctx.walk(m)) 304 paths = list(ctx.walk(m))
270 continue 318 continue
271 actx.annotate(rev, rev) 319 actx.annotate(rev, rev)
272 except (faerror.CannotReuseError, faerror.CorruptedFileError): 320 except (faerror.CannotReuseError, faerror.CorruptedFileError):
273 # the cache is broken (could happen with renaming so the 321 # the cache is broken (could happen with renaming so the
274 # file history gets invalidated). rebuild and try again. 322 # file history gets invalidated). rebuild and try again.
275 ui.debug('fastannotate: %s: rebuilding broken cache\n' 323 ui.debug(
276 % path) 324 'fastannotate: %s: rebuilding broken cache\n' % path
325 )
277 actx.rebuild() 326 actx.rebuild()
278 try: 327 try:
279 actx.annotate(rev, rev) 328 actx.annotate(rev, rev)
280 except Exception as ex: 329 except Exception as ex:
281 # possibly a bug, but should not stop us from building 330 # possibly a bug, but should not stop us from building
282 # cache for other files. 331 # cache for other files.
283 ui.warn(_('fastannotate: %s: failed to ' 332 ui.warn(
284 'build cache: %r\n') % (path, ex)) 333 _(
334 'fastannotate: %s: failed to '
335 'build cache: %r\n'
336 )
337 % (path, ex)
338 )
285 progress.complete() 339 progress.complete()