Mercurial > hg
comparison hgext/keyword.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 | d98ec36be808 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
123 # be specifying the version(s) of Mercurial they are tested with, or | 123 # be specifying the version(s) of Mercurial they are tested with, or |
124 # leave the attribute unspecified. | 124 # leave the attribute unspecified. |
125 testedwith = 'ships-with-hg-core' | 125 testedwith = 'ships-with-hg-core' |
126 | 126 |
127 # hg commands that do not act on keywords | 127 # hg commands that do not act on keywords |
128 nokwcommands = ('add addremove annotate bundle export grep incoming init log' | 128 nokwcommands = ( |
129 ' outgoing push tip verify convert email glog') | 129 'add addremove annotate bundle export grep incoming init log' |
130 ' outgoing push tip verify convert email glog' | |
131 ) | |
130 | 132 |
131 # webcommands that do not act on keywords | 133 # webcommands that do not act on keywords |
132 nokwwebcommands = ('annotate changeset rev filediff diff comparison') | 134 nokwwebcommands = 'annotate changeset rev filediff diff comparison' |
133 | 135 |
134 # hg commands that trigger expansion only when writing to working dir, | 136 # hg commands that trigger expansion only when writing to working dir, |
135 # not when reading filelog, and unexpand when reading from working dir | 137 # not when reading filelog, and unexpand when reading from working dir |
136 restricted = ('merge kwexpand kwshrink record qrecord resolve transplant' | 138 restricted = ( |
137 ' unshelve rebase graft backout histedit fetch') | 139 'merge kwexpand kwshrink record qrecord resolve transplant' |
140 ' unshelve rebase graft backout histedit fetch' | |
141 ) | |
138 | 142 |
139 # names of extensions using dorecord | 143 # names of extensions using dorecord |
140 recordextensions = 'record' | 144 recordextensions = 'record' |
141 | 145 |
142 colortable = { | 146 colortable = { |
143 'kwfiles.enabled': 'green bold', | 147 'kwfiles.enabled': 'green bold', |
144 'kwfiles.deleted': 'cyan bold underline', | 148 'kwfiles.deleted': 'cyan bold underline', |
145 'kwfiles.enabledunknown': 'green', | 149 'kwfiles.enabledunknown': 'green', |
146 'kwfiles.ignored': 'bold', | 150 'kwfiles.ignored': 'bold', |
147 'kwfiles.ignoredunknown': 'none' | 151 'kwfiles.ignoredunknown': 'none', |
148 } | 152 } |
149 | 153 |
150 templatefilter = registrar.templatefilter() | 154 templatefilter = registrar.templatefilter() |
151 | 155 |
152 configtable = {} | 156 configtable = {} |
153 configitem = registrar.configitem(configtable) | 157 configitem = registrar.configitem(configtable) |
154 | 158 |
155 configitem('keywordset', 'svn', | 159 configitem( |
156 default=False, | 160 'keywordset', 'svn', default=False, |
157 ) | 161 ) |
158 # date like in cvs' $Date | 162 # date like in cvs' $Date |
159 @templatefilter('utcdate', intype=templateutil.date) | 163 @templatefilter('utcdate', intype=templateutil.date) |
160 def utcdate(date): | 164 def utcdate(date): |
161 '''Date. Returns a UTC-date in this format: "2009/08/18 11:00:13". | 165 '''Date. Returns a UTC-date in this format: "2009/08/18 11:00:13". |
162 ''' | 166 ''' |
163 dateformat = '%Y/%m/%d %H:%M:%S' | 167 dateformat = '%Y/%m/%d %H:%M:%S' |
164 return dateutil.datestr((date[0], 0), dateformat) | 168 return dateutil.datestr((date[0], 0), dateformat) |
169 | |
170 | |
165 # date like in svn's $Date | 171 # date like in svn's $Date |
166 @templatefilter('svnisodate', intype=templateutil.date) | 172 @templatefilter('svnisodate', intype=templateutil.date) |
167 def svnisodate(date): | 173 def svnisodate(date): |
168 '''Date. Returns a date in this format: "2009-08-18 13:00:13 | 174 '''Date. Returns a date in this format: "2009-08-18 13:00:13 |
169 +0200 (Tue, 18 Aug 2009)". | 175 +0200 (Tue, 18 Aug 2009)". |
170 ''' | 176 ''' |
171 return dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)') | 177 return dateutil.datestr(date, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)') |
178 | |
179 | |
172 # date like in svn's $Id | 180 # date like in svn's $Id |
173 @templatefilter('svnutcdate', intype=templateutil.date) | 181 @templatefilter('svnutcdate', intype=templateutil.date) |
174 def svnutcdate(date): | 182 def svnutcdate(date): |
175 '''Date. Returns a UTC-date in this format: "2009-08-18 | 183 '''Date. Returns a UTC-date in this format: "2009-08-18 |
176 11:00:13Z". | 184 11:00:13Z". |
177 ''' | 185 ''' |
178 dateformat = '%Y-%m-%d %H:%M:%SZ' | 186 dateformat = '%Y-%m-%d %H:%M:%SZ' |
179 return dateutil.datestr((date[0], 0), dateformat) | 187 return dateutil.datestr((date[0], 0), dateformat) |
180 | 188 |
189 | |
181 # make keyword tools accessible | 190 # make keyword tools accessible |
182 kwtools = {'hgcmd': ''} | 191 kwtools = {'hgcmd': ''} |
192 | |
183 | 193 |
184 def _defaultkwmaps(ui): | 194 def _defaultkwmaps(ui): |
185 '''Returns default keywordmaps according to keywordset configuration.''' | 195 '''Returns default keywordmaps according to keywordset configuration.''' |
186 templates = { | 196 templates = { |
187 'Revision': '{node|short}', | 197 'Revision': '{node|short}', |
188 'Author': '{author|user}', | 198 'Author': '{author|user}', |
189 } | 199 } |
190 kwsets = ({ | 200 kwsets = ( |
191 'Date': '{date|utcdate}', | 201 { |
192 'RCSfile': '{file|basename},v', | 202 'Date': '{date|utcdate}', |
193 'RCSFile': '{file|basename},v', # kept for backwards compatibility | 203 'RCSfile': '{file|basename},v', |
194 # with hg-keyword | 204 'RCSFile': '{file|basename},v', # kept for backwards compatibility |
195 'Source': '{root}/{file},v', | 205 # with hg-keyword |
196 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', | 206 'Source': '{root}/{file},v', |
197 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', | 207 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', |
198 }, { | 208 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', |
199 'Date': '{date|svnisodate}', | 209 }, |
200 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}', | 210 { |
201 'LastChangedRevision': '{node|short}', | 211 'Date': '{date|svnisodate}', |
202 'LastChangedBy': '{author|user}', | 212 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}', |
203 'LastChangedDate': '{date|svnisodate}', | 213 'LastChangedRevision': '{node|short}', |
204 }) | 214 'LastChangedBy': '{author|user}', |
215 'LastChangedDate': '{date|svnisodate}', | |
216 }, | |
217 ) | |
205 templates.update(kwsets[ui.configbool('keywordset', 'svn')]) | 218 templates.update(kwsets[ui.configbool('keywordset', 'svn')]) |
206 return templates | 219 return templates |
220 | |
207 | 221 |
208 def _shrinktext(text, subfunc): | 222 def _shrinktext(text, subfunc): |
209 '''Helper for keyword expansion removal in text. | 223 '''Helper for keyword expansion removal in text. |
210 Depending on subfunc also returns number of substitutions.''' | 224 Depending on subfunc also returns number of substitutions.''' |
211 return subfunc(br'$\1$', text) | 225 return subfunc(br'$\1$', text) |
226 | |
212 | 227 |
213 def _preselect(wstatus, changed): | 228 def _preselect(wstatus, changed): |
214 '''Retrieves modified and added files from a working directory state | 229 '''Retrieves modified and added files from a working directory state |
215 and returns the subset of each contained in given changed files | 230 and returns the subset of each contained in given changed files |
216 retrieved from a change context.''' | 231 retrieved from a change context.''' |
231 self.match = match.match(repo.root, '', [], inc, exc) | 246 self.match = match.match(repo.root, '', [], inc, exc) |
232 self.restrict = kwtools['hgcmd'] in restricted.split() | 247 self.restrict = kwtools['hgcmd'] in restricted.split() |
233 self.postcommit = False | 248 self.postcommit = False |
234 | 249 |
235 kwmaps = self.ui.configitems('keywordmaps') | 250 kwmaps = self.ui.configitems('keywordmaps') |
236 if kwmaps: # override default templates | 251 if kwmaps: # override default templates |
237 self.templates = dict(kwmaps) | 252 self.templates = dict(kwmaps) |
238 else: | 253 else: |
239 self.templates = _defaultkwmaps(self.ui) | 254 self.templates = _defaultkwmaps(self.ui) |
240 | 255 |
241 @property | 256 @property |
257 '''Returns regex for expanded keywords.''' | 272 '''Returns regex for expanded keywords.''' |
258 return re.compile(br'\$(%s): [^$\n\r]*? \$' % self.escape) | 273 return re.compile(br'\$(%s): [^$\n\r]*? \$' % self.escape) |
259 | 274 |
260 def substitute(self, data, path, ctx, subfunc): | 275 def substitute(self, data, path, ctx, subfunc): |
261 '''Replaces keywords in data with expanded template.''' | 276 '''Replaces keywords in data with expanded template.''' |
277 | |
262 def kwsub(mobj): | 278 def kwsub(mobj): |
263 kw = mobj.group(1) | 279 kw = mobj.group(1) |
264 ct = logcmdutil.maketemplater(self.ui, self.repo, | 280 ct = logcmdutil.maketemplater( |
265 self.templates[kw]) | 281 self.ui, self.repo, self.templates[kw] |
282 ) | |
266 self.ui.pushbuffer() | 283 self.ui.pushbuffer() |
267 ct.show(ctx, root=self.repo.root, file=path) | 284 ct.show(ctx, root=self.repo.root, file=path) |
268 ekw = templatefilters.firstline(self.ui.popbuffer()) | 285 ekw = templatefilters.firstline(self.ui.popbuffer()) |
269 return '$%s: %s $' % (kw, ekw) | 286 return '$%s: %s $' % (kw, ekw) |
287 | |
270 return subfunc(kwsub, data) | 288 return subfunc(kwsub, data) |
271 | 289 |
272 def linkctx(self, path, fileid): | 290 def linkctx(self, path, fileid): |
273 '''Similar to filelog.linkrev, but returns a changectx.''' | 291 '''Similar to filelog.linkrev, but returns a changectx.''' |
274 return self.repo.filectx(path, fileid=fileid).changectx() | 292 return self.repo.filectx(path, fileid=fileid).changectx() |
275 | 293 |
276 def expand(self, path, node, data): | 294 def expand(self, path, node, data): |
277 '''Returns data with keywords expanded.''' | 295 '''Returns data with keywords expanded.''' |
278 if (not self.restrict and self.match(path) | 296 if ( |
279 and not stringutil.binary(data)): | 297 not self.restrict |
298 and self.match(path) | |
299 and not stringutil.binary(data) | |
300 ): | |
280 ctx = self.linkctx(path, node) | 301 ctx = self.linkctx(path, node) |
281 return self.substitute(data, path, ctx, self.rekw.sub) | 302 return self.substitute(data, path, ctx, self.rekw.sub) |
282 return data | 303 return data |
283 | 304 |
284 def iskwfile(self, cand, ctx): | 305 def iskwfile(self, cand, ctx): |
286 expansion but are not symbolic links.''' | 307 expansion but are not symbolic links.''' |
287 return [f for f in cand if self.match(f) and 'l' not in ctx.flags(f)] | 308 return [f for f in cand if self.match(f) and 'l' not in ctx.flags(f)] |
288 | 309 |
289 def overwrite(self, ctx, candidates, lookup, expand, rekw=False): | 310 def overwrite(self, ctx, candidates, lookup, expand, rekw=False): |
290 '''Overwrites selected files expanding/shrinking keywords.''' | 311 '''Overwrites selected files expanding/shrinking keywords.''' |
291 if self.restrict or lookup or self.postcommit: # exclude kw_copy | 312 if self.restrict or lookup or self.postcommit: # exclude kw_copy |
292 candidates = self.iskwfile(candidates, ctx) | 313 candidates = self.iskwfile(candidates, ctx) |
293 if not candidates: | 314 if not candidates: |
294 return | 315 return |
295 kwcmd = self.restrict and lookup # kwexpand/kwshrink | 316 kwcmd = self.restrict and lookup # kwexpand/kwshrink |
296 if self.restrict or expand and lookup: | 317 if self.restrict or expand and lookup: |
297 mf = ctx.manifest() | 318 mf = ctx.manifest() |
298 if self.restrict or rekw: | 319 if self.restrict or rekw: |
299 re_kw = self.rekw | 320 re_kw = self.rekw |
300 else: | 321 else: |
356 keyword substitutions removed.''' | 377 keyword substitutions removed.''' |
357 if self.restrict: | 378 if self.restrict: |
358 return self.shrink(fname, data) | 379 return self.shrink(fname, data) |
359 return data | 380 return data |
360 | 381 |
382 | |
361 class kwfilelog(filelog.filelog): | 383 class kwfilelog(filelog.filelog): |
362 ''' | 384 ''' |
363 Subclass of filelog to hook into its read, add, cmp methods. | 385 Subclass of filelog to hook into its read, add, cmp methods. |
364 Keywords are "stored" unexpanded, and processed on reading. | 386 Keywords are "stored" unexpanded, and processed on reading. |
365 ''' | 387 ''' |
388 | |
366 def __init__(self, opener, kwt, path): | 389 def __init__(self, opener, kwt, path): |
367 super(kwfilelog, self).__init__(opener, path) | 390 super(kwfilelog, self).__init__(opener, path) |
368 self.kwt = kwt | 391 self.kwt = kwt |
369 self.path = path | 392 self.path = path |
370 | 393 |
383 def cmp(self, node, text): | 406 def cmp(self, node, text): |
384 '''Removes keyword substitutions for comparison.''' | 407 '''Removes keyword substitutions for comparison.''' |
385 text = self.kwt.shrink(self.path, text) | 408 text = self.kwt.shrink(self.path, text) |
386 return super(kwfilelog, self).cmp(node, text) | 409 return super(kwfilelog, self).cmp(node, text) |
387 | 410 |
411 | |
388 def _status(ui, repo, wctx, kwt, *pats, **opts): | 412 def _status(ui, repo, wctx, kwt, *pats, **opts): |
389 '''Bails out if [keyword] configuration is not active. | 413 '''Bails out if [keyword] configuration is not active. |
390 Returns status of working directory.''' | 414 Returns status of working directory.''' |
391 if kwt: | 415 if kwt: |
392 opts = pycompat.byteskwargs(opts) | 416 opts = pycompat.byteskwargs(opts) |
393 return repo.status(match=scmutil.match(wctx, pats, opts), clean=True, | 417 return repo.status( |
394 unknown=opts.get('unknown') or opts.get('all')) | 418 match=scmutil.match(wctx, pats, opts), |
419 clean=True, | |
420 unknown=opts.get('unknown') or opts.get('all'), | |
421 ) | |
395 if ui.configitems('keyword'): | 422 if ui.configitems('keyword'): |
396 raise error.Abort(_('[keyword] patterns cannot match')) | 423 raise error.Abort(_('[keyword] patterns cannot match')) |
397 raise error.Abort(_('no [keyword] patterns configured')) | 424 raise error.Abort(_('no [keyword] patterns configured')) |
425 | |
398 | 426 |
399 def _kwfwrite(ui, repo, expand, *pats, **opts): | 427 def _kwfwrite(ui, repo, expand, *pats, **opts): |
400 '''Selects files and passes them to kwtemplater.overwrite.''' | 428 '''Selects files and passes them to kwtemplater.overwrite.''' |
401 wctx = repo[None] | 429 wctx = repo[None] |
402 if len(wctx.parents()) > 1: | 430 if len(wctx.parents()) > 1: |
406 status = _status(ui, repo, wctx, kwt, *pats, **opts) | 434 status = _status(ui, repo, wctx, kwt, *pats, **opts) |
407 if status.modified or status.added or status.removed or status.deleted: | 435 if status.modified or status.added or status.removed or status.deleted: |
408 raise error.Abort(_('outstanding uncommitted changes')) | 436 raise error.Abort(_('outstanding uncommitted changes')) |
409 kwt.overwrite(wctx, status.clean, True, expand) | 437 kwt.overwrite(wctx, status.clean, True, expand) |
410 | 438 |
411 @command('kwdemo', | 439 |
412 [('d', 'default', None, _('show default keyword template maps')), | 440 @command( |
413 ('f', 'rcfile', '', | 441 'kwdemo', |
414 _('read maps from rcfile'), _('FILE'))], | 442 [ |
415 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'), | 443 ('d', 'default', None, _('show default keyword template maps')), |
416 optionalrepo=True) | 444 ('f', 'rcfile', '', _('read maps from rcfile'), _('FILE')), |
445 ], | |
446 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...'), | |
447 optionalrepo=True, | |
448 ) | |
417 def demo(ui, repo, *args, **opts): | 449 def demo(ui, repo, *args, **opts): |
418 '''print [keywordmaps] configuration and an expansion example | 450 '''print [keywordmaps] configuration and an expansion example |
419 | 451 |
420 Show current, custom, or default keyword template maps and their | 452 Show current, custom, or default keyword template maps and their |
421 expansions. | 453 expansions. |
425 | 457 |
426 Use -d/--default to disable current configuration. | 458 Use -d/--default to disable current configuration. |
427 | 459 |
428 See :hg:`help templates` for information on templates and filters. | 460 See :hg:`help templates` for information on templates and filters. |
429 ''' | 461 ''' |
462 | |
430 def demoitems(section, items): | 463 def demoitems(section, items): |
431 ui.write('[%s]\n' % section) | 464 ui.write('[%s]\n' % section) |
432 for k, v in sorted(items): | 465 for k, v in sorted(items): |
433 if isinstance(v, bool): | 466 if isinstance(v, bool): |
434 v = stringutil.pprint(v) | 467 v = stringutil.pprint(v) |
482 else: | 515 else: |
483 kwmaps = _defaultkwmaps(ui) | 516 kwmaps = _defaultkwmaps(ui) |
484 | 517 |
485 uisetup(ui) | 518 uisetup(ui) |
486 reposetup(ui, repo) | 519 reposetup(ui, repo) |
487 ui.write(('[extensions]\nkeyword =\n')) | 520 ui.write('[extensions]\nkeyword =\n') |
488 demoitems('keyword', ui.configitems('keyword')) | 521 demoitems('keyword', ui.configitems('keyword')) |
489 demoitems('keywordset', ui.configitems('keywordset')) | 522 demoitems('keywordset', ui.configitems('keywordset')) |
490 demoitems('keywordmaps', kwmaps.iteritems()) | 523 demoitems('keywordmaps', kwmaps.iteritems()) |
491 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n' | 524 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n' |
492 repo.wvfs.write(fn, keywords) | 525 repo.wvfs.write(fn, keywords) |
503 repo.commit(text=msg) | 536 repo.commit(text=msg) |
504 ui.status(_('\n\tkeywords expanded\n')) | 537 ui.status(_('\n\tkeywords expanded\n')) |
505 ui.write(repo.wread(fn)) | 538 ui.write(repo.wread(fn)) |
506 repo.wvfs.rmtree(repo.root) | 539 repo.wvfs.rmtree(repo.root) |
507 | 540 |
508 @command('kwexpand', | 541 |
542 @command( | |
543 'kwexpand', | |
509 cmdutil.walkopts, | 544 cmdutil.walkopts, |
510 _('hg kwexpand [OPTION]... [FILE]...'), | 545 _('hg kwexpand [OPTION]... [FILE]...'), |
511 inferrepo=True) | 546 inferrepo=True, |
547 ) | |
512 def expand(ui, repo, *pats, **opts): | 548 def expand(ui, repo, *pats, **opts): |
513 '''expand keywords in the working directory | 549 '''expand keywords in the working directory |
514 | 550 |
515 Run after (re)enabling keyword expansion. | 551 Run after (re)enabling keyword expansion. |
516 | 552 |
517 kwexpand refuses to run if given files contain local changes. | 553 kwexpand refuses to run if given files contain local changes. |
518 ''' | 554 ''' |
519 # 3rd argument sets expansion to True | 555 # 3rd argument sets expansion to True |
520 _kwfwrite(ui, repo, True, *pats, **opts) | 556 _kwfwrite(ui, repo, True, *pats, **opts) |
521 | 557 |
522 @command('kwfiles', | 558 |
523 [('A', 'all', None, _('show keyword status flags of all files')), | 559 @command( |
524 ('i', 'ignore', None, _('show files excluded from expansion')), | 560 'kwfiles', |
525 ('u', 'unknown', None, _('only show unknown (not tracked) files')), | 561 [ |
526 ] + cmdutil.walkopts, | 562 ('A', 'all', None, _('show keyword status flags of all files')), |
527 _('hg kwfiles [OPTION]... [FILE]...'), | 563 ('i', 'ignore', None, _('show files excluded from expansion')), |
528 inferrepo=True) | 564 ('u', 'unknown', None, _('only show unknown (not tracked) files')), |
565 ] | |
566 + cmdutil.walkopts, | |
567 _('hg kwfiles [OPTION]... [FILE]...'), | |
568 inferrepo=True, | |
569 ) | |
529 def files(ui, repo, *pats, **opts): | 570 def files(ui, repo, *pats, **opts): |
530 '''show files configured for keyword expansion | 571 '''show files configured for keyword expansion |
531 | 572 |
532 List which files in the working directory are matched by the | 573 List which files in the working directory are matched by the |
533 [keyword] configuration patterns. | 574 [keyword] configuration patterns. |
564 if not opts.get('ignore') or opts.get('all'): | 605 if not opts.get('ignore') or opts.get('all'): |
565 showfiles = kwfiles, kwdeleted, kwunknown | 606 showfiles = kwfiles, kwdeleted, kwunknown |
566 else: | 607 else: |
567 showfiles = [], [], [] | 608 showfiles = [], [], [] |
568 if opts.get('all') or opts.get('ignore'): | 609 if opts.get('all') or opts.get('ignore'): |
569 showfiles += ([f for f in files if f not in kwfiles], | 610 showfiles += ( |
570 [f for f in status.unknown if f not in kwunknown]) | 611 [f for f in files if f not in kwfiles], |
612 [f for f in status.unknown if f not in kwunknown], | |
613 ) | |
571 kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split() | 614 kwlabels = 'enabled deleted enabledunknown ignored ignoredunknown'.split() |
572 kwstates = zip(kwlabels, pycompat.bytestr('K!kIi'), showfiles) | 615 kwstates = zip(kwlabels, pycompat.bytestr('K!kIi'), showfiles) |
573 fm = ui.formatter('kwfiles', opts) | 616 fm = ui.formatter('kwfiles', opts) |
574 fmt = '%.0s%s\n' | 617 fmt = '%.0s%s\n' |
575 if opts.get('all') or ui.verbose: | 618 if opts.get('all') or ui.verbose: |
580 fm.startitem() | 623 fm.startitem() |
581 fm.data(kwstatus=char, path=f) | 624 fm.data(kwstatus=char, path=f) |
582 fm.plain(fmt % (char, repo.pathto(f, cwd)), label=label) | 625 fm.plain(fmt % (char, repo.pathto(f, cwd)), label=label) |
583 fm.end() | 626 fm.end() |
584 | 627 |
585 @command('kwshrink', | 628 |
629 @command( | |
630 'kwshrink', | |
586 cmdutil.walkopts, | 631 cmdutil.walkopts, |
587 _('hg kwshrink [OPTION]... [FILE]...'), | 632 _('hg kwshrink [OPTION]... [FILE]...'), |
588 inferrepo=True) | 633 inferrepo=True, |
634 ) | |
589 def shrink(ui, repo, *pats, **opts): | 635 def shrink(ui, repo, *pats, **opts): |
590 '''revert expanded keywords in the working directory | 636 '''revert expanded keywords in the working directory |
591 | 637 |
592 Must be run before changing/disabling active keywords. | 638 Must be run before changing/disabling active keywords. |
593 | 639 |
594 kwshrink refuses to run if given files contain local changes. | 640 kwshrink refuses to run if given files contain local changes. |
595 ''' | 641 ''' |
596 # 3rd argument sets expansion to False | 642 # 3rd argument sets expansion to False |
597 _kwfwrite(ui, repo, False, *pats, **opts) | 643 _kwfwrite(ui, repo, False, *pats, **opts) |
598 | 644 |
645 | |
599 # monkeypatches | 646 # monkeypatches |
647 | |
600 | 648 |
601 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None): | 649 def kwpatchfile_init(orig, self, ui, gp, backend, store, eolmode=None): |
602 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid | 650 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid |
603 rejects or conflicts due to expanded keywords in working dir.''' | 651 rejects or conflicts due to expanded keywords in working dir.''' |
604 orig(self, ui, gp, backend, store, eolmode) | 652 orig(self, ui, gp, backend, store, eolmode) |
605 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None) | 653 kwt = getattr(getattr(backend, 'repo', None), '_keywordkwt', None) |
606 if kwt: | 654 if kwt: |
607 # shrink keywords read from working dir | 655 # shrink keywords read from working dir |
608 self.lines = kwt.shrinklines(self.fname, self.lines) | 656 self.lines = kwt.shrinklines(self.fname, self.lines) |
657 | |
609 | 658 |
610 def kwdiff(orig, repo, *args, **kwargs): | 659 def kwdiff(orig, repo, *args, **kwargs): |
611 '''Monkeypatch patch.diff to avoid expansion.''' | 660 '''Monkeypatch patch.diff to avoid expansion.''' |
612 kwt = getattr(repo, '_keywordkwt', None) | 661 kwt = getattr(repo, '_keywordkwt', None) |
613 if kwt: | 662 if kwt: |
618 yield chunk | 667 yield chunk |
619 finally: | 668 finally: |
620 if kwt: | 669 if kwt: |
621 kwt.restrict = restrict | 670 kwt.restrict = restrict |
622 | 671 |
672 | |
623 def kwweb_skip(orig, web): | 673 def kwweb_skip(orig, web): |
624 '''Wraps webcommands.x turning off keyword expansion.''' | 674 '''Wraps webcommands.x turning off keyword expansion.''' |
625 kwt = getattr(web.repo, '_keywordkwt', None) | 675 kwt = getattr(web.repo, '_keywordkwt', None) |
626 if kwt: | 676 if kwt: |
627 origmatch = kwt.match | 677 origmatch = kwt.match |
630 for chunk in orig(web): | 680 for chunk in orig(web): |
631 yield chunk | 681 yield chunk |
632 finally: | 682 finally: |
633 if kwt: | 683 if kwt: |
634 kwt.match = origmatch | 684 kwt.match = origmatch |
685 | |
635 | 686 |
636 def kw_amend(orig, ui, repo, old, extra, pats, opts): | 687 def kw_amend(orig, ui, repo, old, extra, pats, opts): |
637 '''Wraps cmdutil.amend expanding keywords after amend.''' | 688 '''Wraps cmdutil.amend expanding keywords after amend.''' |
638 kwt = getattr(repo, '_keywordkwt', None) | 689 kwt = getattr(repo, '_keywordkwt', None) |
639 if kwt is None: | 690 if kwt is None: |
645 ctx = repo[newid] | 696 ctx = repo[newid] |
646 kwt.restrict = True | 697 kwt.restrict = True |
647 kwt.overwrite(ctx, ctx.files(), False, True) | 698 kwt.overwrite(ctx, ctx.files(), False, True) |
648 kwt.restrict = False | 699 kwt.restrict = False |
649 return newid | 700 return newid |
701 | |
650 | 702 |
651 def kw_copy(orig, ui, repo, pats, opts, rename=False): | 703 def kw_copy(orig, ui, repo, pats, opts, rename=False): |
652 '''Wraps cmdutil.copy so that copy/rename destinations do not | 704 '''Wraps cmdutil.copy so that copy/rename destinations do not |
653 contain expanded keywords. | 705 contain expanded keywords. |
654 Note that the source of a regular file destination may also be a | 706 Note that the source of a regular file destination may also be a |
672 '''Returns true if dest is a regular file and configured for | 724 '''Returns true if dest is a regular file and configured for |
673 expansion or a symlink which points to a file configured for | 725 expansion or a symlink which points to a file configured for |
674 expansion. ''' | 726 expansion. ''' |
675 source = repo.dirstate.copied(dest) | 727 source = repo.dirstate.copied(dest) |
676 if 'l' in wctx.flags(source): | 728 if 'l' in wctx.flags(source): |
677 source = pathutil.canonpath(repo.root, cwd, | 729 source = pathutil.canonpath( |
678 os.path.realpath(source)) | 730 repo.root, cwd, os.path.realpath(source) |
731 ) | |
679 return kwt.match(source) | 732 return kwt.match(source) |
680 | 733 |
681 candidates = [f for f in repo.dirstate.copies() if | 734 candidates = [ |
682 'l' not in wctx.flags(f) and haskwsource(f)] | 735 f |
736 for f in repo.dirstate.copies() | |
737 if 'l' not in wctx.flags(f) and haskwsource(f) | |
738 ] | |
683 kwt.overwrite(wctx, candidates, False, False) | 739 kwt.overwrite(wctx, candidates, False, False) |
740 | |
684 | 741 |
685 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts): | 742 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts): |
686 '''Wraps record.dorecord expanding keywords after recording.''' | 743 '''Wraps record.dorecord expanding keywords after recording.''' |
687 kwt = getattr(repo, '_keywordkwt', None) | 744 kwt = getattr(repo, '_keywordkwt', None) |
688 if kwt is None: | 745 if kwt is None: |
701 kwt.overwrite(recctx, modified, False, True) | 758 kwt.overwrite(recctx, modified, False, True) |
702 kwt.overwrite(recctx, added, False, True, True) | 759 kwt.overwrite(recctx, added, False, True, True) |
703 kwt.restrict = True | 760 kwt.restrict = True |
704 return ret | 761 return ret |
705 | 762 |
763 | |
706 def kwfilectx_cmp(orig, self, fctx): | 764 def kwfilectx_cmp(orig, self, fctx): |
707 if fctx._customcmp: | 765 if fctx._customcmp: |
708 return fctx.cmp(self) | 766 return fctx.cmp(self) |
709 kwt = getattr(self._repo, '_keywordkwt', None) | 767 kwt = getattr(self._repo, '_keywordkwt', None) |
710 if kwt is None: | 768 if kwt is None: |
711 return orig(self, fctx) | 769 return orig(self, fctx) |
712 # keyword affects data size, comparing wdir and filelog size does | 770 # keyword affects data size, comparing wdir and filelog size does |
713 # not make sense | 771 # not make sense |
714 if (fctx._filenode is None and | 772 if ( |
715 (self._repo._encodefilterpats or | 773 fctx._filenode is None |
716 kwt.match(fctx.path()) and 'l' not in fctx.flags() or | 774 and ( |
717 self.size() - 4 == fctx.size()) or | 775 self._repo._encodefilterpats |
718 self.size() == fctx.size()): | 776 or kwt.match(fctx.path()) |
777 and 'l' not in fctx.flags() | |
778 or self.size() - 4 == fctx.size() | |
779 ) | |
780 or self.size() == fctx.size() | |
781 ): | |
719 return self._filelog.cmp(self._filenode, fctx.data()) | 782 return self._filelog.cmp(self._filenode, fctx.data()) |
720 return True | 783 return True |
784 | |
721 | 785 |
722 def uisetup(ui): | 786 def uisetup(ui): |
723 ''' Monkeypatches dispatch._parse to retrieve user command. | 787 ''' Monkeypatches dispatch._parse to retrieve user command. |
724 Overrides file method to return kwfilelog instead of filelog | 788 Overrides file method to return kwfilelog instead of filelog |
725 if file matches user configuration. | 789 if file matches user configuration. |
742 extensions.wrapfunction(cmdutil, 'copy', kw_copy) | 806 extensions.wrapfunction(cmdutil, 'copy', kw_copy) |
743 extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord) | 807 extensions.wrapfunction(cmdutil, 'dorecord', kw_dorecord) |
744 for c in nokwwebcommands.split(): | 808 for c in nokwwebcommands.split(): |
745 extensions.wrapfunction(webcommands, c, kwweb_skip) | 809 extensions.wrapfunction(webcommands, c, kwweb_skip) |
746 | 810 |
811 | |
747 def reposetup(ui, repo): | 812 def reposetup(ui, repo): |
748 '''Sets up repo as kwrepo for keyword substitution.''' | 813 '''Sets up repo as kwrepo for keyword substitution.''' |
749 | 814 |
750 try: | 815 try: |
751 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split() | 816 if ( |
817 not repo.local() | |
818 or kwtools['hgcmd'] in nokwcommands.split() | |
752 or '.hg' in util.splitpath(repo.root) | 819 or '.hg' in util.splitpath(repo.root) |
753 or repo._url.startswith('bundle:')): | 820 or repo._url.startswith('bundle:') |
821 ): | |
754 return | 822 return |
755 except AttributeError: | 823 except AttributeError: |
756 pass | 824 pass |
757 | 825 |
758 inc, exc = [], ['.hg*'] | 826 inc, exc = [], ['.hg*'] |
789 n = super(kwrepo, self).commitctx(ctx, error, origctx) | 857 n = super(kwrepo, self).commitctx(ctx, error, origctx) |
790 # no lock needed, only called from repo.commit() which already locks | 858 # no lock needed, only called from repo.commit() which already locks |
791 if not kwt.postcommit: | 859 if not kwt.postcommit: |
792 restrict = kwt.restrict | 860 restrict = kwt.restrict |
793 kwt.restrict = True | 861 kwt.restrict = True |
794 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()), | 862 kwt.overwrite( |
795 False, True) | 863 self[n], sorted(ctx.added() + ctx.modified()), False, True |
864 ) | |
796 kwt.restrict = restrict | 865 kwt.restrict = restrict |
797 return n | 866 return n |
798 | 867 |
799 def rollback(self, dryrun=False, force=False): | 868 def rollback(self, dryrun=False, force=False): |
800 with self.wlock(): | 869 with self.wlock(): |