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