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