##// END OF EJS Templates
hgweb: treat rev as raw-rev if user agent is hg
Dirkjan Ochtman -
r9731:0e080d51 default
parent child Browse files
Show More
@@ -1,315 +1,319
1 # hgweb/hgweb_mod.py - Web interface for a repository.
1 # hgweb/hgweb_mod.py - Web interface for a repository.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2, incorporated herein by reference.
7 # GNU General Public License version 2, incorporated herein by reference.
8
8
9 import os
9 import os
10 from mercurial import ui, hg, hook, error, encoding, templater
10 from mercurial import ui, hg, hook, error, encoding, templater
11 from common import get_mtime, ErrorResponse
11 from common import get_mtime, ErrorResponse
12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
12 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
13 from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED
13 from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED
14 from request import wsgirequest
14 from request import wsgirequest
15 import webcommands, protocol, webutil
15 import webcommands, protocol, webutil
16
16
17 perms = {
17 perms = {
18 'changegroup': 'pull',
18 'changegroup': 'pull',
19 'changegroupsubset': 'pull',
19 'changegroupsubset': 'pull',
20 'unbundle': 'push',
20 'unbundle': 'push',
21 'stream_out': 'pull',
21 'stream_out': 'pull',
22 }
22 }
23
23
24 class hgweb(object):
24 class hgweb(object):
25 def __init__(self, repo, name=None):
25 def __init__(self, repo, name=None):
26 if isinstance(repo, str):
26 if isinstance(repo, str):
27 u = ui.ui()
27 u = ui.ui()
28 u.setconfig('ui', 'report_untrusted', 'off')
28 u.setconfig('ui', 'report_untrusted', 'off')
29 u.setconfig('ui', 'interactive', 'off')
29 u.setconfig('ui', 'interactive', 'off')
30 self.repo = hg.repository(u, repo)
30 self.repo = hg.repository(u, repo)
31 else:
31 else:
32 self.repo = repo
32 self.repo = repo
33
33
34 hook.redirect(True)
34 hook.redirect(True)
35 self.mtime = -1
35 self.mtime = -1
36 self.reponame = name
36 self.reponame = name
37 self.archives = 'zip', 'gz', 'bz2'
37 self.archives = 'zip', 'gz', 'bz2'
38 self.stripecount = 1
38 self.stripecount = 1
39 # a repo owner may set web.templates in .hg/hgrc to get any file
39 # a repo owner may set web.templates in .hg/hgrc to get any file
40 # readable by the user running the CGI script
40 # readable by the user running the CGI script
41 self.templatepath = self.config('web', 'templates')
41 self.templatepath = self.config('web', 'templates')
42
42
43 # The CGI scripts are often run by a user different from the repo owner.
43 # The CGI scripts are often run by a user different from the repo owner.
44 # Trust the settings from the .hg/hgrc files by default.
44 # Trust the settings from the .hg/hgrc files by default.
45 def config(self, section, name, default=None, untrusted=True):
45 def config(self, section, name, default=None, untrusted=True):
46 return self.repo.ui.config(section, name, default,
46 return self.repo.ui.config(section, name, default,
47 untrusted=untrusted)
47 untrusted=untrusted)
48
48
49 def configbool(self, section, name, default=False, untrusted=True):
49 def configbool(self, section, name, default=False, untrusted=True):
50 return self.repo.ui.configbool(section, name, default,
50 return self.repo.ui.configbool(section, name, default,
51 untrusted=untrusted)
51 untrusted=untrusted)
52
52
53 def configlist(self, section, name, default=None, untrusted=True):
53 def configlist(self, section, name, default=None, untrusted=True):
54 return self.repo.ui.configlist(section, name, default,
54 return self.repo.ui.configlist(section, name, default,
55 untrusted=untrusted)
55 untrusted=untrusted)
56
56
57 def refresh(self):
57 def refresh(self):
58 mtime = get_mtime(self.repo.root)
58 mtime = get_mtime(self.repo.root)
59 if mtime != self.mtime:
59 if mtime != self.mtime:
60 self.mtime = mtime
60 self.mtime = mtime
61 self.repo = hg.repository(self.repo.ui, self.repo.root)
61 self.repo = hg.repository(self.repo.ui, self.repo.root)
62 self.maxchanges = int(self.config("web", "maxchanges", 10))
62 self.maxchanges = int(self.config("web", "maxchanges", 10))
63 self.stripecount = int(self.config("web", "stripes", 1))
63 self.stripecount = int(self.config("web", "stripes", 1))
64 self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
64 self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
65 self.maxfiles = int(self.config("web", "maxfiles", 10))
65 self.maxfiles = int(self.config("web", "maxfiles", 10))
66 self.allowpull = self.configbool("web", "allowpull", True)
66 self.allowpull = self.configbool("web", "allowpull", True)
67 encoding.encoding = self.config("web", "encoding",
67 encoding.encoding = self.config("web", "encoding",
68 encoding.encoding)
68 encoding.encoding)
69
69
70 def run(self):
70 def run(self):
71 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
71 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
72 raise RuntimeError("This function is only intended to be "
72 raise RuntimeError("This function is only intended to be "
73 "called while running as a CGI script.")
73 "called while running as a CGI script.")
74 import mercurial.hgweb.wsgicgi as wsgicgi
74 import mercurial.hgweb.wsgicgi as wsgicgi
75 wsgicgi.launch(self)
75 wsgicgi.launch(self)
76
76
77 def __call__(self, env, respond):
77 def __call__(self, env, respond):
78 req = wsgirequest(env, respond)
78 req = wsgirequest(env, respond)
79 return self.run_wsgi(req)
79 return self.run_wsgi(req)
80
80
81 def run_wsgi(self, req):
81 def run_wsgi(self, req):
82
82
83 self.refresh()
83 self.refresh()
84
84
85 # work with CGI variables to create coherent structure
85 # work with CGI variables to create coherent structure
86 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
86 # use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
87
87
88 req.url = req.env['SCRIPT_NAME']
88 req.url = req.env['SCRIPT_NAME']
89 if not req.url.endswith('/'):
89 if not req.url.endswith('/'):
90 req.url += '/'
90 req.url += '/'
91 if 'REPO_NAME' in req.env:
91 if 'REPO_NAME' in req.env:
92 req.url += req.env['REPO_NAME'] + '/'
92 req.url += req.env['REPO_NAME'] + '/'
93
93
94 if 'PATH_INFO' in req.env:
94 if 'PATH_INFO' in req.env:
95 parts = req.env['PATH_INFO'].strip('/').split('/')
95 parts = req.env['PATH_INFO'].strip('/').split('/')
96 repo_parts = req.env.get('REPO_NAME', '').split('/')
96 repo_parts = req.env.get('REPO_NAME', '').split('/')
97 if parts[:len(repo_parts)] == repo_parts:
97 if parts[:len(repo_parts)] == repo_parts:
98 parts = parts[len(repo_parts):]
98 parts = parts[len(repo_parts):]
99 query = '/'.join(parts)
99 query = '/'.join(parts)
100 else:
100 else:
101 query = req.env['QUERY_STRING'].split('&', 1)[0]
101 query = req.env['QUERY_STRING'].split('&', 1)[0]
102 query = query.split(';', 1)[0]
102 query = query.split(';', 1)[0]
103
103
104 # process this if it's a protocol request
104 # process this if it's a protocol request
105 # protocol bits don't need to create any URLs
105 # protocol bits don't need to create any URLs
106 # and the clients always use the old URL structure
106 # and the clients always use the old URL structure
107
107
108 cmd = req.form.get('cmd', [''])[0]
108 cmd = req.form.get('cmd', [''])[0]
109 if cmd and cmd in protocol.__all__:
109 if cmd and cmd in protocol.__all__:
110 if query:
110 if query:
111 raise ErrorResponse(HTTP_NOT_FOUND)
111 raise ErrorResponse(HTTP_NOT_FOUND)
112 try:
112 try:
113 if cmd in perms:
113 if cmd in perms:
114 try:
114 try:
115 self.check_perm(req, perms[cmd])
115 self.check_perm(req, perms[cmd])
116 except ErrorResponse, inst:
116 except ErrorResponse, inst:
117 if cmd == 'unbundle':
117 if cmd == 'unbundle':
118 req.drain()
118 req.drain()
119 raise
119 raise
120 method = getattr(protocol, cmd)
120 method = getattr(protocol, cmd)
121 return method(self.repo, req)
121 return method(self.repo, req)
122 except ErrorResponse, inst:
122 except ErrorResponse, inst:
123 req.respond(inst, protocol.HGTYPE)
123 req.respond(inst, protocol.HGTYPE)
124 if not inst.message:
124 if not inst.message:
125 return []
125 return []
126 return '0\n%s\n' % inst.message,
126 return '0\n%s\n' % inst.message,
127
127
128 # translate user-visible url structure to internal structure
128 # translate user-visible url structure to internal structure
129
129
130 args = query.split('/', 2)
130 args = query.split('/', 2)
131 if 'cmd' not in req.form and args and args[0]:
131 if 'cmd' not in req.form and args and args[0]:
132
132
133 cmd = args.pop(0)
133 cmd = args.pop(0)
134 style = cmd.rfind('-')
134 style = cmd.rfind('-')
135 if style != -1:
135 if style != -1:
136 req.form['style'] = [cmd[:style]]
136 req.form['style'] = [cmd[:style]]
137 cmd = cmd[style+1:]
137 cmd = cmd[style+1:]
138
138
139 # avoid accepting e.g. style parameter as command
139 # avoid accepting e.g. style parameter as command
140 if hasattr(webcommands, cmd):
140 if hasattr(webcommands, cmd):
141 req.form['cmd'] = [cmd]
141 req.form['cmd'] = [cmd]
142 else:
142 else:
143 cmd = ''
143 cmd = ''
144
144
145 if cmd == 'static':
145 if cmd == 'static':
146 req.form['file'] = ['/'.join(args)]
146 req.form['file'] = ['/'.join(args)]
147 else:
147 else:
148 if args and args[0]:
148 if args and args[0]:
149 node = args.pop(0)
149 node = args.pop(0)
150 req.form['node'] = [node]
150 req.form['node'] = [node]
151 if args:
151 if args:
152 req.form['file'] = args
152 req.form['file'] = args
153
153
154 ua = req.env.get('HTTP_USER_AGENT', '')
155 if cmd == 'rev' and 'mercurial' in ua:
156 req.form['style'] = ['raw']
157
154 if cmd == 'archive':
158 if cmd == 'archive':
155 fn = req.form['node'][0]
159 fn = req.form['node'][0]
156 for type_, spec in self.archive_specs.iteritems():
160 for type_, spec in self.archive_specs.iteritems():
157 ext = spec[2]
161 ext = spec[2]
158 if fn.endswith(ext):
162 if fn.endswith(ext):
159 req.form['node'] = [fn[:-len(ext)]]
163 req.form['node'] = [fn[:-len(ext)]]
160 req.form['type'] = [type_]
164 req.form['type'] = [type_]
161
165
162 # process the web interface request
166 # process the web interface request
163
167
164 try:
168 try:
165 tmpl = self.templater(req)
169 tmpl = self.templater(req)
166 ctype = tmpl('mimetype', encoding=encoding.encoding)
170 ctype = tmpl('mimetype', encoding=encoding.encoding)
167 ctype = templater.stringify(ctype)
171 ctype = templater.stringify(ctype)
168
172
169 # check read permissions non-static content
173 # check read permissions non-static content
170 if cmd != 'static':
174 if cmd != 'static':
171 self.check_perm(req, None)
175 self.check_perm(req, None)
172
176
173 if cmd == '':
177 if cmd == '':
174 req.form['cmd'] = [tmpl.cache['default']]
178 req.form['cmd'] = [tmpl.cache['default']]
175 cmd = req.form['cmd'][0]
179 cmd = req.form['cmd'][0]
176
180
177 if cmd not in webcommands.__all__:
181 if cmd not in webcommands.__all__:
178 msg = 'no such method: %s' % cmd
182 msg = 'no such method: %s' % cmd
179 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
183 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
180 elif cmd == 'file' and 'raw' in req.form.get('style', []):
184 elif cmd == 'file' and 'raw' in req.form.get('style', []):
181 self.ctype = ctype
185 self.ctype = ctype
182 content = webcommands.rawfile(self, req, tmpl)
186 content = webcommands.rawfile(self, req, tmpl)
183 else:
187 else:
184 content = getattr(webcommands, cmd)(self, req, tmpl)
188 content = getattr(webcommands, cmd)(self, req, tmpl)
185 req.respond(HTTP_OK, ctype)
189 req.respond(HTTP_OK, ctype)
186
190
187 return content
191 return content
188
192
189 except error.LookupError, err:
193 except error.LookupError, err:
190 req.respond(HTTP_NOT_FOUND, ctype)
194 req.respond(HTTP_NOT_FOUND, ctype)
191 msg = str(err)
195 msg = str(err)
192 if 'manifest' not in msg:
196 if 'manifest' not in msg:
193 msg = 'revision not found: %s' % err.name
197 msg = 'revision not found: %s' % err.name
194 return tmpl('error', error=msg)
198 return tmpl('error', error=msg)
195 except (error.RepoError, error.RevlogError), inst:
199 except (error.RepoError, error.RevlogError), inst:
196 req.respond(HTTP_SERVER_ERROR, ctype)
200 req.respond(HTTP_SERVER_ERROR, ctype)
197 return tmpl('error', error=str(inst))
201 return tmpl('error', error=str(inst))
198 except ErrorResponse, inst:
202 except ErrorResponse, inst:
199 req.respond(inst, ctype)
203 req.respond(inst, ctype)
200 return tmpl('error', error=inst.message)
204 return tmpl('error', error=inst.message)
201
205
202 def templater(self, req):
206 def templater(self, req):
203
207
204 # determine scheme, port and server name
208 # determine scheme, port and server name
205 # this is needed to create absolute urls
209 # this is needed to create absolute urls
206
210
207 proto = req.env.get('wsgi.url_scheme')
211 proto = req.env.get('wsgi.url_scheme')
208 if proto == 'https':
212 if proto == 'https':
209 proto = 'https'
213 proto = 'https'
210 default_port = "443"
214 default_port = "443"
211 else:
215 else:
212 proto = 'http'
216 proto = 'http'
213 default_port = "80"
217 default_port = "80"
214
218
215 port = req.env["SERVER_PORT"]
219 port = req.env["SERVER_PORT"]
216 port = port != default_port and (":" + port) or ""
220 port = port != default_port and (":" + port) or ""
217 urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
221 urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
218 staticurl = self.config("web", "staticurl") or req.url + 'static/'
222 staticurl = self.config("web", "staticurl") or req.url + 'static/'
219 if not staticurl.endswith('/'):
223 if not staticurl.endswith('/'):
220 staticurl += '/'
224 staticurl += '/'
221
225
222 # some functions for the templater
226 # some functions for the templater
223
227
224 def header(**map):
228 def header(**map):
225 yield tmpl('header', encoding=encoding.encoding, **map)
229 yield tmpl('header', encoding=encoding.encoding, **map)
226
230
227 def footer(**map):
231 def footer(**map):
228 yield tmpl("footer", **map)
232 yield tmpl("footer", **map)
229
233
230 def motd(**map):
234 def motd(**map):
231 yield self.config("web", "motd", "")
235 yield self.config("web", "motd", "")
232
236
233 # figure out which style to use
237 # figure out which style to use
234
238
235 vars = {}
239 vars = {}
236 style = self.config("web", "style", "paper")
240 style = self.config("web", "style", "paper")
237 if 'style' in req.form:
241 if 'style' in req.form:
238 style = req.form['style'][0]
242 style = req.form['style'][0]
239 vars['style'] = style
243 vars['style'] = style
240
244
241 start = req.url[-1] == '?' and '&' or '?'
245 start = req.url[-1] == '?' and '&' or '?'
242 sessionvars = webutil.sessionvars(vars, start)
246 sessionvars = webutil.sessionvars(vars, start)
243 mapfile = templater.stylemap(style, self.templatepath)
247 mapfile = templater.stylemap(style, self.templatepath)
244
248
245 if not self.reponame:
249 if not self.reponame:
246 self.reponame = (self.config("web", "name")
250 self.reponame = (self.config("web", "name")
247 or req.env.get('REPO_NAME')
251 or req.env.get('REPO_NAME')
248 or req.url.strip('/') or self.repo.root)
252 or req.url.strip('/') or self.repo.root)
249
253
250 # create the templater
254 # create the templater
251
255
252 tmpl = templater.templater(mapfile,
256 tmpl = templater.templater(mapfile,
253 defaults={"url": req.url,
257 defaults={"url": req.url,
254 "staticurl": staticurl,
258 "staticurl": staticurl,
255 "urlbase": urlbase,
259 "urlbase": urlbase,
256 "repo": self.reponame,
260 "repo": self.reponame,
257 "header": header,
261 "header": header,
258 "footer": footer,
262 "footer": footer,
259 "motd": motd,
263 "motd": motd,
260 "sessionvars": sessionvars
264 "sessionvars": sessionvars
261 })
265 })
262 return tmpl
266 return tmpl
263
267
264 def archivelist(self, nodeid):
268 def archivelist(self, nodeid):
265 allowed = self.configlist("web", "allow_archive")
269 allowed = self.configlist("web", "allow_archive")
266 for i, spec in self.archive_specs.iteritems():
270 for i, spec in self.archive_specs.iteritems():
267 if i in allowed or self.configbool("web", "allow" + i):
271 if i in allowed or self.configbool("web", "allow" + i):
268 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
272 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
269
273
270 archive_specs = {
274 archive_specs = {
271 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
275 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
272 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
276 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
273 'zip': ('application/zip', 'zip', '.zip', None),
277 'zip': ('application/zip', 'zip', '.zip', None),
274 }
278 }
275
279
276 def check_perm(self, req, op):
280 def check_perm(self, req, op):
277 '''Check permission for operation based on request data (including
281 '''Check permission for operation based on request data (including
278 authentication info). Return if op allowed, else raise an ErrorResponse
282 authentication info). Return if op allowed, else raise an ErrorResponse
279 exception.'''
283 exception.'''
280
284
281 user = req.env.get('REMOTE_USER')
285 user = req.env.get('REMOTE_USER')
282
286
283 deny_read = self.configlist('web', 'deny_read')
287 deny_read = self.configlist('web', 'deny_read')
284 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
288 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
285 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
289 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
286
290
287 allow_read = self.configlist('web', 'allow_read')
291 allow_read = self.configlist('web', 'allow_read')
288 result = (not allow_read) or (allow_read == ['*'])
292 result = (not allow_read) or (allow_read == ['*'])
289 if not (result or user in allow_read):
293 if not (result or user in allow_read):
290 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
294 raise ErrorResponse(HTTP_UNAUTHORIZED, 'read not authorized')
291
295
292 if op == 'pull' and not self.allowpull:
296 if op == 'pull' and not self.allowpull:
293 raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized')
297 raise ErrorResponse(HTTP_UNAUTHORIZED, 'pull not authorized')
294 elif op == 'pull' or op is None: # op is None for interface requests
298 elif op == 'pull' or op is None: # op is None for interface requests
295 return
299 return
296
300
297 # enforce that you can only push using POST requests
301 # enforce that you can only push using POST requests
298 if req.env['REQUEST_METHOD'] != 'POST':
302 if req.env['REQUEST_METHOD'] != 'POST':
299 msg = 'push requires POST request'
303 msg = 'push requires POST request'
300 raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg)
304 raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg)
301
305
302 # require ssl by default for pushing, auth info cannot be sniffed
306 # require ssl by default for pushing, auth info cannot be sniffed
303 # and replayed
307 # and replayed
304 scheme = req.env.get('wsgi.url_scheme')
308 scheme = req.env.get('wsgi.url_scheme')
305 if self.configbool('web', 'push_ssl', True) and scheme != 'https':
309 if self.configbool('web', 'push_ssl', True) and scheme != 'https':
306 raise ErrorResponse(HTTP_OK, 'ssl required')
310 raise ErrorResponse(HTTP_OK, 'ssl required')
307
311
308 deny = self.configlist('web', 'deny_push')
312 deny = self.configlist('web', 'deny_push')
309 if deny and (not user or deny == ['*'] or user in deny):
313 if deny and (not user or deny == ['*'] or user in deny):
310 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
314 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
311
315
312 allow = self.configlist('web', 'allow_push')
316 allow = self.configlist('web', 'allow_push')
313 result = allow and (allow == ['*'] or user in allow)
317 result = allow and (allow == ['*'] or user in allow)
314 if not result:
318 if not result:
315 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
319 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
@@ -1,42 +1,48
1 #!/bin/sh
1 #!/bin/sh
2
2
3 echo % setting up repo
3 echo % setting up repo
4 hg init test
4 hg init test
5 cd test
5 cd test
6 echo a > a
6 echo a > a
7 echo b > b
7 echo b > b
8 hg ci -Ama
8 hg ci -Ama
9
9
10 echo % change permissions for git diffs
10 echo % change permissions for git diffs
11 chmod 755 a
11 chmod 755 a
12 hg ci -Amb
12 hg ci -Amb
13
13
14 echo % set up hgweb
14 echo % set up hgweb
15 hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
15 hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
16 cat hg.pid >> $DAEMON_PIDS
16 cat hg.pid >> $DAEMON_PIDS
17
17
18 echo % revision
18 echo % revision
19 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/0'
19 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/0'
20
20
21 echo % raw revision
21 echo % raw revision
22 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/raw-rev/0'
22 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/raw-rev/0'
23
23
24 echo % diff removed file
24 echo % diff removed file
25 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/tip/a'
25 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/tip/a'
26
26
27 echo % set up hgweb with git diffs
27 echo % set up hgweb with git diffs
28 "$TESTDIR/killdaemons.py"
28 "$TESTDIR/killdaemons.py"
29 hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
29 hg serve --config 'diff.git=1' -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
30 cat hg.pid >> $DAEMON_PIDS
30 cat hg.pid >> $DAEMON_PIDS
31
31
32 echo % revision
32 echo % revision
33 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/0'
33 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/rev/0'
34
34
35 echo % revision
35 echo % revision
36 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/raw-rev/0'
36 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/raw-rev/0'
37
37
38 echo % diff removed file
38 echo % diff removed file
39 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/tip/a'
39 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/diff/tip/a'
40
40
41 cd ..
42 echo % test import rev as raw-rev
43 hg clone -r0 test test1
44 cd test1
45 hg import --exact http://localhost:$HGPORT/rev/1
46
41 echo % errors
47 echo % errors
42 cat errors.log
48 cat ../test/errors.log
@@ -1,420 +1,429
1 % setting up repo
1 % setting up repo
2 adding a
2 adding a
3 adding b
3 adding b
4 % change permissions for git diffs
4 % change permissions for git diffs
5 % set up hgweb
5 % set up hgweb
6 % revision
6 % revision
7 200 Script output follows
7 200 Script output follows
8
8
9 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
9 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
10 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
10 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
11 <head>
11 <head>
12 <link rel="icon" href="/static/hgicon.png" type="image/png" />
12 <link rel="icon" href="/static/hgicon.png" type="image/png" />
13 <meta name="robots" content="index, nofollow" />
13 <meta name="robots" content="index, nofollow" />
14 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
14 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
15
15
16 <title>test: 0cd96de13884</title>
16 <title>test: 0cd96de13884</title>
17 </head>
17 </head>
18 <body>
18 <body>
19 <div class="container">
19 <div class="container">
20 <div class="menu">
20 <div class="menu">
21 <div class="logo">
21 <div class="logo">
22 <a href="http://mercurial.selenic.com/">
22 <a href="http://mercurial.selenic.com/">
23 <img src="/static/hglogo.png" alt="mercurial" /></a>
23 <img src="/static/hglogo.png" alt="mercurial" /></a>
24 </div>
24 </div>
25 <ul>
25 <ul>
26 <li><a href="/shortlog/0cd96de13884">log</a></li>
26 <li><a href="/shortlog/0cd96de13884">log</a></li>
27 <li><a href="/graph/0cd96de13884">graph</a></li>
27 <li><a href="/graph/0cd96de13884">graph</a></li>
28 <li><a href="/tags">tags</a></li>
28 <li><a href="/tags">tags</a></li>
29 <li><a href="/branches">branches</a></li>
29 <li><a href="/branches">branches</a></li>
30 </ul>
30 </ul>
31 <ul>
31 <ul>
32 <li class="active">changeset</li>
32 <li class="active">changeset</li>
33 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
33 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
34 <li><a href="/file/0cd96de13884">browse</a></li>
34 <li><a href="/file/0cd96de13884">browse</a></li>
35 </ul>
35 </ul>
36 <ul>
36 <ul>
37
37
38 </ul>
38 </ul>
39 </div>
39 </div>
40
40
41 <div class="main">
41 <div class="main">
42
42
43 <h2><a href="/">test</a></h2>
43 <h2><a href="/">test</a></h2>
44 <h3>changeset 0:0cd96de13884 </h3>
44 <h3>changeset 0:0cd96de13884 </h3>
45
45
46 <form class="search" action="/log">
46 <form class="search" action="/log">
47
47
48 <p><input name="rev" id="search1" type="text" size="30" /></p>
48 <p><input name="rev" id="search1" type="text" size="30" /></p>
49 <div id="hint">find changesets by author, revision,
49 <div id="hint">find changesets by author, revision,
50 files, or words in the commit message</div>
50 files, or words in the commit message</div>
51 </form>
51 </form>
52
52
53 <div class="description">a</div>
53 <div class="description">a</div>
54
54
55 <table id="changesetEntry">
55 <table id="changesetEntry">
56 <tr>
56 <tr>
57 <th class="author">author</th>
57 <th class="author">author</th>
58 <td class="author">&#116;&#101;&#115;&#116;</td>
58 <td class="author">&#116;&#101;&#115;&#116;</td>
59 </tr>
59 </tr>
60 <tr>
60 <tr>
61 <th class="date">date</th>
61 <th class="date">date</th>
62 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td></tr>
62 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td></tr>
63 <tr>
63 <tr>
64 <th class="author">parents</th>
64 <th class="author">parents</th>
65 <td class="author"></td>
65 <td class="author"></td>
66 </tr>
66 </tr>
67 <tr>
67 <tr>
68 <th class="author">children</th>
68 <th class="author">children</th>
69 <td class="author"> <a href="/rev/78e4ebad7cdf">78e4ebad7cdf</a></td>
69 <td class="author"> <a href="/rev/78e4ebad7cdf">78e4ebad7cdf</a></td>
70 </tr>
70 </tr>
71 <tr>
71 <tr>
72 <th class="files">files</th>
72 <th class="files">files</th>
73 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
73 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
74 </tr>
74 </tr>
75 </table>
75 </table>
76
76
77 <div class="overflow">
77 <div class="overflow">
78 <div class="sourcefirst"> line diff</div>
78 <div class="sourcefirst"> line diff</div>
79
79
80 <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
80 <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
81 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
81 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
82 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
82 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
83 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
83 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
84 </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
84 </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
85 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
85 </span><a href="#l2.2" id="l2.2"> 2.2</a> <span class="plusline">+++ b/b Thu Jan 01 00:00:00 1970 +0000
86 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
86 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="atline">@@ -0,0 +1,1 @@
87 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
87 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="plusline">+b
88 </span></pre></div>
88 </span></pre></div>
89 </div>
89 </div>
90
90
91 </div>
91 </div>
92 </div>
92 </div>
93
93
94
94
95 </body>
95 </body>
96 </html>
96 </html>
97
97
98 % raw revision
98 % raw revision
99 200 Script output follows
99 200 Script output follows
100
100
101
101
102 # HG changeset patch
102 # HG changeset patch
103 # User test
103 # User test
104 # Date 0 0
104 # Date 0 0
105 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
105 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
106
106
107 a
107 a
108
108
109 diff -r 000000000000 -r 0cd96de13884 a
109 diff -r 000000000000 -r 0cd96de13884 a
110 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
110 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
111 +++ b/a Thu Jan 01 00:00:00 1970 +0000
111 +++ b/a Thu Jan 01 00:00:00 1970 +0000
112 @@ -0,0 +1,1 @@
112 @@ -0,0 +1,1 @@
113 +a
113 +a
114 diff -r 000000000000 -r 0cd96de13884 b
114 diff -r 000000000000 -r 0cd96de13884 b
115 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
115 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
116 +++ b/b Thu Jan 01 00:00:00 1970 +0000
116 +++ b/b Thu Jan 01 00:00:00 1970 +0000
117 @@ -0,0 +1,1 @@
117 @@ -0,0 +1,1 @@
118 +b
118 +b
119
119
120 % diff removed file
120 % diff removed file
121 200 Script output follows
121 200 Script output follows
122
122
123 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
123 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
124 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
124 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
125 <head>
125 <head>
126 <link rel="icon" href="/static/hgicon.png" type="image/png" />
126 <link rel="icon" href="/static/hgicon.png" type="image/png" />
127 <meta name="robots" content="index, nofollow" />
127 <meta name="robots" content="index, nofollow" />
128 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
128 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
129
129
130 <title>test: a diff</title>
130 <title>test: a diff</title>
131 </head>
131 </head>
132 <body>
132 <body>
133
133
134 <div class="container">
134 <div class="container">
135 <div class="menu">
135 <div class="menu">
136 <div class="logo">
136 <div class="logo">
137 <a href="http://mercurial.selenic.com/">
137 <a href="http://mercurial.selenic.com/">
138 <img src="/static/hglogo.png" alt="mercurial" /></a>
138 <img src="/static/hglogo.png" alt="mercurial" /></a>
139 </div>
139 </div>
140 <ul>
140 <ul>
141 <li><a href="/shortlog/78e4ebad7cdf">log</a></li>
141 <li><a href="/shortlog/78e4ebad7cdf">log</a></li>
142 <li><a href="/graph/78e4ebad7cdf">graph</a></li>
142 <li><a href="/graph/78e4ebad7cdf">graph</a></li>
143 <li><a href="/tags">tags</a></li>
143 <li><a href="/tags">tags</a></li>
144 <li><a href="/branches">branches</a></li>
144 <li><a href="/branches">branches</a></li>
145 </ul>
145 </ul>
146 <ul>
146 <ul>
147 <li><a href="/rev/78e4ebad7cdf">changeset</a></li>
147 <li><a href="/rev/78e4ebad7cdf">changeset</a></li>
148 <li><a href="/file/78e4ebad7cdf">browse</a></li>
148 <li><a href="/file/78e4ebad7cdf">browse</a></li>
149 </ul>
149 </ul>
150 <ul>
150 <ul>
151 <li><a href="/file/78e4ebad7cdf/a">file</a></li>
151 <li><a href="/file/78e4ebad7cdf/a">file</a></li>
152 <li><a href="/file/tip/a">latest</a></li>
152 <li><a href="/file/tip/a">latest</a></li>
153 <li class="active">diff</li>
153 <li class="active">diff</li>
154 <li><a href="/annotate/78e4ebad7cdf/a">annotate</a></li>
154 <li><a href="/annotate/78e4ebad7cdf/a">annotate</a></li>
155 <li><a href="/log/78e4ebad7cdf/a">file log</a></li>
155 <li><a href="/log/78e4ebad7cdf/a">file log</a></li>
156 <li><a href="/raw-file/78e4ebad7cdf/a">raw</a></li>
156 <li><a href="/raw-file/78e4ebad7cdf/a">raw</a></li>
157 </ul>
157 </ul>
158 </div>
158 </div>
159
159
160 <div class="main">
160 <div class="main">
161 <h2><a href="/">test</a></h2>
161 <h2><a href="/">test</a></h2>
162 <h3>diff a @ 1:78e4ebad7cdf</h3>
162 <h3>diff a @ 1:78e4ebad7cdf</h3>
163
163
164 <form class="search" action="/log">
164 <form class="search" action="/log">
165 <p></p>
165 <p></p>
166 <p><input name="rev" id="search1" type="text" size="30" /></p>
166 <p><input name="rev" id="search1" type="text" size="30" /></p>
167 <div id="hint">find changesets by author, revision,
167 <div id="hint">find changesets by author, revision,
168 files, or words in the commit message</div>
168 files, or words in the commit message</div>
169 </form>
169 </form>
170
170
171 <div class="description">b</div>
171 <div class="description">b</div>
172
172
173 <table id="changesetEntry">
173 <table id="changesetEntry">
174 <tr>
174 <tr>
175 <th>author</th>
175 <th>author</th>
176 <td>&#116;&#101;&#115;&#116;</td>
176 <td>&#116;&#101;&#115;&#116;</td>
177 </tr>
177 </tr>
178 <tr>
178 <tr>
179 <th>date</th>
179 <th>date</th>
180 <td>Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td>
180 <td>Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td>
181 </tr>
181 </tr>
182 <tr>
182 <tr>
183 <th>parents</th>
183 <th>parents</th>
184 <td></td>
184 <td></td>
185 </tr>
185 </tr>
186 <tr>
186 <tr>
187 <th>children</th>
187 <th>children</th>
188 <td></td>
188 <td></td>
189 </tr>
189 </tr>
190
190
191 </table>
191 </table>
192
192
193 <div class="overflow">
193 <div class="overflow">
194 <div class="sourcefirst"> line diff</div>
194 <div class="sourcefirst"> line diff</div>
195
195
196 <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
196 <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
197 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
197 </span><a href="#l1.2" id="l1.2"> 1.2</a> <span class="plusline">+++ b/a Thu Jan 01 00:00:00 1970 +0000
198 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
198 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="atline">@@ -0,0 +1,1 @@
199 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
199 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="plusline">+a
200 </span></pre></div>
200 </span></pre></div>
201 </div>
201 </div>
202 </div>
202 </div>
203 </div>
203 </div>
204
204
205
205
206
206
207 </body>
207 </body>
208 </html>
208 </html>
209
209
210 % set up hgweb with git diffs
210 % set up hgweb with git diffs
211 % revision
211 % revision
212 200 Script output follows
212 200 Script output follows
213
213
214 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
214 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
215 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
215 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
216 <head>
216 <head>
217 <link rel="icon" href="/static/hgicon.png" type="image/png" />
217 <link rel="icon" href="/static/hgicon.png" type="image/png" />
218 <meta name="robots" content="index, nofollow" />
218 <meta name="robots" content="index, nofollow" />
219 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
219 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
220
220
221 <title>test: 0cd96de13884</title>
221 <title>test: 0cd96de13884</title>
222 </head>
222 </head>
223 <body>
223 <body>
224 <div class="container">
224 <div class="container">
225 <div class="menu">
225 <div class="menu">
226 <div class="logo">
226 <div class="logo">
227 <a href="http://mercurial.selenic.com/">
227 <a href="http://mercurial.selenic.com/">
228 <img src="/static/hglogo.png" alt="mercurial" /></a>
228 <img src="/static/hglogo.png" alt="mercurial" /></a>
229 </div>
229 </div>
230 <ul>
230 <ul>
231 <li><a href="/shortlog/0cd96de13884">log</a></li>
231 <li><a href="/shortlog/0cd96de13884">log</a></li>
232 <li><a href="/graph/0cd96de13884">graph</a></li>
232 <li><a href="/graph/0cd96de13884">graph</a></li>
233 <li><a href="/tags">tags</a></li>
233 <li><a href="/tags">tags</a></li>
234 <li><a href="/branches">branches</a></li>
234 <li><a href="/branches">branches</a></li>
235 </ul>
235 </ul>
236 <ul>
236 <ul>
237 <li class="active">changeset</li>
237 <li class="active">changeset</li>
238 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
238 <li><a href="/raw-rev/0cd96de13884">raw</a></li>
239 <li><a href="/file/0cd96de13884">browse</a></li>
239 <li><a href="/file/0cd96de13884">browse</a></li>
240 </ul>
240 </ul>
241 <ul>
241 <ul>
242
242
243 </ul>
243 </ul>
244 </div>
244 </div>
245
245
246 <div class="main">
246 <div class="main">
247
247
248 <h2><a href="/">test</a></h2>
248 <h2><a href="/">test</a></h2>
249 <h3>changeset 0:0cd96de13884 </h3>
249 <h3>changeset 0:0cd96de13884 </h3>
250
250
251 <form class="search" action="/log">
251 <form class="search" action="/log">
252
252
253 <p><input name="rev" id="search1" type="text" size="30" /></p>
253 <p><input name="rev" id="search1" type="text" size="30" /></p>
254 <div id="hint">find changesets by author, revision,
254 <div id="hint">find changesets by author, revision,
255 files, or words in the commit message</div>
255 files, or words in the commit message</div>
256 </form>
256 </form>
257
257
258 <div class="description">a</div>
258 <div class="description">a</div>
259
259
260 <table id="changesetEntry">
260 <table id="changesetEntry">
261 <tr>
261 <tr>
262 <th class="author">author</th>
262 <th class="author">author</th>
263 <td class="author">&#116;&#101;&#115;&#116;</td>
263 <td class="author">&#116;&#101;&#115;&#116;</td>
264 </tr>
264 </tr>
265 <tr>
265 <tr>
266 <th class="date">date</th>
266 <th class="date">date</th>
267 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td></tr>
267 <td class="date">Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td></tr>
268 <tr>
268 <tr>
269 <th class="author">parents</th>
269 <th class="author">parents</th>
270 <td class="author"></td>
270 <td class="author"></td>
271 </tr>
271 </tr>
272 <tr>
272 <tr>
273 <th class="author">children</th>
273 <th class="author">children</th>
274 <td class="author"> <a href="/rev/78e4ebad7cdf">78e4ebad7cdf</a></td>
274 <td class="author"> <a href="/rev/78e4ebad7cdf">78e4ebad7cdf</a></td>
275 </tr>
275 </tr>
276 <tr>
276 <tr>
277 <th class="files">files</th>
277 <th class="files">files</th>
278 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
278 <td class="files"><a href="/file/0cd96de13884/a">a</a> <a href="/file/0cd96de13884/b">b</a> </td>
279 </tr>
279 </tr>
280 </table>
280 </table>
281
281
282 <div class="overflow">
282 <div class="overflow">
283 <div class="sourcefirst"> line diff</div>
283 <div class="sourcefirst"> line diff</div>
284
284
285 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
285 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100644
286 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
286 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
287 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
287 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
288 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
288 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
289 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
289 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
290 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
290 </span></pre></div><div class="source bottomline parity1"><pre><a href="#l2.1" id="l2.1"> 2.1</a> new file mode 100644
291 <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
291 <a href="#l2.2" id="l2.2"> 2.2</a> <span class="minusline">--- /dev/null
292 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
292 </span><a href="#l2.3" id="l2.3"> 2.3</a> <span class="plusline">+++ b/b
293 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
293 </span><a href="#l2.4" id="l2.4"> 2.4</a> <span class="atline">@@ -0,0 +1,1 @@
294 </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
294 </span><a href="#l2.5" id="l2.5"> 2.5</a> <span class="plusline">+b
295 </span></pre></div>
295 </span></pre></div>
296 </div>
296 </div>
297
297
298 </div>
298 </div>
299 </div>
299 </div>
300
300
301
301
302 </body>
302 </body>
303 </html>
303 </html>
304
304
305 % revision
305 % revision
306 200 Script output follows
306 200 Script output follows
307
307
308
308
309 # HG changeset patch
309 # HG changeset patch
310 # User test
310 # User test
311 # Date 0 0
311 # Date 0 0
312 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
312 # Node ID 0cd96de13884b090099512d4794ae87ad067ea8e
313
313
314 a
314 a
315
315
316 diff --git a/a b/a
316 diff --git a/a b/a
317 new file mode 100644
317 new file mode 100644
318 --- /dev/null
318 --- /dev/null
319 +++ b/a
319 +++ b/a
320 @@ -0,0 +1,1 @@
320 @@ -0,0 +1,1 @@
321 +a
321 +a
322 diff --git a/b b/b
322 diff --git a/b b/b
323 new file mode 100644
323 new file mode 100644
324 --- /dev/null
324 --- /dev/null
325 +++ b/b
325 +++ b/b
326 @@ -0,0 +1,1 @@
326 @@ -0,0 +1,1 @@
327 +b
327 +b
328
328
329 % diff removed file
329 % diff removed file
330 200 Script output follows
330 200 Script output follows
331
331
332 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
332 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
333 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
333 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
334 <head>
334 <head>
335 <link rel="icon" href="/static/hgicon.png" type="image/png" />
335 <link rel="icon" href="/static/hgicon.png" type="image/png" />
336 <meta name="robots" content="index, nofollow" />
336 <meta name="robots" content="index, nofollow" />
337 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
337 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
338
338
339 <title>test: a diff</title>
339 <title>test: a diff</title>
340 </head>
340 </head>
341 <body>
341 <body>
342
342
343 <div class="container">
343 <div class="container">
344 <div class="menu">
344 <div class="menu">
345 <div class="logo">
345 <div class="logo">
346 <a href="http://mercurial.selenic.com/">
346 <a href="http://mercurial.selenic.com/">
347 <img src="/static/hglogo.png" alt="mercurial" /></a>
347 <img src="/static/hglogo.png" alt="mercurial" /></a>
348 </div>
348 </div>
349 <ul>
349 <ul>
350 <li><a href="/shortlog/78e4ebad7cdf">log</a></li>
350 <li><a href="/shortlog/78e4ebad7cdf">log</a></li>
351 <li><a href="/graph/78e4ebad7cdf">graph</a></li>
351 <li><a href="/graph/78e4ebad7cdf">graph</a></li>
352 <li><a href="/tags">tags</a></li>
352 <li><a href="/tags">tags</a></li>
353 <li><a href="/branches">branches</a></li>
353 <li><a href="/branches">branches</a></li>
354 </ul>
354 </ul>
355 <ul>
355 <ul>
356 <li><a href="/rev/78e4ebad7cdf">changeset</a></li>
356 <li><a href="/rev/78e4ebad7cdf">changeset</a></li>
357 <li><a href="/file/78e4ebad7cdf">browse</a></li>
357 <li><a href="/file/78e4ebad7cdf">browse</a></li>
358 </ul>
358 </ul>
359 <ul>
359 <ul>
360 <li><a href="/file/78e4ebad7cdf/a">file</a></li>
360 <li><a href="/file/78e4ebad7cdf/a">file</a></li>
361 <li><a href="/file/tip/a">latest</a></li>
361 <li><a href="/file/tip/a">latest</a></li>
362 <li class="active">diff</li>
362 <li class="active">diff</li>
363 <li><a href="/annotate/78e4ebad7cdf/a">annotate</a></li>
363 <li><a href="/annotate/78e4ebad7cdf/a">annotate</a></li>
364 <li><a href="/log/78e4ebad7cdf/a">file log</a></li>
364 <li><a href="/log/78e4ebad7cdf/a">file log</a></li>
365 <li><a href="/raw-file/78e4ebad7cdf/a">raw</a></li>
365 <li><a href="/raw-file/78e4ebad7cdf/a">raw</a></li>
366 </ul>
366 </ul>
367 </div>
367 </div>
368
368
369 <div class="main">
369 <div class="main">
370 <h2><a href="/">test</a></h2>
370 <h2><a href="/">test</a></h2>
371 <h3>diff a @ 1:78e4ebad7cdf</h3>
371 <h3>diff a @ 1:78e4ebad7cdf</h3>
372
372
373 <form class="search" action="/log">
373 <form class="search" action="/log">
374 <p></p>
374 <p></p>
375 <p><input name="rev" id="search1" type="text" size="30" /></p>
375 <p><input name="rev" id="search1" type="text" size="30" /></p>
376 <div id="hint">find changesets by author, revision,
376 <div id="hint">find changesets by author, revision,
377 files, or words in the commit message</div>
377 files, or words in the commit message</div>
378 </form>
378 </form>
379
379
380 <div class="description">b</div>
380 <div class="description">b</div>
381
381
382 <table id="changesetEntry">
382 <table id="changesetEntry">
383 <tr>
383 <tr>
384 <th>author</th>
384 <th>author</th>
385 <td>&#116;&#101;&#115;&#116;</td>
385 <td>&#116;&#101;&#115;&#116;</td>
386 </tr>
386 </tr>
387 <tr>
387 <tr>
388 <th>date</th>
388 <th>date</th>
389 <td>Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td>
389 <td>Thu Jan 01 00:00:00 1970 +0000 (1970-01-01)</td>
390 </tr>
390 </tr>
391 <tr>
391 <tr>
392 <th>parents</th>
392 <th>parents</th>
393 <td></td>
393 <td></td>
394 </tr>
394 </tr>
395 <tr>
395 <tr>
396 <th>children</th>
396 <th>children</th>
397 <td></td>
397 <td></td>
398 </tr>
398 </tr>
399
399
400 </table>
400 </table>
401
401
402 <div class="overflow">
402 <div class="overflow">
403 <div class="sourcefirst"> line diff</div>
403 <div class="sourcefirst"> line diff</div>
404
404
405 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100755
405 <div class="source bottomline parity0"><pre><a href="#l1.1" id="l1.1"> 1.1</a> new file mode 100755
406 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
406 <a href="#l1.2" id="l1.2"> 1.2</a> <span class="minusline">--- /dev/null
407 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
407 </span><a href="#l1.3" id="l1.3"> 1.3</a> <span class="plusline">+++ b/a
408 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
408 </span><a href="#l1.4" id="l1.4"> 1.4</a> <span class="atline">@@ -0,0 +1,1 @@
409 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
409 </span><a href="#l1.5" id="l1.5"> 1.5</a> <span class="plusline">+a
410 </span></pre></div>
410 </span></pre></div>
411 </div>
411 </div>
412 </div>
412 </div>
413 </div>
413 </div>
414
414
415
415
416
416
417 </body>
417 </body>
418 </html>
418 </html>
419
419
420 % test import rev as raw-rev
421 requesting all changes
422 adding changesets
423 adding manifests
424 adding file changes
425 added 1 changesets with 2 changes to 2 files
426 updating to branch default
427 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 applying http://localhost:20059/rev/1
420 % errors
429 % errors
General Comments 0
You need to be logged in to leave comments. Login now