Show More
@@ -0,0 +1,55 b'' | |||||
|
1 | #!/bin/sh | |||
|
2 | ||||
|
3 | mkdir webdir | |||
|
4 | cd webdir | |||
|
5 | ||||
|
6 | hg init a | |||
|
7 | echo a > a/a | |||
|
8 | hg --cwd a ci -Ama -d'1 0' | |||
|
9 | ||||
|
10 | hg init b | |||
|
11 | echo b > b/b | |||
|
12 | hg --cwd b ci -Amb -d'2 0' | |||
|
13 | ||||
|
14 | hg init c | |||
|
15 | echo c > c/c | |||
|
16 | hg --cwd c ci -Amc -d'3 0' | |||
|
17 | root=`pwd` | |||
|
18 | ||||
|
19 | cd .. | |||
|
20 | ||||
|
21 | cat > paths.conf <<EOF | |||
|
22 | [paths] | |||
|
23 | a=$root/a | |||
|
24 | b=$root/b | |||
|
25 | EOF | |||
|
26 | ||||
|
27 | hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \ | |||
|
28 | -A access-paths.log -E error-paths.log | |||
|
29 | cat hg.pid >> $DAEMON_PIDS | |||
|
30 | ||||
|
31 | echo % should give a 404 - file does not exist | |||
|
32 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw' | |||
|
33 | ||||
|
34 | echo % should succeed | |||
|
35 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw' | |||
|
36 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw' | |||
|
37 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw' | |||
|
38 | ||||
|
39 | echo % should give a 404 - repo is not published | |||
|
40 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw' | |||
|
41 | ||||
|
42 | cat > collections.conf <<EOF | |||
|
43 | [collections] | |||
|
44 | $root=$root | |||
|
45 | EOF | |||
|
46 | ||||
|
47 | hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf collections.conf \ | |||
|
48 | -A access-collections.log -E error-collections.log | |||
|
49 | cat hg.pid >> $DAEMON_PIDS | |||
|
50 | ||||
|
51 | echo % should succeed | |||
|
52 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw' | |||
|
53 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/a/file/tip/a?style=raw' | |||
|
54 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/b/file/tip/b?style=raw' | |||
|
55 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/c/file/tip/c?style=raw' |
@@ -0,0 +1,43 b'' | |||||
|
1 | adding a | |||
|
2 | adding b | |||
|
3 | adding c | |||
|
4 | % should give a 404 - file does not exist | |||
|
5 | 404 Not Found | |||
|
6 | ||||
|
7 | ||||
|
8 | error: Path not found: bork/ | |||
|
9 | % should succeed | |||
|
10 | 200 Script output follows | |||
|
11 | ||||
|
12 | ||||
|
13 | /a/ | |||
|
14 | /b/ | |||
|
15 | ||||
|
16 | 200 Script output follows | |||
|
17 | ||||
|
18 | a | |||
|
19 | 200 Script output follows | |||
|
20 | ||||
|
21 | b | |||
|
22 | % should give a 404 - repo is not published | |||
|
23 | 404 Not Found | |||
|
24 | ||||
|
25 | ||||
|
26 | error: repository c not found | |||
|
27 | % should succeed | |||
|
28 | 200 Script output follows | |||
|
29 | ||||
|
30 | ||||
|
31 | /a/ | |||
|
32 | /b/ | |||
|
33 | /c/ | |||
|
34 | ||||
|
35 | 200 Script output follows | |||
|
36 | ||||
|
37 | a | |||
|
38 | 200 Script output follows | |||
|
39 | ||||
|
40 | b | |||
|
41 | 200 Script output follows | |||
|
42 | ||||
|
43 | c |
@@ -6,7 +6,17 b'' | |||||
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
8 |
|
8 | |||
9 |
import o |
|
9 | import errno, mimetypes, os | |
|
10 | ||||
|
11 | class ErrorResponse(Exception): | |||
|
12 | def __init__(self, code, message=None): | |||
|
13 | Exception.__init__(self) | |||
|
14 | self.code = code | |||
|
15 | if message is None: | |||
|
16 | from httplib import responses | |||
|
17 | self.message = responses.get(code, 'Error') | |||
|
18 | else: | |||
|
19 | self.message = message | |||
10 |
|
20 | |||
11 | def get_mtime(repo_path): |
|
21 | def get_mtime(repo_path): | |
12 | store_path = os.path.join(repo_path, ".hg") |
|
22 | store_path = os.path.join(repo_path, ".hg") | |
@@ -40,9 +50,13 b' def staticfile(directory, fname, req):' | |||||
40 | req.header([('Content-type', ct), |
|
50 | req.header([('Content-type', ct), | |
41 | ('Content-length', str(os.path.getsize(path)))]) |
|
51 | ('Content-length', str(os.path.getsize(path)))]) | |
42 | return file(path, 'rb').read() |
|
52 | return file(path, 'rb').read() | |
43 |
except |
|
53 | except TypeError: | |
44 | # illegal fname or unreadable file |
|
54 | raise ErrorResponse(500, 'illegal file name') | |
45 | return "" |
|
55 | except OSError, err: | |
|
56 | if err.errno == errno.ENOENT: | |||
|
57 | raise ErrorResponse(404) | |||
|
58 | else: | |||
|
59 | raise ErrorResponse(500, err.strerror) | |||
46 |
|
60 | |||
47 | def style_map(templatepath, style): |
|
61 | def style_map(templatepath, style): | |
48 | """Return path to mapfile for a given style. |
|
62 | """Return path to mapfile for a given style. |
@@ -6,13 +6,13 b'' | |||||
6 | # This software may be used and distributed according to the terms |
|
6 | # This software may be used and distributed according to the terms | |
7 | # of the GNU General Public License, incorporated herein by reference. |
|
7 | # of the GNU General Public License, incorporated herein by reference. | |
8 |
|
8 | |||
9 | import os, mimetypes, re, zlib, mimetools, cStringIO, sys |
|
9 | import errno, os, mimetypes, re, zlib, mimetools, cStringIO, sys | |
10 | import tempfile, urllib, bz2 |
|
10 | import tempfile, urllib, bz2 | |
11 | from mercurial.node import * |
|
11 | from mercurial.node import * | |
12 | from mercurial.i18n import gettext as _ |
|
12 | from mercurial.i18n import gettext as _ | |
13 | from mercurial import mdiff, ui, hg, util, archival, streamclone, patch |
|
13 | from mercurial import mdiff, ui, hg, util, archival, streamclone, patch | |
14 | from mercurial import revlog, templater |
|
14 | from mercurial import revlog, templater | |
15 | from common import get_mtime, staticfile, style_map, paritygen |
|
15 | from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen | |
16 |
|
16 | |||
17 | def _up(p): |
|
17 | def _up(p): | |
18 | if p[0] != "/": |
|
18 | if p[0] != "/": | |
@@ -478,6 +478,9 b' class hgweb(object):' | |||||
478 | short = os.path.basename(remain) |
|
478 | short = os.path.basename(remain) | |
479 | files[short] = (f, n) |
|
479 | files[short] = (f, n) | |
480 |
|
480 | |||
|
481 | if not files: | |||
|
482 | raise ErrorResponse(404, 'Path not found: ' + path) | |||
|
483 | ||||
481 | def filelist(**map): |
|
484 | def filelist(**map): | |
482 | fl = files.keys() |
|
485 | fl = files.keys() | |
483 | fl.sort() |
|
486 | fl.sort() | |
@@ -845,14 +848,20 b' class hgweb(object):' | |||||
845 |
|
848 | |||
846 | cmd = req.form['cmd'][0] |
|
849 | cmd = req.form['cmd'][0] | |
847 |
|
850 | |||
848 | method = getattr(self, 'do_' + cmd, None) |
|
851 | try: | |
849 | if method: |
|
852 | method = getattr(self, 'do_' + cmd) | |
850 |
|
|
853 | method(req) | |
851 | method(req) |
|
854 | except revlog.LookupError, err: | |
852 | except (hg.RepoError, revlog.RevlogError), inst: |
|
855 | req.respond(404, self.t( | |
853 | req.write(self.t("error", error=str(inst))) |
|
856 | 'error', error='revision not found: %s' % err.name)) | |
854 | else: |
|
857 | except (hg.RepoError, revlog.RevlogError), inst: | |
855 | req.write(self.t("error", error='No such method: ' + cmd)) |
|
858 | req.respond('500 Internal Server Error', | |
|
859 | self.t('error', error=str(inst))) | |||
|
860 | except ErrorResponse, inst: | |||
|
861 | req.respond(inst.code, self.t('error', error=inst.message)) | |||
|
862 | except AttributeError: | |||
|
863 | req.respond(400, | |||
|
864 | self.t('error', error='No such method: ' + cmd)) | |||
856 | finally: |
|
865 | finally: | |
857 | self.t = None |
|
866 | self.t = None | |
858 |
|
867 | |||
@@ -1038,7 +1047,8 b' class hgweb(object):' | |||||
1038 | self.archive(req, req.form['node'][0], type_) |
|
1047 | self.archive(req, req.form['node'][0], type_) | |
1039 | return |
|
1048 | return | |
1040 |
|
1049 | |||
1041 |
req. |
|
1050 | req.respond(400, self.t('error', | |
|
1051 | error='Unsupported archive type: %s' % type_)) | |||
1042 |
|
1052 | |||
1043 | def do_static(self, req): |
|
1053 | def do_static(self, req): | |
1044 | fname = req.form['file'][0] |
|
1054 | fname = req.form['file'][0] | |
@@ -1047,8 +1057,7 b' class hgweb(object):' | |||||
1047 | static = self.config("web", "static", |
|
1057 | static = self.config("web", "static", | |
1048 | os.path.join(self.templatepath, "static"), |
|
1058 | os.path.join(self.templatepath, "static"), | |
1049 | untrusted=False) |
|
1059 | untrusted=False) | |
1050 | req.write(staticfile(static, fname, req) |
|
1060 | req.write(staticfile(static, fname, req)) | |
1051 | or self.t("error", error="%r not found" % fname)) |
|
|||
1052 |
|
1061 | |||
1053 | def do_capabilities(self, req): |
|
1062 | def do_capabilities(self, req): | |
1054 | caps = ['lookup', 'changegroupsubset'] |
|
1063 | caps = ['lookup', 'changegroupsubset'] | |
@@ -1198,7 +1207,11 b' class hgweb(object):' | |||||
1198 | else: |
|
1207 | else: | |
1199 | filename = '' |
|
1208 | filename = '' | |
1200 | error = getattr(inst, 'strerror', 'Unknown error') |
|
1209 | error = getattr(inst, 'strerror', 'Unknown error') | |
1201 | req.write('%s: %s\n' % (error, filename)) |
|
1210 | if inst.errno == errno.ENOENT: | |
|
1211 | code = 404 | |||
|
1212 | else: | |||
|
1213 | code = 500 | |||
|
1214 | req.respond(code, '%s: %s\n' % (error, filename)) | |||
1202 | finally: |
|
1215 | finally: | |
1203 | fp.close() |
|
1216 | fp.close() | |
1204 | os.unlink(tempname) |
|
1217 | os.unlink(tempname) |
@@ -9,7 +9,7 b'' | |||||
9 | import os, mimetools, cStringIO |
|
9 | import os, mimetools, cStringIO | |
10 | from mercurial.i18n import gettext as _ |
|
10 | from mercurial.i18n import gettext as _ | |
11 | from mercurial import ui, hg, util, templater |
|
11 | from mercurial import ui, hg, util, templater | |
12 | from common import get_mtime, staticfile, style_map, paritygen |
|
12 | from common import ErrorResponse, get_mtime, staticfile, style_map, paritygen | |
13 | from hgweb_mod import hgweb |
|
13 | from hgweb_mod import hgweb | |
14 |
|
14 | |||
15 | # This is a stopgap |
|
15 | # This is a stopgap | |
@@ -215,46 +215,47 b' class hgwebdir(object):' | |||||
215 | **dict(sort))) |
|
215 | **dict(sort))) | |
216 |
|
216 | |||
217 | try: |
|
217 | try: | |
218 | virtual = req.env.get("PATH_INFO", "").strip('/') |
|
218 | try: | |
219 | if virtual.startswith('static/'): |
|
219 | virtual = req.env.get("PATH_INFO", "").strip('/') | |
220 | static = os.path.join(templater.templatepath(), 'static') |
|
220 | if virtual.startswith('static/'): | |
221 | fname = virtual[7:] |
|
221 | static = os.path.join(templater.templatepath(), 'static') | |
222 | req.write(staticfile(static, fname, req) or |
|
222 | fname = virtual[7:] | |
223 | tmpl('error', error='%r not found' % fname)) |
|
223 | req.write(staticfile(static, fname, req)) | |
224 | elif virtual: |
|
224 | elif virtual: | |
225 | repos = dict(self.repos) |
|
225 | repos = dict(self.repos) | |
226 | while virtual: |
|
226 | while virtual: | |
227 | real = repos.get(virtual) |
|
227 | real = repos.get(virtual) | |
228 | if real: |
|
228 | if real: | |
229 | req.env['REPO_NAME'] = virtual |
|
229 | req.env['REPO_NAME'] = virtual | |
230 | try: |
|
230 | try: | |
231 | repo = hg.repository(parentui, real) |
|
231 | repo = hg.repository(parentui, real) | |
232 | hgweb(repo).run_wsgi(req) |
|
232 | hgweb(repo).run_wsgi(req) | |
233 |
|
|
233 | return | |
234 |
|
|
234 | except IOError, inst: | |
235 |
|
|
235 | raise ErrorResponse(500, inst.strerror) | |
236 |
|
|
236 | except hg.RepoError, inst: | |
237 | return |
|
237 | raise ErrorResponse(500, str(inst)) | |
238 |
|
238 | |||
239 | # browse subdirectories |
|
239 | # browse subdirectories | |
240 | subdir = virtual + '/' |
|
240 | subdir = virtual + '/' | |
241 | if [r for r in repos if r.startswith(subdir)]: |
|
241 | if [r for r in repos if r.startswith(subdir)]: | |
242 | makeindex(req, subdir) |
|
242 | makeindex(req, subdir) | |
243 | return |
|
243 | return | |
|
244 | ||||
|
245 | up = virtual.rfind('/') | |||
|
246 | if up < 0: | |||
|
247 | break | |||
|
248 | virtual = virtual[:up] | |||
244 |
|
249 | |||
245 | up = virtual.rfind('/') |
|
250 | req.respond(404, tmpl("notfound", repo=virtual)) | |
246 | if up < 0: |
|
|||
247 | break |
|
|||
248 | virtual = virtual[:up] |
|
|||
249 |
|
||||
250 | req.write(tmpl("notfound", repo=virtual)) |
|
|||
251 | else: |
|
|||
252 | if req.form.has_key('static'): |
|
|||
253 | static = os.path.join(templater.templatepath(), "static") |
|
|||
254 | fname = req.form['static'][0] |
|
|||
255 | req.write(staticfile(static, fname, req) |
|
|||
256 | or tmpl("error", error="%r not found" % fname)) |
|
|||
257 | else: |
|
251 | else: | |
258 | makeindex(req) |
|
252 | if req.form.has_key('static'): | |
|
253 | static = os.path.join(templater.templatepath(), "static") | |||
|
254 | fname = req.form['static'][0] | |||
|
255 | req.write(staticfile(static, fname, req)) | |||
|
256 | else: | |||
|
257 | makeindex(req) | |||
|
258 | except ErrorResponse, err: | |||
|
259 | req.respond(err.code, tmpl('error', error=err.message or '')) | |||
259 | finally: |
|
260 | finally: | |
260 | tmpl = None |
|
261 | tmpl = None |
@@ -8,6 +8,7 b'' | |||||
8 |
|
8 | |||
9 | import socket, cgi, errno |
|
9 | import socket, cgi, errno | |
10 | from mercurial.i18n import gettext as _ |
|
10 | from mercurial.i18n import gettext as _ | |
|
11 | from common import ErrorResponse | |||
11 |
|
12 | |||
12 | class wsgiapplication(object): |
|
13 | class wsgiapplication(object): | |
13 | def __init__(self, destmaker): |
|
14 | def __init__(self, destmaker): | |
@@ -42,25 +43,37 b' class _wsgirequest(object):' | |||||
42 | def read(self, count=-1): |
|
43 | def read(self, count=-1): | |
43 | return self.inp.read(count) |
|
44 | return self.inp.read(count) | |
44 |
|
45 | |||
45 |
def |
|
46 | def respond(self, status, *things): | |
46 | for thing in things: |
|
47 | for thing in things: | |
47 | if hasattr(thing, "__iter__"): |
|
48 | if hasattr(thing, "__iter__"): | |
48 | for part in thing: |
|
49 | for part in thing: | |
49 |
self. |
|
50 | self.respond(status, part) | |
50 | else: |
|
51 | else: | |
51 | thing = str(thing) |
|
52 | thing = str(thing) | |
52 | if self.server_write is None: |
|
53 | if self.server_write is None: | |
53 | if not self.headers: |
|
54 | if not self.headers: | |
54 | raise RuntimeError("request.write called before headers sent (%s)." % thing) |
|
55 | raise RuntimeError("request.write called before headers sent (%s)." % thing) | |
55 | self.server_write = self.start_response('200 Script output follows', |
|
56 | code = None | |
|
57 | if isinstance(status, ErrorResponse): | |||
|
58 | code = status.code | |||
|
59 | elif isinstance(status, int): | |||
|
60 | code = status | |||
|
61 | if code: | |||
|
62 | from httplib import responses | |||
|
63 | status = '%d %s' % ( | |||
|
64 | code, responses.get(code, 'Error')) | |||
|
65 | self.server_write = self.start_response(status, | |||
56 | self.headers) |
|
66 | self.headers) | |
57 | self.start_response = None |
|
67 | self.start_response = None | |
58 |
self.headers = |
|
68 | self.headers = [] | |
59 | try: |
|
69 | try: | |
60 | self.server_write(thing) |
|
70 | self.server_write(thing) | |
61 | except socket.error, inst: |
|
71 | except socket.error, inst: | |
62 | if inst[0] != errno.ECONNRESET: |
|
72 | if inst[0] != errno.ECONNRESET: | |
63 | raise |
|
73 | raise | |
|
74 | ||||
|
75 | def write(self, *things): | |||
|
76 | self.respond('200 Script output follows', *things) | |||
64 |
|
77 | |||
65 | def writelines(self, lines): |
|
78 | def writelines(self, lines): | |
66 | for line in lines: |
|
79 | for line in lines: |
@@ -14,3 +14,7 b' for h in headers:' | |||||
14 | print "%s: %s" % (h, response.getheader(h)) |
|
14 | print "%s: %s" % (h, response.getheader(h)) | |
15 |
|
15 | |||
16 | sys.stdout.write(response.read()) |
|
16 | sys.stdout.write(response.read()) | |
|
17 | ||||
|
18 | if 200 <= response.status <= 299: | |||
|
19 | sys.exit(0) | |||
|
20 | sys.exit(1) |
@@ -7,7 +7,25 b' echo foo > da/foo' | |||||
7 | echo foo > foo |
|
7 | echo foo > foo | |
8 | hg ci -Ambase -d '0 0' |
|
8 | hg ci -Ambase -d '0 0' | |
9 | hg serve -p $HGPORT -d --pid-file=hg.pid |
|
9 | hg serve -p $HGPORT -d --pid-file=hg.pid | |
|
10 | cat hg.pid >> $DAEMON_PIDS | |||
10 | echo % manifest |
|
11 | echo % manifest | |
11 | ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/?style=raw') |
|
12 | ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/?style=raw') | |
12 | ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/da?style=raw') |
|
13 | ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/da?style=raw') | |
13 | kill `cat hg.pid` |
|
14 | ||
|
15 | echo % plain file | |||
|
16 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/foo?style=raw' | |||
|
17 | ||||
|
18 | echo % should give a 404 - static file that does not exist | |||
|
19 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/static/bogus' | |||
|
20 | ||||
|
21 | echo % should give a 404 - bad revision | |||
|
22 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/spam/foo?style=raw' | |||
|
23 | ||||
|
24 | echo % should give a 400 - bad command | |||
|
25 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/foo?cmd=spam&style=raw' | |||
|
26 | ||||
|
27 | echo % should give a 404 - file does not exist | |||
|
28 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/file/tip/bork?style=raw' | |||
|
29 | ||||
|
30 | echo % static file | |||
|
31 | "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/static/style-gitweb.css' |
@@ -14,3 +14,123 b' 200 Script output follows' | |||||
14 | -rw-r--r-- 4 foo |
|
14 | -rw-r--r-- 4 foo | |
15 |
|
15 | |||
16 |
|
16 | |||
|
17 | % plain file | |||
|
18 | 200 Script output follows | |||
|
19 | ||||
|
20 | foo | |||
|
21 | % should give a 404 - static file that does not exist | |||
|
22 | 404 Not Found | |||
|
23 | ||||
|
24 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> | |||
|
25 | <html> | |||
|
26 | <head> | |||
|
27 | <link rel="icon" href="/static/hgicon.png" type="image/png"> | |||
|
28 | <meta name="robots" content="index, nofollow" /> | |||
|
29 | <link rel="stylesheet" href="/static/style.css" type="text/css" /> | |||
|
30 | ||||
|
31 | <title>Mercurial Error</title> | |||
|
32 | </head> | |||
|
33 | <body> | |||
|
34 | ||||
|
35 | <h2>Mercurial Error</h2> | |||
|
36 | ||||
|
37 | <p> | |||
|
38 | An error occured while processing your request: | |||
|
39 | </p> | |||
|
40 | <p> | |||
|
41 | Not Found | |||
|
42 | </p> | |||
|
43 | ||||
|
44 | ||||
|
45 | <div class="logo"> | |||
|
46 | powered by<br/> | |||
|
47 | <a href="http://www.selenic.com/mercurial/">mercurial</a> | |||
|
48 | </div> | |||
|
49 | ||||
|
50 | </body> | |||
|
51 | </html> | |||
|
52 | ||||
|
53 | % should give a 404 - bad revision | |||
|
54 | 404 Not Found | |||
|
55 | ||||
|
56 | ||||
|
57 | error: revision not found: spam | |||
|
58 | % should give a 400 - bad command | |||
|
59 | 400 Bad Request | |||
|
60 | ||||
|
61 | ||||
|
62 | error: No such method: spam | |||
|
63 | % should give a 404 - file does not exist | |||
|
64 | 404 Not Found | |||
|
65 | ||||
|
66 | ||||
|
67 | error: Path not found: bork/ | |||
|
68 | % static file | |||
|
69 | 200 Script output follows | |||
|
70 | ||||
|
71 | body { font-family: sans-serif; font-size: 12px; margin:0px; border:solid #d9d8d1; border-width:1px; margin:10px; } | |||
|
72 | a { color:#0000cc; } | |||
|
73 | a:hover, a:visited, a:active { color:#880000; } | |||
|
74 | div.page_header { height:25px; padding:8px; font-size:18px; font-weight:bold; background-color:#d9d8d1; } | |||
|
75 | div.page_header a:visited { color:#0000cc; } | |||
|
76 | div.page_header a:hover { color:#880000; } | |||
|
77 | div.page_nav { padding:8px; } | |||
|
78 | div.page_nav a:visited { color:#0000cc; } | |||
|
79 | div.page_path { padding:8px; border:solid #d9d8d1; border-width:0px 0px 1px} | |||
|
80 | div.page_footer { padding:4px 8px; background-color: #d9d8d1; } | |||
|
81 | div.page_footer_text { float:left; color:#555555; font-style:italic; } | |||
|
82 | div.page_body { padding:8px; } | |||
|
83 | div.title, a.title { | |||
|
84 | display:block; padding:6px 8px; | |||
|
85 | font-weight:bold; background-color:#edece6; text-decoration:none; color:#000000; | |||
|
86 | } | |||
|
87 | a.title:hover { background-color: #d9d8d1; } | |||
|
88 | div.title_text { padding:6px 0px; border: solid #d9d8d1; border-width:0px 0px 1px; } | |||
|
89 | div.log_body { padding:8px 8px 8px 150px; } | |||
|
90 | .age { white-space:nowrap; } | |||
|
91 | span.age { position:relative; float:left; width:142px; font-style:italic; } | |||
|
92 | div.log_link { | |||
|
93 | padding:0px 8px; | |||
|
94 | font-size:10px; font-family:sans-serif; font-style:normal; | |||
|
95 | position:relative; float:left; width:136px; | |||
|
96 | } | |||
|
97 | div.list_head { padding:6px 8px 4px; border:solid #d9d8d1; border-width:1px 0px 0px; font-style:italic; } | |||
|
98 | a.list { text-decoration:none; color:#000000; } | |||
|
99 | a.list:hover { text-decoration:underline; color:#880000; } | |||
|
100 | table { padding:8px 4px; } | |||
|
101 | th { padding:2px 5px; font-size:12px; text-align:left; } | |||
|
102 | tr.light:hover, .parity0:hover { background-color:#edece6; } | |||
|
103 | tr.dark, .parity1 { background-color:#f6f6f0; } | |||
|
104 | tr.dark:hover, .parity1:hover { background-color:#edece6; } | |||
|
105 | td { padding:2px 5px; font-size:12px; vertical-align:top; } | |||
|
106 | td.link { padding:2px 5px; font-family:sans-serif; font-size:10px; } | |||
|
107 | div.pre { font-family:monospace; font-size:12px; white-space:pre; } | |||
|
108 | div.diff_info { font-family:monospace; color:#000099; background-color:#edece6; font-style:italic; } | |||
|
109 | div.index_include { border:solid #d9d8d1; border-width:0px 0px 1px; padding:12px 8px; } | |||
|
110 | div.search { margin:4px 8px; position:absolute; top:56px; right:12px } | |||
|
111 | .linenr { color:#999999; text-decoration:none } | |||
|
112 | a.rss_logo { | |||
|
113 | float:right; padding:3px 0px; width:35px; line-height:10px; | |||
|
114 | border:1px solid; border-color:#fcc7a5 #7d3302 #3e1a01 #ff954e; | |||
|
115 | color:#ffffff; background-color:#ff6600; | |||
|
116 | font-weight:bold; font-family:sans-serif; font-size:10px; | |||
|
117 | text-align:center; text-decoration:none; | |||
|
118 | } | |||
|
119 | a.rss_logo:hover { background-color:#ee5500; } | |||
|
120 | pre { margin: 0; } | |||
|
121 | span.logtags span { | |||
|
122 | padding: 0px 4px; | |||
|
123 | font-size: 10px; | |||
|
124 | font-weight: normal; | |||
|
125 | border: 1px solid; | |||
|
126 | background-color: #ffaaff; | |||
|
127 | border-color: #ffccff #ff00ee #ff00ee #ffccff; | |||
|
128 | } | |||
|
129 | span.logtags span.tagtag { | |||
|
130 | background-color: #ffffaa; | |||
|
131 | border-color: #ffffcc #ffee00 #ffee00 #ffffcc; | |||
|
132 | } | |||
|
133 | span.logtags span.branchtag { | |||
|
134 | background-color: #aaffaa; | |||
|
135 | border-color: #ccffcc #00cc33 #00cc33 #ccffcc; | |||
|
136 | } |
General Comments 0
You need to be logged in to leave comments.
Login now