##// END OF EJS Templates
webcommands: get correct parents when comparing a removed file (issue4962)...
av6 -
r27158:522ffc18 default
parent child Browse files
Show More
@@ -1,1344 +1,1349
1 #
1 #
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
2 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import cgi
10 import cgi
11 import copy
11 import copy
12 import mimetypes
12 import mimetypes
13 import os
13 import os
14 import re
14 import re
15
15
16 from ..i18n import _
16 from ..i18n import _
17 from ..node import hex, short
17 from ..node import hex, short
18
18
19 from .common import (
19 from .common import (
20 ErrorResponse,
20 ErrorResponse,
21 HTTP_FORBIDDEN,
21 HTTP_FORBIDDEN,
22 HTTP_NOT_FOUND,
22 HTTP_NOT_FOUND,
23 HTTP_OK,
23 HTTP_OK,
24 get_contact,
24 get_contact,
25 paritygen,
25 paritygen,
26 staticfile,
26 staticfile,
27 )
27 )
28
28
29 from .. import (
29 from .. import (
30 archival,
30 archival,
31 encoding,
31 encoding,
32 error,
32 error,
33 graphmod,
33 graphmod,
34 patch,
34 patch,
35 revset,
35 revset,
36 scmutil,
36 scmutil,
37 templatefilters,
37 templatefilters,
38 templater,
38 templater,
39 util,
39 util,
40 )
40 )
41
41
42 from . import (
42 from . import (
43 webutil,
43 webutil,
44 )
44 )
45
45
46 __all__ = []
46 __all__ = []
47 commands = {}
47 commands = {}
48
48
49 class webcommand(object):
49 class webcommand(object):
50 """Decorator used to register a web command handler.
50 """Decorator used to register a web command handler.
51
51
52 The decorator takes as its positional arguments the name/path the
52 The decorator takes as its positional arguments the name/path the
53 command should be accessible under.
53 command should be accessible under.
54
54
55 Usage:
55 Usage:
56
56
57 @webcommand('mycommand')
57 @webcommand('mycommand')
58 def mycommand(web, req, tmpl):
58 def mycommand(web, req, tmpl):
59 pass
59 pass
60 """
60 """
61
61
62 def __init__(self, name):
62 def __init__(self, name):
63 self.name = name
63 self.name = name
64
64
65 def __call__(self, func):
65 def __call__(self, func):
66 __all__.append(self.name)
66 __all__.append(self.name)
67 commands[self.name] = func
67 commands[self.name] = func
68 return func
68 return func
69
69
70 @webcommand('log')
70 @webcommand('log')
71 def log(web, req, tmpl):
71 def log(web, req, tmpl):
72 """
72 """
73 /log[/{revision}[/{path}]]
73 /log[/{revision}[/{path}]]
74 --------------------------
74 --------------------------
75
75
76 Show repository or file history.
76 Show repository or file history.
77
77
78 For URLs of the form ``/log/{revision}``, a list of changesets starting at
78 For URLs of the form ``/log/{revision}``, a list of changesets starting at
79 the specified changeset identifier is shown. If ``{revision}`` is not
79 the specified changeset identifier is shown. If ``{revision}`` is not
80 defined, the default is ``tip``. This form is equivalent to the
80 defined, the default is ``tip``. This form is equivalent to the
81 ``changelog`` handler.
81 ``changelog`` handler.
82
82
83 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
83 For URLs of the form ``/log/{revision}/{file}``, the history for a specific
84 file will be shown. This form is equivalent to the ``filelog`` handler.
84 file will be shown. This form is equivalent to the ``filelog`` handler.
85 """
85 """
86
86
87 if 'file' in req.form and req.form['file'][0]:
87 if 'file' in req.form and req.form['file'][0]:
88 return filelog(web, req, tmpl)
88 return filelog(web, req, tmpl)
89 else:
89 else:
90 return changelog(web, req, tmpl)
90 return changelog(web, req, tmpl)
91
91
92 @webcommand('rawfile')
92 @webcommand('rawfile')
93 def rawfile(web, req, tmpl):
93 def rawfile(web, req, tmpl):
94 guessmime = web.configbool('web', 'guessmime', False)
94 guessmime = web.configbool('web', 'guessmime', False)
95
95
96 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
96 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
97 if not path:
97 if not path:
98 content = manifest(web, req, tmpl)
98 content = manifest(web, req, tmpl)
99 req.respond(HTTP_OK, web.ctype)
99 req.respond(HTTP_OK, web.ctype)
100 return content
100 return content
101
101
102 try:
102 try:
103 fctx = webutil.filectx(web.repo, req)
103 fctx = webutil.filectx(web.repo, req)
104 except error.LookupError as inst:
104 except error.LookupError as inst:
105 try:
105 try:
106 content = manifest(web, req, tmpl)
106 content = manifest(web, req, tmpl)
107 req.respond(HTTP_OK, web.ctype)
107 req.respond(HTTP_OK, web.ctype)
108 return content
108 return content
109 except ErrorResponse:
109 except ErrorResponse:
110 raise inst
110 raise inst
111
111
112 path = fctx.path()
112 path = fctx.path()
113 text = fctx.data()
113 text = fctx.data()
114 mt = 'application/binary'
114 mt = 'application/binary'
115 if guessmime:
115 if guessmime:
116 mt = mimetypes.guess_type(path)[0]
116 mt = mimetypes.guess_type(path)[0]
117 if mt is None:
117 if mt is None:
118 if util.binary(text):
118 if util.binary(text):
119 mt = 'application/binary'
119 mt = 'application/binary'
120 else:
120 else:
121 mt = 'text/plain'
121 mt = 'text/plain'
122 if mt.startswith('text/'):
122 if mt.startswith('text/'):
123 mt += '; charset="%s"' % encoding.encoding
123 mt += '; charset="%s"' % encoding.encoding
124
124
125 req.respond(HTTP_OK, mt, path, body=text)
125 req.respond(HTTP_OK, mt, path, body=text)
126 return []
126 return []
127
127
128 def _filerevision(web, req, tmpl, fctx):
128 def _filerevision(web, req, tmpl, fctx):
129 f = fctx.path()
129 f = fctx.path()
130 text = fctx.data()
130 text = fctx.data()
131 parity = paritygen(web.stripecount)
131 parity = paritygen(web.stripecount)
132
132
133 if util.binary(text):
133 if util.binary(text):
134 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
134 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
135 text = '(binary:%s)' % mt
135 text = '(binary:%s)' % mt
136
136
137 def lines():
137 def lines():
138 for lineno, t in enumerate(text.splitlines(True)):
138 for lineno, t in enumerate(text.splitlines(True)):
139 yield {"line": t,
139 yield {"line": t,
140 "lineid": "l%d" % (lineno + 1),
140 "lineid": "l%d" % (lineno + 1),
141 "linenumber": "% 6d" % (lineno + 1),
141 "linenumber": "% 6d" % (lineno + 1),
142 "parity": parity.next()}
142 "parity": parity.next()}
143
143
144 return tmpl("filerevision",
144 return tmpl("filerevision",
145 file=f,
145 file=f,
146 path=webutil.up(f),
146 path=webutil.up(f),
147 text=lines(),
147 text=lines(),
148 rev=fctx.rev(),
148 rev=fctx.rev(),
149 symrev=webutil.symrevorshortnode(req, fctx),
149 symrev=webutil.symrevorshortnode(req, fctx),
150 node=fctx.hex(),
150 node=fctx.hex(),
151 author=fctx.user(),
151 author=fctx.user(),
152 date=fctx.date(),
152 date=fctx.date(),
153 desc=fctx.description(),
153 desc=fctx.description(),
154 extra=fctx.extra(),
154 extra=fctx.extra(),
155 branch=webutil.nodebranchnodefault(fctx),
155 branch=webutil.nodebranchnodefault(fctx),
156 parent=webutil.parents(fctx),
156 parent=webutil.parents(fctx),
157 child=webutil.children(fctx),
157 child=webutil.children(fctx),
158 rename=webutil.renamelink(fctx),
158 rename=webutil.renamelink(fctx),
159 tags=webutil.nodetagsdict(web.repo, fctx.node()),
159 tags=webutil.nodetagsdict(web.repo, fctx.node()),
160 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
160 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
161 permissions=fctx.manifest().flags(f))
161 permissions=fctx.manifest().flags(f))
162
162
163 @webcommand('file')
163 @webcommand('file')
164 def file(web, req, tmpl):
164 def file(web, req, tmpl):
165 """
165 """
166 /file/{revision}[/{path}]
166 /file/{revision}[/{path}]
167 -------------------------
167 -------------------------
168
168
169 Show information about a directory or file in the repository.
169 Show information about a directory or file in the repository.
170
170
171 Info about the ``path`` given as a URL parameter will be rendered.
171 Info about the ``path`` given as a URL parameter will be rendered.
172
172
173 If ``path`` is a directory, information about the entries in that
173 If ``path`` is a directory, information about the entries in that
174 directory will be rendered. This form is equivalent to the ``manifest``
174 directory will be rendered. This form is equivalent to the ``manifest``
175 handler.
175 handler.
176
176
177 If ``path`` is a file, information about that file will be shown via
177 If ``path`` is a file, information about that file will be shown via
178 the ``filerevision`` template.
178 the ``filerevision`` template.
179
179
180 If ``path`` is not defined, information about the root directory will
180 If ``path`` is not defined, information about the root directory will
181 be rendered.
181 be rendered.
182 """
182 """
183 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
183 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
184 if not path:
184 if not path:
185 return manifest(web, req, tmpl)
185 return manifest(web, req, tmpl)
186 try:
186 try:
187 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
187 return _filerevision(web, req, tmpl, webutil.filectx(web.repo, req))
188 except error.LookupError as inst:
188 except error.LookupError as inst:
189 try:
189 try:
190 return manifest(web, req, tmpl)
190 return manifest(web, req, tmpl)
191 except ErrorResponse:
191 except ErrorResponse:
192 raise inst
192 raise inst
193
193
194 def _search(web, req, tmpl):
194 def _search(web, req, tmpl):
195 MODE_REVISION = 'rev'
195 MODE_REVISION = 'rev'
196 MODE_KEYWORD = 'keyword'
196 MODE_KEYWORD = 'keyword'
197 MODE_REVSET = 'revset'
197 MODE_REVSET = 'revset'
198
198
199 def revsearch(ctx):
199 def revsearch(ctx):
200 yield ctx
200 yield ctx
201
201
202 def keywordsearch(query):
202 def keywordsearch(query):
203 lower = encoding.lower
203 lower = encoding.lower
204 qw = lower(query).split()
204 qw = lower(query).split()
205
205
206 def revgen():
206 def revgen():
207 cl = web.repo.changelog
207 cl = web.repo.changelog
208 for i in xrange(len(web.repo) - 1, 0, -100):
208 for i in xrange(len(web.repo) - 1, 0, -100):
209 l = []
209 l = []
210 for j in cl.revs(max(0, i - 99), i):
210 for j in cl.revs(max(0, i - 99), i):
211 ctx = web.repo[j]
211 ctx = web.repo[j]
212 l.append(ctx)
212 l.append(ctx)
213 l.reverse()
213 l.reverse()
214 for e in l:
214 for e in l:
215 yield e
215 yield e
216
216
217 for ctx in revgen():
217 for ctx in revgen():
218 miss = 0
218 miss = 0
219 for q in qw:
219 for q in qw:
220 if not (q in lower(ctx.user()) or
220 if not (q in lower(ctx.user()) or
221 q in lower(ctx.description()) or
221 q in lower(ctx.description()) or
222 q in lower(" ".join(ctx.files()))):
222 q in lower(" ".join(ctx.files()))):
223 miss = 1
223 miss = 1
224 break
224 break
225 if miss:
225 if miss:
226 continue
226 continue
227
227
228 yield ctx
228 yield ctx
229
229
230 def revsetsearch(revs):
230 def revsetsearch(revs):
231 for r in revs:
231 for r in revs:
232 yield web.repo[r]
232 yield web.repo[r]
233
233
234 searchfuncs = {
234 searchfuncs = {
235 MODE_REVISION: (revsearch, 'exact revision search'),
235 MODE_REVISION: (revsearch, 'exact revision search'),
236 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
236 MODE_KEYWORD: (keywordsearch, 'literal keyword search'),
237 MODE_REVSET: (revsetsearch, 'revset expression search'),
237 MODE_REVSET: (revsetsearch, 'revset expression search'),
238 }
238 }
239
239
240 def getsearchmode(query):
240 def getsearchmode(query):
241 try:
241 try:
242 ctx = web.repo[query]
242 ctx = web.repo[query]
243 except (error.RepoError, error.LookupError):
243 except (error.RepoError, error.LookupError):
244 # query is not an exact revision pointer, need to
244 # query is not an exact revision pointer, need to
245 # decide if it's a revset expression or keywords
245 # decide if it's a revset expression or keywords
246 pass
246 pass
247 else:
247 else:
248 return MODE_REVISION, ctx
248 return MODE_REVISION, ctx
249
249
250 revdef = 'reverse(%s)' % query
250 revdef = 'reverse(%s)' % query
251 try:
251 try:
252 tree = revset.parse(revdef)
252 tree = revset.parse(revdef)
253 except error.ParseError:
253 except error.ParseError:
254 # can't parse to a revset tree
254 # can't parse to a revset tree
255 return MODE_KEYWORD, query
255 return MODE_KEYWORD, query
256
256
257 if revset.depth(tree) <= 2:
257 if revset.depth(tree) <= 2:
258 # no revset syntax used
258 # no revset syntax used
259 return MODE_KEYWORD, query
259 return MODE_KEYWORD, query
260
260
261 if any((token, (value or '')[:3]) == ('string', 're:')
261 if any((token, (value or '')[:3]) == ('string', 're:')
262 for token, value, pos in revset.tokenize(revdef)):
262 for token, value, pos in revset.tokenize(revdef)):
263 return MODE_KEYWORD, query
263 return MODE_KEYWORD, query
264
264
265 funcsused = revset.funcsused(tree)
265 funcsused = revset.funcsused(tree)
266 if not funcsused.issubset(revset.safesymbols):
266 if not funcsused.issubset(revset.safesymbols):
267 return MODE_KEYWORD, query
267 return MODE_KEYWORD, query
268
268
269 mfunc = revset.match(web.repo.ui, revdef)
269 mfunc = revset.match(web.repo.ui, revdef)
270 try:
270 try:
271 revs = mfunc(web.repo)
271 revs = mfunc(web.repo)
272 return MODE_REVSET, revs
272 return MODE_REVSET, revs
273 # ParseError: wrongly placed tokens, wrongs arguments, etc
273 # ParseError: wrongly placed tokens, wrongs arguments, etc
274 # RepoLookupError: no such revision, e.g. in 'revision:'
274 # RepoLookupError: no such revision, e.g. in 'revision:'
275 # Abort: bookmark/tag not exists
275 # Abort: bookmark/tag not exists
276 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
276 # LookupError: ambiguous identifier, e.g. in '(bc)' on a large repo
277 except (error.ParseError, error.RepoLookupError, error.Abort,
277 except (error.ParseError, error.RepoLookupError, error.Abort,
278 LookupError):
278 LookupError):
279 return MODE_KEYWORD, query
279 return MODE_KEYWORD, query
280
280
281 def changelist(**map):
281 def changelist(**map):
282 count = 0
282 count = 0
283
283
284 for ctx in searchfunc[0](funcarg):
284 for ctx in searchfunc[0](funcarg):
285 count += 1
285 count += 1
286 n = ctx.node()
286 n = ctx.node()
287 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
287 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
288 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
288 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
289
289
290 yield tmpl('searchentry',
290 yield tmpl('searchentry',
291 parity=parity.next(),
291 parity=parity.next(),
292 author=ctx.user(),
292 author=ctx.user(),
293 parent=lambda **x: webutil.parents(ctx),
293 parent=lambda **x: webutil.parents(ctx),
294 child=lambda **x: webutil.children(ctx),
294 child=lambda **x: webutil.children(ctx),
295 changelogtag=showtags,
295 changelogtag=showtags,
296 desc=ctx.description(),
296 desc=ctx.description(),
297 extra=ctx.extra(),
297 extra=ctx.extra(),
298 date=ctx.date(),
298 date=ctx.date(),
299 files=files,
299 files=files,
300 rev=ctx.rev(),
300 rev=ctx.rev(),
301 node=hex(n),
301 node=hex(n),
302 tags=webutil.nodetagsdict(web.repo, n),
302 tags=webutil.nodetagsdict(web.repo, n),
303 bookmarks=webutil.nodebookmarksdict(web.repo, n),
303 bookmarks=webutil.nodebookmarksdict(web.repo, n),
304 inbranch=webutil.nodeinbranch(web.repo, ctx),
304 inbranch=webutil.nodeinbranch(web.repo, ctx),
305 branches=webutil.nodebranchdict(web.repo, ctx))
305 branches=webutil.nodebranchdict(web.repo, ctx))
306
306
307 if count >= revcount:
307 if count >= revcount:
308 break
308 break
309
309
310 query = req.form['rev'][0]
310 query = req.form['rev'][0]
311 revcount = web.maxchanges
311 revcount = web.maxchanges
312 if 'revcount' in req.form:
312 if 'revcount' in req.form:
313 try:
313 try:
314 revcount = int(req.form.get('revcount', [revcount])[0])
314 revcount = int(req.form.get('revcount', [revcount])[0])
315 revcount = max(revcount, 1)
315 revcount = max(revcount, 1)
316 tmpl.defaults['sessionvars']['revcount'] = revcount
316 tmpl.defaults['sessionvars']['revcount'] = revcount
317 except ValueError:
317 except ValueError:
318 pass
318 pass
319
319
320 lessvars = copy.copy(tmpl.defaults['sessionvars'])
320 lessvars = copy.copy(tmpl.defaults['sessionvars'])
321 lessvars['revcount'] = max(revcount / 2, 1)
321 lessvars['revcount'] = max(revcount / 2, 1)
322 lessvars['rev'] = query
322 lessvars['rev'] = query
323 morevars = copy.copy(tmpl.defaults['sessionvars'])
323 morevars = copy.copy(tmpl.defaults['sessionvars'])
324 morevars['revcount'] = revcount * 2
324 morevars['revcount'] = revcount * 2
325 morevars['rev'] = query
325 morevars['rev'] = query
326
326
327 mode, funcarg = getsearchmode(query)
327 mode, funcarg = getsearchmode(query)
328
328
329 if 'forcekw' in req.form:
329 if 'forcekw' in req.form:
330 showforcekw = ''
330 showforcekw = ''
331 showunforcekw = searchfuncs[mode][1]
331 showunforcekw = searchfuncs[mode][1]
332 mode = MODE_KEYWORD
332 mode = MODE_KEYWORD
333 funcarg = query
333 funcarg = query
334 else:
334 else:
335 if mode != MODE_KEYWORD:
335 if mode != MODE_KEYWORD:
336 showforcekw = searchfuncs[MODE_KEYWORD][1]
336 showforcekw = searchfuncs[MODE_KEYWORD][1]
337 else:
337 else:
338 showforcekw = ''
338 showforcekw = ''
339 showunforcekw = ''
339 showunforcekw = ''
340
340
341 searchfunc = searchfuncs[mode]
341 searchfunc = searchfuncs[mode]
342
342
343 tip = web.repo['tip']
343 tip = web.repo['tip']
344 parity = paritygen(web.stripecount)
344 parity = paritygen(web.stripecount)
345
345
346 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
346 return tmpl('search', query=query, node=tip.hex(), symrev='tip',
347 entries=changelist, archives=web.archivelist("tip"),
347 entries=changelist, archives=web.archivelist("tip"),
348 morevars=morevars, lessvars=lessvars,
348 morevars=morevars, lessvars=lessvars,
349 modedesc=searchfunc[1],
349 modedesc=searchfunc[1],
350 showforcekw=showforcekw, showunforcekw=showunforcekw)
350 showforcekw=showforcekw, showunforcekw=showunforcekw)
351
351
352 @webcommand('changelog')
352 @webcommand('changelog')
353 def changelog(web, req, tmpl, shortlog=False):
353 def changelog(web, req, tmpl, shortlog=False):
354 """
354 """
355 /changelog[/{revision}]
355 /changelog[/{revision}]
356 -----------------------
356 -----------------------
357
357
358 Show information about multiple changesets.
358 Show information about multiple changesets.
359
359
360 If the optional ``revision`` URL argument is absent, information about
360 If the optional ``revision`` URL argument is absent, information about
361 all changesets starting at ``tip`` will be rendered. If the ``revision``
361 all changesets starting at ``tip`` will be rendered. If the ``revision``
362 argument is present, changesets will be shown starting from the specified
362 argument is present, changesets will be shown starting from the specified
363 revision.
363 revision.
364
364
365 If ``revision`` is absent, the ``rev`` query string argument may be
365 If ``revision`` is absent, the ``rev`` query string argument may be
366 defined. This will perform a search for changesets.
366 defined. This will perform a search for changesets.
367
367
368 The argument for ``rev`` can be a single revision, a revision set,
368 The argument for ``rev`` can be a single revision, a revision set,
369 or a literal keyword to search for in changeset data (equivalent to
369 or a literal keyword to search for in changeset data (equivalent to
370 :hg:`log -k`).
370 :hg:`log -k`).
371
371
372 The ``revcount`` query string argument defines the maximum numbers of
372 The ``revcount`` query string argument defines the maximum numbers of
373 changesets to render.
373 changesets to render.
374
374
375 For non-searches, the ``changelog`` template will be rendered.
375 For non-searches, the ``changelog`` template will be rendered.
376 """
376 """
377
377
378 query = ''
378 query = ''
379 if 'node' in req.form:
379 if 'node' in req.form:
380 ctx = webutil.changectx(web.repo, req)
380 ctx = webutil.changectx(web.repo, req)
381 symrev = webutil.symrevorshortnode(req, ctx)
381 symrev = webutil.symrevorshortnode(req, ctx)
382 elif 'rev' in req.form:
382 elif 'rev' in req.form:
383 return _search(web, req, tmpl)
383 return _search(web, req, tmpl)
384 else:
384 else:
385 ctx = web.repo['tip']
385 ctx = web.repo['tip']
386 symrev = 'tip'
386 symrev = 'tip'
387
387
388 def changelist():
388 def changelist():
389 revs = []
389 revs = []
390 if pos != -1:
390 if pos != -1:
391 revs = web.repo.changelog.revs(pos, 0)
391 revs = web.repo.changelog.revs(pos, 0)
392 curcount = 0
392 curcount = 0
393 for rev in revs:
393 for rev in revs:
394 curcount += 1
394 curcount += 1
395 if curcount > revcount + 1:
395 if curcount > revcount + 1:
396 break
396 break
397
397
398 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
398 entry = webutil.changelistentry(web, web.repo[rev], tmpl)
399 entry['parity'] = parity.next()
399 entry['parity'] = parity.next()
400 yield entry
400 yield entry
401
401
402 if shortlog:
402 if shortlog:
403 revcount = web.maxshortchanges
403 revcount = web.maxshortchanges
404 else:
404 else:
405 revcount = web.maxchanges
405 revcount = web.maxchanges
406
406
407 if 'revcount' in req.form:
407 if 'revcount' in req.form:
408 try:
408 try:
409 revcount = int(req.form.get('revcount', [revcount])[0])
409 revcount = int(req.form.get('revcount', [revcount])[0])
410 revcount = max(revcount, 1)
410 revcount = max(revcount, 1)
411 tmpl.defaults['sessionvars']['revcount'] = revcount
411 tmpl.defaults['sessionvars']['revcount'] = revcount
412 except ValueError:
412 except ValueError:
413 pass
413 pass
414
414
415 lessvars = copy.copy(tmpl.defaults['sessionvars'])
415 lessvars = copy.copy(tmpl.defaults['sessionvars'])
416 lessvars['revcount'] = max(revcount / 2, 1)
416 lessvars['revcount'] = max(revcount / 2, 1)
417 morevars = copy.copy(tmpl.defaults['sessionvars'])
417 morevars = copy.copy(tmpl.defaults['sessionvars'])
418 morevars['revcount'] = revcount * 2
418 morevars['revcount'] = revcount * 2
419
419
420 count = len(web.repo)
420 count = len(web.repo)
421 pos = ctx.rev()
421 pos = ctx.rev()
422 parity = paritygen(web.stripecount)
422 parity = paritygen(web.stripecount)
423
423
424 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
424 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
425
425
426 entries = list(changelist())
426 entries = list(changelist())
427 latestentry = entries[:1]
427 latestentry = entries[:1]
428 if len(entries) > revcount:
428 if len(entries) > revcount:
429 nextentry = entries[-1:]
429 nextentry = entries[-1:]
430 entries = entries[:-1]
430 entries = entries[:-1]
431 else:
431 else:
432 nextentry = []
432 nextentry = []
433
433
434 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
434 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
435 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
435 node=ctx.hex(), rev=pos, symrev=symrev, changesets=count,
436 entries=entries,
436 entries=entries,
437 latestentry=latestentry, nextentry=nextentry,
437 latestentry=latestentry, nextentry=nextentry,
438 archives=web.archivelist("tip"), revcount=revcount,
438 archives=web.archivelist("tip"), revcount=revcount,
439 morevars=morevars, lessvars=lessvars, query=query)
439 morevars=morevars, lessvars=lessvars, query=query)
440
440
441 @webcommand('shortlog')
441 @webcommand('shortlog')
442 def shortlog(web, req, tmpl):
442 def shortlog(web, req, tmpl):
443 """
443 """
444 /shortlog
444 /shortlog
445 ---------
445 ---------
446
446
447 Show basic information about a set of changesets.
447 Show basic information about a set of changesets.
448
448
449 This accepts the same parameters as the ``changelog`` handler. The only
449 This accepts the same parameters as the ``changelog`` handler. The only
450 difference is the ``shortlog`` template will be rendered instead of the
450 difference is the ``shortlog`` template will be rendered instead of the
451 ``changelog`` template.
451 ``changelog`` template.
452 """
452 """
453 return changelog(web, req, tmpl, shortlog=True)
453 return changelog(web, req, tmpl, shortlog=True)
454
454
455 @webcommand('changeset')
455 @webcommand('changeset')
456 def changeset(web, req, tmpl):
456 def changeset(web, req, tmpl):
457 """
457 """
458 /changeset[/{revision}]
458 /changeset[/{revision}]
459 -----------------------
459 -----------------------
460
460
461 Show information about a single changeset.
461 Show information about a single changeset.
462
462
463 A URL path argument is the changeset identifier to show. See ``hg help
463 A URL path argument is the changeset identifier to show. See ``hg help
464 revisions`` for possible values. If not defined, the ``tip`` changeset
464 revisions`` for possible values. If not defined, the ``tip`` changeset
465 will be shown.
465 will be shown.
466
466
467 The ``changeset`` template is rendered. Contents of the ``changesettag``,
467 The ``changeset`` template is rendered. Contents of the ``changesettag``,
468 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
468 ``changesetbookmark``, ``filenodelink``, ``filenolink``, and the many
469 templates related to diffs may all be used to produce the output.
469 templates related to diffs may all be used to produce the output.
470 """
470 """
471 ctx = webutil.changectx(web.repo, req)
471 ctx = webutil.changectx(web.repo, req)
472
472
473 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
473 return tmpl('changeset', **webutil.changesetentry(web, req, tmpl, ctx))
474
474
475 rev = webcommand('rev')(changeset)
475 rev = webcommand('rev')(changeset)
476
476
477 def decodepath(path):
477 def decodepath(path):
478 """Hook for mapping a path in the repository to a path in the
478 """Hook for mapping a path in the repository to a path in the
479 working copy.
479 working copy.
480
480
481 Extensions (e.g., largefiles) can override this to remap files in
481 Extensions (e.g., largefiles) can override this to remap files in
482 the virtual file system presented by the manifest command below."""
482 the virtual file system presented by the manifest command below."""
483 return path
483 return path
484
484
485 @webcommand('manifest')
485 @webcommand('manifest')
486 def manifest(web, req, tmpl):
486 def manifest(web, req, tmpl):
487 """
487 """
488 /manifest[/{revision}[/{path}]]
488 /manifest[/{revision}[/{path}]]
489 -------------------------------
489 -------------------------------
490
490
491 Show information about a directory.
491 Show information about a directory.
492
492
493 If the URL path arguments are omitted, information about the root
493 If the URL path arguments are omitted, information about the root
494 directory for the ``tip`` changeset will be shown.
494 directory for the ``tip`` changeset will be shown.
495
495
496 Because this handler can only show information for directories, it
496 Because this handler can only show information for directories, it
497 is recommended to use the ``file`` handler instead, as it can handle both
497 is recommended to use the ``file`` handler instead, as it can handle both
498 directories and files.
498 directories and files.
499
499
500 The ``manifest`` template will be rendered for this handler.
500 The ``manifest`` template will be rendered for this handler.
501 """
501 """
502 if 'node' in req.form:
502 if 'node' in req.form:
503 ctx = webutil.changectx(web.repo, req)
503 ctx = webutil.changectx(web.repo, req)
504 symrev = webutil.symrevorshortnode(req, ctx)
504 symrev = webutil.symrevorshortnode(req, ctx)
505 else:
505 else:
506 ctx = web.repo['tip']
506 ctx = web.repo['tip']
507 symrev = 'tip'
507 symrev = 'tip'
508 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
508 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
509 mf = ctx.manifest()
509 mf = ctx.manifest()
510 node = ctx.node()
510 node = ctx.node()
511
511
512 files = {}
512 files = {}
513 dirs = {}
513 dirs = {}
514 parity = paritygen(web.stripecount)
514 parity = paritygen(web.stripecount)
515
515
516 if path and path[-1] != "/":
516 if path and path[-1] != "/":
517 path += "/"
517 path += "/"
518 l = len(path)
518 l = len(path)
519 abspath = "/" + path
519 abspath = "/" + path
520
520
521 for full, n in mf.iteritems():
521 for full, n in mf.iteritems():
522 # the virtual path (working copy path) used for the full
522 # the virtual path (working copy path) used for the full
523 # (repository) path
523 # (repository) path
524 f = decodepath(full)
524 f = decodepath(full)
525
525
526 if f[:l] != path:
526 if f[:l] != path:
527 continue
527 continue
528 remain = f[l:]
528 remain = f[l:]
529 elements = remain.split('/')
529 elements = remain.split('/')
530 if len(elements) == 1:
530 if len(elements) == 1:
531 files[remain] = full
531 files[remain] = full
532 else:
532 else:
533 h = dirs # need to retain ref to dirs (root)
533 h = dirs # need to retain ref to dirs (root)
534 for elem in elements[0:-1]:
534 for elem in elements[0:-1]:
535 if elem not in h:
535 if elem not in h:
536 h[elem] = {}
536 h[elem] = {}
537 h = h[elem]
537 h = h[elem]
538 if len(h) > 1:
538 if len(h) > 1:
539 break
539 break
540 h[None] = None # denotes files present
540 h[None] = None # denotes files present
541
541
542 if mf and not files and not dirs:
542 if mf and not files and not dirs:
543 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
543 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
544
544
545 def filelist(**map):
545 def filelist(**map):
546 for f in sorted(files):
546 for f in sorted(files):
547 full = files[f]
547 full = files[f]
548
548
549 fctx = ctx.filectx(full)
549 fctx = ctx.filectx(full)
550 yield {"file": full,
550 yield {"file": full,
551 "parity": parity.next(),
551 "parity": parity.next(),
552 "basename": f,
552 "basename": f,
553 "date": fctx.date(),
553 "date": fctx.date(),
554 "size": fctx.size(),
554 "size": fctx.size(),
555 "permissions": mf.flags(full)}
555 "permissions": mf.flags(full)}
556
556
557 def dirlist(**map):
557 def dirlist(**map):
558 for d in sorted(dirs):
558 for d in sorted(dirs):
559
559
560 emptydirs = []
560 emptydirs = []
561 h = dirs[d]
561 h = dirs[d]
562 while isinstance(h, dict) and len(h) == 1:
562 while isinstance(h, dict) and len(h) == 1:
563 k, v = h.items()[0]
563 k, v = h.items()[0]
564 if v:
564 if v:
565 emptydirs.append(k)
565 emptydirs.append(k)
566 h = v
566 h = v
567
567
568 path = "%s%s" % (abspath, d)
568 path = "%s%s" % (abspath, d)
569 yield {"parity": parity.next(),
569 yield {"parity": parity.next(),
570 "path": path,
570 "path": path,
571 "emptydirs": "/".join(emptydirs),
571 "emptydirs": "/".join(emptydirs),
572 "basename": d}
572 "basename": d}
573
573
574 return tmpl("manifest",
574 return tmpl("manifest",
575 rev=ctx.rev(),
575 rev=ctx.rev(),
576 symrev=symrev,
576 symrev=symrev,
577 node=hex(node),
577 node=hex(node),
578 path=abspath,
578 path=abspath,
579 up=webutil.up(abspath),
579 up=webutil.up(abspath),
580 upparity=parity.next(),
580 upparity=parity.next(),
581 fentries=filelist,
581 fentries=filelist,
582 dentries=dirlist,
582 dentries=dirlist,
583 archives=web.archivelist(hex(node)),
583 archives=web.archivelist(hex(node)),
584 tags=webutil.nodetagsdict(web.repo, node),
584 tags=webutil.nodetagsdict(web.repo, node),
585 bookmarks=webutil.nodebookmarksdict(web.repo, node),
585 bookmarks=webutil.nodebookmarksdict(web.repo, node),
586 branch=webutil.nodebranchnodefault(ctx),
586 branch=webutil.nodebranchnodefault(ctx),
587 inbranch=webutil.nodeinbranch(web.repo, ctx),
587 inbranch=webutil.nodeinbranch(web.repo, ctx),
588 branches=webutil.nodebranchdict(web.repo, ctx))
588 branches=webutil.nodebranchdict(web.repo, ctx))
589
589
590 @webcommand('tags')
590 @webcommand('tags')
591 def tags(web, req, tmpl):
591 def tags(web, req, tmpl):
592 """
592 """
593 /tags
593 /tags
594 -----
594 -----
595
595
596 Show information about tags.
596 Show information about tags.
597
597
598 No arguments are accepted.
598 No arguments are accepted.
599
599
600 The ``tags`` template is rendered.
600 The ``tags`` template is rendered.
601 """
601 """
602 i = list(reversed(web.repo.tagslist()))
602 i = list(reversed(web.repo.tagslist()))
603 parity = paritygen(web.stripecount)
603 parity = paritygen(web.stripecount)
604
604
605 def entries(notip, latestonly, **map):
605 def entries(notip, latestonly, **map):
606 t = i
606 t = i
607 if notip:
607 if notip:
608 t = [(k, n) for k, n in i if k != "tip"]
608 t = [(k, n) for k, n in i if k != "tip"]
609 if latestonly:
609 if latestonly:
610 t = t[:1]
610 t = t[:1]
611 for k, n in t:
611 for k, n in t:
612 yield {"parity": parity.next(),
612 yield {"parity": parity.next(),
613 "tag": k,
613 "tag": k,
614 "date": web.repo[n].date(),
614 "date": web.repo[n].date(),
615 "node": hex(n)}
615 "node": hex(n)}
616
616
617 return tmpl("tags",
617 return tmpl("tags",
618 node=hex(web.repo.changelog.tip()),
618 node=hex(web.repo.changelog.tip()),
619 entries=lambda **x: entries(False, False, **x),
619 entries=lambda **x: entries(False, False, **x),
620 entriesnotip=lambda **x: entries(True, False, **x),
620 entriesnotip=lambda **x: entries(True, False, **x),
621 latestentry=lambda **x: entries(True, True, **x))
621 latestentry=lambda **x: entries(True, True, **x))
622
622
623 @webcommand('bookmarks')
623 @webcommand('bookmarks')
624 def bookmarks(web, req, tmpl):
624 def bookmarks(web, req, tmpl):
625 """
625 """
626 /bookmarks
626 /bookmarks
627 ----------
627 ----------
628
628
629 Show information about bookmarks.
629 Show information about bookmarks.
630
630
631 No arguments are accepted.
631 No arguments are accepted.
632
632
633 The ``bookmarks`` template is rendered.
633 The ``bookmarks`` template is rendered.
634 """
634 """
635 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
635 i = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
636 parity = paritygen(web.stripecount)
636 parity = paritygen(web.stripecount)
637
637
638 def entries(latestonly, **map):
638 def entries(latestonly, **map):
639 if latestonly:
639 if latestonly:
640 t = [min(i)]
640 t = [min(i)]
641 else:
641 else:
642 t = sorted(i)
642 t = sorted(i)
643 for k, n in t:
643 for k, n in t:
644 yield {"parity": parity.next(),
644 yield {"parity": parity.next(),
645 "bookmark": k,
645 "bookmark": k,
646 "date": web.repo[n].date(),
646 "date": web.repo[n].date(),
647 "node": hex(n)}
647 "node": hex(n)}
648
648
649 return tmpl("bookmarks",
649 return tmpl("bookmarks",
650 node=hex(web.repo.changelog.tip()),
650 node=hex(web.repo.changelog.tip()),
651 entries=lambda **x: entries(latestonly=False, **x),
651 entries=lambda **x: entries(latestonly=False, **x),
652 latestentry=lambda **x: entries(latestonly=True, **x))
652 latestentry=lambda **x: entries(latestonly=True, **x))
653
653
654 @webcommand('branches')
654 @webcommand('branches')
655 def branches(web, req, tmpl):
655 def branches(web, req, tmpl):
656 """
656 """
657 /branches
657 /branches
658 ---------
658 ---------
659
659
660 Show information about branches.
660 Show information about branches.
661
661
662 All known branches are contained in the output, even closed branches.
662 All known branches are contained in the output, even closed branches.
663
663
664 No arguments are accepted.
664 No arguments are accepted.
665
665
666 The ``branches`` template is rendered.
666 The ``branches`` template is rendered.
667 """
667 """
668 entries = webutil.branchentries(web.repo, web.stripecount)
668 entries = webutil.branchentries(web.repo, web.stripecount)
669 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
669 latestentry = webutil.branchentries(web.repo, web.stripecount, 1)
670 return tmpl('branches', node=hex(web.repo.changelog.tip()),
670 return tmpl('branches', node=hex(web.repo.changelog.tip()),
671 entries=entries, latestentry=latestentry)
671 entries=entries, latestentry=latestentry)
672
672
673 @webcommand('summary')
673 @webcommand('summary')
674 def summary(web, req, tmpl):
674 def summary(web, req, tmpl):
675 """
675 """
676 /summary
676 /summary
677 --------
677 --------
678
678
679 Show a summary of repository state.
679 Show a summary of repository state.
680
680
681 Information about the latest changesets, bookmarks, tags, and branches
681 Information about the latest changesets, bookmarks, tags, and branches
682 is captured by this handler.
682 is captured by this handler.
683
683
684 The ``summary`` template is rendered.
684 The ``summary`` template is rendered.
685 """
685 """
686 i = reversed(web.repo.tagslist())
686 i = reversed(web.repo.tagslist())
687
687
688 def tagentries(**map):
688 def tagentries(**map):
689 parity = paritygen(web.stripecount)
689 parity = paritygen(web.stripecount)
690 count = 0
690 count = 0
691 for k, n in i:
691 for k, n in i:
692 if k == "tip": # skip tip
692 if k == "tip": # skip tip
693 continue
693 continue
694
694
695 count += 1
695 count += 1
696 if count > 10: # limit to 10 tags
696 if count > 10: # limit to 10 tags
697 break
697 break
698
698
699 yield tmpl("tagentry",
699 yield tmpl("tagentry",
700 parity=parity.next(),
700 parity=parity.next(),
701 tag=k,
701 tag=k,
702 node=hex(n),
702 node=hex(n),
703 date=web.repo[n].date())
703 date=web.repo[n].date())
704
704
705 def bookmarks(**map):
705 def bookmarks(**map):
706 parity = paritygen(web.stripecount)
706 parity = paritygen(web.stripecount)
707 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
707 marks = [b for b in web.repo._bookmarks.items() if b[1] in web.repo]
708 for k, n in sorted(marks)[:10]: # limit to 10 bookmarks
708 for k, n in sorted(marks)[:10]: # limit to 10 bookmarks
709 yield {'parity': parity.next(),
709 yield {'parity': parity.next(),
710 'bookmark': k,
710 'bookmark': k,
711 'date': web.repo[n].date(),
711 'date': web.repo[n].date(),
712 'node': hex(n)}
712 'node': hex(n)}
713
713
714 def changelist(**map):
714 def changelist(**map):
715 parity = paritygen(web.stripecount, offset=start - end)
715 parity = paritygen(web.stripecount, offset=start - end)
716 l = [] # build a list in forward order for efficiency
716 l = [] # build a list in forward order for efficiency
717 revs = []
717 revs = []
718 if start < end:
718 if start < end:
719 revs = web.repo.changelog.revs(start, end - 1)
719 revs = web.repo.changelog.revs(start, end - 1)
720 for i in revs:
720 for i in revs:
721 ctx = web.repo[i]
721 ctx = web.repo[i]
722 n = ctx.node()
722 n = ctx.node()
723 hn = hex(n)
723 hn = hex(n)
724
724
725 l.append(tmpl(
725 l.append(tmpl(
726 'shortlogentry',
726 'shortlogentry',
727 parity=parity.next(),
727 parity=parity.next(),
728 author=ctx.user(),
728 author=ctx.user(),
729 desc=ctx.description(),
729 desc=ctx.description(),
730 extra=ctx.extra(),
730 extra=ctx.extra(),
731 date=ctx.date(),
731 date=ctx.date(),
732 rev=i,
732 rev=i,
733 node=hn,
733 node=hn,
734 tags=webutil.nodetagsdict(web.repo, n),
734 tags=webutil.nodetagsdict(web.repo, n),
735 bookmarks=webutil.nodebookmarksdict(web.repo, n),
735 bookmarks=webutil.nodebookmarksdict(web.repo, n),
736 inbranch=webutil.nodeinbranch(web.repo, ctx),
736 inbranch=webutil.nodeinbranch(web.repo, ctx),
737 branches=webutil.nodebranchdict(web.repo, ctx)))
737 branches=webutil.nodebranchdict(web.repo, ctx)))
738
738
739 l.reverse()
739 l.reverse()
740 yield l
740 yield l
741
741
742 tip = web.repo['tip']
742 tip = web.repo['tip']
743 count = len(web.repo)
743 count = len(web.repo)
744 start = max(0, count - web.maxchanges)
744 start = max(0, count - web.maxchanges)
745 end = min(count, start + web.maxchanges)
745 end = min(count, start + web.maxchanges)
746
746
747 return tmpl("summary",
747 return tmpl("summary",
748 desc=web.config("web", "description", "unknown"),
748 desc=web.config("web", "description", "unknown"),
749 owner=get_contact(web.config) or "unknown",
749 owner=get_contact(web.config) or "unknown",
750 lastchange=tip.date(),
750 lastchange=tip.date(),
751 tags=tagentries,
751 tags=tagentries,
752 bookmarks=bookmarks,
752 bookmarks=bookmarks,
753 branches=webutil.branchentries(web.repo, web.stripecount, 10),
753 branches=webutil.branchentries(web.repo, web.stripecount, 10),
754 shortlog=changelist,
754 shortlog=changelist,
755 node=tip.hex(),
755 node=tip.hex(),
756 symrev='tip',
756 symrev='tip',
757 archives=web.archivelist("tip"))
757 archives=web.archivelist("tip"))
758
758
759 @webcommand('filediff')
759 @webcommand('filediff')
760 def filediff(web, req, tmpl):
760 def filediff(web, req, tmpl):
761 """
761 """
762 /diff/{revision}/{path}
762 /diff/{revision}/{path}
763 -----------------------
763 -----------------------
764
764
765 Show how a file changed in a particular commit.
765 Show how a file changed in a particular commit.
766
766
767 The ``filediff`` template is rendered.
767 The ``filediff`` template is rendered.
768
768
769 This handler is registered under both the ``/diff`` and ``/filediff``
769 This handler is registered under both the ``/diff`` and ``/filediff``
770 paths. ``/diff`` is used in modern code.
770 paths. ``/diff`` is used in modern code.
771 """
771 """
772 fctx, ctx = None, None
772 fctx, ctx = None, None
773 try:
773 try:
774 fctx = webutil.filectx(web.repo, req)
774 fctx = webutil.filectx(web.repo, req)
775 except LookupError:
775 except LookupError:
776 ctx = webutil.changectx(web.repo, req)
776 ctx = webutil.changectx(web.repo, req)
777 path = webutil.cleanpath(web.repo, req.form['file'][0])
777 path = webutil.cleanpath(web.repo, req.form['file'][0])
778 if path not in ctx.files():
778 if path not in ctx.files():
779 raise
779 raise
780
780
781 if fctx is not None:
781 if fctx is not None:
782 n = fctx.node()
782 n = fctx.node()
783 path = fctx.path()
783 path = fctx.path()
784 ctx = fctx.changectx()
784 ctx = fctx.changectx()
785 else:
785 else:
786 n = ctx.node()
786 n = ctx.node()
787 # path already defined in except clause
787 # path already defined in except clause
788
788
789 parity = paritygen(web.stripecount)
789 parity = paritygen(web.stripecount)
790 style = web.config('web', 'style', 'paper')
790 style = web.config('web', 'style', 'paper')
791 if 'style' in req.form:
791 if 'style' in req.form:
792 style = req.form['style'][0]
792 style = req.form['style'][0]
793
793
794 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
794 diffs = webutil.diffs(web.repo, tmpl, ctx, None, [path], parity, style)
795 if fctx:
795 if fctx:
796 rename = webutil.renamelink(fctx)
796 rename = webutil.renamelink(fctx)
797 ctx = fctx
797 ctx = fctx
798 else:
798 else:
799 rename = []
799 rename = []
800 ctx = ctx
800 ctx = ctx
801 return tmpl("filediff",
801 return tmpl("filediff",
802 file=path,
802 file=path,
803 node=hex(n),
803 node=hex(n),
804 rev=ctx.rev(),
804 rev=ctx.rev(),
805 symrev=webutil.symrevorshortnode(req, ctx),
805 symrev=webutil.symrevorshortnode(req, ctx),
806 date=ctx.date(),
806 date=ctx.date(),
807 desc=ctx.description(),
807 desc=ctx.description(),
808 extra=ctx.extra(),
808 extra=ctx.extra(),
809 author=ctx.user(),
809 author=ctx.user(),
810 rename=rename,
810 rename=rename,
811 branch=webutil.nodebranchnodefault(ctx),
811 branch=webutil.nodebranchnodefault(ctx),
812 parent=webutil.parents(ctx),
812 parent=webutil.parents(ctx),
813 child=webutil.children(ctx),
813 child=webutil.children(ctx),
814 tags=webutil.nodetagsdict(web.repo, n),
814 tags=webutil.nodetagsdict(web.repo, n),
815 bookmarks=webutil.nodebookmarksdict(web.repo, n),
815 bookmarks=webutil.nodebookmarksdict(web.repo, n),
816 diff=diffs)
816 diff=diffs)
817
817
818 diff = webcommand('diff')(filediff)
818 diff = webcommand('diff')(filediff)
819
819
820 @webcommand('comparison')
820 @webcommand('comparison')
821 def comparison(web, req, tmpl):
821 def comparison(web, req, tmpl):
822 """
822 """
823 /comparison/{revision}/{path}
823 /comparison/{revision}/{path}
824 -----------------------------
824 -----------------------------
825
825
826 Show a comparison between the old and new versions of a file from changes
826 Show a comparison between the old and new versions of a file from changes
827 made on a particular revision.
827 made on a particular revision.
828
828
829 This is similar to the ``diff`` handler. However, this form features
829 This is similar to the ``diff`` handler. However, this form features
830 a split or side-by-side diff rather than a unified diff.
830 a split or side-by-side diff rather than a unified diff.
831
831
832 The ``context`` query string argument can be used to control the lines of
832 The ``context`` query string argument can be used to control the lines of
833 context in the diff.
833 context in the diff.
834
834
835 The ``filecomparison`` template is rendered.
835 The ``filecomparison`` template is rendered.
836 """
836 """
837 ctx = webutil.changectx(web.repo, req)
837 ctx = webutil.changectx(web.repo, req)
838 if 'file' not in req.form:
838 if 'file' not in req.form:
839 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
839 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
840 path = webutil.cleanpath(web.repo, req.form['file'][0])
840 path = webutil.cleanpath(web.repo, req.form['file'][0])
841 rename = path in ctx and webutil.renamelink(ctx[path]) or []
841 rename = path in ctx and webutil.renamelink(ctx[path]) or []
842
842
843 parsecontext = lambda v: v == 'full' and -1 or int(v)
843 parsecontext = lambda v: v == 'full' and -1 or int(v)
844 if 'context' in req.form:
844 if 'context' in req.form:
845 context = parsecontext(req.form['context'][0])
845 context = parsecontext(req.form['context'][0])
846 else:
846 else:
847 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
847 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
848
848
849 def filelines(f):
849 def filelines(f):
850 if util.binary(f.data()):
850 if util.binary(f.data()):
851 mt = mimetypes.guess_type(f.path())[0]
851 mt = mimetypes.guess_type(f.path())[0]
852 if not mt:
852 if not mt:
853 mt = 'application/octet-stream'
853 mt = 'application/octet-stream'
854 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
854 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
855 return f.data().splitlines()
855 return f.data().splitlines()
856
856
857 fctx = None
857 parent = ctx.p1()
858 parent = ctx.p1()
858 leftrev = parent.rev()
859 leftrev = parent.rev()
859 leftnode = parent.node()
860 leftnode = parent.node()
860 rightrev = ctx.rev()
861 rightrev = ctx.rev()
861 rightnode = ctx.node()
862 rightnode = ctx.node()
862 if path in ctx:
863 if path in ctx:
863 fctx = ctx[path]
864 fctx = ctx[path]
864 rightlines = filelines(fctx)
865 rightlines = filelines(fctx)
865 if path not in parent:
866 if path not in parent:
866 leftlines = ()
867 leftlines = ()
867 else:
868 else:
868 pfctx = parent[path]
869 pfctx = parent[path]
869 leftlines = filelines(pfctx)
870 leftlines = filelines(pfctx)
870 else:
871 else:
871 rightlines = ()
872 rightlines = ()
872 fctx = ctx.parents()[0][path]
873 pfctx = ctx.parents()[0][path]
873 leftlines = filelines(fctx)
874 leftlines = filelines(pfctx)
874
875
875 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
876 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
877 if fctx is not None:
878 ctx = fctx
879 else:
880 ctx = ctx
876 return tmpl('filecomparison',
881 return tmpl('filecomparison',
877 file=path,
882 file=path,
878 node=hex(ctx.node()),
883 node=hex(ctx.node()),
879 rev=ctx.rev(),
884 rev=ctx.rev(),
880 symrev=webutil.symrevorshortnode(req, ctx),
885 symrev=webutil.symrevorshortnode(req, ctx),
881 date=ctx.date(),
886 date=ctx.date(),
882 desc=ctx.description(),
887 desc=ctx.description(),
883 extra=ctx.extra(),
888 extra=ctx.extra(),
884 author=ctx.user(),
889 author=ctx.user(),
885 rename=rename,
890 rename=rename,
886 branch=webutil.nodebranchnodefault(ctx),
891 branch=webutil.nodebranchnodefault(ctx),
887 parent=webutil.parents(fctx),
892 parent=webutil.parents(ctx),
888 child=webutil.children(fctx),
893 child=webutil.children(ctx),
889 tags=webutil.nodetagsdict(web.repo, ctx.node()),
894 tags=webutil.nodetagsdict(web.repo, ctx.node()),
890 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
895 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
891 leftrev=leftrev,
896 leftrev=leftrev,
892 leftnode=hex(leftnode),
897 leftnode=hex(leftnode),
893 rightrev=rightrev,
898 rightrev=rightrev,
894 rightnode=hex(rightnode),
899 rightnode=hex(rightnode),
895 comparison=comparison)
900 comparison=comparison)
896
901
897 @webcommand('annotate')
902 @webcommand('annotate')
898 def annotate(web, req, tmpl):
903 def annotate(web, req, tmpl):
899 """
904 """
900 /annotate/{revision}/{path}
905 /annotate/{revision}/{path}
901 ---------------------------
906 ---------------------------
902
907
903 Show changeset information for each line in a file.
908 Show changeset information for each line in a file.
904
909
905 The ``fileannotate`` template is rendered.
910 The ``fileannotate`` template is rendered.
906 """
911 """
907 fctx = webutil.filectx(web.repo, req)
912 fctx = webutil.filectx(web.repo, req)
908 f = fctx.path()
913 f = fctx.path()
909 parity = paritygen(web.stripecount)
914 parity = paritygen(web.stripecount)
910 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
915 diffopts = patch.difffeatureopts(web.repo.ui, untrusted=True,
911 section='annotate', whitespace=True)
916 section='annotate', whitespace=True)
912
917
913 def annotate(**map):
918 def annotate(**map):
914 last = None
919 last = None
915 if util.binary(fctx.data()):
920 if util.binary(fctx.data()):
916 mt = (mimetypes.guess_type(fctx.path())[0]
921 mt = (mimetypes.guess_type(fctx.path())[0]
917 or 'application/octet-stream')
922 or 'application/octet-stream')
918 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
923 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
919 '(binary:%s)' % mt)])
924 '(binary:%s)' % mt)])
920 else:
925 else:
921 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
926 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
922 diffopts=diffopts))
927 diffopts=diffopts))
923 for lineno, ((f, targetline), l) in lines:
928 for lineno, ((f, targetline), l) in lines:
924 fnode = f.filenode()
929 fnode = f.filenode()
925
930
926 if last != fnode:
931 if last != fnode:
927 last = fnode
932 last = fnode
928
933
929 yield {"parity": parity.next(),
934 yield {"parity": parity.next(),
930 "node": f.hex(),
935 "node": f.hex(),
931 "rev": f.rev(),
936 "rev": f.rev(),
932 "author": f.user(),
937 "author": f.user(),
933 "desc": f.description(),
938 "desc": f.description(),
934 "extra": f.extra(),
939 "extra": f.extra(),
935 "file": f.path(),
940 "file": f.path(),
936 "targetline": targetline,
941 "targetline": targetline,
937 "line": l,
942 "line": l,
938 "lineno": lineno + 1,
943 "lineno": lineno + 1,
939 "lineid": "l%d" % (lineno + 1),
944 "lineid": "l%d" % (lineno + 1),
940 "linenumber": "% 6d" % (lineno + 1),
945 "linenumber": "% 6d" % (lineno + 1),
941 "revdate": f.date()}
946 "revdate": f.date()}
942
947
943 return tmpl("fileannotate",
948 return tmpl("fileannotate",
944 file=f,
949 file=f,
945 annotate=annotate,
950 annotate=annotate,
946 path=webutil.up(f),
951 path=webutil.up(f),
947 rev=fctx.rev(),
952 rev=fctx.rev(),
948 symrev=webutil.symrevorshortnode(req, fctx),
953 symrev=webutil.symrevorshortnode(req, fctx),
949 node=fctx.hex(),
954 node=fctx.hex(),
950 author=fctx.user(),
955 author=fctx.user(),
951 date=fctx.date(),
956 date=fctx.date(),
952 desc=fctx.description(),
957 desc=fctx.description(),
953 extra=fctx.extra(),
958 extra=fctx.extra(),
954 rename=webutil.renamelink(fctx),
959 rename=webutil.renamelink(fctx),
955 branch=webutil.nodebranchnodefault(fctx),
960 branch=webutil.nodebranchnodefault(fctx),
956 parent=webutil.parents(fctx),
961 parent=webutil.parents(fctx),
957 child=webutil.children(fctx),
962 child=webutil.children(fctx),
958 tags=webutil.nodetagsdict(web.repo, fctx.node()),
963 tags=webutil.nodetagsdict(web.repo, fctx.node()),
959 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
964 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
960 permissions=fctx.manifest().flags(f))
965 permissions=fctx.manifest().flags(f))
961
966
962 @webcommand('filelog')
967 @webcommand('filelog')
963 def filelog(web, req, tmpl):
968 def filelog(web, req, tmpl):
964 """
969 """
965 /filelog/{revision}/{path}
970 /filelog/{revision}/{path}
966 --------------------------
971 --------------------------
967
972
968 Show information about the history of a file in the repository.
973 Show information about the history of a file in the repository.
969
974
970 The ``revcount`` query string argument can be defined to control the
975 The ``revcount`` query string argument can be defined to control the
971 maximum number of entries to show.
976 maximum number of entries to show.
972
977
973 The ``filelog`` template will be rendered.
978 The ``filelog`` template will be rendered.
974 """
979 """
975
980
976 try:
981 try:
977 fctx = webutil.filectx(web.repo, req)
982 fctx = webutil.filectx(web.repo, req)
978 f = fctx.path()
983 f = fctx.path()
979 fl = fctx.filelog()
984 fl = fctx.filelog()
980 except error.LookupError:
985 except error.LookupError:
981 f = webutil.cleanpath(web.repo, req.form['file'][0])
986 f = webutil.cleanpath(web.repo, req.form['file'][0])
982 fl = web.repo.file(f)
987 fl = web.repo.file(f)
983 numrevs = len(fl)
988 numrevs = len(fl)
984 if not numrevs: # file doesn't exist at all
989 if not numrevs: # file doesn't exist at all
985 raise
990 raise
986 rev = webutil.changectx(web.repo, req).rev()
991 rev = webutil.changectx(web.repo, req).rev()
987 first = fl.linkrev(0)
992 first = fl.linkrev(0)
988 if rev < first: # current rev is from before file existed
993 if rev < first: # current rev is from before file existed
989 raise
994 raise
990 frev = numrevs - 1
995 frev = numrevs - 1
991 while fl.linkrev(frev) > rev:
996 while fl.linkrev(frev) > rev:
992 frev -= 1
997 frev -= 1
993 fctx = web.repo.filectx(f, fl.linkrev(frev))
998 fctx = web.repo.filectx(f, fl.linkrev(frev))
994
999
995 revcount = web.maxshortchanges
1000 revcount = web.maxshortchanges
996 if 'revcount' in req.form:
1001 if 'revcount' in req.form:
997 try:
1002 try:
998 revcount = int(req.form.get('revcount', [revcount])[0])
1003 revcount = int(req.form.get('revcount', [revcount])[0])
999 revcount = max(revcount, 1)
1004 revcount = max(revcount, 1)
1000 tmpl.defaults['sessionvars']['revcount'] = revcount
1005 tmpl.defaults['sessionvars']['revcount'] = revcount
1001 except ValueError:
1006 except ValueError:
1002 pass
1007 pass
1003
1008
1004 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1009 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1005 lessvars['revcount'] = max(revcount / 2, 1)
1010 lessvars['revcount'] = max(revcount / 2, 1)
1006 morevars = copy.copy(tmpl.defaults['sessionvars'])
1011 morevars = copy.copy(tmpl.defaults['sessionvars'])
1007 morevars['revcount'] = revcount * 2
1012 morevars['revcount'] = revcount * 2
1008
1013
1009 count = fctx.filerev() + 1
1014 count = fctx.filerev() + 1
1010 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
1015 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
1011 end = min(count, start + revcount) # last rev on this page
1016 end = min(count, start + revcount) # last rev on this page
1012 parity = paritygen(web.stripecount, offset=start - end)
1017 parity = paritygen(web.stripecount, offset=start - end)
1013
1018
1014 def entries():
1019 def entries():
1015 l = []
1020 l = []
1016
1021
1017 repo = web.repo
1022 repo = web.repo
1018 revs = fctx.filelog().revs(start, end - 1)
1023 revs = fctx.filelog().revs(start, end - 1)
1019 for i in revs:
1024 for i in revs:
1020 iterfctx = fctx.filectx(i)
1025 iterfctx = fctx.filectx(i)
1021
1026
1022 l.append({"parity": parity.next(),
1027 l.append({"parity": parity.next(),
1023 "filerev": i,
1028 "filerev": i,
1024 "file": f,
1029 "file": f,
1025 "node": iterfctx.hex(),
1030 "node": iterfctx.hex(),
1026 "author": iterfctx.user(),
1031 "author": iterfctx.user(),
1027 "date": iterfctx.date(),
1032 "date": iterfctx.date(),
1028 "rename": webutil.renamelink(iterfctx),
1033 "rename": webutil.renamelink(iterfctx),
1029 "parent": lambda **x: webutil.parents(iterfctx),
1034 "parent": lambda **x: webutil.parents(iterfctx),
1030 "child": lambda **x: webutil.children(iterfctx),
1035 "child": lambda **x: webutil.children(iterfctx),
1031 "desc": iterfctx.description(),
1036 "desc": iterfctx.description(),
1032 "extra": iterfctx.extra(),
1037 "extra": iterfctx.extra(),
1033 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
1038 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
1034 "bookmarks": webutil.nodebookmarksdict(
1039 "bookmarks": webutil.nodebookmarksdict(
1035 repo, iterfctx.node()),
1040 repo, iterfctx.node()),
1036 "branch": webutil.nodebranchnodefault(iterfctx),
1041 "branch": webutil.nodebranchnodefault(iterfctx),
1037 "inbranch": webutil.nodeinbranch(repo, iterfctx),
1042 "inbranch": webutil.nodeinbranch(repo, iterfctx),
1038 "branches": webutil.nodebranchdict(repo, iterfctx)})
1043 "branches": webutil.nodebranchdict(repo, iterfctx)})
1039 for e in reversed(l):
1044 for e in reversed(l):
1040 yield e
1045 yield e
1041
1046
1042 entries = list(entries())
1047 entries = list(entries())
1043 latestentry = entries[:1]
1048 latestentry = entries[:1]
1044
1049
1045 revnav = webutil.filerevnav(web.repo, fctx.path())
1050 revnav = webutil.filerevnav(web.repo, fctx.path())
1046 nav = revnav.gen(end - 1, revcount, count)
1051 nav = revnav.gen(end - 1, revcount, count)
1047 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
1052 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
1048 rev=fctx.rev(),
1053 rev=fctx.rev(),
1049 symrev=webutil.symrevorshortnode(req, fctx),
1054 symrev=webutil.symrevorshortnode(req, fctx),
1050 branch=webutil.nodebranchnodefault(fctx),
1055 branch=webutil.nodebranchnodefault(fctx),
1051 tags=webutil.nodetagsdict(web.repo, fctx.node()),
1056 tags=webutil.nodetagsdict(web.repo, fctx.node()),
1052 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
1057 bookmarks=webutil.nodebookmarksdict(web.repo, fctx.node()),
1053 entries=entries,
1058 entries=entries,
1054 latestentry=latestentry,
1059 latestentry=latestentry,
1055 revcount=revcount, morevars=morevars, lessvars=lessvars)
1060 revcount=revcount, morevars=morevars, lessvars=lessvars)
1056
1061
1057 @webcommand('archive')
1062 @webcommand('archive')
1058 def archive(web, req, tmpl):
1063 def archive(web, req, tmpl):
1059 """
1064 """
1060 /archive/{revision}.{format}[/{path}]
1065 /archive/{revision}.{format}[/{path}]
1061 -------------------------------------
1066 -------------------------------------
1062
1067
1063 Obtain an archive of repository content.
1068 Obtain an archive of repository content.
1064
1069
1065 The content and type of the archive is defined by a URL path parameter.
1070 The content and type of the archive is defined by a URL path parameter.
1066 ``format`` is the file extension of the archive type to be generated. e.g.
1071 ``format`` is the file extension of the archive type to be generated. e.g.
1067 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1072 ``zip`` or ``tar.bz2``. Not all archive types may be allowed by your
1068 server configuration.
1073 server configuration.
1069
1074
1070 The optional ``path`` URL parameter controls content to include in the
1075 The optional ``path`` URL parameter controls content to include in the
1071 archive. If omitted, every file in the specified revision is present in the
1076 archive. If omitted, every file in the specified revision is present in the
1072 archive. If included, only the specified file or contents of the specified
1077 archive. If included, only the specified file or contents of the specified
1073 directory will be included in the archive.
1078 directory will be included in the archive.
1074
1079
1075 No template is used for this handler. Raw, binary content is generated.
1080 No template is used for this handler. Raw, binary content is generated.
1076 """
1081 """
1077
1082
1078 type_ = req.form.get('type', [None])[0]
1083 type_ = req.form.get('type', [None])[0]
1079 allowed = web.configlist("web", "allow_archive")
1084 allowed = web.configlist("web", "allow_archive")
1080 key = req.form['node'][0]
1085 key = req.form['node'][0]
1081
1086
1082 if type_ not in web.archives:
1087 if type_ not in web.archives:
1083 msg = 'Unsupported archive type: %s' % type_
1088 msg = 'Unsupported archive type: %s' % type_
1084 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1089 raise ErrorResponse(HTTP_NOT_FOUND, msg)
1085
1090
1086 if not ((type_ in allowed or
1091 if not ((type_ in allowed or
1087 web.configbool("web", "allow" + type_, False))):
1092 web.configbool("web", "allow" + type_, False))):
1088 msg = 'Archive type not allowed: %s' % type_
1093 msg = 'Archive type not allowed: %s' % type_
1089 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1094 raise ErrorResponse(HTTP_FORBIDDEN, msg)
1090
1095
1091 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1096 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
1092 cnode = web.repo.lookup(key)
1097 cnode = web.repo.lookup(key)
1093 arch_version = key
1098 arch_version = key
1094 if cnode == key or key == 'tip':
1099 if cnode == key or key == 'tip':
1095 arch_version = short(cnode)
1100 arch_version = short(cnode)
1096 name = "%s-%s" % (reponame, arch_version)
1101 name = "%s-%s" % (reponame, arch_version)
1097
1102
1098 ctx = webutil.changectx(web.repo, req)
1103 ctx = webutil.changectx(web.repo, req)
1099 pats = []
1104 pats = []
1100 matchfn = scmutil.match(ctx, [])
1105 matchfn = scmutil.match(ctx, [])
1101 file = req.form.get('file', None)
1106 file = req.form.get('file', None)
1102 if file:
1107 if file:
1103 pats = ['path:' + file[0]]
1108 pats = ['path:' + file[0]]
1104 matchfn = scmutil.match(ctx, pats, default='path')
1109 matchfn = scmutil.match(ctx, pats, default='path')
1105 if pats:
1110 if pats:
1106 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1111 files = [f for f in ctx.manifest().keys() if matchfn(f)]
1107 if not files:
1112 if not files:
1108 raise ErrorResponse(HTTP_NOT_FOUND,
1113 raise ErrorResponse(HTTP_NOT_FOUND,
1109 'file(s) not found: %s' % file[0])
1114 'file(s) not found: %s' % file[0])
1110
1115
1111 mimetype, artype, extension, encoding = web.archivespecs[type_]
1116 mimetype, artype, extension, encoding = web.archivespecs[type_]
1112 headers = [
1117 headers = [
1113 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1118 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
1114 ]
1119 ]
1115 if encoding:
1120 if encoding:
1116 headers.append(('Content-Encoding', encoding))
1121 headers.append(('Content-Encoding', encoding))
1117 req.headers.extend(headers)
1122 req.headers.extend(headers)
1118 req.respond(HTTP_OK, mimetype)
1123 req.respond(HTTP_OK, mimetype)
1119
1124
1120 archival.archive(web.repo, req, cnode, artype, prefix=name,
1125 archival.archive(web.repo, req, cnode, artype, prefix=name,
1121 matchfn=matchfn,
1126 matchfn=matchfn,
1122 subrepos=web.configbool("web", "archivesubrepos"))
1127 subrepos=web.configbool("web", "archivesubrepos"))
1123 return []
1128 return []
1124
1129
1125
1130
1126 @webcommand('static')
1131 @webcommand('static')
1127 def static(web, req, tmpl):
1132 def static(web, req, tmpl):
1128 fname = req.form['file'][0]
1133 fname = req.form['file'][0]
1129 # a repo owner may set web.static in .hg/hgrc to get any file
1134 # a repo owner may set web.static in .hg/hgrc to get any file
1130 # readable by the user running the CGI script
1135 # readable by the user running the CGI script
1131 static = web.config("web", "static", None, untrusted=False)
1136 static = web.config("web", "static", None, untrusted=False)
1132 if not static:
1137 if not static:
1133 tp = web.templatepath or templater.templatepaths()
1138 tp = web.templatepath or templater.templatepaths()
1134 if isinstance(tp, str):
1139 if isinstance(tp, str):
1135 tp = [tp]
1140 tp = [tp]
1136 static = [os.path.join(p, 'static') for p in tp]
1141 static = [os.path.join(p, 'static') for p in tp]
1137 staticfile(static, fname, req)
1142 staticfile(static, fname, req)
1138 return []
1143 return []
1139
1144
1140 @webcommand('graph')
1145 @webcommand('graph')
1141 def graph(web, req, tmpl):
1146 def graph(web, req, tmpl):
1142 """
1147 """
1143 /graph[/{revision}]
1148 /graph[/{revision}]
1144 -------------------
1149 -------------------
1145
1150
1146 Show information about the graphical topology of the repository.
1151 Show information about the graphical topology of the repository.
1147
1152
1148 Information rendered by this handler can be used to create visual
1153 Information rendered by this handler can be used to create visual
1149 representations of repository topology.
1154 representations of repository topology.
1150
1155
1151 The ``revision`` URL parameter controls the starting changeset.
1156 The ``revision`` URL parameter controls the starting changeset.
1152
1157
1153 The ``revcount`` query string argument can define the number of changesets
1158 The ``revcount`` query string argument can define the number of changesets
1154 to show information for.
1159 to show information for.
1155
1160
1156 This handler will render the ``graph`` template.
1161 This handler will render the ``graph`` template.
1157 """
1162 """
1158
1163
1159 if 'node' in req.form:
1164 if 'node' in req.form:
1160 ctx = webutil.changectx(web.repo, req)
1165 ctx = webutil.changectx(web.repo, req)
1161 symrev = webutil.symrevorshortnode(req, ctx)
1166 symrev = webutil.symrevorshortnode(req, ctx)
1162 else:
1167 else:
1163 ctx = web.repo['tip']
1168 ctx = web.repo['tip']
1164 symrev = 'tip'
1169 symrev = 'tip'
1165 rev = ctx.rev()
1170 rev = ctx.rev()
1166
1171
1167 bg_height = 39
1172 bg_height = 39
1168 revcount = web.maxshortchanges
1173 revcount = web.maxshortchanges
1169 if 'revcount' in req.form:
1174 if 'revcount' in req.form:
1170 try:
1175 try:
1171 revcount = int(req.form.get('revcount', [revcount])[0])
1176 revcount = int(req.form.get('revcount', [revcount])[0])
1172 revcount = max(revcount, 1)
1177 revcount = max(revcount, 1)
1173 tmpl.defaults['sessionvars']['revcount'] = revcount
1178 tmpl.defaults['sessionvars']['revcount'] = revcount
1174 except ValueError:
1179 except ValueError:
1175 pass
1180 pass
1176
1181
1177 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1182 lessvars = copy.copy(tmpl.defaults['sessionvars'])
1178 lessvars['revcount'] = max(revcount / 2, 1)
1183 lessvars['revcount'] = max(revcount / 2, 1)
1179 morevars = copy.copy(tmpl.defaults['sessionvars'])
1184 morevars = copy.copy(tmpl.defaults['sessionvars'])
1180 morevars['revcount'] = revcount * 2
1185 morevars['revcount'] = revcount * 2
1181
1186
1182 count = len(web.repo)
1187 count = len(web.repo)
1183 pos = rev
1188 pos = rev
1184
1189
1185 uprev = min(max(0, count - 1), rev + revcount)
1190 uprev = min(max(0, count - 1), rev + revcount)
1186 downrev = max(0, rev - revcount)
1191 downrev = max(0, rev - revcount)
1187 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1192 changenav = webutil.revnav(web.repo).gen(pos, revcount, count)
1188
1193
1189 tree = []
1194 tree = []
1190 if pos != -1:
1195 if pos != -1:
1191 allrevs = web.repo.changelog.revs(pos, 0)
1196 allrevs = web.repo.changelog.revs(pos, 0)
1192 revs = []
1197 revs = []
1193 for i in allrevs:
1198 for i in allrevs:
1194 revs.append(i)
1199 revs.append(i)
1195 if len(revs) >= revcount:
1200 if len(revs) >= revcount:
1196 break
1201 break
1197
1202
1198 # We have to feed a baseset to dagwalker as it is expecting smartset
1203 # We have to feed a baseset to dagwalker as it is expecting smartset
1199 # object. This does not have a big impact on hgweb performance itself
1204 # object. This does not have a big impact on hgweb performance itself
1200 # since hgweb graphing code is not itself lazy yet.
1205 # since hgweb graphing code is not itself lazy yet.
1201 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1206 dag = graphmod.dagwalker(web.repo, revset.baseset(revs))
1202 # As we said one line above... not lazy.
1207 # As we said one line above... not lazy.
1203 tree = list(graphmod.colored(dag, web.repo))
1208 tree = list(graphmod.colored(dag, web.repo))
1204
1209
1205 def getcolumns(tree):
1210 def getcolumns(tree):
1206 cols = 0
1211 cols = 0
1207 for (id, type, ctx, vtx, edges) in tree:
1212 for (id, type, ctx, vtx, edges) in tree:
1208 if type != graphmod.CHANGESET:
1213 if type != graphmod.CHANGESET:
1209 continue
1214 continue
1210 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1215 cols = max(cols, max([edge[0] for edge in edges] or [0]),
1211 max([edge[1] for edge in edges] or [0]))
1216 max([edge[1] for edge in edges] or [0]))
1212 return cols
1217 return cols
1213
1218
1214 def graphdata(usetuples, **map):
1219 def graphdata(usetuples, **map):
1215 data = []
1220 data = []
1216
1221
1217 row = 0
1222 row = 0
1218 for (id, type, ctx, vtx, edges) in tree:
1223 for (id, type, ctx, vtx, edges) in tree:
1219 if type != graphmod.CHANGESET:
1224 if type != graphmod.CHANGESET:
1220 continue
1225 continue
1221 node = str(ctx)
1226 node = str(ctx)
1222 age = templatefilters.age(ctx.date())
1227 age = templatefilters.age(ctx.date())
1223 desc = templatefilters.firstline(ctx.description())
1228 desc = templatefilters.firstline(ctx.description())
1224 desc = cgi.escape(templatefilters.nonempty(desc))
1229 desc = cgi.escape(templatefilters.nonempty(desc))
1225 user = cgi.escape(templatefilters.person(ctx.user()))
1230 user = cgi.escape(templatefilters.person(ctx.user()))
1226 branch = cgi.escape(ctx.branch())
1231 branch = cgi.escape(ctx.branch())
1227 try:
1232 try:
1228 branchnode = web.repo.branchtip(branch)
1233 branchnode = web.repo.branchtip(branch)
1229 except error.RepoLookupError:
1234 except error.RepoLookupError:
1230 branchnode = None
1235 branchnode = None
1231 branch = branch, branchnode == ctx.node()
1236 branch = branch, branchnode == ctx.node()
1232
1237
1233 if usetuples:
1238 if usetuples:
1234 data.append((node, vtx, edges, desc, user, age, branch,
1239 data.append((node, vtx, edges, desc, user, age, branch,
1235 [cgi.escape(x) for x in ctx.tags()],
1240 [cgi.escape(x) for x in ctx.tags()],
1236 [cgi.escape(x) for x in ctx.bookmarks()]))
1241 [cgi.escape(x) for x in ctx.bookmarks()]))
1237 else:
1242 else:
1238 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1243 edgedata = [{'col': edge[0], 'nextcol': edge[1],
1239 'color': (edge[2] - 1) % 6 + 1,
1244 'color': (edge[2] - 1) % 6 + 1,
1240 'width': edge[3], 'bcolor': edge[4]}
1245 'width': edge[3], 'bcolor': edge[4]}
1241 for edge in edges]
1246 for edge in edges]
1242
1247
1243 data.append(
1248 data.append(
1244 {'node': node,
1249 {'node': node,
1245 'col': vtx[0],
1250 'col': vtx[0],
1246 'color': (vtx[1] - 1) % 6 + 1,
1251 'color': (vtx[1] - 1) % 6 + 1,
1247 'edges': edgedata,
1252 'edges': edgedata,
1248 'row': row,
1253 'row': row,
1249 'nextrow': row + 1,
1254 'nextrow': row + 1,
1250 'desc': desc,
1255 'desc': desc,
1251 'user': user,
1256 'user': user,
1252 'age': age,
1257 'age': age,
1253 'bookmarks': webutil.nodebookmarksdict(
1258 'bookmarks': webutil.nodebookmarksdict(
1254 web.repo, ctx.node()),
1259 web.repo, ctx.node()),
1255 'branches': webutil.nodebranchdict(web.repo, ctx),
1260 'branches': webutil.nodebranchdict(web.repo, ctx),
1256 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1261 'inbranch': webutil.nodeinbranch(web.repo, ctx),
1257 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1262 'tags': webutil.nodetagsdict(web.repo, ctx.node())})
1258
1263
1259 row += 1
1264 row += 1
1260
1265
1261 return data
1266 return data
1262
1267
1263 cols = getcolumns(tree)
1268 cols = getcolumns(tree)
1264 rows = len(tree)
1269 rows = len(tree)
1265 canvasheight = (rows + 1) * bg_height - 27
1270 canvasheight = (rows + 1) * bg_height - 27
1266
1271
1267 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1272 return tmpl('graph', rev=rev, symrev=symrev, revcount=revcount,
1268 uprev=uprev,
1273 uprev=uprev,
1269 lessvars=lessvars, morevars=morevars, downrev=downrev,
1274 lessvars=lessvars, morevars=morevars, downrev=downrev,
1270 cols=cols, rows=rows,
1275 cols=cols, rows=rows,
1271 canvaswidth=(cols + 1) * bg_height,
1276 canvaswidth=(cols + 1) * bg_height,
1272 truecanvasheight=rows * bg_height,
1277 truecanvasheight=rows * bg_height,
1273 canvasheight=canvasheight, bg_height=bg_height,
1278 canvasheight=canvasheight, bg_height=bg_height,
1274 jsdata=lambda **x: graphdata(True, **x),
1279 jsdata=lambda **x: graphdata(True, **x),
1275 nodes=lambda **x: graphdata(False, **x),
1280 nodes=lambda **x: graphdata(False, **x),
1276 node=ctx.hex(), changenav=changenav)
1281 node=ctx.hex(), changenav=changenav)
1277
1282
1278 def _getdoc(e):
1283 def _getdoc(e):
1279 doc = e[0].__doc__
1284 doc = e[0].__doc__
1280 if doc:
1285 if doc:
1281 doc = _(doc).partition('\n')[0]
1286 doc = _(doc).partition('\n')[0]
1282 else:
1287 else:
1283 doc = _('(no help text available)')
1288 doc = _('(no help text available)')
1284 return doc
1289 return doc
1285
1290
1286 @webcommand('help')
1291 @webcommand('help')
1287 def help(web, req, tmpl):
1292 def help(web, req, tmpl):
1288 """
1293 """
1289 /help[/{topic}]
1294 /help[/{topic}]
1290 ---------------
1295 ---------------
1291
1296
1292 Render help documentation.
1297 Render help documentation.
1293
1298
1294 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1299 This web command is roughly equivalent to :hg:`help`. If a ``topic``
1295 is defined, that help topic will be rendered. If not, an index of
1300 is defined, that help topic will be rendered. If not, an index of
1296 available help topics will be rendered.
1301 available help topics will be rendered.
1297
1302
1298 The ``help`` template will be rendered when requesting help for a topic.
1303 The ``help`` template will be rendered when requesting help for a topic.
1299 ``helptopics`` will be rendered for the index of help topics.
1304 ``helptopics`` will be rendered for the index of help topics.
1300 """
1305 """
1301 from .. import commands, help as helpmod # avoid cycle
1306 from .. import commands, help as helpmod # avoid cycle
1302
1307
1303 topicname = req.form.get('node', [None])[0]
1308 topicname = req.form.get('node', [None])[0]
1304 if not topicname:
1309 if not topicname:
1305 def topics(**map):
1310 def topics(**map):
1306 for entries, summary, _doc in helpmod.helptable:
1311 for entries, summary, _doc in helpmod.helptable:
1307 yield {'topic': entries[0], 'summary': summary}
1312 yield {'topic': entries[0], 'summary': summary}
1308
1313
1309 early, other = [], []
1314 early, other = [], []
1310 primary = lambda s: s.partition('|')[0]
1315 primary = lambda s: s.partition('|')[0]
1311 for c, e in commands.table.iteritems():
1316 for c, e in commands.table.iteritems():
1312 doc = _getdoc(e)
1317 doc = _getdoc(e)
1313 if 'DEPRECATED' in doc or c.startswith('debug'):
1318 if 'DEPRECATED' in doc or c.startswith('debug'):
1314 continue
1319 continue
1315 cmd = primary(c)
1320 cmd = primary(c)
1316 if cmd.startswith('^'):
1321 if cmd.startswith('^'):
1317 early.append((cmd[1:], doc))
1322 early.append((cmd[1:], doc))
1318 else:
1323 else:
1319 other.append((cmd, doc))
1324 other.append((cmd, doc))
1320
1325
1321 early.sort()
1326 early.sort()
1322 other.sort()
1327 other.sort()
1323
1328
1324 def earlycommands(**map):
1329 def earlycommands(**map):
1325 for c, doc in early:
1330 for c, doc in early:
1326 yield {'topic': c, 'summary': doc}
1331 yield {'topic': c, 'summary': doc}
1327
1332
1328 def othercommands(**map):
1333 def othercommands(**map):
1329 for c, doc in other:
1334 for c, doc in other:
1330 yield {'topic': c, 'summary': doc}
1335 yield {'topic': c, 'summary': doc}
1331
1336
1332 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1337 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
1333 othercommands=othercommands, title='Index')
1338 othercommands=othercommands, title='Index')
1334
1339
1335 u = webutil.wsgiui()
1340 u = webutil.wsgiui()
1336 u.verbose = True
1341 u.verbose = True
1337 try:
1342 try:
1338 doc = helpmod.help_(u, topicname)
1343 doc = helpmod.help_(u, topicname)
1339 except error.UnknownCommand:
1344 except error.UnknownCommand:
1340 raise ErrorResponse(HTTP_NOT_FOUND)
1345 raise ErrorResponse(HTTP_NOT_FOUND)
1341 return tmpl('help', topic=topicname, doc=doc)
1346 return tmpl('help', topic=topicname, doc=doc)
1342
1347
1343 # tell hggettext to extract docstrings from these functions:
1348 # tell hggettext to extract docstrings from these functions:
1344 i18nfunctions = commands.values()
1349 i18nfunctions = commands.values()
@@ -1,1168 +1,1168
1 #require serve
1 #require serve
2
2
3 setting up repo
3 setting up repo
4
4
5 $ hg init test
5 $ hg init test
6 $ cd test
6 $ cd test
7 $ echo a > a
7 $ echo a > a
8 $ echo b > b
8 $ echo b > b
9 $ hg ci -Ama
9 $ hg ci -Ama
10 adding a
10 adding a
11 adding b
11 adding b
12
12
13 change permissions for git diffs
13 change permissions for git diffs
14
14
15 $ hg import -q --bypass - <<EOF
15 $ hg import -q --bypass - <<EOF
16 > # HG changeset patch
16 > # HG changeset patch
17 > # User test
17 > # User test
18 > # Date 0 0
18 > # Date 0 0
19 > b
19 > b
20 >
20 >
21 > diff --git a/a b/a
21 > diff --git a/a b/a
22 > old mode 100644
22 > old mode 100644
23 > new mode 100755
23 > new mode 100755
24 > diff --git a/b b/b
24 > diff --git a/b b/b
25 > deleted file mode 100644
25 > deleted file mode 100644
26 > --- a/b
26 > --- a/b
27 > +++ /dev/null
27 > +++ /dev/null
28 > @@ -1,1 +0,0 @@
28 > @@ -1,1 +0,0 @@
29 > -b
29 > -b
30 > EOF
30 > EOF
31
31
32 set up hgweb
32 set up hgweb
33
33
34 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
34 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
35 $ cat hg.pid >> $DAEMON_PIDS
35 $ cat hg.pid >> $DAEMON_PIDS
36
36
37 revision
37 revision
38
38
39 $ get-with-headers.py localhost:$HGPORT 'rev/0'
39 $ get-with-headers.py localhost:$HGPORT 'rev/0'
40 200 Script output follows
40 200 Script output follows
41
41
42 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
42 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
43 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
43 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
44 <head>
44 <head>
45 <link rel="icon" href="/static/hgicon.png" type="image/png" />
45 <link rel="icon" href="/static/hgicon.png" type="image/png" />
46 <meta name="robots" content="index, nofollow" />
46 <meta name="robots" content="index, nofollow" />
47 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
47 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
48 <script type="text/javascript" src="/static/mercurial.js"></script>
48 <script type="text/javascript" src="/static/mercurial.js"></script>
49
49
50 <title>test: 0cd96de13884</title>
50 <title>test: 0cd96de13884</title>
51 </head>
51 </head>
52 <body>
52 <body>
53 <div class="container">
53 <div class="container">
54 <div class="menu">
54 <div class="menu">
55 <div class="logo">
55 <div class="logo">
56 <a href="https://mercurial-scm.org/">
56 <a href="https://mercurial-scm.org/">
57 <img src="/static/hglogo.png" alt="mercurial" /></a>
57 <img src="/static/hglogo.png" alt="mercurial" /></a>
58 </div>
58 </div>
59 <ul>
59 <ul>
60 <li><a href="/shortlog/0">log</a></li>
60 <li><a href="/shortlog/0">log</a></li>
61 <li><a href="/graph/0">graph</a></li>
61 <li><a href="/graph/0">graph</a></li>
62 <li><a href="/tags">tags</a></li>
62 <li><a href="/tags">tags</a></li>
63 <li><a href="/bookmarks">bookmarks</a></li>
63 <li><a href="/bookmarks">bookmarks</a></li>
64 <li><a href="/branches">branches</a></li>
64 <li><a href="/branches">branches</a></li>
65 </ul>
65 </ul>
66 <ul>
66 <ul>
67 <li class="active">changeset</li>
67 <li class="active">changeset</li>
68 <li><a href="/raw-rev/0">raw</a></li>
68 <li><a href="/raw-rev/0">raw</a></li>
69 <li><a href="/file/0">browse</a></li>
69 <li><a href="/file/0">browse</a></li>
70 </ul>
70 </ul>
71 <ul>
71 <ul>
72
72
73 </ul>
73 </ul>
74 <ul>
74 <ul>
75 <li><a href="/help">help</a></li>
75 <li><a href="/help">help</a></li>
76 </ul>
76 </ul>
77 </div>
77 </div>
78
78
79 <div class="main">
79 <div class="main">
80
80
81 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
81 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
82 <h3>
82 <h3>
83 changeset 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
83 changeset 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
84
84
85 </h3>
85 </h3>
86
86
87 <form class="search" action="/log">
87 <form class="search" action="/log">
88
88
89 <p><input name="rev" id="search1" type="text" size="30" /></p>
89 <p><input name="rev" id="search1" type="text" size="30" /></p>
90 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
90 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
91 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
91 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
92 </form>
92 </form>
93
93
94 <div class="description">a</div>
94 <div class="description">a</div>
95
95
96 <table id="changesetEntry">
96 <table id="changesetEntry">
97 <tr>
97 <tr>
98 <th class="author">author</th>
98 <th class="author">author</th>
99 <td class="author">&#116;&#101;&#115;&#116;</td>
99 <td class="author">&#116;&#101;&#115;&#116;</td>
100 </tr>
100 </tr>
101 <tr>
101 <tr>
102 <th class="date">date</th>
102 <th class="date">date</th>
103 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
103 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
104 </tr>
104 </tr>
105 <tr>
105 <tr>
106 <th class="author">parents</th>
106 <th class="author">parents</th>
107 <td class="author"></td>
107 <td class="author"></td>
108 </tr>
108 </tr>
109 <tr>
109 <tr>
110 <th class="author">children</th>
110 <th class="author">children</th>
111 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
111 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
112 </tr>
112 </tr>
113 <tr>
113 <tr>
114 <th class="files">files</th>
114 <th class="files">files</th>
115 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
115 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
116 </tr>
116 </tr>
117 <tr>
117 <tr>
118 <th class="diffstat">diffstat</th>
118 <th class="diffstat">diffstat</th>
119 <td class="diffstat">
119 <td class="diffstat">
120 2 files changed, 2 insertions(+), 0 deletions(-)
120 2 files changed, 2 insertions(+), 0 deletions(-)
121
121
122 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
122 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
123 <div id="diffstatdetails" style="display:none;">
123 <div id="diffstatdetails" style="display:none;">
124 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
124 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
125 <table class="diffstat-table stripes2"> <tr>
125 <table class="diffstat-table stripes2"> <tr>
126 <td class="diffstat-file"><a href="#l1.1">a</a></td>
126 <td class="diffstat-file"><a href="#l1.1">a</a></td>
127 <td class="diffstat-total" align="right">1</td>
127 <td class="diffstat-total" align="right">1</td>
128 <td class="diffstat-graph">
128 <td class="diffstat-graph">
129 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
129 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
130 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
130 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
131 </td>
131 </td>
132 </tr>
132 </tr>
133 <tr>
133 <tr>
134 <td class="diffstat-file"><a href="#l2.1">b</a></td>
134 <td class="diffstat-file"><a href="#l2.1">b</a></td>
135 <td class="diffstat-total" align="right">1</td>
135 <td class="diffstat-total" align="right">1</td>
136 <td class="diffstat-graph">
136 <td class="diffstat-graph">
137 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
137 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
138 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
138 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
139 </td>
139 </td>
140 </tr>
140 </tr>
141 </table>
141 </table>
142 </div>
142 </div>
143 </td>
143 </td>
144 </tr>
144 </tr>
145 </table>
145 </table>
146
146
147 <div class="overflow">
147 <div class="overflow">
148 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
148 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
149 <div class="sourcefirst"> line diff</div>
149 <div class="sourcefirst"> line diff</div>
150 <div class="stripes2 diffblocks">
150 <div class="stripes2 diffblocks">
151 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
151 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
152 <span id="l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
152 <span id="l1.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
153 <span id="l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
153 <span id="l1.2" class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
154 <span id="l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.3"></a>
154 <span id="l1.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.3"></a>
155 <span id="l1.4" class="plusline">+a</span><a href="#l1.4"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
155 <span id="l1.4" class="plusline">+a</span><a href="#l1.4"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
156 <span id="l2.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.1"></a>
156 <span id="l2.1" class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.1"></a>
157 <span id="l2.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.2"></a>
157 <span id="l2.2" class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l2.2"></a>
158 <span id="l2.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.3"></a>
158 <span id="l2.3" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.3"></a>
159 <span id="l2.4" class="plusline">+b</span><a href="#l2.4"></a></pre></div>
159 <span id="l2.4" class="plusline">+b</span><a href="#l2.4"></a></pre></div>
160 </div>
160 </div>
161 </div>
161 </div>
162
162
163 </div>
163 </div>
164 </div>
164 </div>
165 <script type="text/javascript">process_dates()</script>
165 <script type="text/javascript">process_dates()</script>
166
166
167
167
168 </body>
168 </body>
169 </html>
169 </html>
170
170
171
171
172 raw revision
172 raw revision
173
173
174 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
174 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
175 200 Script output follows
175 200 Script output follows
176
176
177
177
178 # HG changeset patch
178 # HG changeset patch
179 # User test
179 # User test
180 # Date 0 0
180 # Date 0 0
181 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
181 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
182
182
183 a
183 a
184
184
185 diff -r 000000000000 -r 0cd96de13884 a
185 diff -r 000000000000 -r 0cd96de13884 a
186 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
186 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187 +++ b/a Thu Jan 01 00:00:00 1970 +0000
187 +++ b/a Thu Jan 01 00:00:00 1970 +0000
188 @@ -0,0 +1,1 @@
188 @@ -0,0 +1,1 @@
189 +a
189 +a
190 diff -r 000000000000 -r 0cd96de13884 b
190 diff -r 000000000000 -r 0cd96de13884 b
191 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
191 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
192 +++ b/b Thu Jan 01 00:00:00 1970 +0000
192 +++ b/b Thu Jan 01 00:00:00 1970 +0000
193 @@ -0,0 +1,1 @@
193 @@ -0,0 +1,1 @@
194 +b
194 +b
195
195
196
196
197 diff removed file
197 diff removed file
198
198
199 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
199 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
200 a
200 a
201 b
201 b
202 $ hg parents --template "{node|short}\n" -r tip
202 $ hg parents --template "{node|short}\n" -r tip
203 0cd96de13884
203 0cd96de13884
204 $ hg parents --template "{node|short}\n" -r tip b
204 $ hg parents --template "{node|short}\n" -r tip b
205 0cd96de13884
205 0cd96de13884
206
206
207 $ get-with-headers.py localhost:$HGPORT 'diff/tip/b'
207 $ get-with-headers.py localhost:$HGPORT 'diff/tip/b'
208 200 Script output follows
208 200 Script output follows
209
209
210 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
210 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
211 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
211 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
212 <head>
212 <head>
213 <link rel="icon" href="/static/hgicon.png" type="image/png" />
213 <link rel="icon" href="/static/hgicon.png" type="image/png" />
214 <meta name="robots" content="index, nofollow" />
214 <meta name="robots" content="index, nofollow" />
215 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
215 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
216 <script type="text/javascript" src="/static/mercurial.js"></script>
216 <script type="text/javascript" src="/static/mercurial.js"></script>
217
217
218 <title>test: b diff</title>
218 <title>test: b diff</title>
219 </head>
219 </head>
220 <body>
220 <body>
221
221
222 <div class="container">
222 <div class="container">
223 <div class="menu">
223 <div class="menu">
224 <div class="logo">
224 <div class="logo">
225 <a href="https://mercurial-scm.org/">
225 <a href="https://mercurial-scm.org/">
226 <img src="/static/hglogo.png" alt="mercurial" /></a>
226 <img src="/static/hglogo.png" alt="mercurial" /></a>
227 </div>
227 </div>
228 <ul>
228 <ul>
229 <li><a href="/shortlog/tip">log</a></li>
229 <li><a href="/shortlog/tip">log</a></li>
230 <li><a href="/graph/tip">graph</a></li>
230 <li><a href="/graph/tip">graph</a></li>
231 <li><a href="/tags">tags</a></li>
231 <li><a href="/tags">tags</a></li>
232 <li><a href="/bookmarks">bookmarks</a></li>
232 <li><a href="/bookmarks">bookmarks</a></li>
233 <li><a href="/branches">branches</a></li>
233 <li><a href="/branches">branches</a></li>
234 </ul>
234 </ul>
235 <ul>
235 <ul>
236 <li><a href="/rev/tip">changeset</a></li>
236 <li><a href="/rev/tip">changeset</a></li>
237 <li><a href="/file/tip">browse</a></li>
237 <li><a href="/file/tip">browse</a></li>
238 </ul>
238 </ul>
239 <ul>
239 <ul>
240 <li><a href="/file/tip/b">file</a></li>
240 <li><a href="/file/tip/b">file</a></li>
241 <li><a href="/file/tip/b">latest</a></li>
241 <li><a href="/file/tip/b">latest</a></li>
242 <li class="active">diff</li>
242 <li class="active">diff</li>
243 <li><a href="/comparison/tip/b">comparison</a></li>
243 <li><a href="/comparison/tip/b">comparison</a></li>
244 <li><a href="/annotate/tip/b">annotate</a></li>
244 <li><a href="/annotate/tip/b">annotate</a></li>
245 <li><a href="/log/tip/b">file log</a></li>
245 <li><a href="/log/tip/b">file log</a></li>
246 <li><a href="/raw-file/tip/b">raw</a></li>
246 <li><a href="/raw-file/tip/b">raw</a></li>
247 </ul>
247 </ul>
248 <ul>
248 <ul>
249 <li><a href="/help">help</a></li>
249 <li><a href="/help">help</a></li>
250 </ul>
250 </ul>
251 </div>
251 </div>
252
252
253 <div class="main">
253 <div class="main">
254 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
254 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
255 <h3>
255 <h3>
256 diff b @ 1:<a href="/rev/559edbd9ed20">559edbd9ed20</a>
256 diff b @ 1:<a href="/rev/559edbd9ed20">559edbd9ed20</a>
257 <span class="tag">tip</span>
257 <span class="tag">tip</span>
258 </h3>
258 </h3>
259
259
260 <form class="search" action="/log">
260 <form class="search" action="/log">
261 <p></p>
261 <p></p>
262 <p><input name="rev" id="search1" type="text" size="30" /></p>
262 <p><input name="rev" id="search1" type="text" size="30" /></p>
263 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
263 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
264 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
264 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
265 </form>
265 </form>
266
266
267 <div class="description">b</div>
267 <div class="description">b</div>
268
268
269 <table id="changesetEntry">
269 <table id="changesetEntry">
270 <tr>
270 <tr>
271 <th>author</th>
271 <th>author</th>
272 <td>&#116;&#101;&#115;&#116;</td>
272 <td>&#116;&#101;&#115;&#116;</td>
273 </tr>
273 </tr>
274 <tr>
274 <tr>
275 <th>date</th>
275 <th>date</th>
276 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
276 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
277 </tr>
277 </tr>
278 <tr>
278 <tr>
279 <th>parents</th>
279 <th>parents</th>
280 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
280 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
281 </tr>
281 </tr>
282 <tr>
282 <tr>
283 <th>children</th>
283 <th>children</th>
284 <td></td>
284 <td></td>
285 </tr>
285 </tr>
286 </table>
286 </table>
287
287
288 <div class="overflow">
288 <div class="overflow">
289 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
289 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
290 <div class="sourcefirst"> line diff</div>
290 <div class="sourcefirst"> line diff</div>
291 <div class="stripes2 diffblocks">
291 <div class="stripes2 diffblocks">
292 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
292 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
293 <span id="l1.1" class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
293 <span id="l1.1" class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.1"></a>
294 <span id="l1.2" class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
294 <span id="l1.2" class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000</span><a href="#l1.2"></a>
295 <span id="l1.3" class="atline">@@ -1,1 +0,0 @@</span><a href="#l1.3"></a>
295 <span id="l1.3" class="atline">@@ -1,1 +0,0 @@</span><a href="#l1.3"></a>
296 <span id="l1.4" class="minusline">-b</span><a href="#l1.4"></a></pre></div>
296 <span id="l1.4" class="minusline">-b</span><a href="#l1.4"></a></pre></div>
297 </div>
297 </div>
298 </div>
298 </div>
299 </div>
299 </div>
300 </div>
300 </div>
301
301
302 <script type="text/javascript">process_dates()</script>
302 <script type="text/javascript">process_dates()</script>
303
303
304
304
305 </body>
305 </body>
306 </html>
306 </html>
307
307
308
308
309 set up hgweb with git diffs
309 set up hgweb with git diffs
310
310
311 $ killdaemons.py
311 $ killdaemons.py
312 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
312 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
313 $ cat hg.pid >> $DAEMON_PIDS
313 $ cat hg.pid >> $DAEMON_PIDS
314
314
315 revision
315 revision
316
316
317 $ get-with-headers.py localhost:$HGPORT 'rev/0'
317 $ get-with-headers.py localhost:$HGPORT 'rev/0'
318 200 Script output follows
318 200 Script output follows
319
319
320 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
320 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
321 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
321 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
322 <head>
322 <head>
323 <link rel="icon" href="/static/hgicon.png" type="image/png" />
323 <link rel="icon" href="/static/hgicon.png" type="image/png" />
324 <meta name="robots" content="index, nofollow" />
324 <meta name="robots" content="index, nofollow" />
325 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
325 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
326 <script type="text/javascript" src="/static/mercurial.js"></script>
326 <script type="text/javascript" src="/static/mercurial.js"></script>
327
327
328 <title>test: 0cd96de13884</title>
328 <title>test: 0cd96de13884</title>
329 </head>
329 </head>
330 <body>
330 <body>
331 <div class="container">
331 <div class="container">
332 <div class="menu">
332 <div class="menu">
333 <div class="logo">
333 <div class="logo">
334 <a href="https://mercurial-scm.org/">
334 <a href="https://mercurial-scm.org/">
335 <img src="/static/hglogo.png" alt="mercurial" /></a>
335 <img src="/static/hglogo.png" alt="mercurial" /></a>
336 </div>
336 </div>
337 <ul>
337 <ul>
338 <li><a href="/shortlog/0">log</a></li>
338 <li><a href="/shortlog/0">log</a></li>
339 <li><a href="/graph/0">graph</a></li>
339 <li><a href="/graph/0">graph</a></li>
340 <li><a href="/tags">tags</a></li>
340 <li><a href="/tags">tags</a></li>
341 <li><a href="/bookmarks">bookmarks</a></li>
341 <li><a href="/bookmarks">bookmarks</a></li>
342 <li><a href="/branches">branches</a></li>
342 <li><a href="/branches">branches</a></li>
343 </ul>
343 </ul>
344 <ul>
344 <ul>
345 <li class="active">changeset</li>
345 <li class="active">changeset</li>
346 <li><a href="/raw-rev/0">raw</a></li>
346 <li><a href="/raw-rev/0">raw</a></li>
347 <li><a href="/file/0">browse</a></li>
347 <li><a href="/file/0">browse</a></li>
348 </ul>
348 </ul>
349 <ul>
349 <ul>
350
350
351 </ul>
351 </ul>
352 <ul>
352 <ul>
353 <li><a href="/help">help</a></li>
353 <li><a href="/help">help</a></li>
354 </ul>
354 </ul>
355 </div>
355 </div>
356
356
357 <div class="main">
357 <div class="main">
358
358
359 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
359 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
360 <h3>
360 <h3>
361 changeset 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
361 changeset 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
362
362
363 </h3>
363 </h3>
364
364
365 <form class="search" action="/log">
365 <form class="search" action="/log">
366
366
367 <p><input name="rev" id="search1" type="text" size="30" /></p>
367 <p><input name="rev" id="search1" type="text" size="30" /></p>
368 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
368 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
369 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
369 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
370 </form>
370 </form>
371
371
372 <div class="description">a</div>
372 <div class="description">a</div>
373
373
374 <table id="changesetEntry">
374 <table id="changesetEntry">
375 <tr>
375 <tr>
376 <th class="author">author</th>
376 <th class="author">author</th>
377 <td class="author">&#116;&#101;&#115;&#116;</td>
377 <td class="author">&#116;&#101;&#115;&#116;</td>
378 </tr>
378 </tr>
379 <tr>
379 <tr>
380 <th class="date">date</th>
380 <th class="date">date</th>
381 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
381 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
382 </tr>
382 </tr>
383 <tr>
383 <tr>
384 <th class="author">parents</th>
384 <th class="author">parents</th>
385 <td class="author"></td>
385 <td class="author"></td>
386 </tr>
386 </tr>
387 <tr>
387 <tr>
388 <th class="author">children</th>
388 <th class="author">children</th>
389 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
389 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
390 </tr>
390 </tr>
391 <tr>
391 <tr>
392 <th class="files">files</th>
392 <th class="files">files</th>
393 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
393 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
394 </tr>
394 </tr>
395 <tr>
395 <tr>
396 <th class="diffstat">diffstat</th>
396 <th class="diffstat">diffstat</th>
397 <td class="diffstat">
397 <td class="diffstat">
398 2 files changed, 2 insertions(+), 0 deletions(-)
398 2 files changed, 2 insertions(+), 0 deletions(-)
399
399
400 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
400 <a id="diffstatexpand" href="javascript:toggleDiffstat()">[<tt>+</tt>]</a>
401 <div id="diffstatdetails" style="display:none;">
401 <div id="diffstatdetails" style="display:none;">
402 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
402 <a href="javascript:toggleDiffstat()">[<tt>-</tt>]</a>
403 <table class="diffstat-table stripes2"> <tr>
403 <table class="diffstat-table stripes2"> <tr>
404 <td class="diffstat-file"><a href="#l1.1">a</a></td>
404 <td class="diffstat-file"><a href="#l1.1">a</a></td>
405 <td class="diffstat-total" align="right">1</td>
405 <td class="diffstat-total" align="right">1</td>
406 <td class="diffstat-graph">
406 <td class="diffstat-graph">
407 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
407 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
408 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
408 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
409 </td>
409 </td>
410 </tr>
410 </tr>
411 <tr>
411 <tr>
412 <td class="diffstat-file"><a href="#l2.1">b</a></td>
412 <td class="diffstat-file"><a href="#l2.1">b</a></td>
413 <td class="diffstat-total" align="right">1</td>
413 <td class="diffstat-total" align="right">1</td>
414 <td class="diffstat-graph">
414 <td class="diffstat-graph">
415 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
415 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
416 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
416 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
417 </td>
417 </td>
418 </tr>
418 </tr>
419 </table>
419 </table>
420 </div>
420 </div>
421 </td>
421 </td>
422 </tr>
422 </tr>
423 </table>
423 </table>
424
424
425 <div class="overflow">
425 <div class="overflow">
426 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
426 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
427 <div class="sourcefirst"> line diff</div>
427 <div class="sourcefirst"> line diff</div>
428 <div class="stripes2 diffblocks">
428 <div class="stripes2 diffblocks">
429 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
429 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
430 <span id="l1.1">new file mode 100644</span><a href="#l1.1"></a>
430 <span id="l1.1">new file mode 100644</span><a href="#l1.1"></a>
431 <span id="l1.2" class="minusline">--- /dev/null</span><a href="#l1.2"></a>
431 <span id="l1.2" class="minusline">--- /dev/null</span><a href="#l1.2"></a>
432 <span id="l1.3" class="plusline">+++ b/a</span><a href="#l1.3"></a>
432 <span id="l1.3" class="plusline">+++ b/a</span><a href="#l1.3"></a>
433 <span id="l1.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.4"></a>
433 <span id="l1.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l1.4"></a>
434 <span id="l1.5" class="plusline">+a</span><a href="#l1.5"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
434 <span id="l1.5" class="plusline">+a</span><a href="#l1.5"></a></pre></div><div class="bottomline inc-lineno"><pre class="sourcelines wrap">
435 <span id="l2.1">new file mode 100644</span><a href="#l2.1"></a>
435 <span id="l2.1">new file mode 100644</span><a href="#l2.1"></a>
436 <span id="l2.2" class="minusline">--- /dev/null</span><a href="#l2.2"></a>
436 <span id="l2.2" class="minusline">--- /dev/null</span><a href="#l2.2"></a>
437 <span id="l2.3" class="plusline">+++ b/b</span><a href="#l2.3"></a>
437 <span id="l2.3" class="plusline">+++ b/b</span><a href="#l2.3"></a>
438 <span id="l2.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.4"></a>
438 <span id="l2.4" class="atline">@@ -0,0 +1,1 @@</span><a href="#l2.4"></a>
439 <span id="l2.5" class="plusline">+b</span><a href="#l2.5"></a></pre></div>
439 <span id="l2.5" class="plusline">+b</span><a href="#l2.5"></a></pre></div>
440 </div>
440 </div>
441 </div>
441 </div>
442
442
443 </div>
443 </div>
444 </div>
444 </div>
445 <script type="text/javascript">process_dates()</script>
445 <script type="text/javascript">process_dates()</script>
446
446
447
447
448 </body>
448 </body>
449 </html>
449 </html>
450
450
451
451
452 revision
452 revision
453
453
454 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
454 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
455 200 Script output follows
455 200 Script output follows
456
456
457
457
458 # HG changeset patch
458 # HG changeset patch
459 # User test
459 # User test
460 # Date 0 0
460 # Date 0 0
461 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
461 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
462
462
463 a
463 a
464
464
465 diff --git a/a b/a
465 diff --git a/a b/a
466 new file mode 100644
466 new file mode 100644
467 --- /dev/null
467 --- /dev/null
468 +++ b/a
468 +++ b/a
469 @@ -0,0 +1,1 @@
469 @@ -0,0 +1,1 @@
470 +a
470 +a
471 diff --git a/b b/b
471 diff --git a/b b/b
472 new file mode 100644
472 new file mode 100644
473 --- /dev/null
473 --- /dev/null
474 +++ b/b
474 +++ b/b
475 @@ -0,0 +1,1 @@
475 @@ -0,0 +1,1 @@
476 +b
476 +b
477
477
478
478
479 diff modified file
479 diff modified file
480
480
481 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
481 $ hg log --template "{file_mods}\n{file_dels}\n" -r tip
482 a
482 a
483 b
483 b
484 $ hg parents --template "{node|short}\n" -r tip
484 $ hg parents --template "{node|short}\n" -r tip
485 0cd96de13884
485 0cd96de13884
486 $ hg parents --template "{node|short}\n" -r tip a
486 $ hg parents --template "{node|short}\n" -r tip a
487 0cd96de13884
487 0cd96de13884
488
488
489 $ get-with-headers.py localhost:$HGPORT 'diff/tip/a'
489 $ get-with-headers.py localhost:$HGPORT 'diff/tip/a'
490 200 Script output follows
490 200 Script output follows
491
491
492 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
492 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
493 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
493 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
494 <head>
494 <head>
495 <link rel="icon" href="/static/hgicon.png" type="image/png" />
495 <link rel="icon" href="/static/hgicon.png" type="image/png" />
496 <meta name="robots" content="index, nofollow" />
496 <meta name="robots" content="index, nofollow" />
497 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
497 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
498 <script type="text/javascript" src="/static/mercurial.js"></script>
498 <script type="text/javascript" src="/static/mercurial.js"></script>
499
499
500 <title>test: a diff</title>
500 <title>test: a diff</title>
501 </head>
501 </head>
502 <body>
502 <body>
503
503
504 <div class="container">
504 <div class="container">
505 <div class="menu">
505 <div class="menu">
506 <div class="logo">
506 <div class="logo">
507 <a href="https://mercurial-scm.org/">
507 <a href="https://mercurial-scm.org/">
508 <img src="/static/hglogo.png" alt="mercurial" /></a>
508 <img src="/static/hglogo.png" alt="mercurial" /></a>
509 </div>
509 </div>
510 <ul>
510 <ul>
511 <li><a href="/shortlog/tip">log</a></li>
511 <li><a href="/shortlog/tip">log</a></li>
512 <li><a href="/graph/tip">graph</a></li>
512 <li><a href="/graph/tip">graph</a></li>
513 <li><a href="/tags">tags</a></li>
513 <li><a href="/tags">tags</a></li>
514 <li><a href="/bookmarks">bookmarks</a></li>
514 <li><a href="/bookmarks">bookmarks</a></li>
515 <li><a href="/branches">branches</a></li>
515 <li><a href="/branches">branches</a></li>
516 </ul>
516 </ul>
517 <ul>
517 <ul>
518 <li><a href="/rev/tip">changeset</a></li>
518 <li><a href="/rev/tip">changeset</a></li>
519 <li><a href="/file/tip">browse</a></li>
519 <li><a href="/file/tip">browse</a></li>
520 </ul>
520 </ul>
521 <ul>
521 <ul>
522 <li><a href="/file/tip/a">file</a></li>
522 <li><a href="/file/tip/a">file</a></li>
523 <li><a href="/file/tip/a">latest</a></li>
523 <li><a href="/file/tip/a">latest</a></li>
524 <li class="active">diff</li>
524 <li class="active">diff</li>
525 <li><a href="/comparison/tip/a">comparison</a></li>
525 <li><a href="/comparison/tip/a">comparison</a></li>
526 <li><a href="/annotate/tip/a">annotate</a></li>
526 <li><a href="/annotate/tip/a">annotate</a></li>
527 <li><a href="/log/tip/a">file log</a></li>
527 <li><a href="/log/tip/a">file log</a></li>
528 <li><a href="/raw-file/tip/a">raw</a></li>
528 <li><a href="/raw-file/tip/a">raw</a></li>
529 </ul>
529 </ul>
530 <ul>
530 <ul>
531 <li><a href="/help">help</a></li>
531 <li><a href="/help">help</a></li>
532 </ul>
532 </ul>
533 </div>
533 </div>
534
534
535 <div class="main">
535 <div class="main">
536 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
536 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
537 <h3>
537 <h3>
538 diff a @ 1:<a href="/rev/559edbd9ed20">559edbd9ed20</a>
538 diff a @ 1:<a href="/rev/559edbd9ed20">559edbd9ed20</a>
539 <span class="tag">tip</span>
539 <span class="tag">tip</span>
540 </h3>
540 </h3>
541
541
542 <form class="search" action="/log">
542 <form class="search" action="/log">
543 <p></p>
543 <p></p>
544 <p><input name="rev" id="search1" type="text" size="30" /></p>
544 <p><input name="rev" id="search1" type="text" size="30" /></p>
545 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
545 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
546 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
546 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
547 </form>
547 </form>
548
548
549 <div class="description">b</div>
549 <div class="description">b</div>
550
550
551 <table id="changesetEntry">
551 <table id="changesetEntry">
552 <tr>
552 <tr>
553 <th>author</th>
553 <th>author</th>
554 <td>&#116;&#101;&#115;&#116;</td>
554 <td>&#116;&#101;&#115;&#116;</td>
555 </tr>
555 </tr>
556 <tr>
556 <tr>
557 <th>date</th>
557 <th>date</th>
558 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
558 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
559 </tr>
559 </tr>
560 <tr>
560 <tr>
561 <th>parents</th>
561 <th>parents</th>
562 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
562 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
563 </tr>
563 </tr>
564 <tr>
564 <tr>
565 <th>children</th>
565 <th>children</th>
566 <td></td>
566 <td></td>
567 </tr>
567 </tr>
568 </table>
568 </table>
569
569
570 <div class="overflow">
570 <div class="overflow">
571 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
571 <div class="sourcefirst linewraptoggle">line wrap: <a class="linewraplink" href="javascript:toggleLinewrap()">on</a></div>
572 <div class="sourcefirst"> line diff</div>
572 <div class="sourcefirst"> line diff</div>
573 <div class="stripes2 diffblocks">
573 <div class="stripes2 diffblocks">
574 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
574 <div class="bottomline inc-lineno"><pre class="sourcelines wrap">
575 <span id="l1.1">old mode 100644</span><a href="#l1.1"></a>
575 <span id="l1.1">old mode 100644</span><a href="#l1.1"></a>
576 <span id="l1.2">new mode 100755</span><a href="#l1.2"></a></pre></div>
576 <span id="l1.2">new mode 100755</span><a href="#l1.2"></a></pre></div>
577 </div>
577 </div>
578 </div>
578 </div>
579 </div>
579 </div>
580 </div>
580 </div>
581
581
582 <script type="text/javascript">process_dates()</script>
582 <script type="text/javascript">process_dates()</script>
583
583
584
584
585 </body>
585 </body>
586 </html>
586 </html>
587
587
588
588
589 comparison new file
589 comparison new file
590
590
591 $ hg parents --template "{rev}:{node|short}\n" -r 0
591 $ hg parents --template "{rev}:{node|short}\n" -r 0
592 $ hg log --template "{rev}:{node|short}\n" -r 0
592 $ hg log --template "{rev}:{node|short}\n" -r 0
593 0:0cd96de13884
593 0:0cd96de13884
594
594
595 $ get-with-headers.py localhost:$HGPORT 'comparison/0/a'
595 $ get-with-headers.py localhost:$HGPORT 'comparison/0/a'
596 200 Script output follows
596 200 Script output follows
597
597
598 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
598 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
599 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
599 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
600 <head>
600 <head>
601 <link rel="icon" href="/static/hgicon.png" type="image/png" />
601 <link rel="icon" href="/static/hgicon.png" type="image/png" />
602 <meta name="robots" content="index, nofollow" />
602 <meta name="robots" content="index, nofollow" />
603 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
603 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
604 <script type="text/javascript" src="/static/mercurial.js"></script>
604 <script type="text/javascript" src="/static/mercurial.js"></script>
605
605
606 <title>test: a comparison</title>
606 <title>test: a comparison</title>
607 </head>
607 </head>
608 <body>
608 <body>
609
609
610 <div class="container">
610 <div class="container">
611 <div class="menu">
611 <div class="menu">
612 <div class="logo">
612 <div class="logo">
613 <a href="https://mercurial-scm.org/">
613 <a href="https://mercurial-scm.org/">
614 <img src="/static/hglogo.png" alt="mercurial" /></a>
614 <img src="/static/hglogo.png" alt="mercurial" /></a>
615 </div>
615 </div>
616 <ul>
616 <ul>
617 <li><a href="/shortlog/0">log</a></li>
617 <li><a href="/shortlog/0">log</a></li>
618 <li><a href="/graph/0">graph</a></li>
618 <li><a href="/graph/0">graph</a></li>
619 <li><a href="/tags">tags</a></li>
619 <li><a href="/tags">tags</a></li>
620 <li><a href="/bookmarks">bookmarks</a></li>
620 <li><a href="/bookmarks">bookmarks</a></li>
621 <li><a href="/branches">branches</a></li>
621 <li><a href="/branches">branches</a></li>
622 </ul>
622 </ul>
623 <ul>
623 <ul>
624 <li><a href="/rev/0">changeset</a></li>
624 <li><a href="/rev/0">changeset</a></li>
625 <li><a href="/file/0">browse</a></li>
625 <li><a href="/file/0">browse</a></li>
626 </ul>
626 </ul>
627 <ul>
627 <ul>
628 <li><a href="/file/0/a">file</a></li>
628 <li><a href="/file/0/a">file</a></li>
629 <li><a href="/file/tip/a">latest</a></li>
629 <li><a href="/file/tip/a">latest</a></li>
630 <li><a href="/diff/0/a">diff</a></li>
630 <li><a href="/diff/0/a">diff</a></li>
631 <li class="active">comparison</li>
631 <li class="active">comparison</li>
632 <li><a href="/annotate/0/a">annotate</a></li>
632 <li><a href="/annotate/0/a">annotate</a></li>
633 <li><a href="/log/0/a">file log</a></li>
633 <li><a href="/log/0/a">file log</a></li>
634 <li><a href="/raw-file/0/a">raw</a></li>
634 <li><a href="/raw-file/0/a">raw</a></li>
635 </ul>
635 </ul>
636 <ul>
636 <ul>
637 <li><a href="/help">help</a></li>
637 <li><a href="/help">help</a></li>
638 </ul>
638 </ul>
639 </div>
639 </div>
640
640
641 <div class="main">
641 <div class="main">
642 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
642 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
643 <h3>
643 <h3>
644 comparison a @ 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
644 comparison a @ 0:<a href="/rev/0cd96de13884">0cd96de13884</a>
645
645
646 </h3>
646 </h3>
647
647
648 <form class="search" action="/log">
648 <form class="search" action="/log">
649 <p></p>
649 <p></p>
650 <p><input name="rev" id="search1" type="text" size="30" /></p>
650 <p><input name="rev" id="search1" type="text" size="30" /></p>
651 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
651 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
652 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
652 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
653 </form>
653 </form>
654
654
655 <div class="description">a</div>
655 <div class="description">a</div>
656
656
657 <table id="changesetEntry">
657 <table id="changesetEntry">
658 <tr>
658 <tr>
659 <th>author</th>
659 <th>author</th>
660 <td>&#116;&#101;&#115;&#116;</td>
660 <td>&#116;&#101;&#115;&#116;</td>
661 </tr>
661 </tr>
662 <tr>
662 <tr>
663 <th>date</th>
663 <th>date</th>
664 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
664 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
665 </tr>
665 </tr>
666 <tr>
666 <tr>
667 <th>parents</th>
667 <th>parents</th>
668 <td></td>
668 <td></td>
669 </tr>
669 </tr>
670 <tr>
670 <tr>
671 <th>children</th>
671 <th>children</th>
672 <td></td>
672 <td></td>
673 </tr>
673 </tr>
674 </table>
674 </table>
675
675
676 <div class="overflow">
676 <div class="overflow">
677 <div class="sourcefirst"> comparison</div>
677 <div class="sourcefirst"> comparison</div>
678 <div class="legend">
678 <div class="legend">
679 <span class="legendinfo equal">equal</span>
679 <span class="legendinfo equal">equal</span>
680 <span class="legendinfo delete">deleted</span>
680 <span class="legendinfo delete">deleted</span>
681 <span class="legendinfo insert">inserted</span>
681 <span class="legendinfo insert">inserted</span>
682 <span class="legendinfo replace">replaced</span>
682 <span class="legendinfo replace">replaced</span>
683 </div>
683 </div>
684
684
685 <table class="bigtable">
685 <table class="bigtable">
686 <thead class="header">
686 <thead class="header">
687 <tr>
687 <tr>
688 <th>-1:000000000000</th>
688 <th>-1:000000000000</th>
689 <th>0:0cd96de13884</th>
689 <th>0:0cd96de13884</th>
690 </tr>
690 </tr>
691 </thead>
691 </thead>
692
692
693 <tbody class="block">
693 <tbody class="block">
694
694
695 <tr id="r1">
695 <tr id="r1">
696 <td class="source insert"><a href="#r1"> </a> </td>
696 <td class="source insert"><a href="#r1"> </a> </td>
697 <td class="source insert"><a href="#r1"> 1</a> a</td>
697 <td class="source insert"><a href="#r1"> 1</a> a</td>
698 </tr>
698 </tr>
699 </tbody>
699 </tbody>
700 </table>
700 </table>
701
701
702 </div>
702 </div>
703 </div>
703 </div>
704 </div>
704 </div>
705
705
706 <script type="text/javascript">process_dates()</script>
706 <script type="text/javascript">process_dates()</script>
707
707
708
708
709 </body>
709 </body>
710 </html>
710 </html>
711
711
712
712
713 comparison existing file
713 comparison existing file
714
714
715 $ hg up
715 $ hg up
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
716 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
717 $ echo a >> a
717 $ echo a >> a
718 $ hg ci -mc
718 $ hg ci -mc
719
719
720 $ hg parents --template "{rev}:{node|short}\n" -r tip
720 $ hg parents --template "{rev}:{node|short}\n" -r tip
721 1:559edbd9ed20
721 1:559edbd9ed20
722 $ hg log --template "{rev}:{node|short}\n" -r tip
722 $ hg log --template "{rev}:{node|short}\n" -r tip
723 2:d73db4d812ff
723 2:d73db4d812ff
724
724
725 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
725 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
726 200 Script output follows
726 200 Script output follows
727
727
728 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
728 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
729 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
729 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
730 <head>
730 <head>
731 <link rel="icon" href="/static/hgicon.png" type="image/png" />
731 <link rel="icon" href="/static/hgicon.png" type="image/png" />
732 <meta name="robots" content="index, nofollow" />
732 <meta name="robots" content="index, nofollow" />
733 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
733 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
734 <script type="text/javascript" src="/static/mercurial.js"></script>
734 <script type="text/javascript" src="/static/mercurial.js"></script>
735
735
736 <title>test: a comparison</title>
736 <title>test: a comparison</title>
737 </head>
737 </head>
738 <body>
738 <body>
739
739
740 <div class="container">
740 <div class="container">
741 <div class="menu">
741 <div class="menu">
742 <div class="logo">
742 <div class="logo">
743 <a href="https://mercurial-scm.org/">
743 <a href="https://mercurial-scm.org/">
744 <img src="/static/hglogo.png" alt="mercurial" /></a>
744 <img src="/static/hglogo.png" alt="mercurial" /></a>
745 </div>
745 </div>
746 <ul>
746 <ul>
747 <li><a href="/shortlog/tip">log</a></li>
747 <li><a href="/shortlog/tip">log</a></li>
748 <li><a href="/graph/tip">graph</a></li>
748 <li><a href="/graph/tip">graph</a></li>
749 <li><a href="/tags">tags</a></li>
749 <li><a href="/tags">tags</a></li>
750 <li><a href="/bookmarks">bookmarks</a></li>
750 <li><a href="/bookmarks">bookmarks</a></li>
751 <li><a href="/branches">branches</a></li>
751 <li><a href="/branches">branches</a></li>
752 </ul>
752 </ul>
753 <ul>
753 <ul>
754 <li><a href="/rev/tip">changeset</a></li>
754 <li><a href="/rev/tip">changeset</a></li>
755 <li><a href="/file/tip">browse</a></li>
755 <li><a href="/file/tip">browse</a></li>
756 </ul>
756 </ul>
757 <ul>
757 <ul>
758 <li><a href="/file/tip/a">file</a></li>
758 <li><a href="/file/tip/a">file</a></li>
759 <li><a href="/file/tip/a">latest</a></li>
759 <li><a href="/file/tip/a">latest</a></li>
760 <li><a href="/diff/tip/a">diff</a></li>
760 <li><a href="/diff/tip/a">diff</a></li>
761 <li class="active">comparison</li>
761 <li class="active">comparison</li>
762 <li><a href="/annotate/tip/a">annotate</a></li>
762 <li><a href="/annotate/tip/a">annotate</a></li>
763 <li><a href="/log/tip/a">file log</a></li>
763 <li><a href="/log/tip/a">file log</a></li>
764 <li><a href="/raw-file/tip/a">raw</a></li>
764 <li><a href="/raw-file/tip/a">raw</a></li>
765 </ul>
765 </ul>
766 <ul>
766 <ul>
767 <li><a href="/help">help</a></li>
767 <li><a href="/help">help</a></li>
768 </ul>
768 </ul>
769 </div>
769 </div>
770
770
771 <div class="main">
771 <div class="main">
772 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
772 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
773 <h3>
773 <h3>
774 comparison a @ 2:<a href="/rev/d73db4d812ff">d73db4d812ff</a>
774 comparison a @ 2:<a href="/rev/d73db4d812ff">d73db4d812ff</a>
775 <span class="tag">tip</span>
775 <span class="tag">tip</span>
776 </h3>
776 </h3>
777
777
778 <form class="search" action="/log">
778 <form class="search" action="/log">
779 <p></p>
779 <p></p>
780 <p><input name="rev" id="search1" type="text" size="30" /></p>
780 <p><input name="rev" id="search1" type="text" size="30" /></p>
781 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
781 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
782 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
782 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
783 </form>
783 </form>
784
784
785 <div class="description">c</div>
785 <div class="description">c</div>
786
786
787 <table id="changesetEntry">
787 <table id="changesetEntry">
788 <tr>
788 <tr>
789 <th>author</th>
789 <th>author</th>
790 <td>&#116;&#101;&#115;&#116;</td>
790 <td>&#116;&#101;&#115;&#116;</td>
791 </tr>
791 </tr>
792 <tr>
792 <tr>
793 <th>date</th>
793 <th>date</th>
794 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
794 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
795 </tr>
795 </tr>
796 <tr>
796 <tr>
797 <th>parents</th>
797 <th>parents</th>
798 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
798 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
799 </tr>
799 </tr>
800 <tr>
800 <tr>
801 <th>children</th>
801 <th>children</th>
802 <td></td>
802 <td></td>
803 </tr>
803 </tr>
804 </table>
804 </table>
805
805
806 <div class="overflow">
806 <div class="overflow">
807 <div class="sourcefirst"> comparison</div>
807 <div class="sourcefirst"> comparison</div>
808 <div class="legend">
808 <div class="legend">
809 <span class="legendinfo equal">equal</span>
809 <span class="legendinfo equal">equal</span>
810 <span class="legendinfo delete">deleted</span>
810 <span class="legendinfo delete">deleted</span>
811 <span class="legendinfo insert">inserted</span>
811 <span class="legendinfo insert">inserted</span>
812 <span class="legendinfo replace">replaced</span>
812 <span class="legendinfo replace">replaced</span>
813 </div>
813 </div>
814
814
815 <table class="bigtable">
815 <table class="bigtable">
816 <thead class="header">
816 <thead class="header">
817 <tr>
817 <tr>
818 <th>1:559edbd9ed20</th>
818 <th>1:559edbd9ed20</th>
819 <th>2:d73db4d812ff</th>
819 <th>2:d73db4d812ff</th>
820 </tr>
820 </tr>
821 </thead>
821 </thead>
822
822
823 <tbody class="block">
823 <tbody class="block">
824
824
825 <tr id="l1r1">
825 <tr id="l1r1">
826 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
826 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
827 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
827 <td class="source equal"><a href="#l1r1"> 1</a> a</td>
828 </tr>
828 </tr>
829 <tr id="r2">
829 <tr id="r2">
830 <td class="source insert"><a href="#r2"> </a> </td>
830 <td class="source insert"><a href="#r2"> </a> </td>
831 <td class="source insert"><a href="#r2"> 2</a> a</td>
831 <td class="source insert"><a href="#r2"> 2</a> a</td>
832 </tr>
832 </tr>
833 </tbody>
833 </tbody>
834 </table>
834 </table>
835
835
836 </div>
836 </div>
837 </div>
837 </div>
838 </div>
838 </div>
839
839
840 <script type="text/javascript">process_dates()</script>
840 <script type="text/javascript">process_dates()</script>
841
841
842
842
843 </body>
843 </body>
844 </html>
844 </html>
845
845
846
846
847 comparison removed file
847 comparison removed file
848
848
849 $ hg rm a
849 $ hg rm a
850 $ hg ci -md
850 $ hg ci -md
851
851
852 $ hg parents --template "{rev}:{node|short}\n" -r tip
852 $ hg parents --template "{rev}:{node|short}\n" -r tip
853 2:d73db4d812ff
853 2:d73db4d812ff
854 $ hg log --template "{rev}:{node|short}\n" -r tip
854 $ hg log --template "{rev}:{node|short}\n" -r tip
855 3:20e80271eb7a
855 3:20e80271eb7a
856
856
857 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
857 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/a'
858 200 Script output follows
858 200 Script output follows
859
859
860 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
860 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
861 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
861 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
862 <head>
862 <head>
863 <link rel="icon" href="/static/hgicon.png" type="image/png" />
863 <link rel="icon" href="/static/hgicon.png" type="image/png" />
864 <meta name="robots" content="index, nofollow" />
864 <meta name="robots" content="index, nofollow" />
865 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
865 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
866 <script type="text/javascript" src="/static/mercurial.js"></script>
866 <script type="text/javascript" src="/static/mercurial.js"></script>
867
867
868 <title>test: a comparison</title>
868 <title>test: a comparison</title>
869 </head>
869 </head>
870 <body>
870 <body>
871
871
872 <div class="container">
872 <div class="container">
873 <div class="menu">
873 <div class="menu">
874 <div class="logo">
874 <div class="logo">
875 <a href="https://mercurial-scm.org/">
875 <a href="https://mercurial-scm.org/">
876 <img src="/static/hglogo.png" alt="mercurial" /></a>
876 <img src="/static/hglogo.png" alt="mercurial" /></a>
877 </div>
877 </div>
878 <ul>
878 <ul>
879 <li><a href="/shortlog/tip">log</a></li>
879 <li><a href="/shortlog/tip">log</a></li>
880 <li><a href="/graph/tip">graph</a></li>
880 <li><a href="/graph/tip">graph</a></li>
881 <li><a href="/tags">tags</a></li>
881 <li><a href="/tags">tags</a></li>
882 <li><a href="/bookmarks">bookmarks</a></li>
882 <li><a href="/bookmarks">bookmarks</a></li>
883 <li><a href="/branches">branches</a></li>
883 <li><a href="/branches">branches</a></li>
884 </ul>
884 </ul>
885 <ul>
885 <ul>
886 <li><a href="/rev/tip">changeset</a></li>
886 <li><a href="/rev/tip">changeset</a></li>
887 <li><a href="/file/tip">browse</a></li>
887 <li><a href="/file/tip">browse</a></li>
888 </ul>
888 </ul>
889 <ul>
889 <ul>
890 <li><a href="/file/tip/a">file</a></li>
890 <li><a href="/file/tip/a">file</a></li>
891 <li><a href="/file/tip/a">latest</a></li>
891 <li><a href="/file/tip/a">latest</a></li>
892 <li><a href="/diff/tip/a">diff</a></li>
892 <li><a href="/diff/tip/a">diff</a></li>
893 <li class="active">comparison</li>
893 <li class="active">comparison</li>
894 <li><a href="/annotate/tip/a">annotate</a></li>
894 <li><a href="/annotate/tip/a">annotate</a></li>
895 <li><a href="/log/tip/a">file log</a></li>
895 <li><a href="/log/tip/a">file log</a></li>
896 <li><a href="/raw-file/tip/a">raw</a></li>
896 <li><a href="/raw-file/tip/a">raw</a></li>
897 </ul>
897 </ul>
898 <ul>
898 <ul>
899 <li><a href="/help">help</a></li>
899 <li><a href="/help">help</a></li>
900 </ul>
900 </ul>
901 </div>
901 </div>
902
902
903 <div class="main">
903 <div class="main">
904 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
904 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
905 <h3>
905 <h3>
906 comparison a @ 3:<a href="/rev/20e80271eb7a">20e80271eb7a</a>
906 comparison a @ 3:<a href="/rev/20e80271eb7a">20e80271eb7a</a>
907 <span class="tag">tip</span>
907 <span class="tag">tip</span>
908 </h3>
908 </h3>
909
909
910 <form class="search" action="/log">
910 <form class="search" action="/log">
911 <p></p>
911 <p></p>
912 <p><input name="rev" id="search1" type="text" size="30" /></p>
912 <p><input name="rev" id="search1" type="text" size="30" /></p>
913 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
913 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
914 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
914 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
915 </form>
915 </form>
916
916
917 <div class="description">d</div>
917 <div class="description">d</div>
918
918
919 <table id="changesetEntry">
919 <table id="changesetEntry">
920 <tr>
920 <tr>
921 <th>author</th>
921 <th>author</th>
922 <td>&#116;&#101;&#115;&#116;</td>
922 <td>&#116;&#101;&#115;&#116;</td>
923 </tr>
923 </tr>
924 <tr>
924 <tr>
925 <th>date</th>
925 <th>date</th>
926 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
926 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
927 </tr>
927 </tr>
928 <tr>
928 <tr>
929 <th>parents</th>
929 <th>parents</th>
930 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
930 <td><a href="/file/d73db4d812ff/a">d73db4d812ff</a> </td>
931 </tr>
931 </tr>
932 <tr>
932 <tr>
933 <th>children</th>
933 <th>children</th>
934 <td></td>
934 <td></td>
935 </tr>
935 </tr>
936 </table>
936 </table>
937
937
938 <div class="overflow">
938 <div class="overflow">
939 <div class="sourcefirst"> comparison</div>
939 <div class="sourcefirst"> comparison</div>
940 <div class="legend">
940 <div class="legend">
941 <span class="legendinfo equal">equal</span>
941 <span class="legendinfo equal">equal</span>
942 <span class="legendinfo delete">deleted</span>
942 <span class="legendinfo delete">deleted</span>
943 <span class="legendinfo insert">inserted</span>
943 <span class="legendinfo insert">inserted</span>
944 <span class="legendinfo replace">replaced</span>
944 <span class="legendinfo replace">replaced</span>
945 </div>
945 </div>
946
946
947 <table class="bigtable">
947 <table class="bigtable">
948 <thead class="header">
948 <thead class="header">
949 <tr>
949 <tr>
950 <th>2:d73db4d812ff</th>
950 <th>2:d73db4d812ff</th>
951 <th>3:20e80271eb7a</th>
951 <th>3:20e80271eb7a</th>
952 </tr>
952 </tr>
953 </thead>
953 </thead>
954
954
955 <tbody class="block">
955 <tbody class="block">
956
956
957 <tr id="l1">
957 <tr id="l1">
958 <td class="source delete"><a href="#l1"> 1</a> a</td>
958 <td class="source delete"><a href="#l1"> 1</a> a</td>
959 <td class="source delete"><a href="#l1"> </a> </td>
959 <td class="source delete"><a href="#l1"> </a> </td>
960 </tr>
960 </tr>
961 <tr id="l2">
961 <tr id="l2">
962 <td class="source delete"><a href="#l2"> 2</a> a</td>
962 <td class="source delete"><a href="#l2"> 2</a> a</td>
963 <td class="source delete"><a href="#l2"> </a> </td>
963 <td class="source delete"><a href="#l2"> </a> </td>
964 </tr>
964 </tr>
965 </tbody>
965 </tbody>
966 </table>
966 </table>
967
967
968 </div>
968 </div>
969 </div>
969 </div>
970 </div>
970 </div>
971
971
972 <script type="text/javascript">process_dates()</script>
972 <script type="text/javascript">process_dates()</script>
973
973
974
974
975 </body>
975 </body>
976 </html>
976 </html>
977
977
978
978
979 comparison not-modified file
979 comparison not-modified file
980
980
981 $ echo e > e
981 $ echo e > e
982 $ hg add e
982 $ hg add e
983 $ hg ci -m e
983 $ hg ci -m e
984 $ echo f > f
984 $ echo f > f
985 $ hg add f
985 $ hg add f
986 $ hg ci -m f
986 $ hg ci -m f
987 $ hg tip --template "{rev}:{node|short}\n"
987 $ hg tip --template "{rev}:{node|short}\n"
988 5:41d9fc4a6ae1
988 5:41d9fc4a6ae1
989 $ hg diff -c tip e
989 $ hg diff -c tip e
990 $ hg parents --template "{rev}:{node|short}\n" -r tip
990 $ hg parents --template "{rev}:{node|short}\n" -r tip
991 4:402bea3b0976
991 4:402bea3b0976
992 $ hg parents --template "{rev}:{node|short}\n" -r tip e
992 $ hg parents --template "{rev}:{node|short}\n" -r tip e
993 4:402bea3b0976
993 4:402bea3b0976
994
994
995 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/e'
995 $ get-with-headers.py localhost:$HGPORT 'comparison/tip/e'
996 200 Script output follows
996 200 Script output follows
997
997
998 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
998 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
999 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
999 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
1000 <head>
1000 <head>
1001 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1001 <link rel="icon" href="/static/hgicon.png" type="image/png" />
1002 <meta name="robots" content="index, nofollow" />
1002 <meta name="robots" content="index, nofollow" />
1003 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1003 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
1004 <script type="text/javascript" src="/static/mercurial.js"></script>
1004 <script type="text/javascript" src="/static/mercurial.js"></script>
1005
1005
1006 <title>test: e comparison</title>
1006 <title>test: e comparison</title>
1007 </head>
1007 </head>
1008 <body>
1008 <body>
1009
1009
1010 <div class="container">
1010 <div class="container">
1011 <div class="menu">
1011 <div class="menu">
1012 <div class="logo">
1012 <div class="logo">
1013 <a href="https://mercurial-scm.org/">
1013 <a href="https://mercurial-scm.org/">
1014 <img src="/static/hglogo.png" alt="mercurial" /></a>
1014 <img src="/static/hglogo.png" alt="mercurial" /></a>
1015 </div>
1015 </div>
1016 <ul>
1016 <ul>
1017 <li><a href="/shortlog/tip">log</a></li>
1017 <li><a href="/shortlog/tip">log</a></li>
1018 <li><a href="/graph/tip">graph</a></li>
1018 <li><a href="/graph/tip">graph</a></li>
1019 <li><a href="/tags">tags</a></li>
1019 <li><a href="/tags">tags</a></li>
1020 <li><a href="/bookmarks">bookmarks</a></li>
1020 <li><a href="/bookmarks">bookmarks</a></li>
1021 <li><a href="/branches">branches</a></li>
1021 <li><a href="/branches">branches</a></li>
1022 </ul>
1022 </ul>
1023 <ul>
1023 <ul>
1024 <li><a href="/rev/tip">changeset</a></li>
1024 <li><a href="/rev/tip">changeset</a></li>
1025 <li><a href="/file/tip">browse</a></li>
1025 <li><a href="/file/tip">browse</a></li>
1026 </ul>
1026 </ul>
1027 <ul>
1027 <ul>
1028 <li><a href="/file/tip/e">file</a></li>
1028 <li><a href="/file/tip/e">file</a></li>
1029 <li><a href="/file/tip/e">latest</a></li>
1029 <li><a href="/file/tip/e">latest</a></li>
1030 <li><a href="/diff/tip/e">diff</a></li>
1030 <li><a href="/diff/tip/e">diff</a></li>
1031 <li class="active">comparison</li>
1031 <li class="active">comparison</li>
1032 <li><a href="/annotate/tip/e">annotate</a></li>
1032 <li><a href="/annotate/tip/e">annotate</a></li>
1033 <li><a href="/log/tip/e">file log</a></li>
1033 <li><a href="/log/tip/e">file log</a></li>
1034 <li><a href="/raw-file/tip/e">raw</a></li>
1034 <li><a href="/raw-file/tip/e">raw</a></li>
1035 </ul>
1035 </ul>
1036 <ul>
1036 <ul>
1037 <li><a href="/help">help</a></li>
1037 <li><a href="/help">help</a></li>
1038 </ul>
1038 </ul>
1039 </div>
1039 </div>
1040
1040
1041 <div class="main">
1041 <div class="main">
1042 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1042 <h2 class="breadcrumb"><a href="/">Mercurial</a> </h2>
1043 <h3>
1043 <h3>
1044 comparison e @ 5:<a href="/rev/41d9fc4a6ae1">41d9fc4a6ae1</a>
1044 comparison e @ 5:<a href="/rev/41d9fc4a6ae1">41d9fc4a6ae1</a>
1045 <span class="tag">tip</span>
1045 <span class="tag">tip</span>
1046 </h3>
1046 </h3>
1047
1047
1048 <form class="search" action="/log">
1048 <form class="search" action="/log">
1049 <p></p>
1049 <p></p>
1050 <p><input name="rev" id="search1" type="text" size="30" /></p>
1050 <p><input name="rev" id="search1" type="text" size="30" /></p>
1051 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1051 <div id="hint">Find changesets by keywords (author, files, the commit message), revision
1052 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1052 number or hash, or <a href="/help/revsets">revset expression</a>.</div>
1053 </form>
1053 </form>
1054
1054
1055 <div class="description">f</div>
1055 <div class="description">f</div>
1056
1056
1057 <table id="changesetEntry">
1057 <table id="changesetEntry">
1058 <tr>
1058 <tr>
1059 <th>author</th>
1059 <th>author</th>
1060 <td>&#116;&#101;&#115;&#116;</td>
1060 <td>&#116;&#101;&#115;&#116;</td>
1061 </tr>
1061 </tr>
1062 <tr>
1062 <tr>
1063 <th>date</th>
1063 <th>date</th>
1064 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1064 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
1065 </tr>
1065 </tr>
1066 <tr>
1066 <tr>
1067 <th>parents</th>
1067 <th>parents</th>
1068 <td><a href="/file/402bea3b0976/e">402bea3b0976</a> </td>
1068 <td><a href="/file/402bea3b0976/e">402bea3b0976</a> </td>
1069 </tr>
1069 </tr>
1070 <tr>
1070 <tr>
1071 <th>children</th>
1071 <th>children</th>
1072 <td></td>
1072 <td></td>
1073 </tr>
1073 </tr>
1074 </table>
1074 </table>
1075
1075
1076 <div class="overflow">
1076 <div class="overflow">
1077 <div class="sourcefirst"> comparison</div>
1077 <div class="sourcefirst"> comparison</div>
1078 <div class="legend">
1078 <div class="legend">
1079 <span class="legendinfo equal">equal</span>
1079 <span class="legendinfo equal">equal</span>
1080 <span class="legendinfo delete">deleted</span>
1080 <span class="legendinfo delete">deleted</span>
1081 <span class="legendinfo insert">inserted</span>
1081 <span class="legendinfo insert">inserted</span>
1082 <span class="legendinfo replace">replaced</span>
1082 <span class="legendinfo replace">replaced</span>
1083 </div>
1083 </div>
1084
1084
1085 <table class="bigtable">
1085 <table class="bigtable">
1086 <thead class="header">
1086 <thead class="header">
1087 <tr>
1087 <tr>
1088 <th>4:402bea3b0976</th>
1088 <th>4:402bea3b0976</th>
1089 <th>5:41d9fc4a6ae1</th>
1089 <th>5:41d9fc4a6ae1</th>
1090 </tr>
1090 </tr>
1091 </thead>
1091 </thead>
1092
1092
1093 </table>
1093 </table>
1094
1094
1095 </div>
1095 </div>
1096 </div>
1096 </div>
1097 </div>
1097 </div>
1098
1098
1099 <script type="text/javascript">process_dates()</script>
1099 <script type="text/javascript">process_dates()</script>
1100
1100
1101
1101
1102 </body>
1102 </body>
1103 </html>
1103 </html>
1104
1104
1105 $ cd ..
1105 $ cd ..
1106
1106
1107 test import rev as raw-rev
1107 test import rev as raw-rev
1108
1108
1109 $ hg clone -r0 test test1
1109 $ hg clone -r0 test test1
1110 adding changesets
1110 adding changesets
1111 adding manifests
1111 adding manifests
1112 adding file changes
1112 adding file changes
1113 added 1 changesets with 2 changes to 2 files
1113 added 1 changesets with 2 changes to 2 files
1114 updating to branch default
1114 updating to branch default
1115 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1115 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1116 $ cd test1
1116 $ cd test1
1117 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
1117 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
1118
1118
1119 raw revision with diff block numbers
1119 raw revision with diff block numbers
1120
1120
1121 $ killdaemons.py
1121 $ killdaemons.py
1122 $ cat <<EOF > .hg/hgrc
1122 $ cat <<EOF > .hg/hgrc
1123 > [web]
1123 > [web]
1124 > templates = rawdiff
1124 > templates = rawdiff
1125 > EOF
1125 > EOF
1126 $ mkdir rawdiff
1126 $ mkdir rawdiff
1127 $ cat <<EOF > rawdiff/map
1127 $ cat <<EOF > rawdiff/map
1128 > mimetype = 'text/plain; charset={encoding}'
1128 > mimetype = 'text/plain; charset={encoding}'
1129 > changeset = '{diff}'
1129 > changeset = '{diff}'
1130 > difflineplus = '{line}'
1130 > difflineplus = '{line}'
1131 > difflineminus = '{line}'
1131 > difflineminus = '{line}'
1132 > difflineat = '{line}'
1132 > difflineat = '{line}'
1133 > diffline = '{line}'
1133 > diffline = '{line}'
1134 > filenodelink = ''
1134 > filenodelink = ''
1135 > filenolink = ''
1135 > filenolink = ''
1136 > fileline = '{line}'
1136 > fileline = '{line}'
1137 > diffblock = 'Block: {blockno}\n{lines}\n'
1137 > diffblock = 'Block: {blockno}\n{lines}\n'
1138 > EOF
1138 > EOF
1139 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1139 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1140 $ cat hg.pid >> $DAEMON_PIDS
1140 $ cat hg.pid >> $DAEMON_PIDS
1141 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
1141 $ get-with-headers.py localhost:$HGPORT 'raw-rev/0'
1142 200 Script output follows
1142 200 Script output follows
1143
1143
1144 Block: 1
1144 Block: 1
1145 diff -r 000000000000 -r 0cd96de13884 a
1145 diff -r 000000000000 -r 0cd96de13884 a
1146 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1146 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1147 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1147 +++ b/a Thu Jan 01 00:00:00 1970 +0000
1148 @@ -0,0 +1,1 @@
1148 @@ -0,0 +1,1 @@
1149 +a
1149 +a
1150
1150
1151 Block: 2
1151 Block: 2
1152 diff -r 000000000000 -r 0cd96de13884 b
1152 diff -r 000000000000 -r 0cd96de13884 b
1153 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1153 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1154 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1154 +++ b/b Thu Jan 01 00:00:00 1970 +0000
1155 @@ -0,0 +1,1 @@
1155 @@ -0,0 +1,1 @@
1156 +b
1156 +b
1157
1157
1158 $ killdaemons.py
1158 $ killdaemons.py
1159 $ rm .hg/hgrc rawdiff/map
1159 $ rm .hg/hgrc rawdiff/map
1160 $ rmdir rawdiff
1160 $ rmdir rawdiff
1161 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1161 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1162 $ cat hg.pid >> $DAEMON_PIDS
1162 $ cat hg.pid >> $DAEMON_PIDS
1163
1163
1164 errors
1164 errors
1165
1165
1166 $ cat ../test/errors.log
1166 $ cat ../test/errors.log
1167
1167
1168 $ cd ..
1168 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now