161 self.ui = ui |
161 self.ui = ui |
162 self.repo = repo |
162 self.repo = repo |
163 self.match = match.match(repo.root, '', [], inc, exc) |
163 self.match = match.match(repo.root, '', [], inc, exc) |
164 self.restrict = kwtools['hgcmd'] in restricted.split() |
164 self.restrict = kwtools['hgcmd'] in restricted.split() |
165 self.record = False |
165 self.record = False |
|
166 self.re_kw = None |
|
167 self.re_kwexp = None |
166 |
168 |
167 kwmaps = self.ui.configitems('keywordmaps') |
169 kwmaps = self.ui.configitems('keywordmaps') |
168 if kwmaps: # override default templates |
170 if kwmaps: # override default templates |
169 self.templates = dict((k, templater.parsestring(v, False)) |
171 self.templates = dict((k, templater.parsestring(v, False)) |
170 for k, v in kwmaps) |
172 for k, v in kwmaps) |
171 else: |
173 else: |
172 self.templates = _defaultkwmaps(self.ui) |
174 self.templates = _defaultkwmaps(self.ui) |
173 escaped = '|'.join(map(re.escape, self.templates.keys())) |
|
174 self.re_kw = re.compile(r'\$(%s)\$' % escaped) |
|
175 self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % escaped) |
|
176 |
|
177 templatefilters.filters.update({'utcdate': utcdate, |
175 templatefilters.filters.update({'utcdate': utcdate, |
178 'svnisodate': svnisodate, |
176 'svnisodate': svnisodate, |
179 'svnutcdate': svnutcdate}) |
177 'svnutcdate': svnutcdate}) |
|
178 |
|
179 def escape(self): |
|
180 '''Returns bar-separated list of keywords.''' |
|
181 return '|'.join(map(re.escape, self.templates.keys())) |
|
182 |
|
183 def rekw(self): |
|
184 '''Compiles regex for unexpanded keywords on demand.''' |
|
185 if self.re_kw is None: |
|
186 self.re_kw = re.compile(r'\$(%s)\$' % self.escape()) |
|
187 return self.re_kw |
|
188 |
|
189 def rekwexp(self): |
|
190 '''Compiles regex for expanded keywords on demand.''' |
|
191 if self.re_kwexp is None: |
|
192 self.re_kwexp = re.compile(r'\$(%s): [^$\n\r]*? \$' % self.escape()) |
|
193 return self.re_kwexp |
180 |
194 |
181 def substitute(self, data, path, ctx, subfunc): |
195 def substitute(self, data, path, ctx, subfunc): |
182 '''Replaces keywords in data with expanded template.''' |
196 '''Replaces keywords in data with expanded template.''' |
183 def kwsub(mobj): |
197 def kwsub(mobj): |
184 kw = mobj.group(1) |
198 kw = mobj.group(1) |
193 |
207 |
194 def expand(self, path, node, data): |
208 def expand(self, path, node, data): |
195 '''Returns data with keywords expanded.''' |
209 '''Returns data with keywords expanded.''' |
196 if not self.restrict and self.match(path) and not util.binary(data): |
210 if not self.restrict and self.match(path) and not util.binary(data): |
197 ctx = self.repo.filectx(path, fileid=node).changectx() |
211 ctx = self.repo.filectx(path, fileid=node).changectx() |
198 return self.substitute(data, path, ctx, self.re_kw.sub) |
212 return self.substitute(data, path, ctx, self.rekw().sub) |
199 return data |
213 return data |
200 |
214 |
201 def iskwfile(self, cand, ctx): |
215 def iskwfile(self, cand, ctx): |
202 '''Returns subset of candidates which are configured for keyword |
216 '''Returns subset of candidates which are configured for keyword |
203 expansion are not symbolic links.''' |
217 expansion are not symbolic links.''' |
211 return |
225 return |
212 kwcmd = self.restrict and lookup # kwexpand/kwshrink |
226 kwcmd = self.restrict and lookup # kwexpand/kwshrink |
213 if self.restrict or expand and lookup: |
227 if self.restrict or expand and lookup: |
214 mf = ctx.manifest() |
228 mf = ctx.manifest() |
215 fctx = ctx |
229 fctx = ctx |
216 subn = (self.restrict or rekw) and self.re_kw.subn or self.re_kwexp.subn |
230 re_kw = (self.restrict or rekw) and self.rekw() or self.rekwexp() |
217 msg = (expand and _('overwriting %s expanding keywords\n') |
231 msg = (expand and _('overwriting %s expanding keywords\n') |
218 or _('overwriting %s shrinking keywords\n')) |
232 or _('overwriting %s shrinking keywords\n')) |
219 for f in candidates: |
233 for f in candidates: |
220 if self.restrict: |
234 if self.restrict: |
221 data = self.repo.file(f).read(mf[f]) |
235 data = self.repo.file(f).read(mf[f]) |
224 if util.binary(data): |
238 if util.binary(data): |
225 continue |
239 continue |
226 if expand: |
240 if expand: |
227 if lookup: |
241 if lookup: |
228 fctx = self.repo.filectx(f, fileid=mf[f]).changectx() |
242 fctx = self.repo.filectx(f, fileid=mf[f]).changectx() |
229 data, found = self.substitute(data, f, fctx, subn) |
243 data, found = self.substitute(data, f, fctx, re_kw.subn) |
230 elif self.restrict: |
244 elif self.restrict: |
231 found = self.re_kw.search(data) |
245 found = re_kw.search(data) |
232 else: |
246 else: |
233 data, found = _shrinktext(data, subn) |
247 data, found = _shrinktext(data, re_kw.subn) |
234 if found: |
248 if found: |
235 self.ui.note(msg % f) |
249 self.ui.note(msg % f) |
236 self.repo.wwrite(f, data, ctx.flags(f)) |
250 self.repo.wwrite(f, data, ctx.flags(f)) |
237 if kwcmd: |
251 if kwcmd: |
238 self.repo.dirstate.normal(f) |
252 self.repo.dirstate.normal(f) |
240 self.repo.dirstate.normallookup(f) |
254 self.repo.dirstate.normallookup(f) |
241 |
255 |
242 def shrink(self, fname, text): |
256 def shrink(self, fname, text): |
243 '''Returns text with all keyword substitutions removed.''' |
257 '''Returns text with all keyword substitutions removed.''' |
244 if self.match(fname) and not util.binary(text): |
258 if self.match(fname) and not util.binary(text): |
245 return _shrinktext(text, self.re_kwexp.sub) |
259 return _shrinktext(text, self.rekwexp().sub) |
246 return text |
260 return text |
247 |
261 |
248 def shrinklines(self, fname, lines): |
262 def shrinklines(self, fname, lines): |
249 '''Returns lines with keyword substitutions removed.''' |
263 '''Returns lines with keyword substitutions removed.''' |
250 if self.match(fname): |
264 if self.match(fname): |
251 text = ''.join(lines) |
265 text = ''.join(lines) |
252 if not util.binary(text): |
266 if not util.binary(text): |
253 return _shrinktext(text, self.re_kwexp.sub).splitlines(True) |
267 return _shrinktext(text, self.rekwexp().sub).splitlines(True) |
254 return lines |
268 return lines |
255 |
269 |
256 def wread(self, fname, data): |
270 def wread(self, fname, data): |
257 '''If in restricted mode returns data read from wdir with |
271 '''If in restricted mode returns data read from wdir with |
258 keyword substitutions removed.''' |
272 keyword substitutions removed.''' |