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