comparison hgext/keyword.py @ 12625:d87f3ff904ba

keyword: refactor kwtemplater.overwrite() Make kwexpand, kwshrink restricted commands - i.e. read from filelog without expansion for substition in kwtemplater.overwrite, and set/unset restricted mode for overwrite() in in kwcommitctx and the dorecord wrapper. Preselect candidates when working on changed files (rollback, record) outside kwtemplater class, and remove 6th argument from overwrite(). Avoid duplicate substitution/search in overwrite(): Only go into restricted read mode when reading from filelog. rollback and record read from the working directory, where restricted mode would already shrink keywords before overwrite() either expands or shrinks them again. This ensures that the usual automatic operations on keywords are turned off during overwrite() and only overwrite() itself acts on them. Reduce manifest calculation to the cases where it is needed. Move helper function for expansion removal outside kwtemplater class.
author Christian Ebert <blacktrash@gmx.net>
date Fri, 08 Oct 2010 18:39:46 +0100
parents aa4a6e3ed0c9
children 41df968a54c9
comparison
equal deleted inserted replaced
12624:557988c691d1 12625:d87f3ff904ba
94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init' 94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
95 ' log outgoing push rename tip verify convert email glog') 95 ' log outgoing push rename tip verify convert email glog')
96 96
97 # hg commands that trigger expansion only when writing to working dir, 97 # hg commands that trigger expansion only when writing to working dir,
98 # not when reading filelog, and unexpand when reading from working dir 98 # not when reading filelog, and unexpand when reading from working dir
99 restricted = 'merge record qrecord resolve transplant' 99 restricted = 'merge kwexpand kwshrink record qrecord resolve transplant'
100 100
101 # commands using dorecord 101 # commands using dorecord
102 recordcommands = 'record qrecord' 102 recordcommands = 'record qrecord'
103 # names of extensions using dorecord 103 # names of extensions using dorecord
104 recordextensions = 'record' 104 recordextensions = 'record'
136 'LastChangedDate': '{date|svnisodate}', 136 'LastChangedDate': '{date|svnisodate}',
137 }) 137 })
138 templates.update(kwsets[ui.configbool('keywordset', 'svn')]) 138 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
139 return templates 139 return templates
140 140
141 def _shrinktext(text, subfunc):
142 '''Helper for keyword expansion removal in text.
143 Depending on subfunc also returns number of substitutions.'''
144 return subfunc(r'$\1$', text)
145
146
141 class kwtemplater(object): 147 class kwtemplater(object):
142 ''' 148 '''
143 Sets up keyword templates, corresponding keyword regex, and 149 Sets up keyword templates, corresponding keyword regex, and
144 provides keyword substitution functions. 150 provides keyword substitution functions.
145 ''' 151 '''
189 '''Returns true if path matches [keyword] pattern 195 '''Returns true if path matches [keyword] pattern
190 and is not a symbolic link. 196 and is not a symbolic link.
191 Caveat: localrepository._link fails on Windows.''' 197 Caveat: localrepository._link fails on Windows.'''
192 return self.match(path) and not 'l' in flagfunc(path) 198 return self.match(path) and not 'l' in flagfunc(path)
193 199
194 def overwrite(self, ctx, candidates, iswctx, expand, changed): 200 def overwrite(self, ctx, candidates, lookup, expand):
195 '''Overwrites selected files expanding/shrinking keywords.''' 201 '''Overwrites selected files expanding/shrinking keywords.'''
196 if changed is not None:
197 candidates = [f for f in candidates if f in changed]
198 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)] 202 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
199 if candidates: 203 if not candidates:
200 restrict = self.restrict 204 return
201 self.restrict = True # do not expand when reading 205 commit = self.restrict and not lookup
202 rollback = kwtools['hgcmd'] == 'rollback' 206 if self.restrict or expand and lookup:
203 mf = ctx.manifest() 207 mf = ctx.manifest()
204 msg = (expand and _('overwriting %s expanding keywords\n') 208 fctx = ctx
205 or _('overwriting %s shrinking keywords\n')) 209 msg = (expand and _('overwriting %s expanding keywords\n')
206 for f in candidates: 210 or _('overwriting %s shrinking keywords\n'))
207 if not self.record and not rollback: 211 for f in candidates:
208 data = self.repo.file(f).read(mf[f]) 212 if self.restrict:
209 else: 213 data = self.repo.file(f).read(mf[f])
210 data = self.repo.wread(f) 214 else:
211 if util.binary(data): 215 data = self.repo.wread(f)
212 continue 216 if util.binary(data):
213 if expand: 217 continue
214 if iswctx: 218 if expand:
215 ctx = self.repo.filectx(f, fileid=mf[f]).changectx() 219 if lookup:
216 data, found = self.substitute(data, f, ctx, 220 fctx = self.repo.filectx(f, fileid=mf[f]).changectx()
217 self.re_kw.subn) 221 data, found = self.substitute(data, f, fctx, self.re_kw.subn)
218 else: 222 elif self.restrict:
219 found = self.re_kw.search(data) 223 found = self.re_kw.search(data)
220 if found: 224 else:
221 self.ui.note(msg % f) 225 data, found = _shrinktext(data, self.re_kw.subn)
222 self.repo.wwrite(f, data, mf.flags(f)) 226 if found:
223 if iswctx and not rollback: 227 self.ui.note(msg % f)
224 self.repo.dirstate.normal(f) 228 self.repo.wwrite(f, data, ctx.flags(f))
225 elif self.record: 229 if commit:
226 self.repo.dirstate.normallookup(f) 230 self.repo.dirstate.normal(f)
227 self.restrict = restrict 231 elif self.record:
228 232 self.repo.dirstate.normallookup(f)
229 def shrinktext(self, text):
230 '''Unconditionally removes all keyword substitutions from text.'''
231 return self.re_kw.sub(r'$\1$', text)
232 233
233 def shrink(self, fname, text): 234 def shrink(self, fname, text):
234 '''Returns text with all keyword substitutions removed.''' 235 '''Returns text with all keyword substitutions removed.'''
235 if self.match(fname) and not util.binary(text): 236 if self.match(fname) and not util.binary(text):
236 return self.shrinktext(text) 237 return _shrinktext(text, self.re_kw.sub)
237 return text 238 return text
238 239
239 def shrinklines(self, fname, lines): 240 def shrinklines(self, fname, lines):
240 '''Returns lines with keyword substitutions removed.''' 241 '''Returns lines with keyword substitutions removed.'''
241 if self.match(fname): 242 if self.match(fname):
242 text = ''.join(lines) 243 text = ''.join(lines)
243 if not util.binary(text): 244 if not util.binary(text):
244 return self.shrinktext(text).splitlines(True) 245 return _shrinktext(text, self.re_kw.sub).splitlines(True)
245 return lines 246 return lines
246 247
247 def wread(self, fname, data): 248 def wread(self, fname, data):
248 '''If in restricted mode returns data read from wdir with 249 '''If in restricted mode returns data read from wdir with
249 keyword substitutions removed.''' 250 keyword substitutions removed.'''
297 try: 298 try:
298 status = _status(ui, repo, kwt, *pats, **opts) 299 status = _status(ui, repo, kwt, *pats, **opts)
299 modified, added, removed, deleted, unknown, ignored, clean = status 300 modified, added, removed, deleted, unknown, ignored, clean = status
300 if modified or added or removed or deleted: 301 if modified or added or removed or deleted:
301 raise util.Abort(_('outstanding uncommitted changes')) 302 raise util.Abort(_('outstanding uncommitted changes'))
302 kwt.overwrite(wctx, clean, True, expand, None) 303 kwt.overwrite(wctx, clean, True, expand)
303 finally: 304 finally:
304 wlock.release() 305 wlock.release()
305 306
306 def demo(ui, repo, *args, **opts): 307 def demo(ui, repo, *args, **opts):
307 '''print [keywordmaps] configuration and an expansion example 308 '''print [keywordmaps] configuration and an expansion example
500 501
501 def kwcommitctx(self, ctx, error=False): 502 def kwcommitctx(self, ctx, error=False):
502 n = super(kwrepo, self).commitctx(ctx, error) 503 n = super(kwrepo, self).commitctx(ctx, error)
503 # no lock needed, only called from repo.commit() which already locks 504 # no lock needed, only called from repo.commit() which already locks
504 if not kwt.record: 505 if not kwt.record:
506 restrict = kwt.restrict
507 kwt.restrict = True
505 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()), 508 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
506 False, True, None) 509 False, True)
510 kwt.restrict = restrict
507 return n 511 return n
508 512
509 def rollback(self, dryrun=False): 513 def rollback(self, dryrun=False):
510 wlock = repo.wlock() 514 wlock = repo.wlock()
511 try: 515 try:
513 changed = self['.'].files() 517 changed = self['.'].files()
514 ret = super(kwrepo, self).rollback(dryrun) 518 ret = super(kwrepo, self).rollback(dryrun)
515 if not dryrun: 519 if not dryrun:
516 ctx = self['.'] 520 ctx = self['.']
517 modified, added = self[None].status()[:2] 521 modified, added = self[None].status()[:2]
518 kwt.overwrite(ctx, added, True, False, changed) 522 modified = [f for f in modified if f in changed]
519 kwt.overwrite(ctx, modified, True, True, changed) 523 added = [f for f in added if f in changed]
524 kwt.overwrite(ctx, added, True, False)
525 kwt.overwrite(ctx, modified, True, True)
520 return ret 526 return ret
521 finally: 527 finally:
522 wlock.release() 528 wlock.release()
523 529
524 # monkeypatches 530 # monkeypatches
549 # therefore compare nodes before and after 555 # therefore compare nodes before and after
550 ctx = repo['.'] 556 ctx = repo['.']
551 ret = orig(ui, repo, commitfunc, *pats, **opts) 557 ret = orig(ui, repo, commitfunc, *pats, **opts)
552 recordctx = repo['.'] 558 recordctx = repo['.']
553 if ctx != recordctx: 559 if ctx != recordctx:
554 kwt.overwrite(recordctx, recordctx.files(), 560 candidates = [f for f in recordctx.files() if f in recordctx]
555 False, True, recordctx) 561 kwt.restrict = False
562 kwt.overwrite(recordctx, candidates, False, True)
563 kwt.restrict = True
556 return ret 564 return ret
557 finally: 565 finally:
558 wlock.release() 566 wlock.release()
559 567
560 repo.__class__ = kwrepo 568 repo.__class__ = kwrepo