95 commands.optionalrepo += ' kwdemo' |
95 commands.optionalrepo += ' kwdemo' |
96 |
96 |
97 def utcdate(date): |
97 def utcdate(date): |
98 '''Returns hgdate in cvs-like UTC format.''' |
98 '''Returns hgdate in cvs-like UTC format.''' |
99 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
99 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
100 |
|
101 def keywordmatcher(ui, repo): |
|
102 '''Collects include/exclude filename patterns for expansion |
|
103 candidates of current configuration. Returns filename matching |
|
104 function if include patterns exist, None otherwise.''' |
|
105 inc, exc = [], ['.hg*'] |
|
106 for pat, opt in ui.configitems('keyword'): |
|
107 if opt != 'ignore': |
|
108 inc.append(pat) |
|
109 else: |
|
110 exc.append(pat) |
|
111 if not inc: |
|
112 return None |
|
113 return util.matcher(repo.root, inc=inc, exc=exc)[1] |
|
114 |
100 |
115 class kwtemplater(object): |
101 class kwtemplater(object): |
116 ''' |
102 ''' |
117 Sets up keyword templates, corresponding keyword regex, and |
103 Sets up keyword templates, corresponding keyword regex, and |
118 provides keyword substitution functions. |
104 provides keyword substitution functions. |
125 'Source': '{root}/{file},v', |
111 'Source': '{root}/{file},v', |
126 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', |
112 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}', |
127 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', |
113 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}', |
128 } |
114 } |
129 |
115 |
130 def __init__(self, ui, repo, path='', node=None, expand=True): |
116 def __init__(self, ui, repo, expand, path='', node=None): |
131 self.ui = ui |
117 self.ui = ui |
132 self.repo = repo |
118 self.repo = repo |
|
119 self.t = expand or None |
133 self.path = path |
120 self.path = path |
134 self.node = node |
121 self.node = node |
135 self.t = expand or None |
|
136 |
122 |
137 templates = dict(ui.configitems('keywordmaps')) |
123 templates = dict(ui.configitems('keywordmaps')) |
138 if templates: |
124 if templates: |
139 for k in templates.keys(): |
125 for k in templates.keys(): |
140 templates[k] = templater.parsestring(templates[k], |
126 templates[k] = templater.parsestring(templates[k], |
190 '''Returns text with all keyword substitutions removed.''' |
176 '''Returns text with all keyword substitutions removed.''' |
191 if util.binary(text): |
177 if util.binary(text): |
192 return text |
178 return text |
193 return self.re_kw.sub(r'$\1$', text) |
179 return self.re_kw.sub(r'$\1$', text) |
194 |
180 |
195 def overwrite(self, candidates, man, commit=True): |
181 def overwrite(self, candidates, man, commit): |
196 '''Overwrites files in working directory if keywords are detected. |
182 '''Overwrites files in working directory if keywords are detected. |
197 Keywords are expanded if keyword templater is initialized, |
183 Keywords are expanded if keyword templater is initialized, |
198 otherwise their substitution is removed.''' |
184 otherwise their substitution is removed.''' |
199 expand = self.t is not None |
185 expand = self.t is not None |
200 action = ('shrinking', 'expanding')[expand] |
186 action = ('shrinking', 'expanding')[expand] |
201 notify = (self.ui.note, self.ui.debug)[commit] |
187 notify = (self.ui.note, self.ui.debug)[commit] |
202 files = [] |
188 files = [] |
203 for f in candidates: |
189 for f in candidates: |
204 fp = self.repo.file(f, kwcnt=True, kwexp=expand) |
190 fp = self.repo.file(f, kwexp=expand, kwcnt=True) |
205 data, cnt = fp.read(man[f]) |
191 data, kwfound = fp.read(man[f]) |
206 if cnt: |
192 if kwfound: |
207 notify(_('overwriting %s %s keywords\n') % (f, action)) |
193 notify(_('overwriting %s %s keywords\n') % (f, action)) |
208 try: |
194 try: |
209 self.repo.wwrite(f, data, man.flags(f)) |
195 self.repo.wwrite(f, data, man.flags(f)) |
210 except AttributeError: |
196 except AttributeError: |
211 # older versions want file descriptor as 3. optional arg |
197 # older versions want file descriptor as 3. optional arg |
245 if self.renamed(node): |
231 if self.renamed(node): |
246 t2 = super(kwfilelog, self).read(node) |
232 t2 = super(kwfilelog, self).read(node) |
247 return t2 != text |
233 return t2 != text |
248 return super(kwfilelog, self).cmp(node, text) |
234 return super(kwfilelog, self).cmp(node, text) |
249 |
235 |
250 def _overwrite(ui, repo, files=None, expand=True): |
236 def _keywordmatcher(ui, repo): |
|
237 '''Collects include/exclude filename patterns for expansion |
|
238 candidates of current configuration. Returns filename matching |
|
239 function if include patterns exist, None otherwise.''' |
|
240 inc, exc = [], ['.hg*'] |
|
241 for pat, opt in ui.configitems('keyword'): |
|
242 if opt != 'ignore': |
|
243 inc.append(pat) |
|
244 else: |
|
245 exc.append(pat) |
|
246 if inc: |
|
247 return util.matcher(repo.root, inc=inc, exc=exc)[1] |
|
248 return None |
|
249 |
|
250 def _overwrite(ui, repo, files, expand): |
251 '''Expands/shrinks keywords in working directory.''' |
251 '''Expands/shrinks keywords in working directory.''' |
252 wlock = None |
252 wlock = None |
253 try: |
253 try: |
254 wlock = repo.wlock() |
254 wlock = repo.wlock() |
255 bail_if_changed(repo) |
255 bail_if_changed(repo) |
256 ctx = repo.changectx() |
256 ctx = repo.changectx() |
257 if not ctx: |
257 if not ctx: |
258 raise hg.RepoError(_('no revision checked out')) |
258 raise hg.RepoError(_('no revision checked out')) |
259 kwfmatcher = keywordmatcher(ui, repo) |
259 kwfmatcher = _keywordmatcher(ui, repo) |
260 if kwfmatcher is None: |
260 if kwfmatcher is None: |
261 ui.warn(_('no files configured for keyword expansion\n')) |
261 ui.warn(_('no files configured for keyword expansion\n')) |
262 return |
262 return |
263 m = ctx.manifest() |
263 m = ctx.manifest() |
264 if files: |
264 if files: |
267 files = m.keys() |
267 files = m.keys() |
268 files = [f for f in files if kwfmatcher(f) and not os.path.islink(f)] |
268 files = [f for f in files if kwfmatcher(f) and not os.path.islink(f)] |
269 if not files: |
269 if not files: |
270 ui.warn(_('files not configured for expansion or untracked\n')) |
270 ui.warn(_('files not configured for expansion or untracked\n')) |
271 return |
271 return |
272 kwt = kwtemplater(ui, repo, node=ctx.node(), expand=expand) |
272 commit = False |
273 kwt.overwrite(files, m, commit=False) |
273 kwt = kwtemplater(ui, repo, expand, node=ctx.node()) |
|
274 kwt.overwrite(files, m, commit) |
274 wlock = None |
275 wlock = None |
275 finally: |
276 finally: |
276 del wlock |
277 del wlock |
277 |
278 |
278 |
279 |
282 run before: |
283 run before: |
283 disabling keyword expansion |
284 disabling keyword expansion |
284 changing keyword expansion configuration |
285 changing keyword expansion configuration |
285 or if you experience problems with "hg import" |
286 or if you experience problems with "hg import" |
286 ''' |
287 ''' |
287 _overwrite(ui, repo, files=args, expand=False) |
288 expand = False |
|
289 _overwrite(ui, repo, args, expand) |
288 |
290 |
289 def expand(ui, repo, *args): |
291 def expand(ui, repo, *args): |
290 '''expand keywords in working directory |
292 '''expand keywords in working directory |
291 |
293 |
292 run after (re)enabling keyword expansion |
294 run after (re)enabling keyword expansion |
293 ''' |
295 ''' |
294 _overwrite(ui, repo, files=args) |
296 expand = True |
|
297 _overwrite(ui, repo, args, expand) |
295 |
298 |
296 def demo(ui, repo, *args, **opts): |
299 def demo(ui, repo, *args, **opts): |
297 '''print [keywordmaps] configuration and an expansion example |
300 '''print [keywordmaps] configuration and an expansion example |
298 |
301 |
299 show current, custom, or default keyword template maps and their expansion |
302 show current, custom, or default keyword template maps and their expansion |
367 return aliases[0] |
370 return aliases[0] |
368 |
371 |
369 if not repo.local() or _getcmd() in nokwcommands: |
372 if not repo.local() or _getcmd() in nokwcommands: |
370 return |
373 return |
371 |
374 |
372 kwfmatcher = keywordmatcher(ui, repo) |
375 kwfmatcher = _keywordmatcher(ui, repo) |
373 if kwfmatcher is None: |
376 if kwfmatcher is None: |
374 return |
377 return |
375 |
378 |
376 class kwrepo(repo.__class__): |
379 class kwrepo(repo.__class__): |
377 def file(self, f, kwcnt=False, kwexp=True): |
380 def file(self, f, kwexp=True, kwcnt=False): |
378 if f[0] == '/': |
381 if f[0] == '/': |
379 f = f[1:] |
382 f = f[1:] |
380 if kwfmatcher(f): |
383 if kwfmatcher(f): |
381 kwt = kwtemplater(ui, self, path=f, expand=kwexp) |
384 kwt = kwtemplater(ui, self, kwexp, path=f) |
382 return kwfilelog(self.sopener, f, kwt, kwcnt) |
385 return kwfilelog(self.sopener, f, kwt, kwcnt) |
383 return filelog.filelog(self.sopener, f) |
386 return filelog.filelog(self.sopener, f) |
384 |
387 |
385 def commit(self, files=None, text='', user=None, date=None, |
388 def commit(self, files=None, text='', user=None, date=None, |
386 match=util.always, force=False, lock=None, wlock=None, |
389 match=util.always, force=False, lock=None, wlock=None, |
402 candidates = [f for f in cl[3] if kwfmatcher(f) |
405 candidates = [f for f in cl[3] if kwfmatcher(f) |
403 and f not in removed |
406 and f not in removed |
404 and not os.path.islink(self.wjoin(f))] |
407 and not os.path.islink(self.wjoin(f))] |
405 if candidates: |
408 if candidates: |
406 m = self.manifest.read(cl[0]) |
409 m = self.manifest.read(cl[0]) |
407 kwt = kwtemplater(ui, self, node=node) |
410 expand = commit = True |
408 kwt.overwrite(candidates, m) |
411 kwt = kwtemplater(ui, self, expand, node=node) |
|
412 kwt.overwrite(candidates, m, commit) |
409 wlock = None |
413 wlock = None |
410 return node |
414 return node |
411 finally: |
415 finally: |
412 del wlock |
416 del wlock |
413 |
417 |