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