##// END OF EJS Templates
keyword: support rollback by restoring expansion to previous values...
Christian Ebert -
r12498:4846e8cd default
parent child Browse files
Show More
@@ -1,575 +1,591 b''
1 # keyword.py - $Keyword$ expansion for Mercurial
1 # keyword.py - $Keyword$ expansion for Mercurial
2 #
2 #
3 # Copyright 2007-2010 Christian Ebert <blacktrash@gmx.net>
3 # Copyright 2007-2010 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 or any later version.
6 # GNU General Public License version 2 or any later version.
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 Keywords expand to the changeset data pertaining to the latest change
38 Keywords expand to the changeset data pertaining to the latest change
39 relative to the working directory parent of each file.
39 relative to the working directory parent of each file.
40
40
41 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
41 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
42 sections of hgrc files.
42 sections of hgrc files.
43
43
44 Example::
44 Example::
45
45
46 [keyword]
46 [keyword]
47 # expand keywords in every python file except those matching "x*"
47 # expand keywords in every python file except those matching "x*"
48 **.py =
48 **.py =
49 x* = ignore
49 x* = ignore
50
50
51 [keywordset]
51 [keywordset]
52 # prefer svn- over cvs-like default keywordmaps
52 # prefer svn- over cvs-like default keywordmaps
53 svn = True
53 svn = True
54
54
55 .. note::
55 .. note::
56 The more specific you are in your filename patterns the less you
56 The more specific you are in your filename patterns the less you
57 lose speed in huge repositories.
57 lose speed in huge repositories.
58
58
59 For [keywordmaps] template mapping and expansion demonstration and
59 For [keywordmaps] template mapping and expansion demonstration and
60 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
60 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
61 available templates and filters.
61 available templates and filters.
62
62
63 Three additional date template filters are provided::
63 Three additional date template filters are provided::
64
64
65 utcdate "2006/09/18 15:13:13"
65 utcdate "2006/09/18 15:13:13"
66 svnutcdate "2006-09-18 15:13:13Z"
66 svnutcdate "2006-09-18 15:13:13Z"
67 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
67 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
68
68
69 The default template mappings (view with :hg:`kwdemo -d`) can be
69 The default template mappings (view with :hg:`kwdemo -d`) can be
70 replaced with customized keywords and templates. Again, run
70 replaced with customized keywords and templates. Again, run
71 :hg:`kwdemo` to control the results of your config changes.
71 :hg:`kwdemo` to control the results of your config changes.
72
72
73 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
73 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
74 the risk of inadvertently storing expanded keywords in the change
74 the risk of inadvertently storing expanded keywords in the change
75 history.
75 history.
76
76
77 To force expansion after enabling it, or a configuration change, run
77 To force expansion after enabling it, or a configuration change, run
78 :hg:`kwexpand`.
78 :hg:`kwexpand`.
79
79
80 Expansions spanning more than one line and incremental expansions,
80 Expansions spanning more than one line and incremental expansions,
81 like CVS' $Log$, are not supported. A keyword template map "Log =
81 like CVS' $Log$, are not supported. A keyword template map "Log =
82 {desc}" expands to the first line of the changeset description.
82 {desc}" expands to the first line of the changeset description.
83 '''
83 '''
84
84
85 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
85 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
86 from mercurial import patch, localrepo, templater, templatefilters, util, match
86 from mercurial import patch, localrepo, templater, templatefilters, util, match
87 from mercurial.hgweb import webcommands
87 from mercurial.hgweb import webcommands
88 from mercurial.i18n import _
88 from mercurial.i18n import _
89 import re, shutil, tempfile
89 import re, shutil, tempfile
90
90
91 commands.optionalrepo += ' kwdemo'
91 commands.optionalrepo += ' kwdemo'
92
92
93 # hg commands that do not act on keywords
93 # hg commands that do not act on keywords
94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
94 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
95 ' log outgoing push rename rollback tip verify'
95 ' log outgoing push rename tip verify convert email glog')
96 ' convert email glog')
97
96
98 # hg commands that trigger expansion only when writing to working dir,
97 # hg commands that trigger expansion only when writing to working dir,
99 # not when reading filelog, and unexpand when reading from working dir
98 # not when reading filelog, and unexpand when reading from working dir
100 restricted = 'merge record qrecord resolve transplant'
99 restricted = 'merge record qrecord resolve transplant'
101
100
102 # commands using dorecord
101 # commands using dorecord
103 recordcommands = 'record qrecord'
102 recordcommands = 'record qrecord'
104 # names of extensions using dorecord
103 # names of extensions using dorecord
105 recordextensions = 'record'
104 recordextensions = 'record'
106
105
107 # date like in cvs' $Date
106 # date like in cvs' $Date
108 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
107 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
109 # date like in svn's $Date
108 # date like in svn's $Date
110 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
109 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
111 # date like in svn's $Id
110 # date like in svn's $Id
112 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
111 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
113
112
114 # make keyword tools accessible
113 # make keyword tools accessible
115 kwtools = {'templater': None, 'hgcmd': ''}
114 kwtools = {'templater': None, 'hgcmd': ''}
116
115
117
116
118 def _defaultkwmaps(ui):
117 def _defaultkwmaps(ui):
119 '''Returns default keywordmaps according to keywordset configuration.'''
118 '''Returns default keywordmaps according to keywordset configuration.'''
120 templates = {
119 templates = {
121 'Revision': '{node|short}',
120 'Revision': '{node|short}',
122 'Author': '{author|user}',
121 'Author': '{author|user}',
123 }
122 }
124 kwsets = ({
123 kwsets = ({
125 'Date': '{date|utcdate}',
124 'Date': '{date|utcdate}',
126 'RCSfile': '{file|basename},v',
125 'RCSfile': '{file|basename},v',
127 'RCSFile': '{file|basename},v', # kept for backwards compatibility
126 'RCSFile': '{file|basename},v', # kept for backwards compatibility
128 # with hg-keyword
127 # with hg-keyword
129 'Source': '{root}/{file},v',
128 'Source': '{root}/{file},v',
130 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
129 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
131 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
130 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
132 }, {
131 }, {
133 'Date': '{date|svnisodate}',
132 'Date': '{date|svnisodate}',
134 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
133 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
135 'LastChangedRevision': '{node|short}',
134 'LastChangedRevision': '{node|short}',
136 'LastChangedBy': '{author|user}',
135 'LastChangedBy': '{author|user}',
137 'LastChangedDate': '{date|svnisodate}',
136 'LastChangedDate': '{date|svnisodate}',
138 })
137 })
139 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
138 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
140 return templates
139 return templates
141
140
142 class kwtemplater(object):
141 class kwtemplater(object):
143 '''
142 '''
144 Sets up keyword templates, corresponding keyword regex, and
143 Sets up keyword templates, corresponding keyword regex, and
145 provides keyword substitution functions.
144 provides keyword substitution functions.
146 '''
145 '''
147
146
148 def __init__(self, ui, repo, inc, exc):
147 def __init__(self, ui, repo, inc, exc):
149 self.ui = ui
148 self.ui = ui
150 self.repo = repo
149 self.repo = repo
151 self.match = match.match(repo.root, '', [], inc, exc)
150 self.match = match.match(repo.root, '', [], inc, exc)
152 self.restrict = kwtools['hgcmd'] in restricted.split()
151 self.restrict = kwtools['hgcmd'] in restricted.split()
153 self.record = kwtools['hgcmd'] in recordcommands.split()
152 self.record = kwtools['hgcmd'] in recordcommands.split()
154
153
155 kwmaps = self.ui.configitems('keywordmaps')
154 kwmaps = self.ui.configitems('keywordmaps')
156 if kwmaps: # override default templates
155 if kwmaps: # override default templates
157 self.templates = dict((k, templater.parsestring(v, False))
156 self.templates = dict((k, templater.parsestring(v, False))
158 for k, v in kwmaps)
157 for k, v in kwmaps)
159 else:
158 else:
160 self.templates = _defaultkwmaps(self.ui)
159 self.templates = _defaultkwmaps(self.ui)
161 escaped = map(re.escape, self.templates.keys())
160 escaped = map(re.escape, self.templates.keys())
162 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
161 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
163 self.re_kw = re.compile(kwpat)
162 self.re_kw = re.compile(kwpat)
164
163
165 templatefilters.filters.update({'utcdate': utcdate,
164 templatefilters.filters.update({'utcdate': utcdate,
166 'svnisodate': svnisodate,
165 'svnisodate': svnisodate,
167 'svnutcdate': svnutcdate})
166 'svnutcdate': svnutcdate})
168
167
169 def substitute(self, data, path, ctx, subfunc):
168 def substitute(self, data, path, ctx, subfunc):
170 '''Replaces keywords in data with expanded template.'''
169 '''Replaces keywords in data with expanded template.'''
171 def kwsub(mobj):
170 def kwsub(mobj):
172 kw = mobj.group(1)
171 kw = mobj.group(1)
173 ct = cmdutil.changeset_templater(self.ui, self.repo,
172 ct = cmdutil.changeset_templater(self.ui, self.repo,
174 False, None, '', False)
173 False, None, '', False)
175 ct.use_template(self.templates[kw])
174 ct.use_template(self.templates[kw])
176 self.ui.pushbuffer()
175 self.ui.pushbuffer()
177 ct.show(ctx, root=self.repo.root, file=path)
176 ct.show(ctx, root=self.repo.root, file=path)
178 ekw = templatefilters.firstline(self.ui.popbuffer())
177 ekw = templatefilters.firstline(self.ui.popbuffer())
179 return '$%s: %s $' % (kw, ekw)
178 return '$%s: %s $' % (kw, ekw)
180 return subfunc(kwsub, data)
179 return subfunc(kwsub, data)
181
180
182 def expand(self, path, node, data):
181 def expand(self, path, node, data):
183 '''Returns data with keywords expanded.'''
182 '''Returns data with keywords expanded.'''
184 if not self.restrict and self.match(path) and not util.binary(data):
183 if not self.restrict and self.match(path) and not util.binary(data):
185 ctx = self.repo.filectx(path, fileid=node).changectx()
184 ctx = self.repo.filectx(path, fileid=node).changectx()
186 return self.substitute(data, path, ctx, self.re_kw.sub)
185 return self.substitute(data, path, ctx, self.re_kw.sub)
187 return data
186 return data
188
187
189 def iskwfile(self, path, flagfunc):
188 def iskwfile(self, path, flagfunc):
190 '''Returns true if path matches [keyword] pattern
189 '''Returns true if path matches [keyword] pattern
191 and is not a symbolic link.
190 and is not a symbolic link.
192 Caveat: localrepository._link fails on Windows.'''
191 Caveat: localrepository._link fails on Windows.'''
193 return self.match(path) and not 'l' in flagfunc(path)
192 return self.match(path) and not 'l' in flagfunc(path)
194
193
195 def overwrite(self, ctx, candidates, iswctx, expand):
194 def overwrite(self, ctx, candidates, iswctx, expand, cfiles):
196 '''Overwrites selected files expanding/shrinking keywords.'''
195 '''Overwrites selected files expanding/shrinking keywords.'''
197 if self.record:
196 if cfiles is not None:
198 candidates = [f for f in ctx.files() if f in ctx]
197 candidates = [f for f in candidates if f in cfiles]
199 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
198 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
200 if candidates:
199 if candidates:
201 restrict = self.restrict
200 restrict = self.restrict
202 self.restrict = True # do not expand when reading
201 self.restrict = True # do not expand when reading
202 rollback = kwtools['hgcmd'] == 'rollback'
203 mf = ctx.manifest()
203 mf = ctx.manifest()
204 msg = (expand and _('overwriting %s expanding keywords\n')
204 msg = (expand and _('overwriting %s expanding keywords\n')
205 or _('overwriting %s shrinking keywords\n'))
205 or _('overwriting %s shrinking keywords\n'))
206 for f in candidates:
206 for f in candidates:
207 if not self.record:
207 if not self.record and not rollback:
208 data = self.repo.file(f).read(mf[f])
208 data = self.repo.file(f).read(mf[f])
209 else:
209 else:
210 data = self.repo.wread(f)
210 data = self.repo.wread(f)
211 if util.binary(data):
211 if util.binary(data):
212 continue
212 continue
213 if expand:
213 if expand:
214 if iswctx:
214 if iswctx:
215 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
215 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
216 data, found = self.substitute(data, f, ctx,
216 data, found = self.substitute(data, f, ctx,
217 self.re_kw.subn)
217 self.re_kw.subn)
218 else:
218 else:
219 found = self.re_kw.search(data)
219 found = self.re_kw.search(data)
220 if found:
220 if found:
221 self.ui.note(msg % f)
221 self.ui.note(msg % f)
222 self.repo.wwrite(f, data, mf.flags(f))
222 self.repo.wwrite(f, data, mf.flags(f))
223 if iswctx:
223 if iswctx and not rollback:
224 self.repo.dirstate.normal(f)
224 self.repo.dirstate.normal(f)
225 elif self.record:
225 elif self.record:
226 self.repo.dirstate.normallookup(f)
226 self.repo.dirstate.normallookup(f)
227 self.restrict = restrict
227 self.restrict = restrict
228
228
229 def shrinktext(self, text):
229 def shrinktext(self, text):
230 '''Unconditionally removes all keyword substitutions from text.'''
230 '''Unconditionally removes all keyword substitutions from text.'''
231 return self.re_kw.sub(r'$\1$', text)
231 return self.re_kw.sub(r'$\1$', text)
232
232
233 def shrink(self, fname, text):
233 def shrink(self, fname, text):
234 '''Returns text with all keyword substitutions removed.'''
234 '''Returns text with all keyword substitutions removed.'''
235 if self.match(fname) and not util.binary(text):
235 if self.match(fname) and not util.binary(text):
236 return self.shrinktext(text)
236 return self.shrinktext(text)
237 return text
237 return text
238
238
239 def shrinklines(self, fname, lines):
239 def shrinklines(self, fname, lines):
240 '''Returns lines with keyword substitutions removed.'''
240 '''Returns lines with keyword substitutions removed.'''
241 if self.match(fname):
241 if self.match(fname):
242 text = ''.join(lines)
242 text = ''.join(lines)
243 if not util.binary(text):
243 if not util.binary(text):
244 return self.shrinktext(text).splitlines(True)
244 return self.shrinktext(text).splitlines(True)
245 return lines
245 return lines
246
246
247 def wread(self, fname, data):
247 def wread(self, fname, data):
248 '''If in restricted mode returns data read from wdir with
248 '''If in restricted mode returns data read from wdir with
249 keyword substitutions removed.'''
249 keyword substitutions removed.'''
250 return self.restrict and self.shrink(fname, data) or data
250 return self.restrict and self.shrink(fname, data) or data
251
251
252 class kwfilelog(filelog.filelog):
252 class kwfilelog(filelog.filelog):
253 '''
253 '''
254 Subclass of filelog to hook into its read, add, cmp methods.
254 Subclass of filelog to hook into its read, add, cmp methods.
255 Keywords are "stored" unexpanded, and processed on reading.
255 Keywords are "stored" unexpanded, and processed on reading.
256 '''
256 '''
257 def __init__(self, opener, kwt, path):
257 def __init__(self, opener, kwt, path):
258 super(kwfilelog, self).__init__(opener, path)
258 super(kwfilelog, self).__init__(opener, path)
259 self.kwt = kwt
259 self.kwt = kwt
260 self.path = path
260 self.path = path
261
261
262 def read(self, node):
262 def read(self, node):
263 '''Expands keywords when reading filelog.'''
263 '''Expands keywords when reading filelog.'''
264 data = super(kwfilelog, self).read(node)
264 data = super(kwfilelog, self).read(node)
265 return self.kwt.expand(self.path, node, data)
265 return self.kwt.expand(self.path, node, data)
266
266
267 def add(self, text, meta, tr, link, p1=None, p2=None):
267 def add(self, text, meta, tr, link, p1=None, p2=None):
268 '''Removes keyword substitutions when adding to filelog.'''
268 '''Removes keyword substitutions when adding to filelog.'''
269 text = self.kwt.shrink(self.path, text)
269 text = self.kwt.shrink(self.path, text)
270 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
270 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
271
271
272 def cmp(self, node, text):
272 def cmp(self, node, text):
273 '''Removes keyword substitutions for comparison.'''
273 '''Removes keyword substitutions for comparison.'''
274 text = self.kwt.shrink(self.path, text)
274 text = self.kwt.shrink(self.path, text)
275 if self.renamed(node):
275 if self.renamed(node):
276 t2 = super(kwfilelog, self).read(node)
276 t2 = super(kwfilelog, self).read(node)
277 return t2 != text
277 return t2 != text
278 return revlog.revlog.cmp(self, node, text)
278 return revlog.revlog.cmp(self, node, text)
279
279
280 def _status(ui, repo, kwt, *pats, **opts):
280 def _status(ui, repo, kwt, *pats, **opts):
281 '''Bails out if [keyword] configuration is not active.
281 '''Bails out if [keyword] configuration is not active.
282 Returns status of working directory.'''
282 Returns status of working directory.'''
283 if kwt:
283 if kwt:
284 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
284 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
285 unknown=opts.get('unknown') or opts.get('all'))
285 unknown=opts.get('unknown') or opts.get('all'))
286 if ui.configitems('keyword'):
286 if ui.configitems('keyword'):
287 raise util.Abort(_('[keyword] patterns cannot match'))
287 raise util.Abort(_('[keyword] patterns cannot match'))
288 raise util.Abort(_('no [keyword] patterns configured'))
288 raise util.Abort(_('no [keyword] patterns configured'))
289
289
290 def _kwfwrite(ui, repo, expand, *pats, **opts):
290 def _kwfwrite(ui, repo, expand, *pats, **opts):
291 '''Selects files and passes them to kwtemplater.overwrite.'''
291 '''Selects files and passes them to kwtemplater.overwrite.'''
292 wctx = repo[None]
292 wctx = repo[None]
293 if len(wctx.parents()) > 1:
293 if len(wctx.parents()) > 1:
294 raise util.Abort(_('outstanding uncommitted merge'))
294 raise util.Abort(_('outstanding uncommitted merge'))
295 kwt = kwtools['templater']
295 kwt = kwtools['templater']
296 wlock = repo.wlock()
296 wlock = repo.wlock()
297 try:
297 try:
298 status = _status(ui, repo, kwt, *pats, **opts)
298 status = _status(ui, repo, kwt, *pats, **opts)
299 modified, added, removed, deleted, unknown, ignored, clean = status
299 modified, added, removed, deleted, unknown, ignored, clean = status
300 if modified or added or removed or deleted:
300 if modified or added or removed or deleted:
301 raise util.Abort(_('outstanding uncommitted changes'))
301 raise util.Abort(_('outstanding uncommitted changes'))
302 kwt.overwrite(wctx, clean, True, expand)
302 kwt.overwrite(wctx, clean, True, expand, None)
303 finally:
303 finally:
304 wlock.release()
304 wlock.release()
305
305
306 def demo(ui, repo, *args, **opts):
306 def demo(ui, repo, *args, **opts):
307 '''print [keywordmaps] configuration and an expansion example
307 '''print [keywordmaps] configuration and an expansion example
308
308
309 Show current, custom, or default keyword template maps and their
309 Show current, custom, or default keyword template maps and their
310 expansions.
310 expansions.
311
311
312 Extend the current configuration by specifying maps as arguments
312 Extend the current configuration by specifying maps as arguments
313 and using -f/--rcfile to source an external hgrc file.
313 and using -f/--rcfile to source an external hgrc file.
314
314
315 Use -d/--default to disable current configuration.
315 Use -d/--default to disable current configuration.
316
316
317 See :hg:`help templates` for information on templates and filters.
317 See :hg:`help templates` for information on templates and filters.
318 '''
318 '''
319 def demoitems(section, items):
319 def demoitems(section, items):
320 ui.write('[%s]\n' % section)
320 ui.write('[%s]\n' % section)
321 for k, v in sorted(items):
321 for k, v in sorted(items):
322 ui.write('%s = %s\n' % (k, v))
322 ui.write('%s = %s\n' % (k, v))
323
323
324 fn = 'demo.txt'
324 fn = 'demo.txt'
325 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
325 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
326 ui.note(_('creating temporary repository at %s\n') % tmpdir)
326 ui.note(_('creating temporary repository at %s\n') % tmpdir)
327 repo = localrepo.localrepository(ui, tmpdir, True)
327 repo = localrepo.localrepository(ui, tmpdir, True)
328 ui.setconfig('keyword', fn, '')
328 ui.setconfig('keyword', fn, '')
329
329
330 uikwmaps = ui.configitems('keywordmaps')
330 uikwmaps = ui.configitems('keywordmaps')
331 if args or opts.get('rcfile'):
331 if args or opts.get('rcfile'):
332 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
332 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
333 if uikwmaps:
333 if uikwmaps:
334 ui.status(_('\textending current template maps\n'))
334 ui.status(_('\textending current template maps\n'))
335 if opts.get('default') or not uikwmaps:
335 if opts.get('default') or not uikwmaps:
336 ui.status(_('\toverriding default template maps\n'))
336 ui.status(_('\toverriding default template maps\n'))
337 if opts.get('rcfile'):
337 if opts.get('rcfile'):
338 ui.readconfig(opts.get('rcfile'))
338 ui.readconfig(opts.get('rcfile'))
339 if args:
339 if args:
340 # simulate hgrc parsing
340 # simulate hgrc parsing
341 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
341 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
342 fp = repo.opener('hgrc', 'w')
342 fp = repo.opener('hgrc', 'w')
343 fp.writelines(rcmaps)
343 fp.writelines(rcmaps)
344 fp.close()
344 fp.close()
345 ui.readconfig(repo.join('hgrc'))
345 ui.readconfig(repo.join('hgrc'))
346 kwmaps = dict(ui.configitems('keywordmaps'))
346 kwmaps = dict(ui.configitems('keywordmaps'))
347 elif opts.get('default'):
347 elif opts.get('default'):
348 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
348 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
349 kwmaps = _defaultkwmaps(ui)
349 kwmaps = _defaultkwmaps(ui)
350 if uikwmaps:
350 if uikwmaps:
351 ui.status(_('\tdisabling current template maps\n'))
351 ui.status(_('\tdisabling current template maps\n'))
352 for k, v in kwmaps.iteritems():
352 for k, v in kwmaps.iteritems():
353 ui.setconfig('keywordmaps', k, v)
353 ui.setconfig('keywordmaps', k, v)
354 else:
354 else:
355 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
355 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
356 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
356 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
357
357
358 uisetup(ui)
358 uisetup(ui)
359 reposetup(ui, repo)
359 reposetup(ui, repo)
360 ui.write('[extensions]\nkeyword =\n')
360 ui.write('[extensions]\nkeyword =\n')
361 demoitems('keyword', ui.configitems('keyword'))
361 demoitems('keyword', ui.configitems('keyword'))
362 demoitems('keywordmaps', kwmaps.iteritems())
362 demoitems('keywordmaps', kwmaps.iteritems())
363 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
363 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
364 repo.wopener(fn, 'w').write(keywords)
364 repo.wopener(fn, 'w').write(keywords)
365 repo[None].add([fn])
365 repo[None].add([fn])
366 ui.note(_('\nkeywords written to %s:\n') % fn)
366 ui.note(_('\nkeywords written to %s:\n') % fn)
367 ui.note(keywords)
367 ui.note(keywords)
368 repo.dirstate.setbranch('demobranch')
368 repo.dirstate.setbranch('demobranch')
369 for name, cmd in ui.configitems('hooks'):
369 for name, cmd in ui.configitems('hooks'):
370 if name.split('.', 1)[0].find('commit') > -1:
370 if name.split('.', 1)[0].find('commit') > -1:
371 repo.ui.setconfig('hooks', name, '')
371 repo.ui.setconfig('hooks', name, '')
372 msg = _('hg keyword configuration and expansion example')
372 msg = _('hg keyword configuration and expansion example')
373 ui.note("hg ci -m '%s'\n" % msg)
373 ui.note("hg ci -m '%s'\n" % msg)
374 repo.commit(text=msg)
374 repo.commit(text=msg)
375 ui.status(_('\n\tkeywords expanded\n'))
375 ui.status(_('\n\tkeywords expanded\n'))
376 ui.write(repo.wread(fn))
376 ui.write(repo.wread(fn))
377 shutil.rmtree(tmpdir, ignore_errors=True)
377 shutil.rmtree(tmpdir, ignore_errors=True)
378
378
379 def expand(ui, repo, *pats, **opts):
379 def expand(ui, repo, *pats, **opts):
380 '''expand keywords in the working directory
380 '''expand keywords in the working directory
381
381
382 Run after (re)enabling keyword expansion.
382 Run after (re)enabling keyword expansion.
383
383
384 kwexpand refuses to run if given files contain local changes.
384 kwexpand refuses to run if given files contain local changes.
385 '''
385 '''
386 # 3rd argument sets expansion to True
386 # 3rd argument sets expansion to True
387 _kwfwrite(ui, repo, True, *pats, **opts)
387 _kwfwrite(ui, repo, True, *pats, **opts)
388
388
389 def files(ui, repo, *pats, **opts):
389 def files(ui, repo, *pats, **opts):
390 '''show files configured for keyword expansion
390 '''show files configured for keyword expansion
391
391
392 List which files in the working directory are matched by the
392 List which files in the working directory are matched by the
393 [keyword] configuration patterns.
393 [keyword] configuration patterns.
394
394
395 Useful to prevent inadvertent keyword expansion and to speed up
395 Useful to prevent inadvertent keyword expansion and to speed up
396 execution by including only files that are actual candidates for
396 execution by including only files that are actual candidates for
397 expansion.
397 expansion.
398
398
399 See :hg:`help keyword` on how to construct patterns both for
399 See :hg:`help keyword` on how to construct patterns both for
400 inclusion and exclusion of files.
400 inclusion and exclusion of files.
401
401
402 With -A/--all and -v/--verbose the codes used to show the status
402 With -A/--all and -v/--verbose the codes used to show the status
403 of files are::
403 of files are::
404
404
405 K = keyword expansion candidate
405 K = keyword expansion candidate
406 k = keyword expansion candidate (not tracked)
406 k = keyword expansion candidate (not tracked)
407 I = ignored
407 I = ignored
408 i = ignored (not tracked)
408 i = ignored (not tracked)
409 '''
409 '''
410 kwt = kwtools['templater']
410 kwt = kwtools['templater']
411 status = _status(ui, repo, kwt, *pats, **opts)
411 status = _status(ui, repo, kwt, *pats, **opts)
412 cwd = pats and repo.getcwd() or ''
412 cwd = pats and repo.getcwd() or ''
413 modified, added, removed, deleted, unknown, ignored, clean = status
413 modified, added, removed, deleted, unknown, ignored, clean = status
414 files = []
414 files = []
415 if not opts.get('unknown') or opts.get('all'):
415 if not opts.get('unknown') or opts.get('all'):
416 files = sorted(modified + added + clean)
416 files = sorted(modified + added + clean)
417 wctx = repo[None]
417 wctx = repo[None]
418 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
418 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
419 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
419 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
420 if not opts.get('ignore') or opts.get('all'):
420 if not opts.get('ignore') or opts.get('all'):
421 showfiles = kwfiles, kwunknown
421 showfiles = kwfiles, kwunknown
422 else:
422 else:
423 showfiles = [], []
423 showfiles = [], []
424 if opts.get('all') or opts.get('ignore'):
424 if opts.get('all') or opts.get('ignore'):
425 showfiles += ([f for f in files if f not in kwfiles],
425 showfiles += ([f for f in files if f not in kwfiles],
426 [f for f in unknown if f not in kwunknown])
426 [f for f in unknown if f not in kwunknown])
427 for char, filenames in zip('KkIi', showfiles):
427 for char, filenames in zip('KkIi', showfiles):
428 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
428 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
429 for f in filenames:
429 for f in filenames:
430 ui.write(fmt % repo.pathto(f, cwd))
430 ui.write(fmt % repo.pathto(f, cwd))
431
431
432 def shrink(ui, repo, *pats, **opts):
432 def shrink(ui, repo, *pats, **opts):
433 '''revert expanded keywords in the working directory
433 '''revert expanded keywords in the working directory
434
434
435 Run before changing/disabling active keywords or if you experience
435 Run before changing/disabling active keywords or if you experience
436 problems with :hg:`import` or :hg:`merge`.
436 problems with :hg:`import` or :hg:`merge`.
437
437
438 kwshrink refuses to run if given files contain local changes.
438 kwshrink refuses to run if given files contain local changes.
439 '''
439 '''
440 # 3rd argument sets expansion to False
440 # 3rd argument sets expansion to False
441 _kwfwrite(ui, repo, False, *pats, **opts)
441 _kwfwrite(ui, repo, False, *pats, **opts)
442
442
443
443
444 def uisetup(ui):
444 def uisetup(ui):
445 ''' Monkeypatches dispatch._parse to retrieve user command.'''
445 ''' Monkeypatches dispatch._parse to retrieve user command.'''
446
446
447 def kwdispatch_parse(orig, ui, args):
447 def kwdispatch_parse(orig, ui, args):
448 '''Monkeypatch dispatch._parse to obtain running hg command.'''
448 '''Monkeypatch dispatch._parse to obtain running hg command.'''
449 cmd, func, args, options, cmdoptions = orig(ui, args)
449 cmd, func, args, options, cmdoptions = orig(ui, args)
450 kwtools['hgcmd'] = cmd
450 kwtools['hgcmd'] = cmd
451 return cmd, func, args, options, cmdoptions
451 return cmd, func, args, options, cmdoptions
452
452
453 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
453 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
454
454
455 def reposetup(ui, repo):
455 def reposetup(ui, repo):
456 '''Sets up repo as kwrepo for keyword substitution.
456 '''Sets up repo as kwrepo for keyword substitution.
457 Overrides file method to return kwfilelog instead of filelog
457 Overrides file method to return kwfilelog instead of filelog
458 if file matches user configuration.
458 if file matches user configuration.
459 Wraps commit to overwrite configured files with updated
459 Wraps commit to overwrite configured files with updated
460 keyword substitutions.
460 keyword substitutions.
461 Monkeypatches patch and webcommands.'''
461 Monkeypatches patch and webcommands.'''
462
462
463 try:
463 try:
464 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
464 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
465 or '.hg' in util.splitpath(repo.root)
465 or '.hg' in util.splitpath(repo.root)
466 or repo._url.startswith('bundle:')):
466 or repo._url.startswith('bundle:')):
467 return
467 return
468 except AttributeError:
468 except AttributeError:
469 pass
469 pass
470
470
471 inc, exc = [], ['.hg*']
471 inc, exc = [], ['.hg*']
472 for pat, opt in ui.configitems('keyword'):
472 for pat, opt in ui.configitems('keyword'):
473 if opt != 'ignore':
473 if opt != 'ignore':
474 inc.append(pat)
474 inc.append(pat)
475 else:
475 else:
476 exc.append(pat)
476 exc.append(pat)
477 if not inc:
477 if not inc:
478 return
478 return
479
479
480 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
480 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
481
481
482 class kwrepo(repo.__class__):
482 class kwrepo(repo.__class__):
483 def file(self, f):
483 def file(self, f):
484 if f[0] == '/':
484 if f[0] == '/':
485 f = f[1:]
485 f = f[1:]
486 return kwfilelog(self.sopener, kwt, f)
486 return kwfilelog(self.sopener, kwt, f)
487
487
488 def wread(self, filename):
488 def wread(self, filename):
489 data = super(kwrepo, self).wread(filename)
489 data = super(kwrepo, self).wread(filename)
490 return kwt.wread(filename, data)
490 return kwt.wread(filename, data)
491
491
492 def commit(self, *args, **opts):
492 def commit(self, *args, **opts):
493 # use custom commitctx for user commands
493 # use custom commitctx for user commands
494 # other extensions can still wrap repo.commitctx directly
494 # other extensions can still wrap repo.commitctx directly
495 self.commitctx = self.kwcommitctx
495 self.commitctx = self.kwcommitctx
496 try:
496 try:
497 return super(kwrepo, self).commit(*args, **opts)
497 return super(kwrepo, self).commit(*args, **opts)
498 finally:
498 finally:
499 del self.commitctx
499 del self.commitctx
500
500
501 def kwcommitctx(self, ctx, error=False):
501 def kwcommitctx(self, ctx, error=False):
502 n = super(kwrepo, self).commitctx(ctx, error)
502 n = super(kwrepo, self).commitctx(ctx, error)
503 # no lock needed, only called from repo.commit() which already locks
503 # no lock needed, only called from repo.commit() which already locks
504 if not kwt.record:
504 if not kwt.record:
505 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
505 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
506 False, True)
506 False, True, None)
507 return n
507 return n
508
508
509 def rollback(self, dryrun=False):
510 wlock = repo.wlock()
511 try:
512 if not dryrun:
513 cfiles = self['.'].files()
514 ret = super(kwrepo, self).rollback(dryrun)
515 if not dryrun:
516 ctx = self['.']
517 modified, added = super(kwrepo, self).status()[:2]
518 kwt.overwrite(ctx, added, True, False, cfiles)
519 kwt.overwrite(ctx, modified, True, True, cfiles)
520 return ret
521 finally:
522 wlock.release()
523
509 # monkeypatches
524 # monkeypatches
510 def kwpatchfile_init(orig, self, ui, fname, opener,
525 def kwpatchfile_init(orig, self, ui, fname, opener,
511 missing=False, eolmode=None):
526 missing=False, eolmode=None):
512 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
527 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
513 rejects or conflicts due to expanded keywords in working dir.'''
528 rejects or conflicts due to expanded keywords in working dir.'''
514 orig(self, ui, fname, opener, missing, eolmode)
529 orig(self, ui, fname, opener, missing, eolmode)
515 # shrink keywords read from working dir
530 # shrink keywords read from working dir
516 self.lines = kwt.shrinklines(self.fname, self.lines)
531 self.lines = kwt.shrinklines(self.fname, self.lines)
517
532
518 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
533 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
519 opts=None, prefix=''):
534 opts=None, prefix=''):
520 '''Monkeypatch patch.diff to avoid expansion.'''
535 '''Monkeypatch patch.diff to avoid expansion.'''
521 kwt.restrict = True
536 kwt.restrict = True
522 return orig(repo, node1, node2, match, changes, opts, prefix)
537 return orig(repo, node1, node2, match, changes, opts, prefix)
523
538
524 def kwweb_skip(orig, web, req, tmpl):
539 def kwweb_skip(orig, web, req, tmpl):
525 '''Wraps webcommands.x turning off keyword expansion.'''
540 '''Wraps webcommands.x turning off keyword expansion.'''
526 kwt.match = util.never
541 kwt.match = util.never
527 return orig(web, req, tmpl)
542 return orig(web, req, tmpl)
528
543
529 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
544 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
530 '''Wraps record.dorecord expanding keywords after recording.'''
545 '''Wraps record.dorecord expanding keywords after recording.'''
531 wlock = repo.wlock()
546 wlock = repo.wlock()
532 try:
547 try:
533 # record returns 0 even when nothing has changed
548 # record returns 0 even when nothing has changed
534 # therefore compare nodes before and after
549 # therefore compare nodes before and after
535 ctx = repo['.']
550 ctx = repo['.']
536 ret = orig(ui, repo, commitfunc, *pats, **opts)
551 ret = orig(ui, repo, commitfunc, *pats, **opts)
537 recordctx = repo['.']
552 recordctx = repo['.']
538 if ctx != recordctx:
553 if ctx != recordctx:
539 kwt.overwrite(recordctx, None, False, True)
554 kwt.overwrite(recordctx, recordctx.files(),
555 False, True, recordctx)
540 return ret
556 return ret
541 finally:
557 finally:
542 wlock.release()
558 wlock.release()
543
559
544 repo.__class__ = kwrepo
560 repo.__class__ = kwrepo
545
561
546 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
562 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
547 extensions.wrapfunction(patch, 'diff', kw_diff)
563 extensions.wrapfunction(patch, 'diff', kw_diff)
548 for c in 'annotate changeset rev filediff diff'.split():
564 for c in 'annotate changeset rev filediff diff'.split():
549 extensions.wrapfunction(webcommands, c, kwweb_skip)
565 extensions.wrapfunction(webcommands, c, kwweb_skip)
550 for name in recordextensions.split():
566 for name in recordextensions.split():
551 try:
567 try:
552 record = extensions.find(name)
568 record = extensions.find(name)
553 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
569 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
554 except KeyError:
570 except KeyError:
555 pass
571 pass
556
572
557 cmdtable = {
573 cmdtable = {
558 'kwdemo':
574 'kwdemo':
559 (demo,
575 (demo,
560 [('d', 'default', None, _('show default keyword template maps')),
576 [('d', 'default', None, _('show default keyword template maps')),
561 ('f', 'rcfile', '',
577 ('f', 'rcfile', '',
562 _('read maps from rcfile'), _('FILE'))],
578 _('read maps from rcfile'), _('FILE'))],
563 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
579 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
564 'kwexpand': (expand, commands.walkopts,
580 'kwexpand': (expand, commands.walkopts,
565 _('hg kwexpand [OPTION]... [FILE]...')),
581 _('hg kwexpand [OPTION]... [FILE]...')),
566 'kwfiles':
582 'kwfiles':
567 (files,
583 (files,
568 [('A', 'all', None, _('show keyword status flags of all files')),
584 [('A', 'all', None, _('show keyword status flags of all files')),
569 ('i', 'ignore', None, _('show files excluded from expansion')),
585 ('i', 'ignore', None, _('show files excluded from expansion')),
570 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
586 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
571 ] + commands.walkopts,
587 ] + commands.walkopts,
572 _('hg kwfiles [OPTION]... [FILE]...')),
588 _('hg kwfiles [OPTION]... [FILE]...')),
573 'kwshrink': (shrink, commands.walkopts,
589 'kwshrink': (shrink, commands.walkopts,
574 _('hg kwshrink [OPTION]... [FILE]...')),
590 _('hg kwshrink [OPTION]... [FILE]...')),
575 }
591 }
@@ -1,927 +1,965 b''
1 $ cat <<EOF >> $HGRCPATH
1 $ cat <<EOF >> $HGRCPATH
2 > [extensions]
2 > [extensions]
3 > keyword =
3 > keyword =
4 > mq =
4 > mq =
5 > notify =
5 > notify =
6 > record =
6 > record =
7 > transplant =
7 > transplant =
8 > [ui]
8 > [ui]
9 > interactive = true
9 > interactive = true
10 > EOF
10 > EOF
11
11
12 Run kwdemo before [keyword] files are set up
12 Run kwdemo before [keyword] files are set up
13 as it would succeed without uisetup otherwise
13 as it would succeed without uisetup otherwise
14
14
15 $ hg --quiet kwdemo
15 $ hg --quiet kwdemo
16 [extensions]
16 [extensions]
17 keyword =
17 keyword =
18 [keyword]
18 [keyword]
19 demo.txt =
19 demo.txt =
20 [keywordmaps]
20 [keywordmaps]
21 Author = {author|user}
21 Author = {author|user}
22 Date = {date|utcdate}
22 Date = {date|utcdate}
23 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
23 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
24 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
24 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
25 RCSFile = {file|basename},v
25 RCSFile = {file|basename},v
26 RCSfile = {file|basename},v
26 RCSfile = {file|basename},v
27 Revision = {node|short}
27 Revision = {node|short}
28 Source = {root}/{file},v
28 Source = {root}/{file},v
29 $Author: test $
29 $Author: test $
30 $Date: ????/??/?? ??:??:?? $ (glob)
30 $Date: ????/??/?? ??:??:?? $ (glob)
31 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
31 $Header: */demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
32 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
32 $Id: demo.txt,v ???????????? ????/??/?? ??:??:?? test $ (glob)
33 $RCSFile: demo.txt,v $
33 $RCSFile: demo.txt,v $
34 $RCSfile: demo.txt,v $
34 $RCSfile: demo.txt,v $
35 $Revision: ???????????? $ (glob)
35 $Revision: ???????????? $ (glob)
36 $Source: */demo.txt,v $ (glob)
36 $Source: */demo.txt,v $ (glob)
37
37
38 $ hg --quiet kwdemo "Branch = {branches}"
38 $ hg --quiet kwdemo "Branch = {branches}"
39 [extensions]
39 [extensions]
40 keyword =
40 keyword =
41 [keyword]
41 [keyword]
42 demo.txt =
42 demo.txt =
43 [keywordmaps]
43 [keywordmaps]
44 Branch = {branches}
44 Branch = {branches}
45 $Branch: demobranch $
45 $Branch: demobranch $
46
46
47 $ cat <<EOF >> $HGRCPATH
47 $ cat <<EOF >> $HGRCPATH
48 > [keyword]
48 > [keyword]
49 > ** =
49 > ** =
50 > b = ignore
50 > b = ignore
51 > [hooks]
51 > [hooks]
52 > commit=
52 > commit=
53 > commit.test=cp a hooktest
53 > commit.test=cp a hooktest
54 > EOF
54 > EOF
55
55
56 $ hg init Test-bndl
56 $ hg init Test-bndl
57 $ cd Test-bndl
57 $ cd Test-bndl
58
58
59 kwshrink should exit silently in empty/invalid repo
59 kwshrink should exit silently in empty/invalid repo
60
60
61 $ hg kwshrink
61 $ hg kwshrink
62
62
63 Symlinks cannot be created on Windows.
63 Symlinks cannot be created on Windows.
64 A bundle to test this was made with:
64 A bundle to test this was made with:
65 hg init t
65 hg init t
66 cd t
66 cd t
67 echo a > a
67 echo a > a
68 ln -s a sym
68 ln -s a sym
69 hg add sym
69 hg add sym
70 hg ci -m addsym -u mercurial
70 hg ci -m addsym -u mercurial
71 hg bundle --base null ../test-keyword.hg
71 hg bundle --base null ../test-keyword.hg
72
72
73 $ hg pull -u "$TESTDIR"/test-keyword.hg
73 $ hg pull -u "$TESTDIR"/test-keyword.hg
74 pulling from *test-keyword.hg (glob)
74 pulling from *test-keyword.hg (glob)
75 requesting all changes
75 requesting all changes
76 adding changesets
76 adding changesets
77 adding manifests
77 adding manifests
78 adding file changes
78 adding file changes
79 added 1 changesets with 1 changes to 1 files
79 added 1 changesets with 1 changes to 1 files
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
80 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
81
81
82 $ echo 'expand $Id$' > a
82 $ echo 'expand $Id$' > a
83 $ echo 'do not process $Id:' >> a
83 $ echo 'do not process $Id:' >> a
84 $ echo 'xxx $' >> a
84 $ echo 'xxx $' >> a
85 $ echo 'ignore $Id$' > b
85 $ echo 'ignore $Id$' > b
86
86
87 Output files as they were created
87 Output files as they were created
88
88
89 $ cat a b
89 $ cat a b
90 expand $Id$
90 expand $Id$
91 do not process $Id:
91 do not process $Id:
92 xxx $
92 xxx $
93 ignore $Id$
93 ignore $Id$
94
94
95 no kwfiles
95 no kwfiles
96
96
97 $ hg kwfiles
97 $ hg kwfiles
98
98
99 untracked candidates
99 untracked candidates
100
100
101 $ hg -v kwfiles --unknown
101 $ hg -v kwfiles --unknown
102 k a
102 k a
103
103
104 Add files and check status
104 Add files and check status
105
105
106 $ hg addremove
106 $ hg addremove
107 adding a
107 adding a
108 adding b
108 adding b
109 $ hg status
109 $ hg status
110 A a
110 A a
111 A b
111 A b
112
112
113
113
114 Default keyword expansion including commit hook
114 Default keyword expansion including commit hook
115 Interrupted commit should not change state or run commit hook
115 Interrupted commit should not change state or run commit hook
116
116
117 $ hg --debug commit
117 $ hg --debug commit
118 abort: empty commit message
118 abort: empty commit message
119 [255]
119 [255]
120 $ hg status
120 $ hg status
121 A a
121 A a
122 A b
122 A b
123
123
124 Commit with several checks
124 Commit with several checks
125
125
126 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
126 $ hg --debug commit -mabsym -u 'User Name <user@example.com>'
127 a
127 a
128 b
128 b
129 overwriting a expanding keywords
129 overwriting a expanding keywords
130 running hook commit.test: cp a hooktest
130 running hook commit.test: cp a hooktest
131 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
131 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
132 $ hg status
132 $ hg status
133 ? hooktest
133 ? hooktest
134 $ hg debugrebuildstate
134 $ hg debugrebuildstate
135 $ hg --quiet identify
135 $ hg --quiet identify
136 ef63ca68695b
136 ef63ca68695b
137
137
138 cat files in working directory with keywords expanded
138 cat files in working directory with keywords expanded
139
139
140 $ cat a b
140 $ cat a b
141 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
141 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
142 do not process $Id:
142 do not process $Id:
143 xxx $
143 xxx $
144 ignore $Id$
144 ignore $Id$
145
145
146 hg cat files and symlink, no expansion
146 hg cat files and symlink, no expansion
147
147
148 $ hg cat sym a b && echo
148 $ hg cat sym a b && echo
149 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
149 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
150 do not process $Id:
150 do not process $Id:
151 xxx $
151 xxx $
152 ignore $Id$
152 ignore $Id$
153 a* (glob)
153 a* (glob)
154
154
155 Test hook execution
155 Test hook execution
156
156
157 $ diff a hooktest
157 $ diff a hooktest
158
158
159 Removing commit hook from config
159 Removing commit hook from config
160
160
161 $ sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nohook
161 $ sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nohook
162 $ mv "$HGRCPATH".nohook "$HGRCPATH"
162 $ mv "$HGRCPATH".nohook "$HGRCPATH"
163 $ rm hooktest
163 $ rm hooktest
164
164
165 bundle
165 bundle
166
166
167 $ hg bundle --base null ../kw.hg
167 $ hg bundle --base null ../kw.hg
168 2 changesets found
168 2 changesets found
169 $ cd ..
169 $ cd ..
170 $ hg init Test
170 $ hg init Test
171 $ cd Test
171 $ cd Test
172
172
173 Notify on pull to check whether keywords stay as is in email
173 Notify on pull to check whether keywords stay as is in email
174 ie. if patch.diff wrapper acts as it should
174 ie. if patch.diff wrapper acts as it should
175
175
176 $ cat <<EOF >> $HGRCPATH
176 $ cat <<EOF >> $HGRCPATH
177 > [hooks]
177 > [hooks]
178 > incoming.notify = python:hgext.notify.hook
178 > incoming.notify = python:hgext.notify.hook
179 > [notify]
179 > [notify]
180 > sources = pull
180 > sources = pull
181 > diffstat = False
181 > diffstat = False
182 > [reposubs]
182 > [reposubs]
183 > * = Test
183 > * = Test
184 > EOF
184 > EOF
185
185
186 Pull from bundle and trigger notify
186 Pull from bundle and trigger notify
187
187
188 $ hg pull -u ../kw.hg
188 $ hg pull -u ../kw.hg
189 pulling from ../kw.hg
189 pulling from ../kw.hg
190 requesting all changes
190 requesting all changes
191 adding changesets
191 adding changesets
192 adding manifests
192 adding manifests
193 adding file changes
193 adding file changes
194 added 2 changesets with 3 changes to 3 files
194 added 2 changesets with 3 changes to 3 files
195 Content-Type: text/plain; charset="us-ascii"
195 Content-Type: text/plain; charset="us-ascii"
196 MIME-Version: 1.0
196 MIME-Version: 1.0
197 Content-Transfer-Encoding: 7bit
197 Content-Transfer-Encoding: 7bit
198 Date: * (glob)
198 Date: * (glob)
199 Subject: changeset in * (glob)
199 Subject: changeset in * (glob)
200 From: mercurial
200 From: mercurial
201 X-Hg-Notification: changeset a2392c293916
201 X-Hg-Notification: changeset a2392c293916
202 Message-Id: <hg.a2392c293916*> (glob)
202 Message-Id: <hg.a2392c293916*> (glob)
203 To: Test
203 To: Test
204
204
205 changeset a2392c293916 in * (glob)
205 changeset a2392c293916 in * (glob)
206 details: *cmd=changeset;node=a2392c293916 (glob)
206 details: *cmd=changeset;node=a2392c293916 (glob)
207 description:
207 description:
208 addsym
208 addsym
209
209
210 diffs (6 lines):
210 diffs (6 lines):
211
211
212 diff -r 000000000000 -r a2392c293916 sym
212 diff -r 000000000000 -r a2392c293916 sym
213 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
213 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
214 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
214 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
215 @@ -0,0 +1,1 @@
215 @@ -0,0 +1,1 @@
216 +a
216 +a
217 \ No newline at end of file
217 \ No newline at end of file
218 Content-Type: text/plain; charset="us-ascii"
218 Content-Type: text/plain; charset="us-ascii"
219 MIME-Version: 1.0
219 MIME-Version: 1.0
220 Content-Transfer-Encoding: 7bit
220 Content-Transfer-Encoding: 7bit
221 Date:* (glob)
221 Date:* (glob)
222 Subject: changeset in* (glob)
222 Subject: changeset in* (glob)
223 From: User Name <user@example.com>
223 From: User Name <user@example.com>
224 X-Hg-Notification: changeset ef63ca68695b
224 X-Hg-Notification: changeset ef63ca68695b
225 Message-Id: <hg.ef63ca68695b*> (glob)
225 Message-Id: <hg.ef63ca68695b*> (glob)
226 To: Test
226 To: Test
227
227
228 changeset ef63ca68695b in * (glob)
228 changeset ef63ca68695b in * (glob)
229 details: *cmd=changeset;node=ef63ca68695b (glob)
229 details: *cmd=changeset;node=ef63ca68695b (glob)
230 description:
230 description:
231 absym
231 absym
232
232
233 diffs (12 lines):
233 diffs (12 lines):
234
234
235 diff -r a2392c293916 -r ef63ca68695b a
235 diff -r a2392c293916 -r ef63ca68695b a
236 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
236 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
237 +++ b/a Thu Jan 01 00:00:00 1970 +0000
237 +++ b/a Thu Jan 01 00:00:00 1970 +0000
238 @@ -0,0 +1,3 @@
238 @@ -0,0 +1,3 @@
239 +expand $Id$
239 +expand $Id$
240 +do not process $Id:
240 +do not process $Id:
241 +xxx $
241 +xxx $
242 diff -r a2392c293916 -r ef63ca68695b b
242 diff -r a2392c293916 -r ef63ca68695b b
243 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
243 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
244 +++ b/b Thu Jan 01 00:00:00 1970 +0000
244 +++ b/b Thu Jan 01 00:00:00 1970 +0000
245 @@ -0,0 +1,1 @@
245 @@ -0,0 +1,1 @@
246 +ignore $Id$
246 +ignore $Id$
247 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
247 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
248
248
249 Remove notify config
249 Remove notify config
250
250
251 $ sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nonotify
251 $ sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nonotify
252 $ mv "$HGRCPATH".nonotify "$HGRCPATH"
252 $ mv "$HGRCPATH".nonotify "$HGRCPATH"
253
253
254 Touch files and check with status
254 Touch files and check with status
255
255
256 $ touch a b
256 $ touch a b
257 $ hg status
257 $ hg status
258
258
259 Update and expand
259 Update and expand
260
260
261 $ rm sym a b
261 $ rm sym a b
262 $ hg update -C
262 $ hg update -C
263 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
264 $ cat a b
264 $ cat a b
265 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
265 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
266 do not process $Id:
266 do not process $Id:
267 xxx $
267 xxx $
268 ignore $Id$
268 ignore $Id$
269
269
270 Check whether expansion is filewise
270 Check whether expansion is filewise
271
271
272 $ echo '$Id$' > c
272 $ echo '$Id$' > c
273 $ echo 'tests for different changenodes' >> c
273 $ echo 'tests for different changenodes' >> c
274
274
275 commit file c
275 commit file c
276
276
277 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
277 $ hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
278 adding c
278 adding c
279
279
280 force expansion
280 force expansion
281
281
282 $ hg -v kwexpand
282 $ hg -v kwexpand
283 overwriting a expanding keywords
283 overwriting a expanding keywords
284 overwriting c expanding keywords
284 overwriting c expanding keywords
285
285
286 compare changenodes in a and c
286 compare changenodes in a and c
287
287
288 $ cat a c
288 $ cat a c
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
289 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
290 do not process $Id:
290 do not process $Id:
291 xxx $
291 xxx $
292 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
292 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
293 tests for different changenodes
293 tests for different changenodes
294
294
295 record chunk
295 record chunk
296
296
297 $ python -c \
297 $ python -c \
298 > 'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
298 > 'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
299 $ hg record -d '1 10' -m rectest<<EOF
299 $ hg record -d '1 10' -m rectest<<EOF
300 > y
300 > y
301 > y
301 > y
302 > n
302 > n
303 > EOF
303 > EOF
304 diff --git a/a b/a
304 diff --git a/a b/a
305 2 hunks, 2 lines changed
305 2 hunks, 2 lines changed
306 examine changes to 'a'? [Ynsfdaq?]
306 examine changes to 'a'? [Ynsfdaq?]
307 @@ -1,3 +1,4 @@
307 @@ -1,3 +1,4 @@
308 expand $Id$
308 expand $Id$
309 +foo
309 +foo
310 do not process $Id:
310 do not process $Id:
311 xxx $
311 xxx $
312 record change 1/2 to 'a'? [Ynsfdaq?]
312 record change 1/2 to 'a'? [Ynsfdaq?]
313 @@ -2,2 +3,3 @@
313 @@ -2,2 +3,3 @@
314 do not process $Id:
314 do not process $Id:
315 xxx $
315 xxx $
316 +bar
316 +bar
317 record change 2/2 to 'a'? [Ynsfdaq?]
317 record change 2/2 to 'a'? [Ynsfdaq?]
318
318
319 $ hg identify
319 $ hg identify
320 d17e03c92c97+ tip
320 d17e03c92c97+ tip
321 $ hg status
321 $ hg status
322 M a
322 M a
323
323
324 Cat modified file a
324 Cat modified file a
325
325
326 $ cat a
326 $ cat a
327 expand $Id: a,v d17e03c92c97 1970/01/01 00:00:01 test $
327 expand $Id: a,v d17e03c92c97 1970/01/01 00:00:01 test $
328 foo
328 foo
329 do not process $Id:
329 do not process $Id:
330 xxx $
330 xxx $
331 bar
331 bar
332
332
333 Diff remaining chunk
333 Diff remaining chunk
334
334
335 $ hg diff
335 $ hg diff
336 diff -r d17e03c92c97 a
336 diff -r d17e03c92c97 a
337 --- a/a Wed Dec 31 23:59:51 1969 -0000
337 --- a/a Wed Dec 31 23:59:51 1969 -0000
338 +++ b/a * (glob)
338 +++ b/a * (glob)
339 @@ -2,3 +2,4 @@
339 @@ -2,3 +2,4 @@
340 foo
340 foo
341 do not process $Id:
341 do not process $Id:
342 xxx $
342 xxx $
343 +bar
343 +bar
344
344
345 $ hg rollback
345 $ hg rollback
346 rolling back to revision 2 (undo commit)
346 rolling back to revision 2 (undo commit)
347
347
348 Record all chunks in file a
348 Record all chunks in file a
349
349
350 $ echo foo > msg
350 $ echo foo > msg
351
351
352 - do not use "hg record -m" here!
352 - do not use "hg record -m" here!
353
353
354 $ hg record -l msg -d '1 11'<<EOF
354 $ hg record -l msg -d '1 11'<<EOF
355 > y
355 > y
356 > y
356 > y
357 > y
357 > y
358 > EOF
358 > EOF
359 diff --git a/a b/a
359 diff --git a/a b/a
360 2 hunks, 2 lines changed
360 2 hunks, 2 lines changed
361 examine changes to 'a'? [Ynsfdaq?]
361 examine changes to 'a'? [Ynsfdaq?]
362 @@ -1,3 +1,4 @@
362 @@ -1,3 +1,4 @@
363 expand $Id$
363 expand $Id$
364 +foo
364 +foo
365 do not process $Id:
365 do not process $Id:
366 xxx $
366 xxx $
367 record change 1/2 to 'a'? [Ynsfdaq?]
367 record change 1/2 to 'a'? [Ynsfdaq?]
368 @@ -2,2 +3,3 @@
368 @@ -2,2 +3,3 @@
369 do not process $Id:
369 do not process $Id:
370 xxx $
370 xxx $
371 +bar
371 +bar
372 record change 2/2 to 'a'? [Ynsfdaq?]
372 record change 2/2 to 'a'? [Ynsfdaq?]
373
373
374 File a should be clean
374 File a should be clean
375
375
376 $ hg status -A a
376 $ hg status -A a
377 C a
377 C a
378 $ rm msg
378
379
379 $ rm msg
380 rollback and revert expansion
380 $ hg rollback
381
382 $ cat a
383 expand $Id: a,v 59f969a3b52c 1970/01/01 00:00:01 test $
384 foo
385 do not process $Id:
386 xxx $
387 bar
388 $ hg --verbose rollback
381 rolling back to revision 2 (undo commit)
389 rolling back to revision 2 (undo commit)
390 overwriting a expanding keywords
391 $ hg status a
392 M a
393 $ cat a
394 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
395 foo
396 do not process $Id:
397 xxx $
398 bar
399 $ echo '$Id$' > y
400 $ echo '$Id$' > z
401 $ hg add y
402 $ hg commit -Am "rollback only" z
403 $ cat z
404 $Id: z,v 45a5d3adce53 1970/01/01 00:00:00 test $
405 $ hg --verbose rollback
406 rolling back to revision 2 (undo commit)
407 overwriting z shrinking keywords
408
409 Only z should be overwritten
410
411 $ hg status a y z
412 M a
413 A y
414 A z
415 $ cat z
416 $Id$
417 $ hg forget y z
418 $ rm y z
419
382 $ hg update -C
420 $ hg update -C
383 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
421 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
384
422
385 Test patch queue repo
423 Test patch queue repo
386
424
387 $ hg init --mq
425 $ hg init --mq
388 $ hg qimport -r tip -n mqtest.diff
426 $ hg qimport -r tip -n mqtest.diff
389 $ hg commit --mq -m mqtest
427 $ hg commit --mq -m mqtest
390
428
391 Keywords should not be expanded in patch
429 Keywords should not be expanded in patch
392
430
393 $ cat .hg/patches/mqtest.diff
431 $ cat .hg/patches/mqtest.diff
394 # HG changeset patch
432 # HG changeset patch
395 # User User Name <user@example.com>
433 # User User Name <user@example.com>
396 # Date 1 0
434 # Date 1 0
397 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
435 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
398 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
436 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
399 cndiff
437 cndiff
400
438
401 diff -r ef63ca68695b -r 40a904bbbe4c c
439 diff -r ef63ca68695b -r 40a904bbbe4c c
402 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
440 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
403 +++ b/c Thu Jan 01 00:00:01 1970 +0000
441 +++ b/c Thu Jan 01 00:00:01 1970 +0000
404 @@ -0,0 +1,2 @@
442 @@ -0,0 +1,2 @@
405 +$Id$
443 +$Id$
406 +tests for different changenodes
444 +tests for different changenodes
407
445
408 $ hg qpop
446 $ hg qpop
409 popping mqtest.diff
447 popping mqtest.diff
410 patch queue now empty
448 patch queue now empty
411
449
412 qgoto, implying qpush, should expand
450 qgoto, implying qpush, should expand
413
451
414 $ hg qgoto mqtest.diff
452 $ hg qgoto mqtest.diff
415 applying mqtest.diff
453 applying mqtest.diff
416 now at: mqtest.diff
454 now at: mqtest.diff
417 $ cat c
455 $ cat c
418 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
456 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
419 tests for different changenodes
457 tests for different changenodes
420 $ hg cat c
458 $ hg cat c
421 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
459 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
422 tests for different changenodes
460 tests for different changenodes
423
461
424 Keywords should not be expanded in filelog
462 Keywords should not be expanded in filelog
425
463
426 $ hg --config 'extensions.keyword=!' cat c
464 $ hg --config 'extensions.keyword=!' cat c
427 $Id$
465 $Id$
428 tests for different changenodes
466 tests for different changenodes
429
467
430 qpop and move on
468 qpop and move on
431
469
432 $ hg qpop
470 $ hg qpop
433 popping mqtest.diff
471 popping mqtest.diff
434 patch queue now empty
472 patch queue now empty
435
473
436 Copy and show added kwfiles
474 Copy and show added kwfiles
437
475
438 $ hg cp a c
476 $ hg cp a c
439 $ hg kwfiles
477 $ hg kwfiles
440 a
478 a
441 c
479 c
442
480
443 Commit and show expansion in original and copy
481 Commit and show expansion in original and copy
444
482
445 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
483 $ hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
446 c
484 c
447 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
485 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
448 overwriting c expanding keywords
486 overwriting c expanding keywords
449 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
487 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
450 $ cat a c
488 $ cat a c
451 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
489 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
452 do not process $Id:
490 do not process $Id:
453 xxx $
491 xxx $
454 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
492 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
455 do not process $Id:
493 do not process $Id:
456 xxx $
494 xxx $
457
495
458 Touch copied c and check its status
496 Touch copied c and check its status
459
497
460 $ touch c
498 $ touch c
461 $ hg status
499 $ hg status
462
500
463 Test different options of hg kwfiles
501 Test different options of hg kwfiles
464
502
465 $ hg kwfiles
503 $ hg kwfiles
466 a
504 a
467 c
505 c
468 $ hg -v kwfiles --ignore
506 $ hg -v kwfiles --ignore
469 I b
507 I b
470 I sym
508 I sym
471 $ hg kwfiles --all
509 $ hg kwfiles --all
472 K a
510 K a
473 K c
511 K c
474 I b
512 I b
475 I sym
513 I sym
476
514
477 Diff specific revision
515 Diff specific revision
478
516
479 $ hg diff --rev 1
517 $ hg diff --rev 1
480 diff -r ef63ca68695b c
518 diff -r ef63ca68695b c
481 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
519 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
482 +++ b/c * (glob)
520 +++ b/c * (glob)
483 @@ -0,0 +1,3 @@
521 @@ -0,0 +1,3 @@
484 +expand $Id$
522 +expand $Id$
485 +do not process $Id:
523 +do not process $Id:
486 +xxx $
524 +xxx $
487
525
488 Status after rollback:
526 Status after rollback:
489
527
490 $ hg rollback
528 $ hg rollback
491 rolling back to revision 1 (undo commit)
529 rolling back to revision 1 (undo commit)
492 $ hg status
530 $ hg status
493 A c
531 A c
494 $ hg update --clean
532 $ hg update --clean
495 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
533 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
496
534
497 Custom keywordmaps as argument to kwdemo
535 Custom keywordmaps as argument to kwdemo
498
536
499 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
537 $ hg --quiet kwdemo "Xinfo = {author}: {desc}"
500 [extensions]
538 [extensions]
501 keyword =
539 keyword =
502 [keyword]
540 [keyword]
503 ** =
541 ** =
504 b = ignore
542 b = ignore
505 demo.txt =
543 demo.txt =
506 [keywordmaps]
544 [keywordmaps]
507 Xinfo = {author}: {desc}
545 Xinfo = {author}: {desc}
508 $Xinfo: test: hg keyword configuration and expansion example $
546 $Xinfo: test: hg keyword configuration and expansion example $
509
547
510 Configure custom keywordmaps
548 Configure custom keywordmaps
511
549
512 $ cat <<EOF >>$HGRCPATH
550 $ cat <<EOF >>$HGRCPATH
513 > [keywordmaps]
551 > [keywordmaps]
514 > Id = {file} {node|short} {date|rfc822date} {author|user}
552 > Id = {file} {node|short} {date|rfc822date} {author|user}
515 > Xinfo = {author}: {desc}
553 > Xinfo = {author}: {desc}
516 > EOF
554 > EOF
517
555
518 Cat and hg cat files before custom expansion
556 Cat and hg cat files before custom expansion
519
557
520 $ cat a b
558 $ cat a b
521 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
559 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
522 do not process $Id:
560 do not process $Id:
523 xxx $
561 xxx $
524 ignore $Id$
562 ignore $Id$
525 $ hg cat sym a b && echo
563 $ hg cat sym a b && echo
526 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
564 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
527 do not process $Id:
565 do not process $Id:
528 xxx $
566 xxx $
529 ignore $Id$
567 ignore $Id$
530 a* (glob)
568 a* (glob)
531
569
532 Write custom keyword and prepare multiline commit message
570 Write custom keyword and prepare multiline commit message
533
571
534 $ echo '$Xinfo$' >> a
572 $ echo '$Xinfo$' >> a
535 $ cat <<EOF >> log
573 $ cat <<EOF >> log
536 > firstline
574 > firstline
537 > secondline
575 > secondline
538 > EOF
576 > EOF
539
577
540 Interrupted commit should not change state
578 Interrupted commit should not change state
541
579
542 $ hg commit
580 $ hg commit
543 abort: empty commit message
581 abort: empty commit message
544 [255]
582 [255]
545 $ hg status
583 $ hg status
546 M a
584 M a
547 ? c
585 ? c
548 ? log
586 ? log
549
587
550 Commit with multiline message and custom expansion
588 Commit with multiline message and custom expansion
551
589
552 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
590 $ hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
553 a
591 a
554 overwriting a expanding keywords
592 overwriting a expanding keywords
555 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
593 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
556 $ rm log
594 $ rm log
557
595
558 Stat, verify and show custom expansion (firstline)
596 Stat, verify and show custom expansion (firstline)
559
597
560 $ hg status
598 $ hg status
561 ? c
599 ? c
562 $ hg verify
600 $ hg verify
563 checking changesets
601 checking changesets
564 checking manifests
602 checking manifests
565 crosschecking files in changesets and manifests
603 crosschecking files in changesets and manifests
566 checking files
604 checking files
567 3 files, 3 changesets, 4 total revisions
605 3 files, 3 changesets, 4 total revisions
568 $ cat a b
606 $ cat a b
569 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
607 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
570 do not process $Id:
608 do not process $Id:
571 xxx $
609 xxx $
572 $Xinfo: User Name <user@example.com>: firstline $
610 $Xinfo: User Name <user@example.com>: firstline $
573 ignore $Id$
611 ignore $Id$
574 $ hg cat sym a b && echo
612 $ hg cat sym a b && echo
575 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
613 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
576 do not process $Id:
614 do not process $Id:
577 xxx $
615 xxx $
578 $Xinfo: User Name <user@example.com>: firstline $
616 $Xinfo: User Name <user@example.com>: firstline $
579 ignore $Id$
617 ignore $Id$
580 a* (glob)
618 a* (glob)
581
619
582 annotate
620 annotate
583
621
584 $ hg annotate a
622 $ hg annotate a
585 1: expand $Id$
623 1: expand $Id$
586 1: do not process $Id:
624 1: do not process $Id:
587 1: xxx $
625 1: xxx $
588 2: $Xinfo$
626 2: $Xinfo$
589
627
590 remove with status checks
628 remove with status checks
591
629
592 $ hg debugrebuildstate
630 $ hg debugrebuildstate
593 $ hg remove a
631 $ hg remove a
594 $ hg --debug commit -m rma
632 $ hg --debug commit -m rma
595 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
633 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
596 $ hg status
634 $ hg status
597 ? c
635 ? c
598
636
599 Rollback, revert, and check expansion
637 Rollback, revert, and check expansion
600
638
601 $ hg rollback
639 $ hg rollback
602 rolling back to revision 2 (undo commit)
640 rolling back to revision 2 (undo commit)
603 $ hg status
641 $ hg status
604 R a
642 R a
605 ? c
643 ? c
606 $ hg revert --no-backup --rev tip a
644 $ hg revert --no-backup --rev tip a
607 $ cat a
645 $ cat a
608 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
646 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
609 do not process $Id:
647 do not process $Id:
610 xxx $
648 xxx $
611 $Xinfo: User Name <user@example.com>: firstline $
649 $Xinfo: User Name <user@example.com>: firstline $
612
650
613 Clone to test global and local configurations
651 Clone to test global and local configurations
614
652
615 $ cd ..
653 $ cd ..
616
654
617 Expansion in destinaton with global configuration
655 Expansion in destinaton with global configuration
618
656
619 $ hg --quiet clone Test globalconf
657 $ hg --quiet clone Test globalconf
620 $ cat globalconf/a
658 $ cat globalconf/a
621 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
659 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
622 do not process $Id:
660 do not process $Id:
623 xxx $
661 xxx $
624 $Xinfo: User Name <user@example.com>: firstline $
662 $Xinfo: User Name <user@example.com>: firstline $
625
663
626 No expansion in destination with local configuration in origin only
664 No expansion in destination with local configuration in origin only
627
665
628 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
666 $ hg --quiet --config 'keyword.**=ignore' clone Test localconf
629 $ cat localconf/a
667 $ cat localconf/a
630 expand $Id$
668 expand $Id$
631 do not process $Id:
669 do not process $Id:
632 xxx $
670 xxx $
633 $Xinfo$
671 $Xinfo$
634
672
635 Clone to test incoming
673 Clone to test incoming
636
674
637 $ hg clone -r1 Test Test-a
675 $ hg clone -r1 Test Test-a
638 requesting all changes
676 requesting all changes
639 adding changesets
677 adding changesets
640 adding manifests
678 adding manifests
641 adding file changes
679 adding file changes
642 added 2 changesets with 3 changes to 3 files
680 added 2 changesets with 3 changes to 3 files
643 updating to branch default
681 updating to branch default
644 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
682 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
645 $ cd Test-a
683 $ cd Test-a
646 $ cat <<EOF >> .hg/hgrc
684 $ cat <<EOF >> .hg/hgrc
647 > [paths]
685 > [paths]
648 > default = ../Test
686 > default = ../Test
649 > EOF
687 > EOF
650 $ hg incoming
688 $ hg incoming
651 comparing with *test-keyword.t/Test (glob)
689 comparing with *test-keyword.t/Test (glob)
652 searching for changes
690 searching for changes
653 changeset: 2:bb948857c743
691 changeset: 2:bb948857c743
654 tag: tip
692 tag: tip
655 user: User Name <user@example.com>
693 user: User Name <user@example.com>
656 date: Thu Jan 01 00:00:02 1970 +0000
694 date: Thu Jan 01 00:00:02 1970 +0000
657 summary: firstline
695 summary: firstline
658
696
659 Imported patch should not be rejected
697 Imported patch should not be rejected
660
698
661 $ sed -e 's/Id.*/& rejecttest/' a > a.new
699 $ sed -e 's/Id.*/& rejecttest/' a > a.new
662 $ mv a.new a
700 $ mv a.new a
663 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
701 $ hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
664 a
702 a
665 overwriting a expanding keywords
703 overwriting a expanding keywords
666 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
704 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
667 $ hg export -o ../rejecttest.diff tip
705 $ hg export -o ../rejecttest.diff tip
668 $ cd ../Test
706 $ cd ../Test
669 $ hg import ../rejecttest.diff
707 $ hg import ../rejecttest.diff
670 applying ../rejecttest.diff
708 applying ../rejecttest.diff
671 $ cat a b
709 $ cat a b
672 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
710 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
673 do not process $Id: rejecttest
711 do not process $Id: rejecttest
674 xxx $
712 xxx $
675 $Xinfo: User Name <user@example.com>: rejects? $
713 $Xinfo: User Name <user@example.com>: rejects? $
676 ignore $Id$
714 ignore $Id$
677
715
678 $ hg rollback
716 $ hg rollback
679 rolling back to revision 2 (undo commit)
717 rolling back to revision 2 (undo commit)
680 $ hg update --clean
718 $ hg update --clean
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
719 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
682
720
683 kwexpand/kwshrink on selected files
721 kwexpand/kwshrink on selected files
684
722
685 $ mkdir x
723 $ mkdir x
686 $ hg copy a x/a
724 $ hg copy a x/a
687 $ hg --verbose kwexpand a
725 $ hg --verbose kwexpand a
688 overwriting a expanding keywords
726 overwriting a expanding keywords
689
727
690 kwexpand x/a should abort
728 kwexpand x/a should abort
691
729
692 $ hg --verbose kwexpand x/a
730 $ hg --verbose kwexpand x/a
693 abort: outstanding uncommitted changes
731 abort: outstanding uncommitted changes
694 [255]
732 [255]
695 $ cd x
733 $ cd x
696 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
734 $ hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
697 x/a
735 x/a
698 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
736 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
699 overwriting x/a expanding keywords
737 overwriting x/a expanding keywords
700 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
738 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
701 $ cat a
739 $ cat a
702 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
740 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
703 do not process $Id:
741 do not process $Id:
704 xxx $
742 xxx $
705 $Xinfo: User Name <user@example.com>: xa $
743 $Xinfo: User Name <user@example.com>: xa $
706
744
707 kwshrink a inside directory x
745 kwshrink a inside directory x
708
746
709 $ hg --verbose kwshrink a
747 $ hg --verbose kwshrink a
710 overwriting x/a shrinking keywords
748 overwriting x/a shrinking keywords
711 $ cat a
749 $ cat a
712 expand $Id$
750 expand $Id$
713 do not process $Id:
751 do not process $Id:
714 xxx $
752 xxx $
715 $Xinfo$
753 $Xinfo$
716 $ cd ..
754 $ cd ..
717
755
718 kwexpand nonexistent
756 kwexpand nonexistent
719
757
720 $ hg kwexpand nonexistent
758 $ hg kwexpand nonexistent
721 nonexistent:* (glob)
759 nonexistent:* (glob)
722
760
723
761
724 hg serve
762 hg serve
725 - expand with hgweb file
763 - expand with hgweb file
726 - no expansion with hgweb annotate/changeset/filediff
764 - no expansion with hgweb annotate/changeset/filediff
727 - check errors
765 - check errors
728
766
729 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
767 $ hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
730 $ cat hg.pid >> $DAEMON_PIDS
768 $ cat hg.pid >> $DAEMON_PIDS
731 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/file/tip/a/?style=raw'
769 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/file/tip/a/?style=raw'
732 200 Script output follows
770 200 Script output follows
733
771
734 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
772 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
735 do not process $Id:
773 do not process $Id:
736 xxx $
774 xxx $
737 $Xinfo: User Name <user@example.com>: firstline $
775 $Xinfo: User Name <user@example.com>: firstline $
738 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/annotate/tip/a/?style=raw'
776 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/annotate/tip/a/?style=raw'
739 200 Script output follows
777 200 Script output follows
740
778
741
779
742 user@1: expand $Id$
780 user@1: expand $Id$
743 user@1: do not process $Id:
781 user@1: do not process $Id:
744 user@1: xxx $
782 user@1: xxx $
745 user@2: $Xinfo$
783 user@2: $Xinfo$
746
784
747
785
748
786
749
787
750 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/rev/tip/?style=raw'
788 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/rev/tip/?style=raw'
751 200 Script output follows
789 200 Script output follows
752
790
753
791
754 # HG changeset patch
792 # HG changeset patch
755 # User User Name <user@example.com>
793 # User User Name <user@example.com>
756 # Date 3 0
794 # Date 3 0
757 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
795 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
758 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
796 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
759 xa
797 xa
760
798
761 diff -r bb948857c743 -r b4560182a3f9 x/a
799 diff -r bb948857c743 -r b4560182a3f9 x/a
762 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
800 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
763 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
801 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
764 @@ -0,0 +1,4 @@
802 @@ -0,0 +1,4 @@
765 +expand $Id$
803 +expand $Id$
766 +do not process $Id:
804 +do not process $Id:
767 +xxx $
805 +xxx $
768 +$Xinfo$
806 +$Xinfo$
769
807
770 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/diff/bb948857c743/a?style=raw'
808 $ $TESTDIR/get-with-headers.py localhost:$HGPORT '/diff/bb948857c743/a?style=raw'
771 200 Script output follows
809 200 Script output follows
772
810
773
811
774 diff -r ef63ca68695b -r bb948857c743 a
812 diff -r ef63ca68695b -r bb948857c743 a
775 --- a/a Thu Jan 01 00:00:00 1970 +0000
813 --- a/a Thu Jan 01 00:00:00 1970 +0000
776 +++ b/a Thu Jan 01 00:00:02 1970 +0000
814 +++ b/a Thu Jan 01 00:00:02 1970 +0000
777 @@ -1,3 +1,4 @@
815 @@ -1,3 +1,4 @@
778 expand $Id$
816 expand $Id$
779 do not process $Id:
817 do not process $Id:
780 xxx $
818 xxx $
781 +$Xinfo$
819 +$Xinfo$
782
820
783
821
784
822
785
823
786 $ cat errors.log
824 $ cat errors.log
787
825
788 Prepare merge and resolve tests
826 Prepare merge and resolve tests
789
827
790 $ echo '$Id$' > m
828 $ echo '$Id$' > m
791 $ hg add m
829 $ hg add m
792 $ hg commit -m 4kw
830 $ hg commit -m 4kw
793 $ echo foo >> m
831 $ echo foo >> m
794 $ hg commit -m 5foo
832 $ hg commit -m 5foo
795
833
796 simplemerge
834 simplemerge
797
835
798 $ hg update 4
836 $ hg update 4
799 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
837 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
800 $ echo foo >> m
838 $ echo foo >> m
801 $ hg commit -m 6foo
839 $ hg commit -m 6foo
802 created new head
840 created new head
803 $ hg merge
841 $ hg merge
804 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
842 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
805 (branch merge, don't forget to commit)
843 (branch merge, don't forget to commit)
806 $ hg commit -m simplemerge
844 $ hg commit -m simplemerge
807 $ cat m
845 $ cat m
808 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
846 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
809 foo
847 foo
810
848
811 conflict: keyword should stay outside conflict zone
849 conflict: keyword should stay outside conflict zone
812
850
813 $ hg update 4
851 $ hg update 4
814 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
852 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
815 $ echo bar >> m
853 $ echo bar >> m
816 $ hg commit -m 8bar
854 $ hg commit -m 8bar
817 created new head
855 created new head
818 $ hg merge
856 $ hg merge
819 merging m
857 merging m
820 warning: conflicts during merge.
858 warning: conflicts during merge.
821 merging m failed!
859 merging m failed!
822 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
860 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
823 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
861 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
824 [1]
862 [1]
825 $ cat m
863 $ cat m
826 $Id$
864 $Id$
827 <<<<<<< local
865 <<<<<<< local
828 bar
866 bar
829 =======
867 =======
830 foo
868 foo
831 >>>>>>> other
869 >>>>>>> other
832
870
833 resolve to local
871 resolve to local
834
872
835 $ HGMERGE=internal:local hg resolve -a
873 $ HGMERGE=internal:local hg resolve -a
836 $ hg commit -m localresolve
874 $ hg commit -m localresolve
837 $ cat m
875 $ cat m
838 $Id: m 41efa6d38e9b Thu, 01 Jan 1970 00:00:00 +0000 test $
876 $Id: m 41efa6d38e9b Thu, 01 Jan 1970 00:00:00 +0000 test $
839 bar
877 bar
840
878
841 Test restricted mode with transplant -b
879 Test restricted mode with transplant -b
842
880
843 $ hg update 6
881 $ hg update 6
844 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
882 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
845 $ hg branch foo
883 $ hg branch foo
846 marked working directory as branch foo
884 marked working directory as branch foo
847 $ mv a a.bak
885 $ mv a a.bak
848 $ echo foobranch > a
886 $ echo foobranch > a
849 $ cat a.bak >> a
887 $ cat a.bak >> a
850 $ rm a.bak
888 $ rm a.bak
851 $ hg commit -m 9foobranch
889 $ hg commit -m 9foobranch
852 $ hg update default
890 $ hg update default
853 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
891 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
854 $ hg -y transplant -b foo tip
892 $ hg -y transplant -b foo tip
855 applying 4aa30d025d50
893 applying 4aa30d025d50
856 4aa30d025d50 transplanted to 5a4da427c162
894 4aa30d025d50 transplanted to 5a4da427c162
857
895
858 Expansion in changeset but not in file
896 Expansion in changeset but not in file
859
897
860 $ hg tip -p
898 $ hg tip -p
861 changeset: 11:5a4da427c162
899 changeset: 11:5a4da427c162
862 tag: tip
900 tag: tip
863 parent: 9:41efa6d38e9b
901 parent: 9:41efa6d38e9b
864 user: test
902 user: test
865 date: Thu Jan 01 00:00:00 1970 +0000
903 date: Thu Jan 01 00:00:00 1970 +0000
866 summary: 9foobranch
904 summary: 9foobranch
867
905
868 diff -r 41efa6d38e9b -r 5a4da427c162 a
906 diff -r 41efa6d38e9b -r 5a4da427c162 a
869 --- a/a Thu Jan 01 00:00:00 1970 +0000
907 --- a/a Thu Jan 01 00:00:00 1970 +0000
870 +++ b/a Thu Jan 01 00:00:00 1970 +0000
908 +++ b/a Thu Jan 01 00:00:00 1970 +0000
871 @@ -1,3 +1,4 @@
909 @@ -1,3 +1,4 @@
872 +foobranch
910 +foobranch
873 expand $Id$
911 expand $Id$
874 do not process $Id:
912 do not process $Id:
875 xxx $
913 xxx $
876
914
877 $ head -n 2 a
915 $ head -n 2 a
878 foobranch
916 foobranch
879 expand $Id: a 5a4da427c162 Thu, 01 Jan 1970 00:00:00 +0000 test $
917 expand $Id: a 5a4da427c162 Thu, 01 Jan 1970 00:00:00 +0000 test $
880
918
881 Turn off expansion
919 Turn off expansion
882
920
883 $ hg -q rollback
921 $ hg -q rollback
884 $ hg -q update -C
922 $ hg -q update -C
885
923
886 kwshrink with unknown file u
924 kwshrink with unknown file u
887
925
888 $ cp a u
926 $ cp a u
889 $ hg --verbose kwshrink
927 $ hg --verbose kwshrink
890 overwriting a shrinking keywords
928 overwriting a shrinking keywords
891 overwriting m shrinking keywords
929 overwriting m shrinking keywords
892 overwriting x/a shrinking keywords
930 overwriting x/a shrinking keywords
893
931
894 Keywords shrunk in working directory, but not yet disabled
932 Keywords shrunk in working directory, but not yet disabled
895 - cat shows unexpanded keywords
933 - cat shows unexpanded keywords
896 - hg cat shows expanded keywords
934 - hg cat shows expanded keywords
897
935
898 $ cat a b
936 $ cat a b
899 expand $Id$
937 expand $Id$
900 do not process $Id:
938 do not process $Id:
901 xxx $
939 xxx $
902 $Xinfo$
940 $Xinfo$
903 ignore $Id$
941 ignore $Id$
904 $ hg cat sym a b && echo
942 $ hg cat sym a b && echo
905 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
943 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
906 do not process $Id:
944 do not process $Id:
907 xxx $
945 xxx $
908 $Xinfo: User Name <user@example.com>: firstline $
946 $Xinfo: User Name <user@example.com>: firstline $
909 ignore $Id$
947 ignore $Id$
910 a* (glob)
948 a* (glob)
911
949
912 Now disable keyword expansion
950 Now disable keyword expansion
913
951
914 $ rm "$HGRCPATH"
952 $ rm "$HGRCPATH"
915 $ cat a b
953 $ cat a b
916 expand $Id$
954 expand $Id$
917 do not process $Id:
955 do not process $Id:
918 xxx $
956 xxx $
919 $Xinfo$
957 $Xinfo$
920 ignore $Id$
958 ignore $Id$
921 $ hg cat sym a b && echo
959 $ hg cat sym a b && echo
922 expand $Id$
960 expand $Id$
923 do not process $Id:
961 do not process $Id:
924 xxx $
962 xxx $
925 $Xinfo$
963 $Xinfo$
926 ignore $Id$
964 ignore $Id$
927 a* (glob)
965 a* (glob)
General Comments 0
You need to be logged in to leave comments. Login now