##// END OF EJS Templates
keyword: improve help for kwfiles...
Christian Ebert -
r8957:7672d8e1 default
parent child Browse files
Show More
@@ -1,540 +1,543 b''
1 # keyword.py - $Keyword$ expansion for Mercurial
1 # keyword.py - $Keyword$ expansion for Mercurial
2 #
2 #
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2, incorporated herein by reference.
6 # GNU General Public License version 2, incorporated herein by reference.
7 #
7 #
8 # $Id$
8 # $Id$
9 #
9 #
10 # Keyword expansion hack against the grain of a DSCM
10 # Keyword expansion hack against the grain of a DSCM
11 #
11 #
12 # There are many good reasons why this is not needed in a distributed
12 # There are many good reasons why this is not needed in a distributed
13 # SCM, still it may be useful in very small projects based on single
13 # SCM, still it may be useful in very small projects based on single
14 # files (like LaTeX packages), that are mostly addressed to an
14 # files (like LaTeX packages), that are mostly addressed to an
15 # audience not running a version control system.
15 # audience not running a version control system.
16 #
16 #
17 # For in-depth discussion refer to
17 # For in-depth discussion refer to
18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
18 # <http://mercurial.selenic.com/wiki/KeywordPlan>.
19 #
19 #
20 # Keyword expansion is based on Mercurial's changeset template mappings.
20 # Keyword expansion is based on Mercurial's changeset template mappings.
21 #
21 #
22 # Binary files are not touched.
22 # Binary files are not touched.
23 #
23 #
24 # Files to act upon/ignore are specified in the [keyword] section.
24 # Files to act upon/ignore are specified in the [keyword] section.
25 # Customized keyword template mappings in the [keywordmaps] section.
25 # Customized keyword template mappings in the [keywordmaps] section.
26 #
26 #
27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
27 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
28
28
29 '''expand keywords in tracked files
29 '''expand keywords in tracked files
30
30
31 This extension expands RCS/CVS-like or self-customized $Keywords$ in
31 This extension expands RCS/CVS-like or self-customized $Keywords$ in
32 tracked text files selected by your configuration.
32 tracked text files selected by your configuration.
33
33
34 Keywords are only expanded in local repositories and not stored in the
34 Keywords are only expanded in local repositories and not stored in the
35 change history. The mechanism can be regarded as a convenience for the
35 change history. The mechanism can be regarded as a convenience for the
36 current user or for archive distribution.
36 current user or for archive distribution.
37
37
38 Configuration is done in the [keyword] and [keywordmaps] sections of
38 Configuration is done in the [keyword] and [keywordmaps] sections of
39 hgrc files.
39 hgrc files.
40
40
41 Example:
41 Example:
42
42
43 [keyword]
43 [keyword]
44 # expand keywords in every python file except those matching "x*"
44 # expand keywords in every python file except those matching "x*"
45 **.py =
45 **.py =
46 x* = ignore
46 x* = ignore
47
47
48 Note: the more specific you are in your filename patterns
48 Note: the more specific you are in your filename patterns
49 the less you lose speed in huge repositories.
49 the less you lose speed in huge repositories.
50
50
51 For [keywordmaps] template mapping and expansion demonstration and
51 For [keywordmaps] template mapping and expansion demonstration and
52 control run "hg kwdemo".
52 control run "hg kwdemo".
53
53
54 An additional date template filter {date|utcdate} is provided.
54 An additional date template filter {date|utcdate} is provided.
55
55
56 The default template mappings (view with "hg kwdemo -d") can be
56 The default template mappings (view with "hg kwdemo -d") can be
57 replaced with customized keywords and templates. Again, run "hg
57 replaced with customized keywords and templates. Again, run "hg
58 kwdemo" to control the results of your config changes.
58 kwdemo" to control the results of your config changes.
59
59
60 Before changing/disabling active keywords, run "hg kwshrink" to avoid
60 Before changing/disabling active keywords, run "hg kwshrink" to avoid
61 the risk of inadvertently storing expanded keywords in the change
61 the risk of inadvertently storing expanded keywords in the change
62 history.
62 history.
63
63
64 To force expansion after enabling it, or a configuration change, run
64 To force expansion after enabling it, or a configuration change, run
65 "hg kwexpand".
65 "hg kwexpand".
66
66
67 Also, when committing with the record extension or using mq's qrecord,
67 Also, when committing with the record extension or using mq's qrecord,
68 be aware that keywords cannot be updated. Again, run "hg kwexpand" on
68 be aware that keywords cannot be updated. Again, run "hg kwexpand" on
69 the files in question to update keyword expansions after all changes
69 the files in question to update keyword expansions after all changes
70 have been checked in.
70 have been checked in.
71
71
72 Expansions spanning more than one line and incremental expansions,
72 Expansions spanning more than one line and incremental expansions,
73 like CVS' $Log$, are not supported. A keyword template map
73 like CVS' $Log$, are not supported. A keyword template map
74 "Log = {desc}" expands to the first line of the changeset description.
74 "Log = {desc}" expands to the first line of the changeset description.
75 '''
75 '''
76
76
77 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
77 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
78 from mercurial import patch, localrepo, templater, templatefilters, util, match
78 from mercurial import patch, localrepo, templater, templatefilters, util, match
79 from mercurial.hgweb import webcommands
79 from mercurial.hgweb import webcommands
80 from mercurial.lock import release
80 from mercurial.lock import release
81 from mercurial.node import nullid, hex
81 from mercurial.node import nullid, hex
82 from mercurial.i18n import _
82 from mercurial.i18n import _
83 import re, shutil, tempfile, time
83 import re, shutil, tempfile, time
84
84
85 commands.optionalrepo += ' kwdemo'
85 commands.optionalrepo += ' kwdemo'
86
86
87 # hg commands that do not act on keywords
87 # hg commands that do not act on keywords
88 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
88 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
89 ' log outgoing push rename rollback tip verify'
89 ' log outgoing push rename rollback tip verify'
90 ' convert email glog')
90 ' convert email glog')
91
91
92 # hg commands that trigger expansion only when writing to working dir,
92 # hg commands that trigger expansion only when writing to working dir,
93 # not when reading filelog, and unexpand when reading from working dir
93 # not when reading filelog, and unexpand when reading from working dir
94 restricted = 'merge record resolve qfold qimport qnew qpush qrefresh qrecord'
94 restricted = 'merge record resolve qfold qimport qnew qpush qrefresh qrecord'
95
95
96 def utcdate(date):
96 def utcdate(date):
97 '''Returns hgdate in cvs-like UTC format.'''
97 '''Returns hgdate in cvs-like UTC format.'''
98 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
98 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
99
99
100 # make keyword tools accessible
100 # make keyword tools accessible
101 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
101 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
102
102
103
103
104 class kwtemplater(object):
104 class kwtemplater(object):
105 '''
105 '''
106 Sets up keyword templates, corresponding keyword regex, and
106 Sets up keyword templates, corresponding keyword regex, and
107 provides keyword substitution functions.
107 provides keyword substitution functions.
108 '''
108 '''
109 templates = {
109 templates = {
110 'Revision': '{node|short}',
110 'Revision': '{node|short}',
111 'Author': '{author|user}',
111 'Author': '{author|user}',
112 'Date': '{date|utcdate}',
112 'Date': '{date|utcdate}',
113 'RCSFile': '{file|basename},v',
113 'RCSFile': '{file|basename},v',
114 'Source': '{root}/{file},v',
114 'Source': '{root}/{file},v',
115 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
115 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
116 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
116 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
117 }
117 }
118
118
119 def __init__(self, ui, repo):
119 def __init__(self, ui, repo):
120 self.ui = ui
120 self.ui = ui
121 self.repo = repo
121 self.repo = repo
122 self.match = match.match(repo.root, '', [],
122 self.match = match.match(repo.root, '', [],
123 kwtools['inc'], kwtools['exc'])
123 kwtools['inc'], kwtools['exc'])
124 self.restrict = kwtools['hgcmd'] in restricted.split()
124 self.restrict = kwtools['hgcmd'] in restricted.split()
125
125
126 kwmaps = self.ui.configitems('keywordmaps')
126 kwmaps = self.ui.configitems('keywordmaps')
127 if kwmaps: # override default templates
127 if kwmaps: # override default templates
128 kwmaps = [(k, templater.parsestring(v, False))
128 kwmaps = [(k, templater.parsestring(v, False))
129 for (k, v) in kwmaps]
129 for (k, v) in kwmaps]
130 self.templates = dict(kwmaps)
130 self.templates = dict(kwmaps)
131 escaped = map(re.escape, self.templates.keys())
131 escaped = map(re.escape, self.templates.keys())
132 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
132 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
133 self.re_kw = re.compile(kwpat)
133 self.re_kw = re.compile(kwpat)
134
134
135 templatefilters.filters['utcdate'] = utcdate
135 templatefilters.filters['utcdate'] = utcdate
136 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
136 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
137 False, None, '', False)
137 False, None, '', False)
138
138
139 def substitute(self, data, path, ctx, subfunc):
139 def substitute(self, data, path, ctx, subfunc):
140 '''Replaces keywords in data with expanded template.'''
140 '''Replaces keywords in data with expanded template.'''
141 def kwsub(mobj):
141 def kwsub(mobj):
142 kw = mobj.group(1)
142 kw = mobj.group(1)
143 self.ct.use_template(self.templates[kw])
143 self.ct.use_template(self.templates[kw])
144 self.ui.pushbuffer()
144 self.ui.pushbuffer()
145 self.ct.show(ctx, root=self.repo.root, file=path)
145 self.ct.show(ctx, root=self.repo.root, file=path)
146 ekw = templatefilters.firstline(self.ui.popbuffer())
146 ekw = templatefilters.firstline(self.ui.popbuffer())
147 return '$%s: %s $' % (kw, ekw)
147 return '$%s: %s $' % (kw, ekw)
148 return subfunc(kwsub, data)
148 return subfunc(kwsub, data)
149
149
150 def expand(self, path, node, data):
150 def expand(self, path, node, data):
151 '''Returns data with keywords expanded.'''
151 '''Returns data with keywords expanded.'''
152 if not self.restrict and self.match(path) and not util.binary(data):
152 if not self.restrict and self.match(path) and not util.binary(data):
153 ctx = self.repo.filectx(path, fileid=node).changectx()
153 ctx = self.repo.filectx(path, fileid=node).changectx()
154 return self.substitute(data, path, ctx, self.re_kw.sub)
154 return self.substitute(data, path, ctx, self.re_kw.sub)
155 return data
155 return data
156
156
157 def iskwfile(self, path, flagfunc):
157 def iskwfile(self, path, flagfunc):
158 '''Returns true if path matches [keyword] pattern
158 '''Returns true if path matches [keyword] pattern
159 and is not a symbolic link.
159 and is not a symbolic link.
160 Caveat: localrepository._link fails on Windows.'''
160 Caveat: localrepository._link fails on Windows.'''
161 return self.match(path) and not 'l' in flagfunc(path)
161 return self.match(path) and not 'l' in flagfunc(path)
162
162
163 def overwrite(self, node, expand, files):
163 def overwrite(self, node, expand, files):
164 '''Overwrites selected files expanding/shrinking keywords.'''
164 '''Overwrites selected files expanding/shrinking keywords.'''
165 ctx = self.repo[node]
165 ctx = self.repo[node]
166 mf = ctx.manifest()
166 mf = ctx.manifest()
167 if node is not None: # commit
167 if node is not None: # commit
168 files = [f for f in ctx.files() if f in mf]
168 files = [f for f in ctx.files() if f in mf]
169 notify = self.ui.debug
169 notify = self.ui.debug
170 else: # kwexpand/kwshrink
170 else: # kwexpand/kwshrink
171 notify = self.ui.note
171 notify = self.ui.note
172 candidates = [f for f in files if self.iskwfile(f, ctx.flags)]
172 candidates = [f for f in files if self.iskwfile(f, ctx.flags)]
173 if candidates:
173 if candidates:
174 self.restrict = True # do not expand when reading
174 self.restrict = True # do not expand when reading
175 msg = (expand and _('overwriting %s expanding keywords\n')
175 msg = (expand and _('overwriting %s expanding keywords\n')
176 or _('overwriting %s shrinking keywords\n'))
176 or _('overwriting %s shrinking keywords\n'))
177 for f in candidates:
177 for f in candidates:
178 fp = self.repo.file(f)
178 fp = self.repo.file(f)
179 data = fp.read(mf[f])
179 data = fp.read(mf[f])
180 if util.binary(data):
180 if util.binary(data):
181 continue
181 continue
182 if expand:
182 if expand:
183 if node is None:
183 if node is None:
184 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
184 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
185 data, found = self.substitute(data, f, ctx,
185 data, found = self.substitute(data, f, ctx,
186 self.re_kw.subn)
186 self.re_kw.subn)
187 else:
187 else:
188 found = self.re_kw.search(data)
188 found = self.re_kw.search(data)
189 if found:
189 if found:
190 notify(msg % f)
190 notify(msg % f)
191 self.repo.wwrite(f, data, mf.flags(f))
191 self.repo.wwrite(f, data, mf.flags(f))
192 self.repo.dirstate.normal(f)
192 self.repo.dirstate.normal(f)
193 self.restrict = False
193 self.restrict = False
194
194
195 def shrinktext(self, text):
195 def shrinktext(self, text):
196 '''Unconditionally removes all keyword substitutions from text.'''
196 '''Unconditionally removes all keyword substitutions from text.'''
197 return self.re_kw.sub(r'$\1$', text)
197 return self.re_kw.sub(r'$\1$', text)
198
198
199 def shrink(self, fname, text):
199 def shrink(self, fname, text):
200 '''Returns text with all keyword substitutions removed.'''
200 '''Returns text with all keyword substitutions removed.'''
201 if self.match(fname) and not util.binary(text):
201 if self.match(fname) and not util.binary(text):
202 return self.shrinktext(text)
202 return self.shrinktext(text)
203 return text
203 return text
204
204
205 def shrinklines(self, fname, lines):
205 def shrinklines(self, fname, lines):
206 '''Returns lines with keyword substitutions removed.'''
206 '''Returns lines with keyword substitutions removed.'''
207 if self.match(fname):
207 if self.match(fname):
208 text = ''.join(lines)
208 text = ''.join(lines)
209 if not util.binary(text):
209 if not util.binary(text):
210 return self.shrinktext(text).splitlines(True)
210 return self.shrinktext(text).splitlines(True)
211 return lines
211 return lines
212
212
213 def wread(self, fname, data):
213 def wread(self, fname, data):
214 '''If in restricted mode returns data read from wdir with
214 '''If in restricted mode returns data read from wdir with
215 keyword substitutions removed.'''
215 keyword substitutions removed.'''
216 return self.restrict and self.shrink(fname, data) or data
216 return self.restrict and self.shrink(fname, data) or data
217
217
218 class kwfilelog(filelog.filelog):
218 class kwfilelog(filelog.filelog):
219 '''
219 '''
220 Subclass of filelog to hook into its read, add, cmp methods.
220 Subclass of filelog to hook into its read, add, cmp methods.
221 Keywords are "stored" unexpanded, and processed on reading.
221 Keywords are "stored" unexpanded, and processed on reading.
222 '''
222 '''
223 def __init__(self, opener, kwt, path):
223 def __init__(self, opener, kwt, path):
224 super(kwfilelog, self).__init__(opener, path)
224 super(kwfilelog, self).__init__(opener, path)
225 self.kwt = kwt
225 self.kwt = kwt
226 self.path = path
226 self.path = path
227
227
228 def read(self, node):
228 def read(self, node):
229 '''Expands keywords when reading filelog.'''
229 '''Expands keywords when reading filelog.'''
230 data = super(kwfilelog, self).read(node)
230 data = super(kwfilelog, self).read(node)
231 return self.kwt.expand(self.path, node, data)
231 return self.kwt.expand(self.path, node, data)
232
232
233 def add(self, text, meta, tr, link, p1=None, p2=None):
233 def add(self, text, meta, tr, link, p1=None, p2=None):
234 '''Removes keyword substitutions when adding to filelog.'''
234 '''Removes keyword substitutions when adding to filelog.'''
235 text = self.kwt.shrink(self.path, text)
235 text = self.kwt.shrink(self.path, text)
236 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
236 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
237
237
238 def cmp(self, node, text):
238 def cmp(self, node, text):
239 '''Removes keyword substitutions for comparison.'''
239 '''Removes keyword substitutions for comparison.'''
240 text = self.kwt.shrink(self.path, text)
240 text = self.kwt.shrink(self.path, text)
241 if self.renamed(node):
241 if self.renamed(node):
242 t2 = super(kwfilelog, self).read(node)
242 t2 = super(kwfilelog, self).read(node)
243 return t2 != text
243 return t2 != text
244 return revlog.revlog.cmp(self, node, text)
244 return revlog.revlog.cmp(self, node, text)
245
245
246 def _status(ui, repo, kwt, unknown, *pats, **opts):
246 def _status(ui, repo, kwt, unknown, *pats, **opts):
247 '''Bails out if [keyword] configuration is not active.
247 '''Bails out if [keyword] configuration is not active.
248 Returns status of working directory.'''
248 Returns status of working directory.'''
249 if kwt:
249 if kwt:
250 match = cmdutil.match(repo, pats, opts)
250 match = cmdutil.match(repo, pats, opts)
251 return repo.status(match=match, unknown=unknown, clean=True)
251 return repo.status(match=match, unknown=unknown, clean=True)
252 if ui.configitems('keyword'):
252 if ui.configitems('keyword'):
253 raise util.Abort(_('[keyword] patterns cannot match'))
253 raise util.Abort(_('[keyword] patterns cannot match'))
254 raise util.Abort(_('no [keyword] patterns configured'))
254 raise util.Abort(_('no [keyword] patterns configured'))
255
255
256 def _kwfwrite(ui, repo, expand, *pats, **opts):
256 def _kwfwrite(ui, repo, expand, *pats, **opts):
257 '''Selects files and passes them to kwtemplater.overwrite.'''
257 '''Selects files and passes them to kwtemplater.overwrite.'''
258 if repo.dirstate.parents()[1] != nullid:
258 if repo.dirstate.parents()[1] != nullid:
259 raise util.Abort(_('outstanding uncommitted merge'))
259 raise util.Abort(_('outstanding uncommitted merge'))
260 kwt = kwtools['templater']
260 kwt = kwtools['templater']
261 status = _status(ui, repo, kwt, False, *pats, **opts)
261 status = _status(ui, repo, kwt, False, *pats, **opts)
262 modified, added, removed, deleted = status[:4]
262 modified, added, removed, deleted = status[:4]
263 if modified or added or removed or deleted:
263 if modified or added or removed or deleted:
264 raise util.Abort(_('outstanding uncommitted changes'))
264 raise util.Abort(_('outstanding uncommitted changes'))
265 wlock = lock = None
265 wlock = lock = None
266 try:
266 try:
267 wlock = repo.wlock()
267 wlock = repo.wlock()
268 lock = repo.lock()
268 lock = repo.lock()
269 kwt.overwrite(None, expand, status[6])
269 kwt.overwrite(None, expand, status[6])
270 finally:
270 finally:
271 release(lock, wlock)
271 release(lock, wlock)
272
272
273 def demo(ui, repo, *args, **opts):
273 def demo(ui, repo, *args, **opts):
274 '''print [keywordmaps] configuration and an expansion example
274 '''print [keywordmaps] configuration and an expansion example
275
275
276 Show current, custom, or default keyword template maps and their
276 Show current, custom, or default keyword template maps and their
277 expansions.
277 expansions.
278
278
279 Extend current configuration by specifying maps as arguments and
279 Extend current configuration by specifying maps as arguments and
280 optionally by reading from an additional hgrc file.
280 optionally by reading from an additional hgrc file.
281
281
282 Override current keyword template maps with "default" option.
282 Override current keyword template maps with "default" option.
283 '''
283 '''
284 def demoitems(section, items):
284 def demoitems(section, items):
285 ui.write('[%s]\n' % section)
285 ui.write('[%s]\n' % section)
286 for k, v in items:
286 for k, v in items:
287 ui.write('%s = %s\n' % (k, v))
287 ui.write('%s = %s\n' % (k, v))
288
288
289 msg = 'hg keyword config and expansion example'
289 msg = 'hg keyword config and expansion example'
290 kwstatus = 'current'
290 kwstatus = 'current'
291 fn = 'demo.txt'
291 fn = 'demo.txt'
292 branchname = 'demobranch'
292 branchname = 'demobranch'
293 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
293 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
294 ui.note(_('creating temporary repository at %s\n') % tmpdir)
294 ui.note(_('creating temporary repository at %s\n') % tmpdir)
295 repo = localrepo.localrepository(ui, tmpdir, True)
295 repo = localrepo.localrepository(ui, tmpdir, True)
296 ui.setconfig('keyword', fn, '')
296 ui.setconfig('keyword', fn, '')
297 if args or opts.get('rcfile'):
297 if args or opts.get('rcfile'):
298 kwstatus = 'custom'
298 kwstatus = 'custom'
299 if opts.get('rcfile'):
299 if opts.get('rcfile'):
300 ui.readconfig(opts.get('rcfile'))
300 ui.readconfig(opts.get('rcfile'))
301 if opts.get('default'):
301 if opts.get('default'):
302 kwstatus = 'default'
302 kwstatus = 'default'
303 kwmaps = kwtemplater.templates
303 kwmaps = kwtemplater.templates
304 if ui.configitems('keywordmaps'):
304 if ui.configitems('keywordmaps'):
305 # override maps from optional rcfile
305 # override maps from optional rcfile
306 for k, v in kwmaps.iteritems():
306 for k, v in kwmaps.iteritems():
307 ui.setconfig('keywordmaps', k, v)
307 ui.setconfig('keywordmaps', k, v)
308 elif args:
308 elif args:
309 # simulate hgrc parsing
309 # simulate hgrc parsing
310 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
310 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
311 fp = repo.opener('hgrc', 'w')
311 fp = repo.opener('hgrc', 'w')
312 fp.writelines(rcmaps)
312 fp.writelines(rcmaps)
313 fp.close()
313 fp.close()
314 ui.readconfig(repo.join('hgrc'))
314 ui.readconfig(repo.join('hgrc'))
315 if not opts.get('default'):
315 if not opts.get('default'):
316 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
316 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
317 uisetup(ui)
317 uisetup(ui)
318 reposetup(ui, repo)
318 reposetup(ui, repo)
319 for k, v in ui.configitems('extensions'):
319 for k, v in ui.configitems('extensions'):
320 if k.endswith('keyword'):
320 if k.endswith('keyword'):
321 extension = '%s = %s' % (k, v)
321 extension = '%s = %s' % (k, v)
322 break
322 break
323 ui.status(_('\n\tconfig using %s keyword template maps\n') % kwstatus)
323 ui.status(_('\n\tconfig using %s keyword template maps\n') % kwstatus)
324 ui.write('[extensions]\n%s\n' % extension)
324 ui.write('[extensions]\n%s\n' % extension)
325 demoitems('keyword', ui.configitems('keyword'))
325 demoitems('keyword', ui.configitems('keyword'))
326 demoitems('keywordmaps', kwmaps.iteritems())
326 demoitems('keywordmaps', kwmaps.iteritems())
327 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
327 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
328 repo.wopener(fn, 'w').write(keywords)
328 repo.wopener(fn, 'w').write(keywords)
329 repo.add([fn])
329 repo.add([fn])
330 path = repo.wjoin(fn)
330 path = repo.wjoin(fn)
331 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
331 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
332 ui.note(keywords)
332 ui.note(keywords)
333 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
333 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
334 # silence branch command if not verbose
334 # silence branch command if not verbose
335 quiet = ui.quiet
335 quiet = ui.quiet
336 ui.quiet = not ui.verbose
336 ui.quiet = not ui.verbose
337 commands.branch(ui, repo, branchname)
337 commands.branch(ui, repo, branchname)
338 ui.quiet = quiet
338 ui.quiet = quiet
339 for name, cmd in ui.configitems('hooks'):
339 for name, cmd in ui.configitems('hooks'):
340 if name.split('.', 1)[0].find('commit') > -1:
340 if name.split('.', 1)[0].find('commit') > -1:
341 repo.ui.setconfig('hooks', name, '')
341 repo.ui.setconfig('hooks', name, '')
342 ui.note(_('unhooked all commit hooks\n'))
342 ui.note(_('unhooked all commit hooks\n'))
343 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
343 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
344 repo.commit(text=msg)
344 repo.commit(text=msg)
345 fmt = ui.verbose and ' in %s' % path or ''
345 fmt = ui.verbose and ' in %s' % path or ''
346 ui.status(_('\n\t%s keywords expanded%s\n') % (kwstatus, fmt))
346 ui.status(_('\n\t%s keywords expanded%s\n') % (kwstatus, fmt))
347 ui.write(repo.wread(fn))
347 ui.write(repo.wread(fn))
348 ui.debug(_('\nremoving temporary repository %s\n') % tmpdir)
348 ui.debug(_('\nremoving temporary repository %s\n') % tmpdir)
349 shutil.rmtree(tmpdir, ignore_errors=True)
349 shutil.rmtree(tmpdir, ignore_errors=True)
350
350
351 def expand(ui, repo, *pats, **opts):
351 def expand(ui, repo, *pats, **opts):
352 '''expand keywords in the working directory
352 '''expand keywords in the working directory
353
353
354 Run after (re)enabling keyword expansion.
354 Run after (re)enabling keyword expansion.
355
355
356 kwexpand refuses to run if given files contain local changes.
356 kwexpand refuses to run if given files contain local changes.
357 '''
357 '''
358 # 3rd argument sets expansion to True
358 # 3rd argument sets expansion to True
359 _kwfwrite(ui, repo, True, *pats, **opts)
359 _kwfwrite(ui, repo, True, *pats, **opts)
360
360
361 def files(ui, repo, *pats, **opts):
361 def files(ui, repo, *pats, **opts):
362 '''print filenames configured for keyword expansion
362 '''show files configured for keyword expansion
363
363
364 Check which filenames in the working directory are matched by the
364 List which files in the working directory are matched by the
365 [keyword] configuration patterns.
365 [keyword] configuration patterns.
366
366
367 Useful to prevent inadvertent keyword expansion and to speed up
367 Useful to prevent inadvertent keyword expansion and to speed up
368 execution by including only filenames that are actual candidates
368 execution by including only files that are actual candidates
369 for expansion.
369 for expansion.
370
370
371 Use -u/--untracked to display untracked filenames as well.
371 See "hg help keyword" on how to construct patterns both for
372 inclusion and exclusion of files.
373
374 Use -u/--untracked to list untracked files as well.
372
375
373 With -a/--all and -v/--verbose the codes used to show the status
376 With -a/--all and -v/--verbose the codes used to show the status
374 of files are:
377 of files are:
375 K = keyword expansion candidate
378 K = keyword expansion candidate
376 k = keyword expansion candidate (untracked)
379 k = keyword expansion candidate (untracked)
377 I = ignored
380 I = ignored
378 i = ignored (untracked)
381 i = ignored (untracked)
379 '''
382 '''
380 kwt = kwtools['templater']
383 kwt = kwtools['templater']
381 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts)
384 status = _status(ui, repo, kwt, opts.get('untracked'), *pats, **opts)
382 modified, added, removed, deleted, unknown, ignored, clean = status
385 modified, added, removed, deleted, unknown, ignored, clean = status
383 files = sorted(modified + added + clean)
386 files = sorted(modified + added + clean)
384 wctx = repo[None]
387 wctx = repo[None]
385 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
388 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
386 kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
389 kwuntracked = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
387 cwd = pats and repo.getcwd() or ''
390 cwd = pats and repo.getcwd() or ''
388 kwfstats = (not opts.get('ignore') and
391 kwfstats = (not opts.get('ignore') and
389 (('K', kwfiles), ('k', kwuntracked),) or ())
392 (('K', kwfiles), ('k', kwuntracked),) or ())
390 if opts.get('all') or opts.get('ignore'):
393 if opts.get('all') or opts.get('ignore'):
391 kwfstats += (('I', [f for f in files if f not in kwfiles]),
394 kwfstats += (('I', [f for f in files if f not in kwfiles]),
392 ('i', [f for f in unknown if f not in kwuntracked]),)
395 ('i', [f for f in unknown if f not in kwuntracked]),)
393 for char, filenames in kwfstats:
396 for char, filenames in kwfstats:
394 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
397 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
395 for f in filenames:
398 for f in filenames:
396 ui.write(fmt % repo.pathto(f, cwd))
399 ui.write(fmt % repo.pathto(f, cwd))
397
400
398 def shrink(ui, repo, *pats, **opts):
401 def shrink(ui, repo, *pats, **opts):
399 '''revert expanded keywords in the working directory
402 '''revert expanded keywords in the working directory
400
403
401 Run before changing/disabling active keywords or if you experience
404 Run before changing/disabling active keywords or if you experience
402 problems with "hg import" or "hg merge".
405 problems with "hg import" or "hg merge".
403
406
404 kwshrink refuses to run if given files contain local changes.
407 kwshrink refuses to run if given files contain local changes.
405 '''
408 '''
406 # 3rd argument sets expansion to False
409 # 3rd argument sets expansion to False
407 _kwfwrite(ui, repo, False, *pats, **opts)
410 _kwfwrite(ui, repo, False, *pats, **opts)
408
411
409
412
410 def uisetup(ui):
413 def uisetup(ui):
411 '''Collects [keyword] config in kwtools.
414 '''Collects [keyword] config in kwtools.
412 Monkeypatches dispatch._parse if needed.'''
415 Monkeypatches dispatch._parse if needed.'''
413
416
414 for pat, opt in ui.configitems('keyword'):
417 for pat, opt in ui.configitems('keyword'):
415 if opt != 'ignore':
418 if opt != 'ignore':
416 kwtools['inc'].append(pat)
419 kwtools['inc'].append(pat)
417 else:
420 else:
418 kwtools['exc'].append(pat)
421 kwtools['exc'].append(pat)
419
422
420 if kwtools['inc']:
423 if kwtools['inc']:
421 def kwdispatch_parse(orig, ui, args):
424 def kwdispatch_parse(orig, ui, args):
422 '''Monkeypatch dispatch._parse to obtain running hg command.'''
425 '''Monkeypatch dispatch._parse to obtain running hg command.'''
423 cmd, func, args, options, cmdoptions = orig(ui, args)
426 cmd, func, args, options, cmdoptions = orig(ui, args)
424 kwtools['hgcmd'] = cmd
427 kwtools['hgcmd'] = cmd
425 return cmd, func, args, options, cmdoptions
428 return cmd, func, args, options, cmdoptions
426
429
427 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
430 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
428
431
429 def reposetup(ui, repo):
432 def reposetup(ui, repo):
430 '''Sets up repo as kwrepo for keyword substitution.
433 '''Sets up repo as kwrepo for keyword substitution.
431 Overrides file method to return kwfilelog instead of filelog
434 Overrides file method to return kwfilelog instead of filelog
432 if file matches user configuration.
435 if file matches user configuration.
433 Wraps commit to overwrite configured files with updated
436 Wraps commit to overwrite configured files with updated
434 keyword substitutions.
437 keyword substitutions.
435 Monkeypatches patch and webcommands.'''
438 Monkeypatches patch and webcommands.'''
436
439
437 try:
440 try:
438 if (not repo.local() or not kwtools['inc']
441 if (not repo.local() or not kwtools['inc']
439 or kwtools['hgcmd'] in nokwcommands.split()
442 or kwtools['hgcmd'] in nokwcommands.split()
440 or '.hg' in util.splitpath(repo.root)
443 or '.hg' in util.splitpath(repo.root)
441 or repo._url.startswith('bundle:')):
444 or repo._url.startswith('bundle:')):
442 return
445 return
443 except AttributeError:
446 except AttributeError:
444 pass
447 pass
445
448
446 kwtools['templater'] = kwt = kwtemplater(ui, repo)
449 kwtools['templater'] = kwt = kwtemplater(ui, repo)
447
450
448 class kwrepo(repo.__class__):
451 class kwrepo(repo.__class__):
449 def file(self, f):
452 def file(self, f):
450 if f[0] == '/':
453 if f[0] == '/':
451 f = f[1:]
454 f = f[1:]
452 return kwfilelog(self.sopener, kwt, f)
455 return kwfilelog(self.sopener, kwt, f)
453
456
454 def wread(self, filename):
457 def wread(self, filename):
455 data = super(kwrepo, self).wread(filename)
458 data = super(kwrepo, self).wread(filename)
456 return kwt.wread(filename, data)
459 return kwt.wread(filename, data)
457
460
458 def commit(self, text='', user=None, date=None, match=None,
461 def commit(self, text='', user=None, date=None, match=None,
459 force=False, editor=None, extra={}):
462 force=False, editor=None, extra={}):
460 wlock = lock = None
463 wlock = lock = None
461 _p1 = _p2 = None
464 _p1 = _p2 = None
462 try:
465 try:
463 wlock = self.wlock()
466 wlock = self.wlock()
464 lock = self.lock()
467 lock = self.lock()
465 # store and postpone commit hooks
468 # store and postpone commit hooks
466 commithooks = {}
469 commithooks = {}
467 for name, cmd in ui.configitems('hooks'):
470 for name, cmd in ui.configitems('hooks'):
468 if name.split('.', 1)[0] == 'commit':
471 if name.split('.', 1)[0] == 'commit':
469 commithooks[name] = cmd
472 commithooks[name] = cmd
470 ui.setconfig('hooks', name, None)
473 ui.setconfig('hooks', name, None)
471 if commithooks:
474 if commithooks:
472 # store parents for commit hook environment
475 # store parents for commit hook environment
473 _p1, _p2 = repo.dirstate.parents()
476 _p1, _p2 = repo.dirstate.parents()
474 _p1 = hex(_p1)
477 _p1 = hex(_p1)
475 if _p2 == nullid:
478 if _p2 == nullid:
476 _p2 = ''
479 _p2 = ''
477 else:
480 else:
478 _p2 = hex(_p2)
481 _p2 = hex(_p2)
479
482
480 n = super(kwrepo, self).commit(text, user, date, match, force,
483 n = super(kwrepo, self).commit(text, user, date, match, force,
481 editor, extra)
484 editor, extra)
482
485
483 # restore commit hooks
486 # restore commit hooks
484 for name, cmd in commithooks.iteritems():
487 for name, cmd in commithooks.iteritems():
485 ui.setconfig('hooks', name, cmd)
488 ui.setconfig('hooks', name, cmd)
486 if n is not None:
489 if n is not None:
487 kwt.overwrite(n, True, None)
490 kwt.overwrite(n, True, None)
488 repo.hook('commit', node=n, parent1=_p1, parent2=_p2)
491 repo.hook('commit', node=n, parent1=_p1, parent2=_p2)
489 return n
492 return n
490 finally:
493 finally:
491 release(lock, wlock)
494 release(lock, wlock)
492
495
493 # monkeypatches
496 # monkeypatches
494 def kwpatchfile_init(orig, self, ui, fname, opener, missing=False, eol=None):
497 def kwpatchfile_init(orig, self, ui, fname, opener, missing=False, eol=None):
495 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
498 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
496 rejects or conflicts due to expanded keywords in working dir.'''
499 rejects or conflicts due to expanded keywords in working dir.'''
497 orig(self, ui, fname, opener, missing, eol)
500 orig(self, ui, fname, opener, missing, eol)
498 # shrink keywords read from working dir
501 # shrink keywords read from working dir
499 self.lines = kwt.shrinklines(self.fname, self.lines)
502 self.lines = kwt.shrinklines(self.fname, self.lines)
500
503
501 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
504 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
502 opts=None):
505 opts=None):
503 '''Monkeypatch patch.diff to avoid expansion except when
506 '''Monkeypatch patch.diff to avoid expansion except when
504 comparing against working dir.'''
507 comparing against working dir.'''
505 if node2 is not None:
508 if node2 is not None:
506 kwt.match = util.never
509 kwt.match = util.never
507 elif node1 is not None and node1 != repo['.'].node():
510 elif node1 is not None and node1 != repo['.'].node():
508 kwt.restrict = True
511 kwt.restrict = True
509 return orig(repo, node1, node2, match, changes, opts)
512 return orig(repo, node1, node2, match, changes, opts)
510
513
511 def kwweb_skip(orig, web, req, tmpl):
514 def kwweb_skip(orig, web, req, tmpl):
512 '''Wraps webcommands.x turning off keyword expansion.'''
515 '''Wraps webcommands.x turning off keyword expansion.'''
513 kwt.match = util.never
516 kwt.match = util.never
514 return orig(web, req, tmpl)
517 return orig(web, req, tmpl)
515
518
516 repo.__class__ = kwrepo
519 repo.__class__ = kwrepo
517
520
518 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
521 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
519 extensions.wrapfunction(patch, 'diff', kw_diff)
522 extensions.wrapfunction(patch, 'diff', kw_diff)
520 for c in 'annotate changeset rev filediff diff'.split():
523 for c in 'annotate changeset rev filediff diff'.split():
521 extensions.wrapfunction(webcommands, c, kwweb_skip)
524 extensions.wrapfunction(webcommands, c, kwweb_skip)
522
525
523 cmdtable = {
526 cmdtable = {
524 'kwdemo':
527 'kwdemo':
525 (demo,
528 (demo,
526 [('d', 'default', None, _('show default keyword template maps')),
529 [('d', 'default', None, _('show default keyword template maps')),
527 ('f', 'rcfile', [], _('read maps from rcfile'))],
530 ('f', 'rcfile', [], _('read maps from rcfile'))],
528 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
531 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
529 'kwexpand': (expand, commands.walkopts,
532 'kwexpand': (expand, commands.walkopts,
530 _('hg kwexpand [OPTION]... [FILE]...')),
533 _('hg kwexpand [OPTION]... [FILE]...')),
531 'kwfiles':
534 'kwfiles':
532 (files,
535 (files,
533 [('a', 'all', None, _('show keyword status flags of all files')),
536 [('a', 'all', None, _('show keyword status flags of all files')),
534 ('i', 'ignore', None, _('show files excluded from expansion')),
537 ('i', 'ignore', None, _('show files excluded from expansion')),
535 ('u', 'untracked', None, _('additionally show untracked files')),
538 ('u', 'untracked', None, _('additionally show untracked files')),
536 ] + commands.walkopts,
539 ] + commands.walkopts,
537 _('hg kwfiles [OPTION]... [FILE]...')),
540 _('hg kwfiles [OPTION]... [FILE]...')),
538 'kwshrink': (shrink, commands.walkopts,
541 'kwshrink': (shrink, commands.walkopts,
539 _('hg kwshrink [OPTION]... [FILE]...')),
542 _('hg kwshrink [OPTION]... [FILE]...')),
540 }
543 }
@@ -1,502 +1,502 b''
1 % help
1 % help
2 keyword extension - expand keywords in tracked files
2 keyword extension - expand keywords in tracked files
3
3
4 This extension expands RCS/CVS-like or self-customized $Keywords$ in
4 This extension expands RCS/CVS-like or self-customized $Keywords$ in
5 tracked text files selected by your configuration.
5 tracked text files selected by your configuration.
6
6
7 Keywords are only expanded in local repositories and not stored in the
7 Keywords are only expanded in local repositories and not stored in the
8 change history. The mechanism can be regarded as a convenience for the
8 change history. The mechanism can be regarded as a convenience for the
9 current user or for archive distribution.
9 current user or for archive distribution.
10
10
11 Configuration is done in the [keyword] and [keywordmaps] sections of
11 Configuration is done in the [keyword] and [keywordmaps] sections of
12 hgrc files.
12 hgrc files.
13
13
14 Example:
14 Example:
15
15
16 [keyword]
16 [keyword]
17 # expand keywords in every python file except those matching "x*"
17 # expand keywords in every python file except those matching "x*"
18 **.py =
18 **.py =
19 x* = ignore
19 x* = ignore
20
20
21 Note: the more specific you are in your filename patterns
21 Note: the more specific you are in your filename patterns
22 the less you lose speed in huge repositories.
22 the less you lose speed in huge repositories.
23
23
24 For [keywordmaps] template mapping and expansion demonstration and
24 For [keywordmaps] template mapping and expansion demonstration and
25 control run "hg kwdemo".
25 control run "hg kwdemo".
26
26
27 An additional date template filter {date|utcdate} is provided.
27 An additional date template filter {date|utcdate} is provided.
28
28
29 The default template mappings (view with "hg kwdemo -d") can be
29 The default template mappings (view with "hg kwdemo -d") can be
30 replaced with customized keywords and templates. Again, run "hg
30 replaced with customized keywords and templates. Again, run "hg
31 kwdemo" to control the results of your config changes.
31 kwdemo" to control the results of your config changes.
32
32
33 Before changing/disabling active keywords, run "hg kwshrink" to avoid
33 Before changing/disabling active keywords, run "hg kwshrink" to avoid
34 the risk of inadvertently storing expanded keywords in the change
34 the risk of inadvertently storing expanded keywords in the change
35 history.
35 history.
36
36
37 To force expansion after enabling it, or a configuration change, run
37 To force expansion after enabling it, or a configuration change, run
38 "hg kwexpand".
38 "hg kwexpand".
39
39
40 Also, when committing with the record extension or using mq's qrecord,
40 Also, when committing with the record extension or using mq's qrecord,
41 be aware that keywords cannot be updated. Again, run "hg kwexpand" on
41 be aware that keywords cannot be updated. Again, run "hg kwexpand" on
42 the files in question to update keyword expansions after all changes
42 the files in question to update keyword expansions after all changes
43 have been checked in.
43 have been checked in.
44
44
45 Expansions spanning more than one line and incremental expansions,
45 Expansions spanning more than one line and incremental expansions,
46 like CVS' $Log$, are not supported. A keyword template map
46 like CVS' $Log$, are not supported. A keyword template map
47 "Log = {desc}" expands to the first line of the changeset description.
47 "Log = {desc}" expands to the first line of the changeset description.
48
48
49 list of commands:
49 list of commands:
50
50
51 kwdemo print [keywordmaps] configuration and an expansion example
51 kwdemo print [keywordmaps] configuration and an expansion example
52 kwexpand expand keywords in the working directory
52 kwexpand expand keywords in the working directory
53 kwfiles print filenames configured for keyword expansion
53 kwfiles show files configured for keyword expansion
54 kwshrink revert expanded keywords in the working directory
54 kwshrink revert expanded keywords in the working directory
55
55
56 enabled extensions:
56 enabled extensions:
57
57
58 keyword expand keywords in tracked files
58 keyword expand keywords in tracked files
59 mq manage a stack of patches
59 mq manage a stack of patches
60 notify hooks for sending email notifications at commit/push time
60 notify hooks for sending email notifications at commit/push time
61
61
62 use "hg -v help keyword" to show aliases and global options
62 use "hg -v help keyword" to show aliases and global options
63 % hg kwdemo
63 % hg kwdemo
64 [extensions]
64 [extensions]
65 hgext.keyword =
65 hgext.keyword =
66 [keyword]
66 [keyword]
67 * =
67 * =
68 b = ignore
68 b = ignore
69 demo.txt =
69 demo.txt =
70 [keywordmaps]
70 [keywordmaps]
71 RCSFile = {file|basename},v
71 RCSFile = {file|basename},v
72 Author = {author|user}
72 Author = {author|user}
73 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
73 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
74 Source = {root}/{file},v
74 Source = {root}/{file},v
75 Date = {date|utcdate}
75 Date = {date|utcdate}
76 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
76 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
77 Revision = {node|short}
77 Revision = {node|short}
78 $RCSFile: demo.txt,v $
78 $RCSFile: demo.txt,v $
79 $Author: test $
79 $Author: test $
80 $Header: /TMP/demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
80 $Header: /TMP/demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
81 $Source: /TMP/demo.txt,v $
81 $Source: /TMP/demo.txt,v $
82 $Date: 2000/00/00 00:00:00 $
82 $Date: 2000/00/00 00:00:00 $
83 $Id: demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
83 $Id: demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
84 $Revision: xxxxxxxxxxxx $
84 $Revision: xxxxxxxxxxxx $
85 [extensions]
85 [extensions]
86 hgext.keyword =
86 hgext.keyword =
87 [keyword]
87 [keyword]
88 * =
88 * =
89 b = ignore
89 b = ignore
90 demo.txt =
90 demo.txt =
91 [keywordmaps]
91 [keywordmaps]
92 Branch = {branches}
92 Branch = {branches}
93 $Branch: demobranch $
93 $Branch: demobranch $
94 % kwshrink should exit silently in empty/invalid repo
94 % kwshrink should exit silently in empty/invalid repo
95 pulling from test-keyword.hg
95 pulling from test-keyword.hg
96 requesting all changes
96 requesting all changes
97 adding changesets
97 adding changesets
98 adding manifests
98 adding manifests
99 adding file changes
99 adding file changes
100 added 1 changesets with 1 changes to 1 files
100 added 1 changesets with 1 changes to 1 files
101 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
102 % cat
102 % cat
103 expand $Id$
103 expand $Id$
104 do not process $Id:
104 do not process $Id:
105 xxx $
105 xxx $
106 ignore $Id$
106 ignore $Id$
107 % addremove
107 % addremove
108 adding a
108 adding a
109 adding b
109 adding b
110 % status
110 % status
111 A a
111 A a
112 A b
112 A b
113 % default keyword expansion including commit hook
113 % default keyword expansion including commit hook
114 % interrupted commit should not change state or run commit hook
114 % interrupted commit should not change state or run commit hook
115 abort: empty commit message
115 abort: empty commit message
116 % status
116 % status
117 A a
117 A a
118 A b
118 A b
119 % commit
119 % commit
120 a
120 a
121 b
121 b
122 overwriting a expanding keywords
122 overwriting a expanding keywords
123 running hook commit.test: cp a hooktest
123 running hook commit.test: cp a hooktest
124 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
124 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
125 % status
125 % status
126 ? hooktest
126 ? hooktest
127 % identify
127 % identify
128 ef63ca68695b
128 ef63ca68695b
129 % cat
129 % cat
130 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
130 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
131 do not process $Id:
131 do not process $Id:
132 xxx $
132 xxx $
133 ignore $Id$
133 ignore $Id$
134 % hg cat
134 % hg cat
135 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
135 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
136 do not process $Id:
136 do not process $Id:
137 xxx $
137 xxx $
138 ignore $Id$
138 ignore $Id$
139 a
139 a
140 % diff a hooktest
140 % diff a hooktest
141 % removing commit hook from config
141 % removing commit hook from config
142 % bundle
142 % bundle
143 2 changesets found
143 2 changesets found
144 % notify on pull to check whether keywords stay as is in email
144 % notify on pull to check whether keywords stay as is in email
145 % ie. if patch.diff wrapper acts as it should
145 % ie. if patch.diff wrapper acts as it should
146 % pull from bundle
146 % pull from bundle
147 pulling from ../kw.hg
147 pulling from ../kw.hg
148 requesting all changes
148 requesting all changes
149 adding changesets
149 adding changesets
150 adding manifests
150 adding manifests
151 adding file changes
151 adding file changes
152 added 2 changesets with 3 changes to 3 files
152 added 2 changesets with 3 changes to 3 files
153
153
154 diff -r 000000000000 -r a2392c293916 sym
154 diff -r 000000000000 -r a2392c293916 sym
155 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
155 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
156 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
156 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
157 @@ -0,0 +1,1 @@
157 @@ -0,0 +1,1 @@
158 +a
158 +a
159 \ No newline at end of file
159 \ No newline at end of file
160
160
161 diff -r a2392c293916 -r ef63ca68695b a
161 diff -r a2392c293916 -r ef63ca68695b a
162 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
162 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
163 +++ b/a Thu Jan 01 00:00:00 1970 +0000
163 +++ b/a Thu Jan 01 00:00:00 1970 +0000
164 @@ -0,0 +1,3 @@
164 @@ -0,0 +1,3 @@
165 +expand $Id$
165 +expand $Id$
166 +do not process $Id:
166 +do not process $Id:
167 +xxx $
167 +xxx $
168 diff -r a2392c293916 -r ef63ca68695b b
168 diff -r a2392c293916 -r ef63ca68695b b
169 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
169 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
170 +++ b/b Thu Jan 01 00:00:00 1970 +0000
170 +++ b/b Thu Jan 01 00:00:00 1970 +0000
171 @@ -0,0 +1,1 @@
171 @@ -0,0 +1,1 @@
172 +ignore $Id$
172 +ignore $Id$
173 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
173 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
174 % remove notify config
174 % remove notify config
175 % touch
175 % touch
176 % status
176 % status
177 % update
177 % update
178 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
178 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 % cat
179 % cat
180 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
180 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
181 do not process $Id:
181 do not process $Id:
182 xxx $
182 xxx $
183 ignore $Id$
183 ignore $Id$
184 % check whether expansion is filewise
184 % check whether expansion is filewise
185 % commit c
185 % commit c
186 adding c
186 adding c
187 % force expansion
187 % force expansion
188 overwriting a expanding keywords
188 overwriting a expanding keywords
189 overwriting c expanding keywords
189 overwriting c expanding keywords
190 % compare changenodes in a c
190 % compare changenodes in a c
191 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
191 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
192 do not process $Id:
192 do not process $Id:
193 xxx $
193 xxx $
194 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
194 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
195 tests for different changenodes
195 tests for different changenodes
196 % qinit -c
196 % qinit -c
197 % qimport
197 % qimport
198 % qcommit
198 % qcommit
199 % keywords should not be expanded in patch
199 % keywords should not be expanded in patch
200 # HG changeset patch
200 # HG changeset patch
201 # User User Name <user@example.com>
201 # User User Name <user@example.com>
202 # Date 1 0
202 # Date 1 0
203 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
203 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
204 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
204 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
205 cndiff
205 cndiff
206
206
207 diff -r ef63ca68695b -r 40a904bbbe4c c
207 diff -r ef63ca68695b -r 40a904bbbe4c c
208 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
208 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
209 +++ b/c Thu Jan 01 00:00:01 1970 +0000
209 +++ b/c Thu Jan 01 00:00:01 1970 +0000
210 @@ -0,0 +1,2 @@
210 @@ -0,0 +1,2 @@
211 +$Id$
211 +$Id$
212 +tests for different changenodes
212 +tests for different changenodes
213 % qpop
213 % qpop
214 patch queue now empty
214 patch queue now empty
215 % qgoto - should imply qpush
215 % qgoto - should imply qpush
216 applying mqtest.diff
216 applying mqtest.diff
217 now at: mqtest.diff
217 now at: mqtest.diff
218 % cat
218 % cat
219 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
219 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
220 tests for different changenodes
220 tests for different changenodes
221 % qpop and move on
221 % qpop and move on
222 patch queue now empty
222 patch queue now empty
223 % copy
223 % copy
224 % kwfiles added
224 % kwfiles added
225 a
225 a
226 c
226 c
227 % commit
227 % commit
228 c
228 c
229 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
229 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
230 overwriting c expanding keywords
230 overwriting c expanding keywords
231 committed changeset 2:e22d299ac0c2bd8897b3df5114374b9e4d4ca62f
231 committed changeset 2:e22d299ac0c2bd8897b3df5114374b9e4d4ca62f
232 % cat a c
232 % cat a c
233 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
233 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
234 do not process $Id:
234 do not process $Id:
235 xxx $
235 xxx $
236 expand $Id: c,v e22d299ac0c2 1970/01/01 00:00:01 user $
236 expand $Id: c,v e22d299ac0c2 1970/01/01 00:00:01 user $
237 do not process $Id:
237 do not process $Id:
238 xxx $
238 xxx $
239 % touch copied c
239 % touch copied c
240 % status
240 % status
241 % kwfiles
241 % kwfiles
242 a
242 a
243 c
243 c
244 % diff --rev
244 % diff --rev
245 diff -r ef63ca68695b c
245 diff -r ef63ca68695b c
246 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
246 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
247 @@ -0,0 +1,3 @@
247 @@ -0,0 +1,3 @@
248 +expand $Id$
248 +expand $Id$
249 +do not process $Id:
249 +do not process $Id:
250 +xxx $
250 +xxx $
251 % rollback
251 % rollback
252 rolling back last transaction
252 rolling back last transaction
253 % status
253 % status
254 A c
254 A c
255 % update -C
255 % update -C
256 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
256 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
257 % custom keyword expansion
257 % custom keyword expansion
258 % try with kwdemo
258 % try with kwdemo
259 [extensions]
259 [extensions]
260 hgext.keyword =
260 hgext.keyword =
261 [keyword]
261 [keyword]
262 * =
262 * =
263 b = ignore
263 b = ignore
264 demo.txt =
264 demo.txt =
265 [keywordmaps]
265 [keywordmaps]
266 Xinfo = {author}: {desc}
266 Xinfo = {author}: {desc}
267 $Xinfo: test: hg keyword config and expansion example $
267 $Xinfo: test: hg keyword config and expansion example $
268 % cat
268 % cat
269 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
269 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
270 do not process $Id:
270 do not process $Id:
271 xxx $
271 xxx $
272 ignore $Id$
272 ignore $Id$
273 % hg cat
273 % hg cat
274 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
274 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
275 do not process $Id:
275 do not process $Id:
276 xxx $
276 xxx $
277 ignore $Id$
277 ignore $Id$
278 a
278 a
279 % interrupted commit should not change state
279 % interrupted commit should not change state
280 abort: empty commit message
280 abort: empty commit message
281 % status
281 % status
282 M a
282 M a
283 ? c
283 ? c
284 ? log
284 ? log
285 % commit
285 % commit
286 a
286 a
287 overwriting a expanding keywords
287 overwriting a expanding keywords
288 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
288 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
289 % status
289 % status
290 ? c
290 ? c
291 % verify
291 % verify
292 checking changesets
292 checking changesets
293 checking manifests
293 checking manifests
294 crosschecking files in changesets and manifests
294 crosschecking files in changesets and manifests
295 checking files
295 checking files
296 3 files, 3 changesets, 4 total revisions
296 3 files, 3 changesets, 4 total revisions
297 % cat
297 % cat
298 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
298 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
299 do not process $Id:
299 do not process $Id:
300 xxx $
300 xxx $
301 $Xinfo: User Name <user@example.com>: firstline $
301 $Xinfo: User Name <user@example.com>: firstline $
302 ignore $Id$
302 ignore $Id$
303 % hg cat
303 % hg cat
304 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
304 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
305 do not process $Id:
305 do not process $Id:
306 xxx $
306 xxx $
307 $Xinfo: User Name <user@example.com>: firstline $
307 $Xinfo: User Name <user@example.com>: firstline $
308 ignore $Id$
308 ignore $Id$
309 a
309 a
310 % annotate
310 % annotate
311 1: expand $Id$
311 1: expand $Id$
312 1: do not process $Id:
312 1: do not process $Id:
313 1: xxx $
313 1: xxx $
314 2: $Xinfo$
314 2: $Xinfo$
315 % remove
315 % remove
316 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
316 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
317 % status
317 % status
318 ? c
318 ? c
319 % rollback
319 % rollback
320 rolling back last transaction
320 rolling back last transaction
321 % status
321 % status
322 R a
322 R a
323 ? c
323 ? c
324 % revert a
324 % revert a
325 % cat a
325 % cat a
326 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
326 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
327 do not process $Id:
327 do not process $Id:
328 xxx $
328 xxx $
329 $Xinfo: User Name <user@example.com>: firstline $
329 $Xinfo: User Name <user@example.com>: firstline $
330 % clone to test incoming
330 % clone to test incoming
331 requesting all changes
331 requesting all changes
332 adding changesets
332 adding changesets
333 adding manifests
333 adding manifests
334 adding file changes
334 adding file changes
335 added 2 changesets with 3 changes to 3 files
335 added 2 changesets with 3 changes to 3 files
336 updating working directory
336 updating working directory
337 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
337 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
338 % incoming
338 % incoming
339 comparing with test-keyword/Test
339 comparing with test-keyword/Test
340 searching for changes
340 searching for changes
341 changeset: 2:bb948857c743
341 changeset: 2:bb948857c743
342 tag: tip
342 tag: tip
343 user: User Name <user@example.com>
343 user: User Name <user@example.com>
344 date: Thu Jan 01 00:00:02 1970 +0000
344 date: Thu Jan 01 00:00:02 1970 +0000
345 summary: firstline
345 summary: firstline
346
346
347 % commit rejecttest
347 % commit rejecttest
348 a
348 a
349 overwriting a expanding keywords
349 overwriting a expanding keywords
350 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
350 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
351 % export
351 % export
352 % import
352 % import
353 applying ../rejecttest.diff
353 applying ../rejecttest.diff
354 % cat
354 % cat
355 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
355 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
356 do not process $Id: rejecttest
356 do not process $Id: rejecttest
357 xxx $
357 xxx $
358 $Xinfo: User Name <user@example.com>: rejects? $
358 $Xinfo: User Name <user@example.com>: rejects? $
359 ignore $Id$
359 ignore $Id$
360
360
361 % rollback
361 % rollback
362 rolling back last transaction
362 rolling back last transaction
363 % clean update
363 % clean update
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
364 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
365 % kwexpand/kwshrink on selected files
365 % kwexpand/kwshrink on selected files
366 % copy a x/a
366 % copy a x/a
367 % kwexpand a
367 % kwexpand a
368 overwriting a expanding keywords
368 overwriting a expanding keywords
369 % kwexpand x/a should abort
369 % kwexpand x/a should abort
370 abort: outstanding uncommitted changes
370 abort: outstanding uncommitted changes
371 x/a
371 x/a
372 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
372 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
373 overwriting x/a expanding keywords
373 overwriting x/a expanding keywords
374 committed changeset 3:cfa68229c1167443337266ebac453c73b1d5d16e
374 committed changeset 3:cfa68229c1167443337266ebac453c73b1d5d16e
375 % cat a
375 % cat a
376 expand $Id: x/a cfa68229c116 Thu, 01 Jan 1970 00:00:03 +0000 user $
376 expand $Id: x/a cfa68229c116 Thu, 01 Jan 1970 00:00:03 +0000 user $
377 do not process $Id:
377 do not process $Id:
378 xxx $
378 xxx $
379 $Xinfo: User Name <user@example.com>: xa $
379 $Xinfo: User Name <user@example.com>: xa $
380 % kwshrink a inside directory x
380 % kwshrink a inside directory x
381 overwriting x/a shrinking keywords
381 overwriting x/a shrinking keywords
382 % cat a
382 % cat a
383 expand $Id$
383 expand $Id$
384 do not process $Id:
384 do not process $Id:
385 xxx $
385 xxx $
386 $Xinfo$
386 $Xinfo$
387 % kwexpand nonexistent
387 % kwexpand nonexistent
388 nonexistent:
388 nonexistent:
389 % hg serve
389 % hg serve
390 % expansion
390 % expansion
391 % hgweb file
391 % hgweb file
392 200 Script output follows
392 200 Script output follows
393
393
394 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
394 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
395 do not process $Id:
395 do not process $Id:
396 xxx $
396 xxx $
397 $Xinfo: User Name <user@example.com>: firstline $
397 $Xinfo: User Name <user@example.com>: firstline $
398 % no expansion
398 % no expansion
399 % hgweb annotate
399 % hgweb annotate
400 200 Script output follows
400 200 Script output follows
401
401
402
402
403 user@1: expand $Id$
403 user@1: expand $Id$
404 user@1: do not process $Id:
404 user@1: do not process $Id:
405 user@1: xxx $
405 user@1: xxx $
406 user@2: $Xinfo$
406 user@2: $Xinfo$
407
407
408
408
409
409
410
410
411 % hgweb changeset
411 % hgweb changeset
412 200 Script output follows
412 200 Script output follows
413
413
414
414
415 # HG changeset patch
415 # HG changeset patch
416 # User User Name <user@example.com>
416 # User User Name <user@example.com>
417 # Date 3 0
417 # Date 3 0
418 # Node ID cfa68229c1167443337266ebac453c73b1d5d16e
418 # Node ID cfa68229c1167443337266ebac453c73b1d5d16e
419 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
419 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
420 xa
420 xa
421
421
422 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
422 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
423 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
423 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
424 @@ -0,0 +1,4 @@
424 @@ -0,0 +1,4 @@
425 +expand $Id$
425 +expand $Id$
426 +do not process $Id:
426 +do not process $Id:
427 +xxx $
427 +xxx $
428 +$Xinfo$
428 +$Xinfo$
429
429
430 % hgweb filediff
430 % hgweb filediff
431 200 Script output follows
431 200 Script output follows
432
432
433
433
434 --- a/a Thu Jan 01 00:00:00 1970 +0000
434 --- a/a Thu Jan 01 00:00:00 1970 +0000
435 +++ b/a Thu Jan 01 00:00:02 1970 +0000
435 +++ b/a Thu Jan 01 00:00:02 1970 +0000
436 @@ -1,3 +1,4 @@
436 @@ -1,3 +1,4 @@
437 expand $Id$
437 expand $Id$
438 do not process $Id:
438 do not process $Id:
439 xxx $
439 xxx $
440 +$Xinfo$
440 +$Xinfo$
441
441
442
442
443
443
444
444
445 % errors encountered
445 % errors encountered
446 % merge/resolve
446 % merge/resolve
447 % simplemerge
447 % simplemerge
448 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
448 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
449 created new head
449 created new head
450 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
450 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
451 (branch merge, don't forget to commit)
451 (branch merge, don't forget to commit)
452 $Id: m 8731e1dadc99 Thu, 01 Jan 1970 00:00:00 +0000 test $
452 $Id: m 8731e1dadc99 Thu, 01 Jan 1970 00:00:00 +0000 test $
453 foo
453 foo
454 % conflict
454 % conflict
455 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
455 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
456 created new head
456 created new head
457 merging m
457 merging m
458 warning: conflicts during merge.
458 warning: conflicts during merge.
459 merging m failed!
459 merging m failed!
460 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
460 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
461 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
461 use 'hg resolve' to retry unresolved file merges or 'hg up --clean' to abandon
462 % keyword stays outside conflict zone
462 % keyword stays outside conflict zone
463 $Id$
463 $Id$
464 <<<<<<< local
464 <<<<<<< local
465 bar
465 bar
466 =======
466 =======
467 foo
467 foo
468 >>>>>>> other
468 >>>>>>> other
469 % resolve to local
469 % resolve to local
470 $Id: m 43dfd2854b5b Thu, 01 Jan 1970 00:00:00 +0000 test $
470 $Id: m 43dfd2854b5b Thu, 01 Jan 1970 00:00:00 +0000 test $
471 bar
471 bar
472 % switch off expansion
472 % switch off expansion
473 % kwshrink with unknown file u
473 % kwshrink with unknown file u
474 overwriting a shrinking keywords
474 overwriting a shrinking keywords
475 overwriting m shrinking keywords
475 overwriting m shrinking keywords
476 overwriting x/a shrinking keywords
476 overwriting x/a shrinking keywords
477 % cat
477 % cat
478 expand $Id$
478 expand $Id$
479 do not process $Id:
479 do not process $Id:
480 xxx $
480 xxx $
481 $Xinfo$
481 $Xinfo$
482 ignore $Id$
482 ignore $Id$
483 % hg cat
483 % hg cat
484 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
484 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
485 do not process $Id:
485 do not process $Id:
486 xxx $
486 xxx $
487 $Xinfo: User Name <user@example.com>: firstline $
487 $Xinfo: User Name <user@example.com>: firstline $
488 ignore $Id$
488 ignore $Id$
489 a
489 a
490 % cat
490 % cat
491 expand $Id$
491 expand $Id$
492 do not process $Id:
492 do not process $Id:
493 xxx $
493 xxx $
494 $Xinfo$
494 $Xinfo$
495 ignore $Id$
495 ignore $Id$
496 % hg cat
496 % hg cat
497 expand $Id$
497 expand $Id$
498 do not process $Id:
498 do not process $Id:
499 xxx $
499 xxx $
500 $Xinfo$
500 $Xinfo$
501 ignore $Id$
501 ignore $Id$
502 a
502 a
General Comments 0
You need to be logged in to leave comments. Login now