83 cause rejects if the patch context contains an active keyword. |
83 cause rejects if the patch context contains an active keyword. |
84 In that case run "hg kwshrink", and then reimport. |
84 In that case run "hg kwshrink", and then reimport. |
85 Or, better, use bundle/unbundle to share changes. |
85 Or, better, use bundle/unbundle to share changes. |
86 ''' |
86 ''' |
87 |
87 |
88 from mercurial import commands, cmdutil, context, filelog |
88 from mercurial import commands, cmdutil, context |
89 from mercurial import localrepo, revlog, templater, util |
89 from mercurial import localrepo, revlog, templater, util |
90 from mercurial.node import * |
90 from mercurial.node import * |
91 from mercurial.i18n import gettext as _ |
91 from mercurial.i18n import gettext as _ |
92 import os.path, re, shutil, tempfile, time |
92 import mimetypes, os.path, re, shutil, tempfile, time |
93 |
93 |
94 try: |
94 try: |
95 # avoid spurious rejects if patchfile is available |
95 # avoid spurious rejects if patchfile is available |
96 from mercurial.patch import patchfile |
96 from mercurial.patch import patchfile |
97 _patchfile_init = patchfile.__init__ |
97 _patchfile_init = patchfile.__init__ |
106 template_filters = templatefilters.filters |
106 template_filters = templatefilters.filters |
107 template_firstline = templatefilters.firstline |
107 template_firstline = templatefilters.firstline |
108 except ImportError: |
108 except ImportError: |
109 template_filters = templater.common_filters |
109 template_filters = templater.common_filters |
110 template_firstline = templater.firstline |
110 template_firstline = templater.firstline |
|
111 |
|
112 try: |
|
113 # webcommands module introduced in 08887121a652 |
|
114 from mercurial.hgweb import webcommands |
|
115 _webcommands = True |
|
116 kwweb_func = webcommands.rawfile |
|
117 except ImportError: |
|
118 from mercurial.hgweb import hgweb_mod |
|
119 _webcommands = False |
111 |
120 |
112 def _normal(repo, files): |
121 def _normal(repo, files): |
113 '''Backwards compatible repo.dirstate.normal/update.''' |
122 '''Backwards compatible repo.dirstate.normal/update.''' |
114 # 6fd953d5faea introduced dirstate.normal() |
123 # 6fd953d5faea introduced dirstate.normal() |
115 try: |
124 try: |
188 c = context.filectx(self.repo, path, fileid=fnode, filelog=fl) |
197 c = context.filectx(self.repo, path, fileid=fnode, filelog=fl) |
189 node = c.node() |
198 node = c.node() |
190 except revlog.LookupError: |
199 except revlog.LookupError: |
191 # eg: convert |
200 # eg: convert |
192 return subfunc == self.re_kw.sub and data or (data, None) |
201 return subfunc == self.re_kw.sub and data or (data, None) |
193 elif subfunc == self.re_kw.sub: |
|
194 # hg kwcat using kwfilelog.read |
|
195 c = context.filectx(self.repo, path, fileid=node) |
|
196 node = c.node() |
|
197 |
202 |
198 def kwsub(mobj): |
203 def kwsub(mobj): |
199 '''Substitutes keyword using corresponding template.''' |
204 '''Substitutes keyword using corresponding template.''' |
200 kw = mobj.group(1) |
205 kw = mobj.group(1) |
201 self.ct.use_template(self.templates[kw]) |
206 self.ct.use_template(self.templates[kw]) |
227 '''Returns text with all keyword substitutions removed.''' |
232 '''Returns text with all keyword substitutions removed.''' |
228 if util.binary(data): |
233 if util.binary(data): |
229 return data |
234 return data |
230 return self.re_kw.sub(r'$\1$', data) |
235 return self.re_kw.sub(r'$\1$', data) |
231 |
236 |
232 class kwfilelog(filelog.filelog): |
|
233 ''' |
|
234 Subclass of filelog to hook into its read method for kwcat. |
|
235 ''' |
|
236 def __init__(self, opener, path, kwt): |
|
237 super(kwfilelog, self).__init__(opener, path) |
|
238 self._kwt = kwt |
|
239 self._path = path |
|
240 |
|
241 def read(self, node): |
|
242 '''Expands keywords when reading filelog.''' |
|
243 data = super(kwfilelog, self).read(node) |
|
244 return self._kwt.expand(self._path, data, node) |
|
245 |
237 |
246 |
238 |
247 def _status(ui, repo, *pats, **opts): |
239 def _status(ui, repo, *pats, **opts): |
248 '''Bails out if [keyword] configuration is not active. |
240 '''Bails out if [keyword] configuration is not active. |
249 Returns status of working directory.''' |
241 Returns status of working directory.''' |
305 |
297 |
306 %s basename of file being printed |
298 %s basename of file being printed |
307 %d dirname of file being printed, or '.' if in repo root |
299 %d dirname of file being printed, or '.' if in repo root |
308 %p root-relative path name of file being printed |
300 %p root-relative path name of file being printed |
309 ''' |
301 ''' |
|
302 ctx = repo.changectx(opts['rev']) |
310 try: |
303 try: |
311 repo.file = repo._kwfile |
304 repo._kwt.ctx = ctx |
|
305 kw = True |
312 except AttributeError: |
306 except AttributeError: |
313 pass |
307 kw = False |
314 commands.cat(ui, repo, file1, *pats, **opts) |
308 err = 1 |
|
309 for src, abs, rel, exact in cmdutil.walk(repo, (file1,) + pats, opts, |
|
310 ctx.node()): |
|
311 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs) |
|
312 data = ctx.filectx(abs).data() |
|
313 if kw and repo._kwt.matcher(abs): |
|
314 data = repo._kwt.expand(abs, data, None) |
|
315 fp.write(data) |
|
316 err = 0 |
|
317 return err |
315 |
318 |
316 def demo(ui, repo, *args, **opts): |
319 def demo(ui, repo, *args, **opts): |
317 '''print [keywordmaps] configuration and an expansion example |
320 '''print [keywordmaps] configuration and an expansion example |
318 |
321 |
319 Show current, custom, or default keyword template maps |
322 Show current, custom, or default keyword template maps |
452 exc.append(pat) |
455 exc.append(pat) |
453 if not inc: |
456 if not inc: |
454 return |
457 return |
455 |
458 |
456 class kwrepo(repo.__class__): |
459 class kwrepo(repo.__class__): |
457 def _kwfile(self, f): |
|
458 '''Returns filelog expanding keywords on read (for kwcat).''' |
|
459 if f[0] == '/': |
|
460 f = f[1:] |
|
461 if self._kwt.matcher(f): |
|
462 return kwfilelog(self.sopener, f, self._kwt) |
|
463 return filelog.filelog(self.sopener, f) |
|
464 |
|
465 def _wreadkwct(self, filename, expand, ctx, node): |
460 def _wreadkwct(self, filename, expand, ctx, node): |
466 '''Reads filename and returns tuple of data with keywords |
461 '''Reads filename and returns tuple of data with keywords |
467 expanded/shrunk and count of keywords (for _overwrite).''' |
462 expanded/shrunk and count of keywords (for _overwrite).''' |
468 data = super(kwrepo, self).wread(filename) |
463 data = super(kwrepo, self).wread(filename) |
469 return self._kwt.process(filename, data, expand, ctx, node) |
464 return self._kwt.process(filename, data, expand, ctx, node) |
576 kwshrunk = kwt.shrink(''.join(self.lines)) |
571 kwshrunk = kwt.shrink(''.join(self.lines)) |
577 self.lines = kwshrunk.splitlines(True) |
572 self.lines = kwshrunk.splitlines(True) |
578 |
573 |
579 patchfile.__init__ = kwpatchfile_init |
574 patchfile.__init__ = kwpatchfile_init |
580 |
575 |
|
576 if _webcommands: |
|
577 def kwweb_rawfile(web, req, tmpl): |
|
578 '''Monkeypatch webcommands.rawfile so it expands keywords.''' |
|
579 path = web.cleanpath(req.form.get('file', [''])[0]) |
|
580 if not path: |
|
581 content = web.manifest(tmpl, web.changectx(req), path) |
|
582 req.respond(webcommands.HTTP_OK, web.ctype) |
|
583 return content |
|
584 try: |
|
585 fctx = web.filectx(req) |
|
586 except revlog.LookupError: |
|
587 content = web.manifest(tmpl, web.changectx(req), path) |
|
588 req.respond(webcommands.HTTP_OK, web.ctype) |
|
589 return content |
|
590 path = fctx.path() |
|
591 text = fctx.data() |
|
592 if kwt.matcher(path): |
|
593 text = kwt.expand(path, text, fctx.node()) |
|
594 mt = mimetypes.guess_type(path)[0] |
|
595 if mt is None or util.binary(text): |
|
596 mt = mt or 'application/octet-stream' |
|
597 req.respond(webcommands.HTTP_OK, mt, path, len(text)) |
|
598 return [text] |
|
599 |
|
600 webcommands.rawfile = kwweb_rawfile |
|
601 |
|
602 else: |
|
603 def kwweb_filerevision(self, fctx): |
|
604 '''Monkeypatch hgweb_mod.hgweb.filerevision so keywords are |
|
605 expanded in raw file output.''' |
|
606 f = fctx.path() |
|
607 text = fctx.data() |
|
608 fl = fctx.filelog() |
|
609 n = fctx.filenode() |
|
610 parity = hgweb_mod.paritygen(self.stripecount) |
|
611 mt = mimetypes.guess_type(f)[0] |
|
612 rawtext = text |
|
613 if kwt.matcher(f): |
|
614 rawtext = kwt.expand(f, text, fctx.node()) |
|
615 if util.binary(text): |
|
616 mt = mt or 'application/octet-stream' |
|
617 text = "(binary:%s)" % mt |
|
618 mt = mt or 'text/plain' |
|
619 def lines(): |
|
620 for l, t in enumerate(text.splitlines(1)): |
|
621 yield {"line": t, |
|
622 "linenumber": "% 6d" % (l + 1), |
|
623 "parity": parity.next()} |
|
624 yield self.t("filerevision", |
|
625 file=f, |
|
626 path=hgweb_mod._up(f), |
|
627 text=lines(), |
|
628 raw=rawtext, |
|
629 mimetype=mt, |
|
630 rev=fctx.rev(), |
|
631 node=hex(fctx.node()), |
|
632 author=fctx.user(), |
|
633 date=fctx.date(), |
|
634 desc=fctx.description(), |
|
635 parent=self.siblings(fctx.parents()), |
|
636 child=self.siblings(fctx.children()), |
|
637 rename=self.renamelink(fl, n), |
|
638 permissions=fctx.manifest().flags(f)) |
|
639 |
|
640 hgweb_mod.hgweb.filerevision = kwweb_filerevision |
|
641 |
581 repo.__class__ = kwrepo |
642 repo.__class__ = kwrepo |
582 |
643 |
583 |
644 |
584 cmdtable = { |
645 cmdtable = { |
585 'kwcat': |
646 'kwcat': |