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