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