Mercurial > hg
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 |