comparison hgext/keyword.py @ 45942:89a2afe31e82

formating: upgrade to black 20.8b1 This required a couple of small tweaks to un-confuse black, but now it works. Big formatting changes come from: * Dramatically improved collection-splitting logic upstream * Black having a strong (correct IMO) opinion that """ is better than ''' Differential Revision: https://phab.mercurial-scm.org/D9430
author Augie Fackler <raf@durin42.com>
date Fri, 27 Nov 2020 17:03:29 -0500
parents 9f70512ae2cf
children b492bc018011
comparison
equal deleted inserted replaced
45941:346af7687c6f 45942:89a2afe31e82
156 156
157 configtable = {} 157 configtable = {}
158 configitem = registrar.configitem(configtable) 158 configitem = registrar.configitem(configtable)
159 159
160 configitem( 160 configitem(
161 b'keywordset', b'svn', default=False, 161 b'keywordset',
162 b'svn',
163 default=False,
162 ) 164 )
163 # date like in cvs' $Date 165 # date like in cvs' $Date
164 @templatefilter(b'utcdate', intype=templateutil.date) 166 @templatefilter(b'utcdate', intype=templateutil.date)
165 def utcdate(date): 167 def utcdate(date):
166 '''Date. Returns a UTC-date in this format: "2009/08/18 11:00:13". 168 """Date. Returns a UTC-date in this format: "2009/08/18 11:00:13"."""
167 '''
168 dateformat = b'%Y/%m/%d %H:%M:%S' 169 dateformat = b'%Y/%m/%d %H:%M:%S'
169 return dateutil.datestr((date[0], 0), dateformat) 170 return dateutil.datestr((date[0], 0), dateformat)
170 171
171 172
172 # date like in svn's $Date 173 # date like in svn's $Date
173 @templatefilter(b'svnisodate', intype=templateutil.date) 174 @templatefilter(b'svnisodate', intype=templateutil.date)
174 def svnisodate(date): 175 def svnisodate(date):
175 '''Date. Returns a date in this format: "2009-08-18 13:00:13 176 """Date. Returns a date in this format: "2009-08-18 13:00:13
176 +0200 (Tue, 18 Aug 2009)". 177 +0200 (Tue, 18 Aug 2009)".
177 ''' 178 """
178 return dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)') 179 return dateutil.datestr(date, b'%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
179 180
180 181
181 # date like in svn's $Id 182 # date like in svn's $Id
182 @templatefilter(b'svnutcdate', intype=templateutil.date) 183 @templatefilter(b'svnutcdate', intype=templateutil.date)
183 def svnutcdate(date): 184 def svnutcdate(date):
184 '''Date. Returns a UTC-date in this format: "2009-08-18 185 """Date. Returns a UTC-date in this format: "2009-08-18
185 11:00:13Z". 186 11:00:13Z".
186 ''' 187 """
187 dateformat = b'%Y-%m-%d %H:%M:%SZ' 188 dateformat = b'%Y-%m-%d %H:%M:%SZ'
188 return dateutil.datestr((date[0], 0), dateformat) 189 return dateutil.datestr((date[0], 0), dateformat)
189 190
190 191
191 # make keyword tools accessible 192 # make keyword tools accessible
219 templates.update(kwsets[ui.configbool(b'keywordset', b'svn')]) 220 templates.update(kwsets[ui.configbool(b'keywordset', b'svn')])
220 return templates 221 return templates
221 222
222 223
223 def _shrinktext(text, subfunc): 224 def _shrinktext(text, subfunc):
224 '''Helper for keyword expansion removal in text. 225 """Helper for keyword expansion removal in text.
225 Depending on subfunc also returns number of substitutions.''' 226 Depending on subfunc also returns number of substitutions."""
226 return subfunc(br'$\1$', text) 227 return subfunc(br'$\1$', text)
227 228
228 229
229 def _preselect(wstatus, changed): 230 def _preselect(wstatus, changed):
230 '''Retrieves modified and added files from a working directory state 231 """Retrieves modified and added files from a working directory state
231 and returns the subset of each contained in given changed files 232 and returns the subset of each contained in given changed files
232 retrieved from a change context.''' 233 retrieved from a change context."""
233 modified = [f for f in wstatus.modified if f in changed] 234 modified = [f for f in wstatus.modified if f in changed]
234 added = [f for f in wstatus.added if f in changed] 235 added = [f for f in wstatus.added if f in changed]
235 return modified, added 236 return modified, added
236 237
237 238
238 class kwtemplater(object): 239 class kwtemplater(object):
239 ''' 240 """
240 Sets up keyword templates, corresponding keyword regex, and 241 Sets up keyword templates, corresponding keyword regex, and
241 provides keyword substitution functions. 242 provides keyword substitution functions.
242 ''' 243 """
243 244
244 def __init__(self, ui, repo, inc, exc): 245 def __init__(self, ui, repo, inc, exc):
245 self.ui = ui 246 self.ui = ui
246 self._repo = weakref.ref(repo) 247 self._repo = weakref.ref(repo)
247 self.match = match.match(repo.root, b'', [], inc, exc) 248 self.match = match.match(repo.root, b'', [], inc, exc)
302 ctx = self.linkctx(path, node) 303 ctx = self.linkctx(path, node)
303 return self.substitute(data, path, ctx, self.rekw.sub) 304 return self.substitute(data, path, ctx, self.rekw.sub)
304 return data 305 return data
305 306
306 def iskwfile(self, cand, ctx): 307 def iskwfile(self, cand, ctx):
307 '''Returns subset of candidates which are configured for keyword 308 """Returns subset of candidates which are configured for keyword
308 expansion but are not symbolic links.''' 309 expansion but are not symbolic links."""
309 return [f for f in cand if self.match(f) and b'l' not in ctx.flags(f)] 310 return [f for f in cand if self.match(f) and b'l' not in ctx.flags(f)]
310 311
311 def overwrite(self, ctx, candidates, lookup, expand, rekw=False): 312 def overwrite(self, ctx, candidates, lookup, expand, rekw=False):
312 '''Overwrites selected files expanding/shrinking keywords.''' 313 '''Overwrites selected files expanding/shrinking keywords.'''
313 if self.restrict or lookup or self.postcommit: # exclude kw_copy 314 if self.restrict or lookup or self.postcommit: # exclude kw_copy
372 if not stringutil.binary(text): 373 if not stringutil.binary(text):
373 return _shrinktext(text, self.rekwexp.sub).splitlines(True) 374 return _shrinktext(text, self.rekwexp.sub).splitlines(True)
374 return lines 375 return lines
375 376
376 def wread(self, fname, data): 377 def wread(self, fname, data):
377 '''If in restricted mode returns data read from wdir with 378 """If in restricted mode returns data read from wdir with
378 keyword substitutions removed.''' 379 keyword substitutions removed."""
379 if self.restrict: 380 if self.restrict:
380 return self.shrink(fname, data) 381 return self.shrink(fname, data)
381 return data 382 return data
382 383
383 384
384 class kwfilelog(filelog.filelog): 385 class kwfilelog(filelog.filelog):
385 ''' 386 """
386 Subclass of filelog to hook into its read, add, cmp methods. 387 Subclass of filelog to hook into its read, add, cmp methods.
387 Keywords are "stored" unexpanded, and processed on reading. 388 Keywords are "stored" unexpanded, and processed on reading.
388 ''' 389 """
389 390
390 def __init__(self, opener, kwt, path): 391 def __init__(self, opener, kwt, path):
391 super(kwfilelog, self).__init__(opener, path) 392 super(kwfilelog, self).__init__(opener, path)
392 self.kwt = kwt 393 self.kwt = kwt
393 self.path = path 394 self.path = path
409 text = self.kwt.shrink(self.path, text) 410 text = self.kwt.shrink(self.path, text)
410 return super(kwfilelog, self).cmp(node, text) 411 return super(kwfilelog, self).cmp(node, text)
411 412
412 413
413 def _status(ui, repo, wctx, kwt, *pats, **opts): 414 def _status(ui, repo, wctx, kwt, *pats, **opts):
414 '''Bails out if [keyword] configuration is not active. 415 """Bails out if [keyword] configuration is not active.
415 Returns status of working directory.''' 416 Returns status of working directory."""
416 if kwt: 417 if kwt:
417 opts = pycompat.byteskwargs(opts) 418 opts = pycompat.byteskwargs(opts)
418 return repo.status( 419 return repo.status(
419 match=scmutil.match(wctx, pats, opts), 420 match=scmutil.match(wctx, pats, opts),
420 clean=True, 421 clean=True,
446 ], 447 ],
447 _(b'hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'), 448 _(b'hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'),
448 optionalrepo=True, 449 optionalrepo=True,
449 ) 450 )
450 def demo(ui, repo, *args, **opts): 451 def demo(ui, repo, *args, **opts):
451 '''print [keywordmaps] configuration and an expansion example 452 """print [keywordmaps] configuration and an expansion example
452 453
453 Show current, custom, or default keyword template maps and their 454 Show current, custom, or default keyword template maps and their
454 expansions. 455 expansions.
455 456
456 Extend the current configuration by specifying maps as arguments 457 Extend the current configuration by specifying maps as arguments
457 and using -f/--rcfile to source an external hgrc file. 458 and using -f/--rcfile to source an external hgrc file.
458 459
459 Use -d/--default to disable current configuration. 460 Use -d/--default to disable current configuration.
460 461
461 See :hg:`help templates` for information on templates and filters. 462 See :hg:`help templates` for information on templates and filters.
462 ''' 463 """
463 464
464 def demoitems(section, items): 465 def demoitems(section, items):
465 ui.write(b'[%s]\n' % section) 466 ui.write(b'[%s]\n' % section)
466 for k, v in sorted(items): 467 for k, v in sorted(items):
467 if isinstance(v, bool): 468 if isinstance(v, bool):
545 cmdutil.walkopts, 546 cmdutil.walkopts,
546 _(b'hg kwexpand [OPTION]... [FILE]...'), 547 _(b'hg kwexpand [OPTION]... [FILE]...'),
547 inferrepo=True, 548 inferrepo=True,
548 ) 549 )
549 def expand(ui, repo, *pats, **opts): 550 def expand(ui, repo, *pats, **opts):
550 '''expand keywords in the working directory 551 """expand keywords in the working directory
551 552
552 Run after (re)enabling keyword expansion. 553 Run after (re)enabling keyword expansion.
553 554
554 kwexpand refuses to run if given files contain local changes. 555 kwexpand refuses to run if given files contain local changes.
555 ''' 556 """
556 # 3rd argument sets expansion to True 557 # 3rd argument sets expansion to True
557 _kwfwrite(ui, repo, True, *pats, **opts) 558 _kwfwrite(ui, repo, True, *pats, **opts)
558 559
559 560
560 @command( 561 @command(
567 + cmdutil.walkopts, 568 + cmdutil.walkopts,
568 _(b'hg kwfiles [OPTION]... [FILE]...'), 569 _(b'hg kwfiles [OPTION]... [FILE]...'),
569 inferrepo=True, 570 inferrepo=True,
570 ) 571 )
571 def files(ui, repo, *pats, **opts): 572 def files(ui, repo, *pats, **opts):
572 '''show files configured for keyword expansion 573 """show files configured for keyword expansion
573 574
574 List which files in the working directory are matched by the 575 List which files in the working directory are matched by the
575 [keyword] configuration patterns. 576 [keyword] configuration patterns.
576 577
577 Useful to prevent inadvertent keyword expansion and to speed up 578 Useful to prevent inadvertent keyword expansion and to speed up
586 587
587 K = keyword expansion candidate 588 K = keyword expansion candidate
588 k = keyword expansion candidate (not tracked) 589 k = keyword expansion candidate (not tracked)
589 I = ignored 590 I = ignored
590 i = ignored (not tracked) 591 i = ignored (not tracked)
591 ''' 592 """
592 kwt = getattr(repo, '_keywordkwt', None) 593 kwt = getattr(repo, '_keywordkwt', None)
593 wctx = repo[None] 594 wctx = repo[None]
594 status = _status(ui, repo, wctx, kwt, *pats, **opts) 595 status = _status(ui, repo, wctx, kwt, *pats, **opts)
595 if pats: 596 if pats:
596 cwd = repo.getcwd() 597 cwd = repo.getcwd()
632 cmdutil.walkopts, 633 cmdutil.walkopts,
633 _(b'hg kwshrink [OPTION]... [FILE]...'), 634 _(b'hg kwshrink [OPTION]... [FILE]...'),
634 inferrepo=True, 635 inferrepo=True,
635 ) 636 )
636 def shrink(ui, repo, *pats, **opts): 637 def shrink(ui, repo, *pats, **opts):
637 '''revert expanded keywords in the working directory 638 """revert expanded keywords in the working directory
638 639
639 Must be run before changing/disabling active keywords. 640 Must be run before changing/disabling active keywords.
640 641
641 kwshrink refuses to run if given files contain local changes. 642 kwshrink refuses to run if given files contain local changes.
642 ''' 643 """
643 # 3rd argument sets expansion to False 644 # 3rd argument sets expansion to False
644 _kwfwrite(ui, repo, False, *pats, **opts) 645 _kwfwrite(ui, repo, False, *pats, **opts)
645 646
646 647
647 # monkeypatches 648 # monkeypatches
648 649
649 650
650 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None): 651 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None):
651 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid 652 """Monkeypatch/wrap patch.patchfile.__init__ to avoid
652 rejects or conflicts due to expanded keywords in working dir.''' 653 rejects or conflicts due to expanded keywords in working dir."""
653 orig(self, ui, gp, backend, store, eolmode) 654 orig(self, ui, gp, backend, store, eolmode)
654 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None) 655 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None)
655 if kwt: 656 if kwt:
656 # shrink keywords read from working dir 657 # shrink keywords read from working dir
657 self.lines = kwt.shrinklines(self.fname, self.lines) 658 self.lines = kwt.shrinklines(self.fname, self.lines)
700 kwt.restrict = False 701 kwt.restrict = False
701 return newid 702 return newid
702 703
703 704
704 def kw_copy(orig, ui, repo, pats, opts, rename=False): 705 def kw_copy(orig, ui, repo, pats, opts, rename=False):
705 '''Wraps cmdutil.copy so that copy/rename destinations do not 706 """Wraps cmdutil.copy so that copy/rename destinations do not
706 contain expanded keywords. 707 contain expanded keywords.
707 Note that the source of a regular file destination may also be a 708 Note that the source of a regular file destination may also be a
708 symlink: 709 symlink:
709 hg cp sym x -> x is symlink 710 hg cp sym x -> x is symlink
710 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords) 711 cp sym x; hg cp -A sym x -> x is file (maybe expanded keywords)
711 For the latter we have to follow the symlink to find out whether its 712 For the latter we have to follow the symlink to find out whether its
712 target is configured for expansion and we therefore must unexpand the 713 target is configured for expansion and we therefore must unexpand the
713 keywords in the destination.''' 714 keywords in the destination."""
714 kwt = getattr(repo, '_keywordkwt', None) 715 kwt = getattr(repo, '_keywordkwt', None)
715 if kwt is None: 716 if kwt is None:
716 return orig(ui, repo, pats, opts, rename) 717 return orig(ui, repo, pats, opts, rename)
717 with repo.wlock(): 718 with repo.wlock():
718 orig(ui, repo, pats, opts, rename) 719 orig(ui, repo, pats, opts, rename)
720 return 721 return
721 wctx = repo[None] 722 wctx = repo[None]
722 cwd = repo.getcwd() 723 cwd = repo.getcwd()
723 724
724 def haskwsource(dest): 725 def haskwsource(dest):
725 '''Returns true if dest is a regular file and configured for 726 """Returns true if dest is a regular file and configured for
726 expansion or a symlink which points to a file configured for 727 expansion or a symlink which points to a file configured for
727 expansion. ''' 728 expansion."""
728 source = repo.dirstate.copied(dest) 729 source = repo.dirstate.copied(dest)
729 if b'l' in wctx.flags(source): 730 if b'l' in wctx.flags(source):
730 source = pathutil.canonpath( 731 source = pathutil.canonpath(
731 repo.root, cwd, os.path.realpath(source) 732 repo.root, cwd, os.path.realpath(source)
732 ) 733 )
783 return self._filelog.cmp(self._filenode, fctx.data()) 784 return self._filelog.cmp(self._filenode, fctx.data())
784 return True 785 return True
785 786
786 787
787 def uisetup(ui): 788 def uisetup(ui):
788 ''' Monkeypatches dispatch._parse to retrieve user command. 789 """Monkeypatches dispatch._parse to retrieve user command.
789 Overrides file method to return kwfilelog instead of filelog 790 Overrides file method to return kwfilelog instead of filelog
790 if file matches user configuration. 791 if file matches user configuration.
791 Wraps commit to overwrite configured files with updated 792 Wraps commit to overwrite configured files with updated
792 keyword substitutions. 793 keyword substitutions.
793 Monkeypatches patch and webcommands.''' 794 Monkeypatches patch and webcommands."""
794 795
795 def kwdispatch_parse(orig, ui, args): 796 def kwdispatch_parse(orig, ui, args):
796 '''Monkeypatch dispatch._parse to obtain running hg command.''' 797 '''Monkeypatch dispatch._parse to obtain running hg command.'''
797 cmd, func, args, options, cmdoptions = orig(ui, args) 798 cmd, func, args, options, cmdoptions = orig(ui, args)
798 kwtools[b'hgcmd'] = cmd 799 kwtools[b'hgcmd'] = cmd