##// END OF EJS Templates
Merge with stable
Matt Mackall -
r11681:c5e555e0 merge default
parent child Browse files
Show More
@@ -1,576 +1,575 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 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
38 Configuration is done in the [keyword], [keywordset] and [keywordmaps]
39 sections of hgrc files.
39 sections of hgrc files.
40
40
41 Example::
41 Example::
42
42
43 [keyword]
43 [keyword]
44 # expand keywords in every python file except those matching "x*"
44 # expand keywords in every python file except those matching "x*"
45 **.py =
45 **.py =
46 x* = ignore
46 x* = ignore
47
47
48 [keywordset]
48 [keywordset]
49 # prefer svn- over cvs-like default keywordmaps
49 # prefer svn- over cvs-like default keywordmaps
50 svn = True
50 svn = True
51
51
52 NOTE: the more specific you are in your filename patterns the less you
52 NOTE: the more specific you are in your filename patterns the less you
53 lose speed in huge repositories.
53 lose speed in huge repositories.
54
54
55 For [keywordmaps] template mapping and expansion demonstration and
55 For [keywordmaps] template mapping and expansion demonstration and
56 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
56 control run :hg:`kwdemo`. See :hg:`help templates` for a list of
57 available templates and filters.
57 available templates and filters.
58
58
59 Three additional date template filters are provided::
59 Three additional date template filters are provided::
60
60
61 utcdate "2006/09/18 15:13:13"
61 utcdate "2006/09/18 15:13:13"
62 svnutcdate "2006-09-18 15:13:13Z"
62 svnutcdate "2006-09-18 15:13:13Z"
63 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
63 svnisodate "2006-09-18 08:13:13 -700 (Mon, 18 Sep 2006)"
64
64
65 The default template mappings (view with :hg:`kwdemo -d`) can be
65 The default template mappings (view with :hg:`kwdemo -d`) can be
66 replaced with customized keywords and templates. Again, run
66 replaced with customized keywords and templates. Again, run
67 :hg:`kwdemo` to control the results of your config changes.
67 :hg:`kwdemo` to control the results of your config changes.
68
68
69 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
69 Before changing/disabling active keywords, run :hg:`kwshrink` to avoid
70 the risk of inadvertently storing expanded keywords in the change
70 the risk of inadvertently storing expanded keywords in the change
71 history.
71 history.
72
72
73 To force expansion after enabling it, or a configuration change, run
73 To force expansion after enabling it, or a configuration change, run
74 :hg:`kwexpand`.
74 :hg:`kwexpand`.
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 "Log =
77 like CVS' $Log$, are not supported. A keyword template map "Log =
78 {desc}" expands to the first line of the changeset description.
78 {desc}" expands to the first line of the changeset description.
79 '''
79 '''
80
80
81 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
81 from mercurial import commands, cmdutil, dispatch, filelog, revlog, extensions
82 from mercurial import patch, localrepo, templater, templatefilters, util, match
82 from mercurial import patch, localrepo, templater, templatefilters, util, match
83 from mercurial.hgweb import webcommands
83 from mercurial.hgweb import webcommands
84 from mercurial.i18n import _
84 from mercurial.i18n import _
85 import re, shutil, tempfile
85 import re, shutil, tempfile
86
86
87 commands.optionalrepo += ' kwdemo'
87 commands.optionalrepo += ' kwdemo'
88
88
89 # hg commands that do not act on keywords
89 # hg commands that do not act on keywords
90 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
90 nokwcommands = ('add addremove annotate bundle copy export grep incoming init'
91 ' log outgoing push rename rollback tip verify'
91 ' log outgoing push rename rollback tip verify'
92 ' convert email glog')
92 ' convert email glog')
93
93
94 # hg commands that trigger expansion only when writing to working dir,
94 # hg commands that trigger expansion only when writing to working dir,
95 # not when reading filelog, and unexpand when reading from working dir
95 # not when reading filelog, and unexpand when reading from working dir
96 restricted = 'merge record qrecord resolve transplant'
96 restricted = 'merge record qrecord resolve transplant'
97
97
98 # commands using dorecord
98 # commands using dorecord
99 recordcommands = 'record qrecord'
99 recordcommands = 'record qrecord'
100 # names of extensions using dorecord
100 # names of extensions using dorecord
101 recordextensions = 'record'
101 recordextensions = 'record'
102
102
103 # date like in cvs' $Date
103 # date like in cvs' $Date
104 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
104 utcdate = lambda x: util.datestr((x[0], 0), '%Y/%m/%d %H:%M:%S')
105 # date like in svn's $Date
105 # date like in svn's $Date
106 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
106 svnisodate = lambda x: util.datestr(x, '%Y-%m-%d %H:%M:%S %1%2 (%a, %d %b %Y)')
107 # date like in svn's $Id
107 # date like in svn's $Id
108 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
108 svnutcdate = lambda x: util.datestr((x[0], 0), '%Y-%m-%d %H:%M:%SZ')
109
109
110 # make keyword tools accessible
110 # make keyword tools accessible
111 kwtools = {'templater': None, 'hgcmd': '', 'inc': [], 'exc': ['.hg*']}
111 kwtools = {'templater': None, 'hgcmd': ''}
112
112
113
113
114 def _defaultkwmaps(ui):
114 def _defaultkwmaps(ui):
115 '''Returns default keywordmaps according to keywordset configuration.'''
115 '''Returns default keywordmaps according to keywordset configuration.'''
116 templates = {
116 templates = {
117 'Revision': '{node|short}',
117 'Revision': '{node|short}',
118 'Author': '{author|user}',
118 'Author': '{author|user}',
119 }
119 }
120 kwsets = ({
120 kwsets = ({
121 'Date': '{date|utcdate}',
121 'Date': '{date|utcdate}',
122 'RCSfile': '{file|basename},v',
122 'RCSfile': '{file|basename},v',
123 'RCSFile': '{file|basename},v', # kept for backwards compatibility
123 'RCSFile': '{file|basename},v', # kept for backwards compatibility
124 # with hg-keyword
124 # with hg-keyword
125 'Source': '{root}/{file},v',
125 'Source': '{root}/{file},v',
126 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
126 'Id': '{file|basename},v {node|short} {date|utcdate} {author|user}',
127 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
127 'Header': '{root}/{file},v {node|short} {date|utcdate} {author|user}',
128 }, {
128 }, {
129 'Date': '{date|svnisodate}',
129 'Date': '{date|svnisodate}',
130 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
130 'Id': '{file|basename},v {node|short} {date|svnutcdate} {author|user}',
131 'LastChangedRevision': '{node|short}',
131 'LastChangedRevision': '{node|short}',
132 'LastChangedBy': '{author|user}',
132 'LastChangedBy': '{author|user}',
133 'LastChangedDate': '{date|svnisodate}',
133 'LastChangedDate': '{date|svnisodate}',
134 })
134 })
135 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
135 templates.update(kwsets[ui.configbool('keywordset', 'svn')])
136 return templates
136 return templates
137
137
138 class kwtemplater(object):
138 class kwtemplater(object):
139 '''
139 '''
140 Sets up keyword templates, corresponding keyword regex, and
140 Sets up keyword templates, corresponding keyword regex, and
141 provides keyword substitution functions.
141 provides keyword substitution functions.
142 '''
142 '''
143
143
144 def __init__(self, ui, repo):
144 def __init__(self, ui, repo, inc, exc):
145 self.ui = ui
145 self.ui = ui
146 self.repo = repo
146 self.repo = repo
147 self.match = match.match(repo.root, '', [],
147 self.match = match.match(repo.root, '', [], inc, exc)
148 kwtools['inc'], kwtools['exc'])
149 self.restrict = kwtools['hgcmd'] in restricted.split()
148 self.restrict = kwtools['hgcmd'] in restricted.split()
150 self.record = kwtools['hgcmd'] in recordcommands.split()
149 self.record = kwtools['hgcmd'] in recordcommands.split()
151
150
152 kwmaps = self.ui.configitems('keywordmaps')
151 kwmaps = self.ui.configitems('keywordmaps')
153 if kwmaps: # override default templates
152 if kwmaps: # override default templates
154 self.templates = dict((k, templater.parsestring(v, False))
153 self.templates = dict((k, templater.parsestring(v, False))
155 for k, v in kwmaps)
154 for k, v in kwmaps)
156 else:
155 else:
157 self.templates = _defaultkwmaps(self.ui)
156 self.templates = _defaultkwmaps(self.ui)
158 escaped = map(re.escape, self.templates.keys())
157 escaped = map(re.escape, self.templates.keys())
159 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
158 kwpat = r'\$(%s)(: [^$\n\r]*? )??\$' % '|'.join(escaped)
160 self.re_kw = re.compile(kwpat)
159 self.re_kw = re.compile(kwpat)
161
160
162 templatefilters.filters.update({'utcdate': utcdate,
161 templatefilters.filters.update({'utcdate': utcdate,
163 'svnisodate': svnisodate,
162 'svnisodate': svnisodate,
164 'svnutcdate': svnutcdate})
163 'svnutcdate': svnutcdate})
165
164
166 def substitute(self, data, path, ctx, subfunc):
165 def substitute(self, data, path, ctx, subfunc):
167 '''Replaces keywords in data with expanded template.'''
166 '''Replaces keywords in data with expanded template.'''
168 def kwsub(mobj):
167 def kwsub(mobj):
169 kw = mobj.group(1)
168 kw = mobj.group(1)
170 ct = cmdutil.changeset_templater(self.ui, self.repo,
169 ct = cmdutil.changeset_templater(self.ui, self.repo,
171 False, None, '', False)
170 False, None, '', False)
172 ct.use_template(self.templates[kw])
171 ct.use_template(self.templates[kw])
173 self.ui.pushbuffer()
172 self.ui.pushbuffer()
174 ct.show(ctx, root=self.repo.root, file=path)
173 ct.show(ctx, root=self.repo.root, file=path)
175 ekw = templatefilters.firstline(self.ui.popbuffer())
174 ekw = templatefilters.firstline(self.ui.popbuffer())
176 return '$%s: %s $' % (kw, ekw)
175 return '$%s: %s $' % (kw, ekw)
177 return subfunc(kwsub, data)
176 return subfunc(kwsub, data)
178
177
179 def expand(self, path, node, data):
178 def expand(self, path, node, data):
180 '''Returns data with keywords expanded.'''
179 '''Returns data with keywords expanded.'''
181 if not self.restrict and self.match(path) and not util.binary(data):
180 if not self.restrict and self.match(path) and not util.binary(data):
182 ctx = self.repo.filectx(path, fileid=node).changectx()
181 ctx = self.repo.filectx(path, fileid=node).changectx()
183 return self.substitute(data, path, ctx, self.re_kw.sub)
182 return self.substitute(data, path, ctx, self.re_kw.sub)
184 return data
183 return data
185
184
186 def iskwfile(self, path, flagfunc):
185 def iskwfile(self, path, flagfunc):
187 '''Returns true if path matches [keyword] pattern
186 '''Returns true if path matches [keyword] pattern
188 and is not a symbolic link.
187 and is not a symbolic link.
189 Caveat: localrepository._link fails on Windows.'''
188 Caveat: localrepository._link fails on Windows.'''
190 return self.match(path) and not 'l' in flagfunc(path)
189 return self.match(path) and not 'l' in flagfunc(path)
191
190
192 def overwrite(self, ctx, candidates, iswctx, expand):
191 def overwrite(self, ctx, candidates, iswctx, expand):
193 '''Overwrites selected files expanding/shrinking keywords.'''
192 '''Overwrites selected files expanding/shrinking keywords.'''
194 if self.record:
193 if self.record:
195 candidates = [f for f in ctx.files() if f in ctx]
194 candidates = [f for f in ctx.files() if f in ctx]
196 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
195 candidates = [f for f in candidates if self.iskwfile(f, ctx.flags)]
197 if candidates:
196 if candidates:
198 self.restrict = True # do not expand when reading
197 self.restrict = True # do not expand when reading
199 mf = ctx.manifest()
198 mf = ctx.manifest()
200 msg = (expand and _('overwriting %s expanding keywords\n')
199 msg = (expand and _('overwriting %s expanding keywords\n')
201 or _('overwriting %s shrinking keywords\n'))
200 or _('overwriting %s shrinking keywords\n'))
202 for f in candidates:
201 for f in candidates:
203 if not self.record:
202 if not self.record:
204 data = self.repo.file(f).read(mf[f])
203 data = self.repo.file(f).read(mf[f])
205 else:
204 else:
206 data = self.repo.wread(f)
205 data = self.repo.wread(f)
207 if util.binary(data):
206 if util.binary(data):
208 continue
207 continue
209 if expand:
208 if expand:
210 if iswctx:
209 if iswctx:
211 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
210 ctx = self.repo.filectx(f, fileid=mf[f]).changectx()
212 data, found = self.substitute(data, f, ctx,
211 data, found = self.substitute(data, f, ctx,
213 self.re_kw.subn)
212 self.re_kw.subn)
214 else:
213 else:
215 found = self.re_kw.search(data)
214 found = self.re_kw.search(data)
216 if found:
215 if found:
217 self.ui.note(msg % f)
216 self.ui.note(msg % f)
218 self.repo.wwrite(f, data, mf.flags(f))
217 self.repo.wwrite(f, data, mf.flags(f))
219 if iswctx:
218 if iswctx:
220 self.repo.dirstate.normal(f)
219 self.repo.dirstate.normal(f)
221 elif self.record:
220 elif self.record:
222 self.repo.dirstate.normallookup(f)
221 self.repo.dirstate.normallookup(f)
223 self.restrict = False
222 self.restrict = False
224
223
225 def shrinktext(self, text):
224 def shrinktext(self, text):
226 '''Unconditionally removes all keyword substitutions from text.'''
225 '''Unconditionally removes all keyword substitutions from text.'''
227 return self.re_kw.sub(r'$\1$', text)
226 return self.re_kw.sub(r'$\1$', text)
228
227
229 def shrink(self, fname, text):
228 def shrink(self, fname, text):
230 '''Returns text with all keyword substitutions removed.'''
229 '''Returns text with all keyword substitutions removed.'''
231 if self.match(fname) and not util.binary(text):
230 if self.match(fname) and not util.binary(text):
232 return self.shrinktext(text)
231 return self.shrinktext(text)
233 return text
232 return text
234
233
235 def shrinklines(self, fname, lines):
234 def shrinklines(self, fname, lines):
236 '''Returns lines with keyword substitutions removed.'''
235 '''Returns lines with keyword substitutions removed.'''
237 if self.match(fname):
236 if self.match(fname):
238 text = ''.join(lines)
237 text = ''.join(lines)
239 if not util.binary(text):
238 if not util.binary(text):
240 return self.shrinktext(text).splitlines(True)
239 return self.shrinktext(text).splitlines(True)
241 return lines
240 return lines
242
241
243 def wread(self, fname, data):
242 def wread(self, fname, data):
244 '''If in restricted mode returns data read from wdir with
243 '''If in restricted mode returns data read from wdir with
245 keyword substitutions removed.'''
244 keyword substitutions removed.'''
246 return self.restrict and self.shrink(fname, data) or data
245 return self.restrict and self.shrink(fname, data) or data
247
246
248 class kwfilelog(filelog.filelog):
247 class kwfilelog(filelog.filelog):
249 '''
248 '''
250 Subclass of filelog to hook into its read, add, cmp methods.
249 Subclass of filelog to hook into its read, add, cmp methods.
251 Keywords are "stored" unexpanded, and processed on reading.
250 Keywords are "stored" unexpanded, and processed on reading.
252 '''
251 '''
253 def __init__(self, opener, kwt, path):
252 def __init__(self, opener, kwt, path):
254 super(kwfilelog, self).__init__(opener, path)
253 super(kwfilelog, self).__init__(opener, path)
255 self.kwt = kwt
254 self.kwt = kwt
256 self.path = path
255 self.path = path
257
256
258 def read(self, node):
257 def read(self, node):
259 '''Expands keywords when reading filelog.'''
258 '''Expands keywords when reading filelog.'''
260 data = super(kwfilelog, self).read(node)
259 data = super(kwfilelog, self).read(node)
261 return self.kwt.expand(self.path, node, data)
260 return self.kwt.expand(self.path, node, data)
262
261
263 def add(self, text, meta, tr, link, p1=None, p2=None):
262 def add(self, text, meta, tr, link, p1=None, p2=None):
264 '''Removes keyword substitutions when adding to filelog.'''
263 '''Removes keyword substitutions when adding to filelog.'''
265 text = self.kwt.shrink(self.path, text)
264 text = self.kwt.shrink(self.path, text)
266 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
265 return super(kwfilelog, self).add(text, meta, tr, link, p1, p2)
267
266
268 def cmp(self, node, text):
267 def cmp(self, node, text):
269 '''Removes keyword substitutions for comparison.'''
268 '''Removes keyword substitutions for comparison.'''
270 text = self.kwt.shrink(self.path, text)
269 text = self.kwt.shrink(self.path, text)
271 if self.renamed(node):
270 if self.renamed(node):
272 t2 = super(kwfilelog, self).read(node)
271 t2 = super(kwfilelog, self).read(node)
273 return t2 != text
272 return t2 != text
274 return revlog.revlog.cmp(self, node, text)
273 return revlog.revlog.cmp(self, node, text)
275
274
276 def _status(ui, repo, kwt, *pats, **opts):
275 def _status(ui, repo, kwt, *pats, **opts):
277 '''Bails out if [keyword] configuration is not active.
276 '''Bails out if [keyword] configuration is not active.
278 Returns status of working directory.'''
277 Returns status of working directory.'''
279 if kwt:
278 if kwt:
280 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
279 return repo.status(match=cmdutil.match(repo, pats, opts), clean=True,
281 unknown=opts.get('unknown') or opts.get('all'))
280 unknown=opts.get('unknown') or opts.get('all'))
282 if ui.configitems('keyword'):
281 if ui.configitems('keyword'):
283 raise util.Abort(_('[keyword] patterns cannot match'))
282 raise util.Abort(_('[keyword] patterns cannot match'))
284 raise util.Abort(_('no [keyword] patterns configured'))
283 raise util.Abort(_('no [keyword] patterns configured'))
285
284
286 def _kwfwrite(ui, repo, expand, *pats, **opts):
285 def _kwfwrite(ui, repo, expand, *pats, **opts):
287 '''Selects files and passes them to kwtemplater.overwrite.'''
286 '''Selects files and passes them to kwtemplater.overwrite.'''
288 wctx = repo[None]
287 wctx = repo[None]
289 if len(wctx.parents()) > 1:
288 if len(wctx.parents()) > 1:
290 raise util.Abort(_('outstanding uncommitted merge'))
289 raise util.Abort(_('outstanding uncommitted merge'))
291 kwt = kwtools['templater']
290 kwt = kwtools['templater']
292 wlock = repo.wlock()
291 wlock = repo.wlock()
293 try:
292 try:
294 status = _status(ui, repo, kwt, *pats, **opts)
293 status = _status(ui, repo, kwt, *pats, **opts)
295 modified, added, removed, deleted, unknown, ignored, clean = status
294 modified, added, removed, deleted, unknown, ignored, clean = status
296 if modified or added or removed or deleted:
295 if modified or added or removed or deleted:
297 raise util.Abort(_('outstanding uncommitted changes'))
296 raise util.Abort(_('outstanding uncommitted changes'))
298 kwt.overwrite(wctx, clean, True, expand)
297 kwt.overwrite(wctx, clean, True, expand)
299 finally:
298 finally:
300 wlock.release()
299 wlock.release()
301
300
302 def demo(ui, repo, *args, **opts):
301 def demo(ui, repo, *args, **opts):
303 '''print [keywordmaps] configuration and an expansion example
302 '''print [keywordmaps] configuration and an expansion example
304
303
305 Show current, custom, or default keyword template maps and their
304 Show current, custom, or default keyword template maps and their
306 expansions.
305 expansions.
307
306
308 Extend the current configuration by specifying maps as arguments
307 Extend the current configuration by specifying maps as arguments
309 and using -f/--rcfile to source an external hgrc file.
308 and using -f/--rcfile to source an external hgrc file.
310
309
311 Use -d/--default to disable current configuration.
310 Use -d/--default to disable current configuration.
312
311
313 See :hg:`help templates` for information on templates and filters.
312 See :hg:`help templates` for information on templates and filters.
314 '''
313 '''
315 def demoitems(section, items):
314 def demoitems(section, items):
316 ui.write('[%s]\n' % section)
315 ui.write('[%s]\n' % section)
317 for k, v in sorted(items):
316 for k, v in sorted(items):
318 ui.write('%s = %s\n' % (k, v))
317 ui.write('%s = %s\n' % (k, v))
319
318
320 fn = 'demo.txt'
319 fn = 'demo.txt'
321 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
320 tmpdir = tempfile.mkdtemp('', 'kwdemo.')
322 ui.note(_('creating temporary repository at %s\n') % tmpdir)
321 ui.note(_('creating temporary repository at %s\n') % tmpdir)
323 repo = localrepo.localrepository(ui, tmpdir, True)
322 repo = localrepo.localrepository(ui, tmpdir, True)
324 ui.setconfig('keyword', fn, '')
323 ui.setconfig('keyword', fn, '')
325
324
326 uikwmaps = ui.configitems('keywordmaps')
325 uikwmaps = ui.configitems('keywordmaps')
327 if args or opts.get('rcfile'):
326 if args or opts.get('rcfile'):
328 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
327 ui.status(_('\n\tconfiguration using custom keyword template maps\n'))
329 if uikwmaps:
328 if uikwmaps:
330 ui.status(_('\textending current template maps\n'))
329 ui.status(_('\textending current template maps\n'))
331 if opts.get('default') or not uikwmaps:
330 if opts.get('default') or not uikwmaps:
332 ui.status(_('\toverriding default template maps\n'))
331 ui.status(_('\toverriding default template maps\n'))
333 if opts.get('rcfile'):
332 if opts.get('rcfile'):
334 ui.readconfig(opts.get('rcfile'))
333 ui.readconfig(opts.get('rcfile'))
335 if args:
334 if args:
336 # simulate hgrc parsing
335 # simulate hgrc parsing
337 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
336 rcmaps = ['[keywordmaps]\n'] + [a + '\n' for a in args]
338 fp = repo.opener('hgrc', 'w')
337 fp = repo.opener('hgrc', 'w')
339 fp.writelines(rcmaps)
338 fp.writelines(rcmaps)
340 fp.close()
339 fp.close()
341 ui.readconfig(repo.join('hgrc'))
340 ui.readconfig(repo.join('hgrc'))
342 kwmaps = dict(ui.configitems('keywordmaps'))
341 kwmaps = dict(ui.configitems('keywordmaps'))
343 elif opts.get('default'):
342 elif opts.get('default'):
344 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
343 ui.status(_('\n\tconfiguration using default keyword template maps\n'))
345 kwmaps = _defaultkwmaps(ui)
344 kwmaps = _defaultkwmaps(ui)
346 if uikwmaps:
345 if uikwmaps:
347 ui.status(_('\tdisabling current template maps\n'))
346 ui.status(_('\tdisabling current template maps\n'))
348 for k, v in kwmaps.iteritems():
347 for k, v in kwmaps.iteritems():
349 ui.setconfig('keywordmaps', k, v)
348 ui.setconfig('keywordmaps', k, v)
350 else:
349 else:
351 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
350 ui.status(_('\n\tconfiguration using current keyword template maps\n'))
352 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
351 kwmaps = dict(uikwmaps) or _defaultkwmaps(ui)
353
352
354 uisetup(ui)
353 uisetup(ui)
355 reposetup(ui, repo)
354 reposetup(ui, repo)
356 ui.write('[extensions]\nkeyword =\n')
355 ui.write('[extensions]\nkeyword =\n')
357 demoitems('keyword', ui.configitems('keyword'))
356 demoitems('keyword', ui.configitems('keyword'))
358 demoitems('keywordmaps', kwmaps.iteritems())
357 demoitems('keywordmaps', kwmaps.iteritems())
359 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
358 keywords = '$' + '$\n$'.join(sorted(kwmaps.keys())) + '$\n'
360 repo.wopener(fn, 'w').write(keywords)
359 repo.wopener(fn, 'w').write(keywords)
361 repo[None].add([fn])
360 repo[None].add([fn])
362 ui.note(_('\nkeywords written to %s:\n') % fn)
361 ui.note(_('\nkeywords written to %s:\n') % fn)
363 ui.note(keywords)
362 ui.note(keywords)
364 repo.dirstate.setbranch('demobranch')
363 repo.dirstate.setbranch('demobranch')
365 for name, cmd in ui.configitems('hooks'):
364 for name, cmd in ui.configitems('hooks'):
366 if name.split('.', 1)[0].find('commit') > -1:
365 if name.split('.', 1)[0].find('commit') > -1:
367 repo.ui.setconfig('hooks', name, '')
366 repo.ui.setconfig('hooks', name, '')
368 msg = _('hg keyword configuration and expansion example')
367 msg = _('hg keyword configuration and expansion example')
369 ui.note("hg ci -m '%s'\n" % msg)
368 ui.note("hg ci -m '%s'\n" % msg)
370 repo.commit(text=msg)
369 repo.commit(text=msg)
371 ui.status(_('\n\tkeywords expanded\n'))
370 ui.status(_('\n\tkeywords expanded\n'))
372 ui.write(repo.wread(fn))
371 ui.write(repo.wread(fn))
373 shutil.rmtree(tmpdir, ignore_errors=True)
372 shutil.rmtree(tmpdir, ignore_errors=True)
374
373
375 def expand(ui, repo, *pats, **opts):
374 def expand(ui, repo, *pats, **opts):
376 '''expand keywords in the working directory
375 '''expand keywords in the working directory
377
376
378 Run after (re)enabling keyword expansion.
377 Run after (re)enabling keyword expansion.
379
378
380 kwexpand refuses to run if given files contain local changes.
379 kwexpand refuses to run if given files contain local changes.
381 '''
380 '''
382 # 3rd argument sets expansion to True
381 # 3rd argument sets expansion to True
383 _kwfwrite(ui, repo, True, *pats, **opts)
382 _kwfwrite(ui, repo, True, *pats, **opts)
384
383
385 def files(ui, repo, *pats, **opts):
384 def files(ui, repo, *pats, **opts):
386 '''show files configured for keyword expansion
385 '''show files configured for keyword expansion
387
386
388 List which files in the working directory are matched by the
387 List which files in the working directory are matched by the
389 [keyword] configuration patterns.
388 [keyword] configuration patterns.
390
389
391 Useful to prevent inadvertent keyword expansion and to speed up
390 Useful to prevent inadvertent keyword expansion and to speed up
392 execution by including only files that are actual candidates for
391 execution by including only files that are actual candidates for
393 expansion.
392 expansion.
394
393
395 See :hg:`help keyword` on how to construct patterns both for
394 See :hg:`help keyword` on how to construct patterns both for
396 inclusion and exclusion of files.
395 inclusion and exclusion of files.
397
396
398 With -A/--all and -v/--verbose the codes used to show the status
397 With -A/--all and -v/--verbose the codes used to show the status
399 of files are::
398 of files are::
400
399
401 K = keyword expansion candidate
400 K = keyword expansion candidate
402 k = keyword expansion candidate (not tracked)
401 k = keyword expansion candidate (not tracked)
403 I = ignored
402 I = ignored
404 i = ignored (not tracked)
403 i = ignored (not tracked)
405 '''
404 '''
406 kwt = kwtools['templater']
405 kwt = kwtools['templater']
407 status = _status(ui, repo, kwt, *pats, **opts)
406 status = _status(ui, repo, kwt, *pats, **opts)
408 cwd = pats and repo.getcwd() or ''
407 cwd = pats and repo.getcwd() or ''
409 modified, added, removed, deleted, unknown, ignored, clean = status
408 modified, added, removed, deleted, unknown, ignored, clean = status
410 files = []
409 files = []
411 if not opts.get('unknown') or opts.get('all'):
410 if not opts.get('unknown') or opts.get('all'):
412 files = sorted(modified + added + clean)
411 files = sorted(modified + added + clean)
413 wctx = repo[None]
412 wctx = repo[None]
414 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
413 kwfiles = [f for f in files if kwt.iskwfile(f, wctx.flags)]
415 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
414 kwunknown = [f for f in unknown if kwt.iskwfile(f, wctx.flags)]
416 if not opts.get('ignore') or opts.get('all'):
415 if not opts.get('ignore') or opts.get('all'):
417 showfiles = kwfiles, kwunknown
416 showfiles = kwfiles, kwunknown
418 else:
417 else:
419 showfiles = [], []
418 showfiles = [], []
420 if opts.get('all') or opts.get('ignore'):
419 if opts.get('all') or opts.get('ignore'):
421 showfiles += ([f for f in files if f not in kwfiles],
420 showfiles += ([f for f in files if f not in kwfiles],
422 [f for f in unknown if f not in kwunknown])
421 [f for f in unknown if f not in kwunknown])
423 for char, filenames in zip('KkIi', showfiles):
422 for char, filenames in zip('KkIi', showfiles):
424 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
423 fmt = (opts.get('all') or ui.verbose) and '%s %%s\n' % char or '%s\n'
425 for f in filenames:
424 for f in filenames:
426 ui.write(fmt % repo.pathto(f, cwd))
425 ui.write(fmt % repo.pathto(f, cwd))
427
426
428 def shrink(ui, repo, *pats, **opts):
427 def shrink(ui, repo, *pats, **opts):
429 '''revert expanded keywords in the working directory
428 '''revert expanded keywords in the working directory
430
429
431 Run before changing/disabling active keywords or if you experience
430 Run before changing/disabling active keywords or if you experience
432 problems with :hg:`import` or :hg:`merge`.
431 problems with :hg:`import` or :hg:`merge`.
433
432
434 kwshrink refuses to run if given files contain local changes.
433 kwshrink refuses to run if given files contain local changes.
435 '''
434 '''
436 # 3rd argument sets expansion to False
435 # 3rd argument sets expansion to False
437 _kwfwrite(ui, repo, False, *pats, **opts)
436 _kwfwrite(ui, repo, False, *pats, **opts)
438
437
439
438
440 def uisetup(ui):
439 def uisetup(ui):
441 '''Collects [keyword] config in kwtools.
440 ''' Monkeypatches dispatch._parse to retrieve user command.'''
442 Monkeypatches dispatch._parse if needed.'''
443
444 for pat, opt in ui.configitems('keyword'):
445 if opt != 'ignore':
446 kwtools['inc'].append(pat)
447 else:
448 kwtools['exc'].append(pat)
449
441
450 if kwtools['inc']:
442 def kwdispatch_parse(orig, ui, args):
451 def kwdispatch_parse(orig, ui, args):
443 '''Monkeypatch dispatch._parse to obtain running hg command.'''
452 '''Monkeypatch dispatch._parse to obtain running hg command.'''
444 cmd, func, args, options, cmdoptions = orig(ui, args)
453 cmd, func, args, options, cmdoptions = orig(ui, args)
445 kwtools['hgcmd'] = cmd
454 kwtools['hgcmd'] = cmd
446 return cmd, func, args, options, cmdoptions
455 return cmd, func, args, options, cmdoptions
456
447
457 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
448 extensions.wrapfunction(dispatch, '_parse', kwdispatch_parse)
458
449
459 def reposetup(ui, repo):
450 def reposetup(ui, repo):
460 '''Sets up repo as kwrepo for keyword substitution.
451 '''Sets up repo as kwrepo for keyword substitution.
461 Overrides file method to return kwfilelog instead of filelog
452 Overrides file method to return kwfilelog instead of filelog
462 if file matches user configuration.
453 if file matches user configuration.
463 Wraps commit to overwrite configured files with updated
454 Wraps commit to overwrite configured files with updated
464 keyword substitutions.
455 keyword substitutions.
465 Monkeypatches patch and webcommands.'''
456 Monkeypatches patch and webcommands.'''
466
457
467 try:
458 try:
468 if (not repo.local() or not kwtools['inc']
459 if (not repo.local() or kwtools['hgcmd'] in nokwcommands.split()
469 or kwtools['hgcmd'] in nokwcommands.split()
470 or '.hg' in util.splitpath(repo.root)
460 or '.hg' in util.splitpath(repo.root)
471 or repo._url.startswith('bundle:')):
461 or repo._url.startswith('bundle:')):
472 return
462 return
473 except AttributeError:
463 except AttributeError:
474 pass
464 pass
475
465
476 kwtools['templater'] = kwt = kwtemplater(ui, repo)
466 inc, exc = [], ['.hg*']
467 for pat, opt in ui.configitems('keyword'):
468 if opt != 'ignore':
469 inc.append(pat)
470 else:
471 exc.append(pat)
472 if not inc:
473 return
474
475 kwtools['templater'] = kwt = kwtemplater(ui, repo, inc, exc)
477
476
478 class kwrepo(repo.__class__):
477 class kwrepo(repo.__class__):
479 def file(self, f):
478 def file(self, f):
480 if f[0] == '/':
479 if f[0] == '/':
481 f = f[1:]
480 f = f[1:]
482 return kwfilelog(self.sopener, kwt, f)
481 return kwfilelog(self.sopener, kwt, f)
483
482
484 def wread(self, filename):
483 def wread(self, filename):
485 data = super(kwrepo, self).wread(filename)
484 data = super(kwrepo, self).wread(filename)
486 return kwt.wread(filename, data)
485 return kwt.wread(filename, data)
487
486
488 def commit(self, *args, **opts):
487 def commit(self, *args, **opts):
489 # use custom commitctx for user commands
488 # use custom commitctx for user commands
490 # other extensions can still wrap repo.commitctx directly
489 # other extensions can still wrap repo.commitctx directly
491 self.commitctx = self.kwcommitctx
490 self.commitctx = self.kwcommitctx
492 try:
491 try:
493 return super(kwrepo, self).commit(*args, **opts)
492 return super(kwrepo, self).commit(*args, **opts)
494 finally:
493 finally:
495 del self.commitctx
494 del self.commitctx
496
495
497 def kwcommitctx(self, ctx, error=False):
496 def kwcommitctx(self, ctx, error=False):
498 n = super(kwrepo, self).commitctx(ctx, error)
497 n = super(kwrepo, self).commitctx(ctx, error)
499 # no lock needed, only called from repo.commit() which already locks
498 # no lock needed, only called from repo.commit() which already locks
500 if not kwt.record:
499 if not kwt.record:
501 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
500 kwt.overwrite(self[n], sorted(ctx.added() + ctx.modified()),
502 False, True)
501 False, True)
503 return n
502 return n
504
503
505 # monkeypatches
504 # monkeypatches
506 def kwpatchfile_init(orig, self, ui, fname, opener,
505 def kwpatchfile_init(orig, self, ui, fname, opener,
507 missing=False, eolmode=None):
506 missing=False, eolmode=None):
508 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
507 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
509 rejects or conflicts due to expanded keywords in working dir.'''
508 rejects or conflicts due to expanded keywords in working dir.'''
510 orig(self, ui, fname, opener, missing, eolmode)
509 orig(self, ui, fname, opener, missing, eolmode)
511 # shrink keywords read from working dir
510 # shrink keywords read from working dir
512 self.lines = kwt.shrinklines(self.fname, self.lines)
511 self.lines = kwt.shrinklines(self.fname, self.lines)
513
512
514 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
513 def kw_diff(orig, repo, node1=None, node2=None, match=None, changes=None,
515 opts=None):
514 opts=None):
516 '''Monkeypatch patch.diff to avoid expansion except when
515 '''Monkeypatch patch.diff to avoid expansion except when
517 comparing against working dir.'''
516 comparing against working dir.'''
518 if node2 is not None:
517 if node2 is not None:
519 kwt.match = util.never
518 kwt.match = util.never
520 elif node1 is not None and node1 != repo['.'].node():
519 elif node1 is not None and node1 != repo['.'].node():
521 kwt.restrict = True
520 kwt.restrict = True
522 return orig(repo, node1, node2, match, changes, opts)
521 return orig(repo, node1, node2, match, changes, opts)
523
522
524 def kwweb_skip(orig, web, req, tmpl):
523 def kwweb_skip(orig, web, req, tmpl):
525 '''Wraps webcommands.x turning off keyword expansion.'''
524 '''Wraps webcommands.x turning off keyword expansion.'''
526 kwt.match = util.never
525 kwt.match = util.never
527 return orig(web, req, tmpl)
526 return orig(web, req, tmpl)
528
527
529 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
528 def kw_dorecord(orig, ui, repo, commitfunc, *pats, **opts):
530 '''Wraps record.dorecord expanding keywords after recording.'''
529 '''Wraps record.dorecord expanding keywords after recording.'''
531 wlock = repo.wlock()
530 wlock = repo.wlock()
532 try:
531 try:
533 # record returns 0 even when nothing has changed
532 # record returns 0 even when nothing has changed
534 # therefore compare nodes before and after
533 # therefore compare nodes before and after
535 ctx = repo['.']
534 ctx = repo['.']
536 ret = orig(ui, repo, commitfunc, *pats, **opts)
535 ret = orig(ui, repo, commitfunc, *pats, **opts)
537 recordctx = repo['.']
536 recordctx = repo['.']
538 if ctx != recordctx:
537 if ctx != recordctx:
539 kwt.overwrite(recordctx, None, False, True)
538 kwt.overwrite(recordctx, None, False, True)
540 return ret
539 return ret
541 finally:
540 finally:
542 wlock.release()
541 wlock.release()
543
542
544 repo.__class__ = kwrepo
543 repo.__class__ = kwrepo
545
544
546 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
545 extensions.wrapfunction(patch.patchfile, '__init__', kwpatchfile_init)
547 if not kwt.restrict:
546 if not kwt.restrict:
548 extensions.wrapfunction(patch, 'diff', kw_diff)
547 extensions.wrapfunction(patch, 'diff', kw_diff)
549 for c in 'annotate changeset rev filediff diff'.split():
548 for c in 'annotate changeset rev filediff diff'.split():
550 extensions.wrapfunction(webcommands, c, kwweb_skip)
549 extensions.wrapfunction(webcommands, c, kwweb_skip)
551 for name in recordextensions.split():
550 for name in recordextensions.split():
552 try:
551 try:
553 record = extensions.find(name)
552 record = extensions.find(name)
554 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
553 extensions.wrapfunction(record, 'dorecord', kw_dorecord)
555 except KeyError:
554 except KeyError:
556 pass
555 pass
557
556
558 cmdtable = {
557 cmdtable = {
559 'kwdemo':
558 'kwdemo':
560 (demo,
559 (demo,
561 [('d', 'default', None, _('show default keyword template maps')),
560 [('d', 'default', None, _('show default keyword template maps')),
562 ('f', 'rcfile', '',
561 ('f', 'rcfile', '',
563 _('read maps from rcfile'), _('FILE'))],
562 _('read maps from rcfile'), _('FILE'))],
564 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
563 _('hg kwdemo [-d] [-f RCFILE] [TEMPLATEMAP]...')),
565 'kwexpand': (expand, commands.walkopts,
564 'kwexpand': (expand, commands.walkopts,
566 _('hg kwexpand [OPTION]... [FILE]...')),
565 _('hg kwexpand [OPTION]... [FILE]...')),
567 'kwfiles':
566 'kwfiles':
568 (files,
567 (files,
569 [('A', 'all', None, _('show keyword status flags of all files')),
568 [('A', 'all', None, _('show keyword status flags of all files')),
570 ('i', 'ignore', None, _('show files excluded from expansion')),
569 ('i', 'ignore', None, _('show files excluded from expansion')),
571 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
570 ('u', 'unknown', None, _('only show unknown (not tracked) files')),
572 ] + commands.walkopts,
571 ] + commands.walkopts,
573 _('hg kwfiles [OPTION]... [FILE]...')),
572 _('hg kwfiles [OPTION]... [FILE]...')),
574 'kwshrink': (shrink, commands.walkopts,
573 'kwshrink': (shrink, commands.walkopts,
575 _('hg kwshrink [OPTION]... [FILE]...')),
574 _('hg kwshrink [OPTION]... [FILE]...')),
576 }
575 }
@@ -1,550 +1,555 b''
1 # dispatch.py - command dispatching for mercurial
1 # dispatch.py - command dispatching for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 from i18n import _
8 from i18n import _
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback
9 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback
10 import util, commands, hg, fancyopts, extensions, hook, error
10 import util, commands, hg, fancyopts, extensions, hook, error
11 import cmdutil, encoding
11 import cmdutil, encoding
12 import ui as uimod
12 import ui as uimod
13
13
14 def run():
14 def run():
15 "run the command in sys.argv"
15 "run the command in sys.argv"
16 sys.exit(dispatch(sys.argv[1:]))
16 sys.exit(dispatch(sys.argv[1:]))
17
17
18 def dispatch(args):
18 def dispatch(args):
19 "run the command specified in args"
19 "run the command specified in args"
20 try:
20 try:
21 u = uimod.ui()
21 u = uimod.ui()
22 if '--traceback' in args:
22 if '--traceback' in args:
23 u.setconfig('ui', 'traceback', 'on')
23 u.setconfig('ui', 'traceback', 'on')
24 except util.Abort, inst:
24 except util.Abort, inst:
25 sys.stderr.write(_("abort: %s\n") % inst)
25 sys.stderr.write(_("abort: %s\n") % inst)
26 if inst.hint:
26 if inst.hint:
27 sys.stdout.write(_("(%s)\n") % inst.hint)
27 sys.stdout.write(_("(%s)\n") % inst.hint)
28 return -1
28 return -1
29 except error.ParseError, inst:
29 except error.ParseError, inst:
30 if len(inst.args) > 1:
30 if len(inst.args) > 1:
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
31 sys.stderr.write(_("hg: parse error at %s: %s\n") %
32 (inst.args[1], inst.args[0]))
32 (inst.args[1], inst.args[0]))
33 else:
33 else:
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
34 sys.stderr.write(_("hg: parse error: %s\n") % inst.args[0])
35 return -1
35 return -1
36 return _runcatch(u, args)
36 return _runcatch(u, args)
37
37
38 def _runcatch(ui, args):
38 def _runcatch(ui, args):
39 def catchterm(*args):
39 def catchterm(*args):
40 raise error.SignalInterrupt
40 raise error.SignalInterrupt
41
41
42 try:
42 try:
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
43 for name in 'SIGBREAK', 'SIGHUP', 'SIGTERM':
44 num = getattr(signal, name, None)
44 num = getattr(signal, name, None)
45 if num:
45 if num:
46 signal.signal(num, catchterm)
46 signal.signal(num, catchterm)
47 except ValueError:
47 except ValueError:
48 pass # happens if called in a thread
48 pass # happens if called in a thread
49
49
50 try:
50 try:
51 try:
51 try:
52 # enter the debugger before command execution
52 # enter the debugger before command execution
53 if '--debugger' in args:
53 if '--debugger' in args:
54 ui.warn(_("entering debugger - "
54 ui.warn(_("entering debugger - "
55 "type c to continue starting hg or h for help\n"))
55 "type c to continue starting hg or h for help\n"))
56 pdb.set_trace()
56 pdb.set_trace()
57 try:
57 try:
58 return _dispatch(ui, args)
58 return _dispatch(ui, args)
59 finally:
59 finally:
60 ui.flush()
60 ui.flush()
61 except:
61 except:
62 # enter the debugger when we hit an exception
62 # enter the debugger when we hit an exception
63 if '--debugger' in args:
63 if '--debugger' in args:
64 traceback.print_exc()
64 traceback.print_exc()
65 pdb.post_mortem(sys.exc_info()[2])
65 pdb.post_mortem(sys.exc_info()[2])
66 ui.traceback()
66 ui.traceback()
67 raise
67 raise
68
68
69 # Global exception handling, alphabetically
69 # Global exception handling, alphabetically
70 # Mercurial-specific first, followed by built-in and library exceptions
70 # Mercurial-specific first, followed by built-in and library exceptions
71 except error.AmbiguousCommand, inst:
71 except error.AmbiguousCommand, inst:
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
72 ui.warn(_("hg: command '%s' is ambiguous:\n %s\n") %
73 (inst.args[0], " ".join(inst.args[1])))
73 (inst.args[0], " ".join(inst.args[1])))
74 except error.ParseError, inst:
74 except error.ParseError, inst:
75 if len(inst.args) > 1:
75 if len(inst.args) > 1:
76 ui.warn(_("hg: parse error at %s: %s\n") %
76 ui.warn(_("hg: parse error at %s: %s\n") %
77 (inst.args[1], inst.args[0]))
77 (inst.args[1], inst.args[0]))
78 else:
78 else:
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
79 ui.warn(_("hg: parse error: %s\n") % inst.args[0])
80 return -1
80 return -1
81 except error.LockHeld, inst:
81 except error.LockHeld, inst:
82 if inst.errno == errno.ETIMEDOUT:
82 if inst.errno == errno.ETIMEDOUT:
83 reason = _('timed out waiting for lock held by %s') % inst.locker
83 reason = _('timed out waiting for lock held by %s') % inst.locker
84 else:
84 else:
85 reason = _('lock held by %s') % inst.locker
85 reason = _('lock held by %s') % inst.locker
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
86 ui.warn(_("abort: %s: %s\n") % (inst.desc or inst.filename, reason))
87 except error.LockUnavailable, inst:
87 except error.LockUnavailable, inst:
88 ui.warn(_("abort: could not lock %s: %s\n") %
88 ui.warn(_("abort: could not lock %s: %s\n") %
89 (inst.desc or inst.filename, inst.strerror))
89 (inst.desc or inst.filename, inst.strerror))
90 except error.CommandError, inst:
90 except error.CommandError, inst:
91 if inst.args[0]:
91 if inst.args[0]:
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
92 ui.warn(_("hg %s: %s\n") % (inst.args[0], inst.args[1]))
93 commands.help_(ui, inst.args[0])
93 commands.help_(ui, inst.args[0])
94 else:
94 else:
95 ui.warn(_("hg: %s\n") % inst.args[1])
95 ui.warn(_("hg: %s\n") % inst.args[1])
96 commands.help_(ui, 'shortlist')
96 commands.help_(ui, 'shortlist')
97 except error.RepoError, inst:
97 except error.RepoError, inst:
98 ui.warn(_("abort: %s!\n") % inst)
98 ui.warn(_("abort: %s!\n") % inst)
99 except error.ResponseError, inst:
99 except error.ResponseError, inst:
100 ui.warn(_("abort: %s") % inst.args[0])
100 ui.warn(_("abort: %s") % inst.args[0])
101 if not isinstance(inst.args[1], basestring):
101 if not isinstance(inst.args[1], basestring):
102 ui.warn(" %r\n" % (inst.args[1],))
102 ui.warn(" %r\n" % (inst.args[1],))
103 elif not inst.args[1]:
103 elif not inst.args[1]:
104 ui.warn(_(" empty string\n"))
104 ui.warn(_(" empty string\n"))
105 else:
105 else:
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
106 ui.warn("\n%r\n" % util.ellipsis(inst.args[1]))
107 except error.RevlogError, inst:
107 except error.RevlogError, inst:
108 ui.warn(_("abort: %s!\n") % inst)
108 ui.warn(_("abort: %s!\n") % inst)
109 except error.SignalInterrupt:
109 except error.SignalInterrupt:
110 ui.warn(_("killed!\n"))
110 ui.warn(_("killed!\n"))
111 except error.UnknownCommand, inst:
111 except error.UnknownCommand, inst:
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
112 ui.warn(_("hg: unknown command '%s'\n") % inst.args[0])
113 try:
113 try:
114 # check if the command is in a disabled extension
114 # check if the command is in a disabled extension
115 # (but don't check for extensions themselves)
115 # (but don't check for extensions themselves)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
116 commands.help_(ui, inst.args[0], unknowncmd=True)
117 except error.UnknownCommand:
117 except error.UnknownCommand:
118 commands.help_(ui, 'shortlist')
118 commands.help_(ui, 'shortlist')
119 except util.Abort, inst:
119 except util.Abort, inst:
120 ui.warn(_("abort: %s\n") % inst)
120 ui.warn(_("abort: %s\n") % inst)
121 if inst.hint:
121 if inst.hint:
122 ui.status(_("(%s)\n") % inst.hint)
122 ui.status(_("(%s)\n") % inst.hint)
123 except ImportError, inst:
123 except ImportError, inst:
124 ui.warn(_("abort: %s!\n") % inst)
124 ui.warn(_("abort: %s!\n") % inst)
125 m = str(inst).split()[-1]
125 m = str(inst).split()[-1]
126 if m in "mpatch bdiff".split():
126 if m in "mpatch bdiff".split():
127 ui.warn(_("(did you forget to compile extensions?)\n"))
127 ui.warn(_("(did you forget to compile extensions?)\n"))
128 elif m in "zlib".split():
128 elif m in "zlib".split():
129 ui.warn(_("(is your Python install correct?)\n"))
129 ui.warn(_("(is your Python install correct?)\n"))
130 except IOError, inst:
130 except IOError, inst:
131 if hasattr(inst, "code"):
131 if hasattr(inst, "code"):
132 ui.warn(_("abort: %s\n") % inst)
132 ui.warn(_("abort: %s\n") % inst)
133 elif hasattr(inst, "reason"):
133 elif hasattr(inst, "reason"):
134 try: # usually it is in the form (errno, strerror)
134 try: # usually it is in the form (errno, strerror)
135 reason = inst.reason.args[1]
135 reason = inst.reason.args[1]
136 except: # it might be anything, for example a string
136 except: # it might be anything, for example a string
137 reason = inst.reason
137 reason = inst.reason
138 ui.warn(_("abort: error: %s\n") % reason)
138 ui.warn(_("abort: error: %s\n") % reason)
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
139 elif hasattr(inst, "args") and inst.args[0] == errno.EPIPE:
140 if ui.debugflag:
140 if ui.debugflag:
141 ui.warn(_("broken pipe\n"))
141 ui.warn(_("broken pipe\n"))
142 elif getattr(inst, "strerror", None):
142 elif getattr(inst, "strerror", None):
143 if getattr(inst, "filename", None):
143 if getattr(inst, "filename", None):
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
144 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
145 else:
145 else:
146 ui.warn(_("abort: %s\n") % inst.strerror)
146 ui.warn(_("abort: %s\n") % inst.strerror)
147 else:
147 else:
148 raise
148 raise
149 except OSError, inst:
149 except OSError, inst:
150 if getattr(inst, "filename", None):
150 if getattr(inst, "filename", None):
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
151 ui.warn(_("abort: %s: %s\n") % (inst.strerror, inst.filename))
152 else:
152 else:
153 ui.warn(_("abort: %s\n") % inst.strerror)
153 ui.warn(_("abort: %s\n") % inst.strerror)
154 except KeyboardInterrupt:
154 except KeyboardInterrupt:
155 try:
155 try:
156 ui.warn(_("interrupted!\n"))
156 ui.warn(_("interrupted!\n"))
157 except IOError, inst:
157 except IOError, inst:
158 if inst.errno == errno.EPIPE:
158 if inst.errno == errno.EPIPE:
159 if ui.debugflag:
159 if ui.debugflag:
160 ui.warn(_("\nbroken pipe\n"))
160 ui.warn(_("\nbroken pipe\n"))
161 else:
161 else:
162 raise
162 raise
163 except MemoryError:
163 except MemoryError:
164 ui.warn(_("abort: out of memory\n"))
164 ui.warn(_("abort: out of memory\n"))
165 except SystemExit, inst:
165 except SystemExit, inst:
166 # Commands shouldn't sys.exit directly, but give a return code.
166 # Commands shouldn't sys.exit directly, but give a return code.
167 # Just in case catch this and and pass exit code to caller.
167 # Just in case catch this and and pass exit code to caller.
168 return inst.code
168 return inst.code
169 except socket.error, inst:
169 except socket.error, inst:
170 ui.warn(_("abort: %s\n") % inst.args[-1])
170 ui.warn(_("abort: %s\n") % inst.args[-1])
171 except:
171 except:
172 ui.warn(_("** unknown exception encountered, details follow\n"))
172 ui.warn(_("** unknown exception encountered, details follow\n"))
173 ui.warn(_("** report bug details to "
173 ui.warn(_("** report bug details to "
174 "http://mercurial.selenic.com/bts/\n"))
174 "http://mercurial.selenic.com/bts/\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
175 ui.warn(_("** or mercurial@selenic.com\n"))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
176 ui.warn(_("** Python %s\n") % sys.version.replace('\n', ''))
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
177 ui.warn(_("** Mercurial Distributed SCM (version %s)\n")
178 % util.version())
178 % util.version())
179 ui.warn(_("** Extensions loaded: %s\n")
179 ui.warn(_("** Extensions loaded: %s\n")
180 % ", ".join([x[0] for x in extensions.extensions()]))
180 % ", ".join([x[0] for x in extensions.extensions()]))
181 raise
181 raise
182
182
183 return -1
183 return -1
184
184
185 def aliasargs(fn):
185 def aliasargs(fn):
186 if hasattr(fn, 'args'):
186 if hasattr(fn, 'args'):
187 return fn.args
187 return fn.args
188 return []
188 return []
189
189
190 class cmdalias(object):
190 class cmdalias(object):
191 def __init__(self, name, definition, cmdtable):
191 def __init__(self, name, definition, cmdtable):
192 self.name = name
192 self.name = name
193 self.definition = definition
193 self.definition = definition
194 self.args = []
194 self.args = []
195 self.opts = []
195 self.opts = []
196 self.help = ''
196 self.help = ''
197 self.norepo = True
197 self.norepo = True
198 self.badalias = False
198 self.badalias = False
199
199
200 try:
200 try:
201 cmdutil.findcmd(self.name, cmdtable, True)
201 cmdutil.findcmd(self.name, cmdtable, True)
202 self.shadows = True
202 self.shadows = True
203 except error.UnknownCommand:
203 except error.UnknownCommand:
204 self.shadows = False
204 self.shadows = False
205
205
206 if not self.definition:
206 if not self.definition:
207 def fn(ui, *args):
207 def fn(ui, *args):
208 ui.warn(_("no definition for alias '%s'\n") % self.name)
208 ui.warn(_("no definition for alias '%s'\n") % self.name)
209 return 1
209 return 1
210 self.fn = fn
210 self.fn = fn
211 self.badalias = True
211 self.badalias = True
212
212
213 return
213 return
214
214
215 if self.definition.startswith('!'):
215 if self.definition.startswith('!'):
216 def fn(ui, *args):
216 def fn(ui, *args):
217 cmd = '%s %s' % (self.definition[1:], ' '.join(args))
217 cmd = '%s %s' % (self.definition[1:], ' '.join(args))
218 return util.system(cmd)
218 return util.system(cmd)
219 self.fn = fn
219 self.fn = fn
220 return
220 return
221
221
222 args = shlex.split(self.definition)
222 args = shlex.split(self.definition)
223 cmd = args.pop(0)
223 cmd = args.pop(0)
224 args = map(util.expandpath, args)
224 args = map(util.expandpath, args)
225
225
226 try:
226 try:
227 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
227 tableentry = cmdutil.findcmd(cmd, cmdtable, False)[1]
228 if len(tableentry) > 2:
228 if len(tableentry) > 2:
229 self.fn, self.opts, self.help = tableentry
229 self.fn, self.opts, self.help = tableentry
230 else:
230 else:
231 self.fn, self.opts = tableentry
231 self.fn, self.opts = tableentry
232
232
233 self.args = aliasargs(self.fn) + args
233 self.args = aliasargs(self.fn) + args
234 if cmd not in commands.norepo.split(' '):
234 if cmd not in commands.norepo.split(' '):
235 self.norepo = False
235 self.norepo = False
236 if self.help.startswith("hg " + cmd):
236 if self.help.startswith("hg " + cmd):
237 # drop prefix in old-style help lines so hg shows the alias
237 # drop prefix in old-style help lines so hg shows the alias
238 self.help = self.help[4 + len(cmd):]
238 self.help = self.help[4 + len(cmd):]
239 self.__doc__ = self.fn.__doc__
239 self.__doc__ = self.fn.__doc__
240
240
241 except error.UnknownCommand:
241 except error.UnknownCommand:
242 def fn(ui, *args):
242 def fn(ui, *args):
243 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
243 ui.warn(_("alias '%s' resolves to unknown command '%s'\n") \
244 % (self.name, cmd))
244 % (self.name, cmd))
245 try:
245 try:
246 # check if the command is in a disabled extension
246 # check if the command is in a disabled extension
247 commands.help_(ui, cmd, unknowncmd=True)
247 commands.help_(ui, cmd, unknowncmd=True)
248 except error.UnknownCommand:
248 except error.UnknownCommand:
249 pass
249 pass
250 return 1
250 return 1
251 self.fn = fn
251 self.fn = fn
252 self.badalias = True
252 self.badalias = True
253 except error.AmbiguousCommand:
253 except error.AmbiguousCommand:
254 def fn(ui, *args):
254 def fn(ui, *args):
255 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
255 ui.warn(_("alias '%s' resolves to ambiguous command '%s'\n") \
256 % (self.name, cmd))
256 % (self.name, cmd))
257 return 1
257 return 1
258 self.fn = fn
258 self.fn = fn
259 self.badalias = True
259 self.badalias = True
260
260
261 def __call__(self, ui, *args, **opts):
261 def __call__(self, ui, *args, **opts):
262 if self.shadows:
262 if self.shadows:
263 ui.debug("alias '%s' shadows command\n" % self.name)
263 ui.debug("alias '%s' shadows command\n" % self.name)
264
264
265 return self.fn(ui, *args, **opts)
265 return util.checksignature(self.fn)(ui, *args, **opts)
266
266
267 def addaliases(ui, cmdtable):
267 def addaliases(ui, cmdtable):
268 # aliases are processed after extensions have been loaded, so they
268 # aliases are processed after extensions have been loaded, so they
269 # may use extension commands. Aliases can also use other alias definitions,
269 # may use extension commands. Aliases can also use other alias definitions,
270 # but only if they have been defined prior to the current definition.
270 # but only if they have been defined prior to the current definition.
271 for alias, definition in ui.configitems('alias'):
271 for alias, definition in ui.configitems('alias'):
272 aliasdef = cmdalias(alias, definition, cmdtable)
272 aliasdef = cmdalias(alias, definition, cmdtable)
273 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
273 cmdtable[alias] = (aliasdef, aliasdef.opts, aliasdef.help)
274 if aliasdef.norepo:
274 if aliasdef.norepo:
275 commands.norepo += ' %s' % alias
275 commands.norepo += ' %s' % alias
276
276
277 def _parse(ui, args):
277 def _parse(ui, args):
278 options = {}
278 options = {}
279 cmdoptions = {}
279 cmdoptions = {}
280
280
281 try:
281 try:
282 args = fancyopts.fancyopts(args, commands.globalopts, options)
282 args = fancyopts.fancyopts(args, commands.globalopts, options)
283 except fancyopts.getopt.GetoptError, inst:
283 except fancyopts.getopt.GetoptError, inst:
284 raise error.CommandError(None, inst)
284 raise error.CommandError(None, inst)
285
285
286 if args:
286 if args:
287 cmd, args = args[0], args[1:]
287 cmd, args = args[0], args[1:]
288 aliases, entry = cmdutil.findcmd(cmd, commands.table,
288 aliases, entry = cmdutil.findcmd(cmd, commands.table,
289 ui.config("ui", "strict"))
289 ui.config("ui", "strict"))
290 cmd = aliases[0]
290 cmd = aliases[0]
291 args = aliasargs(entry[0]) + args
291 args = aliasargs(entry[0]) + args
292 defaults = ui.config("defaults", cmd)
292 defaults = ui.config("defaults", cmd)
293 if defaults:
293 if defaults:
294 args = map(util.expandpath, shlex.split(defaults)) + args
294 args = map(util.expandpath, shlex.split(defaults)) + args
295 c = list(entry[1])
295 c = list(entry[1])
296 else:
296 else:
297 cmd = None
297 cmd = None
298 c = []
298 c = []
299
299
300 # combine global options into local
300 # combine global options into local
301 for o in commands.globalopts:
301 for o in commands.globalopts:
302 c.append((o[0], o[1], options[o[1]], o[3]))
302 c.append((o[0], o[1], options[o[1]], o[3]))
303
303
304 try:
304 try:
305 args = fancyopts.fancyopts(args, c, cmdoptions, True)
305 args = fancyopts.fancyopts(args, c, cmdoptions, True)
306 except fancyopts.getopt.GetoptError, inst:
306 except fancyopts.getopt.GetoptError, inst:
307 raise error.CommandError(cmd, inst)
307 raise error.CommandError(cmd, inst)
308
308
309 # separate global options back out
309 # separate global options back out
310 for o in commands.globalopts:
310 for o in commands.globalopts:
311 n = o[1]
311 n = o[1]
312 options[n] = cmdoptions[n]
312 options[n] = cmdoptions[n]
313 del cmdoptions[n]
313 del cmdoptions[n]
314
314
315 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
315 return (cmd, cmd and entry[0] or None, args, options, cmdoptions)
316
316
317 def _parseconfig(ui, config):
317 def _parseconfig(ui, config):
318 """parse the --config options from the command line"""
318 """parse the --config options from the command line"""
319 for cfg in config:
319 for cfg in config:
320 try:
320 try:
321 name, value = cfg.split('=', 1)
321 name, value = cfg.split('=', 1)
322 section, name = name.split('.', 1)
322 section, name = name.split('.', 1)
323 if not section or not name:
323 if not section or not name:
324 raise IndexError
324 raise IndexError
325 ui.setconfig(section, name, value)
325 ui.setconfig(section, name, value)
326 except (IndexError, ValueError):
326 except (IndexError, ValueError):
327 raise util.Abort(_('malformed --config option: %r '
327 raise util.Abort(_('malformed --config option: %r '
328 '(use --config section.name=value)') % cfg)
328 '(use --config section.name=value)') % cfg)
329
329
330 def _earlygetopt(aliases, args):
330 def _earlygetopt(aliases, args):
331 """Return list of values for an option (or aliases).
331 """Return list of values for an option (or aliases).
332
332
333 The values are listed in the order they appear in args.
333 The values are listed in the order they appear in args.
334 The options and values are removed from args.
334 The options and values are removed from args.
335 """
335 """
336 try:
336 try:
337 argcount = args.index("--")
337 argcount = args.index("--")
338 except ValueError:
338 except ValueError:
339 argcount = len(args)
339 argcount = len(args)
340 shortopts = [opt for opt in aliases if len(opt) == 2]
340 shortopts = [opt for opt in aliases if len(opt) == 2]
341 values = []
341 values = []
342 pos = 0
342 pos = 0
343 while pos < argcount:
343 while pos < argcount:
344 if args[pos] in aliases:
344 if args[pos] in aliases:
345 if pos + 1 >= argcount:
345 if pos + 1 >= argcount:
346 # ignore and let getopt report an error if there is no value
346 # ignore and let getopt report an error if there is no value
347 break
347 break
348 del args[pos]
348 del args[pos]
349 values.append(args.pop(pos))
349 values.append(args.pop(pos))
350 argcount -= 2
350 argcount -= 2
351 elif args[pos][:2] in shortopts:
351 elif args[pos][:2] in shortopts:
352 # short option can have no following space, e.g. hg log -Rfoo
352 # short option can have no following space, e.g. hg log -Rfoo
353 values.append(args.pop(pos)[2:])
353 values.append(args.pop(pos)[2:])
354 argcount -= 1
354 argcount -= 1
355 else:
355 else:
356 pos += 1
356 pos += 1
357 return values
357 return values
358
358
359 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
359 def runcommand(lui, repo, cmd, fullargs, ui, options, d, cmdpats, cmdoptions):
360 # run pre-hook, and abort if it fails
360 # run pre-hook, and abort if it fails
361 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
361 ret = hook.hook(lui, repo, "pre-%s" % cmd, False, args=" ".join(fullargs),
362 pats=cmdpats, opts=cmdoptions)
362 pats=cmdpats, opts=cmdoptions)
363 if ret:
363 if ret:
364 return ret
364 return ret
365 ret = _runcommand(ui, options, cmd, d)
365 ret = _runcommand(ui, options, cmd, d)
366 # run post-hook, passing command result
366 # run post-hook, passing command result
367 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
367 hook.hook(lui, repo, "post-%s" % cmd, False, args=" ".join(fullargs),
368 result=ret, pats=cmdpats, opts=cmdoptions)
368 result=ret, pats=cmdpats, opts=cmdoptions)
369 return ret
369 return ret
370
370
371 _loaded = set()
371 _loaded = set()
372 def _dispatch(ui, args):
372 def _dispatch(ui, args):
373 # read --config before doing anything else
373 # read --config before doing anything else
374 # (e.g. to change trust settings for reading .hg/hgrc)
374 # (e.g. to change trust settings for reading .hg/hgrc)
375 _parseconfig(ui, _earlygetopt(['--config'], args))
375 _parseconfig(ui, _earlygetopt(['--config'], args))
376
376
377 # check for cwd
377 # check for cwd
378 cwd = _earlygetopt(['--cwd'], args)
378 cwd = _earlygetopt(['--cwd'], args)
379 if cwd:
379 if cwd:
380 os.chdir(cwd[-1])
380 os.chdir(cwd[-1])
381
381
382 # read the local repository .hgrc into a local ui object
382 # read the local repository .hgrc into a local ui object
383 path = cmdutil.findrepo(os.getcwd()) or ""
383 try:
384 wd = os.getcwd()
385 except OSError, e:
386 raise util.Abort(_("error getting current working directory: %s") %
387 e.strerror)
388 path = cmdutil.findrepo(wd) or ""
384 if not path:
389 if not path:
385 lui = ui
390 lui = ui
386 else:
391 else:
387 try:
392 try:
388 lui = ui.copy()
393 lui = ui.copy()
389 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
394 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
390 except IOError:
395 except IOError:
391 pass
396 pass
392
397
393 # now we can expand paths, even ones in .hg/hgrc
398 # now we can expand paths, even ones in .hg/hgrc
394 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
399 rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
395 if rpath:
400 if rpath:
396 path = lui.expandpath(rpath[-1])
401 path = lui.expandpath(rpath[-1])
397 lui = ui.copy()
402 lui = ui.copy()
398 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
403 lui.readconfig(os.path.join(path, ".hg", "hgrc"))
399
404
400 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
405 # Configure extensions in phases: uisetup, extsetup, cmdtable, and
401 # reposetup. Programs like TortoiseHg will call _dispatch several
406 # reposetup. Programs like TortoiseHg will call _dispatch several
402 # times so we keep track of configured extensions in _loaded.
407 # times so we keep track of configured extensions in _loaded.
403 extensions.loadall(lui)
408 extensions.loadall(lui)
404 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
409 exts = [ext for ext in extensions.extensions() if ext[0] not in _loaded]
405 # Propagate any changes to lui.__class__ by extensions
410 # Propagate any changes to lui.__class__ by extensions
406 ui.__class__ = lui.__class__
411 ui.__class__ = lui.__class__
407
412
408 # (uisetup and extsetup are handled in extensions.loadall)
413 # (uisetup and extsetup are handled in extensions.loadall)
409
414
410 for name, module in exts:
415 for name, module in exts:
411 cmdtable = getattr(module, 'cmdtable', {})
416 cmdtable = getattr(module, 'cmdtable', {})
412 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
417 overrides = [cmd for cmd in cmdtable if cmd in commands.table]
413 if overrides:
418 if overrides:
414 ui.warn(_("extension '%s' overrides commands: %s\n")
419 ui.warn(_("extension '%s' overrides commands: %s\n")
415 % (name, " ".join(overrides)))
420 % (name, " ".join(overrides)))
416 commands.table.update(cmdtable)
421 commands.table.update(cmdtable)
417 _loaded.add(name)
422 _loaded.add(name)
418
423
419 # (reposetup is handled in hg.repository)
424 # (reposetup is handled in hg.repository)
420
425
421 addaliases(lui, commands.table)
426 addaliases(lui, commands.table)
422
427
423 # check for fallback encoding
428 # check for fallback encoding
424 fallback = lui.config('ui', 'fallbackencoding')
429 fallback = lui.config('ui', 'fallbackencoding')
425 if fallback:
430 if fallback:
426 encoding.fallbackencoding = fallback
431 encoding.fallbackencoding = fallback
427
432
428 fullargs = args
433 fullargs = args
429 cmd, func, args, options, cmdoptions = _parse(lui, args)
434 cmd, func, args, options, cmdoptions = _parse(lui, args)
430
435
431 if options["config"]:
436 if options["config"]:
432 raise util.Abort(_("Option --config may not be abbreviated!"))
437 raise util.Abort(_("Option --config may not be abbreviated!"))
433 if options["cwd"]:
438 if options["cwd"]:
434 raise util.Abort(_("Option --cwd may not be abbreviated!"))
439 raise util.Abort(_("Option --cwd may not be abbreviated!"))
435 if options["repository"]:
440 if options["repository"]:
436 raise util.Abort(_(
441 raise util.Abort(_(
437 "Option -R has to be separated from other options (e.g. not -qR) "
442 "Option -R has to be separated from other options (e.g. not -qR) "
438 "and --repository may only be abbreviated as --repo!"))
443 "and --repository may only be abbreviated as --repo!"))
439
444
440 if options["encoding"]:
445 if options["encoding"]:
441 encoding.encoding = options["encoding"]
446 encoding.encoding = options["encoding"]
442 if options["encodingmode"]:
447 if options["encodingmode"]:
443 encoding.encodingmode = options["encodingmode"]
448 encoding.encodingmode = options["encodingmode"]
444 if options["time"]:
449 if options["time"]:
445 def get_times():
450 def get_times():
446 t = os.times()
451 t = os.times()
447 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
452 if t[4] == 0.0: # Windows leaves this as zero, so use time.clock()
448 t = (t[0], t[1], t[2], t[3], time.clock())
453 t = (t[0], t[1], t[2], t[3], time.clock())
449 return t
454 return t
450 s = get_times()
455 s = get_times()
451 def print_time():
456 def print_time():
452 t = get_times()
457 t = get_times()
453 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
458 ui.warn(_("Time: real %.3f secs (user %.3f+%.3f sys %.3f+%.3f)\n") %
454 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
459 (t[4]-s[4], t[0]-s[0], t[2]-s[2], t[1]-s[1], t[3]-s[3]))
455 atexit.register(print_time)
460 atexit.register(print_time)
456
461
457 if options['verbose'] or options['debug'] or options['quiet']:
462 if options['verbose'] or options['debug'] or options['quiet']:
458 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
463 ui.setconfig('ui', 'verbose', str(bool(options['verbose'])))
459 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
464 ui.setconfig('ui', 'debug', str(bool(options['debug'])))
460 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
465 ui.setconfig('ui', 'quiet', str(bool(options['quiet'])))
461 if options['traceback']:
466 if options['traceback']:
462 ui.setconfig('ui', 'traceback', 'on')
467 ui.setconfig('ui', 'traceback', 'on')
463 if options['noninteractive']:
468 if options['noninteractive']:
464 ui.setconfig('ui', 'interactive', 'off')
469 ui.setconfig('ui', 'interactive', 'off')
465
470
466 if options['help']:
471 if options['help']:
467 return commands.help_(ui, cmd, options['version'])
472 return commands.help_(ui, cmd, options['version'])
468 elif options['version']:
473 elif options['version']:
469 return commands.version_(ui)
474 return commands.version_(ui)
470 elif not cmd:
475 elif not cmd:
471 return commands.help_(ui, 'shortlist')
476 return commands.help_(ui, 'shortlist')
472
477
473 repo = None
478 repo = None
474 cmdpats = args[:]
479 cmdpats = args[:]
475 if cmd not in commands.norepo.split():
480 if cmd not in commands.norepo.split():
476 try:
481 try:
477 repo = hg.repository(ui, path=path)
482 repo = hg.repository(ui, path=path)
478 ui = repo.ui
483 ui = repo.ui
479 if not repo.local():
484 if not repo.local():
480 raise util.Abort(_("repository '%s' is not local") % path)
485 raise util.Abort(_("repository '%s' is not local") % path)
481 ui.setconfig("bundle", "mainreporoot", repo.root)
486 ui.setconfig("bundle", "mainreporoot", repo.root)
482 except error.RepoError:
487 except error.RepoError:
483 if cmd not in commands.optionalrepo.split():
488 if cmd not in commands.optionalrepo.split():
484 if args and not path: # try to infer -R from command args
489 if args and not path: # try to infer -R from command args
485 repos = map(cmdutil.findrepo, args)
490 repos = map(cmdutil.findrepo, args)
486 guess = repos[0]
491 guess = repos[0]
487 if guess and repos.count(guess) == len(repos):
492 if guess and repos.count(guess) == len(repos):
488 return _dispatch(ui, ['--repository', guess] + fullargs)
493 return _dispatch(ui, ['--repository', guess] + fullargs)
489 if not path:
494 if not path:
490 raise error.RepoError(_("There is no Mercurial repository"
495 raise error.RepoError(_("There is no Mercurial repository"
491 " here (.hg not found)"))
496 " here (.hg not found)"))
492 raise
497 raise
493 args.insert(0, repo)
498 args.insert(0, repo)
494 elif rpath:
499 elif rpath:
495 ui.warn(_("warning: --repository ignored\n"))
500 ui.warn(_("warning: --repository ignored\n"))
496
501
497 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
502 d = lambda: util.checksignature(func)(ui, *args, **cmdoptions)
498 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
503 return runcommand(lui, repo, cmd, fullargs, ui, options, d,
499 cmdpats, cmdoptions)
504 cmdpats, cmdoptions)
500
505
501 def _runcommand(ui, options, cmd, cmdfunc):
506 def _runcommand(ui, options, cmd, cmdfunc):
502 def checkargs():
507 def checkargs():
503 try:
508 try:
504 return cmdfunc()
509 return cmdfunc()
505 except error.SignatureError:
510 except error.SignatureError:
506 raise error.CommandError(cmd, _("invalid arguments"))
511 raise error.CommandError(cmd, _("invalid arguments"))
507
512
508 if options['profile']:
513 if options['profile']:
509 format = ui.config('profiling', 'format', default='text')
514 format = ui.config('profiling', 'format', default='text')
510
515
511 if not format in ['text', 'kcachegrind']:
516 if not format in ['text', 'kcachegrind']:
512 ui.warn(_("unrecognized profiling format '%s'"
517 ui.warn(_("unrecognized profiling format '%s'"
513 " - Ignored\n") % format)
518 " - Ignored\n") % format)
514 format = 'text'
519 format = 'text'
515
520
516 output = ui.config('profiling', 'output')
521 output = ui.config('profiling', 'output')
517
522
518 if output:
523 if output:
519 path = ui.expandpath(output)
524 path = ui.expandpath(output)
520 ostream = open(path, 'wb')
525 ostream = open(path, 'wb')
521 else:
526 else:
522 ostream = sys.stderr
527 ostream = sys.stderr
523
528
524 try:
529 try:
525 from mercurial import lsprof
530 from mercurial import lsprof
526 except ImportError:
531 except ImportError:
527 raise util.Abort(_(
532 raise util.Abort(_(
528 'lsprof not available - install from '
533 'lsprof not available - install from '
529 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
534 'http://codespeak.net/svn/user/arigo/hack/misc/lsprof/'))
530 p = lsprof.Profiler()
535 p = lsprof.Profiler()
531 p.enable(subcalls=True)
536 p.enable(subcalls=True)
532 try:
537 try:
533 return checkargs()
538 return checkargs()
534 finally:
539 finally:
535 p.disable()
540 p.disable()
536
541
537 if format == 'kcachegrind':
542 if format == 'kcachegrind':
538 import lsprofcalltree
543 import lsprofcalltree
539 calltree = lsprofcalltree.KCacheGrind(p)
544 calltree = lsprofcalltree.KCacheGrind(p)
540 calltree.output(ostream)
545 calltree.output(ostream)
541 else:
546 else:
542 # format == 'text'
547 # format == 'text'
543 stats = lsprof.Stats(p.getstats())
548 stats = lsprof.Stats(p.getstats())
544 stats.sort()
549 stats.sort()
545 stats.pprint(top=10, file=ostream, climit=5)
550 stats.pprint(top=10, file=ostream, climit=5)
546
551
547 if output:
552 if output:
548 ostream.close()
553 ostream.close()
549 else:
554 else:
550 return checkargs()
555 return checkargs()
@@ -1,352 +1,352 b''
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os, re, time, urlparse
9 import os, re, time, urlparse
10 from mercurial.i18n import _
10 from mercurial.i18n import _
11 from mercurial import ui, hg, util, templater
11 from mercurial import ui, hg, util, templater
12 from mercurial import error, encoding
12 from mercurial import error, encoding
13 from common import ErrorResponse, get_mtime, staticfile, paritygen, \
13 from common import ErrorResponse, get_mtime, staticfile, paritygen, \
14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
15 from hgweb_mod import hgweb
15 from hgweb_mod import hgweb
16 from request import wsgirequest
16 from request import wsgirequest
17 import webutil
17 import webutil
18
18
19 def cleannames(items):
19 def cleannames(items):
20 return [(util.pconvert(name).strip('/'), path) for name, path in items]
20 return [(util.pconvert(name).strip('/'), path) for name, path in items]
21
21
22 def findrepos(paths):
22 def findrepos(paths):
23 repos = []
23 repos = []
24 for prefix, root in cleannames(paths):
24 for prefix, root in cleannames(paths):
25 roothead, roottail = os.path.split(root)
25 roothead, roottail = os.path.split(root)
26 # "foo = /bar/*" makes every subrepo of /bar/ to be
26 # "foo = /bar/*" makes every subrepo of /bar/ to be
27 # mounted as foo/subrepo
27 # mounted as foo/subrepo
28 # and "foo = /bar/**" also recurses into the subdirectories,
28 # and "foo = /bar/**" also recurses into the subdirectories,
29 # remember to use it without working dir.
29 # remember to use it without working dir.
30 try:
30 try:
31 recurse = {'*': False, '**': True}[roottail]
31 recurse = {'*': False, '**': True}[roottail]
32 except KeyError:
32 except KeyError:
33 repos.append((prefix, root))
33 repos.append((prefix, root))
34 continue
34 continue
35 roothead = os.path.normpath(roothead)
35 roothead = os.path.normpath(os.path.abspath(roothead))
36 for path in util.walkrepos(roothead, followsym=True, recurse=recurse):
36 for path in util.walkrepos(roothead, followsym=True, recurse=recurse):
37 path = os.path.normpath(path)
37 path = os.path.normpath(path)
38 name = util.pconvert(path[len(roothead):]).strip('/')
38 name = util.pconvert(path[len(roothead):]).strip('/')
39 if prefix:
39 if prefix:
40 name = prefix + '/' + name
40 name = prefix + '/' + name
41 repos.append((name, path))
41 repos.append((name, path))
42 return repos
42 return repos
43
43
44 class hgwebdir(object):
44 class hgwebdir(object):
45 refreshinterval = 20
45 refreshinterval = 20
46
46
47 def __init__(self, conf, baseui=None):
47 def __init__(self, conf, baseui=None):
48 self.conf = conf
48 self.conf = conf
49 self.baseui = baseui
49 self.baseui = baseui
50 self.lastrefresh = 0
50 self.lastrefresh = 0
51 self.motd = None
51 self.motd = None
52 self.refresh()
52 self.refresh()
53
53
54 def refresh(self):
54 def refresh(self):
55 if self.lastrefresh + self.refreshinterval > time.time():
55 if self.lastrefresh + self.refreshinterval > time.time():
56 return
56 return
57
57
58 if self.baseui:
58 if self.baseui:
59 u = self.baseui.copy()
59 u = self.baseui.copy()
60 else:
60 else:
61 u = ui.ui()
61 u = ui.ui()
62 u.setconfig('ui', 'report_untrusted', 'off')
62 u.setconfig('ui', 'report_untrusted', 'off')
63 u.setconfig('ui', 'interactive', 'off')
63 u.setconfig('ui', 'interactive', 'off')
64
64
65 if not isinstance(self.conf, (dict, list, tuple)):
65 if not isinstance(self.conf, (dict, list, tuple)):
66 map = {'paths': 'hgweb-paths'}
66 map = {'paths': 'hgweb-paths'}
67 u.readconfig(self.conf, remap=map, trust=True)
67 u.readconfig(self.conf, remap=map, trust=True)
68 paths = u.configitems('hgweb-paths')
68 paths = u.configitems('hgweb-paths')
69 elif isinstance(self.conf, (list, tuple)):
69 elif isinstance(self.conf, (list, tuple)):
70 paths = self.conf
70 paths = self.conf
71 elif isinstance(self.conf, dict):
71 elif isinstance(self.conf, dict):
72 paths = self.conf.items()
72 paths = self.conf.items()
73
73
74 repos = findrepos(paths)
74 repos = findrepos(paths)
75 for prefix, root in u.configitems('collections'):
75 for prefix, root in u.configitems('collections'):
76 prefix = util.pconvert(prefix)
76 prefix = util.pconvert(prefix)
77 for path in util.walkrepos(root, followsym=True):
77 for path in util.walkrepos(root, followsym=True):
78 repo = os.path.normpath(path)
78 repo = os.path.normpath(path)
79 name = util.pconvert(repo)
79 name = util.pconvert(repo)
80 if name.startswith(prefix):
80 if name.startswith(prefix):
81 name = name[len(prefix):]
81 name = name[len(prefix):]
82 repos.append((name.lstrip('/'), repo))
82 repos.append((name.lstrip('/'), repo))
83
83
84 self.repos = repos
84 self.repos = repos
85 self.ui = u
85 self.ui = u
86 encoding.encoding = self.ui.config('web', 'encoding',
86 encoding.encoding = self.ui.config('web', 'encoding',
87 encoding.encoding)
87 encoding.encoding)
88 self.style = self.ui.config('web', 'style', 'paper')
88 self.style = self.ui.config('web', 'style', 'paper')
89 self.templatepath = self.ui.config('web', 'templates', None)
89 self.templatepath = self.ui.config('web', 'templates', None)
90 self.stripecount = self.ui.config('web', 'stripes', 1)
90 self.stripecount = self.ui.config('web', 'stripes', 1)
91 if self.stripecount:
91 if self.stripecount:
92 self.stripecount = int(self.stripecount)
92 self.stripecount = int(self.stripecount)
93 self._baseurl = self.ui.config('web', 'baseurl')
93 self._baseurl = self.ui.config('web', 'baseurl')
94 self.lastrefresh = time.time()
94 self.lastrefresh = time.time()
95
95
96 def run(self):
96 def run(self):
97 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
97 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
98 raise RuntimeError("This function is only intended to be "
98 raise RuntimeError("This function is only intended to be "
99 "called while running as a CGI script.")
99 "called while running as a CGI script.")
100 import mercurial.hgweb.wsgicgi as wsgicgi
100 import mercurial.hgweb.wsgicgi as wsgicgi
101 wsgicgi.launch(self)
101 wsgicgi.launch(self)
102
102
103 def __call__(self, env, respond):
103 def __call__(self, env, respond):
104 req = wsgirequest(env, respond)
104 req = wsgirequest(env, respond)
105 return self.run_wsgi(req)
105 return self.run_wsgi(req)
106
106
107 def read_allowed(self, ui, req):
107 def read_allowed(self, ui, req):
108 """Check allow_read and deny_read config options of a repo's ui object
108 """Check allow_read and deny_read config options of a repo's ui object
109 to determine user permissions. By default, with neither option set (or
109 to determine user permissions. By default, with neither option set (or
110 both empty), allow all users to read the repo. There are two ways a
110 both empty), allow all users to read the repo. There are two ways a
111 user can be denied read access: (1) deny_read is not empty, and the
111 user can be denied read access: (1) deny_read is not empty, and the
112 user is unauthenticated or deny_read contains user (or *), and (2)
112 user is unauthenticated or deny_read contains user (or *), and (2)
113 allow_read is not empty and the user is not in allow_read. Return True
113 allow_read is not empty and the user is not in allow_read. Return True
114 if user is allowed to read the repo, else return False."""
114 if user is allowed to read the repo, else return False."""
115
115
116 user = req.env.get('REMOTE_USER')
116 user = req.env.get('REMOTE_USER')
117
117
118 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
118 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
119 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
119 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
120 return False
120 return False
121
121
122 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
122 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
123 # by default, allow reading if no allow_read option has been set
123 # by default, allow reading if no allow_read option has been set
124 if (not allow_read) or (allow_read == ['*']) or (user in allow_read):
124 if (not allow_read) or (allow_read == ['*']) or (user in allow_read):
125 return True
125 return True
126
126
127 return False
127 return False
128
128
129 def run_wsgi(self, req):
129 def run_wsgi(self, req):
130 try:
130 try:
131 try:
131 try:
132 self.refresh()
132 self.refresh()
133
133
134 virtual = req.env.get("PATH_INFO", "").strip('/')
134 virtual = req.env.get("PATH_INFO", "").strip('/')
135 tmpl = self.templater(req)
135 tmpl = self.templater(req)
136 ctype = tmpl('mimetype', encoding=encoding.encoding)
136 ctype = tmpl('mimetype', encoding=encoding.encoding)
137 ctype = templater.stringify(ctype)
137 ctype = templater.stringify(ctype)
138
138
139 # a static file
139 # a static file
140 if virtual.startswith('static/') or 'static' in req.form:
140 if virtual.startswith('static/') or 'static' in req.form:
141 if virtual.startswith('static/'):
141 if virtual.startswith('static/'):
142 fname = virtual[7:]
142 fname = virtual[7:]
143 else:
143 else:
144 fname = req.form['static'][0]
144 fname = req.form['static'][0]
145 static = templater.templatepath('static')
145 static = templater.templatepath('static')
146 return (staticfile(static, fname, req),)
146 return (staticfile(static, fname, req),)
147
147
148 # top-level index
148 # top-level index
149 elif not virtual:
149 elif not virtual:
150 req.respond(HTTP_OK, ctype)
150 req.respond(HTTP_OK, ctype)
151 return self.makeindex(req, tmpl)
151 return self.makeindex(req, tmpl)
152
152
153 # nested indexes and hgwebs
153 # nested indexes and hgwebs
154
154
155 repos = dict(self.repos)
155 repos = dict(self.repos)
156 while virtual:
156 while virtual:
157 real = repos.get(virtual)
157 real = repos.get(virtual)
158 if real:
158 if real:
159 req.env['REPO_NAME'] = virtual
159 req.env['REPO_NAME'] = virtual
160 try:
160 try:
161 repo = hg.repository(self.ui, real)
161 repo = hg.repository(self.ui, real)
162 return hgweb(repo).run_wsgi(req)
162 return hgweb(repo).run_wsgi(req)
163 except IOError, inst:
163 except IOError, inst:
164 msg = inst.strerror
164 msg = inst.strerror
165 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
165 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
166 except error.RepoError, inst:
166 except error.RepoError, inst:
167 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
167 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
168
168
169 # browse subdirectories
169 # browse subdirectories
170 subdir = virtual + '/'
170 subdir = virtual + '/'
171 if [r for r in repos if r.startswith(subdir)]:
171 if [r for r in repos if r.startswith(subdir)]:
172 req.respond(HTTP_OK, ctype)
172 req.respond(HTTP_OK, ctype)
173 return self.makeindex(req, tmpl, subdir)
173 return self.makeindex(req, tmpl, subdir)
174
174
175 up = virtual.rfind('/')
175 up = virtual.rfind('/')
176 if up < 0:
176 if up < 0:
177 break
177 break
178 virtual = virtual[:up]
178 virtual = virtual[:up]
179
179
180 # prefixes not found
180 # prefixes not found
181 req.respond(HTTP_NOT_FOUND, ctype)
181 req.respond(HTTP_NOT_FOUND, ctype)
182 return tmpl("notfound", repo=virtual)
182 return tmpl("notfound", repo=virtual)
183
183
184 except ErrorResponse, err:
184 except ErrorResponse, err:
185 req.respond(err, ctype)
185 req.respond(err, ctype)
186 return tmpl('error', error=err.message or '')
186 return tmpl('error', error=err.message or '')
187 finally:
187 finally:
188 tmpl = None
188 tmpl = None
189
189
190 def makeindex(self, req, tmpl, subdir=""):
190 def makeindex(self, req, tmpl, subdir=""):
191
191
192 def archivelist(ui, nodeid, url):
192 def archivelist(ui, nodeid, url):
193 allowed = ui.configlist("web", "allow_archive", untrusted=True)
193 allowed = ui.configlist("web", "allow_archive", untrusted=True)
194 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
194 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
195 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
195 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
196 untrusted=True):
196 untrusted=True):
197 yield {"type" : i[0], "extension": i[1],
197 yield {"type" : i[0], "extension": i[1],
198 "node": nodeid, "url": url}
198 "node": nodeid, "url": url}
199
199
200 def rawentries(subdir="", **map):
200 def rawentries(subdir="", **map):
201
201
202 descend = self.ui.configbool('web', 'descend', True)
202 descend = self.ui.configbool('web', 'descend', True)
203 for name, path in self.repos:
203 for name, path in self.repos:
204
204
205 if not name.startswith(subdir):
205 if not name.startswith(subdir):
206 continue
206 continue
207 name = name[len(subdir):]
207 name = name[len(subdir):]
208 if not descend and '/' in name:
208 if not descend and '/' in name:
209 continue
209 continue
210
210
211 u = self.ui.copy()
211 u = self.ui.copy()
212 try:
212 try:
213 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
213 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
214 except Exception, e:
214 except Exception, e:
215 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
215 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
216 continue
216 continue
217 def get(section, name, default=None):
217 def get(section, name, default=None):
218 return u.config(section, name, default, untrusted=True)
218 return u.config(section, name, default, untrusted=True)
219
219
220 if u.configbool("web", "hidden", untrusted=True):
220 if u.configbool("web", "hidden", untrusted=True):
221 continue
221 continue
222
222
223 if not self.read_allowed(u, req):
223 if not self.read_allowed(u, req):
224 continue
224 continue
225
225
226 parts = [name]
226 parts = [name]
227 if 'PATH_INFO' in req.env:
227 if 'PATH_INFO' in req.env:
228 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
228 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
229 if req.env['SCRIPT_NAME']:
229 if req.env['SCRIPT_NAME']:
230 parts.insert(0, req.env['SCRIPT_NAME'])
230 parts.insert(0, req.env['SCRIPT_NAME'])
231 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
231 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
232
232
233 # update time with local timezone
233 # update time with local timezone
234 try:
234 try:
235 r = hg.repository(self.ui, path)
235 r = hg.repository(self.ui, path)
236 d = (get_mtime(r.spath), util.makedate()[1])
236 d = (get_mtime(r.spath), util.makedate()[1])
237 except OSError:
237 except OSError:
238 continue
238 continue
239
239
240 contact = get_contact(get)
240 contact = get_contact(get)
241 description = get("web", "description", "")
241 description = get("web", "description", "")
242 name = get("web", "name", name)
242 name = get("web", "name", name)
243 row = dict(contact=contact or "unknown",
243 row = dict(contact=contact or "unknown",
244 contact_sort=contact.upper() or "unknown",
244 contact_sort=contact.upper() or "unknown",
245 name=name,
245 name=name,
246 name_sort=name,
246 name_sort=name,
247 url=url,
247 url=url,
248 description=description or "unknown",
248 description=description or "unknown",
249 description_sort=description.upper() or "unknown",
249 description_sort=description.upper() or "unknown",
250 lastchange=d,
250 lastchange=d,
251 lastchange_sort=d[1]-d[0],
251 lastchange_sort=d[1]-d[0],
252 archives=archivelist(u, "tip", url))
252 archives=archivelist(u, "tip", url))
253 yield row
253 yield row
254
254
255 sortdefault = None, False
255 sortdefault = None, False
256 def entries(sortcolumn="", descending=False, subdir="", **map):
256 def entries(sortcolumn="", descending=False, subdir="", **map):
257 rows = rawentries(subdir=subdir, **map)
257 rows = rawentries(subdir=subdir, **map)
258
258
259 if sortcolumn and sortdefault != (sortcolumn, descending):
259 if sortcolumn and sortdefault != (sortcolumn, descending):
260 sortkey = '%s_sort' % sortcolumn
260 sortkey = '%s_sort' % sortcolumn
261 rows = sorted(rows, key=lambda x: x[sortkey],
261 rows = sorted(rows, key=lambda x: x[sortkey],
262 reverse=descending)
262 reverse=descending)
263 for row, parity in zip(rows, paritygen(self.stripecount)):
263 for row, parity in zip(rows, paritygen(self.stripecount)):
264 row['parity'] = parity
264 row['parity'] = parity
265 yield row
265 yield row
266
266
267 self.refresh()
267 self.refresh()
268 sortable = ["name", "description", "contact", "lastchange"]
268 sortable = ["name", "description", "contact", "lastchange"]
269 sortcolumn, descending = sortdefault
269 sortcolumn, descending = sortdefault
270 if 'sort' in req.form:
270 if 'sort' in req.form:
271 sortcolumn = req.form['sort'][0]
271 sortcolumn = req.form['sort'][0]
272 descending = sortcolumn.startswith('-')
272 descending = sortcolumn.startswith('-')
273 if descending:
273 if descending:
274 sortcolumn = sortcolumn[1:]
274 sortcolumn = sortcolumn[1:]
275 if sortcolumn not in sortable:
275 if sortcolumn not in sortable:
276 sortcolumn = ""
276 sortcolumn = ""
277
277
278 sort = [("sort_%s" % column,
278 sort = [("sort_%s" % column,
279 "%s%s" % ((not descending and column == sortcolumn)
279 "%s%s" % ((not descending and column == sortcolumn)
280 and "-" or "", column))
280 and "-" or "", column))
281 for column in sortable]
281 for column in sortable]
282
282
283 self.refresh()
283 self.refresh()
284 self.updatereqenv(req.env)
284 self.updatereqenv(req.env)
285
285
286 return tmpl("index", entries=entries, subdir=subdir,
286 return tmpl("index", entries=entries, subdir=subdir,
287 sortcolumn=sortcolumn, descending=descending,
287 sortcolumn=sortcolumn, descending=descending,
288 **dict(sort))
288 **dict(sort))
289
289
290 def templater(self, req):
290 def templater(self, req):
291
291
292 def header(**map):
292 def header(**map):
293 yield tmpl('header', encoding=encoding.encoding, **map)
293 yield tmpl('header', encoding=encoding.encoding, **map)
294
294
295 def footer(**map):
295 def footer(**map):
296 yield tmpl("footer", **map)
296 yield tmpl("footer", **map)
297
297
298 def motd(**map):
298 def motd(**map):
299 if self.motd is not None:
299 if self.motd is not None:
300 yield self.motd
300 yield self.motd
301 else:
301 else:
302 yield config('web', 'motd', '')
302 yield config('web', 'motd', '')
303
303
304 def config(section, name, default=None, untrusted=True):
304 def config(section, name, default=None, untrusted=True):
305 return self.ui.config(section, name, default, untrusted)
305 return self.ui.config(section, name, default, untrusted)
306
306
307 self.updatereqenv(req.env)
307 self.updatereqenv(req.env)
308
308
309 url = req.env.get('SCRIPT_NAME', '')
309 url = req.env.get('SCRIPT_NAME', '')
310 if not url.endswith('/'):
310 if not url.endswith('/'):
311 url += '/'
311 url += '/'
312
312
313 vars = {}
313 vars = {}
314 styles = (
314 styles = (
315 req.form.get('style', [None])[0],
315 req.form.get('style', [None])[0],
316 config('web', 'style'),
316 config('web', 'style'),
317 'paper'
317 'paper'
318 )
318 )
319 style, mapfile = templater.stylemap(styles, self.templatepath)
319 style, mapfile = templater.stylemap(styles, self.templatepath)
320 if style == styles[0]:
320 if style == styles[0]:
321 vars['style'] = style
321 vars['style'] = style
322
322
323 start = url[-1] == '?' and '&' or '?'
323 start = url[-1] == '?' and '&' or '?'
324 sessionvars = webutil.sessionvars(vars, start)
324 sessionvars = webutil.sessionvars(vars, start)
325 staticurl = config('web', 'staticurl') or url + 'static/'
325 staticurl = config('web', 'staticurl') or url + 'static/'
326 if not staticurl.endswith('/'):
326 if not staticurl.endswith('/'):
327 staticurl += '/'
327 staticurl += '/'
328
328
329 tmpl = templater.templater(mapfile,
329 tmpl = templater.templater(mapfile,
330 defaults={"header": header,
330 defaults={"header": header,
331 "footer": footer,
331 "footer": footer,
332 "motd": motd,
332 "motd": motd,
333 "url": url,
333 "url": url,
334 "staticurl": staticurl,
334 "staticurl": staticurl,
335 "sessionvars": sessionvars})
335 "sessionvars": sessionvars})
336 return tmpl
336 return tmpl
337
337
338 def updatereqenv(self, env):
338 def updatereqenv(self, env):
339 def splitnetloc(netloc):
339 def splitnetloc(netloc):
340 if ':' in netloc:
340 if ':' in netloc:
341 return netloc.split(':', 1)
341 return netloc.split(':', 1)
342 else:
342 else:
343 return (netloc, None)
343 return (netloc, None)
344
344
345 if self._baseurl is not None:
345 if self._baseurl is not None:
346 urlcomp = urlparse.urlparse(self._baseurl)
346 urlcomp = urlparse.urlparse(self._baseurl)
347 host, port = splitnetloc(urlcomp[1])
347 host, port = splitnetloc(urlcomp[1])
348 path = urlcomp[2]
348 path = urlcomp[2]
349 env['SERVER_NAME'] = host
349 env['SERVER_NAME'] = host
350 if port:
350 if port:
351 env['SERVER_PORT'] = port
351 env['SERVER_PORT'] = port
352 env['SCRIPT_NAME'] = path
352 env['SCRIPT_NAME'] = path
@@ -1,70 +1,75 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat >> $HGRCPATH <<EOF
3 cat >> $HGRCPATH <<EOF
4 [alias]
4 [alias]
5 myinit = init
5 myinit = init
6 cleanstatus = status -c
6 cleanstatus = status -c
7 unknown = bargle
7 unknown = bargle
8 ambiguous = s
8 ambiguous = s
9 recursive = recursive
9 recursive = recursive
10 nodefinition =
10 nodefinition =
11 mylog = log
11 mylog = log
12 lognull = log -r null
12 lognull = log -r null
13 shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
13 shortlog = log --template '{rev} {node|short} | {date|isodate}\n'
14 dln = lognull --debug
14 dln = lognull --debug
15 nousage = rollback
15 nousage = rollback
16 put = export -r 0 -o "\$FOO/%R.diff"
16 put = export -r 0 -o "\$FOO/%R.diff"
17 echo = !echo
17 echo = !echo
18 rt = root
18
19
19 [defaults]
20 [defaults]
20 mylog = -q
21 mylog = -q
21 lognull = -q
22 lognull = -q
22 log = -v
23 log = -v
23 EOF
24 EOF
24
25
25 echo '% basic'
26 echo '% basic'
26 hg myinit alias
27 hg myinit alias
27
28
28 echo '% unknown'
29 echo '% unknown'
29 hg unknown
30 hg unknown
30 hg help unknown
31 hg help unknown
31
32
32 echo '% ambiguous'
33 echo '% ambiguous'
33 hg ambiguous
34 hg ambiguous
34 hg help ambiguous
35 hg help ambiguous
35
36
36 echo '% recursive'
37 echo '% recursive'
37 hg recursive
38 hg recursive
38 hg help recursive
39 hg help recursive
39
40
40 echo '% no definition'
41 echo '% no definition'
41 hg nodef
42 hg nodef
42 hg help nodef
43 hg help nodef
43
44
44 cd alias
45 cd alias
45
46
46 echo '% no usage'
47 echo '% no usage'
47 hg nousage
48 hg nousage
48
49
49 echo foo > foo
50 echo foo > foo
50 hg ci -Amfoo
51 hg ci -Amfoo
51
52
52 echo '% with opts'
53 echo '% with opts'
53 hg cleanst
54 hg cleanst
54
55
55 echo '% with opts and whitespace'
56 echo '% with opts and whitespace'
56 hg shortlog
57 hg shortlog
57
58
58 echo '% interaction with defaults'
59 echo '% interaction with defaults'
59 hg mylog
60 hg mylog
60 hg lognull
61 hg lognull
61
62
62 echo '% properly recursive'
63 echo '% properly recursive'
63 hg dln
64 hg dln
64
65
65 echo '% path expanding'
66 echo '% path expanding'
66 FOO=`pwd` hg put
67 FOO=`pwd` hg put
67 cat 0.diff
68 cat 0.diff
68
69
69 echo '% shell aliases'
70 echo '% shell aliases'
70 hg echo foo
71 hg echo foo
72 echo '% invalid arguments'
73 hg rt foo
74
75 exit 0
@@ -1,47 +1,60 b''
1 % basic
1 % basic
2 % unknown
2 % unknown
3 alias 'unknown' resolves to unknown command 'bargle'
3 alias 'unknown' resolves to unknown command 'bargle'
4 alias 'unknown' resolves to unknown command 'bargle'
4 alias 'unknown' resolves to unknown command 'bargle'
5 % ambiguous
5 % ambiguous
6 alias 'ambiguous' resolves to ambiguous command 's'
6 alias 'ambiguous' resolves to ambiguous command 's'
7 alias 'ambiguous' resolves to ambiguous command 's'
7 alias 'ambiguous' resolves to ambiguous command 's'
8 % recursive
8 % recursive
9 alias 'recursive' resolves to unknown command 'recursive'
9 alias 'recursive' resolves to unknown command 'recursive'
10 alias 'recursive' resolves to unknown command 'recursive'
10 alias 'recursive' resolves to unknown command 'recursive'
11 % no definition
11 % no definition
12 no definition for alias 'nodefinition'
12 no definition for alias 'nodefinition'
13 no definition for alias 'nodefinition'
13 no definition for alias 'nodefinition'
14 % no usage
14 % no usage
15 no rollback information available
15 no rollback information available
16 adding foo
16 adding foo
17 % with opts
17 % with opts
18 C foo
18 C foo
19 % with opts and whitespace
19 % with opts and whitespace
20 0 e63c23eaa88a | 1970-01-01 00:00 +0000
20 0 e63c23eaa88a | 1970-01-01 00:00 +0000
21 % interaction with defaults
21 % interaction with defaults
22 0:e63c23eaa88a
22 0:e63c23eaa88a
23 -1:000000000000
23 -1:000000000000
24 % properly recursive
24 % properly recursive
25 changeset: -1:0000000000000000000000000000000000000000
25 changeset: -1:0000000000000000000000000000000000000000
26 parent: -1:0000000000000000000000000000000000000000
26 parent: -1:0000000000000000000000000000000000000000
27 parent: -1:0000000000000000000000000000000000000000
27 parent: -1:0000000000000000000000000000000000000000
28 manifest: -1:0000000000000000000000000000000000000000
28 manifest: -1:0000000000000000000000000000000000000000
29 user:
29 user:
30 date: Thu Jan 01 00:00:00 1970 +0000
30 date: Thu Jan 01 00:00:00 1970 +0000
31 extra: branch=default
31 extra: branch=default
32
32
33 % path expanding
33 % path expanding
34 # HG changeset patch
34 # HG changeset patch
35 # User test
35 # User test
36 # Date 0 0
36 # Date 0 0
37 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
37 # Node ID e63c23eaa88ae77967edcf4ea194d31167c478b0
38 # Parent 0000000000000000000000000000000000000000
38 # Parent 0000000000000000000000000000000000000000
39 foo
39 foo
40
40
41 diff -r 000000000000 -r e63c23eaa88a foo
41 diff -r 000000000000 -r e63c23eaa88a foo
42 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
43 +++ b/foo Thu Jan 01 00:00:00 1970 +0000
44 @@ -0,0 +1,1 @@
44 @@ -0,0 +1,1 @@
45 +foo
45 +foo
46 % shell aliases
46 % shell aliases
47 foo
47 foo
48 % invalid arguments
49 hg rt: invalid arguments
50 hg rt
51
52 alias for: hg root
53
54 print the root (top) of the current working directory
55
56 Print the root directory of the current repository.
57
58 Returns 0 on success.
59
60 use "hg -v help rt" to show global options
@@ -1,27 +1,33 b''
1 #!/bin/sh
1 #!/bin/sh
2 # test command parsing and dispatch
2 # test command parsing and dispatch
3
3
4 "$TESTDIR/hghave" no-outer-repo || exit 80
4 "$TESTDIR/hghave" no-outer-repo || exit 80
5
5
6 dir=`pwd`
7
6 hg init a
8 hg init a
7 cd a
9 cd a
8 echo a > a
10 echo a > a
9 hg ci -Ama
11 hg ci -Ama
10
12
11 echo "# missing arg"
13 echo "# missing arg"
12 hg cat
14 hg cat
13
15
14 echo '% [defaults]'
16 echo '% [defaults]'
15 hg cat a
17 hg cat a
16 cat >> $HGRCPATH <<EOF
18 cat >> $HGRCPATH <<EOF
17 [defaults]
19 [defaults]
18 cat = -r null
20 cat = -r null
19 EOF
21 EOF
20 hg cat a
22 hg cat a
21
23
24 echo '% working directory removed'
25 rm -rf $dir/a
26 hg --version
27
22 echo '% no repo'
28 echo '% no repo'
23 cd ..
29 cd $dir
24 hg cat
30 hg cat
25
31
26 exit 0
32 exit 0
27
33
@@ -1,37 +1,39 b''
1 adding a
1 adding a
2 # missing arg
2 # missing arg
3 hg cat: invalid arguments
3 hg cat: invalid arguments
4 hg cat [OPTION]... FILE...
4 hg cat [OPTION]... FILE...
5
5
6 output the current or given revision of files
6 output the current or given revision of files
7
7
8 Print the specified files as they were at the given revision. If no
8 Print the specified files as they were at the given revision. If no
9 revision is given, the parent of the working directory is used, or tip if
9 revision is given, the parent of the working directory is used, or tip if
10 no revision is checked out.
10 no revision is checked out.
11
11
12 Output may be to a file, in which case the name of the file is given using
12 Output may be to a file, in which case the name of the file is given using
13 a format string. The formatting rules are the same as for the export
13 a format string. The formatting rules are the same as for the export
14 command, with the following additions:
14 command, with the following additions:
15
15
16 "%s" basename of file being printed
16 "%s" basename of file being printed
17 "%d" dirname of file being printed, or '.' if in repository root
17 "%d" dirname of file being printed, or '.' if in repository root
18 "%p" root-relative path name of file being printed
18 "%p" root-relative path name of file being printed
19
19
20 Returns 0 on success.
20 Returns 0 on success.
21
21
22 options:
22 options:
23
23
24 -o --output FORMAT print output to file with formatted name
24 -o --output FORMAT print output to file with formatted name
25 -r --rev REV print the given revision
25 -r --rev REV print the given revision
26 --decode apply any matching decode filter
26 --decode apply any matching decode filter
27 -I --include PATTERN [+] include names matching the given patterns
27 -I --include PATTERN [+] include names matching the given patterns
28 -X --exclude PATTERN [+] exclude names matching the given patterns
28 -X --exclude PATTERN [+] exclude names matching the given patterns
29
29
30 [+] marked option can be specified multiple times
30 [+] marked option can be specified multiple times
31
31
32 use "hg -v help cat" to show global options
32 use "hg -v help cat" to show global options
33 % [defaults]
33 % [defaults]
34 a
34 a
35 a: No such file in rev 000000000000
35 a: No such file in rev 000000000000
36 % working directory removed
37 abort: error getting current working directory: No such file or directory
36 % no repo
38 % no repo
37 abort: There is no Mercurial repository here (.hg not found)!
39 abort: There is no Mercurial repository here (.hg not found)!
@@ -1,123 +1,127 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 ########################################
3 ########################################
4
4
5 HGENCODING=utf-8
5 HGENCODING=utf-8
6 export HGENCODING
6 export HGENCODING
7
7
8 hg init t
8 hg init t
9 cd t
9 cd t
10
10
11 python << EOF
11 python << EOF
12 # (byte, width) = (6, 4)
12 # (byte, width) = (6, 4)
13 s = "\xe7\x9f\xad\xe5\x90\x8d"
13 s = "\xe7\x9f\xad\xe5\x90\x8d"
14 # (byte, width) = (7, 7): odd width is good for alignment test
14 # (byte, width) = (7, 7): odd width is good for alignment test
15 m = "MIDDLE_"
15 m = "MIDDLE_"
16 # (byte, width) = (18, 12)
16 # (byte, width) = (18, 12)
17 l = "\xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d"
17 l = "\xe9\x95\xb7\xe3\x81\x84\xe9\x95\xb7\xe3\x81\x84\xe5\x90\x8d\xe5\x89\x8d"
18
18
19 f = file('s', 'w'); f.write(s); f.close()
19 f = file('s', 'w'); f.write(s); f.close()
20 f = file('m', 'w'); f.write(m); f.close()
20 f = file('m', 'w'); f.write(m); f.close()
21 f = file('l', 'w'); f.write(l); f.close()
21 f = file('l', 'w'); f.write(l); f.close()
22
22
23 # instant extension to show list of options
23 # instant extension to show list of options
24 f = file('showoptlist.py', 'w'); f.write("""# encoding: utf-8
24 f = file('showoptlist.py', 'w'); f.write("""# encoding: utf-8
25 def showoptlist(ui, repo, *pats, **opts):
25 def showoptlist(ui, repo, *pats, **opts):
26 '''dummy command to show option descriptions'''
26 '''dummy command to show option descriptions'''
27 return 0
27 return 0
28
28
29 cmdtable = {
29 cmdtable = {
30 'showoptlist':
30 'showoptlist':
31 (showoptlist,
31 (showoptlist,
32 [('s', 'opt1', '', 'short width', '""" + s + """'),
32 [('s', 'opt1', '', 'short width', '""" + s + """'),
33 ('m', 'opt2', '', 'middle width', '""" + m + """'),
33 ('m', 'opt2', '', 'middle width', '""" + m + """'),
34 ('l', 'opt3', '', 'long width', '""" + l + """')
34 ('l', 'opt3', '', 'long width', '""" + l + """')
35 ],
35 ],
36 ""
36 ""
37 )
37 )
38 }
38 }
39 """)
39 """)
40 f.close()
40 f.close()
41 EOF
41 EOF
42
42
43 S=`cat s`
43 S=`cat s`
44 M=`cat m`
44 M=`cat m`
45 L=`cat l`
45 L=`cat l`
46
46
47 ########################################
47 ########################################
48 #### alignment of:
48 #### alignment of:
49 #### - option descriptions in help
49 #### - option descriptions in help
50
50
51 cat <<EOF > .hg/hgrc
51 cat <<EOF > .hg/hgrc
52 [extensions]
52 [extensions]
53 ja_ext = `pwd`/showoptlist.py
53 ja_ext = `pwd`/showoptlist.py
54 EOF
54 EOF
55 echo '% check alignment of option descriptions in help'
55 echo '% check alignment of option descriptions in help'
56 hg help showoptlist
56 hg help showoptlist
57
57
58 ########################################
58 ########################################
59 #### alignment of:
59 #### alignment of:
60 #### - user names in annotate
60 #### - user names in annotate
61 #### - file names in diffstat
61 #### - file names in diffstat
62
62
63 rm -f s; touch s
64 rm -f m; touch m
65 rm -f l; touch l
66
63 #### add files
67 #### add files
64
68
65 touch $S
69 cp s $S
66 hg add $S
70 hg add $S
67 touch $M
71 cp m $M
68 hg add $M
72 hg add $M
69 touch $L
73 cp l $L
70 hg add $L
74 hg add $L
71
75
72 #### commit(1)
76 #### commit(1)
73
77
74 echo 'first line(1)' >> $S
78 echo 'first line(1)' >> s; cp s $S
75 echo 'first line(2)' >> $M
79 echo 'first line(2)' >> m; cp m $M
76 echo 'first line(3)' >> $L
80 echo 'first line(3)' >> l; cp l $L
77 hg commit -m 'first commit' -u $S -d "1000000 0"
81 hg commit -m 'first commit' -u $S -d "1000000 0"
78
82
79 #### commit(2)
83 #### commit(2)
80
84
81 echo 'second line(1)' >> $S
85 echo 'second line(1)' >> s; cp s $S
82 echo 'second line(2)' >> $M
86 echo 'second line(2)' >> m; cp m $M
83 echo 'second line(3)' >> $L
87 echo 'second line(3)' >> l; cp l $L
84 hg commit -m 'second commit' -u $M -d "1000000 0"
88 hg commit -m 'second commit' -u $M -d "1000000 0"
85
89
86 #### commit(3)
90 #### commit(3)
87
91
88 echo 'third line(1)' >> $S
92 echo 'third line(1)' >> s; cp s $S
89 echo 'third line(2)' >> $M
93 echo 'third line(2)' >> m; cp m $M
90 echo 'third line(3)' >> $L
94 echo 'third line(3)' >> l; cp l $L
91 hg commit -m 'third commit' -u $L -d "1000000 0"
95 hg commit -m 'third commit' -u $L -d "1000000 0"
92
96
93 #### check
97 #### check
94
98
95 echo '% check alignment of user names in annotate'
99 echo '% check alignment of user names in annotate'
96 hg annotate -u $M
100 hg annotate -u $M
97 echo '% check alignment of filenames in diffstat'
101 echo '% check alignment of filenames in diffstat'
98 hg diff -c tip --stat
102 hg diff -c tip --stat
99
103
100 ########################################
104 ########################################
101 #### alignment of:
105 #### alignment of:
102 #### - branch names in list
106 #### - branch names in list
103 #### - tag names in list
107 #### - tag names in list
104
108
105 #### add branches/tags
109 #### add branches/tags
106
110
107 hg branch $S
111 hg branch $S
108 hg tag -d "1000000 0" $S
112 hg tag -d "1000000 0" $S
109 hg branch $M
113 hg branch $M
110 hg tag -d "1000000 0" $M
114 hg tag -d "1000000 0" $M
111 hg branch $L
115 hg branch $L
112 hg tag -d "1000000 0" $L
116 hg tag -d "1000000 0" $L
113
117
114 #### check
118 #### check
115
119
116 echo '% check alignment of branches'
120 echo '% check alignment of branches'
117 hg tags
121 hg tags
118 echo '% check alignment of tags'
122 echo '% check alignment of tags'
119 hg tags
123 hg tags
120
124
121 ########################################
125 ########################################
122
126
123 exit 0
127 exit 0
@@ -1,161 +1,163 b''
1 #!/bin/sh
1 #!/bin/sh
2 # Tests some basic hgwebdir functionality. Tests setting up paths and
2 # Tests some basic hgwebdir functionality. Tests setting up paths and
3 # collection, different forms of 404s and the subdirectory support.
3 # collection, different forms of 404s and the subdirectory support.
4
4
5 mkdir webdir
5 mkdir webdir
6 cd webdir
6 cd webdir
7
7
8 hg init a
8 hg init a
9 echo a > a/a
9 echo a > a/a
10 hg --cwd a ci -Ama -d'1 0'
10 hg --cwd a ci -Ama -d'1 0'
11 # create a mercurial queue repository
11 # create a mercurial queue repository
12 hg --cwd a qinit --config extensions.hgext.mq= -c
12 hg --cwd a qinit --config extensions.hgext.mq= -c
13
13
14 hg init b
14 hg init b
15 echo b > b/b
15 echo b > b/b
16 hg --cwd b ci -Amb -d'2 0'
16 hg --cwd b ci -Amb -d'2 0'
17
17
18 # create a nested repository
18 # create a nested repository
19 cd b
19 cd b
20 hg init d
20 hg init d
21 echo d > d/d
21 echo d > d/d
22 hg --cwd d ci -Amd -d'3 0'
22 hg --cwd d ci -Amd -d'3 0'
23 cd ..
23 cd ..
24
24
25 hg init c
25 hg init c
26 echo c > c/c
26 echo c > c/c
27 hg --cwd c ci -Amc -d'3 0'
27 hg --cwd c ci -Amc -d'3 0'
28
28
29 root=`pwd`
29 root=`pwd`
30 cd ..
30 cd ..
31
31
32
32
33 cat > paths.conf <<EOF
33 cat > paths.conf <<EOF
34 [paths]
34 [paths]
35 a=$root/a
35 a=$root/a
36 b=$root/b
36 b=$root/b
37 EOF
37 EOF
38
38
39 hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
39 hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
40 -A access-paths.log -E error-paths-1.log
40 -A access-paths.log -E error-paths-1.log
41 cat hg.pid >> $DAEMON_PIDS
41 cat hg.pid >> $DAEMON_PIDS
42
42
43 echo % should give a 404 - file does not exist
43 echo % should give a 404 - file does not exist
44 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
44 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
45
45
46 echo % should succeed
46 echo % should succeed
47 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
47 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
48 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
48 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
49 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
49 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
50
50
51 echo % should give a 404 - repo is not published
51 echo % should give a 404 - repo is not published
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
53
53
54 echo % atom-log without basedir
54 echo % atom-log without basedir
55 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' \
55 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' \
56 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
56 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
57
57
58 echo % rss-log without basedir
58 echo % rss-log without basedir
59 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' \
59 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' \
60 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
60 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
61
61
62 cat > paths.conf <<EOF
62 cat > paths.conf <<EOF
63 [paths]
63 [paths]
64 t/a/=$root/a
64 t/a/=$root/a
65 b=$root/b
65 b=$root/b
66 coll=$root/*
66 coll=$root/*
67 rcoll=$root/**
67 rcoll=$root/**
68 star=*
69 starstar=**
68 EOF
70 EOF
69
71
70 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
72 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
71 -A access-paths.log -E error-paths-2.log
73 -A access-paths.log -E error-paths-2.log
72 cat hg.pid >> $DAEMON_PIDS
74 cat hg.pid >> $DAEMON_PIDS
73
75
74 echo % should succeed, slashy names
76 echo % should succeed, slashy names
75 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
77 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
76 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
78 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
77 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
79 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
78 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
80 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
79 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
81 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
80 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
81 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
83 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
83 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
85 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
85 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
87 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
87 # Test [paths] '*' extension
89 # Test [paths] '*' extension
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
90 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
89 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
91 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
90 #test [paths] '**' extension
92 #test [paths] '**' extension
91 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
93 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
92 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
94 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
93
95
94
96
95 "$TESTDIR/killdaemons.py"
97 "$TESTDIR/killdaemons.py"
96 cat > paths.conf <<EOF
98 cat > paths.conf <<EOF
97 [paths]
99 [paths]
98 t/a = $root/a
100 t/a = $root/a
99 t/b = $root/b
101 t/b = $root/b
100 c = $root/c
102 c = $root/c
101 [web]
103 [web]
102 descend=false
104 descend=false
103 EOF
105 EOF
104
106
105 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
107 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
106 -A access-paths.log -E error-paths-3.log
108 -A access-paths.log -E error-paths-3.log
107 cat hg.pid >> $DAEMON_PIDS
109 cat hg.pid >> $DAEMON_PIDS
108 echo % test descend = False
110 echo % test descend = False
109 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
111 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
110 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
112 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
111
113
112
114
113 cat > collections.conf <<EOF
115 cat > collections.conf <<EOF
114 [collections]
116 [collections]
115 $root=$root
117 $root=$root
116 EOF
118 EOF
117
119
118 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
120 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
119 --pid-file=hg.pid --webdir-conf collections.conf \
121 --pid-file=hg.pid --webdir-conf collections.conf \
120 -A access-collections.log -E error-collections.log
122 -A access-collections.log -E error-collections.log
121 cat hg.pid >> $DAEMON_PIDS
123 cat hg.pid >> $DAEMON_PIDS
122
124
123 echo % collections: should succeed
125 echo % collections: should succeed
124 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
126 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
125 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
127 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
126 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
128 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
127 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
129 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
128
130
129 echo % atom-log with basedir /
131 echo % atom-log with basedir /
130 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
132 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
131 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
133 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
132
134
133 echo % rss-log with basedir /
135 echo % rss-log with basedir /
134 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
136 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
135 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
137 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
136
138
137 "$TESTDIR/killdaemons.py"
139 "$TESTDIR/killdaemons.py"
138
140
139 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
141 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
140 --pid-file=hg.pid --webdir-conf collections.conf \
142 --pid-file=hg.pid --webdir-conf collections.conf \
141 -A access-collections-2.log -E error-collections-2.log
143 -A access-collections-2.log -E error-collections-2.log
142 cat hg.pid >> $DAEMON_PIDS
144 cat hg.pid >> $DAEMON_PIDS
143
145
144 echo % atom-log with basedir /foo/
146 echo % atom-log with basedir /foo/
145 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
147 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
146 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
148 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
147
149
148 echo % rss-log with basedir /foo/
150 echo % rss-log with basedir /foo/
149 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
151 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
150 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
152 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
151
153
152 echo % paths errors 1
154 echo % paths errors 1
153 cat error-paths-1.log
155 cat error-paths-1.log
154 echo % paths errors 2
156 echo % paths errors 2
155 cat error-paths-2.log
157 cat error-paths-2.log
156 echo % paths errors 3
158 echo % paths errors 3
157 cat error-paths-3.log
159 cat error-paths-3.log
158 echo % collections errors
160 echo % collections errors
159 cat error-collections.log
161 cat error-collections.log
160 echo % collections errors 2
162 echo % collections errors 2
161 cat error-collections-2.log
163 cat error-collections-2.log
@@ -1,362 +1,443 b''
1 adding a
1 adding a
2 adding b
2 adding b
3 adding d
3 adding d
4 adding c
4 adding c
5 % should give a 404 - file does not exist
5 % should give a 404 - file does not exist
6 404 Not Found
6 404 Not Found
7
7
8
8
9 error: bork@8580ff50825a: not found in manifest
9 error: bork@8580ff50825a: not found in manifest
10 % should succeed
10 % should succeed
11 200 Script output follows
11 200 Script output follows
12
12
13
13
14 /a/
14 /a/
15 /b/
15 /b/
16
16
17 200 Script output follows
17 200 Script output follows
18
18
19 a
19 a
20 200 Script output follows
20 200 Script output follows
21
21
22 b
22 b
23 % should give a 404 - repo is not published
23 % should give a 404 - repo is not published
24 404 Not Found
24 404 Not Found
25
25
26
26
27 error: repository c not found
27 error: repository c not found
28 % atom-log without basedir
28 % atom-log without basedir
29 <link rel="self" href="http://example.com:8080/a/atom-log"/>
29 <link rel="self" href="http://example.com:8080/a/atom-log"/>
30 <link rel="alternate" href="http://example.com:8080/a/"/>
30 <link rel="alternate" href="http://example.com:8080/a/"/>
31 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
31 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
32 % rss-log without basedir
32 % rss-log without basedir
33 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
33 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
34 % should succeed, slashy names
34 % should succeed, slashy names
35 200 Script output follows
35 200 Script output follows
36
36
37
37
38 /t/a/
38 /t/a/
39 /b/
39 /b/
40 /coll/a/
40 /coll/a/
41 /coll/a/.hg/patches/
41 /coll/a/.hg/patches/
42 /coll/b/
42 /coll/b/
43 /coll/c/
43 /coll/c/
44 /rcoll/a/
44 /rcoll/a/
45 /rcoll/a/.hg/patches/
45 /rcoll/a/.hg/patches/
46 /rcoll/b/
46 /rcoll/b/
47 /rcoll/b/d/
47 /rcoll/b/d/
48 /rcoll/c/
48 /rcoll/c/
49 /star/webdir/a/
50 /star/webdir/a/.hg/patches/
51 /star/webdir/b/
52 /star/webdir/c/
53 /starstar/webdir/a/
54 /starstar/webdir/a/.hg/patches/
55 /starstar/webdir/b/
56 /starstar/webdir/b/d/
57 /starstar/webdir/c/
49
58
50 200 Script output follows
59 200 Script output follows
51
60
52 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
61 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
53 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
62 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
54 <head>
63 <head>
55 <link rel="icon" href="/static/hgicon.png" type="image/png" />
64 <link rel="icon" href="/static/hgicon.png" type="image/png" />
56 <meta name="robots" content="index, nofollow" />
65 <meta name="robots" content="index, nofollow" />
57 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
66 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
58
67
59 <title>Mercurial repositories index</title>
68 <title>Mercurial repositories index</title>
60 </head>
69 </head>
61 <body>
70 <body>
62
71
63 <div class="container">
72 <div class="container">
64 <div class="menu">
73 <div class="menu">
65 <a href="http://mercurial.selenic.com/">
74 <a href="http://mercurial.selenic.com/">
66 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
75 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
67 </div>
76 </div>
68 <div class="main">
77 <div class="main">
69 <h2>Mercurial Repositories</h2>
78 <h2>Mercurial Repositories</h2>
70
79
71 <table class="bigtable">
80 <table class="bigtable">
72 <tr>
81 <tr>
73 <th><a href="?sort=name">Name</a></th>
82 <th><a href="?sort=name">Name</a></th>
74 <th><a href="?sort=description">Description</a></th>
83 <th><a href="?sort=description">Description</a></th>
75 <th><a href="?sort=contact">Contact</a></th>
84 <th><a href="?sort=contact">Contact</a></th>
76 <th><a href="?sort=lastchange">Last modified</a></th>
85 <th><a href="?sort=lastchange">Last modified</a></th>
77 <th>&nbsp;</th>
86 <th>&nbsp;</th>
78 </tr>
87 </tr>
79
88
80 <tr class="parity0">
89 <tr class="parity0">
81 <td><a href="/t/a/?style=paper">t/a</a></td>
90 <td><a href="/t/a/?style=paper">t/a</a></td>
82 <td>unknown</td>
91 <td>unknown</td>
83 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
92 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
84 <td class="age">seconds ago</td>
93 <td class="age">seconds ago</td>
85 <td class="indexlinks"></td>
94 <td class="indexlinks"></td>
86 </tr>
95 </tr>
87
96
88 <tr class="parity1">
97 <tr class="parity1">
89 <td><a href="/b/?style=paper">b</a></td>
98 <td><a href="/b/?style=paper">b</a></td>
90 <td>unknown</td>
99 <td>unknown</td>
91 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
100 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
92 <td class="age">seconds ago</td>
101 <td class="age">seconds ago</td>
93 <td class="indexlinks"></td>
102 <td class="indexlinks"></td>
94 </tr>
103 </tr>
95
104
96 <tr class="parity0">
105 <tr class="parity0">
97 <td><a href="/coll/a/?style=paper">coll/a</a></td>
106 <td><a href="/coll/a/?style=paper">coll/a</a></td>
98 <td>unknown</td>
107 <td>unknown</td>
99 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
108 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
100 <td class="age">seconds ago</td>
109 <td class="age">seconds ago</td>
101 <td class="indexlinks"></td>
110 <td class="indexlinks"></td>
102 </tr>
111 </tr>
103
112
104 <tr class="parity1">
113 <tr class="parity1">
105 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
114 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
106 <td>unknown</td>
115 <td>unknown</td>
107 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
116 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
108 <td class="age">seconds ago</td>
117 <td class="age">seconds ago</td>
109 <td class="indexlinks"></td>
118 <td class="indexlinks"></td>
110 </tr>
119 </tr>
111
120
112 <tr class="parity0">
121 <tr class="parity0">
113 <td><a href="/coll/b/?style=paper">coll/b</a></td>
122 <td><a href="/coll/b/?style=paper">coll/b</a></td>
114 <td>unknown</td>
123 <td>unknown</td>
115 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
124 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
116 <td class="age">seconds ago</td>
125 <td class="age">seconds ago</td>
117 <td class="indexlinks"></td>
126 <td class="indexlinks"></td>
118 </tr>
127 </tr>
119
128
120 <tr class="parity1">
129 <tr class="parity1">
121 <td><a href="/coll/c/?style=paper">coll/c</a></td>
130 <td><a href="/coll/c/?style=paper">coll/c</a></td>
122 <td>unknown</td>
131 <td>unknown</td>
123 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
132 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
124 <td class="age">seconds ago</td>
133 <td class="age">seconds ago</td>
125 <td class="indexlinks"></td>
134 <td class="indexlinks"></td>
126 </tr>
135 </tr>
127
136
128 <tr class="parity0">
137 <tr class="parity0">
129 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
138 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
130 <td>unknown</td>
139 <td>unknown</td>
131 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
140 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
132 <td class="age">seconds ago</td>
141 <td class="age">seconds ago</td>
133 <td class="indexlinks"></td>
142 <td class="indexlinks"></td>
134 </tr>
143 </tr>
135
144
136 <tr class="parity1">
145 <tr class="parity1">
137 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
146 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
138 <td>unknown</td>
147 <td>unknown</td>
139 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
148 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
140 <td class="age">seconds ago</td>
149 <td class="age">seconds ago</td>
141 <td class="indexlinks"></td>
150 <td class="indexlinks"></td>
142 </tr>
151 </tr>
143
152
144 <tr class="parity0">
153 <tr class="parity0">
145 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
154 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
146 <td>unknown</td>
155 <td>unknown</td>
147 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
156 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
148 <td class="age">seconds ago</td>
157 <td class="age">seconds ago</td>
149 <td class="indexlinks"></td>
158 <td class="indexlinks"></td>
150 </tr>
159 </tr>
151
160
152 <tr class="parity1">
161 <tr class="parity1">
153 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
162 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
154 <td>unknown</td>
163 <td>unknown</td>
155 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
164 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
156 <td class="age">seconds ago</td>
165 <td class="age">seconds ago</td>
157 <td class="indexlinks"></td>
166 <td class="indexlinks"></td>
158 </tr>
167 </tr>
159
168
160 <tr class="parity0">
169 <tr class="parity0">
161 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
170 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
162 <td>unknown</td>
171 <td>unknown</td>
163 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
172 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
164 <td class="age">seconds ago</td>
173 <td class="age">seconds ago</td>
165 <td class="indexlinks"></td>
174 <td class="indexlinks"></td>
166 </tr>
175 </tr>
167
176
177 <tr class="parity1">
178 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
179 <td>unknown</td>
180 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
181 <td class="age">seconds ago</td>
182 <td class="indexlinks"></td>
183 </tr>
184
185 <tr class="parity0">
186 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
187 <td>unknown</td>
188 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
189 <td class="age">seconds ago</td>
190 <td class="indexlinks"></td>
191 </tr>
192
193 <tr class="parity1">
194 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
195 <td>unknown</td>
196 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
197 <td class="age">seconds ago</td>
198 <td class="indexlinks"></td>
199 </tr>
200
201 <tr class="parity0">
202 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
203 <td>unknown</td>
204 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
205 <td class="age">seconds ago</td>
206 <td class="indexlinks"></td>
207 </tr>
208
209 <tr class="parity1">
210 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
211 <td>unknown</td>
212 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
213 <td class="age">seconds ago</td>
214 <td class="indexlinks"></td>
215 </tr>
216
217 <tr class="parity0">
218 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
219 <td>unknown</td>
220 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
221 <td class="age">seconds ago</td>
222 <td class="indexlinks"></td>
223 </tr>
224
225 <tr class="parity1">
226 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
227 <td>unknown</td>
228 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
229 <td class="age">seconds ago</td>
230 <td class="indexlinks"></td>
231 </tr>
232
233 <tr class="parity0">
234 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
235 <td>unknown</td>
236 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
237 <td class="age">seconds ago</td>
238 <td class="indexlinks"></td>
239 </tr>
240
241 <tr class="parity1">
242 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
243 <td>unknown</td>
244 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
245 <td class="age">seconds ago</td>
246 <td class="indexlinks"></td>
247 </tr>
248
168 </table>
249 </table>
169 </div>
250 </div>
170 </div>
251 </div>
171
252
172
253
173 </body>
254 </body>
174 </html>
255 </html>
175
256
176 200 Script output follows
257 200 Script output follows
177
258
178
259
179 /t/a/
260 /t/a/
180
261
181 200 Script output follows
262 200 Script output follows
182
263
183
264
184 /t/a/
265 /t/a/
185
266
186 200 Script output follows
267 200 Script output follows
187
268
188 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
269 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
189 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
270 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
190 <head>
271 <head>
191 <link rel="icon" href="/static/hgicon.png" type="image/png" />
272 <link rel="icon" href="/static/hgicon.png" type="image/png" />
192 <meta name="robots" content="index, nofollow" />
273 <meta name="robots" content="index, nofollow" />
193 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
274 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
194
275
195 <title>Mercurial repositories index</title>
276 <title>Mercurial repositories index</title>
196 </head>
277 </head>
197 <body>
278 <body>
198
279
199 <div class="container">
280 <div class="container">
200 <div class="menu">
281 <div class="menu">
201 <a href="http://mercurial.selenic.com/">
282 <a href="http://mercurial.selenic.com/">
202 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
283 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
203 </div>
284 </div>
204 <div class="main">
285 <div class="main">
205 <h2>Mercurial Repositories</h2>
286 <h2>Mercurial Repositories</h2>
206
287
207 <table class="bigtable">
288 <table class="bigtable">
208 <tr>
289 <tr>
209 <th><a href="?sort=name">Name</a></th>
290 <th><a href="?sort=name">Name</a></th>
210 <th><a href="?sort=description">Description</a></th>
291 <th><a href="?sort=description">Description</a></th>
211 <th><a href="?sort=contact">Contact</a></th>
292 <th><a href="?sort=contact">Contact</a></th>
212 <th><a href="?sort=lastchange">Last modified</a></th>
293 <th><a href="?sort=lastchange">Last modified</a></th>
213 <th>&nbsp;</th>
294 <th>&nbsp;</th>
214 </tr>
295 </tr>
215
296
216 <tr class="parity0">
297 <tr class="parity0">
217 <td><a href="/t/a/?style=paper">a</a></td>
298 <td><a href="/t/a/?style=paper">a</a></td>
218 <td>unknown</td>
299 <td>unknown</td>
219 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
300 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
220 <td class="age">seconds ago</td>
301 <td class="age">seconds ago</td>
221 <td class="indexlinks"></td>
302 <td class="indexlinks"></td>
222 </tr>
303 </tr>
223
304
224 </table>
305 </table>
225 </div>
306 </div>
226 </div>
307 </div>
227
308
228
309
229 </body>
310 </body>
230 </html>
311 </html>
231
312
232 200 Script output follows
313 200 Script output follows
233
314
234 <?xml version="1.0" encoding="ascii"?>
315 <?xml version="1.0" encoding="ascii"?>
235 <feed xmlns="http://127.0.0.1/2005/Atom">
316 <feed xmlns="http://127.0.0.1/2005/Atom">
236 <!-- Changelog -->
317 <!-- Changelog -->
237 <id>http://127.0.0.1/t/a/</id>
318 <id>http://127.0.0.1/t/a/</id>
238 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
319 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
239 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
320 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
240 <title>t/a Changelog</title>
321 <title>t/a Changelog</title>
241 <updated>1970-01-01T00:00:01+00:00</updated>
322 <updated>1970-01-01T00:00:01+00:00</updated>
242
323
243 <entry>
324 <entry>
244 <title>a</title>
325 <title>a</title>
245 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
326 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
246 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
327 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
247 <author>
328 <author>
248 <name>test</name>
329 <name>test</name>
249 <email>&#116;&#101;&#115;&#116;</email>
330 <email>&#116;&#101;&#115;&#116;</email>
250 </author>
331 </author>
251 <updated>1970-01-01T00:00:01+00:00</updated>
332 <updated>1970-01-01T00:00:01+00:00</updated>
252 <published>1970-01-01T00:00:01+00:00</published>
333 <published>1970-01-01T00:00:01+00:00</published>
253 <content type="xhtml">
334 <content type="xhtml">
254 <div xmlns="http://127.0.0.1/1999/xhtml">
335 <div xmlns="http://127.0.0.1/1999/xhtml">
255 <pre xml:space="preserve">a</pre>
336 <pre xml:space="preserve">a</pre>
256 </div>
337 </div>
257 </content>
338 </content>
258 </entry>
339 </entry>
259
340
260 </feed>
341 </feed>
261 200 Script output follows
342 200 Script output follows
262
343
263 <?xml version="1.0" encoding="ascii"?>
344 <?xml version="1.0" encoding="ascii"?>
264 <feed xmlns="http://127.0.0.1/2005/Atom">
345 <feed xmlns="http://127.0.0.1/2005/Atom">
265 <!-- Changelog -->
346 <!-- Changelog -->
266 <id>http://127.0.0.1/t/a/</id>
347 <id>http://127.0.0.1/t/a/</id>
267 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
348 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
268 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
349 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
269 <title>t/a Changelog</title>
350 <title>t/a Changelog</title>
270 <updated>1970-01-01T00:00:01+00:00</updated>
351 <updated>1970-01-01T00:00:01+00:00</updated>
271
352
272 <entry>
353 <entry>
273 <title>a</title>
354 <title>a</title>
274 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
355 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
275 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
356 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
276 <author>
357 <author>
277 <name>test</name>
358 <name>test</name>
278 <email>&#116;&#101;&#115;&#116;</email>
359 <email>&#116;&#101;&#115;&#116;</email>
279 </author>
360 </author>
280 <updated>1970-01-01T00:00:01+00:00</updated>
361 <updated>1970-01-01T00:00:01+00:00</updated>
281 <published>1970-01-01T00:00:01+00:00</published>
362 <published>1970-01-01T00:00:01+00:00</published>
282 <content type="xhtml">
363 <content type="xhtml">
283 <div xmlns="http://127.0.0.1/1999/xhtml">
364 <div xmlns="http://127.0.0.1/1999/xhtml">
284 <pre xml:space="preserve">a</pre>
365 <pre xml:space="preserve">a</pre>
285 </div>
366 </div>
286 </content>
367 </content>
287 </entry>
368 </entry>
288
369
289 </feed>
370 </feed>
290 200 Script output follows
371 200 Script output follows
291
372
292 a
373 a
293 200 Script output follows
374 200 Script output follows
294
375
295
376
296 /coll/a/
377 /coll/a/
297 /coll/a/.hg/patches/
378 /coll/a/.hg/patches/
298 /coll/b/
379 /coll/b/
299 /coll/c/
380 /coll/c/
300
381
301 200 Script output follows
382 200 Script output follows
302
383
303 a
384 a
304 200 Script output follows
385 200 Script output follows
305
386
306
387
307 /rcoll/a/
388 /rcoll/a/
308 /rcoll/a/.hg/patches/
389 /rcoll/a/.hg/patches/
309 /rcoll/b/
390 /rcoll/b/
310 /rcoll/b/d/
391 /rcoll/b/d/
311 /rcoll/c/
392 /rcoll/c/
312
393
313 200 Script output follows
394 200 Script output follows
314
395
315 d
396 d
316 % test descend = False
397 % test descend = False
317 200 Script output follows
398 200 Script output follows
318
399
319
400
320 /c/
401 /c/
321
402
322 200 Script output follows
403 200 Script output follows
323
404
324
405
325 /t/a/
406 /t/a/
326 /t/b/
407 /t/b/
327
408
328 % collections: should succeed
409 % collections: should succeed
329 200 Script output follows
410 200 Script output follows
330
411
331
412
332 /a/
413 /a/
333 /a/.hg/patches/
414 /a/.hg/patches/
334 /b/
415 /b/
335 /c/
416 /c/
336
417
337 200 Script output follows
418 200 Script output follows
338
419
339 a
420 a
340 200 Script output follows
421 200 Script output follows
341
422
342 b
423 b
343 200 Script output follows
424 200 Script output follows
344
425
345 c
426 c
346 % atom-log with basedir /
427 % atom-log with basedir /
347 <link rel="self" href="http://example.com:8080/a/atom-log"/>
428 <link rel="self" href="http://example.com:8080/a/atom-log"/>
348 <link rel="alternate" href="http://example.com:8080/a/"/>
429 <link rel="alternate" href="http://example.com:8080/a/"/>
349 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
430 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
350 % rss-log with basedir /
431 % rss-log with basedir /
351 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
432 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
352 % atom-log with basedir /foo/
433 % atom-log with basedir /foo/
353 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
434 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
354 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
435 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
355 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
436 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
356 % rss-log with basedir /foo/
437 % rss-log with basedir /foo/
357 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
438 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
358 % paths errors 1
439 % paths errors 1
359 % paths errors 2
440 % paths errors 2
360 % paths errors 3
441 % paths errors 3
361 % collections errors
442 % collections errors
362 % collections errors 2
443 % collections errors 2
@@ -1,409 +1,418 b''
1 #!/bin/sh
1 #!/bin/sh
2
2
3 cat <<EOF >> $HGRCPATH
3 cat <<EOF >> $HGRCPATH
4 [extensions]
4 [extensions]
5 keyword =
5 keyword =
6 mq =
6 mq =
7 notify =
7 notify =
8 record =
8 record =
9 transplant =
9 transplant =
10 [ui]
10 [ui]
11 interactive = true
11 interactive = true
12 EOF
12 EOF
13
13
14 # demo before [keyword] files are set up
14 # demo before [keyword] files are set up
15 # would succeed without uisetup otherwise
15 # would succeed without uisetup otherwise
16 echo % hg kwdemo
16 echo % hg kwdemo
17 hg --quiet kwdemo \
17 hg --quiet kwdemo \
18 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
18 | sed -e 's![^ ][^ ]*demo.txt,v!/TMP/demo.txt,v!' \
19 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
19 -e 's/,v [a-z0-9][a-z0-9]* /,v xxxxxxxxxxxx /' \
20 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
20 -e '/[$]Revision/ s/: [a-z0-9][a-z0-9]* /: xxxxxxxxxxxx /' \
21 -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!'
21 -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!'
22
22
23 hg --quiet kwdemo "Branch = {branches}"
23 hg --quiet kwdemo "Branch = {branches}"
24
24
25 cat <<EOF >> $HGRCPATH
25 cat <<EOF >> $HGRCPATH
26 [keyword]
26 [keyword]
27 ** =
27 ** =
28 b = ignore
28 b = ignore
29 [hooks]
29 [hooks]
30 commit=
30 commit=
31 commit.test=cp a hooktest
31 commit.test=cp a hooktest
32 EOF
32 EOF
33
33
34 hg init Test-bndl
34 hg init Test-bndl
35 cd Test-bndl
35 cd Test-bndl
36
36
37 echo % kwshrink should exit silently in empty/invalid repo
37 echo % kwshrink should exit silently in empty/invalid repo
38 hg kwshrink
38 hg kwshrink
39
39
40 # Symlinks cannot be created on Windows. The bundle was made with:
40 # Symlinks cannot be created on Windows. The bundle was made with:
41 #
41 #
42 # hg init t
42 # hg init t
43 # cd t
43 # cd t
44 # echo a > a
44 # echo a > a
45 # ln -s a sym
45 # ln -s a sym
46 # hg add sym
46 # hg add sym
47 # hg ci -m addsym -u mercurial
47 # hg ci -m addsym -u mercurial
48 # hg bundle --base null ../test-keyword.hg
48 # hg bundle --base null ../test-keyword.hg
49 #
49 #
50 hg pull -u "$TESTDIR/test-keyword.hg" \
50 hg pull -u "$TESTDIR/test-keyword.hg" \
51 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
51 | sed 's/pulling from.*test-keyword.hg/pulling from test-keyword.hg/'
52
52
53 echo 'expand $Id$' > a
53 echo 'expand $Id$' > a
54 echo 'do not process $Id:' >> a
54 echo 'do not process $Id:' >> a
55 echo 'xxx $' >> a
55 echo 'xxx $' >> a
56 echo 'ignore $Id$' > b
56 echo 'ignore $Id$' > b
57 echo % cat
57 echo % cat
58 cat a b
58 cat a b
59
59
60 echo % no kwfiles
60 echo % no kwfiles
61 hg kwfiles
61 hg kwfiles
62 echo % untracked candidates
62 echo % untracked candidates
63 hg -v kwfiles --unknown
63 hg -v kwfiles --unknown
64
64
65 echo % addremove
65 echo % addremove
66 hg addremove
66 hg addremove
67 echo % status
67 echo % status
68 hg status
68 hg status
69
69
70 echo % default keyword expansion including commit hook
70 echo % default keyword expansion including commit hook
71 echo % interrupted commit should not change state or run commit hook
71 echo % interrupted commit should not change state or run commit hook
72 hg --debug commit
72 hg --debug commit
73 echo % status
73 echo % status
74 hg status
74 hg status
75
75
76 echo % commit
76 echo % commit
77 hg --debug commit -mabsym -u 'User Name <user@example.com>'
77 hg --debug commit -mabsym -u 'User Name <user@example.com>'
78 echo % status
78 echo % status
79 hg status
79 hg status
80 echo % identify
80 echo % identify
81 hg debugrebuildstate
81 hg debugrebuildstate
82 hg --quiet identify
82 hg --quiet identify
83 echo % cat
83 echo % cat
84 cat a b
84 cat a b
85 echo % hg cat
85 echo % hg cat
86 hg cat sym a b
86 hg cat sym a b
87
87
88 echo
88 echo
89 echo % diff a hooktest
89 echo % diff a hooktest
90 diff a hooktest
90 diff a hooktest
91
91
92 echo % removing commit hook from config
92 echo % removing commit hook from config
93 sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nohook
93 sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nohook
94 mv "$HGRCPATH".nohook "$HGRCPATH"
94 mv "$HGRCPATH".nohook "$HGRCPATH"
95 rm hooktest
95 rm hooktest
96
96
97 echo % bundle
97 echo % bundle
98 hg bundle --base null ../kw.hg
98 hg bundle --base null ../kw.hg
99
99
100 cd ..
100 cd ..
101 hg init Test
101 hg init Test
102 cd Test
102 cd Test
103
103
104 echo % notify on pull to check whether keywords stay as is in email
104 echo % notify on pull to check whether keywords stay as is in email
105 echo % ie. if patch.diff wrapper acts as it should
105 echo % ie. if patch.diff wrapper acts as it should
106
106
107 cat <<EOF >> $HGRCPATH
107 cat <<EOF >> $HGRCPATH
108 [hooks]
108 [hooks]
109 incoming.notify = python:hgext.notify.hook
109 incoming.notify = python:hgext.notify.hook
110 [notify]
110 [notify]
111 sources = pull
111 sources = pull
112 diffstat = False
112 diffstat = False
113 [reposubs]
113 [reposubs]
114 * = Test
114 * = Test
115 EOF
115 EOF
116
116
117 echo % pull from bundle
117 echo % pull from bundle
118 hg pull -u ../kw.hg 2>&1 | sed -e '/^Content-Type:/,/^diffs (/ d'
118 hg pull -u ../kw.hg 2>&1 | sed -e '/^Content-Type:/,/^diffs (/ d'
119
119
120 echo % remove notify config
120 echo % remove notify config
121 sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nonotify
121 sed -e '/\[hooks\]/,$ d' "$HGRCPATH" > $HGRCPATH.nonotify
122 mv "$HGRCPATH".nonotify "$HGRCPATH"
122 mv "$HGRCPATH".nonotify "$HGRCPATH"
123
123
124 echo % touch
124 echo % touch
125 touch a b
125 touch a b
126 echo % status
126 echo % status
127 hg status
127 hg status
128
128
129 rm sym a b
129 rm sym a b
130 echo % update
130 echo % update
131 hg update -C
131 hg update -C
132 echo % cat
132 echo % cat
133 cat a b
133 cat a b
134
134
135 echo % check whether expansion is filewise
135 echo % check whether expansion is filewise
136 echo '$Id$' > c
136 echo '$Id$' > c
137 echo 'tests for different changenodes' >> c
137 echo 'tests for different changenodes' >> c
138 echo % commit c
138 echo % commit c
139 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
139 hg commit -A -mcndiff -d '1 0' -u 'User Name <user@example.com>'
140 echo % force expansion
140 echo % force expansion
141 hg -v kwexpand
141 hg -v kwexpand
142 echo % compare changenodes in a c
142 echo % compare changenodes in a c
143 cat a c
143 cat a c
144
144
145 echo % record chunk
145 echo % record chunk
146 python -c \
146 python -c \
147 'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
147 'l=open("a").readlines();l.insert(1,"foo\n");l.append("bar\n");open("a","w").writelines(l);'
148 hg record -d '1 10' -m rectest<<EOF
148 hg record -d '1 10' -m rectest<<EOF
149 y
149 y
150 y
150 y
151 n
151 n
152 EOF
152 EOF
153 echo
153 echo
154 hg identify
154 hg identify
155 hg status
155 hg status
156 echo % cat modified file
156 echo % cat modified file
157 cat a
157 cat a
158 hg diff | grep -v 'b/a'
158 hg diff | grep -v 'b/a'
159 hg rollback
159 hg rollback
160
160
161 echo % record file
161 echo % record file
162 echo foo > msg
162 echo foo > msg
163 # do not use "hg record -m" here!
163 # do not use "hg record -m" here!
164 hg record -l msg -d '1 11'<<EOF
164 hg record -l msg -d '1 11'<<EOF
165 y
165 y
166 y
166 y
167 y
167 y
168 EOF
168 EOF
169 echo % a should be clean
169 echo % a should be clean
170 hg status -A a
170 hg status -A a
171 rm msg
171 rm msg
172 hg rollback
172 hg rollback
173 hg update -C
173 hg update -C
174
174
175 echo % init --mq
175 echo % init --mq
176 hg init --mq
176 hg init --mq
177 echo % qimport
177 echo % qimport
178 hg qimport -r tip -n mqtest.diff
178 hg qimport -r tip -n mqtest.diff
179 echo % commit --mq
179 echo % commit --mq
180 hg commit --mq -m mqtest
180 hg commit --mq -m mqtest
181 echo % keywords should not be expanded in patch
181 echo % keywords should not be expanded in patch
182 cat .hg/patches/mqtest.diff
182 cat .hg/patches/mqtest.diff
183 echo % qpop
183 echo % qpop
184 hg qpop
184 hg qpop
185 echo % qgoto - should imply qpush
185 echo % qgoto - should imply qpush
186 hg qgoto mqtest.diff
186 hg qgoto mqtest.diff
187 echo % cat
187 echo % cat
188 cat c
188 cat c
189 echo % hg cat
189 echo % hg cat
190 hg cat c
190 hg cat c
191 echo % keyword should not be expanded in filelog
191 echo % keyword should not be expanded in filelog
192 hg --config 'extensions.keyword=!' cat c
192 hg --config 'extensions.keyword=!' cat c
193 echo % qpop and move on
193 echo % qpop and move on
194 hg qpop
194 hg qpop
195
195
196 echo % copy
196 echo % copy
197 hg cp a c
197 hg cp a c
198
198
199 echo % kwfiles added
199 echo % kwfiles added
200 hg kwfiles
200 hg kwfiles
201
201
202 echo % commit
202 echo % commit
203 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
203 hg --debug commit -ma2c -d '1 0' -u 'User Name <user@example.com>'
204 echo % cat a c
204 echo % cat a c
205 cat a c
205 cat a c
206 echo % touch copied c
206 echo % touch copied c
207 touch c
207 touch c
208 echo % status
208 echo % status
209 hg status
209 hg status
210
210
211 echo % kwfiles
211 echo % kwfiles
212 hg kwfiles
212 hg kwfiles
213 echo % ignored files
213 echo % ignored files
214 hg -v kwfiles --ignore
214 hg -v kwfiles --ignore
215 echo % all files
215 echo % all files
216 hg kwfiles --all
216 hg kwfiles --all
217
217
218 echo % diff --rev
218 echo % diff --rev
219 hg diff --rev 1 | grep -v 'b/c'
219 hg diff --rev 1 | grep -v 'b/c'
220
220
221 echo % rollback
221 echo % rollback
222 hg rollback
222 hg rollback
223 echo % status
223 echo % status
224 hg status
224 hg status
225 echo % update -C
225 echo % update -C
226 hg update --clean
226 hg update --clean
227
227
228 echo % custom keyword expansion
228 echo % custom keyword expansion
229 echo % try with kwdemo
229 echo % try with kwdemo
230 hg --quiet kwdemo "Xinfo = {author}: {desc}"
230 hg --quiet kwdemo "Xinfo = {author}: {desc}"
231
231
232 cat <<EOF >>$HGRCPATH
232 cat <<EOF >>$HGRCPATH
233 [keywordmaps]
233 [keywordmaps]
234 Id = {file} {node|short} {date|rfc822date} {author|user}
234 Id = {file} {node|short} {date|rfc822date} {author|user}
235 Xinfo = {author}: {desc}
235 Xinfo = {author}: {desc}
236 EOF
236 EOF
237
237
238 echo % cat
238 echo % cat
239 cat a b
239 cat a b
240 echo % hg cat
240 echo % hg cat
241 hg cat sym a b
241 hg cat sym a b
242
242
243 echo
243 echo
244 echo '$Xinfo$' >> a
244 echo '$Xinfo$' >> a
245 cat <<EOF >> log
245 cat <<EOF >> log
246 firstline
246 firstline
247 secondline
247 secondline
248 EOF
248 EOF
249
249
250 echo % interrupted commit should not change state
250 echo % interrupted commit should not change state
251 hg commit
251 hg commit
252 echo % status
252 echo % status
253 hg status
253 hg status
254
254
255 echo % commit
255 echo % commit
256 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
256 hg --debug commit -l log -d '2 0' -u 'User Name <user@example.com>'
257 rm log
257 rm log
258 echo % status
258 echo % status
259 hg status
259 hg status
260 echo % verify
260 echo % verify
261 hg verify
261 hg verify
262
262
263 echo % cat
263 echo % cat
264 cat a b
264 cat a b
265 echo % hg cat
265 echo % hg cat
266 hg cat sym a b
266 hg cat sym a b
267 echo
267 echo
268 echo % annotate
268 echo % annotate
269 hg annotate a
269 hg annotate a
270
270
271 echo % remove
271 echo % remove
272 hg debugrebuildstate
272 hg debugrebuildstate
273 hg remove a
273 hg remove a
274 hg --debug commit -m rma
274 hg --debug commit -m rma
275 echo % status
275 echo % status
276 hg status
276 hg status
277 echo % rollback
277 echo % rollback
278 hg rollback
278 hg rollback
279 echo % status
279 echo % status
280 hg status
280 hg status
281 echo % revert a
281 echo % revert a
282 hg revert --no-backup --rev tip a
282 hg revert --no-backup --rev tip a
283 echo % cat a
283 echo % cat a
284 cat a
284 cat a
285
285
286 echo % clone
287 cd ..
288
289 echo % expansion in dest
290 hg --quiet clone Test globalconf
291 cat globalconf/a
292 echo % no expansion in dest
293 hg --quiet --config 'keyword.**=ignore' clone Test localconf
294 cat localconf/a
295
286 echo % clone to test incoming
296 echo % clone to test incoming
287 cd ..
288 hg clone -r1 Test Test-a
297 hg clone -r1 Test Test-a
289 cd Test-a
298 cd Test-a
290 cat <<EOF >> .hg/hgrc
299 cat <<EOF >> .hg/hgrc
291 [paths]
300 [paths]
292 default = ../Test
301 default = ../Test
293 EOF
302 EOF
294 echo % incoming
303 echo % incoming
295 # remove path to temp dir
304 # remove path to temp dir
296 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
305 hg incoming | sed -e 's/^\(comparing with \).*\(test-keyword.*\)/\1\2/'
297
306
298 sed -e 's/Id.*/& rejecttest/' a > a.new
307 sed -e 's/Id.*/& rejecttest/' a > a.new
299 mv a.new a
308 mv a.new a
300 echo % commit rejecttest
309 echo % commit rejecttest
301 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
310 hg --debug commit -m'rejects?' -d '3 0' -u 'User Name <user@example.com>'
302 echo % export
311 echo % export
303 hg export -o ../rejecttest.diff tip
312 hg export -o ../rejecttest.diff tip
304
313
305 cd ../Test
314 cd ../Test
306 echo % import
315 echo % import
307 hg import ../rejecttest.diff
316 hg import ../rejecttest.diff
308 echo % cat
317 echo % cat
309 cat a b
318 cat a b
310 echo
319 echo
311 echo % rollback
320 echo % rollback
312 hg rollback
321 hg rollback
313 echo % clean update
322 echo % clean update
314 hg update --clean
323 hg update --clean
315
324
316 echo % kwexpand/kwshrink on selected files
325 echo % kwexpand/kwshrink on selected files
317 mkdir x
326 mkdir x
318 echo % copy a x/a
327 echo % copy a x/a
319 hg copy a x/a
328 hg copy a x/a
320 echo % kwexpand a
329 echo % kwexpand a
321 hg --verbose kwexpand a
330 hg --verbose kwexpand a
322 echo % kwexpand x/a should abort
331 echo % kwexpand x/a should abort
323 hg --verbose kwexpand x/a
332 hg --verbose kwexpand x/a
324 cd x
333 cd x
325 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
334 hg --debug commit -m xa -d '3 0' -u 'User Name <user@example.com>'
326 echo % cat a
335 echo % cat a
327 cat a
336 cat a
328 echo % kwshrink a inside directory x
337 echo % kwshrink a inside directory x
329 hg --verbose kwshrink a
338 hg --verbose kwshrink a
330 echo % cat a
339 echo % cat a
331 cat a
340 cat a
332 cd ..
341 cd ..
333
342
334 echo % kwexpand nonexistent
343 echo % kwexpand nonexistent
335 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
344 hg kwexpand nonexistent 2>&1 | sed 's/nonexistent:.*/nonexistent:/'
336
345
337 echo % hg serve
346 echo % hg serve
338 hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
347 hg serve -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
339 cat hg.pid >> $DAEMON_PIDS
348 cat hg.pid >> $DAEMON_PIDS
340 echo % expansion
349 echo % expansion
341 echo % hgweb file
350 echo % hgweb file
342 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/a/?style=raw')
351 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/a/?style=raw')
343 echo % no expansion
352 echo % no expansion
344 echo % hgweb annotate
353 echo % hgweb annotate
345 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/annotate/tip/a/?style=raw')
354 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/annotate/tip/a/?style=raw')
346 echo % hgweb changeset
355 echo % hgweb changeset
347 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/tip/?style=raw')
356 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/tip/?style=raw')
348 echo % hgweb filediff
357 echo % hgweb filediff
349 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/bb948857c743/a?style=raw')
358 ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/bb948857c743/a?style=raw')
350 echo % errors encountered
359 echo % errors encountered
351 cat errors.log
360 cat errors.log
352
361
353 echo % merge/resolve
362 echo % merge/resolve
354 echo '$Id$' > m
363 echo '$Id$' > m
355 hg add m
364 hg add m
356 hg commit -m 4kw
365 hg commit -m 4kw
357 echo foo >> m
366 echo foo >> m
358 hg commit -m 5foo
367 hg commit -m 5foo
359 echo % simplemerge
368 echo % simplemerge
360 hg update 4
369 hg update 4
361 echo foo >> m
370 echo foo >> m
362 hg commit -m 6foo
371 hg commit -m 6foo
363 hg merge
372 hg merge
364 hg commit -m simplemerge
373 hg commit -m simplemerge
365 cat m
374 cat m
366 echo % conflict
375 echo % conflict
367 hg update 4
376 hg update 4
368 echo bar >> m
377 echo bar >> m
369 hg commit -m 8bar
378 hg commit -m 8bar
370 hg merge
379 hg merge
371 echo % keyword stays outside conflict zone
380 echo % keyword stays outside conflict zone
372 cat m
381 cat m
373 echo % resolve to local
382 echo % resolve to local
374 HGMERGE=internal:local hg resolve -a
383 HGMERGE=internal:local hg resolve -a
375 hg commit -m localresolve
384 hg commit -m localresolve
376 cat m
385 cat m
377
386
378 echo % test restricted mode with transplant -b
387 echo % test restricted mode with transplant -b
379 hg update 6
388 hg update 6
380 hg branch foo
389 hg branch foo
381 mv a a.bak
390 mv a a.bak
382 echo foobranch > a
391 echo foobranch > a
383 cat a.bak >> a
392 cat a.bak >> a
384 rm a.bak
393 rm a.bak
385 hg commit -m 9foobranch
394 hg commit -m 9foobranch
386 hg update default
395 hg update default
387 hg -y transplant -b foo tip
396 hg -y transplant -b foo tip
388 echo % no expansion in changeset
397 echo % no expansion in changeset
389 hg tip -p
398 hg tip -p
390 echo % expansion in file
399 echo % expansion in file
391 head -n 2 a
400 head -n 2 a
392 hg -q rollback
401 hg -q rollback
393 hg -q update -C
402 hg -q update -C
394
403
395 echo % switch off expansion
404 echo % switch off expansion
396 echo % kwshrink with unknown file u
405 echo % kwshrink with unknown file u
397 cp a u
406 cp a u
398 hg --verbose kwshrink
407 hg --verbose kwshrink
399 echo % cat
408 echo % cat
400 cat a b
409 cat a b
401 echo % hg cat
410 echo % hg cat
402 hg cat sym a b
411 hg cat sym a b
403 echo
412 echo
404 rm "$HGRCPATH"
413 rm "$HGRCPATH"
405 echo % cat
414 echo % cat
406 cat a b
415 cat a b
407 echo % hg cat
416 echo % hg cat
408 hg cat sym a b
417 hg cat sym a b
409 echo
418 echo
@@ -1,536 +1,547 b''
1 % hg kwdemo
1 % hg kwdemo
2 [extensions]
2 [extensions]
3 keyword =
3 keyword =
4 [keyword]
4 [keyword]
5 demo.txt =
5 demo.txt =
6 [keywordmaps]
6 [keywordmaps]
7 Author = {author|user}
7 Author = {author|user}
8 Date = {date|utcdate}
8 Date = {date|utcdate}
9 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
9 Header = {root}/{file},v {node|short} {date|utcdate} {author|user}
10 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
10 Id = {file|basename},v {node|short} {date|utcdate} {author|user}
11 RCSFile = {file|basename},v
11 RCSFile = {file|basename},v
12 RCSfile = {file|basename},v
12 RCSfile = {file|basename},v
13 Revision = {node|short}
13 Revision = {node|short}
14 Source = {root}/{file},v
14 Source = {root}/{file},v
15 $Author: test $
15 $Author: test $
16 $Date: 2000/00/00 00:00:00 $
16 $Date: 2000/00/00 00:00:00 $
17 $Header: /TMP/demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
17 $Header: /TMP/demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
18 $Id: demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
18 $Id: demo.txt,v xxxxxxxxxxxx 2000/00/00 00:00:00 test $
19 $RCSFile: demo.txt,v $
19 $RCSFile: demo.txt,v $
20 $RCSfile: demo.txt,v $
20 $RCSfile: demo.txt,v $
21 $Revision: xxxxxxxxxxxx $
21 $Revision: xxxxxxxxxxxx $
22 $Source: /TMP/demo.txt,v $
22 $Source: /TMP/demo.txt,v $
23 [extensions]
23 [extensions]
24 keyword =
24 keyword =
25 [keyword]
25 [keyword]
26 demo.txt =
26 demo.txt =
27 [keywordmaps]
27 [keywordmaps]
28 Branch = {branches}
28 Branch = {branches}
29 $Branch: demobranch $
29 $Branch: demobranch $
30 % kwshrink should exit silently in empty/invalid repo
30 % kwshrink should exit silently in empty/invalid repo
31 pulling from test-keyword.hg
31 pulling from test-keyword.hg
32 requesting all changes
32 requesting all changes
33 adding changesets
33 adding changesets
34 adding manifests
34 adding manifests
35 adding file changes
35 adding file changes
36 added 1 changesets with 1 changes to 1 files
36 added 1 changesets with 1 changes to 1 files
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 % cat
38 % cat
39 expand $Id$
39 expand $Id$
40 do not process $Id:
40 do not process $Id:
41 xxx $
41 xxx $
42 ignore $Id$
42 ignore $Id$
43 % no kwfiles
43 % no kwfiles
44 % untracked candidates
44 % untracked candidates
45 k a
45 k a
46 % addremove
46 % addremove
47 adding a
47 adding a
48 adding b
48 adding b
49 % status
49 % status
50 A a
50 A a
51 A b
51 A b
52 % default keyword expansion including commit hook
52 % default keyword expansion including commit hook
53 % interrupted commit should not change state or run commit hook
53 % interrupted commit should not change state or run commit hook
54 abort: empty commit message
54 abort: empty commit message
55 % status
55 % status
56 A a
56 A a
57 A b
57 A b
58 % commit
58 % commit
59 a
59 a
60 b
60 b
61 overwriting a expanding keywords
61 overwriting a expanding keywords
62 running hook commit.test: cp a hooktest
62 running hook commit.test: cp a hooktest
63 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
63 committed changeset 1:ef63ca68695bc9495032c6fda1350c71e6d256e9
64 % status
64 % status
65 ? hooktest
65 ? hooktest
66 % identify
66 % identify
67 ef63ca68695b
67 ef63ca68695b
68 % cat
68 % cat
69 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
69 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
70 do not process $Id:
70 do not process $Id:
71 xxx $
71 xxx $
72 ignore $Id$
72 ignore $Id$
73 % hg cat
73 % hg cat
74 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
74 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
75 do not process $Id:
75 do not process $Id:
76 xxx $
76 xxx $
77 ignore $Id$
77 ignore $Id$
78 a
78 a
79 % diff a hooktest
79 % diff a hooktest
80 % removing commit hook from config
80 % removing commit hook from config
81 % bundle
81 % bundle
82 2 changesets found
82 2 changesets found
83 % notify on pull to check whether keywords stay as is in email
83 % notify on pull to check whether keywords stay as is in email
84 % ie. if patch.diff wrapper acts as it should
84 % ie. if patch.diff wrapper acts as it should
85 % pull from bundle
85 % pull from bundle
86 pulling from ../kw.hg
86 pulling from ../kw.hg
87 requesting all changes
87 requesting all changes
88 adding changesets
88 adding changesets
89 adding manifests
89 adding manifests
90 adding file changes
90 adding file changes
91 added 2 changesets with 3 changes to 3 files
91 added 2 changesets with 3 changes to 3 files
92
92
93 diff -r 000000000000 -r a2392c293916 sym
93 diff -r 000000000000 -r a2392c293916 sym
94 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
94 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
95 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
95 +++ b/sym Sat Feb 09 20:25:47 2008 +0100
96 @@ -0,0 +1,1 @@
96 @@ -0,0 +1,1 @@
97 +a
97 +a
98 \ No newline at end of file
98 \ No newline at end of file
99
99
100 diff -r a2392c293916 -r ef63ca68695b a
100 diff -r a2392c293916 -r ef63ca68695b a
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
101 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
102 +++ b/a Thu Jan 01 00:00:00 1970 +0000
102 +++ b/a Thu Jan 01 00:00:00 1970 +0000
103 @@ -0,0 +1,3 @@
103 @@ -0,0 +1,3 @@
104 +expand $Id$
104 +expand $Id$
105 +do not process $Id:
105 +do not process $Id:
106 +xxx $
106 +xxx $
107 diff -r a2392c293916 -r ef63ca68695b b
107 diff -r a2392c293916 -r ef63ca68695b b
108 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
108 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
109 +++ b/b Thu Jan 01 00:00:00 1970 +0000
109 +++ b/b Thu Jan 01 00:00:00 1970 +0000
110 @@ -0,0 +1,1 @@
110 @@ -0,0 +1,1 @@
111 +ignore $Id$
111 +ignore $Id$
112 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
112 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
113 % remove notify config
113 % remove notify config
114 % touch
114 % touch
115 % status
115 % status
116 % update
116 % update
117 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 % cat
118 % cat
119 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
119 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
120 do not process $Id:
120 do not process $Id:
121 xxx $
121 xxx $
122 ignore $Id$
122 ignore $Id$
123 % check whether expansion is filewise
123 % check whether expansion is filewise
124 % commit c
124 % commit c
125 adding c
125 adding c
126 % force expansion
126 % force expansion
127 overwriting a expanding keywords
127 overwriting a expanding keywords
128 overwriting c expanding keywords
128 overwriting c expanding keywords
129 % compare changenodes in a c
129 % compare changenodes in a c
130 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
130 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
131 do not process $Id:
131 do not process $Id:
132 xxx $
132 xxx $
133 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
133 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
134 tests for different changenodes
134 tests for different changenodes
135 % record chunk
135 % record chunk
136 diff --git a/a b/a
136 diff --git a/a b/a
137 2 hunks, 2 lines changed
137 2 hunks, 2 lines changed
138 examine changes to 'a'? [Ynsfdaq?]
138 examine changes to 'a'? [Ynsfdaq?]
139 @@ -1,3 +1,4 @@
139 @@ -1,3 +1,4 @@
140 expand $Id$
140 expand $Id$
141 +foo
141 +foo
142 do not process $Id:
142 do not process $Id:
143 xxx $
143 xxx $
144 record change 1/2 to 'a'? [Ynsfdaq?]
144 record change 1/2 to 'a'? [Ynsfdaq?]
145 @@ -2,2 +3,3 @@
145 @@ -2,2 +3,3 @@
146 do not process $Id:
146 do not process $Id:
147 xxx $
147 xxx $
148 +bar
148 +bar
149 record change 2/2 to 'a'? [Ynsfdaq?]
149 record change 2/2 to 'a'? [Ynsfdaq?]
150
150
151 d17e03c92c97+ tip
151 d17e03c92c97+ tip
152 M a
152 M a
153 % cat modified file
153 % cat modified file
154 expand $Id: a,v d17e03c92c97 1970/01/01 00:00:01 test $
154 expand $Id: a,v d17e03c92c97 1970/01/01 00:00:01 test $
155 foo
155 foo
156 do not process $Id:
156 do not process $Id:
157 xxx $
157 xxx $
158 bar
158 bar
159 diff -r d17e03c92c97 a
159 diff -r d17e03c92c97 a
160 --- a/a Wed Dec 31 23:59:51 1969 -0000
160 --- a/a Wed Dec 31 23:59:51 1969 -0000
161 @@ -2,3 +2,4 @@
161 @@ -2,3 +2,4 @@
162 foo
162 foo
163 do not process $Id:
163 do not process $Id:
164 xxx $
164 xxx $
165 +bar
165 +bar
166 rolling back to revision 2 (undo commit)
166 rolling back to revision 2 (undo commit)
167 % record file
167 % record file
168 diff --git a/a b/a
168 diff --git a/a b/a
169 2 hunks, 2 lines changed
169 2 hunks, 2 lines changed
170 examine changes to 'a'? [Ynsfdaq?]
170 examine changes to 'a'? [Ynsfdaq?]
171 @@ -1,3 +1,4 @@
171 @@ -1,3 +1,4 @@
172 expand $Id$
172 expand $Id$
173 +foo
173 +foo
174 do not process $Id:
174 do not process $Id:
175 xxx $
175 xxx $
176 record change 1/2 to 'a'? [Ynsfdaq?]
176 record change 1/2 to 'a'? [Ynsfdaq?]
177 @@ -2,2 +3,3 @@
177 @@ -2,2 +3,3 @@
178 do not process $Id:
178 do not process $Id:
179 xxx $
179 xxx $
180 +bar
180 +bar
181 record change 2/2 to 'a'? [Ynsfdaq?]
181 record change 2/2 to 'a'? [Ynsfdaq?]
182 % a should be clean
182 % a should be clean
183 C a
183 C a
184 rolling back to revision 2 (undo commit)
184 rolling back to revision 2 (undo commit)
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
185 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 % init --mq
186 % init --mq
187 % qimport
187 % qimport
188 % commit --mq
188 % commit --mq
189 % keywords should not be expanded in patch
189 % keywords should not be expanded in patch
190 # HG changeset patch
190 # HG changeset patch
191 # User User Name <user@example.com>
191 # User User Name <user@example.com>
192 # Date 1 0
192 # Date 1 0
193 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
193 # Node ID 40a904bbbe4cd4ab0a1f28411e35db26341a40ad
194 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
194 # Parent ef63ca68695bc9495032c6fda1350c71e6d256e9
195 cndiff
195 cndiff
196
196
197 diff -r ef63ca68695b -r 40a904bbbe4c c
197 diff -r ef63ca68695b -r 40a904bbbe4c c
198 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
198 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
199 +++ b/c Thu Jan 01 00:00:01 1970 +0000
199 +++ b/c Thu Jan 01 00:00:01 1970 +0000
200 @@ -0,0 +1,2 @@
200 @@ -0,0 +1,2 @@
201 +$Id$
201 +$Id$
202 +tests for different changenodes
202 +tests for different changenodes
203 % qpop
203 % qpop
204 popping mqtest.diff
204 popping mqtest.diff
205 patch queue now empty
205 patch queue now empty
206 % qgoto - should imply qpush
206 % qgoto - should imply qpush
207 applying mqtest.diff
207 applying mqtest.diff
208 now at: mqtest.diff
208 now at: mqtest.diff
209 % cat
209 % cat
210 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
210 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
211 tests for different changenodes
211 tests for different changenodes
212 % hg cat
212 % hg cat
213 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
213 $Id: c,v 40a904bbbe4c 1970/01/01 00:00:01 user $
214 tests for different changenodes
214 tests for different changenodes
215 % keyword should not be expanded in filelog
215 % keyword should not be expanded in filelog
216 $Id$
216 $Id$
217 tests for different changenodes
217 tests for different changenodes
218 % qpop and move on
218 % qpop and move on
219 popping mqtest.diff
219 popping mqtest.diff
220 patch queue now empty
220 patch queue now empty
221 % copy
221 % copy
222 % kwfiles added
222 % kwfiles added
223 a
223 a
224 c
224 c
225 % commit
225 % commit
226 c
226 c
227 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
227 c: copy a:0045e12f6c5791aac80ca6cbfd97709a88307292
228 overwriting c expanding keywords
228 overwriting c expanding keywords
229 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
229 committed changeset 2:25736cf2f5cbe41f6be4e6784ef6ecf9f3bbcc7d
230 % cat a c
230 % cat a c
231 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
231 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
232 do not process $Id:
232 do not process $Id:
233 xxx $
233 xxx $
234 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
234 expand $Id: c,v 25736cf2f5cb 1970/01/01 00:00:01 user $
235 do not process $Id:
235 do not process $Id:
236 xxx $
236 xxx $
237 % touch copied c
237 % touch copied c
238 % status
238 % status
239 % kwfiles
239 % kwfiles
240 a
240 a
241 c
241 c
242 % ignored files
242 % ignored files
243 I b
243 I b
244 I sym
244 I sym
245 % all files
245 % all files
246 K a
246 K a
247 K c
247 K c
248 I b
248 I b
249 I sym
249 I sym
250 % diff --rev
250 % diff --rev
251 diff -r ef63ca68695b c
251 diff -r ef63ca68695b c
252 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
252 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
253 @@ -0,0 +1,3 @@
253 @@ -0,0 +1,3 @@
254 +expand $Id$
254 +expand $Id$
255 +do not process $Id:
255 +do not process $Id:
256 +xxx $
256 +xxx $
257 % rollback
257 % rollback
258 rolling back to revision 1 (undo commit)
258 rolling back to revision 1 (undo commit)
259 % status
259 % status
260 A c
260 A c
261 % update -C
261 % update -C
262 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
262 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
263 % custom keyword expansion
263 % custom keyword expansion
264 % try with kwdemo
264 % try with kwdemo
265 [extensions]
265 [extensions]
266 keyword =
266 keyword =
267 [keyword]
267 [keyword]
268 ** =
268 ** =
269 b = ignore
269 b = ignore
270 demo.txt =
270 demo.txt =
271 [keywordmaps]
271 [keywordmaps]
272 Xinfo = {author}: {desc}
272 Xinfo = {author}: {desc}
273 $Xinfo: test: hg keyword configuration and expansion example $
273 $Xinfo: test: hg keyword configuration and expansion example $
274 % cat
274 % cat
275 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
275 expand $Id: a,v ef63ca68695b 1970/01/01 00:00:00 user $
276 do not process $Id:
276 do not process $Id:
277 xxx $
277 xxx $
278 ignore $Id$
278 ignore $Id$
279 % hg cat
279 % hg cat
280 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
280 expand $Id: a ef63ca68695b Thu, 01 Jan 1970 00:00:00 +0000 user $
281 do not process $Id:
281 do not process $Id:
282 xxx $
282 xxx $
283 ignore $Id$
283 ignore $Id$
284 a
284 a
285 % interrupted commit should not change state
285 % interrupted commit should not change state
286 abort: empty commit message
286 abort: empty commit message
287 % status
287 % status
288 M a
288 M a
289 ? c
289 ? c
290 ? log
290 ? log
291 % commit
291 % commit
292 a
292 a
293 overwriting a expanding keywords
293 overwriting a expanding keywords
294 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
294 committed changeset 2:bb948857c743469b22bbf51f7ec8112279ca5d83
295 % status
295 % status
296 ? c
296 ? c
297 % verify
297 % verify
298 checking changesets
298 checking changesets
299 checking manifests
299 checking manifests
300 crosschecking files in changesets and manifests
300 crosschecking files in changesets and manifests
301 checking files
301 checking files
302 3 files, 3 changesets, 4 total revisions
302 3 files, 3 changesets, 4 total revisions
303 % cat
303 % cat
304 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
304 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
305 do not process $Id:
305 do not process $Id:
306 xxx $
306 xxx $
307 $Xinfo: User Name <user@example.com>: firstline $
307 $Xinfo: User Name <user@example.com>: firstline $
308 ignore $Id$
308 ignore $Id$
309 % hg cat
309 % hg cat
310 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
310 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
311 do not process $Id:
311 do not process $Id:
312 xxx $
312 xxx $
313 $Xinfo: User Name <user@example.com>: firstline $
313 $Xinfo: User Name <user@example.com>: firstline $
314 ignore $Id$
314 ignore $Id$
315 a
315 a
316 % annotate
316 % annotate
317 1: expand $Id$
317 1: expand $Id$
318 1: do not process $Id:
318 1: do not process $Id:
319 1: xxx $
319 1: xxx $
320 2: $Xinfo$
320 2: $Xinfo$
321 % remove
321 % remove
322 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
322 committed changeset 3:d14c712653769de926994cf7fbb06c8fbd68f012
323 % status
323 % status
324 ? c
324 ? c
325 % rollback
325 % rollback
326 rolling back to revision 2 (undo commit)
326 rolling back to revision 2 (undo commit)
327 % status
327 % status
328 R a
328 R a
329 ? c
329 ? c
330 % revert a
330 % revert a
331 % cat a
331 % cat a
332 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
332 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
333 do not process $Id:
333 do not process $Id:
334 xxx $
334 xxx $
335 $Xinfo: User Name <user@example.com>: firstline $
335 $Xinfo: User Name <user@example.com>: firstline $
336 % clone
337 % expansion in dest
338 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
339 do not process $Id:
340 xxx $
341 $Xinfo: User Name <user@example.com>: firstline $
342 % no expansion in dest
343 expand $Id$
344 do not process $Id:
345 xxx $
346 $Xinfo$
336 % clone to test incoming
347 % clone to test incoming
337 requesting all changes
348 requesting all changes
338 adding changesets
349 adding changesets
339 adding manifests
350 adding manifests
340 adding file changes
351 adding file changes
341 added 2 changesets with 3 changes to 3 files
352 added 2 changesets with 3 changes to 3 files
342 updating to branch default
353 updating to branch default
343 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
354 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
344 % incoming
355 % incoming
345 comparing with test-keyword/Test
356 comparing with test-keyword/Test
346 searching for changes
357 searching for changes
347 changeset: 2:bb948857c743
358 changeset: 2:bb948857c743
348 tag: tip
359 tag: tip
349 user: User Name <user@example.com>
360 user: User Name <user@example.com>
350 date: Thu Jan 01 00:00:02 1970 +0000
361 date: Thu Jan 01 00:00:02 1970 +0000
351 summary: firstline
362 summary: firstline
352
363
353 % commit rejecttest
364 % commit rejecttest
354 a
365 a
355 overwriting a expanding keywords
366 overwriting a expanding keywords
356 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
367 committed changeset 2:85e279d709ffc28c9fdd1b868570985fc3d87082
357 % export
368 % export
358 % import
369 % import
359 applying ../rejecttest.diff
370 applying ../rejecttest.diff
360 % cat
371 % cat
361 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
372 expand $Id: a 4e0994474d25 Thu, 01 Jan 1970 00:00:03 +0000 user $ rejecttest
362 do not process $Id: rejecttest
373 do not process $Id: rejecttest
363 xxx $
374 xxx $
364 $Xinfo: User Name <user@example.com>: rejects? $
375 $Xinfo: User Name <user@example.com>: rejects? $
365 ignore $Id$
376 ignore $Id$
366
377
367 % rollback
378 % rollback
368 rolling back to revision 2 (undo commit)
379 rolling back to revision 2 (undo commit)
369 % clean update
380 % clean update
370 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
371 % kwexpand/kwshrink on selected files
382 % kwexpand/kwshrink on selected files
372 % copy a x/a
383 % copy a x/a
373 % kwexpand a
384 % kwexpand a
374 overwriting a expanding keywords
385 overwriting a expanding keywords
375 % kwexpand x/a should abort
386 % kwexpand x/a should abort
376 abort: outstanding uncommitted changes
387 abort: outstanding uncommitted changes
377 x/a
388 x/a
378 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
389 x/a: copy a:779c764182ce5d43e2b1eb66ce06d7b47bfe342e
379 overwriting x/a expanding keywords
390 overwriting x/a expanding keywords
380 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
391 committed changeset 3:b4560182a3f9a358179fd2d835c15e9da379c1e4
381 % cat a
392 % cat a
382 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
393 expand $Id: x/a b4560182a3f9 Thu, 01 Jan 1970 00:00:03 +0000 user $
383 do not process $Id:
394 do not process $Id:
384 xxx $
395 xxx $
385 $Xinfo: User Name <user@example.com>: xa $
396 $Xinfo: User Name <user@example.com>: xa $
386 % kwshrink a inside directory x
397 % kwshrink a inside directory x
387 overwriting x/a shrinking keywords
398 overwriting x/a shrinking keywords
388 % cat a
399 % cat a
389 expand $Id$
400 expand $Id$
390 do not process $Id:
401 do not process $Id:
391 xxx $
402 xxx $
392 $Xinfo$
403 $Xinfo$
393 % kwexpand nonexistent
404 % kwexpand nonexistent
394 nonexistent:
405 nonexistent:
395 % hg serve
406 % hg serve
396 % expansion
407 % expansion
397 % hgweb file
408 % hgweb file
398 200 Script output follows
409 200 Script output follows
399
410
400 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
411 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
401 do not process $Id:
412 do not process $Id:
402 xxx $
413 xxx $
403 $Xinfo: User Name <user@example.com>: firstline $
414 $Xinfo: User Name <user@example.com>: firstline $
404 % no expansion
415 % no expansion
405 % hgweb annotate
416 % hgweb annotate
406 200 Script output follows
417 200 Script output follows
407
418
408
419
409 user@1: expand $Id$
420 user@1: expand $Id$
410 user@1: do not process $Id:
421 user@1: do not process $Id:
411 user@1: xxx $
422 user@1: xxx $
412 user@2: $Xinfo$
423 user@2: $Xinfo$
413
424
414
425
415
426
416
427
417 % hgweb changeset
428 % hgweb changeset
418 200 Script output follows
429 200 Script output follows
419
430
420
431
421 # HG changeset patch
432 # HG changeset patch
422 # User User Name <user@example.com>
433 # User User Name <user@example.com>
423 # Date 3 0
434 # Date 3 0
424 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
435 # Node ID b4560182a3f9a358179fd2d835c15e9da379c1e4
425 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
436 # Parent bb948857c743469b22bbf51f7ec8112279ca5d83
426 xa
437 xa
427
438
428 diff -r bb948857c743 -r b4560182a3f9 x/a
439 diff -r bb948857c743 -r b4560182a3f9 x/a
429 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
440 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
430 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
441 +++ b/x/a Thu Jan 01 00:00:03 1970 +0000
431 @@ -0,0 +1,4 @@
442 @@ -0,0 +1,4 @@
432 +expand $Id$
443 +expand $Id$
433 +do not process $Id:
444 +do not process $Id:
434 +xxx $
445 +xxx $
435 +$Xinfo$
446 +$Xinfo$
436
447
437 % hgweb filediff
448 % hgweb filediff
438 200 Script output follows
449 200 Script output follows
439
450
440
451
441 diff -r ef63ca68695b -r bb948857c743 a
452 diff -r ef63ca68695b -r bb948857c743 a
442 --- a/a Thu Jan 01 00:00:00 1970 +0000
453 --- a/a Thu Jan 01 00:00:00 1970 +0000
443 +++ b/a Thu Jan 01 00:00:02 1970 +0000
454 +++ b/a Thu Jan 01 00:00:02 1970 +0000
444 @@ -1,3 +1,4 @@
455 @@ -1,3 +1,4 @@
445 expand $Id$
456 expand $Id$
446 do not process $Id:
457 do not process $Id:
447 xxx $
458 xxx $
448 +$Xinfo$
459 +$Xinfo$
449
460
450
461
451
462
452
463
453 % errors encountered
464 % errors encountered
454 % merge/resolve
465 % merge/resolve
455 % simplemerge
466 % simplemerge
456 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
467 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
457 created new head
468 created new head
458 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
459 (branch merge, don't forget to commit)
470 (branch merge, don't forget to commit)
460 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
471 $Id: m 27d48ee14f67 Thu, 01 Jan 1970 00:00:00 +0000 test $
461 foo
472 foo
462 % conflict
473 % conflict
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
474 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
464 created new head
475 created new head
465 merging m
476 merging m
466 warning: conflicts during merge.
477 warning: conflicts during merge.
467 merging m failed!
478 merging m failed!
468 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
479 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
469 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
480 use 'hg resolve' to retry unresolved file merges or 'hg update -C' to abandon
470 % keyword stays outside conflict zone
481 % keyword stays outside conflict zone
471 $Id$
482 $Id$
472 <<<<<<< local
483 <<<<<<< local
473 bar
484 bar
474 =======
485 =======
475 foo
486 foo
476 >>>>>>> other
487 >>>>>>> other
477 % resolve to local
488 % resolve to local
478 $Id: m 41efa6d38e9b Thu, 01 Jan 1970 00:00:00 +0000 test $
489 $Id: m 41efa6d38e9b Thu, 01 Jan 1970 00:00:00 +0000 test $
479 bar
490 bar
480 % test restricted mode with transplant -b
491 % test restricted mode with transplant -b
481 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
492 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
482 marked working directory as branch foo
493 marked working directory as branch foo
483 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
494 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
484 applying 4aa30d025d50
495 applying 4aa30d025d50
485 4aa30d025d50 transplanted to 5a4da427c162
496 4aa30d025d50 transplanted to 5a4da427c162
486 % no expansion in changeset
497 % no expansion in changeset
487 changeset: 11:5a4da427c162
498 changeset: 11:5a4da427c162
488 tag: tip
499 tag: tip
489 parent: 9:41efa6d38e9b
500 parent: 9:41efa6d38e9b
490 user: test
501 user: test
491 date: Thu Jan 01 00:00:00 1970 +0000
502 date: Thu Jan 01 00:00:00 1970 +0000
492 summary: 9foobranch
503 summary: 9foobranch
493
504
494 diff -r 41efa6d38e9b -r 5a4da427c162 a
505 diff -r 41efa6d38e9b -r 5a4da427c162 a
495 --- a/a Thu Jan 01 00:00:00 1970 +0000
506 --- a/a Thu Jan 01 00:00:00 1970 +0000
496 +++ b/a Thu Jan 01 00:00:00 1970 +0000
507 +++ b/a Thu Jan 01 00:00:00 1970 +0000
497 @@ -1,3 +1,4 @@
508 @@ -1,3 +1,4 @@
498 +foobranch
509 +foobranch
499 expand $Id$
510 expand $Id$
500 do not process $Id:
511 do not process $Id:
501 xxx $
512 xxx $
502
513
503 % expansion in file
514 % expansion in file
504 foobranch
515 foobranch
505 expand $Id: a 5a4da427c162 Thu, 01 Jan 1970 00:00:00 +0000 test $
516 expand $Id: a 5a4da427c162 Thu, 01 Jan 1970 00:00:00 +0000 test $
506 % switch off expansion
517 % switch off expansion
507 % kwshrink with unknown file u
518 % kwshrink with unknown file u
508 overwriting a shrinking keywords
519 overwriting a shrinking keywords
509 overwriting m shrinking keywords
520 overwriting m shrinking keywords
510 overwriting x/a shrinking keywords
521 overwriting x/a shrinking keywords
511 % cat
522 % cat
512 expand $Id$
523 expand $Id$
513 do not process $Id:
524 do not process $Id:
514 xxx $
525 xxx $
515 $Xinfo$
526 $Xinfo$
516 ignore $Id$
527 ignore $Id$
517 % hg cat
528 % hg cat
518 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
529 expand $Id: a bb948857c743 Thu, 01 Jan 1970 00:00:02 +0000 user $
519 do not process $Id:
530 do not process $Id:
520 xxx $
531 xxx $
521 $Xinfo: User Name <user@example.com>: firstline $
532 $Xinfo: User Name <user@example.com>: firstline $
522 ignore $Id$
533 ignore $Id$
523 a
534 a
524 % cat
535 % cat
525 expand $Id$
536 expand $Id$
526 do not process $Id:
537 do not process $Id:
527 xxx $
538 xxx $
528 $Xinfo$
539 $Xinfo$
529 ignore $Id$
540 ignore $Id$
530 % hg cat
541 % hg cat
531 expand $Id$
542 expand $Id$
532 do not process $Id:
543 do not process $Id:
533 xxx $
544 xxx $
534 $Xinfo$
545 $Xinfo$
535 ignore $Id$
546 ignore $Id$
536 a
547 a
General Comments 0
You need to be logged in to leave comments. Login now