##// END OF EJS Templates
hgweb: fixes invalid parents / children in comparison...
wujek srujek -
r17303:06217d3c stable
parent child Browse files
Show More
@@ -1,972 +1,972 b''
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 import os, mimetypes, re, cgi, copy
8 import os, mimetypes, re, cgi, copy
9 import webutil
9 import webutil
10 from mercurial import error, encoding, archival, templater, templatefilters
10 from mercurial import error, encoding, archival, templater, templatefilters
11 from mercurial.node import short, hex, nullid
11 from mercurial.node import short, hex, nullid
12 from mercurial.util import binary
12 from mercurial.util import binary
13 from common import paritygen, staticfile, get_contact, ErrorResponse
13 from common import paritygen, staticfile, get_contact, ErrorResponse
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
14 from common import HTTP_OK, HTTP_FORBIDDEN, HTTP_NOT_FOUND
15 from mercurial import graphmod, patch
15 from mercurial import graphmod, patch
16 from mercurial import help as helpmod
16 from mercurial import help as helpmod
17 from mercurial.i18n import _
17 from mercurial.i18n import _
18
18
19 # __all__ is populated with the allowed commands. Be sure to add to it if
19 # __all__ is populated with the allowed commands. Be sure to add to it if
20 # you're adding a new command, or the new command won't work.
20 # you're adding a new command, or the new command won't work.
21
21
22 __all__ = [
22 __all__ = [
23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
23 'log', 'rawfile', 'file', 'changelog', 'shortlog', 'changeset', 'rev',
24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
24 'manifest', 'tags', 'bookmarks', 'branches', 'summary', 'filediff', 'diff',
25 'comparison', 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
25 'comparison', 'annotate', 'filelog', 'archive', 'static', 'graph', 'help',
26 ]
26 ]
27
27
28 def log(web, req, tmpl):
28 def log(web, req, tmpl):
29 if 'file' in req.form and req.form['file'][0]:
29 if 'file' in req.form and req.form['file'][0]:
30 return filelog(web, req, tmpl)
30 return filelog(web, req, tmpl)
31 else:
31 else:
32 return changelog(web, req, tmpl)
32 return changelog(web, req, tmpl)
33
33
34 def rawfile(web, req, tmpl):
34 def rawfile(web, req, tmpl):
35 guessmime = web.configbool('web', 'guessmime', False)
35 guessmime = web.configbool('web', 'guessmime', False)
36
36
37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
37 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
38 if not path:
38 if not path:
39 content = manifest(web, req, tmpl)
39 content = manifest(web, req, tmpl)
40 req.respond(HTTP_OK, web.ctype)
40 req.respond(HTTP_OK, web.ctype)
41 return content
41 return content
42
42
43 try:
43 try:
44 fctx = webutil.filectx(web.repo, req)
44 fctx = webutil.filectx(web.repo, req)
45 except error.LookupError, inst:
45 except error.LookupError, inst:
46 try:
46 try:
47 content = manifest(web, req, tmpl)
47 content = manifest(web, req, tmpl)
48 req.respond(HTTP_OK, web.ctype)
48 req.respond(HTTP_OK, web.ctype)
49 return content
49 return content
50 except ErrorResponse:
50 except ErrorResponse:
51 raise inst
51 raise inst
52
52
53 path = fctx.path()
53 path = fctx.path()
54 text = fctx.data()
54 text = fctx.data()
55 mt = 'application/binary'
55 mt = 'application/binary'
56 if guessmime:
56 if guessmime:
57 mt = mimetypes.guess_type(path)[0]
57 mt = mimetypes.guess_type(path)[0]
58 if mt is None:
58 if mt is None:
59 mt = binary(text) and 'application/binary' or 'text/plain'
59 mt = binary(text) and 'application/binary' or 'text/plain'
60 if mt.startswith('text/'):
60 if mt.startswith('text/'):
61 mt += '; charset="%s"' % encoding.encoding
61 mt += '; charset="%s"' % encoding.encoding
62
62
63 req.respond(HTTP_OK, mt, path, len(text))
63 req.respond(HTTP_OK, mt, path, len(text))
64 return [text]
64 return [text]
65
65
66 def _filerevision(web, tmpl, fctx):
66 def _filerevision(web, tmpl, fctx):
67 f = fctx.path()
67 f = fctx.path()
68 text = fctx.data()
68 text = fctx.data()
69 parity = paritygen(web.stripecount)
69 parity = paritygen(web.stripecount)
70
70
71 if binary(text):
71 if binary(text):
72 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
72 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
73 text = '(binary:%s)' % mt
73 text = '(binary:%s)' % mt
74
74
75 def lines():
75 def lines():
76 for lineno, t in enumerate(text.splitlines(True)):
76 for lineno, t in enumerate(text.splitlines(True)):
77 yield {"line": t,
77 yield {"line": t,
78 "lineid": "l%d" % (lineno + 1),
78 "lineid": "l%d" % (lineno + 1),
79 "linenumber": "% 6d" % (lineno + 1),
79 "linenumber": "% 6d" % (lineno + 1),
80 "parity": parity.next()}
80 "parity": parity.next()}
81
81
82 return tmpl("filerevision",
82 return tmpl("filerevision",
83 file=f,
83 file=f,
84 path=webutil.up(f),
84 path=webutil.up(f),
85 text=lines(),
85 text=lines(),
86 rev=fctx.rev(),
86 rev=fctx.rev(),
87 node=fctx.hex(),
87 node=fctx.hex(),
88 author=fctx.user(),
88 author=fctx.user(),
89 date=fctx.date(),
89 date=fctx.date(),
90 desc=fctx.description(),
90 desc=fctx.description(),
91 branch=webutil.nodebranchnodefault(fctx),
91 branch=webutil.nodebranchnodefault(fctx),
92 parent=webutil.parents(fctx),
92 parent=webutil.parents(fctx),
93 child=webutil.children(fctx),
93 child=webutil.children(fctx),
94 rename=webutil.renamelink(fctx),
94 rename=webutil.renamelink(fctx),
95 permissions=fctx.manifest().flags(f))
95 permissions=fctx.manifest().flags(f))
96
96
97 def file(web, req, tmpl):
97 def file(web, req, tmpl):
98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
98 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
99 if not path:
99 if not path:
100 return manifest(web, req, tmpl)
100 return manifest(web, req, tmpl)
101 try:
101 try:
102 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
102 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
103 except error.LookupError, inst:
103 except error.LookupError, inst:
104 try:
104 try:
105 return manifest(web, req, tmpl)
105 return manifest(web, req, tmpl)
106 except ErrorResponse:
106 except ErrorResponse:
107 raise inst
107 raise inst
108
108
109 def _search(web, req, tmpl):
109 def _search(web, req, tmpl):
110
110
111 query = req.form['rev'][0]
111 query = req.form['rev'][0]
112 revcount = web.maxchanges
112 revcount = web.maxchanges
113 if 'revcount' in req.form:
113 if 'revcount' in req.form:
114 revcount = int(req.form.get('revcount', [revcount])[0])
114 revcount = int(req.form.get('revcount', [revcount])[0])
115 revcount = max(revcount, 1)
115 revcount = max(revcount, 1)
116 tmpl.defaults['sessionvars']['revcount'] = revcount
116 tmpl.defaults['sessionvars']['revcount'] = revcount
117
117
118 lessvars = copy.copy(tmpl.defaults['sessionvars'])
118 lessvars = copy.copy(tmpl.defaults['sessionvars'])
119 lessvars['revcount'] = max(revcount / 2, 1)
119 lessvars['revcount'] = max(revcount / 2, 1)
120 lessvars['rev'] = query
120 lessvars['rev'] = query
121 morevars = copy.copy(tmpl.defaults['sessionvars'])
121 morevars = copy.copy(tmpl.defaults['sessionvars'])
122 morevars['revcount'] = revcount * 2
122 morevars['revcount'] = revcount * 2
123 morevars['rev'] = query
123 morevars['rev'] = query
124
124
125 def changelist(**map):
125 def changelist(**map):
126 count = 0
126 count = 0
127 lower = encoding.lower
127 lower = encoding.lower
128 qw = lower(query).split()
128 qw = lower(query).split()
129
129
130 def revgen():
130 def revgen():
131 for i in xrange(len(web.repo) - 1, 0, -100):
131 for i in xrange(len(web.repo) - 1, 0, -100):
132 l = []
132 l = []
133 for j in xrange(max(0, i - 100), i + 1):
133 for j in xrange(max(0, i - 100), i + 1):
134 ctx = web.repo[j]
134 ctx = web.repo[j]
135 l.append(ctx)
135 l.append(ctx)
136 l.reverse()
136 l.reverse()
137 for e in l:
137 for e in l:
138 yield e
138 yield e
139
139
140 for ctx in revgen():
140 for ctx in revgen():
141 miss = 0
141 miss = 0
142 for q in qw:
142 for q in qw:
143 if not (q in lower(ctx.user()) or
143 if not (q in lower(ctx.user()) or
144 q in lower(ctx.description()) or
144 q in lower(ctx.description()) or
145 q in lower(" ".join(ctx.files()))):
145 q in lower(" ".join(ctx.files()))):
146 miss = 1
146 miss = 1
147 break
147 break
148 if miss:
148 if miss:
149 continue
149 continue
150
150
151 count += 1
151 count += 1
152 n = ctx.node()
152 n = ctx.node()
153 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
153 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
154 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
154 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
155
155
156 yield tmpl('searchentry',
156 yield tmpl('searchentry',
157 parity=parity.next(),
157 parity=parity.next(),
158 author=ctx.user(),
158 author=ctx.user(),
159 parent=webutil.parents(ctx),
159 parent=webutil.parents(ctx),
160 child=webutil.children(ctx),
160 child=webutil.children(ctx),
161 changelogtag=showtags,
161 changelogtag=showtags,
162 desc=ctx.description(),
162 desc=ctx.description(),
163 date=ctx.date(),
163 date=ctx.date(),
164 files=files,
164 files=files,
165 rev=ctx.rev(),
165 rev=ctx.rev(),
166 node=hex(n),
166 node=hex(n),
167 tags=webutil.nodetagsdict(web.repo, n),
167 tags=webutil.nodetagsdict(web.repo, n),
168 bookmarks=webutil.nodebookmarksdict(web.repo, n),
168 bookmarks=webutil.nodebookmarksdict(web.repo, n),
169 inbranch=webutil.nodeinbranch(web.repo, ctx),
169 inbranch=webutil.nodeinbranch(web.repo, ctx),
170 branches=webutil.nodebranchdict(web.repo, ctx))
170 branches=webutil.nodebranchdict(web.repo, ctx))
171
171
172 if count >= revcount:
172 if count >= revcount:
173 break
173 break
174
174
175 tip = web.repo['tip']
175 tip = web.repo['tip']
176 parity = paritygen(web.stripecount)
176 parity = paritygen(web.stripecount)
177
177
178 return tmpl('search', query=query, node=tip.hex(),
178 return tmpl('search', query=query, node=tip.hex(),
179 entries=changelist, archives=web.archivelist("tip"),
179 entries=changelist, archives=web.archivelist("tip"),
180 morevars=morevars, lessvars=lessvars)
180 morevars=morevars, lessvars=lessvars)
181
181
182 def changelog(web, req, tmpl, shortlog=False):
182 def changelog(web, req, tmpl, shortlog=False):
183
183
184 if 'node' in req.form:
184 if 'node' in req.form:
185 ctx = webutil.changectx(web.repo, req)
185 ctx = webutil.changectx(web.repo, req)
186 else:
186 else:
187 if 'rev' in req.form:
187 if 'rev' in req.form:
188 hi = req.form['rev'][0]
188 hi = req.form['rev'][0]
189 else:
189 else:
190 hi = len(web.repo) - 1
190 hi = len(web.repo) - 1
191 try:
191 try:
192 ctx = web.repo[hi]
192 ctx = web.repo[hi]
193 except error.RepoError:
193 except error.RepoError:
194 return _search(web, req, tmpl) # XXX redirect to 404 page?
194 return _search(web, req, tmpl) # XXX redirect to 404 page?
195
195
196 def changelist(limit=0, **map):
196 def changelist(limit=0, **map):
197 l = [] # build a list in forward order for efficiency
197 l = [] # build a list in forward order for efficiency
198 for i in xrange(start, end):
198 for i in xrange(start, end):
199 ctx = web.repo[i]
199 ctx = web.repo[i]
200 n = ctx.node()
200 n = ctx.node()
201 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
201 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
202 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
202 files = webutil.listfilediffs(tmpl, ctx.files(), n, web.maxfiles)
203
203
204 l.insert(0, {"parity": parity.next(),
204 l.insert(0, {"parity": parity.next(),
205 "author": ctx.user(),
205 "author": ctx.user(),
206 "parent": webutil.parents(ctx, i - 1),
206 "parent": webutil.parents(ctx, i - 1),
207 "child": webutil.children(ctx, i + 1),
207 "child": webutil.children(ctx, i + 1),
208 "changelogtag": showtags,
208 "changelogtag": showtags,
209 "desc": ctx.description(),
209 "desc": ctx.description(),
210 "date": ctx.date(),
210 "date": ctx.date(),
211 "files": files,
211 "files": files,
212 "rev": i,
212 "rev": i,
213 "node": hex(n),
213 "node": hex(n),
214 "tags": webutil.nodetagsdict(web.repo, n),
214 "tags": webutil.nodetagsdict(web.repo, n),
215 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
215 "bookmarks": webutil.nodebookmarksdict(web.repo, n),
216 "inbranch": webutil.nodeinbranch(web.repo, ctx),
216 "inbranch": webutil.nodeinbranch(web.repo, ctx),
217 "branches": webutil.nodebranchdict(web.repo, ctx)
217 "branches": webutil.nodebranchdict(web.repo, ctx)
218 })
218 })
219
219
220 if limit > 0:
220 if limit > 0:
221 l = l[:limit]
221 l = l[:limit]
222
222
223 for e in l:
223 for e in l:
224 yield e
224 yield e
225
225
226 revcount = shortlog and web.maxshortchanges or web.maxchanges
226 revcount = shortlog and web.maxshortchanges or web.maxchanges
227 if 'revcount' in req.form:
227 if 'revcount' in req.form:
228 revcount = int(req.form.get('revcount', [revcount])[0])
228 revcount = int(req.form.get('revcount', [revcount])[0])
229 revcount = max(revcount, 1)
229 revcount = max(revcount, 1)
230 tmpl.defaults['sessionvars']['revcount'] = revcount
230 tmpl.defaults['sessionvars']['revcount'] = revcount
231
231
232 lessvars = copy.copy(tmpl.defaults['sessionvars'])
232 lessvars = copy.copy(tmpl.defaults['sessionvars'])
233 lessvars['revcount'] = max(revcount / 2, 1)
233 lessvars['revcount'] = max(revcount / 2, 1)
234 morevars = copy.copy(tmpl.defaults['sessionvars'])
234 morevars = copy.copy(tmpl.defaults['sessionvars'])
235 morevars['revcount'] = revcount * 2
235 morevars['revcount'] = revcount * 2
236
236
237 count = len(web.repo)
237 count = len(web.repo)
238 pos = ctx.rev()
238 pos = ctx.rev()
239 start = max(0, pos - revcount + 1)
239 start = max(0, pos - revcount + 1)
240 end = min(count, start + revcount)
240 end = min(count, start + revcount)
241 pos = end - 1
241 pos = end - 1
242 parity = paritygen(web.stripecount, offset=start - end)
242 parity = paritygen(web.stripecount, offset=start - end)
243
243
244 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
244 changenav = webutil.revnavgen(pos, revcount, count, web.repo.changectx)
245
245
246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
246 return tmpl(shortlog and 'shortlog' or 'changelog', changenav=changenav,
247 node=ctx.hex(), rev=pos, changesets=count,
247 node=ctx.hex(), rev=pos, changesets=count,
248 entries=lambda **x: changelist(limit=0,**x),
248 entries=lambda **x: changelist(limit=0,**x),
249 latestentry=lambda **x: changelist(limit=1,**x),
249 latestentry=lambda **x: changelist(limit=1,**x),
250 archives=web.archivelist("tip"), revcount=revcount,
250 archives=web.archivelist("tip"), revcount=revcount,
251 morevars=morevars, lessvars=lessvars)
251 morevars=morevars, lessvars=lessvars)
252
252
253 def shortlog(web, req, tmpl):
253 def shortlog(web, req, tmpl):
254 return changelog(web, req, tmpl, shortlog = True)
254 return changelog(web, req, tmpl, shortlog = True)
255
255
256 def changeset(web, req, tmpl):
256 def changeset(web, req, tmpl):
257 ctx = webutil.changectx(web.repo, req)
257 ctx = webutil.changectx(web.repo, req)
258 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
258 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', ctx.node())
259 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
259 showbookmarks = webutil.showbookmark(web.repo, tmpl, 'changesetbookmark',
260 ctx.node())
260 ctx.node())
261 showbranch = webutil.nodebranchnodefault(ctx)
261 showbranch = webutil.nodebranchnodefault(ctx)
262
262
263 files = []
263 files = []
264 parity = paritygen(web.stripecount)
264 parity = paritygen(web.stripecount)
265 for blockno, f in enumerate(ctx.files()):
265 for blockno, f in enumerate(ctx.files()):
266 template = f in ctx and 'filenodelink' or 'filenolink'
266 template = f in ctx and 'filenodelink' or 'filenolink'
267 files.append(tmpl(template,
267 files.append(tmpl(template,
268 node=ctx.hex(), file=f, blockno=blockno + 1,
268 node=ctx.hex(), file=f, blockno=blockno + 1,
269 parity=parity.next()))
269 parity=parity.next()))
270
270
271 style = web.config('web', 'style', 'paper')
271 style = web.config('web', 'style', 'paper')
272 if 'style' in req.form:
272 if 'style' in req.form:
273 style = req.form['style'][0]
273 style = req.form['style'][0]
274
274
275 parity = paritygen(web.stripecount)
275 parity = paritygen(web.stripecount)
276 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
276 diffs = webutil.diffs(web.repo, tmpl, ctx, None, parity, style)
277
277
278 parity = paritygen(web.stripecount)
278 parity = paritygen(web.stripecount)
279 diffstatgen = webutil.diffstatgen(ctx)
279 diffstatgen = webutil.diffstatgen(ctx)
280 diffstat = webutil.diffstat(tmpl, ctx, diffstatgen, parity)
280 diffstat = webutil.diffstat(tmpl, ctx, diffstatgen, parity)
281
281
282 return tmpl('changeset',
282 return tmpl('changeset',
283 diff=diffs,
283 diff=diffs,
284 rev=ctx.rev(),
284 rev=ctx.rev(),
285 node=ctx.hex(),
285 node=ctx.hex(),
286 parent=webutil.parents(ctx),
286 parent=webutil.parents(ctx),
287 child=webutil.children(ctx),
287 child=webutil.children(ctx),
288 changesettag=showtags,
288 changesettag=showtags,
289 changesetbookmark=showbookmarks,
289 changesetbookmark=showbookmarks,
290 changesetbranch=showbranch,
290 changesetbranch=showbranch,
291 author=ctx.user(),
291 author=ctx.user(),
292 desc=ctx.description(),
292 desc=ctx.description(),
293 date=ctx.date(),
293 date=ctx.date(),
294 files=files,
294 files=files,
295 diffsummary=lambda **x: webutil.diffsummary(diffstatgen),
295 diffsummary=lambda **x: webutil.diffsummary(diffstatgen),
296 diffstat=diffstat,
296 diffstat=diffstat,
297 archives=web.archivelist(ctx.hex()),
297 archives=web.archivelist(ctx.hex()),
298 tags=webutil.nodetagsdict(web.repo, ctx.node()),
298 tags=webutil.nodetagsdict(web.repo, ctx.node()),
299 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
299 bookmarks=webutil.nodebookmarksdict(web.repo, ctx.node()),
300 branch=webutil.nodebranchnodefault(ctx),
300 branch=webutil.nodebranchnodefault(ctx),
301 inbranch=webutil.nodeinbranch(web.repo, ctx),
301 inbranch=webutil.nodeinbranch(web.repo, ctx),
302 branches=webutil.nodebranchdict(web.repo, ctx))
302 branches=webutil.nodebranchdict(web.repo, ctx))
303
303
304 rev = changeset
304 rev = changeset
305
305
306 def decodepath(path):
306 def decodepath(path):
307 """Hook for mapping a path in the repository to a path in the
307 """Hook for mapping a path in the repository to a path in the
308 working copy.
308 working copy.
309
309
310 Extensions (e.g., largefiles) can override this to remap files in
310 Extensions (e.g., largefiles) can override this to remap files in
311 the virtual file system presented by the manifest command below."""
311 the virtual file system presented by the manifest command below."""
312 return path
312 return path
313
313
314 def manifest(web, req, tmpl):
314 def manifest(web, req, tmpl):
315 ctx = webutil.changectx(web.repo, req)
315 ctx = webutil.changectx(web.repo, req)
316 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
316 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
317 mf = ctx.manifest()
317 mf = ctx.manifest()
318 node = ctx.node()
318 node = ctx.node()
319
319
320 files = {}
320 files = {}
321 dirs = {}
321 dirs = {}
322 parity = paritygen(web.stripecount)
322 parity = paritygen(web.stripecount)
323
323
324 if path and path[-1] != "/":
324 if path and path[-1] != "/":
325 path += "/"
325 path += "/"
326 l = len(path)
326 l = len(path)
327 abspath = "/" + path
327 abspath = "/" + path
328
328
329 for full, n in mf.iteritems():
329 for full, n in mf.iteritems():
330 # the virtual path (working copy path) used for the full
330 # the virtual path (working copy path) used for the full
331 # (repository) path
331 # (repository) path
332 f = decodepath(full)
332 f = decodepath(full)
333
333
334 if f[:l] != path:
334 if f[:l] != path:
335 continue
335 continue
336 remain = f[l:]
336 remain = f[l:]
337 elements = remain.split('/')
337 elements = remain.split('/')
338 if len(elements) == 1:
338 if len(elements) == 1:
339 files[remain] = full
339 files[remain] = full
340 else:
340 else:
341 h = dirs # need to retain ref to dirs (root)
341 h = dirs # need to retain ref to dirs (root)
342 for elem in elements[0:-1]:
342 for elem in elements[0:-1]:
343 if elem not in h:
343 if elem not in h:
344 h[elem] = {}
344 h[elem] = {}
345 h = h[elem]
345 h = h[elem]
346 if len(h) > 1:
346 if len(h) > 1:
347 break
347 break
348 h[None] = None # denotes files present
348 h[None] = None # denotes files present
349
349
350 if mf and not files and not dirs:
350 if mf and not files and not dirs:
351 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
351 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
352
352
353 def filelist(**map):
353 def filelist(**map):
354 for f in sorted(files):
354 for f in sorted(files):
355 full = files[f]
355 full = files[f]
356
356
357 fctx = ctx.filectx(full)
357 fctx = ctx.filectx(full)
358 yield {"file": full,
358 yield {"file": full,
359 "parity": parity.next(),
359 "parity": parity.next(),
360 "basename": f,
360 "basename": f,
361 "date": fctx.date(),
361 "date": fctx.date(),
362 "size": fctx.size(),
362 "size": fctx.size(),
363 "permissions": mf.flags(full)}
363 "permissions": mf.flags(full)}
364
364
365 def dirlist(**map):
365 def dirlist(**map):
366 for d in sorted(dirs):
366 for d in sorted(dirs):
367
367
368 emptydirs = []
368 emptydirs = []
369 h = dirs[d]
369 h = dirs[d]
370 while isinstance(h, dict) and len(h) == 1:
370 while isinstance(h, dict) and len(h) == 1:
371 k, v = h.items()[0]
371 k, v = h.items()[0]
372 if v:
372 if v:
373 emptydirs.append(k)
373 emptydirs.append(k)
374 h = v
374 h = v
375
375
376 path = "%s%s" % (abspath, d)
376 path = "%s%s" % (abspath, d)
377 yield {"parity": parity.next(),
377 yield {"parity": parity.next(),
378 "path": path,
378 "path": path,
379 "emptydirs": "/".join(emptydirs),
379 "emptydirs": "/".join(emptydirs),
380 "basename": d}
380 "basename": d}
381
381
382 return tmpl("manifest",
382 return tmpl("manifest",
383 rev=ctx.rev(),
383 rev=ctx.rev(),
384 node=hex(node),
384 node=hex(node),
385 path=abspath,
385 path=abspath,
386 up=webutil.up(abspath),
386 up=webutil.up(abspath),
387 upparity=parity.next(),
387 upparity=parity.next(),
388 fentries=filelist,
388 fentries=filelist,
389 dentries=dirlist,
389 dentries=dirlist,
390 archives=web.archivelist(hex(node)),
390 archives=web.archivelist(hex(node)),
391 tags=webutil.nodetagsdict(web.repo, node),
391 tags=webutil.nodetagsdict(web.repo, node),
392 bookmarks=webutil.nodebookmarksdict(web.repo, node),
392 bookmarks=webutil.nodebookmarksdict(web.repo, node),
393 inbranch=webutil.nodeinbranch(web.repo, ctx),
393 inbranch=webutil.nodeinbranch(web.repo, ctx),
394 branches=webutil.nodebranchdict(web.repo, ctx))
394 branches=webutil.nodebranchdict(web.repo, ctx))
395
395
396 def tags(web, req, tmpl):
396 def tags(web, req, tmpl):
397 i = reversed(web.repo.tagslist())
397 i = reversed(web.repo.tagslist())
398 parity = paritygen(web.stripecount)
398 parity = paritygen(web.stripecount)
399
399
400 def entries(notip=False, limit=0, **map):
400 def entries(notip=False, limit=0, **map):
401 count = 0
401 count = 0
402 for k, n in i:
402 for k, n in i:
403 if notip and k == "tip":
403 if notip and k == "tip":
404 continue
404 continue
405 if limit > 0 and count >= limit:
405 if limit > 0 and count >= limit:
406 continue
406 continue
407 count = count + 1
407 count = count + 1
408 yield {"parity": parity.next(),
408 yield {"parity": parity.next(),
409 "tag": k,
409 "tag": k,
410 "date": web.repo[n].date(),
410 "date": web.repo[n].date(),
411 "node": hex(n)}
411 "node": hex(n)}
412
412
413 return tmpl("tags",
413 return tmpl("tags",
414 node=hex(web.repo.changelog.tip()),
414 node=hex(web.repo.changelog.tip()),
415 entries=lambda **x: entries(False, 0, **x),
415 entries=lambda **x: entries(False, 0, **x),
416 entriesnotip=lambda **x: entries(True, 0, **x),
416 entriesnotip=lambda **x: entries(True, 0, **x),
417 latestentry=lambda **x: entries(True, 1, **x))
417 latestentry=lambda **x: entries(True, 1, **x))
418
418
419 def bookmarks(web, req, tmpl):
419 def bookmarks(web, req, tmpl):
420 i = web.repo._bookmarks.items()
420 i = web.repo._bookmarks.items()
421 parity = paritygen(web.stripecount)
421 parity = paritygen(web.stripecount)
422
422
423 def entries(limit=0, **map):
423 def entries(limit=0, **map):
424 count = 0
424 count = 0
425 for k, n in sorted(i):
425 for k, n in sorted(i):
426 if limit > 0 and count >= limit:
426 if limit > 0 and count >= limit:
427 continue
427 continue
428 count = count + 1
428 count = count + 1
429 yield {"parity": parity.next(),
429 yield {"parity": parity.next(),
430 "bookmark": k,
430 "bookmark": k,
431 "date": web.repo[n].date(),
431 "date": web.repo[n].date(),
432 "node": hex(n)}
432 "node": hex(n)}
433
433
434 return tmpl("bookmarks",
434 return tmpl("bookmarks",
435 node=hex(web.repo.changelog.tip()),
435 node=hex(web.repo.changelog.tip()),
436 entries=lambda **x: entries(0, **x),
436 entries=lambda **x: entries(0, **x),
437 latestentry=lambda **x: entries(1, **x))
437 latestentry=lambda **x: entries(1, **x))
438
438
439 def branches(web, req, tmpl):
439 def branches(web, req, tmpl):
440 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
440 tips = (web.repo[n] for t, n in web.repo.branchtags().iteritems())
441 heads = web.repo.heads()
441 heads = web.repo.heads()
442 parity = paritygen(web.stripecount)
442 parity = paritygen(web.stripecount)
443 sortkey = lambda ctx: (not ctx.closesbranch(), ctx.rev())
443 sortkey = lambda ctx: (not ctx.closesbranch(), ctx.rev())
444
444
445 def entries(limit, **map):
445 def entries(limit, **map):
446 count = 0
446 count = 0
447 for ctx in sorted(tips, key=sortkey, reverse=True):
447 for ctx in sorted(tips, key=sortkey, reverse=True):
448 if limit > 0 and count >= limit:
448 if limit > 0 and count >= limit:
449 return
449 return
450 count += 1
450 count += 1
451 if not web.repo.branchheads(ctx.branch()):
451 if not web.repo.branchheads(ctx.branch()):
452 status = 'closed'
452 status = 'closed'
453 elif ctx.node() not in heads:
453 elif ctx.node() not in heads:
454 status = 'inactive'
454 status = 'inactive'
455 else:
455 else:
456 status = 'open'
456 status = 'open'
457 yield {'parity': parity.next(),
457 yield {'parity': parity.next(),
458 'branch': ctx.branch(),
458 'branch': ctx.branch(),
459 'status': status,
459 'status': status,
460 'node': ctx.hex(),
460 'node': ctx.hex(),
461 'date': ctx.date()}
461 'date': ctx.date()}
462
462
463 return tmpl('branches', node=hex(web.repo.changelog.tip()),
463 return tmpl('branches', node=hex(web.repo.changelog.tip()),
464 entries=lambda **x: entries(0, **x),
464 entries=lambda **x: entries(0, **x),
465 latestentry=lambda **x: entries(1, **x))
465 latestentry=lambda **x: entries(1, **x))
466
466
467 def summary(web, req, tmpl):
467 def summary(web, req, tmpl):
468 i = reversed(web.repo.tagslist())
468 i = reversed(web.repo.tagslist())
469
469
470 def tagentries(**map):
470 def tagentries(**map):
471 parity = paritygen(web.stripecount)
471 parity = paritygen(web.stripecount)
472 count = 0
472 count = 0
473 for k, n in i:
473 for k, n in i:
474 if k == "tip": # skip tip
474 if k == "tip": # skip tip
475 continue
475 continue
476
476
477 count += 1
477 count += 1
478 if count > 10: # limit to 10 tags
478 if count > 10: # limit to 10 tags
479 break
479 break
480
480
481 yield tmpl("tagentry",
481 yield tmpl("tagentry",
482 parity=parity.next(),
482 parity=parity.next(),
483 tag=k,
483 tag=k,
484 node=hex(n),
484 node=hex(n),
485 date=web.repo[n].date())
485 date=web.repo[n].date())
486
486
487 def bookmarks(**map):
487 def bookmarks(**map):
488 parity = paritygen(web.stripecount)
488 parity = paritygen(web.stripecount)
489 b = web.repo._bookmarks.items()
489 b = web.repo._bookmarks.items()
490 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
490 for k, n in sorted(b)[:10]: # limit to 10 bookmarks
491 yield {'parity': parity.next(),
491 yield {'parity': parity.next(),
492 'bookmark': k,
492 'bookmark': k,
493 'date': web.repo[n].date(),
493 'date': web.repo[n].date(),
494 'node': hex(n)}
494 'node': hex(n)}
495
495
496 def branches(**map):
496 def branches(**map):
497 parity = paritygen(web.stripecount)
497 parity = paritygen(web.stripecount)
498
498
499 b = web.repo.branchtags()
499 b = web.repo.branchtags()
500 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
500 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.iteritems()]
501 for r, n, t in sorted(l):
501 for r, n, t in sorted(l):
502 yield {'parity': parity.next(),
502 yield {'parity': parity.next(),
503 'branch': t,
503 'branch': t,
504 'node': hex(n),
504 'node': hex(n),
505 'date': web.repo[n].date()}
505 'date': web.repo[n].date()}
506
506
507 def changelist(**map):
507 def changelist(**map):
508 parity = paritygen(web.stripecount, offset=start - end)
508 parity = paritygen(web.stripecount, offset=start - end)
509 l = [] # build a list in forward order for efficiency
509 l = [] # build a list in forward order for efficiency
510 for i in xrange(start, end):
510 for i in xrange(start, end):
511 ctx = web.repo[i]
511 ctx = web.repo[i]
512 n = ctx.node()
512 n = ctx.node()
513 hn = hex(n)
513 hn = hex(n)
514
514
515 l.insert(0, tmpl(
515 l.insert(0, tmpl(
516 'shortlogentry',
516 'shortlogentry',
517 parity=parity.next(),
517 parity=parity.next(),
518 author=ctx.user(),
518 author=ctx.user(),
519 desc=ctx.description(),
519 desc=ctx.description(),
520 date=ctx.date(),
520 date=ctx.date(),
521 rev=i,
521 rev=i,
522 node=hn,
522 node=hn,
523 tags=webutil.nodetagsdict(web.repo, n),
523 tags=webutil.nodetagsdict(web.repo, n),
524 bookmarks=webutil.nodebookmarksdict(web.repo, n),
524 bookmarks=webutil.nodebookmarksdict(web.repo, n),
525 inbranch=webutil.nodeinbranch(web.repo, ctx),
525 inbranch=webutil.nodeinbranch(web.repo, ctx),
526 branches=webutil.nodebranchdict(web.repo, ctx)))
526 branches=webutil.nodebranchdict(web.repo, ctx)))
527
527
528 yield l
528 yield l
529
529
530 tip = web.repo['tip']
530 tip = web.repo['tip']
531 count = len(web.repo)
531 count = len(web.repo)
532 start = max(0, count - web.maxchanges)
532 start = max(0, count - web.maxchanges)
533 end = min(count, start + web.maxchanges)
533 end = min(count, start + web.maxchanges)
534
534
535 return tmpl("summary",
535 return tmpl("summary",
536 desc=web.config("web", "description", "unknown"),
536 desc=web.config("web", "description", "unknown"),
537 owner=get_contact(web.config) or "unknown",
537 owner=get_contact(web.config) or "unknown",
538 lastchange=tip.date(),
538 lastchange=tip.date(),
539 tags=tagentries,
539 tags=tagentries,
540 bookmarks=bookmarks,
540 bookmarks=bookmarks,
541 branches=branches,
541 branches=branches,
542 shortlog=changelist,
542 shortlog=changelist,
543 node=tip.hex(),
543 node=tip.hex(),
544 archives=web.archivelist("tip"))
544 archives=web.archivelist("tip"))
545
545
546 def filediff(web, req, tmpl):
546 def filediff(web, req, tmpl):
547 fctx, ctx = None, None
547 fctx, ctx = None, None
548 try:
548 try:
549 fctx = webutil.filectx(web.repo, req)
549 fctx = webutil.filectx(web.repo, req)
550 except LookupError:
550 except LookupError:
551 ctx = webutil.changectx(web.repo, req)
551 ctx = webutil.changectx(web.repo, req)
552 path = webutil.cleanpath(web.repo, req.form['file'][0])
552 path = webutil.cleanpath(web.repo, req.form['file'][0])
553 if path not in ctx.files():
553 if path not in ctx.files():
554 raise
554 raise
555
555
556 if fctx is not None:
556 if fctx is not None:
557 n = fctx.node()
557 n = fctx.node()
558 path = fctx.path()
558 path = fctx.path()
559 ctx = fctx.changectx()
559 ctx = fctx.changectx()
560 else:
560 else:
561 n = ctx.node()
561 n = ctx.node()
562 # path already defined in except clause
562 # path already defined in except clause
563
563
564 parity = paritygen(web.stripecount)
564 parity = paritygen(web.stripecount)
565 style = web.config('web', 'style', 'paper')
565 style = web.config('web', 'style', 'paper')
566 if 'style' in req.form:
566 if 'style' in req.form:
567 style = req.form['style'][0]
567 style = req.form['style'][0]
568
568
569 diffs = webutil.diffs(web.repo, tmpl, ctx, [path], parity, style)
569 diffs = webutil.diffs(web.repo, tmpl, ctx, [path], parity, style)
570 rename = fctx and webutil.renamelink(fctx) or []
570 rename = fctx and webutil.renamelink(fctx) or []
571 ctx = fctx and fctx or ctx
571 ctx = fctx and fctx or ctx
572 return tmpl("filediff",
572 return tmpl("filediff",
573 file=path,
573 file=path,
574 node=hex(n),
574 node=hex(n),
575 rev=ctx.rev(),
575 rev=ctx.rev(),
576 date=ctx.date(),
576 date=ctx.date(),
577 desc=ctx.description(),
577 desc=ctx.description(),
578 author=ctx.user(),
578 author=ctx.user(),
579 rename=rename,
579 rename=rename,
580 branch=webutil.nodebranchnodefault(ctx),
580 branch=webutil.nodebranchnodefault(ctx),
581 parent=webutil.parents(ctx),
581 parent=webutil.parents(ctx),
582 child=webutil.children(ctx),
582 child=webutil.children(ctx),
583 diff=diffs)
583 diff=diffs)
584
584
585 diff = filediff
585 diff = filediff
586
586
587 def comparison(web, req, tmpl):
587 def comparison(web, req, tmpl):
588 ctx = webutil.changectx(web.repo, req)
588 ctx = webutil.changectx(web.repo, req)
589 if 'file' not in req.form:
589 if 'file' not in req.form:
590 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
590 raise ErrorResponse(HTTP_NOT_FOUND, 'file not given')
591 path = webutil.cleanpath(web.repo, req.form['file'][0])
591 path = webutil.cleanpath(web.repo, req.form['file'][0])
592 rename = path in ctx and webutil.renamelink(ctx[path]) or []
592 rename = path in ctx and webutil.renamelink(ctx[path]) or []
593
593
594 parsecontext = lambda v: v == 'full' and -1 or int(v)
594 parsecontext = lambda v: v == 'full' and -1 or int(v)
595 if 'context' in req.form:
595 if 'context' in req.form:
596 context = parsecontext(req.form['context'][0])
596 context = parsecontext(req.form['context'][0])
597 else:
597 else:
598 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
598 context = parsecontext(web.config('web', 'comparisoncontext', '5'))
599
599
600 def filelines(f):
600 def filelines(f):
601 if binary(f.data()):
601 if binary(f.data()):
602 mt = mimetypes.guess_type(f.path())[0]
602 mt = mimetypes.guess_type(f.path())[0]
603 if not mt:
603 if not mt:
604 mt = 'application/octet-stream'
604 mt = 'application/octet-stream'
605 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
605 return [_('(binary file %s, hash: %s)') % (mt, hex(f.filenode()))]
606 return f.data().splitlines()
606 return f.data().splitlines()
607
607
608 if path in ctx:
608 if path in ctx:
609 fctx = ctx[path]
609 fctx = ctx[path]
610 rightrev = fctx.filerev()
610 rightrev = fctx.filerev()
611 rightnode = fctx.filenode()
611 rightnode = fctx.filenode()
612 rightlines = filelines(fctx)
612 rightlines = filelines(fctx)
613 parents = fctx.parents()
613 parents = fctx.parents()
614 if not parents:
614 if not parents:
615 leftrev = -1
615 leftrev = -1
616 leftnode = nullid
616 leftnode = nullid
617 leftlines = ()
617 leftlines = ()
618 else:
618 else:
619 pfctx = parents[0]
619 pfctx = parents[0]
620 leftrev = pfctx.filerev()
620 leftrev = pfctx.filerev()
621 leftnode = pfctx.filenode()
621 leftnode = pfctx.filenode()
622 leftlines = filelines(pfctx)
622 leftlines = filelines(pfctx)
623 else:
623 else:
624 rightrev = -1
624 rightrev = -1
625 rightnode = nullid
625 rightnode = nullid
626 rightlines = ()
626 rightlines = ()
627 fctx = ctx.parents()[0][path]
627 fctx = ctx.parents()[0][path]
628 leftrev = fctx.filerev()
628 leftrev = fctx.filerev()
629 leftnode = fctx.filenode()
629 leftnode = fctx.filenode()
630 leftlines = filelines(fctx)
630 leftlines = filelines(fctx)
631
631
632 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
632 comparison = webutil.compare(tmpl, context, leftlines, rightlines)
633 return tmpl('filecomparison',
633 return tmpl('filecomparison',
634 file=path,
634 file=path,
635 node=hex(ctx.node()),
635 node=hex(ctx.node()),
636 rev=ctx.rev(),
636 rev=ctx.rev(),
637 date=ctx.date(),
637 date=ctx.date(),
638 desc=ctx.description(),
638 desc=ctx.description(),
639 author=ctx.user(),
639 author=ctx.user(),
640 rename=rename,
640 rename=rename,
641 branch=webutil.nodebranchnodefault(ctx),
641 branch=webutil.nodebranchnodefault(ctx),
642 parent=webutil.parents(ctx),
642 parent=webutil.parents(fctx),
643 child=webutil.children(ctx),
643 child=webutil.children(fctx),
644 leftrev=leftrev,
644 leftrev=leftrev,
645 leftnode=hex(leftnode),
645 leftnode=hex(leftnode),
646 rightrev=rightrev,
646 rightrev=rightrev,
647 rightnode=hex(rightnode),
647 rightnode=hex(rightnode),
648 comparison=comparison)
648 comparison=comparison)
649
649
650 def annotate(web, req, tmpl):
650 def annotate(web, req, tmpl):
651 fctx = webutil.filectx(web.repo, req)
651 fctx = webutil.filectx(web.repo, req)
652 f = fctx.path()
652 f = fctx.path()
653 parity = paritygen(web.stripecount)
653 parity = paritygen(web.stripecount)
654 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
654 diffopts = patch.diffopts(web.repo.ui, untrusted=True, section='annotate')
655
655
656 def annotate(**map):
656 def annotate(**map):
657 last = None
657 last = None
658 if binary(fctx.data()):
658 if binary(fctx.data()):
659 mt = (mimetypes.guess_type(fctx.path())[0]
659 mt = (mimetypes.guess_type(fctx.path())[0]
660 or 'application/octet-stream')
660 or 'application/octet-stream')
661 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
661 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
662 '(binary:%s)' % mt)])
662 '(binary:%s)' % mt)])
663 else:
663 else:
664 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
664 lines = enumerate(fctx.annotate(follow=True, linenumber=True,
665 diffopts=diffopts))
665 diffopts=diffopts))
666 for lineno, ((f, targetline), l) in lines:
666 for lineno, ((f, targetline), l) in lines:
667 fnode = f.filenode()
667 fnode = f.filenode()
668
668
669 if last != fnode:
669 if last != fnode:
670 last = fnode
670 last = fnode
671
671
672 yield {"parity": parity.next(),
672 yield {"parity": parity.next(),
673 "node": f.hex(),
673 "node": f.hex(),
674 "rev": f.rev(),
674 "rev": f.rev(),
675 "author": f.user(),
675 "author": f.user(),
676 "desc": f.description(),
676 "desc": f.description(),
677 "file": f.path(),
677 "file": f.path(),
678 "targetline": targetline,
678 "targetline": targetline,
679 "line": l,
679 "line": l,
680 "lineid": "l%d" % (lineno + 1),
680 "lineid": "l%d" % (lineno + 1),
681 "linenumber": "% 6d" % (lineno + 1),
681 "linenumber": "% 6d" % (lineno + 1),
682 "revdate": f.date()}
682 "revdate": f.date()}
683
683
684 return tmpl("fileannotate",
684 return tmpl("fileannotate",
685 file=f,
685 file=f,
686 annotate=annotate,
686 annotate=annotate,
687 path=webutil.up(f),
687 path=webutil.up(f),
688 rev=fctx.rev(),
688 rev=fctx.rev(),
689 node=fctx.hex(),
689 node=fctx.hex(),
690 author=fctx.user(),
690 author=fctx.user(),
691 date=fctx.date(),
691 date=fctx.date(),
692 desc=fctx.description(),
692 desc=fctx.description(),
693 rename=webutil.renamelink(fctx),
693 rename=webutil.renamelink(fctx),
694 branch=webutil.nodebranchnodefault(fctx),
694 branch=webutil.nodebranchnodefault(fctx),
695 parent=webutil.parents(fctx),
695 parent=webutil.parents(fctx),
696 child=webutil.children(fctx),
696 child=webutil.children(fctx),
697 permissions=fctx.manifest().flags(f))
697 permissions=fctx.manifest().flags(f))
698
698
699 def filelog(web, req, tmpl):
699 def filelog(web, req, tmpl):
700
700
701 try:
701 try:
702 fctx = webutil.filectx(web.repo, req)
702 fctx = webutil.filectx(web.repo, req)
703 f = fctx.path()
703 f = fctx.path()
704 fl = fctx.filelog()
704 fl = fctx.filelog()
705 except error.LookupError:
705 except error.LookupError:
706 f = webutil.cleanpath(web.repo, req.form['file'][0])
706 f = webutil.cleanpath(web.repo, req.form['file'][0])
707 fl = web.repo.file(f)
707 fl = web.repo.file(f)
708 numrevs = len(fl)
708 numrevs = len(fl)
709 if not numrevs: # file doesn't exist at all
709 if not numrevs: # file doesn't exist at all
710 raise
710 raise
711 rev = webutil.changectx(web.repo, req).rev()
711 rev = webutil.changectx(web.repo, req).rev()
712 first = fl.linkrev(0)
712 first = fl.linkrev(0)
713 if rev < first: # current rev is from before file existed
713 if rev < first: # current rev is from before file existed
714 raise
714 raise
715 frev = numrevs - 1
715 frev = numrevs - 1
716 while fl.linkrev(frev) > rev:
716 while fl.linkrev(frev) > rev:
717 frev -= 1
717 frev -= 1
718 fctx = web.repo.filectx(f, fl.linkrev(frev))
718 fctx = web.repo.filectx(f, fl.linkrev(frev))
719
719
720 revcount = web.maxshortchanges
720 revcount = web.maxshortchanges
721 if 'revcount' in req.form:
721 if 'revcount' in req.form:
722 revcount = int(req.form.get('revcount', [revcount])[0])
722 revcount = int(req.form.get('revcount', [revcount])[0])
723 revcount = max(revcount, 1)
723 revcount = max(revcount, 1)
724 tmpl.defaults['sessionvars']['revcount'] = revcount
724 tmpl.defaults['sessionvars']['revcount'] = revcount
725
725
726 lessvars = copy.copy(tmpl.defaults['sessionvars'])
726 lessvars = copy.copy(tmpl.defaults['sessionvars'])
727 lessvars['revcount'] = max(revcount / 2, 1)
727 lessvars['revcount'] = max(revcount / 2, 1)
728 morevars = copy.copy(tmpl.defaults['sessionvars'])
728 morevars = copy.copy(tmpl.defaults['sessionvars'])
729 morevars['revcount'] = revcount * 2
729 morevars['revcount'] = revcount * 2
730
730
731 count = fctx.filerev() + 1
731 count = fctx.filerev() + 1
732 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
732 start = max(0, fctx.filerev() - revcount + 1) # first rev on this page
733 end = min(count, start + revcount) # last rev on this page
733 end = min(count, start + revcount) # last rev on this page
734 parity = paritygen(web.stripecount, offset=start - end)
734 parity = paritygen(web.stripecount, offset=start - end)
735
735
736 def entries(limit=0, **map):
736 def entries(limit=0, **map):
737 l = []
737 l = []
738
738
739 repo = web.repo
739 repo = web.repo
740 for i in xrange(start, end):
740 for i in xrange(start, end):
741 iterfctx = fctx.filectx(i)
741 iterfctx = fctx.filectx(i)
742
742
743 l.insert(0, {"parity": parity.next(),
743 l.insert(0, {"parity": parity.next(),
744 "filerev": i,
744 "filerev": i,
745 "file": f,
745 "file": f,
746 "node": iterfctx.hex(),
746 "node": iterfctx.hex(),
747 "author": iterfctx.user(),
747 "author": iterfctx.user(),
748 "date": iterfctx.date(),
748 "date": iterfctx.date(),
749 "rename": webutil.renamelink(iterfctx),
749 "rename": webutil.renamelink(iterfctx),
750 "parent": webutil.parents(iterfctx),
750 "parent": webutil.parents(iterfctx),
751 "child": webutil.children(iterfctx),
751 "child": webutil.children(iterfctx),
752 "desc": iterfctx.description(),
752 "desc": iterfctx.description(),
753 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
753 "tags": webutil.nodetagsdict(repo, iterfctx.node()),
754 "bookmarks": webutil.nodebookmarksdict(
754 "bookmarks": webutil.nodebookmarksdict(
755 repo, iterfctx.node()),
755 repo, iterfctx.node()),
756 "branch": webutil.nodebranchnodefault(iterfctx),
756 "branch": webutil.nodebranchnodefault(iterfctx),
757 "inbranch": webutil.nodeinbranch(repo, iterfctx),
757 "inbranch": webutil.nodeinbranch(repo, iterfctx),
758 "branches": webutil.nodebranchdict(repo, iterfctx)})
758 "branches": webutil.nodebranchdict(repo, iterfctx)})
759
759
760 if limit > 0:
760 if limit > 0:
761 l = l[:limit]
761 l = l[:limit]
762
762
763 for e in l:
763 for e in l:
764 yield e
764 yield e
765
765
766 nodefunc = lambda x: fctx.filectx(fileid=x)
766 nodefunc = lambda x: fctx.filectx(fileid=x)
767 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
767 nav = webutil.revnavgen(end - 1, revcount, count, nodefunc)
768 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
768 return tmpl("filelog", file=f, node=fctx.hex(), nav=nav,
769 entries=lambda **x: entries(limit=0, **x),
769 entries=lambda **x: entries(limit=0, **x),
770 latestentry=lambda **x: entries(limit=1, **x),
770 latestentry=lambda **x: entries(limit=1, **x),
771 revcount=revcount, morevars=morevars, lessvars=lessvars)
771 revcount=revcount, morevars=morevars, lessvars=lessvars)
772
772
773 def archive(web, req, tmpl):
773 def archive(web, req, tmpl):
774 type_ = req.form.get('type', [None])[0]
774 type_ = req.form.get('type', [None])[0]
775 allowed = web.configlist("web", "allow_archive")
775 allowed = web.configlist("web", "allow_archive")
776 key = req.form['node'][0]
776 key = req.form['node'][0]
777
777
778 if type_ not in web.archives:
778 if type_ not in web.archives:
779 msg = 'Unsupported archive type: %s' % type_
779 msg = 'Unsupported archive type: %s' % type_
780 raise ErrorResponse(HTTP_NOT_FOUND, msg)
780 raise ErrorResponse(HTTP_NOT_FOUND, msg)
781
781
782 if not ((type_ in allowed or
782 if not ((type_ in allowed or
783 web.configbool("web", "allow" + type_, False))):
783 web.configbool("web", "allow" + type_, False))):
784 msg = 'Archive type not allowed: %s' % type_
784 msg = 'Archive type not allowed: %s' % type_
785 raise ErrorResponse(HTTP_FORBIDDEN, msg)
785 raise ErrorResponse(HTTP_FORBIDDEN, msg)
786
786
787 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
787 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
788 cnode = web.repo.lookup(key)
788 cnode = web.repo.lookup(key)
789 arch_version = key
789 arch_version = key
790 if cnode == key or key == 'tip':
790 if cnode == key or key == 'tip':
791 arch_version = short(cnode)
791 arch_version = short(cnode)
792 name = "%s-%s" % (reponame, arch_version)
792 name = "%s-%s" % (reponame, arch_version)
793 mimetype, artype, extension, encoding = web.archive_specs[type_]
793 mimetype, artype, extension, encoding = web.archive_specs[type_]
794 headers = [
794 headers = [
795 ('Content-Type', mimetype),
795 ('Content-Type', mimetype),
796 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
796 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
797 ]
797 ]
798 if encoding:
798 if encoding:
799 headers.append(('Content-Encoding', encoding))
799 headers.append(('Content-Encoding', encoding))
800 req.header(headers)
800 req.header(headers)
801 req.respond(HTTP_OK)
801 req.respond(HTTP_OK)
802 archival.archive(web.repo, req, cnode, artype, prefix=name)
802 archival.archive(web.repo, req, cnode, artype, prefix=name)
803 return []
803 return []
804
804
805
805
806 def static(web, req, tmpl):
806 def static(web, req, tmpl):
807 fname = req.form['file'][0]
807 fname = req.form['file'][0]
808 # a repo owner may set web.static in .hg/hgrc to get any file
808 # a repo owner may set web.static in .hg/hgrc to get any file
809 # readable by the user running the CGI script
809 # readable by the user running the CGI script
810 static = web.config("web", "static", None, untrusted=False)
810 static = web.config("web", "static", None, untrusted=False)
811 if not static:
811 if not static:
812 tp = web.templatepath or templater.templatepath()
812 tp = web.templatepath or templater.templatepath()
813 if isinstance(tp, str):
813 if isinstance(tp, str):
814 tp = [tp]
814 tp = [tp]
815 static = [os.path.join(p, 'static') for p in tp]
815 static = [os.path.join(p, 'static') for p in tp]
816 return [staticfile(static, fname, req)]
816 return [staticfile(static, fname, req)]
817
817
818 def graph(web, req, tmpl):
818 def graph(web, req, tmpl):
819
819
820 rev = webutil.changectx(web.repo, req).rev()
820 rev = webutil.changectx(web.repo, req).rev()
821 bg_height = 39
821 bg_height = 39
822 revcount = web.maxshortchanges
822 revcount = web.maxshortchanges
823 if 'revcount' in req.form:
823 if 'revcount' in req.form:
824 revcount = int(req.form.get('revcount', [revcount])[0])
824 revcount = int(req.form.get('revcount', [revcount])[0])
825 revcount = max(revcount, 1)
825 revcount = max(revcount, 1)
826 tmpl.defaults['sessionvars']['revcount'] = revcount
826 tmpl.defaults['sessionvars']['revcount'] = revcount
827
827
828 lessvars = copy.copy(tmpl.defaults['sessionvars'])
828 lessvars = copy.copy(tmpl.defaults['sessionvars'])
829 lessvars['revcount'] = max(revcount / 2, 1)
829 lessvars['revcount'] = max(revcount / 2, 1)
830 morevars = copy.copy(tmpl.defaults['sessionvars'])
830 morevars = copy.copy(tmpl.defaults['sessionvars'])
831 morevars['revcount'] = revcount * 2
831 morevars['revcount'] = revcount * 2
832
832
833 max_rev = len(web.repo) - 1
833 max_rev = len(web.repo) - 1
834 revcount = min(max_rev, revcount)
834 revcount = min(max_rev, revcount)
835 revnode = web.repo.changelog.node(rev)
835 revnode = web.repo.changelog.node(rev)
836 revnode_hex = hex(revnode)
836 revnode_hex = hex(revnode)
837 uprev = min(max_rev, rev + revcount)
837 uprev = min(max_rev, rev + revcount)
838 downrev = max(0, rev - revcount)
838 downrev = max(0, rev - revcount)
839 count = len(web.repo)
839 count = len(web.repo)
840 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
840 changenav = webutil.revnavgen(rev, revcount, count, web.repo.changectx)
841 startrev = rev
841 startrev = rev
842 # if starting revision is less than 60 set it to uprev
842 # if starting revision is less than 60 set it to uprev
843 if rev < web.maxshortchanges:
843 if rev < web.maxshortchanges:
844 startrev = uprev
844 startrev = uprev
845
845
846 dag = graphmod.dagwalker(web.repo, range(startrev, downrev - 1, -1))
846 dag = graphmod.dagwalker(web.repo, range(startrev, downrev - 1, -1))
847 tree = list(graphmod.colored(dag, web.repo))
847 tree = list(graphmod.colored(dag, web.repo))
848
848
849 def getcolumns(tree):
849 def getcolumns(tree):
850 cols = 0
850 cols = 0
851 for (id, type, ctx, vtx, edges) in tree:
851 for (id, type, ctx, vtx, edges) in tree:
852 if type != graphmod.CHANGESET:
852 if type != graphmod.CHANGESET:
853 continue
853 continue
854 cols = max(cols, max([edge[0] for edge in edges] or [0]),
854 cols = max(cols, max([edge[0] for edge in edges] or [0]),
855 max([edge[1] for edge in edges] or [0]))
855 max([edge[1] for edge in edges] or [0]))
856 return cols
856 return cols
857
857
858 def graphdata(usetuples, **map):
858 def graphdata(usetuples, **map):
859 data = []
859 data = []
860
860
861 row = 0
861 row = 0
862 for (id, type, ctx, vtx, edges) in tree:
862 for (id, type, ctx, vtx, edges) in tree:
863 if type != graphmod.CHANGESET:
863 if type != graphmod.CHANGESET:
864 continue
864 continue
865 node = str(ctx)
865 node = str(ctx)
866 age = templatefilters.age(ctx.date())
866 age = templatefilters.age(ctx.date())
867 desc = templatefilters.firstline(ctx.description())
867 desc = templatefilters.firstline(ctx.description())
868 desc = cgi.escape(templatefilters.nonempty(desc))
868 desc = cgi.escape(templatefilters.nonempty(desc))
869 user = cgi.escape(templatefilters.person(ctx.user()))
869 user = cgi.escape(templatefilters.person(ctx.user()))
870 branch = ctx.branch()
870 branch = ctx.branch()
871 try:
871 try:
872 branchnode = web.repo.branchtip(branch)
872 branchnode = web.repo.branchtip(branch)
873 except error.RepoLookupError:
873 except error.RepoLookupError:
874 branchnode = None
874 branchnode = None
875 branch = branch, branchnode == ctx.node()
875 branch = branch, branchnode == ctx.node()
876
876
877 if usetuples:
877 if usetuples:
878 data.append((node, vtx, edges, desc, user, age, branch,
878 data.append((node, vtx, edges, desc, user, age, branch,
879 ctx.tags(), ctx.bookmarks()))
879 ctx.tags(), ctx.bookmarks()))
880 else:
880 else:
881 edgedata = [dict(col=edge[0], nextcol=edge[1],
881 edgedata = [dict(col=edge[0], nextcol=edge[1],
882 color=(edge[2] - 1) % 6 + 1,
882 color=(edge[2] - 1) % 6 + 1,
883 width=edge[3], bcolor=edge[4])
883 width=edge[3], bcolor=edge[4])
884 for edge in edges]
884 for edge in edges]
885
885
886 data.append(
886 data.append(
887 dict(node=node,
887 dict(node=node,
888 col=vtx[0],
888 col=vtx[0],
889 color=(vtx[1] - 1) % 6 + 1,
889 color=(vtx[1] - 1) % 6 + 1,
890 edges=edgedata,
890 edges=edgedata,
891 row=row,
891 row=row,
892 nextrow=row + 1,
892 nextrow=row + 1,
893 desc=desc,
893 desc=desc,
894 user=user,
894 user=user,
895 age=age,
895 age=age,
896 bookmarks=webutil.nodebookmarksdict(
896 bookmarks=webutil.nodebookmarksdict(
897 web.repo, ctx.node()),
897 web.repo, ctx.node()),
898 branches=webutil.nodebranchdict(web.repo, ctx),
898 branches=webutil.nodebranchdict(web.repo, ctx),
899 inbranch=webutil.nodeinbranch(web.repo, ctx),
899 inbranch=webutil.nodeinbranch(web.repo, ctx),
900 tags=webutil.nodetagsdict(web.repo, ctx.node())))
900 tags=webutil.nodetagsdict(web.repo, ctx.node())))
901
901
902 row += 1
902 row += 1
903
903
904 return data
904 return data
905
905
906 cols = getcolumns(tree)
906 cols = getcolumns(tree)
907 rows = len(tree)
907 rows = len(tree)
908 canvasheight = (rows + 1) * bg_height - 27
908 canvasheight = (rows + 1) * bg_height - 27
909
909
910 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
910 return tmpl('graph', rev=rev, revcount=revcount, uprev=uprev,
911 lessvars=lessvars, morevars=morevars, downrev=downrev,
911 lessvars=lessvars, morevars=morevars, downrev=downrev,
912 cols=cols, rows=rows,
912 cols=cols, rows=rows,
913 canvaswidth=(cols + 1) * bg_height,
913 canvaswidth=(cols + 1) * bg_height,
914 truecanvasheight=rows * bg_height,
914 truecanvasheight=rows * bg_height,
915 canvasheight=canvasheight, bg_height=bg_height,
915 canvasheight=canvasheight, bg_height=bg_height,
916 jsdata=lambda **x: graphdata(True, **x),
916 jsdata=lambda **x: graphdata(True, **x),
917 nodes=lambda **x: graphdata(False, **x),
917 nodes=lambda **x: graphdata(False, **x),
918 node=revnode_hex, changenav=changenav)
918 node=revnode_hex, changenav=changenav)
919
919
920 def _getdoc(e):
920 def _getdoc(e):
921 doc = e[0].__doc__
921 doc = e[0].__doc__
922 if doc:
922 if doc:
923 doc = _(doc).split('\n')[0]
923 doc = _(doc).split('\n')[0]
924 else:
924 else:
925 doc = _('(no help text available)')
925 doc = _('(no help text available)')
926 return doc
926 return doc
927
927
928 def help(web, req, tmpl):
928 def help(web, req, tmpl):
929 from mercurial import commands # avoid cycle
929 from mercurial import commands # avoid cycle
930
930
931 topicname = req.form.get('node', [None])[0]
931 topicname = req.form.get('node', [None])[0]
932 if not topicname:
932 if not topicname:
933 def topics(**map):
933 def topics(**map):
934 for entries, summary, _ in helpmod.helptable:
934 for entries, summary, _ in helpmod.helptable:
935 entries = sorted(entries, key=len)
935 entries = sorted(entries, key=len)
936 yield {'topic': entries[-1], 'summary': summary}
936 yield {'topic': entries[-1], 'summary': summary}
937
937
938 early, other = [], []
938 early, other = [], []
939 primary = lambda s: s.split('|')[0]
939 primary = lambda s: s.split('|')[0]
940 for c, e in commands.table.iteritems():
940 for c, e in commands.table.iteritems():
941 doc = _getdoc(e)
941 doc = _getdoc(e)
942 if 'DEPRECATED' in doc or c.startswith('debug'):
942 if 'DEPRECATED' in doc or c.startswith('debug'):
943 continue
943 continue
944 cmd = primary(c)
944 cmd = primary(c)
945 if cmd.startswith('^'):
945 if cmd.startswith('^'):
946 early.append((cmd[1:], doc))
946 early.append((cmd[1:], doc))
947 else:
947 else:
948 other.append((cmd, doc))
948 other.append((cmd, doc))
949
949
950 early.sort()
950 early.sort()
951 other.sort()
951 other.sort()
952
952
953 def earlycommands(**map):
953 def earlycommands(**map):
954 for c, doc in early:
954 for c, doc in early:
955 yield {'topic': c, 'summary': doc}
955 yield {'topic': c, 'summary': doc}
956
956
957 def othercommands(**map):
957 def othercommands(**map):
958 for c, doc in other:
958 for c, doc in other:
959 yield {'topic': c, 'summary': doc}
959 yield {'topic': c, 'summary': doc}
960
960
961 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
961 return tmpl('helptopics', topics=topics, earlycommands=earlycommands,
962 othercommands=othercommands, title='Index')
962 othercommands=othercommands, title='Index')
963
963
964 u = webutil.wsgiui()
964 u = webutil.wsgiui()
965 u.pushbuffer()
965 u.pushbuffer()
966 u.verbose = True
966 u.verbose = True
967 try:
967 try:
968 commands.help_(u, topicname)
968 commands.help_(u, topicname)
969 except error.UnknownCommand:
969 except error.UnknownCommand:
970 raise ErrorResponse(HTTP_NOT_FOUND)
970 raise ErrorResponse(HTTP_NOT_FOUND)
971 doc = u.popbuffer()
971 doc = u.popbuffer()
972 return tmpl('help', topic=topicname, doc=doc)
972 return tmpl('help', topic=topicname, doc=doc)
@@ -1,986 +1,986 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
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 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
39 $ "$TESTDIR/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="http://mercurial.selenic.com/">
56 <a href="http://mercurial.selenic.com/">
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/0cd96de13884">log</a></li>
60 <li><a href="/shortlog/0cd96de13884">log</a></li>
61 <li><a href="/graph/0cd96de13884">graph</a></li>
61 <li><a href="/graph/0cd96de13884">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/0cd96de13884">raw</a></li>
68 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
69 <li><a href="/file/0cd96de13884">browse</a></li>
69 <li><a href="/file/0cd96de13884">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><a href="/">test</a></h2>
81 <h2><a href="/">test</a></h2>
82 <h3>changeset 0:0cd96de13884 </h3>
82 <h3>changeset 0:0cd96de13884 </h3>
83
83
84 <form class="search" action="/log">
84 <form class="search" action="/log">
85
85
86 <p><input name="rev" id="search1" type="text" size="30" /></p>
86 <p><input name="rev" id="search1" type="text" size="30" /></p>
87 <div id="hint">find changesets by author, revision,
87 <div id="hint">find changesets by author, revision,
88 files, or words in the commit message</div>
88 files, or words in the commit message</div>
89 </form>
89 </form>
90
90
91 <div class="description">a</div>
91 <div class="description">a</div>
92
92
93 <table id="changesetEntry">
93 <table id="changesetEntry">
94 <tr>
94 <tr>
95 <th class="author">author</th>
95 <th class="author">author</th>
96 <td class="author">&#116;&#101;&#115;&#116;</td>
96 <td class="author">&#116;&#101;&#115;&#116;</td>
97 </tr>
97 </tr>
98 <tr>
98 <tr>
99 <th class="date">date</th>
99 <th class="date">date</th>
100 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
100 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
101 <tr>
101 <tr>
102 <th class="author">parents</th>
102 <th class="author">parents</th>
103 <td class="author"></td>
103 <td class="author"></td>
104 </tr>
104 </tr>
105 <tr>
105 <tr>
106 <th class="author">children</th>
106 <th class="author">children</th>
107 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
107 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
108 </tr>
108 </tr>
109 <tr>
109 <tr>
110 <th class="files">files</th>
110 <th class="files">files</th>
111 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
111 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
112 </tr>
112 </tr>
113 <tr>
113 <tr>
114 <th class="diffstat">diffstat</th>
114 <th class="diffstat">diffstat</th>
115 <td class="diffstat">
115 <td class="diffstat">
116 2 files changed, 2 insertions(+), 0 deletions(-)
116 2 files changed, 2 insertions(+), 0 deletions(-)
117
117
118 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
118 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
119 <div id="diffstatdetails" style="display:none;">
119 <div id="diffstatdetails" style="display:none;">
120 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
120 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
121 <p>
121 <p>
122 <table> <tr class="parity0">
122 <table> <tr class="parity0">
123 <td class="diffstat-file"><a href="#l1.1">a</a></td>
123 <td class="diffstat-file"><a href="#l1.1">a</a></td>
124 <td class="diffstat-total" align="right">1</td>
124 <td class="diffstat-total" align="right">1</td>
125 <td class="diffstat-graph">
125 <td class="diffstat-graph">
126 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
126 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
127 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
127 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
128 </td>
128 </td>
129 </tr>
129 </tr>
130 <tr class="parity1">
130 <tr class="parity1">
131 <td class="diffstat-file"><a href="#l2.1">b</a></td>
131 <td class="diffstat-file"><a href="#l2.1">b</a></td>
132 <td class="diffstat-total" align="right">1</td>
132 <td class="diffstat-total" align="right">1</td>
133 <td class="diffstat-graph">
133 <td class="diffstat-graph">
134 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
134 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
135 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
135 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
136 </td>
136 </td>
137 </tr>
137 </tr>
138 </table>
138 </table>
139 </div>
139 </div>
140 </td>
140 </td>
141 </tr>
141 </tr>
142 </table>
142 </table>
143
143
144 <div class="overflow">
144 <div class="overflow">
145 <div class="sourcefirst"> line diff</div>
145 <div class="sourcefirst"> line diff</div>
146
146
147 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
147 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
148 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
148 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
149 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
149 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
150 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
150 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
151 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
151 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> <span class="minusline">--- /dev/null Thu Jan 01 00:00:00 1970 +0000
152 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
152 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
153 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
153 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
154 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
154 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
155 </span></pre></div>
155 </span></pre></div>
156 </div>
156 </div>
157
157
158 </div>
158 </div>
159 </div>
159 </div>
160 <script type="text/javascript">process_dates()</script>
160 <script type="text/javascript">process_dates()</script>
161
161
162
162
163 </body>
163 </body>
164 </html>
164 </html>
165
165
166
166
167 raw revision
167 raw revision
168
168
169 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
169 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
170 200 Script output follows
170 200 Script output follows
171
171
172
172
173 # HG changeset patch
173 # HG changeset patch
174 # User test
174 # User test
175 # Date 0 0
175 # Date 0 0
176 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
176 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
177
177
178 a
178 a
179
179
180 diff -r 000000000000 -r 0cd96de13884 a
180 diff -r 000000000000 -r 0cd96de13884 a
181 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
181 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
182 +++ b/a Thu Jan 01 00:00:00 1970 +0000
182 +++ b/a Thu Jan 01 00:00:00 1970 +0000
183 @@ -0,0 +1,1 @@
183 @@ -0,0 +1,1 @@
184 +a
184 +a
185 diff -r 000000000000 -r 0cd96de13884 b
185 diff -r 000000000000 -r 0cd96de13884 b
186 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
186 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
187 +++ b/b Thu Jan 01 00:00:00 1970 +0000
187 +++ b/b Thu Jan 01 00:00:00 1970 +0000
188 @@ -0,0 +1,1 @@
188 @@ -0,0 +1,1 @@
189 +b
189 +b
190
190
191
191
192 diff removed file
192 diff removed file
193
193
194 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
194 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/b'
195 200 Script output follows
195 200 Script output follows
196
196
197 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
197 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
198 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
198 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
199 <head>
199 <head>
200 <link rel="icon" href="/static/hgicon.png" type="image/png" />
200 <link rel="icon" href="/static/hgicon.png" type="image/png" />
201 <meta name="robots" content="index, nofollow" />
201 <meta name="robots" content="index, nofollow" />
202 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
202 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
203 <script type="text/javascript" src="/static/mercurial.js"></script>
203 <script type="text/javascript" src="/static/mercurial.js"></script>
204
204
205 <title>test: b diff</title>
205 <title>test: b diff</title>
206 </head>
206 </head>
207 <body>
207 <body>
208
208
209 <div class="container">
209 <div class="container">
210 <div class="menu">
210 <div class="menu">
211 <div class="logo">
211 <div class="logo">
212 <a href="http://mercurial.selenic.com/">
212 <a href="http://mercurial.selenic.com/">
213 <img src="/static/hglogo.png" alt="mercurial" /></a>
213 <img src="/static/hglogo.png" alt="mercurial" /></a>
214 </div>
214 </div>
215 <ul>
215 <ul>
216 <li><a href="/shortlog/559edbd9ed20">log</a></li>
216 <li><a href="/shortlog/559edbd9ed20">log</a></li>
217 <li><a href="/graph/559edbd9ed20">graph</a></li>
217 <li><a href="/graph/559edbd9ed20">graph</a></li>
218 <li><a href="/tags">tags</a></li>
218 <li><a href="/tags">tags</a></li>
219 <li><a href="/bookmarks">bookmarks</a></li>
219 <li><a href="/bookmarks">bookmarks</a></li>
220 <li><a href="/branches">branches</a></li>
220 <li><a href="/branches">branches</a></li>
221 </ul>
221 </ul>
222 <ul>
222 <ul>
223 <li><a href="/rev/559edbd9ed20">changeset</a></li>
223 <li><a href="/rev/559edbd9ed20">changeset</a></li>
224 <li><a href="/file/559edbd9ed20">browse</a></li>
224 <li><a href="/file/559edbd9ed20">browse</a></li>
225 </ul>
225 </ul>
226 <ul>
226 <ul>
227 <li><a href="/file/559edbd9ed20/b">file</a></li>
227 <li><a href="/file/559edbd9ed20/b">file</a></li>
228 <li><a href="/file/tip/b">latest</a></li>
228 <li><a href="/file/tip/b">latest</a></li>
229 <li class="active">diff</li>
229 <li class="active">diff</li>
230 <li><a href="/comparison/559edbd9ed20/b">comparison</a></li>
230 <li><a href="/comparison/559edbd9ed20/b">comparison</a></li>
231 <li><a href="/annotate/559edbd9ed20/b">annotate</a></li>
231 <li><a href="/annotate/559edbd9ed20/b">annotate</a></li>
232 <li><a href="/log/559edbd9ed20/b">file log</a></li>
232 <li><a href="/log/559edbd9ed20/b">file log</a></li>
233 <li><a href="/raw-file/559edbd9ed20/b">raw</a></li>
233 <li><a href="/raw-file/559edbd9ed20/b">raw</a></li>
234 </ul>
234 </ul>
235 <ul>
235 <ul>
236 <li><a href="/help">help</a></li>
236 <li><a href="/help">help</a></li>
237 </ul>
237 </ul>
238 </div>
238 </div>
239
239
240 <div class="main">
240 <div class="main">
241 <h2><a href="/">test</a></h2>
241 <h2><a href="/">test</a></h2>
242 <h3>diff b @ 1:559edbd9ed20</h3>
242 <h3>diff b @ 1:559edbd9ed20</h3>
243
243
244 <form class="search" action="/log">
244 <form class="search" action="/log">
245 <p></p>
245 <p></p>
246 <p><input name="rev" id="search1" type="text" size="30" /></p>
246 <p><input name="rev" id="search1" type="text" size="30" /></p>
247 <div id="hint">find changesets by author, revision,
247 <div id="hint">find changesets by author, revision,
248 files, or words in the commit message</div>
248 files, or words in the commit message</div>
249 </form>
249 </form>
250
250
251 <div class="description">b</div>
251 <div class="description">b</div>
252
252
253 <table id="changesetEntry">
253 <table id="changesetEntry">
254 <tr>
254 <tr>
255 <th>author</th>
255 <th>author</th>
256 <td>&#116;&#101;&#115;&#116;</td>
256 <td>&#116;&#101;&#115;&#116;</td>
257 </tr>
257 </tr>
258 <tr>
258 <tr>
259 <th>date</th>
259 <th>date</th>
260 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
260 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
261 </tr>
261 </tr>
262 <tr>
262 <tr>
263 <th>parents</th>
263 <th>parents</th>
264 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
264 <td><a href="/file/0cd96de13884/b">0cd96de13884</a> </td>
265 </tr>
265 </tr>
266 <tr>
266 <tr>
267 <th>children</th>
267 <th>children</th>
268 <td></td>
268 <td></td>
269 </tr>
269 </tr>
270
270
271 </table>
271 </table>
272
272
273 <div class="overflow">
273 <div class="overflow">
274 <div class="sourcefirst"> line diff</div>
274 <div class="sourcefirst"> line diff</div>
275
275
276 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000
276 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> <span class="minusline">--- a/b Thu Jan 01 00:00:00 1970 +0000
277 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
277 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
278 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
278 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -1,1 +0,0 @@
279 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-b
279 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="minusline">-b
280 </span></pre></div>
280 </span></pre></div>
281 </div>
281 </div>
282 </div>
282 </div>
283 </div>
283 </div>
284
284
285 <script type="text/javascript">process_dates()</script>
285 <script type="text/javascript">process_dates()</script>
286
286
287
287
288 </body>
288 </body>
289 </html>
289 </html>
290
290
291
291
292 set up hgweb with git diffs
292 set up hgweb with git diffs
293
293
294 $ "$TESTDIR/killdaemons.py"
294 $ "$TESTDIR/killdaemons.py"
295 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
295 $ hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
296 $ cat hg.pid >> $DAEMON_PIDS
296 $ cat hg.pid >> $DAEMON_PIDS
297
297
298 revision
298 revision
299
299
300 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
300 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'rev/0'
301 200 Script output follows
301 200 Script output follows
302
302
303 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
303 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
304 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
304 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
305 <head>
305 <head>
306 <link rel="icon" href="/static/hgicon.png" type="image/png" />
306 <link rel="icon" href="/static/hgicon.png" type="image/png" />
307 <meta name="robots" content="index, nofollow" />
307 <meta name="robots" content="index, nofollow" />
308 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
308 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
309 <script type="text/javascript" src="/static/mercurial.js"></script>
309 <script type="text/javascript" src="/static/mercurial.js"></script>
310
310
311 <title>test: 0cd96de13884</title>
311 <title>test: 0cd96de13884</title>
312 </head>
312 </head>
313 <body>
313 <body>
314 <div class="container">
314 <div class="container">
315 <div class="menu">
315 <div class="menu">
316 <div class="logo">
316 <div class="logo">
317 <a href="http://mercurial.selenic.com/">
317 <a href="http://mercurial.selenic.com/">
318 <img src="/static/hglogo.png" alt="mercurial" /></a>
318 <img src="/static/hglogo.png" alt="mercurial" /></a>
319 </div>
319 </div>
320 <ul>
320 <ul>
321 <li><a href="/shortlog/0cd96de13884">log</a></li>
321 <li><a href="/shortlog/0cd96de13884">log</a></li>
322 <li><a href="/graph/0cd96de13884">graph</a></li>
322 <li><a href="/graph/0cd96de13884">graph</a></li>
323 <li><a href="/tags">tags</a></li>
323 <li><a href="/tags">tags</a></li>
324 <li><a href="/bookmarks">bookmarks</a></li>
324 <li><a href="/bookmarks">bookmarks</a></li>
325 <li><a href="/branches">branches</a></li>
325 <li><a href="/branches">branches</a></li>
326 </ul>
326 </ul>
327 <ul>
327 <ul>
328 <li class="active">changeset</li>
328 <li class="active">changeset</li>
329 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
329 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
330 <li><a href="/file/0cd96de13884">browse</a></li>
330 <li><a href="/file/0cd96de13884">browse</a></li>
331 </ul>
331 </ul>
332 <ul>
332 <ul>
333
333
334 </ul>
334 </ul>
335 <ul>
335 <ul>
336 <li><a href="/help">help</a></li>
336 <li><a href="/help">help</a></li>
337 </ul>
337 </ul>
338 </div>
338 </div>
339
339
340 <div class="main">
340 <div class="main">
341
341
342 <h2><a href="/">test</a></h2>
342 <h2><a href="/">test</a></h2>
343 <h3>changeset 0:0cd96de13884 </h3>
343 <h3>changeset 0:0cd96de13884 </h3>
344
344
345 <form class="search" action="/log">
345 <form class="search" action="/log">
346
346
347 <p><input name="rev" id="search1" type="text" size="30" /></p>
347 <p><input name="rev" id="search1" type="text" size="30" /></p>
348 <div id="hint">find changesets by author, revision,
348 <div id="hint">find changesets by author, revision,
349 files, or words in the commit message</div>
349 files, or words in the commit message</div>
350 </form>
350 </form>
351
351
352 <div class="description">a</div>
352 <div class="description">a</div>
353
353
354 <table id="changesetEntry">
354 <table id="changesetEntry">
355 <tr>
355 <tr>
356 <th class="author">author</th>
356 <th class="author">author</th>
357 <td class="author">&#116;&#101;&#115;&#116;</td>
357 <td class="author">&#116;&#101;&#115;&#116;</td>
358 </tr>
358 </tr>
359 <tr>
359 <tr>
360 <th class="date">date</th>
360 <th class="date">date</th>
361 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
361 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td></tr>
362 <tr>
362 <tr>
363 <th class="author">parents</th>
363 <th class="author">parents</th>
364 <td class="author"></td>
364 <td class="author"></td>
365 </tr>
365 </tr>
366 <tr>
366 <tr>
367 <th class="author">children</th>
367 <th class="author">children</th>
368 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
368 <td class="author"> <a href="/rev/559edbd9ed20">559edbd9ed20</a></td>
369 </tr>
369 </tr>
370 <tr>
370 <tr>
371 <th class="files">files</th>
371 <th class="files">files</th>
372 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
372 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
373 </tr>
373 </tr>
374 <tr>
374 <tr>
375 <th class="diffstat">diffstat</th>
375 <th class="diffstat">diffstat</th>
376 <td class="diffstat">
376 <td class="diffstat">
377 2 files changed, 2 insertions(+), 0 deletions(-)
377 2 files changed, 2 insertions(+), 0 deletions(-)
378
378
379 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
379 <a id="diffstatexpand" href="javascript:showDiffstat()"/>[<tt>+</tt>]</a>
380 <div id="diffstatdetails" style="display:none;">
380 <div id="diffstatdetails" style="display:none;">
381 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
381 <a href="javascript:hideDiffstat()"/>[<tt>-</tt>]</a>
382 <p>
382 <p>
383 <table> <tr class="parity0">
383 <table> <tr class="parity0">
384 <td class="diffstat-file"><a href="#l1.1">a</a></td>
384 <td class="diffstat-file"><a href="#l1.1">a</a></td>
385 <td class="diffstat-total" align="right">1</td>
385 <td class="diffstat-total" align="right">1</td>
386 <td class="diffstat-graph">
386 <td class="diffstat-graph">
387 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
387 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
388 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
388 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
389 </td>
389 </td>
390 </tr>
390 </tr>
391 <tr class="parity1">
391 <tr class="parity1">
392 <td class="diffstat-file"><a href="#l2.1">b</a></td>
392 <td class="diffstat-file"><a href="#l2.1">b</a></td>
393 <td class="diffstat-total" align="right">1</td>
393 <td class="diffstat-total" align="right">1</td>
394 <td class="diffstat-graph">
394 <td class="diffstat-graph">
395 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
395 <span class="diffstat-add" style="width:100.0%;">&nbsp;</span>
396 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
396 <span class="diffstat-remove" style="width:0.0%;">&nbsp;</span>
397 </td>
397 </td>
398 </tr>
398 </tr>
399 </table>
399 </table>
400 </div>
400 </div>
401 </td>
401 </td>
402 </tr>
402 </tr>
403 </table>
403 </table>
404
404
405 <div class="overflow">
405 <div class="overflow">
406 <div class="sourcefirst"> line diff</div>
406 <div class="sourcefirst"> line diff</div>
407
407
408 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
408 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
409 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
409 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
410 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
410 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
411 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
411 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
412 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
412 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
413 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
413 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
414 <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
414 <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
415 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
415 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
416 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
416 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
417 </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
417 </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
418 </span></pre></div>
418 </span></pre></div>
419 </div>
419 </div>
420
420
421 </div>
421 </div>
422 </div>
422 </div>
423 <script type="text/javascript">process_dates()</script>
423 <script type="text/javascript">process_dates()</script>
424
424
425
425
426 </body>
426 </body>
427 </html>
427 </html>
428
428
429
429
430 revision
430 revision
431
431
432 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
432 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
433 200 Script output follows
433 200 Script output follows
434
434
435
435
436 # HG changeset patch
436 # HG changeset patch
437 # User test
437 # User test
438 # Date 0 0
438 # Date 0 0
439 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
439 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
440
440
441 a
441 a
442
442
443 diff --git a/a b/a
443 diff --git a/a b/a
444 new file mode 100644
444 new file mode 100644
445 --- /dev/null
445 --- /dev/null
446 +++ b/a
446 +++ b/a
447 @@ -0,0 +1,1 @@
447 @@ -0,0 +1,1 @@
448 +a
448 +a
449 diff --git a/b b/b
449 diff --git a/b b/b
450 new file mode 100644
450 new file mode 100644
451 --- /dev/null
451 --- /dev/null
452 +++ b/b
452 +++ b/b
453 @@ -0,0 +1,1 @@
453 @@ -0,0 +1,1 @@
454 +b
454 +b
455
455
456
456
457 diff removed file
457 diff removed file
458
458
459 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
459 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'diff/tip/a'
460 200 Script output follows
460 200 Script output follows
461
461
462 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
462 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
463 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
463 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
464 <head>
464 <head>
465 <link rel="icon" href="/static/hgicon.png" type="image/png" />
465 <link rel="icon" href="/static/hgicon.png" type="image/png" />
466 <meta name="robots" content="index, nofollow" />
466 <meta name="robots" content="index, nofollow" />
467 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
467 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
468 <script type="text/javascript" src="/static/mercurial.js"></script>
468 <script type="text/javascript" src="/static/mercurial.js"></script>
469
469
470 <title>test: a diff</title>
470 <title>test: a diff</title>
471 </head>
471 </head>
472 <body>
472 <body>
473
473
474 <div class="container">
474 <div class="container">
475 <div class="menu">
475 <div class="menu">
476 <div class="logo">
476 <div class="logo">
477 <a href="http://mercurial.selenic.com/">
477 <a href="http://mercurial.selenic.com/">
478 <img src="/static/hglogo.png" alt="mercurial" /></a>
478 <img src="/static/hglogo.png" alt="mercurial" /></a>
479 </div>
479 </div>
480 <ul>
480 <ul>
481 <li><a href="/shortlog/559edbd9ed20">log</a></li>
481 <li><a href="/shortlog/559edbd9ed20">log</a></li>
482 <li><a href="/graph/559edbd9ed20">graph</a></li>
482 <li><a href="/graph/559edbd9ed20">graph</a></li>
483 <li><a href="/tags">tags</a></li>
483 <li><a href="/tags">tags</a></li>
484 <li><a href="/bookmarks">bookmarks</a></li>
484 <li><a href="/bookmarks">bookmarks</a></li>
485 <li><a href="/branches">branches</a></li>
485 <li><a href="/branches">branches</a></li>
486 </ul>
486 </ul>
487 <ul>
487 <ul>
488 <li><a href="/rev/559edbd9ed20">changeset</a></li>
488 <li><a href="/rev/559edbd9ed20">changeset</a></li>
489 <li><a href="/file/559edbd9ed20">browse</a></li>
489 <li><a href="/file/559edbd9ed20">browse</a></li>
490 </ul>
490 </ul>
491 <ul>
491 <ul>
492 <li><a href="/file/559edbd9ed20/a">file</a></li>
492 <li><a href="/file/559edbd9ed20/a">file</a></li>
493 <li><a href="/file/tip/a">latest</a></li>
493 <li><a href="/file/tip/a">latest</a></li>
494 <li class="active">diff</li>
494 <li class="active">diff</li>
495 <li><a href="/comparison/559edbd9ed20/a">comparison</a></li>
495 <li><a href="/comparison/559edbd9ed20/a">comparison</a></li>
496 <li><a href="/annotate/559edbd9ed20/a">annotate</a></li>
496 <li><a href="/annotate/559edbd9ed20/a">annotate</a></li>
497 <li><a href="/log/559edbd9ed20/a">file log</a></li>
497 <li><a href="/log/559edbd9ed20/a">file log</a></li>
498 <li><a href="/raw-file/559edbd9ed20/a">raw</a></li>
498 <li><a href="/raw-file/559edbd9ed20/a">raw</a></li>
499 </ul>
499 </ul>
500 <ul>
500 <ul>
501 <li><a href="/help">help</a></li>
501 <li><a href="/help">help</a></li>
502 </ul>
502 </ul>
503 </div>
503 </div>
504
504
505 <div class="main">
505 <div class="main">
506 <h2><a href="/">test</a></h2>
506 <h2><a href="/">test</a></h2>
507 <h3>diff a @ 1:559edbd9ed20</h3>
507 <h3>diff a @ 1:559edbd9ed20</h3>
508
508
509 <form class="search" action="/log">
509 <form class="search" action="/log">
510 <p></p>
510 <p></p>
511 <p><input name="rev" id="search1" type="text" size="30" /></p>
511 <p><input name="rev" id="search1" type="text" size="30" /></p>
512 <div id="hint">find changesets by author, revision,
512 <div id="hint">find changesets by author, revision,
513 files, or words in the commit message</div>
513 files, or words in the commit message</div>
514 </form>
514 </form>
515
515
516 <div class="description">b</div>
516 <div class="description">b</div>
517
517
518 <table id="changesetEntry">
518 <table id="changesetEntry">
519 <tr>
519 <tr>
520 <th>author</th>
520 <th>author</th>
521 <td>&#116;&#101;&#115;&#116;</td>
521 <td>&#116;&#101;&#115;&#116;</td>
522 </tr>
522 </tr>
523 <tr>
523 <tr>
524 <th>date</th>
524 <th>date</th>
525 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
525 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
526 </tr>
526 </tr>
527 <tr>
527 <tr>
528 <th>parents</th>
528 <th>parents</th>
529 <td></td>
529 <td></td>
530 </tr>
530 </tr>
531 <tr>
531 <tr>
532 <th>children</th>
532 <th>children</th>
533 <td></td>
533 <td></td>
534 </tr>
534 </tr>
535
535
536 </table>
536 </table>
537
537
538 <div class="overflow">
538 <div class="overflow">
539 <div class="sourcefirst"> line diff</div>
539 <div class="sourcefirst"> line diff</div>
540
540
541 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> old mode 100644
541 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> old mode 100644
542 <a href="#l1.2" id="l1.2"> 1.2</a> new mode 100755
542 <a href="#l1.2" id="l1.2"> 1.2</a> new mode 100755
543 </pre></div>
543 </pre></div>
544 </div>
544 </div>
545 </div>
545 </div>
546 </div>
546 </div>
547
547
548 <script type="text/javascript">process_dates()</script>
548 <script type="text/javascript">process_dates()</script>
549
549
550
550
551 </body>
551 </body>
552 </html>
552 </html>
553
553
554
554
555 comparison new file
555 comparison new file
556
556
557 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
557 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/0/a'
558 200 Script output follows
558 200 Script output follows
559
559
560 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
560 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
561 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
561 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
562 <head>
562 <head>
563 <link rel="icon" href="/static/hgicon.png" type="image/png" />
563 <link rel="icon" href="/static/hgicon.png" type="image/png" />
564 <meta name="robots" content="index, nofollow" />
564 <meta name="robots" content="index, nofollow" />
565 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
565 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
566 <script type="text/javascript" src="/static/mercurial.js"></script>
566 <script type="text/javascript" src="/static/mercurial.js"></script>
567
567
568 <title>test: a comparison</title>
568 <title>test: a comparison</title>
569 </head>
569 </head>
570 <body>
570 <body>
571
571
572 <div class="container">
572 <div class="container">
573 <div class="menu">
573 <div class="menu">
574 <div class="logo">
574 <div class="logo">
575 <a href="http://mercurial.selenic.com/">
575 <a href="http://mercurial.selenic.com/">
576 <img src="/static/hglogo.png" alt="mercurial" /></a>
576 <img src="/static/hglogo.png" alt="mercurial" /></a>
577 </div>
577 </div>
578 <ul>
578 <ul>
579 <li><a href="/shortlog/0cd96de13884">log</a></li>
579 <li><a href="/shortlog/0cd96de13884">log</a></li>
580 <li><a href="/graph/0cd96de13884">graph</a></li>
580 <li><a href="/graph/0cd96de13884">graph</a></li>
581 <li><a href="/tags">tags</a></li>
581 <li><a href="/tags">tags</a></li>
582 <li><a href="/bookmarks">bookmarks</a></li>
582 <li><a href="/bookmarks">bookmarks</a></li>
583 <li><a href="/branches">branches</a></li>
583 <li><a href="/branches">branches</a></li>
584 </ul>
584 </ul>
585 <ul>
585 <ul>
586 <li><a href="/rev/0cd96de13884">changeset</a></li>
586 <li><a href="/rev/0cd96de13884">changeset</a></li>
587 <li><a href="/file/0cd96de13884">browse</a></li>
587 <li><a href="/file/0cd96de13884">browse</a></li>
588 </ul>
588 </ul>
589 <ul>
589 <ul>
590 <li><a href="/file/0cd96de13884/a">file</a></li>
590 <li><a href="/file/0cd96de13884/a">file</a></li>
591 <li><a href="/file/tip/a">latest</a></li>
591 <li><a href="/file/tip/a">latest</a></li>
592 <li><a href="/diff/0cd96de13884/a">diff</a></li>
592 <li><a href="/diff/0cd96de13884/a">diff</a></li>
593 <li class="active">comparison</li>
593 <li class="active">comparison</li>
594 <li><a href="/annotate/0cd96de13884/a">annotate</a></li>
594 <li><a href="/annotate/0cd96de13884/a">annotate</a></li>
595 <li><a href="/log/0cd96de13884/a">file log</a></li>
595 <li><a href="/log/0cd96de13884/a">file log</a></li>
596 <li><a href="/raw-file/0cd96de13884/a">raw</a></li>
596 <li><a href="/raw-file/0cd96de13884/a">raw</a></li>
597 </ul>
597 </ul>
598 <ul>
598 <ul>
599 <li><a href="/help">help</a></li>
599 <li><a href="/help">help</a></li>
600 </ul>
600 </ul>
601 </div>
601 </div>
602
602
603 <div class="main">
603 <div class="main">
604 <h2><a href="/">test</a></h2>
604 <h2><a href="/">test</a></h2>
605 <h3>comparison a @ 0:0cd96de13884</h3>
605 <h3>comparison a @ 0:0cd96de13884</h3>
606
606
607 <form class="search" action="/log">
607 <form class="search" action="/log">
608 <p></p>
608 <p></p>
609 <p><input name="rev" id="search1" type="text" size="30" /></p>
609 <p><input name="rev" id="search1" type="text" size="30" /></p>
610 <div id="hint">find changesets by author, revision,
610 <div id="hint">find changesets by author, revision,
611 files, or words in the commit message</div>
611 files, or words in the commit message</div>
612 </form>
612 </form>
613
613
614 <div class="description">a</div>
614 <div class="description">a</div>
615
615
616 <table id="changesetEntry">
616 <table id="changesetEntry">
617 <tr>
617 <tr>
618 <th>author</th>
618 <th>author</th>
619 <td>&#116;&#101;&#115;&#116;</td>
619 <td>&#116;&#101;&#115;&#116;</td>
620 </tr>
620 </tr>
621 <tr>
621 <tr>
622 <th>date</th>
622 <th>date</th>
623 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
623 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
624 </tr>
624 </tr>
625 <tr>
625 <tr>
626 <th>parents</th>
626 <th>parents</th>
627 <td></td>
627 <td></td>
628 </tr>
628 </tr>
629 <tr>
629 <tr>
630 <th>children</th>
630 <th>children</th>
631 <td><a href="/file/559edbd9ed20/a">559edbd9ed20</a> </td>
631 <td></td>
632 </tr>
632 </tr>
633
633
634 </table>
634 </table>
635
635
636 <div class="overflow">
636 <div class="overflow">
637 <div class="sourcefirst"> comparison</div>
637 <div class="sourcefirst"> comparison</div>
638 <div class="legend">
638 <div class="legend">
639 <span class="legendinfo equal">equal</span>
639 <span class="legendinfo equal">equal</span>
640 <span class="legendinfo delete">deleted</span>
640 <span class="legendinfo delete">deleted</span>
641 <span class="legendinfo insert">inserted</span>
641 <span class="legendinfo insert">inserted</span>
642 <span class="legendinfo replace">replaced</span>
642 <span class="legendinfo replace">replaced</span>
643 </div>
643 </div>
644
644
645 <table class="bigtable">
645 <table class="bigtable">
646 <thead class="header">
646 <thead class="header">
647 <tr>
647 <tr>
648 <th>-1:000000000000</th>
648 <th>-1:000000000000</th>
649 <th>0:b789fdd96dc2</th>
649 <th>0:b789fdd96dc2</th>
650 </tr>
650 </tr>
651 </thead>
651 </thead>
652
652
653 <tbody class="block">
653 <tbody class="block">
654
654
655 <tr>
655 <tr>
656 <td class="source insert"><a href="#r1" id="r1"> </a> </td>
656 <td class="source insert"><a href="#r1" id="r1"> </a> </td>
657 <td class="source insert"><a href="#r1" id="r1"> 1</a> a</td>
657 <td class="source insert"><a href="#r1" id="r1"> 1</a> a</td>
658 </tr>
658 </tr>
659 </tbody>
659 </tbody>
660 </table>
660 </table>
661
661
662 </div>
662 </div>
663 </div>
663 </div>
664 </div>
664 </div>
665
665
666 <script type="text/javascript">process_dates()</script>
666 <script type="text/javascript">process_dates()</script>
667
667
668
668
669 </body>
669 </body>
670 </html>
670 </html>
671
671
672
672
673 comparison existing file
673 comparison existing file
674
674
675 $ hg up
675 $ hg up
676 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
676 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 $ echo a >> a
677 $ echo a >> a
678 $ hg ci -mc
678 $ hg ci -mc
679 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
679 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
680 200 Script output follows
680 200 Script output follows
681
681
682 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
682 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
683 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
683 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
684 <head>
684 <head>
685 <link rel="icon" href="/static/hgicon.png" type="image/png" />
685 <link rel="icon" href="/static/hgicon.png" type="image/png" />
686 <meta name="robots" content="index, nofollow" />
686 <meta name="robots" content="index, nofollow" />
687 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
687 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
688 <script type="text/javascript" src="/static/mercurial.js"></script>
688 <script type="text/javascript" src="/static/mercurial.js"></script>
689
689
690 <title>test: a comparison</title>
690 <title>test: a comparison</title>
691 </head>
691 </head>
692 <body>
692 <body>
693
693
694 <div class="container">
694 <div class="container">
695 <div class="menu">
695 <div class="menu">
696 <div class="logo">
696 <div class="logo">
697 <a href="http://mercurial.selenic.com/">
697 <a href="http://mercurial.selenic.com/">
698 <img src="/static/hglogo.png" alt="mercurial" /></a>
698 <img src="/static/hglogo.png" alt="mercurial" /></a>
699 </div>
699 </div>
700 <ul>
700 <ul>
701 <li><a href="/shortlog/d73db4d812ff">log</a></li>
701 <li><a href="/shortlog/d73db4d812ff">log</a></li>
702 <li><a href="/graph/d73db4d812ff">graph</a></li>
702 <li><a href="/graph/d73db4d812ff">graph</a></li>
703 <li><a href="/tags">tags</a></li>
703 <li><a href="/tags">tags</a></li>
704 <li><a href="/bookmarks">bookmarks</a></li>
704 <li><a href="/bookmarks">bookmarks</a></li>
705 <li><a href="/branches">branches</a></li>
705 <li><a href="/branches">branches</a></li>
706 </ul>
706 </ul>
707 <ul>
707 <ul>
708 <li><a href="/rev/d73db4d812ff">changeset</a></li>
708 <li><a href="/rev/d73db4d812ff">changeset</a></li>
709 <li><a href="/file/d73db4d812ff">browse</a></li>
709 <li><a href="/file/d73db4d812ff">browse</a></li>
710 </ul>
710 </ul>
711 <ul>
711 <ul>
712 <li><a href="/file/d73db4d812ff/a">file</a></li>
712 <li><a href="/file/d73db4d812ff/a">file</a></li>
713 <li><a href="/file/tip/a">latest</a></li>
713 <li><a href="/file/tip/a">latest</a></li>
714 <li><a href="/diff/d73db4d812ff/a">diff</a></li>
714 <li><a href="/diff/d73db4d812ff/a">diff</a></li>
715 <li class="active">comparison</li>
715 <li class="active">comparison</li>
716 <li><a href="/annotate/d73db4d812ff/a">annotate</a></li>
716 <li><a href="/annotate/d73db4d812ff/a">annotate</a></li>
717 <li><a href="/log/d73db4d812ff/a">file log</a></li>
717 <li><a href="/log/d73db4d812ff/a">file log</a></li>
718 <li><a href="/raw-file/d73db4d812ff/a">raw</a></li>
718 <li><a href="/raw-file/d73db4d812ff/a">raw</a></li>
719 </ul>
719 </ul>
720 <ul>
720 <ul>
721 <li><a href="/help">help</a></li>
721 <li><a href="/help">help</a></li>
722 </ul>
722 </ul>
723 </div>
723 </div>
724
724
725 <div class="main">
725 <div class="main">
726 <h2><a href="/">test</a></h2>
726 <h2><a href="/">test</a></h2>
727 <h3>comparison a @ 2:d73db4d812ff</h3>
727 <h3>comparison a @ 2:d73db4d812ff</h3>
728
728
729 <form class="search" action="/log">
729 <form class="search" action="/log">
730 <p></p>
730 <p></p>
731 <p><input name="rev" id="search1" type="text" size="30" /></p>
731 <p><input name="rev" id="search1" type="text" size="30" /></p>
732 <div id="hint">find changesets by author, revision,
732 <div id="hint">find changesets by author, revision,
733 files, or words in the commit message</div>
733 files, or words in the commit message</div>
734 </form>
734 </form>
735
735
736 <div class="description">c</div>
736 <div class="description">c</div>
737
737
738 <table id="changesetEntry">
738 <table id="changesetEntry">
739 <tr>
739 <tr>
740 <th>author</th>
740 <th>author</th>
741 <td>&#116;&#101;&#115;&#116;</td>
741 <td>&#116;&#101;&#115;&#116;</td>
742 </tr>
742 </tr>
743 <tr>
743 <tr>
744 <th>date</th>
744 <th>date</th>
745 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
745 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
746 </tr>
746 </tr>
747 <tr>
747 <tr>
748 <th>parents</th>
748 <th>parents</th>
749 <td><a href="/file/559edbd9ed20/a">559edbd9ed20</a> </td>
749 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
750 </tr>
750 </tr>
751 <tr>
751 <tr>
752 <th>children</th>
752 <th>children</th>
753 <td></td>
753 <td></td>
754 </tr>
754 </tr>
755
755
756 </table>
756 </table>
757
757
758 <div class="overflow">
758 <div class="overflow">
759 <div class="sourcefirst"> comparison</div>
759 <div class="sourcefirst"> comparison</div>
760 <div class="legend">
760 <div class="legend">
761 <span class="legendinfo equal">equal</span>
761 <span class="legendinfo equal">equal</span>
762 <span class="legendinfo delete">deleted</span>
762 <span class="legendinfo delete">deleted</span>
763 <span class="legendinfo insert">inserted</span>
763 <span class="legendinfo insert">inserted</span>
764 <span class="legendinfo replace">replaced</span>
764 <span class="legendinfo replace">replaced</span>
765 </div>
765 </div>
766
766
767 <table class="bigtable">
767 <table class="bigtable">
768 <thead class="header">
768 <thead class="header">
769 <tr>
769 <tr>
770 <th>0:b789fdd96dc2</th>
770 <th>0:b789fdd96dc2</th>
771 <th>1:a80d06849b33</th>
771 <th>1:a80d06849b33</th>
772 </tr>
772 </tr>
773 </thead>
773 </thead>
774
774
775 <tbody class="block">
775 <tbody class="block">
776
776
777 <tr>
777 <tr>
778 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
778 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
779 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
779 <td class="source equal"><a href="#l1r1" id="l1r1"> 1</a> a</td>
780 </tr>
780 </tr>
781 <tr>
781 <tr>
782 <td class="source insert"><a href="#r2" id="r2"> </a> </td>
782 <td class="source insert"><a href="#r2" id="r2"> </a> </td>
783 <td class="source insert"><a href="#r2" id="r2"> 2</a> a</td>
783 <td class="source insert"><a href="#r2" id="r2"> 2</a> a</td>
784 </tr>
784 </tr>
785 </tbody>
785 </tbody>
786 </table>
786 </table>
787
787
788 </div>
788 </div>
789 </div>
789 </div>
790 </div>
790 </div>
791
791
792 <script type="text/javascript">process_dates()</script>
792 <script type="text/javascript">process_dates()</script>
793
793
794
794
795 </body>
795 </body>
796 </html>
796 </html>
797
797
798
798
799 comparison removed file
799 comparison removed file
800
800
801 $ hg rm a
801 $ hg rm a
802 $ hg ci -md
802 $ hg ci -md
803 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
803 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'comparison/tip/a'
804 200 Script output follows
804 200 Script output follows
805
805
806 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
806 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
807 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
807 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
808 <head>
808 <head>
809 <link rel="icon" href="/static/hgicon.png" type="image/png" />
809 <link rel="icon" href="/static/hgicon.png" type="image/png" />
810 <meta name="robots" content="index, nofollow" />
810 <meta name="robots" content="index, nofollow" />
811 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
811 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
812 <script type="text/javascript" src="/static/mercurial.js"></script>
812 <script type="text/javascript" src="/static/mercurial.js"></script>
813
813
814 <title>test: a comparison</title>
814 <title>test: a comparison</title>
815 </head>
815 </head>
816 <body>
816 <body>
817
817
818 <div class="container">
818 <div class="container">
819 <div class="menu">
819 <div class="menu">
820 <div class="logo">
820 <div class="logo">
821 <a href="http://mercurial.selenic.com/">
821 <a href="http://mercurial.selenic.com/">
822 <img src="/static/hglogo.png" alt="mercurial" /></a>
822 <img src="/static/hglogo.png" alt="mercurial" /></a>
823 </div>
823 </div>
824 <ul>
824 <ul>
825 <li><a href="/shortlog/20e80271eb7a">log</a></li>
825 <li><a href="/shortlog/20e80271eb7a">log</a></li>
826 <li><a href="/graph/20e80271eb7a">graph</a></li>
826 <li><a href="/graph/20e80271eb7a">graph</a></li>
827 <li><a href="/tags">tags</a></li>
827 <li><a href="/tags">tags</a></li>
828 <li><a href="/bookmarks">bookmarks</a></li>
828 <li><a href="/bookmarks">bookmarks</a></li>
829 <li><a href="/branches">branches</a></li>
829 <li><a href="/branches">branches</a></li>
830 </ul>
830 </ul>
831 <ul>
831 <ul>
832 <li><a href="/rev/20e80271eb7a">changeset</a></li>
832 <li><a href="/rev/20e80271eb7a">changeset</a></li>
833 <li><a href="/file/20e80271eb7a">browse</a></li>
833 <li><a href="/file/20e80271eb7a">browse</a></li>
834 </ul>
834 </ul>
835 <ul>
835 <ul>
836 <li><a href="/file/20e80271eb7a/a">file</a></li>
836 <li><a href="/file/20e80271eb7a/a">file</a></li>
837 <li><a href="/file/tip/a">latest</a></li>
837 <li><a href="/file/tip/a">latest</a></li>
838 <li><a href="/diff/20e80271eb7a/a">diff</a></li>
838 <li><a href="/diff/20e80271eb7a/a">diff</a></li>
839 <li class="active">comparison</li>
839 <li class="active">comparison</li>
840 <li><a href="/annotate/20e80271eb7a/a">annotate</a></li>
840 <li><a href="/annotate/20e80271eb7a/a">annotate</a></li>
841 <li><a href="/log/20e80271eb7a/a">file log</a></li>
841 <li><a href="/log/20e80271eb7a/a">file log</a></li>
842 <li><a href="/raw-file/20e80271eb7a/a">raw</a></li>
842 <li><a href="/raw-file/20e80271eb7a/a">raw</a></li>
843 </ul>
843 </ul>
844 <ul>
844 <ul>
845 <li><a href="/help">help</a></li>
845 <li><a href="/help">help</a></li>
846 </ul>
846 </ul>
847 </div>
847 </div>
848
848
849 <div class="main">
849 <div class="main">
850 <h2><a href="/">test</a></h2>
850 <h2><a href="/">test</a></h2>
851 <h3>comparison a @ 3:20e80271eb7a</h3>
851 <h3>comparison a @ 3:20e80271eb7a</h3>
852
852
853 <form class="search" action="/log">
853 <form class="search" action="/log">
854 <p></p>
854 <p></p>
855 <p><input name="rev" id="search1" type="text" size="30" /></p>
855 <p><input name="rev" id="search1" type="text" size="30" /></p>
856 <div id="hint">find changesets by author, revision,
856 <div id="hint">find changesets by author, revision,
857 files, or words in the commit message</div>
857 files, or words in the commit message</div>
858 </form>
858 </form>
859
859
860 <div class="description">d</div>
860 <div class="description">d</div>
861
861
862 <table id="changesetEntry">
862 <table id="changesetEntry">
863 <tr>
863 <tr>
864 <th>author</th>
864 <th>author</th>
865 <td>&#116;&#101;&#115;&#116;</td>
865 <td>&#116;&#101;&#115;&#116;</td>
866 </tr>
866 </tr>
867 <tr>
867 <tr>
868 <th>date</th>
868 <th>date</th>
869 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
869 <td class="date age">Thu, 01 Jan 1970 00:00:00 +0000</td>
870 </tr>
870 </tr>
871 <tr>
871 <tr>
872 <th>parents</th>
872 <th>parents</th>
873 <td><a href="/file/d73db4d812ff/a">d73db4d812ff</a> </td>
873 <td><a href="/file/0cd96de13884/a">0cd96de13884</a> </td>
874 </tr>
874 </tr>
875 <tr>
875 <tr>
876 <th>children</th>
876 <th>children</th>
877 <td></td>
877 <td></td>
878 </tr>
878 </tr>
879
879
880 </table>
880 </table>
881
881
882 <div class="overflow">
882 <div class="overflow">
883 <div class="sourcefirst"> comparison</div>
883 <div class="sourcefirst"> comparison</div>
884 <div class="legend">
884 <div class="legend">
885 <span class="legendinfo equal">equal</span>
885 <span class="legendinfo equal">equal</span>
886 <span class="legendinfo delete">deleted</span>
886 <span class="legendinfo delete">deleted</span>
887 <span class="legendinfo insert">inserted</span>
887 <span class="legendinfo insert">inserted</span>
888 <span class="legendinfo replace">replaced</span>
888 <span class="legendinfo replace">replaced</span>
889 </div>
889 </div>
890
890
891 <table class="bigtable">
891 <table class="bigtable">
892 <thead class="header">
892 <thead class="header">
893 <tr>
893 <tr>
894 <th>1:a80d06849b33</th>
894 <th>1:a80d06849b33</th>
895 <th>-1:000000000000</th>
895 <th>-1:000000000000</th>
896 </tr>
896 </tr>
897 </thead>
897 </thead>
898
898
899 <tbody class="block">
899 <tbody class="block">
900
900
901 <tr>
901 <tr>
902 <td class="source delete"><a href="#l1" id="l1"> 1</a> a</td>
902 <td class="source delete"><a href="#l1" id="l1"> 1</a> a</td>
903 <td class="source delete"><a href="#l1" id="l1"> </a> </td>
903 <td class="source delete"><a href="#l1" id="l1"> </a> </td>
904 </tr>
904 </tr>
905 <tr>
905 <tr>
906 <td class="source delete"><a href="#l2" id="l2"> 2</a> a</td>
906 <td class="source delete"><a href="#l2" id="l2"> 2</a> a</td>
907 <td class="source delete"><a href="#l2" id="l2"> </a> </td>
907 <td class="source delete"><a href="#l2" id="l2"> </a> </td>
908 </tr>
908 </tr>
909 </tbody>
909 </tbody>
910 </table>
910 </table>
911
911
912 </div>
912 </div>
913 </div>
913 </div>
914 </div>
914 </div>
915
915
916 <script type="text/javascript">process_dates()</script>
916 <script type="text/javascript">process_dates()</script>
917
917
918
918
919 </body>
919 </body>
920 </html>
920 </html>
921
921
922
922
923 $ cd ..
923 $ cd ..
924
924
925 test import rev as raw-rev
925 test import rev as raw-rev
926
926
927 $ hg clone -r0 test test1
927 $ hg clone -r0 test test1
928 adding changesets
928 adding changesets
929 adding manifests
929 adding manifests
930 adding file changes
930 adding file changes
931 added 1 changesets with 2 changes to 2 files
931 added 1 changesets with 2 changes to 2 files
932 updating to branch default
932 updating to branch default
933 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
933 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
934 $ cd test1
934 $ cd test1
935 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
935 $ hg import -q --bypass --exact http://localhost:$HGPORT/rev/1
936
936
937 raw revision with diff block numbers
937 raw revision with diff block numbers
938
938
939 $ "$TESTDIR/killdaemons.py"
939 $ "$TESTDIR/killdaemons.py"
940 $ cat <<EOF > .hg/hgrc
940 $ cat <<EOF > .hg/hgrc
941 > [web]
941 > [web]
942 > templates = rawdiff
942 > templates = rawdiff
943 > EOF
943 > EOF
944 $ mkdir rawdiff
944 $ mkdir rawdiff
945 $ cat <<EOF > rawdiff/map
945 $ cat <<EOF > rawdiff/map
946 > mimetype = 'text/plain; charset={encoding}'
946 > mimetype = 'text/plain; charset={encoding}'
947 > changeset = '{diff}'
947 > changeset = '{diff}'
948 > difflineplus = '{line}'
948 > difflineplus = '{line}'
949 > difflineminus = '{line}'
949 > difflineminus = '{line}'
950 > difflineat = '{line}'
950 > difflineat = '{line}'
951 > diffline = '{line}'
951 > diffline = '{line}'
952 > filenodelink = ''
952 > filenodelink = ''
953 > filenolink = ''
953 > filenolink = ''
954 > fileline = '{line}'
954 > fileline = '{line}'
955 > diffblock = 'Block: {blockno}\n{lines}\n'
955 > diffblock = 'Block: {blockno}\n{lines}\n'
956 > EOF
956 > EOF
957 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
957 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
958 $ cat hg.pid >> $DAEMON_PIDS
958 $ cat hg.pid >> $DAEMON_PIDS
959 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
959 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT 'raw-rev/0'
960 200 Script output follows
960 200 Script output follows
961
961
962 Block: 1
962 Block: 1
963 diff -r 000000000000 -r 0cd96de13884 a
963 diff -r 000000000000 -r 0cd96de13884 a
964 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
964 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
965 +++ b/a Thu Jan 01 00:00:00 1970 +0000
965 +++ b/a Thu Jan 01 00:00:00 1970 +0000
966 @@ -0,0 +1,1 @@
966 @@ -0,0 +1,1 @@
967 +a
967 +a
968
968
969 Block: 2
969 Block: 2
970 diff -r 000000000000 -r 0cd96de13884 b
970 diff -r 000000000000 -r 0cd96de13884 b
971 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
971 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
972 +++ b/b Thu Jan 01 00:00:00 1970 +0000
972 +++ b/b Thu Jan 01 00:00:00 1970 +0000
973 @@ -0,0 +1,1 @@
973 @@ -0,0 +1,1 @@
974 +b
974 +b
975
975
976 $ "$TESTDIR/killdaemons.py"
976 $ "$TESTDIR/killdaemons.py"
977 $ rm .hg/hgrc rawdiff/map
977 $ rm .hg/hgrc rawdiff/map
978 $ rmdir rawdiff
978 $ rmdir rawdiff
979 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
979 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
980 $ cat hg.pid >> $DAEMON_PIDS
980 $ cat hg.pid >> $DAEMON_PIDS
981
981
982 errors
982 errors
983
983
984 $ cat ../test/errors.log
984 $ cat ../test/errors.log
985
985
986 $ cd ..
986 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now