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