92 |
92 |
93 def utcdate(date): |
93 def utcdate(date): |
94 '''Returns hgdate in cvs-like UTC format.''' |
94 '''Returns hgdate in cvs-like UTC format.''' |
95 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
95 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0])) |
96 |
96 |
97 def kwdemo(ui, repo, **opts): |
97 def getcmd(ui): |
|
98 '''Returns current hg command.''' |
|
99 # commands.parse(ui, sys.argv[1:])[0] breaks "hg diff -r" |
|
100 try: |
|
101 args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {}) |
|
102 except fancyopts.getopt.GetoptError, inst: |
|
103 raise commands.ParseError(None, inst) |
|
104 if args: |
|
105 cmd = args[0] |
|
106 aliases, i = findcmd(ui, cmd) |
|
107 return aliases[0] |
|
108 |
|
109 class kwtemplater(object): |
|
110 ''' |
|
111 Sets up keyword templates, corresponding keyword regex, and |
|
112 provides keyword substitution functions. |
|
113 ''' |
|
114 def __init__(self, ui, repo, path='', node=None): |
|
115 self.ui = ui |
|
116 self.repo = repo |
|
117 self.path = path |
|
118 self.node = node |
|
119 templates = dict(ui.configitems('keywordmaps')) |
|
120 if templates: |
|
121 # parse templates here for less overhead in kwsub matchfunc |
|
122 for k in templates.keys(): |
|
123 templates[k] = templater.parsestring(templates[k], |
|
124 quoted=False) |
|
125 self.templates = templates or deftemplates |
|
126 escaped = [re.escape(k) for k in self.templates.keys()] |
|
127 self.re_kw = re.compile(r'\$(%s)[^$]*?\$' % '|'.join(escaped)) |
|
128 templater.common_filters['utcdate'] = utcdate |
|
129 try: |
|
130 self.t = cmdutil.changeset_templater(ui, repo, False, '', False) |
|
131 except TypeError: |
|
132 # depending on hg rev changeset_templater has extra "brinfo" arg |
|
133 self.t = cmdutil.changeset_templater(ui, repo, |
|
134 False, None, '', False) |
|
135 |
|
136 def kwsub(self, mobj): |
|
137 '''Substitutes keyword using corresponding template.''' |
|
138 kw = mobj.group(1) |
|
139 self.t.use_template(self.templates[kw]) |
|
140 self.ui.pushbuffer() |
|
141 self.t.show(changenode=self.node, root=self.repo.root, file=self.path) |
|
142 keywordsub = templater.firstline(self.ui.popbuffer()) |
|
143 return '$%s: %s $' % (kw, keywordsub) |
|
144 |
|
145 def expand(self, node, data): |
|
146 '''Returns data with expanded keywords.''' |
|
147 if util.binary(data): |
|
148 return data |
|
149 c = context.filectx(self.repo, self.path, fileid=node) |
|
150 self.node = c.node() |
|
151 return self.re_kw.sub(self.kwsub, data) |
|
152 |
|
153 def shrink(self, text): |
|
154 '''Returns text with all keyword substitutions removed.''' |
|
155 if util.binary(text): |
|
156 return text |
|
157 return self.re_kw.sub(r'$\1$', text) |
|
158 |
|
159 def overwrite(self, candidates, mn): |
|
160 '''Overwrites candidates in working dir expanding keywords.''' |
|
161 files = [] |
|
162 m = self.repo.manifest.read(mn) |
|
163 for f in candidates: |
|
164 data = self.repo.wread(f) |
|
165 if not util.binary(data): |
|
166 self.path = f |
|
167 data, kwct = self.re_kw.subn(self.kwsub, data) |
|
168 if kwct: |
|
169 self.ui.debug(_('overwriting %s expanding keywords\n') % f) |
|
170 self.repo.wwrite(f, data, m.flags(f)) |
|
171 files.append(f) |
|
172 if files: |
|
173 self.repo.dirstate.update(files, 'n') |
|
174 |
|
175 class kwfilelog(filelog.filelog): |
|
176 ''' |
|
177 Subclass of filelog to hook into its read, add, cmp methods. |
|
178 Keywords are "stored" unexpanded, and expanded on reading. |
|
179 ''' |
|
180 def __init__(self, opener, path, kwtemplater): |
|
181 super(kwfilelog, self).__init__(opener, path) |
|
182 self.kwtemplater = kwtemplater |
|
183 |
|
184 def read(self, node): |
|
185 '''Substitutes keywords when reading filelog.''' |
|
186 data = super(kwfilelog, self).read(node) |
|
187 return self.kwtemplater.expand(node, data) |
|
188 |
|
189 def add(self, text, meta, tr, link, p1=None, p2=None): |
|
190 '''Removes keyword substitutions when adding to filelog.''' |
|
191 text = self.kwtemplater.shrink(text) |
|
192 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2) |
|
193 |
|
194 def cmp(self, node, text): |
|
195 '''Removes keyword substitutions for comparison.''' |
|
196 text = self.kwtemplater.shrink(text) |
|
197 if self.renamed(node): |
|
198 t2 = super(kwfilelog, self).read(node) |
|
199 return t2 != text |
|
200 return super(kwfilelog, self).cmp(node, text) |
|
201 |
|
202 |
|
203 def demo(ui, repo, **opts): |
98 '''print [keywordmaps] configuration and an expansion example |
204 '''print [keywordmaps] configuration and an expansion example |
99 ''' |
205 ''' |
100 log = 'hg keyword config and expansion example' |
206 log = 'hg keyword config and expansion example' |
101 fn = 'demo.txt' |
207 fn = 'demo.txt' |
102 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
208 tmpdir = tempfile.mkdtemp('', 'kwdemo.') |
133 ui.status(_('\n%s keywords expanded:\n') % kwstatus) |
239 ui.status(_('\n%s keywords expanded:\n') % kwstatus) |
134 ui.write(_repo.wread(fn)) |
240 ui.write(_repo.wread(fn)) |
135 ui.debug(_('\nremoving temporary repo\n')) |
241 ui.debug(_('\nremoving temporary repo\n')) |
136 shutil.rmtree(tmpdir) |
242 shutil.rmtree(tmpdir) |
137 |
243 |
138 def getcmd(ui): |
|
139 '''Returns current hg command.''' |
|
140 # commands.parse(ui, sys.argv[1:])[0] breaks "hg diff -r" |
|
141 try: |
|
142 args = fancyopts.fancyopts(sys.argv[1:], commands.globalopts, {}) |
|
143 except fancyopts.getopt.GetoptError, inst: |
|
144 raise commands.ParseError(None, inst) |
|
145 if args: |
|
146 cmd = args[0] |
|
147 aliases, i = findcmd(ui, cmd) |
|
148 return aliases[0] |
|
149 |
|
150 class kwtemplater(object): |
|
151 ''' |
|
152 Sets up keyword templates, corresponding keyword regex, and |
|
153 provides keyword substitution functions. |
|
154 ''' |
|
155 def __init__(self, ui, repo, path='', node=None): |
|
156 self.ui = ui |
|
157 self.repo = repo |
|
158 self.path = path |
|
159 self.node = node |
|
160 templates = dict(ui.configitems('keywordmaps')) |
|
161 if templates: |
|
162 # parse templates here for less overhead in kwsub matchfunc |
|
163 for k in templates.keys(): |
|
164 templates[k] = templater.parsestring(templates[k], |
|
165 quoted=False) |
|
166 self.templates = templates or deftemplates |
|
167 escaped = [re.escape(k) for k in self.templates.keys()] |
|
168 self.re_kw = re.compile(r'\$(%s)[^$]*?\$' % '|'.join(escaped)) |
|
169 templater.common_filters['utcdate'] = utcdate |
|
170 try: |
|
171 self.t = cmdutil.changeset_templater(ui, repo, False, '', False) |
|
172 except TypeError: |
|
173 # depending on hg rev changeset_templater has extra "brinfo" arg |
|
174 self.t = cmdutil.changeset_templater(ui, repo, |
|
175 False, None, '', False) |
|
176 |
|
177 def kwsub(self, mobj): |
|
178 '''Substitutes keyword using corresponding template.''' |
|
179 kw = mobj.group(1) |
|
180 self.t.use_template(self.templates[kw]) |
|
181 self.ui.pushbuffer() |
|
182 self.t.show(changenode=self.node, root=self.repo.root, file=self.path) |
|
183 keywordsub = templater.firstline(self.ui.popbuffer()) |
|
184 return '$%s: %s $' % (kw, keywordsub) |
|
185 |
|
186 def expand(self, node, data): |
|
187 '''Returns data with expanded keywords.''' |
|
188 if util.binary(data): |
|
189 return data |
|
190 c = context.filectx(self.repo, self.path, fileid=node) |
|
191 self.node = c.node() |
|
192 return self.re_kw.sub(self.kwsub, data) |
|
193 |
|
194 def shrink(self, text): |
|
195 '''Returns text with all keyword substitutions removed.''' |
|
196 if util.binary(text): |
|
197 return text |
|
198 return self.re_kw.sub(r'$\1$', text) |
|
199 |
|
200 def overwrite(self, candidates, mn): |
|
201 '''Overwrites candidates in working dir expanding keywords.''' |
|
202 files = [] |
|
203 m = self.repo.manifest.read(mn) |
|
204 for f in candidates: |
|
205 data = self.repo.wread(f) |
|
206 if not util.binary(data): |
|
207 self.path = f |
|
208 data, kwct = self.re_kw.subn(self.kwsub, data) |
|
209 if kwct: |
|
210 self.ui.debug(_('overwriting %s expanding keywords\n') % f) |
|
211 self.repo.wwrite(f, data, m.flags(f)) |
|
212 files.append(f) |
|
213 if files: |
|
214 self.repo.dirstate.update(files, 'n') |
|
215 |
|
216 class kwfilelog(filelog.filelog): |
|
217 ''' |
|
218 Subclass of filelog to hook into its read, add, cmp methods. |
|
219 Keywords are "stored" unexpanded, and expanded on reading. |
|
220 ''' |
|
221 def __init__(self, opener, path, kwtemplater): |
|
222 super(kwfilelog, self).__init__(opener, path) |
|
223 self.kwtemplater = kwtemplater |
|
224 |
|
225 def read(self, node): |
|
226 '''Substitutes keywords when reading filelog.''' |
|
227 data = super(kwfilelog, self).read(node) |
|
228 return self.kwtemplater.expand(node, data) |
|
229 |
|
230 def add(self, text, meta, tr, link, p1=None, p2=None): |
|
231 '''Removes keyword substitutions when adding to filelog.''' |
|
232 text = self.kwtemplater.shrink(text) |
|
233 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2) |
|
234 |
|
235 def cmp(self, node, text): |
|
236 '''Removes keyword substitutions for comparison.''' |
|
237 text = self.kwtemplater.shrink(text) |
|
238 if self.renamed(node): |
|
239 t2 = super(kwfilelog, self).read(node) |
|
240 return t2 != text |
|
241 return super(kwfilelog, self).cmp(node, text) |
|
242 |
|
243 |
|
244 def reposetup(ui, repo): |
244 def reposetup(ui, repo): |
245 '''Sets up repo as kwrepo for keyword substitution. |
245 '''Sets up repo as kwrepo for keyword substitution. |
246 Overrides file method to return kwfilelog instead of filelog |
246 Overrides file method to return kwfilelog instead of filelog |
247 if file matches user configuration. |
247 if file matches user configuration. |
248 Wraps commit to overwrite configured files with updated |
248 Wraps commit to overwrite configured files with updated |