##// END OF EJS Templates
keyword: move expand/shrink decisions into kwtemplater...
Christian Ebert -
r6114:ee83510f default
parent child Browse files
Show More
@@ -101,8 +101,8 b' def utcdate(date):'
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
102
102
103
103
104 _kwtemplater = _cmd = _cmdoptions = None
104 _kwtemplater = _cmd = None
105
105
106 # store originals of monkeypatches
106 # store originals of monkeypatches
107 _patchfile_init = patch.patchfile.__init__
107 _patchfile_init = patch.patchfile.__init__
108 _patch_diff = patch.diff
108 _patch_diff = patch.diff
@@ -112,10 +112,8 b' def _kwpatchfile_init(self, ui, fname, m'
112 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
112 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
113 rejects or conflicts due to expanded keywords in working dir.'''
113 rejects or conflicts due to expanded keywords in working dir.'''
114 _patchfile_init(self, ui, fname, missing=missing)
114 _patchfile_init(self, ui, fname, missing=missing)
115 if _kwtemplater.matcher(self.fname):
115 # shrink keywords read from working dir
116 # shrink keywords read from working dir
116 self.lines = _kwtemplater.shrinklines(self.fname, self.lines)
117 kwshrunk = _kwtemplater.shrink(''.join(self.lines))
118 self.lines = kwshrunk.splitlines(True)
119
117
120 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
118 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
121 fp=None, changes=None, opts=None):
119 fp=None, changes=None, opts=None):
@@ -162,13 +160,11 b' class kwtemplater(object):'
162 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
160 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
163 }
161 }
164
162
165 def __init__(self, ui, repo, inc, exc, hgcmd):
163 def __init__(self, ui, repo, inc, exc):
166 self.ui = ui
164 self.ui = ui
167 self.repo = repo
165 self.repo = repo
168 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
166 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
169 self.restrict = hgcmd in restricted.split()
167 self.restrict = _cmd in restricted.split()
170 self.commitnode = None
171 self.path = ''
172
168
173 kwmaps = self.ui.configitems('keywordmaps')
169 kwmaps = self.ui.configitems('keywordmaps')
174 if kwmaps: # override default templates
170 if kwmaps: # override default templates
@@ -183,47 +179,89 b' class kwtemplater(object):'
183 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
179 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
184 False, '', False)
180 False, '', False)
185
181
186 def substitute(self, node, data, subfunc):
182 def getnode(self, path, fnode):
187 '''Obtains file's changenode if commit node not given,
183 '''Derives changenode from file path and filenode.'''
188 and calls given substitution function.'''
184 # used by kwfilelog.read and kwexpand
189 if self.commitnode:
185 c = context.filectx(self.repo, path, fileid=fnode)
190 fnode = self.commitnode
186 return c.node()
191 else:
192 c = context.filectx(self.repo, self.path, fileid=node)
193 fnode = c.node()
194
187
188 def substitute(self, data, path, node, subfunc):
189 '''Replaces keywords in data with expanded template.'''
195 def kwsub(mobj):
190 def kwsub(mobj):
196 '''Substitutes keyword using corresponding template.'''
197 kw = mobj.group(1)
191 kw = mobj.group(1)
198 self.ct.use_template(self.templates[kw])
192 self.ct.use_template(self.templates[kw])
199 self.ui.pushbuffer()
193 self.ui.pushbuffer()
200 self.ct.show(changenode=fnode, root=self.repo.root, file=self.path)
194 self.ct.show(changenode=node, root=self.repo.root, file=path)
201 ekw = templatefilters.firstline(self.ui.popbuffer())
195 ekw = templatefilters.firstline(self.ui.popbuffer())
202 return '$%s: %s $' % (kw, ekw)
196 return '$%s: %s $' % (kw, ekw)
203
204 return subfunc(kwsub, data)
197 return subfunc(kwsub, data)
205
198
206 def expand(self, node, data):
199 def expand(self, path, node, data):
207 '''Returns data with keywords expanded.'''
200 '''Returns data with keywords expanded.'''
208 if self.restrict or util.binary(data):
201 if not self.restrict and self.matcher(path) and not util.binary(data):
209 return data
202 changenode = self.getnode(path, node)
210 return self.substitute(node, data, self.re_kw.sub)
203 return self.substitute(data, path, changenode, self.re_kw.sub)
204 return data
205
206 def iskwfile(self, path, islink):
207 '''Returns true if path matches [keyword] pattern
208 and is not a symbolic link.
209 Caveat: localrepository._link fails on Windows.'''
210 return self.matcher(path) and not islink(path)
211
211
212 def process(self, node, data, expand):
212 def overwrite(self, node=None, expand=True, files=None):
213 '''Returns a tuple: data, count.
213 '''Overwrites selected files expanding/shrinking keywords.'''
214 Count is number of keywords/keyword substitutions,
214 ctx = self.repo.changectx(node)
215 telling caller whether to act on file containing data.'''
215 mf = ctx.manifest()
216 if util.binary(data):
216 if node is not None: # commit
217 return data, None
217 files = [f for f in ctx.files() if f in mf]
218 if expand:
218 notify = self.ui.debug
219 return self.substitute(node, data, self.re_kw.subn)
219 else: # kwexpand/kwshrink
220 return data, self.re_kw.search(data)
220 notify = self.ui.note
221 candidates = [f for f in files if self.iskwfile(f, mf.linkf)]
222 if candidates:
223 self.restrict = True # do not expand when reading
224 candidates.sort()
225 action = expand and 'expanding' or 'shrinking'
226 for f in candidates:
227 fp = self.repo.file(f)
228 data = fp.read(mf[f])
229 if util.binary(data):
230 continue
231 if expand:
232 changenode = node or self.getnode(f, mf[f])
233 data, found = self.substitute(data, f, changenode,
234 self.re_kw.subn)
235 else:
236 found = self.re_kw.search(data)
237 if found:
238 notify(_('overwriting %s %s keywords\n') % (f, action))
239 self.repo.wwrite(f, data, mf.flags(f))
240 self.repo.dirstate.normal(f)
241 self.restrict = False
221
242
222 def shrink(self, text):
243 def shrinktext(self, text):
244 '''Unconditionally removes all keyword substitutions from text.'''
245 return self.re_kw.sub(r'$\1$', text)
246
247 def shrink(self, fname, text):
223 '''Returns text with all keyword substitutions removed.'''
248 '''Returns text with all keyword substitutions removed.'''
224 if util.binary(text):
249 if self.matcher(fname) and not util.binary(text):
225 return text
250 return self.shrinktext(text)
226 return self.re_kw.sub(r'$\1$', text)
251 return text
252
253 def shrinklines(self, fname, lines):
254 '''Returns lines with keyword substitutions removed.'''
255 if self.matcher(fname):
256 text = ''.join(lines)
257 if not util.binary(text):
258 return self.shrinktext(text).splitlines(True)
259 return lines
260
261 def wread(self, fname, data):
262 '''If in restricted mode returns data read from wdir with
263 keyword substitutions removed.'''
264 return self.restrict and self.shrink(fname, data) or data
227
265
228 class kwfilelog(filelog.filelog):
266 class kwfilelog(filelog.filelog):
229 '''
267 '''
@@ -232,34 +270,26 b' class kwfilelog(filelog.filelog):'
232 '''
270 '''
233 def __init__(self, opener, path):
271 def __init__(self, opener, path):
234 super(kwfilelog, self).__init__(opener, path)
272 super(kwfilelog, self).__init__(opener, path)
235 _kwtemplater.path = path
273 self.path = path
236
237 def kwctread(self, node, expand):
238 '''Reads expanding and counting keywords, called from _overwrite.'''
239 data = super(kwfilelog, self).read(node)
240 return _kwtemplater.process(node, data, expand)
241
274
242 def read(self, node):
275 def read(self, node):
243 '''Expands keywords when reading filelog.'''
276 '''Expands keywords when reading filelog.'''
244 data = super(kwfilelog, self).read(node)
277 data = super(kwfilelog, self).read(node)
245 return _kwtemplater.expand(node, data)
278 return _kwtemplater.expand(self.path, node, data)
246
279
247 def add(self, text, meta, tr, link, p1=None, p2=None):
280 def add(self, text, meta, tr, link, p1=None, p2=None):
248 '''Removes keyword substitutions when adding to filelog.'''
281 '''Removes keyword substitutions when adding to filelog.'''
249 text = _kwtemplater.shrink(text)
282 text = _kwtemplater.shrink(self.path, text)
250 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
283 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
251
284
252 def cmp(self, node, text):
285 def cmp(self, node, text):
253 '''Removes keyword substitutions for comparison.'''
286 '''Removes keyword substitutions for comparison.'''
254 text = _kwtemplater.shrink(text)
287 text = _kwtemplater.shrink(self.path, text)
255 if self.renamed(node):
288 if self.renamed(node):
256 t2 = super(kwfilelog, self).read(node)
289 t2 = super(kwfilelog, self).read(node)
257 return t2 != text
290 return t2 != text
258 return revlog.revlog.cmp(self, node, text)
291 return revlog.revlog.cmp(self, node, text)
259
292
260 def _iskwfile(f, link):
261 return not link(f) and _kwtemplater.matcher(f)
262
263 def _status(ui, repo, *pats, **opts):
293 def _status(ui, repo, *pats, **opts):
264 '''Bails out if [keyword] configuration is not active.
294 '''Bails out if [keyword] configuration is not active.
265 Returns status of working directory.'''
295 Returns status of working directory.'''
@@ -270,30 +300,8 b' def _status(ui, repo, *pats, **opts):'
270 raise util.Abort(_('[keyword] patterns cannot match'))
300 raise util.Abort(_('[keyword] patterns cannot match'))
271 raise util.Abort(_('no [keyword] patterns configured'))
301 raise util.Abort(_('no [keyword] patterns configured'))
272
302
273 def _overwrite(ui, repo, node=None, expand=True, files=None):
274 '''Overwrites selected files expanding/shrinking keywords.'''
275 ctx = repo.changectx(node)
276 mf = ctx.manifest()
277 if node is not None: # commit
278 _kwtemplater.commitnode = node
279 files = [f for f in ctx.files() if f in mf]
280 notify = ui.debug
281 else: # kwexpand/kwshrink
282 notify = ui.note
283 candidates = [f for f in files if _iskwfile(f, mf.linkf)]
284 if candidates:
285 candidates.sort()
286 action = expand and 'expanding' or 'shrinking'
287 for f in candidates:
288 fp = repo.file(f, kwmatch=True)
289 data, kwfound = fp.kwctread(mf[f], expand)
290 if kwfound:
291 notify(_('overwriting %s %s keywords\n') % (f, action))
292 repo.wwrite(f, data, mf.flags(f))
293 repo.dirstate.normal(f)
294
295 def _kwfwrite(ui, repo, expand, *pats, **opts):
303 def _kwfwrite(ui, repo, expand, *pats, **opts):
296 '''Selects files and passes them to _overwrite.'''
304 '''Selects files and passes them to kwtemplater.overwrite.'''
297 status = _status(ui, repo, *pats, **opts)
305 status = _status(ui, repo, *pats, **opts)
298 modified, added, removed, deleted, unknown, ignored, clean = status
306 modified, added, removed, deleted, unknown, ignored, clean = status
299 if modified or added or removed or deleted:
307 if modified or added or removed or deleted:
@@ -302,7 +310,7 b' def _kwfwrite(ui, repo, expand, *pats, *'
302 try:
310 try:
303 wlock = repo.wlock()
311 wlock = repo.wlock()
304 lock = repo.lock()
312 lock = repo.lock()
305 _overwrite(ui, repo, expand=expand, files=clean)
313 _kwtemplater.overwrite(expand=expand, files=clean)
306 finally:
314 finally:
307 del wlock, lock
315 del wlock, lock
308
316
@@ -412,7 +420,7 b' def files(ui, repo, *pats, **opts):'
412 files.sort()
420 files.sort()
413 wctx = repo.workingctx()
421 wctx = repo.workingctx()
414 islink = lambda p: 'l' in wctx.fileflags(p)
422 islink = lambda p: 'l' in wctx.fileflags(p)
415 kwfiles = [f for f in files if _iskwfile(f, islink)]
423 kwfiles = [f for f in files if _kwtemplater.iskwfile(f, islink)]
416 cwd = pats and repo.getcwd() or ''
424 cwd = pats and repo.getcwd() or ''
417 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
425 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
418 if opts.get('all') or opts.get('ignore'):
426 if opts.get('all') or opts.get('ignore'):
@@ -446,7 +454,7 b' def reposetup(ui, repo):'
446 global _kwtemplater
454 global _kwtemplater
447
455
448 try:
456 try:
449 if (not repo.local() or _cmd in nokwcommands.split()
457 if (not repo.local() or _cmd in nokwcommands.split()
450 or '.hg' in util.splitpath(repo.root)
458 or '.hg' in util.splitpath(repo.root)
451 or repo._url.startswith('bundle:')):
459 or repo._url.startswith('bundle:')):
452 return
460 return
@@ -462,21 +470,17 b' def reposetup(ui, repo):'
462 if not inc:
470 if not inc:
463 return
471 return
464
472
465 _kwtemplater = kwtemplater(ui, repo, inc, exc, _cmd)
473 _kwtemplater = kwtemplater(ui, repo, inc, exc)
466
474
467 class kwrepo(repo.__class__):
475 class kwrepo(repo.__class__):
468 def file(self, f, kwmatch=False):
476 def file(self, f):
469 if f[0] == '/':
477 if f[0] == '/':
470 f = f[1:]
478 f = f[1:]
471 if kwmatch or _kwtemplater.matcher(f):
479 return kwfilelog(self.sopener, f)
472 return kwfilelog(self.sopener, f)
473 return filelog.filelog(self.sopener, f)
474
480
475 def wread(self, filename):
481 def wread(self, filename):
476 data = super(kwrepo, self).wread(filename)
482 data = super(kwrepo, self).wread(filename)
477 if _kwtemplater.restrict and _kwtemplater.matcher(filename):
483 return _kwtemplater.wread(filename, data)
478 return _kwtemplater.shrink(data)
479 return data
480
484
481 def commit(self, files=None, text='', user=None, date=None,
485 def commit(self, files=None, text='', user=None, date=None,
482 match=util.always, force=False, force_editor=False,
486 match=util.always, force=False, force_editor=False,
@@ -515,7 +519,7 b' def reposetup(ui, repo):'
515 for name, cmd in commithooks.iteritems():
519 for name, cmd in commithooks.iteritems():
516 ui.setconfig('hooks', name, cmd)
520 ui.setconfig('hooks', name, cmd)
517 if node is not None:
521 if node is not None:
518 _overwrite(ui, self, node=node)
522 _kwtemplater.overwrite(node=node)
519 repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
523 repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
520 return node
524 return node
521 finally:
525 finally:
General Comments 0
You need to be logged in to leave comments. Login now