##// END OF EJS Templates
keyword: remove "identify" and "remove" from nokwcommands...
Alexis S. L. Carvalho -
r6157:09b00faa default
parent child Browse files
Show More
@@ -1,556 +1,556 b''
1 # keyword.py - $Keyword$ expansion for Mercurial
1 # keyword.py - $Keyword$ expansion for Mercurial
2 #
2 #
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
3 # Copyright 2007, 2008 Christian Ebert <blacktrash@gmx.net>
4 #
4 #
5 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7 #
7 #
8 # $Id$
8 # $Id$
9 #
9 #
10 # Keyword expansion hack against the grain of a DSCM
10 # Keyword expansion hack against the grain of a DSCM
11 #
11 #
12 # There are many good reasons why this is not needed in a distributed
12 # There are many good reasons why this is not needed in a distributed
13 # SCM, still it may be useful in very small projects based on single
13 # SCM, still it may be useful in very small projects based on single
14 # files (like LaTeX packages), that are mostly addressed to an audience
14 # files (like LaTeX packages), that are mostly addressed to an audience
15 # not running a version control system.
15 # not running a version control system.
16 #
16 #
17 # For in-depth discussion refer to
17 # For in-depth discussion refer to
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/KeywordPlan>.
18 # <http://www.selenic.com/mercurial/wiki/index.cgi/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 # Setup in hgrc:
24 # Setup in hgrc:
25 #
25 #
26 # [extensions]
26 # [extensions]
27 # # enable extension
27 # # enable extension
28 # hgext.keyword =
28 # hgext.keyword =
29 #
29 #
30 # Files to act upon/ignore are specified in the [keyword] section.
30 # Files to act upon/ignore are specified in the [keyword] section.
31 # Customized keyword template mappings in the [keywordmaps] section.
31 # Customized keyword template mappings in the [keywordmaps] section.
32 #
32 #
33 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
33 # Run "hg help keyword" and "hg kwdemo" to get info on configuration.
34
34
35 '''keyword expansion in local repositories
35 '''keyword expansion in local repositories
36
36
37 This extension expands RCS/CVS-like or self-customized $Keywords$
37 This extension expands RCS/CVS-like or self-customized $Keywords$
38 in tracked text files selected by your configuration.
38 in tracked text files selected by your configuration.
39
39
40 Keywords are only expanded in local repositories and not stored in
40 Keywords are only expanded in local repositories and not stored in
41 the change history. The mechanism can be regarded as a convenience
41 the change history. The mechanism can be regarded as a convenience
42 for the current user or for archive distribution.
42 for the current user or for archive distribution.
43
43
44 Configuration is done in the [keyword] and [keywordmaps] sections
44 Configuration is done in the [keyword] and [keywordmaps] sections
45 of hgrc files.
45 of hgrc files.
46
46
47 Example:
47 Example:
48
48
49 [keyword]
49 [keyword]
50 # expand keywords in every python file except those matching "x*"
50 # expand keywords in every python file except those matching "x*"
51 **.py =
51 **.py =
52 x* = ignore
52 x* = ignore
53
53
54 Note: the more specific you are in your filename patterns
54 Note: the more specific you are in your filename patterns
55 the less you lose speed in huge repos.
55 the less you lose speed in huge repos.
56
56
57 For [keywordmaps] template mapping and expansion demonstration and
57 For [keywordmaps] template mapping and expansion demonstration and
58 control run "hg kwdemo".
58 control run "hg kwdemo".
59
59
60 An additional date template filter {date|utcdate} is provided.
60 An additional date template filter {date|utcdate} is provided.
61
61
62 The default template mappings (view with "hg kwdemo -d") can be replaced
62 The default template mappings (view with "hg kwdemo -d") can be replaced
63 with customized keywords and templates.
63 with customized keywords and templates.
64 Again, run "hg kwdemo" to control the results of your config changes.
64 Again, run "hg kwdemo" to control the results of your config changes.
65
65
66 Before changing/disabling active keywords, run "hg kwshrink" to avoid
66 Before changing/disabling active keywords, run "hg kwshrink" to avoid
67 the risk of inadvertedly storing expanded keywords in the change history.
67 the risk of inadvertedly storing expanded keywords in the change history.
68
68
69 To force expansion after enabling it, or a configuration change, run
69 To force expansion after enabling it, or a configuration change, run
70 "hg kwexpand".
70 "hg kwexpand".
71
71
72 Also, when committing with the record extension or using mq's qrecord, be aware
72 Also, when committing with the record extension or using mq's qrecord, be aware
73 that keywords cannot be updated. Again, run "hg kwexpand" on the files in
73 that keywords cannot be updated. Again, run "hg kwexpand" on the files in
74 question to update keyword expansions after all changes have been checked in.
74 question to update keyword expansions after all changes have been checked in.
75
75
76 Expansions spanning more than one line and incremental expansions,
76 Expansions spanning more than one line and incremental expansions,
77 like CVS' $Log$, are not supported. A keyword template map
77 like CVS' $Log$, are not supported. A keyword template map
78 "Log = {desc}" expands to the first line of the changeset description.
78 "Log = {desc}" expands to the first line of the changeset description.
79 '''
79 '''
80
80
81 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog
81 from mercurial import commands, cmdutil, context, dispatch, filelog, revlog
82 from mercurial import patch, localrepo, templater, templatefilters, util
82 from mercurial import patch, localrepo, templater, templatefilters, util
83 from mercurial.hgweb import webcommands
83 from mercurial.hgweb import webcommands
84 from mercurial.node import *
84 from mercurial.node import *
85 from mercurial.i18n import _
85 from mercurial.i18n import _
86 import re, shutil, tempfile, time
86 import re, shutil, tempfile, time
87
87
88 commands.optionalrepo += ' kwdemo'
88 commands.optionalrepo += ' kwdemo'
89
89
90 # hg commands that do not act on keywords
90 # hg commands that do not act on keywords
91 nokwcommands = ('add addremove bundle copy export grep identify incoming init'
91 nokwcommands = ('add addremove bundle copy export grep incoming init'
92 ' log outgoing push remove rename rollback tip'
92 ' log outgoing push rename rollback tip'
93 ' convert email glog')
93 ' convert email glog')
94
94
95 # hg commands that trigger expansion only when writing to working dir,
95 # hg commands that trigger expansion only when writing to working dir,
96 # not when reading filelog, and unexpand when reading from working dir
96 # not when reading filelog, and unexpand when reading from working dir
97 restricted = 'record qfold qimport qnew qpush qrefresh qrecord'
97 restricted = 'record qfold qimport qnew qpush qrefresh qrecord'
98
98
99 def utcdate(date):
99 def utcdate(date):
100 '''Returns hgdate in cvs-like UTC format.'''
100 '''Returns hgdate in cvs-like UTC format.'''
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
101 return time.strftime('%Y/%m/%d %H:%M:%S', time.gmtime(date[0]))
102
102
103
103
104 # make keyword tools accessible
104 # make keyword tools accessible
105 kwtools = {'templater': None, 'hgcmd': None}
105 kwtools = {'templater': None, 'hgcmd': None}
106
106
107 # store originals of monkeypatches
107 # store originals of monkeypatches
108 _patchfile_init = patch.patchfile.__init__
108 _patchfile_init = patch.patchfile.__init__
109 _patch_diff = patch.diff
109 _patch_diff = patch.diff
110 _dispatch_parse = dispatch._parse
110 _dispatch_parse = dispatch._parse
111
111
112 def _kwpatchfile_init(self, ui, fname, missing=False):
112 def _kwpatchfile_init(self, ui, fname, missing=False):
113 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
113 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
114 rejects or conflicts due to expanded keywords in working dir.'''
114 rejects or conflicts due to expanded keywords in working dir.'''
115 _patchfile_init(self, ui, fname, missing=missing)
115 _patchfile_init(self, ui, fname, missing=missing)
116 # shrink keywords read from working dir
116 # shrink keywords read from working dir
117 kwt = kwtools['templater']
117 kwt = kwtools['templater']
118 self.lines = kwt.shrinklines(self.fname, self.lines)
118 self.lines = kwt.shrinklines(self.fname, self.lines)
119
119
120 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
120 def _kw_diff(repo, node1=None, node2=None, files=None, match=util.always,
121 fp=None, changes=None, opts=None):
121 fp=None, changes=None, opts=None):
122 '''Monkeypatch patch.diff to avoid expansion except when
122 '''Monkeypatch patch.diff to avoid expansion except when
123 comparing against working dir.'''
123 comparing against working dir.'''
124 if node2 is not None:
124 if node2 is not None:
125 kwtools['templater'].matcher = util.never
125 kwtools['templater'].matcher = util.never
126 elif node1 is not None and node1 != repo.changectx().node():
126 elif node1 is not None and node1 != repo.changectx().node():
127 kwtools['templater'].restrict = True
127 kwtools['templater'].restrict = True
128 _patch_diff(repo, node1=node1, node2=node2, files=files, match=match,
128 _patch_diff(repo, node1=node1, node2=node2, files=files, match=match,
129 fp=fp, changes=changes, opts=opts)
129 fp=fp, changes=changes, opts=opts)
130
130
131 def _kwweb_changeset(web, req, tmpl):
131 def _kwweb_changeset(web, req, tmpl):
132 '''Wraps webcommands.changeset turning off keyword expansion.'''
132 '''Wraps webcommands.changeset turning off keyword expansion.'''
133 kwtools['templater'].matcher = util.never
133 kwtools['templater'].matcher = util.never
134 return web.changeset(tmpl, web.changectx(req))
134 return web.changeset(tmpl, web.changectx(req))
135
135
136 def _kwweb_filediff(web, req, tmpl):
136 def _kwweb_filediff(web, req, tmpl):
137 '''Wraps webcommands.filediff turning off keyword expansion.'''
137 '''Wraps webcommands.filediff turning off keyword expansion.'''
138 kwtools['templater'].matcher = util.never
138 kwtools['templater'].matcher = util.never
139 return web.filediff(tmpl, web.filectx(req))
139 return web.filediff(tmpl, web.filectx(req))
140
140
141 def _kwdispatch_parse(ui, args):
141 def _kwdispatch_parse(ui, args):
142 '''Monkeypatch dispatch._parse to obtain running hg command.'''
142 '''Monkeypatch dispatch._parse to obtain running hg command.'''
143 cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args)
143 cmd, func, args, options, cmdoptions = _dispatch_parse(ui, args)
144 kwtools['hgcmd'] = cmd
144 kwtools['hgcmd'] = cmd
145 return cmd, func, args, options, cmdoptions
145 return cmd, func, args, options, cmdoptions
146
146
147 # dispatch._parse is run before reposetup, so wrap it here
147 # dispatch._parse is run before reposetup, so wrap it here
148 dispatch._parse = _kwdispatch_parse
148 dispatch._parse = _kwdispatch_parse
149
149
150
150
151 class kwtemplater(object):
151 class kwtemplater(object):
152 '''
152 '''
153 Sets up keyword templates, corresponding keyword regex, and
153 Sets up keyword templates, corresponding keyword regex, and
154 provides keyword substitution functions.
154 provides keyword substitution functions.
155 '''
155 '''
156 templates = {
156 templates = {
157 'Revision': '{node|short}',
157 'Revision': '{node|short}',
158 'Author': '{author|user}',
158 'Author': '{author|user}',
159 'Date': '{date|utcdate}',
159 'Date': '{date|utcdate}',
160 'RCSFile': '{file|basename},v',
160 'RCSFile': '{file|basename},v',
161 'Source': '{root}/{file},v',
161 'Source': '{root}/{file},v',
162 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
162 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
163 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
163 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
164 }
164 }
165
165
166 def __init__(self, ui, repo, inc, exc):
166 def __init__(self, ui, repo, inc, exc):
167 self.ui = ui
167 self.ui = ui
168 self.repo = repo
168 self.repo = repo
169 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
169 self.matcher = util.matcher(repo.root, inc=inc, exc=exc)[1]
170 self.restrict = kwtools['hgcmd'] in restricted.split()
170 self.restrict = kwtools['hgcmd'] in restricted.split()
171
171
172 kwmaps = self.ui.configitems('keywordmaps')
172 kwmaps = self.ui.configitems('keywordmaps')
173 if kwmaps: # override default templates
173 if kwmaps: # override default templates
174 kwmaps = [(k, templater.parsestring(v, quoted=False))
174 kwmaps = [(k, templater.parsestring(v, quoted=False))
175 for (k, v) in kwmaps]
175 for (k, v) in kwmaps]
176 self.templates = dict(kwmaps)
176 self.templates = dict(kwmaps)
177 escaped = map(re.escape, self.templates.keys())
177 escaped = map(re.escape, self.templates.keys())
178 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
178 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
179 self.re_kw = re.compile(kwpat)
179 self.re_kw = re.compile(kwpat)
180
180
181 templatefilters.filters['utcdate'] = utcdate
181 templatefilters.filters['utcdate'] = utcdate
182 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
182 self.ct = cmdutil.changeset_templater(self.ui, self.repo,
183 False, '', False)
183 False, '', False)
184
184
185 def getnode(self, path, fnode):
185 def getnode(self, path, fnode):
186 '''Derives changenode from file path and filenode.'''
186 '''Derives changenode from file path and filenode.'''
187 # used by kwfilelog.read and kwexpand
187 # used by kwfilelog.read and kwexpand
188 c = context.filectx(self.repo, path, fileid=fnode)
188 c = context.filectx(self.repo, path, fileid=fnode)
189 return c.node()
189 return c.node()
190
190
191 def substitute(self, data, path, node, subfunc):
191 def substitute(self, data, path, node, subfunc):
192 '''Replaces keywords in data with expanded template.'''
192 '''Replaces keywords in data with expanded template.'''
193 def kwsub(mobj):
193 def kwsub(mobj):
194 kw = mobj.group(1)
194 kw = mobj.group(1)
195 self.ct.use_template(self.templates[kw])
195 self.ct.use_template(self.templates[kw])
196 self.ui.pushbuffer()
196 self.ui.pushbuffer()
197 self.ct.show(changenode=node, root=self.repo.root, file=path)
197 self.ct.show(changenode=node, root=self.repo.root, file=path)
198 ekw = templatefilters.firstline(self.ui.popbuffer())
198 ekw = templatefilters.firstline(self.ui.popbuffer())
199 return '$%s: %s $' % (kw, ekw)
199 return '$%s: %s $' % (kw, ekw)
200 return subfunc(kwsub, data)
200 return subfunc(kwsub, data)
201
201
202 def expand(self, path, node, data):
202 def expand(self, path, node, data):
203 '''Returns data with keywords expanded.'''
203 '''Returns data with keywords expanded.'''
204 if not self.restrict and self.matcher(path) and not util.binary(data):
204 if not self.restrict and self.matcher(path) and not util.binary(data):
205 changenode = self.getnode(path, node)
205 changenode = self.getnode(path, node)
206 return self.substitute(data, path, changenode, self.re_kw.sub)
206 return self.substitute(data, path, changenode, self.re_kw.sub)
207 return data
207 return data
208
208
209 def iskwfile(self, path, islink):
209 def iskwfile(self, path, islink):
210 '''Returns true if path matches [keyword] pattern
210 '''Returns true if path matches [keyword] pattern
211 and is not a symbolic link.
211 and is not a symbolic link.
212 Caveat: localrepository._link fails on Windows.'''
212 Caveat: localrepository._link fails on Windows.'''
213 return self.matcher(path) and not islink(path)
213 return self.matcher(path) and not islink(path)
214
214
215 def overwrite(self, node=None, expand=True, files=None):
215 def overwrite(self, node=None, expand=True, files=None):
216 '''Overwrites selected files expanding/shrinking keywords.'''
216 '''Overwrites selected files expanding/shrinking keywords.'''
217 ctx = self.repo.changectx(node)
217 ctx = self.repo.changectx(node)
218 mf = ctx.manifest()
218 mf = ctx.manifest()
219 if node is not None: # commit
219 if node is not None: # commit
220 files = [f for f in ctx.files() if f in mf]
220 files = [f for f in ctx.files() if f in mf]
221 notify = self.ui.debug
221 notify = self.ui.debug
222 else: # kwexpand/kwshrink
222 else: # kwexpand/kwshrink
223 notify = self.ui.note
223 notify = self.ui.note
224 candidates = [f for f in files if self.iskwfile(f, mf.linkf)]
224 candidates = [f for f in files if self.iskwfile(f, mf.linkf)]
225 if candidates:
225 if candidates:
226 self.restrict = True # do not expand when reading
226 self.restrict = True # do not expand when reading
227 candidates.sort()
227 candidates.sort()
228 action = expand and 'expanding' or 'shrinking'
228 action = expand and 'expanding' or 'shrinking'
229 for f in candidates:
229 for f in candidates:
230 fp = self.repo.file(f)
230 fp = self.repo.file(f)
231 data = fp.read(mf[f])
231 data = fp.read(mf[f])
232 if util.binary(data):
232 if util.binary(data):
233 continue
233 continue
234 if expand:
234 if expand:
235 changenode = node or self.getnode(f, mf[f])
235 changenode = node or self.getnode(f, mf[f])
236 data, found = self.substitute(data, f, changenode,
236 data, found = self.substitute(data, f, changenode,
237 self.re_kw.subn)
237 self.re_kw.subn)
238 else:
238 else:
239 found = self.re_kw.search(data)
239 found = self.re_kw.search(data)
240 if found:
240 if found:
241 notify(_('overwriting %s %s keywords\n') % (f, action))
241 notify(_('overwriting %s %s keywords\n') % (f, action))
242 self.repo.wwrite(f, data, mf.flags(f))
242 self.repo.wwrite(f, data, mf.flags(f))
243 self.repo.dirstate.normal(f)
243 self.repo.dirstate.normal(f)
244 self.restrict = False
244 self.restrict = False
245
245
246 def shrinktext(self, text):
246 def shrinktext(self, text):
247 '''Unconditionally removes all keyword substitutions from text.'''
247 '''Unconditionally removes all keyword substitutions from text.'''
248 return self.re_kw.sub(r'$\1$', text)
248 return self.re_kw.sub(r'$\1$', text)
249
249
250 def shrink(self, fname, text):
250 def shrink(self, fname, text):
251 '''Returns text with all keyword substitutions removed.'''
251 '''Returns text with all keyword substitutions removed.'''
252 if self.matcher(fname) and not util.binary(text):
252 if self.matcher(fname) and not util.binary(text):
253 return self.shrinktext(text)
253 return self.shrinktext(text)
254 return text
254 return text
255
255
256 def shrinklines(self, fname, lines):
256 def shrinklines(self, fname, lines):
257 '''Returns lines with keyword substitutions removed.'''
257 '''Returns lines with keyword substitutions removed.'''
258 if self.matcher(fname):
258 if self.matcher(fname):
259 text = ''.join(lines)
259 text = ''.join(lines)
260 if not util.binary(text):
260 if not util.binary(text):
261 return self.shrinktext(text).splitlines(True)
261 return self.shrinktext(text).splitlines(True)
262 return lines
262 return lines
263
263
264 def wread(self, fname, data):
264 def wread(self, fname, data):
265 '''If in restricted mode returns data read from wdir with
265 '''If in restricted mode returns data read from wdir with
266 keyword substitutions removed.'''
266 keyword substitutions removed.'''
267 return self.restrict and self.shrink(fname, data) or data
267 return self.restrict and self.shrink(fname, data) or data
268
268
269 class kwfilelog(filelog.filelog):
269 class kwfilelog(filelog.filelog):
270 '''
270 '''
271 Subclass of filelog to hook into its read, add, cmp methods.
271 Subclass of filelog to hook into its read, add, cmp methods.
272 Keywords are "stored" unexpanded, and processed on reading.
272 Keywords are "stored" unexpanded, and processed on reading.
273 '''
273 '''
274 def __init__(self, opener, path):
274 def __init__(self, opener, path):
275 super(kwfilelog, self).__init__(opener, path)
275 super(kwfilelog, self).__init__(opener, path)
276 self.kwt = kwtools['templater']
276 self.kwt = kwtools['templater']
277 self.path = path
277 self.path = path
278
278
279 def read(self, node):
279 def read(self, node):
280 '''Expands keywords when reading filelog.'''
280 '''Expands keywords when reading filelog.'''
281 data = super(kwfilelog, self).read(node)
281 data = super(kwfilelog, self).read(node)
282 return self.kwt.expand(self.path, node, data)
282 return self.kwt.expand(self.path, node, data)
283
283
284 def add(self, text, meta, tr, link, p1=None, p2=None):
284 def add(self, text, meta, tr, link, p1=None, p2=None):
285 '''Removes keyword substitutions when adding to filelog.'''
285 '''Removes keyword substitutions when adding to filelog.'''
286 text = self.kwt.shrink(self.path, text)
286 text = self.kwt.shrink(self.path, text)
287 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
287 return super(kwfilelog, self).add(text, meta, tr, link, p1=p1, p2=p2)
288
288
289 def cmp(self, node, text):
289 def cmp(self, node, text):
290 '''Removes keyword substitutions for comparison.'''
290 '''Removes keyword substitutions for comparison.'''
291 text = self.kwt.shrink(self.path, text)
291 text = self.kwt.shrink(self.path, text)
292 if self.renamed(node):
292 if self.renamed(node):
293 t2 = super(kwfilelog, self).read(node)
293 t2 = super(kwfilelog, self).read(node)
294 return t2 != text
294 return t2 != text
295 return revlog.revlog.cmp(self, node, text)
295 return revlog.revlog.cmp(self, node, text)
296
296
297 def _status(ui, repo, kwt, *pats, **opts):
297 def _status(ui, repo, kwt, *pats, **opts):
298 '''Bails out if [keyword] configuration is not active.
298 '''Bails out if [keyword] configuration is not active.
299 Returns status of working directory.'''
299 Returns status of working directory.'''
300 if kwt:
300 if kwt:
301 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
301 files, match, anypats = cmdutil.matchpats(repo, pats, opts)
302 return repo.status(files=files, match=match, list_clean=True)
302 return repo.status(files=files, match=match, list_clean=True)
303 if ui.configitems('keyword'):
303 if ui.configitems('keyword'):
304 raise util.Abort(_('[keyword] patterns cannot match'))
304 raise util.Abort(_('[keyword] patterns cannot match'))
305 raise util.Abort(_('no [keyword] patterns configured'))
305 raise util.Abort(_('no [keyword] patterns configured'))
306
306
307 def _kwfwrite(ui, repo, expand, *pats, **opts):
307 def _kwfwrite(ui, repo, expand, *pats, **opts):
308 '''Selects files and passes them to kwtemplater.overwrite.'''
308 '''Selects files and passes them to kwtemplater.overwrite.'''
309 kwt = kwtools['templater']
309 kwt = kwtools['templater']
310 status = _status(ui, repo, kwt, *pats, **opts)
310 status = _status(ui, repo, kwt, *pats, **opts)
311 modified, added, removed, deleted, unknown, ignored, clean = status
311 modified, added, removed, deleted, unknown, ignored, clean = status
312 if modified or added or removed or deleted:
312 if modified or added or removed or deleted:
313 raise util.Abort(_('outstanding uncommitted changes in given files'))
313 raise util.Abort(_('outstanding uncommitted changes in given files'))
314 wlock = lock = None
314 wlock = lock = None
315 try:
315 try:
316 wlock = repo.wlock()
316 wlock = repo.wlock()
317 lock = repo.lock()
317 lock = repo.lock()
318 kwt.overwrite(expand=expand, files=clean)
318 kwt.overwrite(expand=expand, files=clean)
319 finally:
319 finally:
320 del wlock, lock
320 del wlock, lock
321
321
322
322
323 def demo(ui, repo, *args, **opts):
323 def demo(ui, repo, *args, **opts):
324 '''print [keywordmaps] configuration and an expansion example
324 '''print [keywordmaps] configuration and an expansion example
325
325
326 Show current, custom, or default keyword template maps
326 Show current, custom, or default keyword template maps
327 and their expansion.
327 and their expansion.
328
328
329 Extend current configuration by specifying maps as arguments
329 Extend current configuration by specifying maps as arguments
330 and optionally by reading from an additional hgrc file.
330 and optionally by reading from an additional hgrc file.
331
331
332 Override current keyword template maps with "default" option.
332 Override current keyword template maps with "default" option.
333 '''
333 '''
334 def demostatus(stat):
334 def demostatus(stat):
335 ui.status(_('\n\t%s\n') % stat)
335 ui.status(_('\n\t%s\n') % stat)
336
336
337 def demoitems(section, items):
337 def demoitems(section, items):
338 ui.write('[%s]\n' % section)
338 ui.write('[%s]\n' % section)
339 for k, v in items:
339 for k, v in items:
340 ui.write('%s = %s\n' % (k, v))
340 ui.write('%s = %s\n' % (k, v))
341
341
342 msg = 'hg keyword config and expansion example'
342 msg = 'hg keyword config and expansion example'
343 kwstatus = 'current'
343 kwstatus = 'current'
344 fn = 'demo.txt'
344 fn = 'demo.txt'
345 branchname = 'demobranch'
345 branchname = 'demobranch'
346 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
346 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
347 ui.note(_('creating temporary repo at %s\n') % tmpdir)
347 ui.note(_('creating temporary repo at %s\n') % tmpdir)
348 repo = localrepo.localrepository(ui, path=tmpdir, create=True)
348 repo = localrepo.localrepository(ui, path=tmpdir, create=True)
349 ui.setconfig('keyword', fn, '')
349 ui.setconfig('keyword', fn, '')
350 if args or opts.get('rcfile'):
350 if args or opts.get('rcfile'):
351 kwstatus = 'custom'
351 kwstatus = 'custom'
352 if opts.get('rcfile'):
352 if opts.get('rcfile'):
353 ui.readconfig(opts.get('rcfile'))
353 ui.readconfig(opts.get('rcfile'))
354 if opts.get('default'):
354 if opts.get('default'):
355 kwstatus = 'default'
355 kwstatus = 'default'
356 kwmaps = kwtemplater.templates
356 kwmaps = kwtemplater.templates
357 if ui.configitems('keywordmaps'):
357 if ui.configitems('keywordmaps'):
358 # override maps from optional rcfile
358 # override maps from optional rcfile
359 for k, v in kwmaps.iteritems():
359 for k, v in kwmaps.iteritems():
360 ui.setconfig('keywordmaps', k, v)
360 ui.setconfig('keywordmaps', k, v)
361 elif args:
361 elif args:
362 # simulate hgrc parsing
362 # simulate hgrc parsing
363 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
363 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
364 fp = repo.opener('hgrc', 'w')
364 fp = repo.opener('hgrc', 'w')
365 fp.writelines(rcmaps)
365 fp.writelines(rcmaps)
366 fp.close()
366 fp.close()
367 ui.readconfig(repo.join('hgrc'))
367 ui.readconfig(repo.join('hgrc'))
368 if not opts.get('default'):
368 if not opts.get('default'):
369 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
369 kwmaps = dict(ui.configitems('keywordmaps')) or kwtemplater.templates
370 reposetup(ui, repo)
370 reposetup(ui, repo)
371 for k, v in ui.configitems('extensions'):
371 for k, v in ui.configitems('extensions'):
372 if k.endswith('keyword'):
372 if k.endswith('keyword'):
373 extension = '%s = %s' % (k, v)
373 extension = '%s = %s' % (k, v)
374 break
374 break
375 demostatus('config using %s keyword template maps' % kwstatus)
375 demostatus('config using %s keyword template maps' % kwstatus)
376 ui.write('[extensions]\n%s\n' % extension)
376 ui.write('[extensions]\n%s\n' % extension)
377 demoitems('keyword', ui.configitems('keyword'))
377 demoitems('keyword', ui.configitems('keyword'))
378 demoitems('keywordmaps', kwmaps.iteritems())
378 demoitems('keywordmaps', kwmaps.iteritems())
379 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
379 keywords = '$' + '$\n$'.join(kwmaps.keys()) + '$\n'
380 repo.wopener(fn, 'w').write(keywords)
380 repo.wopener(fn, 'w').write(keywords)
381 repo.add([fn])
381 repo.add([fn])
382 path = repo.wjoin(fn)
382 path = repo.wjoin(fn)
383 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
383 ui.note(_('\n%s keywords written to %s:\n') % (kwstatus, path))
384 ui.note(keywords)
384 ui.note(keywords)
385 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
385 ui.note('\nhg -R "%s" branch "%s"\n' % (tmpdir, branchname))
386 # silence branch command if not verbose
386 # silence branch command if not verbose
387 quiet = ui.quiet
387 quiet = ui.quiet
388 ui.quiet = not ui.verbose
388 ui.quiet = not ui.verbose
389 commands.branch(ui, repo, branchname)
389 commands.branch(ui, repo, branchname)
390 ui.quiet = quiet
390 ui.quiet = quiet
391 for name, cmd in ui.configitems('hooks'):
391 for name, cmd in ui.configitems('hooks'):
392 if name.split('.', 1)[0].find('commit') > -1:
392 if name.split('.', 1)[0].find('commit') > -1:
393 repo.ui.setconfig('hooks', name, '')
393 repo.ui.setconfig('hooks', name, '')
394 ui.note(_('unhooked all commit hooks\n'))
394 ui.note(_('unhooked all commit hooks\n'))
395 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
395 ui.note('hg -R "%s" ci -m "%s"\n' % (tmpdir, msg))
396 repo.commit(text=msg)
396 repo.commit(text=msg)
397 format = ui.verbose and ' in %s' % path or ''
397 format = ui.verbose and ' in %s' % path or ''
398 demostatus('%s keywords expanded%s' % (kwstatus, format))
398 demostatus('%s keywords expanded%s' % (kwstatus, format))
399 ui.write(repo.wread(fn))
399 ui.write(repo.wread(fn))
400 ui.debug(_('\nremoving temporary repo %s\n') % tmpdir)
400 ui.debug(_('\nremoving temporary repo %s\n') % tmpdir)
401 shutil.rmtree(tmpdir, ignore_errors=True)
401 shutil.rmtree(tmpdir, ignore_errors=True)
402
402
403 def expand(ui, repo, *pats, **opts):
403 def expand(ui, repo, *pats, **opts):
404 '''expand keywords in working directory
404 '''expand keywords in working directory
405
405
406 Run after (re)enabling keyword expansion.
406 Run after (re)enabling keyword expansion.
407
407
408 kwexpand refuses to run if given files contain local changes.
408 kwexpand refuses to run if given files contain local changes.
409 '''
409 '''
410 # 3rd argument sets expansion to True
410 # 3rd argument sets expansion to True
411 _kwfwrite(ui, repo, True, *pats, **opts)
411 _kwfwrite(ui, repo, True, *pats, **opts)
412
412
413 def files(ui, repo, *pats, **opts):
413 def files(ui, repo, *pats, **opts):
414 '''print files currently configured for keyword expansion
414 '''print files currently configured for keyword expansion
415
415
416 Crosscheck which files in working directory are potential targets for
416 Crosscheck which files in working directory are potential targets for
417 keyword expansion.
417 keyword expansion.
418 That is, files matched by [keyword] config patterns but not symlinks.
418 That is, files matched by [keyword] config patterns but not symlinks.
419 '''
419 '''
420 kwt = kwtools['templater']
420 kwt = kwtools['templater']
421 status = _status(ui, repo, kwt, *pats, **opts)
421 status = _status(ui, repo, kwt, *pats, **opts)
422 modified, added, removed, deleted, unknown, ignored, clean = status
422 modified, added, removed, deleted, unknown, ignored, clean = status
423 files = modified + added + clean
423 files = modified + added + clean
424 if opts.get('untracked'):
424 if opts.get('untracked'):
425 files += unknown
425 files += unknown
426 files.sort()
426 files.sort()
427 wctx = repo.workingctx()
427 wctx = repo.workingctx()
428 islink = lambda p: 'l' in wctx.fileflags(p)
428 islink = lambda p: 'l' in wctx.fileflags(p)
429 kwfiles = [f for f in files if kwt.iskwfile(f, islink)]
429 kwfiles = [f for f in files if kwt.iskwfile(f, islink)]
430 cwd = pats and repo.getcwd() or ''
430 cwd = pats and repo.getcwd() or ''
431 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
431 kwfstats = not opts.get('ignore') and (('K', kwfiles),) or ()
432 if opts.get('all') or opts.get('ignore'):
432 if opts.get('all') or opts.get('ignore'):
433 kwfstats += (('I', [f for f in files if f not in kwfiles]),)
433 kwfstats += (('I', [f for f in files if f not in kwfiles]),)
434 for char, filenames in kwfstats:
434 for char, filenames in kwfstats:
435 format = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
435 format = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
436 for f in filenames:
436 for f in filenames:
437 ui.write(format % repo.pathto(f, cwd))
437 ui.write(format % repo.pathto(f, cwd))
438
438
439 def shrink(ui, repo, *pats, **opts):
439 def shrink(ui, repo, *pats, **opts):
440 '''revert expanded keywords in working directory
440 '''revert expanded keywords in working directory
441
441
442 Run before changing/disabling active keywords
442 Run before changing/disabling active keywords
443 or if you experience problems with "hg import" or "hg merge".
443 or if you experience problems with "hg import" or "hg merge".
444
444
445 kwshrink refuses to run if given files contain local changes.
445 kwshrink refuses to run if given files contain local changes.
446 '''
446 '''
447 # 3rd argument sets expansion to False
447 # 3rd argument sets expansion to False
448 _kwfwrite(ui, repo, False, *pats, **opts)
448 _kwfwrite(ui, repo, False, *pats, **opts)
449
449
450
450
451 def reposetup(ui, repo):
451 def reposetup(ui, repo):
452 '''Sets up repo as kwrepo for keyword substitution.
452 '''Sets up repo as kwrepo for keyword substitution.
453 Overrides file method to return kwfilelog instead of filelog
453 Overrides file method to return kwfilelog instead of filelog
454 if file matches user configuration.
454 if file matches user configuration.
455 Wraps commit to overwrite configured files with updated
455 Wraps commit to overwrite configured files with updated
456 keyword substitutions.
456 keyword substitutions.
457 This is done for local repos only, and only if there are
457 This is done for local repos only, and only if there are
458 files configured at all for keyword substitution.'''
458 files configured at all for keyword substitution.'''
459
459
460 try:
460 try:
461 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
461 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
462 or '.hg' in util.splitpath(repo.root)
462 or '.hg' in util.splitpath(repo.root)
463 or repo._url.startswith('bundle:')):
463 or repo._url.startswith('bundle:')):
464 return
464 return
465 except AttributeError:
465 except AttributeError:
466 pass
466 pass
467
467
468 inc, exc = [], ['.hg*']
468 inc, exc = [], ['.hg*']
469 for pat, opt in ui.configitems('keyword'):
469 for pat, opt in ui.configitems('keyword'):
470 if opt != 'ignore':
470 if opt != 'ignore':
471 inc.append(pat)
471 inc.append(pat)
472 else:
472 else:
473 exc.append(pat)
473 exc.append(pat)
474 if not inc:
474 if not inc:
475 return
475 return
476
476
477 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
477 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
478
478
479 class kwrepo(repo.__class__):
479 class kwrepo(repo.__class__):
480 def file(self, f):
480 def file(self, f):
481 if f[0] == '/':
481 if f[0] == '/':
482 f = f[1:]
482 f = f[1:]
483 return kwfilelog(self.sopener, f)
483 return kwfilelog(self.sopener, f)
484
484
485 def wread(self, filename):
485 def wread(self, filename):
486 data = super(kwrepo, self).wread(filename)
486 data = super(kwrepo, self).wread(filename)
487 return kwt.wread(filename, data)
487 return kwt.wread(filename, data)
488
488
489 def commit(self, files=None, text='', user=None, date=None,
489 def commit(self, files=None, text='', user=None, date=None,
490 match=util.always, force=False, force_editor=False,
490 match=util.always, force=False, force_editor=False,
491 p1=None, p2=None, extra={}, empty_ok=False):
491 p1=None, p2=None, extra={}, empty_ok=False):
492 wlock = lock = None
492 wlock = lock = None
493 _p1 = _p2 = None
493 _p1 = _p2 = None
494 try:
494 try:
495 wlock = self.wlock()
495 wlock = self.wlock()
496 lock = self.lock()
496 lock = self.lock()
497 # store and postpone commit hooks
497 # store and postpone commit hooks
498 commithooks = {}
498 commithooks = {}
499 for name, cmd in ui.configitems('hooks'):
499 for name, cmd in ui.configitems('hooks'):
500 if name.split('.', 1)[0] == 'commit':
500 if name.split('.', 1)[0] == 'commit':
501 commithooks[name] = cmd
501 commithooks[name] = cmd
502 ui.setconfig('hooks', name, None)
502 ui.setconfig('hooks', name, None)
503 if commithooks:
503 if commithooks:
504 # store parents for commit hook environment
504 # store parents for commit hook environment
505 if p1 is None:
505 if p1 is None:
506 _p1, _p2 = repo.dirstate.parents()
506 _p1, _p2 = repo.dirstate.parents()
507 else:
507 else:
508 _p1, _p2 = p1, p2 or nullid
508 _p1, _p2 = p1, p2 or nullid
509 _p1 = hex(_p1)
509 _p1 = hex(_p1)
510 if _p2 == nullid:
510 if _p2 == nullid:
511 _p2 = ''
511 _p2 = ''
512 else:
512 else:
513 _p2 = hex(_p2)
513 _p2 = hex(_p2)
514
514
515 node = super(kwrepo,
515 node = super(kwrepo,
516 self).commit(files=files, text=text, user=user,
516 self).commit(files=files, text=text, user=user,
517 date=date, match=match, force=force,
517 date=date, match=match, force=force,
518 force_editor=force_editor,
518 force_editor=force_editor,
519 p1=p1, p2=p2, extra=extra,
519 p1=p1, p2=p2, extra=extra,
520 empty_ok=empty_ok)
520 empty_ok=empty_ok)
521
521
522 # restore commit hooks
522 # restore commit hooks
523 for name, cmd in commithooks.iteritems():
523 for name, cmd in commithooks.iteritems():
524 ui.setconfig('hooks', name, cmd)
524 ui.setconfig('hooks', name, cmd)
525 if node is not None:
525 if node is not None:
526 kwt.overwrite(node=node)
526 kwt.overwrite(node=node)
527 repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
527 repo.hook('commit', node=node, parent1=_p1, parent2=_p2)
528 return node
528 return node
529 finally:
529 finally:
530 del wlock, lock
530 del wlock, lock
531
531
532 repo.__class__ = kwrepo
532 repo.__class__ = kwrepo
533 patch.patchfile.__init__ = _kwpatchfile_init
533 patch.patchfile.__init__ = _kwpatchfile_init
534 patch.diff = _kw_diff
534 patch.diff = _kw_diff
535 webcommands.changeset = webcommands.rev = _kwweb_changeset
535 webcommands.changeset = webcommands.rev = _kwweb_changeset
536 webcommands.filediff = webcommands.diff = _kwweb_filediff
536 webcommands.filediff = webcommands.diff = _kwweb_filediff
537
537
538
538
539 cmdtable = {
539 cmdtable = {
540 'kwdemo':
540 'kwdemo':
541 (demo,
541 (demo,
542 [('d', 'default', None, _('show default keyword template maps')),
542 [('d', 'default', None, _('show default keyword template maps')),
543 ('f', 'rcfile', [], _('read maps from rcfile'))],
543 ('f', 'rcfile', [], _('read maps from rcfile'))],
544 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
544 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
545 'kwexpand': (expand, commands.walkopts,
545 'kwexpand': (expand, commands.walkopts,
546 _('hg kwexpand [OPTION]... [FILE]...')),
546 _('hg kwexpand [OPTION]... [FILE]...')),
547 'kwfiles':
547 'kwfiles':
548 (files,
548 (files,
549 [('a', 'all', None, _('show keyword status flags of all files')),
549 [('a', 'all', None, _('show keyword status flags of all files')),
550 ('i', 'ignore', None, _('show files excluded from expansion')),
550 ('i', 'ignore', None, _('show files excluded from expansion')),
551 ('u', 'untracked', None, _('additionally show untracked files')),
551 ('u', 'untracked', None, _('additionally show untracked files')),
552 ] + commands.walkopts,
552 ] + commands.walkopts,
553 _('hg kwfiles [OPTION]... [FILE]...')),
553 _('hg kwfiles [OPTION]... [FILE]...')),
554 'kwshrink': (shrink, commands.walkopts,
554 'kwshrink': (shrink, commands.walkopts,
555 _('hg kwshrink [OPTION]... [FILE]...')),
555 _('hg kwshrink [OPTION]... [FILE]...')),
556 }
556 }
@@ -1,297 +1,299 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat <<EOF >> $HGRCPATH
3 cat <<EOF >> $HGRCPATH
4 [extensions]
4 [extensions]
5 hgext.keyword =
5 hgext.keyword =
6 hgext.mq =
6 hgext.mq =
7 hgext.notify =
7 hgext.notify =
8 [keyword]
8 [keyword]
9 * =
9 * =
10 b = ignore
10 b = ignore
11 [hooks]
11 [hooks]
12 commit=
12 commit=
13 commit.test=cp a hooktest
13 commit.test=cp a hooktest
14 EOF
14 EOF
15
15
16 echo % help
16 echo % help
17 hg help keyword
17 hg help keyword
18
18
19 echo % hg kwdemo
19 echo % hg kwdemo
20 hg --quiet kwdemo --default \
20 hg --quiet kwdemo --default \
21 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
21 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
22 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
22 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
23 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
23 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
24 -e 's! 20[0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]! 2000/00/00 00:00:00!'
24 -e 's! 20[0-9][0-9]/[01][0-9]/[0-3][0-9] [0-2][0-9]:[0-6][0-9]:[0-6][0-9]! 2000/00/00 00:00:00!'
25
25
26 hg --quiet kwdemo "Branch = {branches}"
26 hg --quiet kwdemo "Branch = {branches}"
27
27
28 hg init Test-bndl
28 hg init Test-bndl
29 cd Test-bndl
29 cd Test-bndl
30
30
31 echo % kwshrink should exit silently in empty/invalid repo
31 echo % kwshrink should exit silently in empty/invalid repo
32 hg kwshrink
32 hg kwshrink
33
33
34 # Symlinks cannot be created on Windows. The bundle was made with:
34 # Symlinks cannot be created on Windows. The bundle was made with:
35 #
35 #
36 # hg init t
36 # hg init t
37 # cd t
37 # cd t
38 # echo a > a
38 # echo a > a
39 # ln -s a sym
39 # ln -s a sym
40 # hg add sym
40 # hg add sym
41 # hg ci -m addsym -u mercurial
41 # hg ci -m addsym -u mercurial
42 # hg bundle --base null ../test-keyword.hg
42 # hg bundle --base null ../test-keyword.hg
43 #
43 #
44 hg pull -u "$TESTDIR/test-keyword.hg" \
44 hg pull -u "$TESTDIR/test-keyword.hg" \
45 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
45 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
46
46
47 echo 'expand $Id$' > a
47 echo 'expand $Id$' > a
48 echo 'do not process $Id:' >> a
48 echo 'do not process $Id:' >> a
49 echo 'xxx $' >> a
49 echo 'xxx $' >> a
50 echo 'ignore $Id$' > b
50 echo 'ignore $Id$' > b
51 echo % cat
51 echo % cat
52 cat a b
52 cat a b
53
53
54 echo % addremove
54 echo % addremove
55 hg addremove
55 hg addremove
56 echo % status
56 echo % status
57 hg status
57 hg status
58
58
59 echo % default keyword expansion including commit hook
59 echo % default keyword expansion including commit hook
60 echo % interrupted commit should not change state or run commit hook
60 echo % interrupted commit should not change state or run commit hook
61 hg --debug commit
61 hg --debug commit
62 echo % status
62 echo % status
63 hg status
63 hg status
64
64
65 echo % commit
65 echo % commit
66 hg --debug commit -mabsym -d '0 0' -u 'User Name <user@example.com>'
66 hg --debug commit -mabsym -d '0 0' -u 'User Name <user@example.com>'
67 echo % status
67 echo % status
68 hg status
68 hg status
69 echo % identify
69 echo % identify
70 hg debugrebuildstate
70 hg --quiet identify
71 hg --quiet identify
71 echo % cat
72 echo % cat
72 cat a b
73 cat a b
73 echo % hg cat
74 echo % hg cat
74 hg cat sym a b
75 hg cat sym a b
75
76
76 echo
77 echo
77 echo % diff a hooktest
78 echo % diff a hooktest
78 diff a hooktest
79 diff a hooktest
79
80
80 echo % removing commit hook from config
81 echo % removing commit hook from config
81 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nohook
82 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nohook
82 mv $HGRCPATH.nohook $HGRCPATH
83 mv $HGRCPATH.nohook $HGRCPATH
83 rm hooktest
84 rm hooktest
84
85
85 echo % bundle
86 echo % bundle
86 hg bundle --base null ../kw.hg
87 hg bundle --base null ../kw.hg
87
88
88 cd ..
89 cd ..
89 hg init Test
90 hg init Test
90 cd Test
91 cd Test
91
92
92 echo % notify on pull to check whether keywords stay as is in email
93 echo % notify on pull to check whether keywords stay as is in email
93 echo % ie. if patch.diff wrapper acts as it should
94 echo % ie. if patch.diff wrapper acts as it should
94
95
95 cat <<EOF >> $HGRCPATH
96 cat <<EOF >> $HGRCPATH
96 [hooks]
97 [hooks]
97 incoming.notify = python:hgext.notify.hook
98 incoming.notify = python:hgext.notify.hook
98 [notify]
99 [notify]
99 sources = pull
100 sources = pull
100 diffstat = False
101 diffstat = False
101 [reposubs]
102 [reposubs]
102 * = Test
103 * = Test
103 EOF
104 EOF
104
105
105 echo % pull from bundle
106 echo % pull from bundle
106 hg pull -u ../kw.hg 2>&1 | sed -e '/^Date:/,/^diffs (/ d'
107 hg pull -u ../kw.hg 2>&1 | sed -e '/^Date:/,/^diffs (/ d'
107
108
108 echo % remove notify config
109 echo % remove notify config
109 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nonotify
110 sed -e '/\[hooks\]/,$ d' $HGRCPATH > $HGRCPATH.nonotify
110 mv $HGRCPATH.nonotify $HGRCPATH
111 mv $HGRCPATH.nonotify $HGRCPATH
111
112
112 echo % touch
113 echo % touch
113 touch a b
114 touch a b
114 echo % status
115 echo % status
115 hg status
116 hg status
116
117
117 rm sym a b
118 rm sym a b
118 echo % update
119 echo % update
119 hg update
120 hg update
120 echo % cat
121 echo % cat
121 cat a b
122 cat a b
122
123
123 echo % check whether expansion is filewise
124 echo % check whether expansion is filewise
124 echo '$Id$' > c
125 echo '$Id$' > c
125 echo 'tests for different changenodes' >> c
126 echo 'tests for different changenodes' >> c
126 echo % commit c
127 echo % commit c
127 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
128 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
128 echo % force expansion
129 echo % force expansion
129 hg -v kwexpand
130 hg -v kwexpand
130 echo % compare changenodes in a c
131 echo % compare changenodes in a c
131 cat a c
132 cat a c
132
133
133 echo % qinit -c
134 echo % qinit -c
134 hg qinit -c
135 hg qinit -c
135 echo % qimport
136 echo % qimport
136 hg qimport -r tip -n mqtest.diff
137 hg qimport -r tip -n mqtest.diff
137 echo % qcommit
138 echo % qcommit
138 hg qcommit -mqtest
139 hg qcommit -mqtest
139 echo % keywords should not be expanded in patch
140 echo % keywords should not be expanded in patch
140 cat .hg/patches/mqtest.diff
141 cat .hg/patches/mqtest.diff
141 echo % qpop
142 echo % qpop
142 hg qpop
143 hg qpop
143 echo % qgoto - should imply qpush
144 echo % qgoto - should imply qpush
144 hg qgoto mqtest.diff
145 hg qgoto mqtest.diff
145 echo % cat
146 echo % cat
146 cat c
147 cat c
147 echo % qpop and move on
148 echo % qpop and move on
148 hg qpop
149 hg qpop
149
150
150 echo % copy
151 echo % copy
151 hg cp a c
152 hg cp a c
152
153
153 echo % kwfiles added
154 echo % kwfiles added
154 hg kwfiles
155 hg kwfiles
155
156
156 echo % commit
157 echo % commit
157 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
158 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
158 echo % cat a c
159 echo % cat a c
159 cat a c
160 cat a c
160 echo % touch copied c after 1 second
161 echo % touch copied c after 1 second
161 sleep 1
162 sleep 1
162 touch c
163 touch c
163 echo % status
164 echo % status
164 hg status
165 hg status
165
166
166 echo % kwfiles
167 echo % kwfiles
167 hg kwfiles
168 hg kwfiles
168
169
169 echo % diff --rev
170 echo % diff --rev
170 hg diff --rev 1 | grep -v 'b/c'
171 hg diff --rev 1 | grep -v 'b/c'
171
172
172 echo % rollback
173 echo % rollback
173 hg rollback
174 hg rollback
174 echo % status
175 echo % status
175 hg status
176 hg status
176 echo % update -C
177 echo % update -C
177 hg update --clean
178 hg update --clean
178
179
179 echo % custom keyword expansion
180 echo % custom keyword expansion
180 echo % try with kwdemo
181 echo % try with kwdemo
181 hg --quiet kwdemo "Xinfo = {author}: {desc}"
182 hg --quiet kwdemo "Xinfo = {author}: {desc}"
182
183
183 cat <<EOF >>$HGRCPATH
184 cat <<EOF >>$HGRCPATH
184 [keywordmaps]
185 [keywordmaps]
185 Id = {file} {node|short} {date|rfc822date} {author|user}
186 Id = {file} {node|short} {date|rfc822date} {author|user}
186 Xinfo = {author}: {desc}
187 Xinfo = {author}: {desc}
187 EOF
188 EOF
188
189
189 echo % cat
190 echo % cat
190 cat a b
191 cat a b
191 echo % hg cat
192 echo % hg cat
192 hg cat sym a b
193 hg cat sym a b
193
194
194 echo
195 echo
195 echo '$Xinfo$' >> a
196 echo '$Xinfo$' >> a
196 cat <<EOF >> log
197 cat <<EOF >> log
197 firstline
198 firstline
198 secondline
199 secondline
199 EOF
200 EOF
200
201
201 echo % interrupted commit should not change state
202 echo % interrupted commit should not change state
202 hg commit
203 hg commit
203 echo % status
204 echo % status
204 hg status
205 hg status
205
206
206 echo % commit
207 echo % commit
207 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
208 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
208 rm log
209 rm log
209 echo % status
210 echo % status
210 hg status
211 hg status
211
212
212 echo % cat
213 echo % cat
213 cat a b
214 cat a b
214 echo % hg cat
215 echo % hg cat
215 hg cat sym a b
216 hg cat sym a b
216 echo
217 echo
217
218
218 echo % remove
219 echo % remove
220 hg debugrebuildstate
219 hg remove a
221 hg remove a
220 hg --debug commit -m rma
222 hg --debug commit -m rma
221 echo % status
223 echo % status
222 hg status
224 hg status
223 echo % rollback
225 echo % rollback
224 hg rollback
226 hg rollback
225 echo % status
227 echo % status
226 hg status
228 hg status
227 echo % revert a
229 echo % revert a
228 hg revert --no-backup --rev tip a
230 hg revert --no-backup --rev tip a
229 echo % cat a
231 echo % cat a
230 cat a
232 cat a
231
233
232 echo % clone to test incoming
234 echo % clone to test incoming
233 cd ..
235 cd ..
234 hg clone -r1 Test Test-a
236 hg clone -r1 Test Test-a
235 cd Test-a
237 cd Test-a
236 cat <<EOF >> .hg/hgrc
238 cat <<EOF >> .hg/hgrc
237 [paths]
239 [paths]
238 default = ../Test
240 default = ../Test
239 EOF
241 EOF
240 echo % incoming
242 echo % incoming
241 # remove path to temp dir
243 # remove path to temp dir
242 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
244 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
243
245
244 sed -e 's/Id.*/& rejecttest/' a > a.new
246 sed -e 's/Id.*/& rejecttest/' a > a.new
245 mv a.new a
247 mv a.new a
246 echo % commit rejecttest
248 echo % commit rejecttest
247 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
249 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
248 echo % export
250 echo % export
249 hg export -o ../rejecttest.diff tip
251 hg export -o ../rejecttest.diff tip
250
252
251 cd ../Test
253 cd ../Test
252 echo % import
254 echo % import
253 hg import ../rejecttest.diff
255 hg import ../rejecttest.diff
254 echo % cat
256 echo % cat
255 cat a b
257 cat a b
256 echo
258 echo
257 echo % rollback
259 echo % rollback
258 hg rollback
260 hg rollback
259 echo % clean update
261 echo % clean update
260 hg update --clean
262 hg update --clean
261
263
262 echo % kwexpand/kwshrink on selected files
264 echo % kwexpand/kwshrink on selected files
263 mkdir x
265 mkdir x
264 echo % copy a x/a
266 echo % copy a x/a
265 hg copy a x/a
267 hg copy a x/a
266 echo % kwexpand a
268 echo % kwexpand a
267 hg --verbose kwexpand a
269 hg --verbose kwexpand a
268 echo % kwexpand x/a should abort
270 echo % kwexpand x/a should abort
269 hg --verbose kwexpand x/a
271 hg --verbose kwexpand x/a
270 cd x
272 cd x
271 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
273 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
272 echo % cat a
274 echo % cat a
273 cat a
275 cat a
274 echo % kwshrink a inside directory x
276 echo % kwshrink a inside directory x
275 hg --verbose kwshrink a
277 hg --verbose kwshrink a
276 echo % cat a
278 echo % cat a
277 cat a
279 cat a
278 cd ..
280 cd ..
279
281
280 echo % kwexpand nonexistent
282 echo % kwexpand nonexistent
281 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
283 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
282
284
283 echo % switch off expansion
285 echo % switch off expansion
284 echo % kwshrink with unknown file u
286 echo % kwshrink with unknown file u
285 cp a u
287 cp a u
286 hg --verbose kwshrink
288 hg --verbose kwshrink
287 echo % cat
289 echo % cat
288 cat a b
290 cat a b
289 echo % hg cat
291 echo % hg cat
290 hg cat sym a b
292 hg cat sym a b
291 echo
293 echo
292 rm $HGRCPATH
294 rm $HGRCPATH
293 echo % cat
295 echo % cat
294 cat a b
296 cat a b
295 echo % hg cat
297 echo % hg cat
296 hg cat sym a b
298 hg cat sym a b
297 echo
299 echo
General Comments 0
You need to be logged in to leave comments. Login now