##// END OF EJS Templates
Merge from crew-stable.
Dirkjan Ochtman -
r6457:7ef281e7 merge default
parent child Browse files
Show More
@@ -0,0 +1,21 b''
1 #!/usr/bin/env python
2 # Dump revlogs as raw data stream
3 # $ find .hg/store/ -name "*.i" | xargs dumprevlog > repo.dump
4
5 import sys
6 from mercurial import revlog, node
7
8 for f in sys.argv[1:]:
9 r = revlog.revlog(open, f)
10 print "file:", f
11 for i in xrange(r.count()):
12 n = r.node(i)
13 p = r.parents(n)
14 d = r.revision(n)
15 print "node:", node.hex(n)
16 print "linkrev:", r.linkrev(n)
17 print "parents:", node.hex(p[0]), node.hex(p[1])
18 print "length:", len(d)
19 print "-start-"
20 print d
21 print "-end-"
@@ -0,0 +1,34 b''
1 #!/usr/bin/env python
2 # Undump a dump from dumprevlog
3 # $ hg init
4 # $ undumprevlog < repo.dump
5
6 import sys
7 from mercurial import revlog, node, util, transaction
8
9 opener = util.opener('.', False)
10 tr = transaction.transaction(sys.stderr.write, opener, "undump.journal")
11 while 1:
12 l = sys.stdin.readline()
13 if not l:
14 break
15 if l.startswith("file:"):
16 f = l[6:-1]
17 r = revlog.revlog(opener, f)
18 print f
19 elif l.startswith("node:"):
20 n = node.bin(l[6:-1])
21 elif l.startswith("linkrev:"):
22 lr = int(l[9:-1])
23 elif l.startswith("parents:"):
24 p = l[9:-1].split()
25 p1 = node.bin(p[0])
26 p2 = node.bin(p[1])
27 elif l.startswith("length:"):
28 length = int(l[8:-1])
29 sys.stdin.readline() # start marker
30 d = sys.stdin.read(length)
31 sys.stdin.readline() # end marker
32 r.addrevision(d, tr, lr, p1, p2)
33
34 tr.close()
@@ -0,0 +1,143 b''
1 # hgweb/webutil.py - utility library for the web interface.
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
5 #
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
8
9 import os
10 from mercurial.node import hex, nullid
11 from mercurial.repo import RepoError
12 from mercurial import util
13
14 def up(p):
15 if p[0] != "/":
16 p = "/" + p
17 if p[-1] == "/":
18 p = p[:-1]
19 up = os.path.dirname(p)
20 if up == "/":
21 return "/"
22 return up + "/"
23
24 def revnavgen(pos, pagelen, limit, nodefunc):
25 def seq(factor, limit=None):
26 if limit:
27 yield limit
28 if limit >= 20 and limit <= 40:
29 yield 50
30 else:
31 yield 1 * factor
32 yield 3 * factor
33 for f in seq(factor * 10):
34 yield f
35
36 def nav(**map):
37 l = []
38 last = 0
39 for f in seq(1, pagelen):
40 if f < pagelen or f <= last:
41 continue
42 if f > limit:
43 break
44 last = f
45 if pos + f < limit:
46 l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
47 if pos - f >= 0:
48 l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
49
50 try:
51 yield {"label": "(0)", "node": hex(nodefunc('0').node())}
52
53 for label, node in l:
54 yield {"label": label, "node": node}
55
56 yield {"label": "tip", "node": "tip"}
57 except RepoError:
58 pass
59
60 return nav
61
62 def siblings(siblings=[], hiderev=None, **args):
63 siblings = [s for s in siblings if s.node() != nullid]
64 if len(siblings) == 1 and siblings[0].rev() == hiderev:
65 return
66 for s in siblings:
67 d = {'node': hex(s.node()), 'rev': s.rev()}
68 if hasattr(s, 'path'):
69 d['file'] = s.path()
70 d.update(args)
71 yield d
72
73 def renamelink(fctx):
74 r = fctx.renamed()
75 if r:
76 return [dict(file=r[0], node=hex(r[1]))]
77 return []
78
79 def nodetagsdict(repo, node):
80 return [{"name": i} for i in repo.nodetags(node)]
81
82 def nodebranchdict(repo, ctx):
83 branches = []
84 branch = ctx.branch()
85 # If this is an empty repo, ctx.node() == nullid,
86 # ctx.branch() == 'default', but branchtags() is
87 # an empty dict. Using dict.get avoids a traceback.
88 if repo.branchtags().get(branch) == ctx.node():
89 branches.append({"name": branch})
90 return branches
91
92 def nodeinbranch(repo, ctx):
93 branches = []
94 branch = ctx.branch()
95 if branch != 'default' and repo.branchtags().get(branch) != ctx.node():
96 branches.append({"name": branch})
97 return branches
98
99 def nodebranchnodefault(ctx):
100 branches = []
101 branch = ctx.branch()
102 if branch != 'default':
103 branches.append({"name": branch})
104 return branches
105
106 def showtag(repo, tmpl, t1, node=nullid, **args):
107 for t in repo.nodetags(node):
108 yield tmpl(t1, tag=t, **args)
109
110 def cleanpath(repo, path):
111 path = path.lstrip('/')
112 return util.canonpath(repo.root, '', path)
113
114 def changectx(repo, req):
115 if 'node' in req.form:
116 changeid = req.form['node'][0]
117 elif 'manifest' in req.form:
118 changeid = req.form['manifest'][0]
119 else:
120 changeid = repo.changelog.count() - 1
121
122 try:
123 ctx = repo.changectx(changeid)
124 except RepoError:
125 man = repo.manifest
126 mn = man.lookup(changeid)
127 ctx = repo.changectx(man.linkrev(mn))
128
129 return ctx
130
131 def filectx(repo, req):
132 path = cleanpath(repo, req.form['file'][0])
133 if 'node' in req.form:
134 changeid = req.form['node'][0]
135 else:
136 changeid = req.form['filenode'][0]
137 try:
138 ctx = repo.changectx(changeid)
139 fctx = ctx.filectx(path)
140 except RepoError:
141 fctx = repo.filectx(path, fileid=changeid)
142
143 return fctx
@@ -0,0 +1,169 b''
1 /*
2 parsers.c - efficient content parsing
3
4 Copyright 2008 Matt Mackall <mpm@selenic.com> and others
5
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
8 */
9
10 #include <Python.h>
11 #include <ctype.h>
12 #include <string.h>
13
14 static int hexdigit(char c)
15 {
16 if (c >= '0' && c <= '9')
17 return c - '0';
18
19 if (c >= 'A' && c <= 'F')
20 return c - 'A' + 10;
21
22 if (c >= 'a' && c <= 'f')
23 return c - 'a' + 10;
24
25 return -1;
26 }
27
28 /*
29 * Turn a hex-encoded string into binary.
30 */
31 static PyObject *unhexlify(const char *str, int len)
32 {
33 PyObject *ret = NULL;
34 const char *c;
35 char *d;
36
37 if (len % 2) {
38 PyErr_SetString(PyExc_ValueError,
39 "input is not even in length");
40 goto bail;
41 }
42
43 ret = PyString_FromStringAndSize(NULL, len / 2);
44 if (!ret)
45 goto bail;
46
47 d = PyString_AsString(ret);
48 if (!d)
49 goto bail;
50
51 for (c = str; c < str + len;) {
52 int hi = hexdigit(*c++);
53 int lo = hexdigit(*c++);
54
55 if (hi == -1 || lo == -1) {
56 PyErr_SetString(PyExc_ValueError,
57 "input contains non-hex character");
58 goto bail;
59 }
60
61 *d++ = (hi << 4) | lo;
62 }
63
64 goto done;
65
66 bail:
67 Py_XDECREF(ret);
68 ret = NULL;
69 done:
70 return ret;
71 }
72
73 /*
74 * This code assumes that a manifest is stitched together with newline
75 * ('\n') characters.
76 */
77 static PyObject *parse_manifest(PyObject *self, PyObject *args)
78 {
79 PyObject *mfdict, *fdict;
80 char *str, *cur, *start, *zero;
81 int len;
82
83 if (!PyArg_ParseTuple(args, "O!O!s#:parse_manifest",
84 &PyDict_Type, &mfdict,
85 &PyDict_Type, &fdict,
86 &str, &len))
87 goto quit;
88
89 for (start = cur = str, zero = NULL; cur < str + len; cur++) {
90 PyObject *file = NULL, *node = NULL;
91 PyObject *flags = NULL;
92 int nlen;
93
94 if (!*cur) {
95 zero = cur;
96 continue;
97 }
98 else if (*cur != '\n')
99 continue;
100
101 if (!zero) {
102 PyErr_SetString(PyExc_ValueError,
103 "manifest entry has no separator");
104 goto quit;
105 }
106
107 file = PyString_FromStringAndSize(start, zero - start);
108 if (!file)
109 goto bail;
110
111 nlen = cur - zero - 1;
112
113 node = unhexlify(zero + 1, nlen > 40 ? 40 : nlen);
114 if (!node)
115 goto bail;
116
117 if (nlen > 40) {
118 PyObject *flags;
119
120 flags = PyString_FromStringAndSize(zero + 41,
121 nlen - 40);
122 if (!flags)
123 goto bail;
124
125 if (PyDict_SetItem(fdict, file, flags) == -1)
126 goto bail;
127 }
128
129 if (PyDict_SetItem(mfdict, file, node) == -1)
130 goto bail;
131
132 start = cur + 1;
133 zero = NULL;
134
135 Py_XDECREF(flags);
136 Py_XDECREF(node);
137 Py_XDECREF(file);
138 continue;
139 bail:
140 Py_XDECREF(flags);
141 Py_XDECREF(node);
142 Py_XDECREF(file);
143 goto quit;
144 }
145
146 if (len > 0 && *(cur - 1) != '\n') {
147 PyErr_SetString(PyExc_ValueError,
148 "manifest contains trailing garbage");
149 goto quit;
150 }
151
152 Py_INCREF(Py_None);
153 return Py_None;
154
155 quit:
156 return NULL;
157 }
158
159 static char parsers_doc[] = "Efficient content parsing.";
160
161 static PyMethodDef methods[] = {
162 {"parse_manifest", parse_manifest, METH_VARARGS, "parse a manifest\n"},
163 {NULL, NULL}
164 };
165
166 PyMODINIT_FUNC initparsers(void)
167 {
168 Py_InitModule3("parsers", methods, parsers_doc);
169 }
@@ -0,0 +1,71 b''
1 {header}
2 <title>{repo|escape}: {node|short}</title>
3 </head>
4 <body>
5 <div class="container">
6 <div class="menu">
7 <div class="logo">
8 <a href="http://www.selenic.com/mercurial/">
9 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
10 </div>
11 <ul>
12 <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
13 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
14 </ul>
15 <ul>
16 <li class="active">changeset</li>
17 <li><a href="{url}file/{node|short}{sessionvars%urlparameter}">browse</a></li>
18 </ul>
19 <ul>
20 {archives%archiveentry}</ul>
21 </ul>
22 </div>
23
24 <div class="main">
25
26 <h2>{repo|escape}</h2>
27 <h3>changeset {rev}:{node|short} {changesettag}</h3>
28
29 <form class="search" action="{url}log">
30 {sessionvars%hiddenformentry}
31 <p><input name="rev" id="search1" type="text" size="30"></p>
32 </form>
33
34 <div class="description">{desc|strip|escape|addbreaks}</div>
35
36 <table id="changesetEntry">
37 <tr>
38 <th class="author">author</th>
39 <td class="author">{author|obfuscate}</td>
40 </tr>
41 <tr>
42 <th class="date">date</th>
43 <td class="date">{date|date} ({date|age} ago)</td></tr>
44 <tr>
45 <th class="author">parents</th>
46 <td class="author">{parent%changesetparent}</td>
47 </tr>
48 <tr>
49 <th class="author">children</th>
50 <td class="author">{child%changesetchild}</td>
51 </tr>
52 <tr>
53 <th class="files">files</th>
54 <td class="files">{files}</td></tr>
55 </tr>
56 </table>
57 <tr>
58
59 <div class="overflow">
60 <table class="bigtable">
61 <tr>
62 <th class="lineno">Line</th>
63 <th class="source">Diff</th>
64 </tr>
65 </table>
66 {diff}
67 </div>
68 </div>
69 {footer}
70
71
@@ -0,0 +1,39 b''
1 {header}
2 <title>{repo|escape}: error</title>
3 </head>
4 <body>
5
6 <div class="content">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}log{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16 </div>
17
18 <div class="main">
19
20 <h2>{repo|escape}</h2>
21 <h3>error</h3>
22
23 <form class="search" action="{url}log">
24 {sessionvars%hiddenformentry}
25 <p><input name="rev" id="search1" type="text" size="30"></p>
26 </form>
27
28 <div class="description">
29 <p>
30 An error occurred while processing your request:
31 </p>
32 <p>
33 {error|escape}
34 </p>
35 </div>
36 </div>
37 </div>
38
39 {footer}
@@ -0,0 +1,76 b''
1 {header}
2 <title>{repo|escape}: {file|escape} annotate</title>
3 </head>
4 <body>
5
6 <div class="container">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16
17 <ul>
18 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
19 <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
20 </ul>
21 <ul>
22 <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
23 <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
24 <li class="active">annotate</li>
25 <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
26 <li><a href="{url}raw-annotate/{node|short}/{file|urlescape}">raw</a></li>
27 </ul>
28 </div>
29
30 <div class="main">
31 <h2>{repo|escape}</h2>
32 <h3>Annotate {file|escape} @ {diff}:{node|short}</h2>
33
34 <form class="search" action="{url}log">
35 {sessionvars%hiddenformentry}
36 <p><input name="rev" id="search1" type="text" size="30"></p>
37 </form>
38
39 <div class="description">{desc|strip|escape|addbreaks}</div>
40
41 <table id="changesetEntry">
42 <tr>
43 <th class="author">author</th>
44 <td class="author">{author|obfuscate}</td>
45 </tr>
46 <tr>
47 <th class="date">date</th>
48 <td class="date">{date|date} ({date|age} ago)</td>
49 </tr>
50 <tr>
51 <th class="author">parents</th>
52 <td class="author">{parent%filerevparent}</td>
53 </tr>
54 <tr>
55 <th class="author">children</th>
56 <td class="author">{child%filerevchild}</td>
57 </tr>
58 {changesettag}
59 </table>
60
61 <br/>
62
63 <div class="overflow">
64 <table class="bigtable">
65 <tr>
66 <th class="annotate">Rev</th>
67 <th class="lineno">Line</th>
68 <th class="line">Source</th>
69 </tr>
70 {annotate%annotateline}
71 </table>
72 </div>
73 </div>
74 </div>
75
76 {footer}
@@ -0,0 +1,74 b''
1 {header}
2 <title>{repo|escape}: {file|escape} diff</title>
3 </head>
4 <body>
5
6 <div class="container">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16 <ul>
17 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
18 <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
19 </ul>
20 <ul>
21 <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
22 <li class="active">diff</li>
23 <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
24 <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
25 <li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
26 </ul>
27 </div>
28
29 <div class="main">
30 <h2>{repo|escape}</h2>
31 <h3>diff {file|escape} @ {rev}:{node|short}</h3>
32
33 <form class="search" action="{url}log">
34 {sessionvars%hiddenformentry}
35 <p><input name="rev" id="search1" type="text" size="30"></p>
36 </form>
37
38 <div class="description">{desc|strip|escape|addbreaks}</div>
39
40 <table id="changesetEntry">
41 <tr>
42 <th>author</th>
43 <td>{author|obfuscate}</td>
44 </tr>
45 <tr>
46 <th>date</th>
47 <td>{date|date} ({date|age} ago)</td>
48 </tr>
49 <tr>
50 <th>parents</th>
51 <td>{parent%filerevparent}</td>
52 </tr>
53 <tr>
54 <th>children</th>
55 <td>{child%filerevchild}</td>
56 </tr>
57 {changesettag}
58 </table>
59
60 <div class="overflow">
61 <table class="bigtable">
62 <tr>
63 <th class="lineno">Line</th>
64 <th class="source">Diff</th>
65 </tr>
66 <table>
67 {diff}
68 </div>
69 </div>
70 </div>
71
72 {footer}
73
74
@@ -0,0 +1,58 b''
1 {header}
2 <title>{repo|escape}: {file|escape} history</title>
3 <link rel="alternate" type="application/atom+xml"
4 href="{url}atom-log/tip/{file|urlescape}" title="Atom feed for {repo|escape}:{file}">
5 <link rel="alternate" type="application/rss+xml"
6 href="{url}rss-log/tip/{file|urlescape}" title="RSS feed for {repo|escape}:{file}">
7 </head>
8 </head>
9 <body>
10
11 <div class="container">
12 <div class="menu">
13 <div class="logo">
14 <a href="http://www.selenic.com/mercurial/">
15 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
16 </div>
17 <ul>
18 <li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
19 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
20 </ul>
21 <ul>
22 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
23 <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
24 </ul>
25 <ul>
26 <li><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file</a></li>
27 <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
28 <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
29 <li class="active">file log</li>
30 <li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
31 </ul>
32 </div>
33
34 <div class="main">
35
36 <h2>{repo|escape}</h2>
37 <h3>log {file|escape}</h3>
38
39 <form class="search" action="{url}log">
40 {sessionvars%hiddenformentry}
41 <p><input name="rev" id="search1" type="text" size="30"></p>
42 </form>
43
44 <div class="navigate">{nav%filenaventry}</div>
45
46 <table class="bigtable">
47 <tr>
48 <th class="age">Age</td>
49 <th class="author">Author</td>
50 <th class="description">Description</td>
51 </tr>
52 {entries%filelogentry}
53 </table>
54
55 </div>
56 </div>
57
58 {footer}
@@ -0,0 +1,5 b''
1 <tr class="parity{parity}">
2 <td class="age">{date|age}</td>
3 <td class="author">{author|person}</td>
4 <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape}</a></td>
5 </tr>
@@ -0,0 +1,73 b''
1 {header}
2 <title>{repo|escape}: {node|short} {file|escape}</title>
3 </head>
4 <body>
5
6 <div class="container">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16 <ul>
17 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
18 <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
19 </ul>
20 <ul>
21 <li class="active">file</li>
22 <li><a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">diff</a></li>
23 <li><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">annotate</a></li>
24 <li><a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">file log</a></li>
25 <li><a href="{url}raw-file/{node|short}/{file|urlescape}">raw</a></li>
26 </ul>
27 </div>
28
29 <div class="main">
30
31 <h2>{repo|escape}</h2>
32 <h3>view {file|escape} @ {rev}:{node|short}</h3>
33
34 <form class="search" action="{url}log">
35 {sessionvars%hiddenformentry}
36 <p><input name="rev" id="search1" type="text" size="30"></p>
37 </form>
38
39 <div class="description">{desc|strip|escape|addbreaks}</div>
40
41 <table id="changesetEntry">
42 <tr>
43 <th class="author">author</th>
44 <td class="author">{author|obfuscate}</td>
45 </tr>
46 <tr>
47 <th class="date">date</th>
48 <td class="date">{date|date} ({date|age} ago)</td>
49 </tr>
50 <tr>
51 <th class="author">parents</th>
52 <td class="author">{parent%filerevparent}</td>
53 </tr>
54 <tr>
55 <th class="author">children</th>
56 <td class="author">{child%filerevchild}</td>
57 </tr>
58 {changesettag}
59 </table>
60
61 <div class="overflow">
62 <table class="bigtable">
63 <tr>
64 <th class="lineno">Line</th>
65 <th class="source">Source</th>
66 </tr>
67 {text%fileline}
68 </table>
69 </div>
70 </div>
71 </div>
72
73 {footer}
@@ -0,0 +1,4 b''
1 {motd}
2
3 </body>
4 </html>
@@ -0,0 +1,7 b''
1 <!-- quirksmode -->
2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
3 <html>
4 <head>
5 <link rel="icon" href="{staticurl}hgicon.png" type="image/png">
6 <meta name="robots" content="index, nofollow" />
7 <link rel="stylesheet" href="{staticurl}style-coal.css" type="text/css" />
@@ -0,0 +1,19 b''
1 {header}
2 <title>Mercurial repositories index</title>
3 </head>
4 <body>
5
6 <h2>Mercurial Repositories</h2>
7
8 <table>
9 <tr>
10 <td><a href="?sort={sort_name}">Name</a></td>
11 <td><a href="?sort={sort_description}">Description</a></td>
12 <td><a href="?sort={sort_contact}">Contact</a></td>
13 <td><a href="?sort={sort_lastchange}">Last change</a></td>
14 <td>&nbsp;</td>
15 <tr>
16 {entries%indexentry}
17 </table>
18
19 {footer}
@@ -0,0 +1,53 b''
1 {header}
2 <title>{repo|escape}: {node|short} {path|escape}</title>
3 </head>
4 <body>
5
6 <div class="container">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}shortlog/{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16 <ul>
17 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
18 <li class="active">browse</li>
19 </ul>
20 <ul>
21 {archives%archiveentry}
22 </ul>
23 </div>
24
25 <div class="main">
26
27 <h2>{repo|escape}</h2>
28 <h3>directory {path|escape} @ {rev}:{node|short} {tags%changelogtag}</h3>
29
30 <form class="search" action="{url}log">
31 {sessionvars%hiddenformentry}
32 <p><input name="rev" id="search1" type="text" size="30"></p>
33 </form>
34
35 <table class="bigtable">
36 <tr>
37 <th class="permissions">permissions</th>
38 <th class="date">date</th>
39 <th class="size">size</th>
40 <th class="name">name</th>
41 </tr>
42 <tr class="parity{upparity}">
43 <td class="permissions">drwxr-xr-x
44 <td class="date">
45 <td class="size">
46 <td class="name"><a href="{url}file/{node|short}{up|urlescape}{sessionvars%urlparameter}">[up]</a>
47 </tr>
48 {dentries%direntry}
49 {fentries%fileentry}
50 </table>
51 </div>
52 </div>
53 {footer}
@@ -0,0 +1,69 b''
1 default = 'shortlog'
2
3 mimetype = 'text/html; charset={encoding}'
4 header = header.tmpl
5 footer = footer.tmpl
6 search = search.tmpl
7
8 changelog = shortlog.tmpl
9 shortlog = shortlog.tmpl
10 shortlogentry = shortlogentry.tmpl
11
12 naventry = '<a href="{url}log/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
13 navshortentry = '<a href="{url}shortlog/{node|short}{sessionvars%urlparameter}">{label|escape}</a> '
14 filenaventry = '<a href="{url}log/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{label|escape}</a> '
15 filedifflink = '<a href="{url}diff/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
16 filenodelink = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}</a> '
17 fileellipses = '...'
18 changelogentry = shortlogentry.tmpl
19 searchentry = shortlogentry.tmpl
20 changeset = changeset.tmpl
21 manifest = manifest.tmpl
22
23 direntry = '<tr class="parity{parity}"><td class="permissions">drwxr-xr-x</td><td class="date"></td><td class="size"></td><td class="name"><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">{basename|escape}/</a></td></tr>'
24 fileentry = '<tr class="parity{parity}"><td class="permissions">{permissions|permissions}&nbsp;</td><td class="date">{date|isodate}&nbsp;</td><td class="size">{size}&nbsp;</td><td clase="filename"><a href="{url}file/{node|short}/{file|urlescape}#l1{sessionvars%urlparameter}">{basename|escape}</a></td></tr>'
25
26 filerevision = filerevision.tmpl
27 fileannotate = fileannotate.tmpl
28 filediff = filediff.tmpl
29 filelog = filelog.tmpl
30 fileline = '<tr class="parity{parity}"><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
31 filelogentry = filelogentry.tmpl
32
33 annotateline = '<tr class="parity{parity}"><td class="annotate"><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}#{targetline}">{author|obfuscate}@{rev}</a></td><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
34
35 diffblock = '<table class="bigtable parity{parity}">{lines}</table>'
36 difflineplus = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source plusline">{line|escape}</td></tr>'
37 difflineminus = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source minusline">{line|escape}</td></tr>'
38 difflineat = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source atline">{line|escape}</td></tr>'
39 diffline = '<tr><td class="lineno"><a href="#{lineid}" id="{lineid}">{linenumber}</a></td><td class="source">{line|escape}</td></tr>'
40
41 changelogparent = '<tr><th class="parent">parent {rev}:</th><td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
42
43 changesetparent = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a> '
44
45 filerevparent = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a> '
46 filerevchild = '<a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a> '
47
48 filerename = '{file|escape}@'
49 filelogrename = '<tr><th>base:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{file|escape}@{node|short}</a></td></tr>'
50 fileannotateparent = '<tr><td class="metatag">parent:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{rename%filerename}{node|short}</a></td></tr>'
51 changesetchild = '<a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a>'
52 changelogchild = '<tr><th class="child">child</th><td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
53 fileannotatechild = '<tr><td class="metatag">child:</td><td><a href="{url}annotate/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
54 tags = tags.tmpl
55 tagentry = '<tr class="tagEntry parity{parity}"><td><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{tag|escape}</a></td><td class="node">{node|short}</td></tr>'
56 changelogtag = '<tr><th class="tag">tag:</th><td class="tag">{tag|escape}</td></tr>'
57 changelogtag = '<span class="tag">{name|escape}</span> '
58 changesettag = '<span class="tag">{tag|escape}</span> '
59 filediffparent = '<tr><th class="parent">parent {rev}:</th><td class="parent"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
60 filelogparent = '<tr><th>parent {rev}:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
61 filediffchild = '<tr><th class="child">child {rev}:</th><td class="child"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
62 filelogchild = '<tr><th>child {rev}:</th><td><a href="{url}file/{node|short}/{file|urlescape}{sessionvars%urlparameter}">{node|short}</a></td></tr>'
63 indexentry = '<tr class="parity{parity}"><td><a href="{url}{sessionvars%urlparameter}">{name|escape}</a></td><td>{description}</td><td>{contact|obfuscate}</td><td class="age">{lastchange|age} ago</td><td class="indexlinks"><a href="{url}rss-log">RSS</a> <a href="{url}atom-log">Atom</a> {archives%archiveentry}</td></tr>'
64 index = index.tmpl
65 archiveentry = '<li><a href="{url}archive/{node|short}{extension|urlescape}">{type|escape}</a></li>'
66 notfound = notfound.tmpl
67 error = error.tmpl
68 urlparameter = '{separator}{name}={value|urlescape}'
69 hiddenformentry = '<input type="hidden" name="{name}" value="{value|escape}" />'
@@ -0,0 +1,12 b''
1 {header}
2 <title>Mercurial repository not found</title>
3 </head>
4 <body>
5
6 <h2>Mercurial repository not found</h2>
7
8 The specified repository "{repo|escape}" is unknown, sorry.
9
10 Please go back to the main repository list page.
11
12 {footer}
@@ -0,0 +1,40 b''
1 {header}
2 <title>{repo|escape}: searching for {query|escape}</title>
3 </head>
4 <body>
5
6 <div class="content">
7 <div class="menu">
8 <div class="logo">
9 <a href="http://www.selenic.com/mercurial/">
10 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
11 </div>
12 <ul>
13 <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
14 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
15 </ul>
16 </div>
17
18 <div class="main">
19
20 <h2>{repo|escape}</h2>
21 <h3>searching for '{query|escape}'</h3>
22
23 <form class="search" action="{url}log">
24 {sessionvars%hiddenformentry}
25 <p><input name="rev" id="search1" type="text" size="30"></p>
26 </form>
27
28 <table class="bigtable">
29 <tr>
30 <th class="age">Age</td>
31 <th class="author">Author</td>
32 <th class="description">Description</td>
33 </tr>
34 {entries}
35 </table>
36
37 </div>
38 </div>
39
40 {footer}
@@ -0,0 +1,54 b''
1 {header}
2 <title>{repo|escape}: log</title>
3 <link rel="alternate" type="application/atom+xml"
4 href="{url}atom-log" title="Atom feed for {repo|escape}">
5 <link rel="alternate" type="application/rss+xml"
6 href="{url}rss-log" title="RSS feed for {repo|escape}">
7 </head>
8 <body>
9
10 <div class="container">
11 <div class="menu">
12 <div class="logo">
13 <a href="http://www.selenic.com/mercurial/">
14 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
15 </div>
16 <ul>
17 <li class="active">log</li>
18 <li><a href="{url}tags{sessionvars%urlparameter}">tags</a></li>
19 </ul>
20 <ul>
21 <li><a href="{url}rev/{node|short}{sessionvars%urlparameter}">changeset</a></li>
22 <li><a href="{url}file/{node|short}{path|urlescape}{sessionvars%urlparameter}">browse</a></li>
23 </ul>
24 <ul>
25 {archives%archiveentry}
26 </ul>
27 </div>
28
29 <div class="main">
30
31 <h2>{repo|escape}</h2>
32 <h3>log</h3>
33
34 <form class="search" action="{url}log">
35 {sessionvars%hiddenformentry}
36 <p><input name="rev" id="search1" type="text" size="30"></p>
37 </form>
38
39 <div class="navigate">rev {rev}: {changenav%navshortentry}</div>
40
41 <table class="bigtable">
42 <tr>
43 <th class="age">Age</td>
44 <th class="author">Author</td>
45 <th class="description">Description</td>
46 </tr>
47 {entries%shortlogentry}
48 </table>
49
50 <div class="navigate">rev {rev}: {changenav%navshortentry}</div>
51 </div>
52 </div>
53
54 {footer}
@@ -0,0 +1,5 b''
1 <tr class="parity{parity}">
2 <td class="age">{date|age}</td>
3 <td class="author">{author|person}</td>
4 <td class="description"><a href="{url}rev/{node|short}{sessionvars%urlparameter}">{desc|strip|firstline|escape}</a>{tags%changelogtag}</td>
5 </tr>
@@ -0,0 +1,41 b''
1 {header}
2 <title>{repo|escape}: tags</title>
3 <link rel="alternate" type="application/atom+xml"
4 href="{url}atom-tags" title="Atom feed for {repo|escape}: tags">
5 <link rel="alternate" type="application/rss+xml"
6 href="{url}rss-tags" title="RSS feed for {repo|escape}: tags">
7 </head>
8 <body>
9
10 <div class="container">
11 <div class="menu">
12 <div class="logo">
13 <a href="http://www.selenic.com/mercurial/">
14 <img src="{staticurl}hglogo.png" width=75 height=90 border=0 alt="mercurial"></a>
15 </div>
16 <ul>
17 <li><a href="{url}shortlog{sessionvars%urlparameter}">log</a></li>
18 <li class="active">tags</li>
19 </ul>
20 </div>
21
22 <div class="main">
23 <h2>{repo|escape}</h2>
24 <h3>tags</h3>
25
26 <form class="search" action="{url}log">
27 {sessionvars%hiddenformentry}
28 <p><input name="rev" id="search1" type="text" size="30"></p>
29 </form>
30
31 <table class="bigtable">
32 <tr>
33 <th>tag</th>
34 <th>node</th>
35 </tr>
36 {entries%tagentry}
37 </table>
38 </div>
39 </div>
40
41 {footer}
1 NO CONTENT: new file 100644, binary diff hidden
@@ -0,0 +1,160 b''
1 body {
2 margin: 0;
3 padding: 0;
4 background: black url(background.png) repeat-x;
5 font-family: sans-serif;
6 }
7
8 .container {
9 padding-right: 150px;
10 }
11
12 .main {
13 position: relative;
14 background: white;
15 padding: 2em;
16 border-right: 15px solid black;
17 border-bottom: 15px solid black;
18 }
19
20 .overflow {
21 width: 100%;
22 overflow: auto;
23 }
24
25 .menu {
26 background: #999;
27 padding: 10px;
28 width: 75px;
29 margin: 0;
30 font-size: 80% /*smaller*/;
31 text-align: left;
32 position: fixed;
33 top: 27px;
34 left: auto;
35 right: 27px;
36 }
37
38 .menu ul {
39 list-style: none;
40 padding: 0;
41 margin: 10px 0 0 0;
42 }
43
44 .menu li {
45 margin-bottom: 3px;
46 padding: 2px 4px;
47 background: white;
48 color: black;
49 font-weight: normal;
50 }
51
52 .menu li.active {
53 border-left: 3px solid black;
54 }
55
56 .search {
57 position: absolute;
58 top: .7em;
59 right: 2em;
60 }
61
62 .menu a { color: black; display: block; }
63
64 a { text-decoration:none; }
65 .age { white-space:nowrap; }
66 .date { white-space:nowrap; }
67 .indexlinks { white-space:nowrap; }
68 .parity0 { background-color: #f5f5f5; }
69 .parity1 { background-color: white; }
70 .plusline { color: green; }
71 .minusline { color: red; }
72 .atline { color: purple; }
73
74 .navigate {
75 text-align: right;
76 font-size: 60%;
77 margin: 1em 0 1em 0;
78 }
79
80 .tag {
81 color: #999;
82 font-size: 70%;
83 font-weight: normal;
84 margin-left: .5em;
85 vertical-align: text-baseline;
86 }
87
88 .navigate a {
89 #padding: 2pt;
90 #background-color: #f5f5f5;
91 }
92
93 /* Common */
94 pre { margin: 0; }
95
96 h2 { font-size: 120%; border-bottom: 1px solid #999; }
97 h3 {
98 margin-top: -.7em;
99 font-size: 100%;
100 }
101
102 /* log and tags tables */
103 .bigtable {
104 border-bottom: 1px solid #999;
105 border-collapse: collapse;
106 font-size: 90%;
107 width: 100%;
108 font-weight: normal;
109 text-align: left;
110 }
111
112 .bigtable td {
113 padding: 1px 4px 1px 4px;
114 vertical-align: top;
115 }
116
117 .bigtable th {
118 padding: 1px 4px 1px 4px;
119 border-bottom: 1px solid #999;
120 font-size: smaller;
121 }
122 .bigtable tr { border: none; }
123 .bigtable .age { width: 6em; }
124 .bigtable .author { width: 10em; }
125 .bigtable .description { }
126 .bigtable .node { width: 5em; font-family: monospace;}
127 .bigtable .lineno { width: 2em; text-align: right;}
128 .bigtable .lineno a { color: #999; font-size: smaller; font-family: monospace;}
129 .bigtable td.source { font-family: monospace; white-space: pre; }
130 .bigtable .permissions { width: 8em; text-align: left;}
131 .bigtable td.permissions { font-family: monospace; }
132 .bigtable .date { width: 10em; text-align: left;}
133 .bigtable .size { width: 5em; text-align: right; }
134 .bigtable td.size { font-family: monospace; }
135 .bigtable .annotate { text-align: right; padding-right: }
136 .bigtable td.annotate { font-size: smaller; }
137
138 /* Changeset entry */
139 #changesetEntry {
140 border-collapse: collapse;
141 font-size: 90%;
142 width: 100%;
143 margin-bottom: 1em;
144 }
145
146 #changesetEntry th {
147 padding: 1px 4px 1px 4px;
148 width: 4em;
149 text-align: right;
150 font-weight: normal;
151 color: #999;
152 margin-right: .5em;
153 vertical-align: top;
154 }
155
156 div.description {
157 border-left: 3px solid #999;
158 margin: 1em 0 1em 0;
159 padding: .3em;
160 }
@@ -35,8 +35,10 b''
35 35 ;; This code has been developed under XEmacs 21.5, and may not work as
36 36 ;; well under GNU Emacs (albeit tested under 21.4). Patches to
37 37 ;; enhance the portability of this code, fix bugs, and add features
38 ;; are most welcome. You can clone a Mercurial repository for this
39 ;; package from http://www.serpentine.com/hg/hg-emacs
38 ;; are most welcome.
39
40 ;; As of version 22.3, GNU Emacs's VC mode has direct support for
41 ;; Mercurial, so this package may not prove as useful there.
40 42
41 43 ;; Please send problem reports and suggestions to bos@serpentine.com.
42 44
@@ -30,7 +30,7 b' revision::'
30 30
31 31 repository path::
32 32 either the pathname of a local repository or the URI of a remote
33 repository. There are two available URI protocols, http:// which is
33 repository. There are two available URI protocols, http:// which is
34 34 fast and the static-http:// protocol which is much slower but does not
35 35 require a special server on the web host.
36 36
@@ -43,7 +43,7 b' SPECIFYING SINGLE REVISIONS'
43 43 Mercurial accepts several notations for identifying individual
44 44 revisions.
45 45
46 A plain integer is treated as a revision number. Negative
46 A plain integer is treated as a revision number. Negative
47 47 integers are treated as offsets from the tip, with -1 denoting the
48 48 tip.
49 49
@@ -52,11 +52,11 b' SPECIFYING SINGLE REVISIONS'
52 52
53 53 A hexadecimal string less than 40 characters long is treated as a
54 54 unique revision identifier, and referred to as a short-form
55 identifier. A short-form identifier is only valid if it is the
55 identifier. A short-form identifier is only valid if it is the
56 56 prefix of one full-length identifier.
57 57
58 58 Any other string is treated as a tag name, which is a symbolic
59 name associated with a revision identifier. Tag names may not
59 name associated with a revision identifier. Tag names may not
60 60 contain the ":" character.
61 61
62 62 The reserved name "tip" is a special tag that always identifies
@@ -78,16 +78,16 b' SPECIFYING MULTIPLE REVISIONS'
78 78 separated by the ":" character.
79 79
80 80 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
81 are revision identifiers. Both BEGIN and END are optional. If
82 BEGIN is not specified, it defaults to revision number 0. If END
83 is not specified, it defaults to the tip. The range ":" thus
81 are revision identifiers. Both BEGIN and END are optional. If
82 BEGIN is not specified, it defaults to revision number 0. If END
83 is not specified, it defaults to the tip. The range ":" thus
84 84 means "all revisions".
85 85
86 86 If BEGIN is greater than END, revisions are treated in reverse
87 87 order.
88 88
89 A range acts as a closed interval. This means that a range of 3:5
90 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
89 A range acts as a closed interval. This means that a range of 3:5
90 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
91 91
92 92 FILES
93 93 -----
@@ -103,7 +103,7 b' FILES'
103 103 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
104 104 This file contains defaults and configuration. Values in .hg/hgrc
105 105 override those in $HOME/.hgrc, and these override settings made in the
106 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
106 global /etc/mercurial/hgrc configuration. See hgrc(5) for details of
107 107 the contents and format of these files.
108 108
109 109 Some commands (e.g. revert) produce backup files ending in .orig, if
@@ -17,25 +17,25 b' DESCRIPTION'
17 17 -----------
18 18
19 19 Mercurial ignores every unmanaged file that matches any pattern in an
20 ignore file. The patterns in an ignore file do not apply to files
21 managed by Mercurial. To control Mercurial's handling of files that
22 it manages, see the hg(1) man page. Look for the "-I" and "-X"
20 ignore file. The patterns in an ignore file do not apply to files
21 managed by Mercurial. To control Mercurial's handling of files that
22 it manages, see the hg(1) man page. Look for the "-I" and "-X"
23 23 options.
24 24
25 25 In addition, a Mercurial configuration file can point to a set of
26 per-user or global ignore files. See the hgrc(5) man page for details
27 of how to configure these files. Look for the "ignore" entry in the
26 per-user or global ignore files. See the hgrc(5) man page for details
27 of how to configure these files. Look for the "ignore" entry in the
28 28 "ui" section.
29 29
30 30 SYNTAX
31 31 ------
32 32
33 33 An ignore file is a plain text file consisting of a list of patterns,
34 with one pattern per line. Empty lines are skipped. The "#"
34 with one pattern per line. Empty lines are skipped. The "#"
35 35 character is treated as a comment character, and the "\" character is
36 36 treated as an escape character.
37 37
38 Mercurial supports several pattern syntaxes. The default syntax used
38 Mercurial supports several pattern syntaxes. The default syntax used
39 39 is Python/Perl-style regular expressions.
40 40
41 41 To change the syntax used, use a line of the following form:
@@ -52,9 +52,9 b' glob::'
52 52 The chosen syntax stays in effect when parsing all patterns that
53 53 follow, until another syntax is selected.
54 54
55 Neither glob nor regexp patterns are rooted. A glob-syntax pattern of
55 Neither glob nor regexp patterns are rooted. A glob-syntax pattern of
56 56 the form "*.c" will match a file ending in ".c" in any directory, and
57 a regexp pattern of the form "\.c$" will do the same. To root a
57 a regexp pattern of the form "\.c$" will do the same. To root a
58 58 regexp pattern, start it with "^".
59 59
60 60 EXAMPLE
@@ -17,26 +17,26 b' FILES'
17 17
18 18 Mercurial reads configuration data from several files, if they exist.
19 19 The names of these files depend on the system on which Mercurial is
20 installed. *.rc files from a single directory are read in
21 alphabetical order, later ones overriding earlier ones. Where
20 installed. *.rc files from a single directory are read in
21 alphabetical order, later ones overriding earlier ones. Where
22 22 multiple paths are given below, settings from later paths override
23 23 earlier ones.
24 24
25 25 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
26 26 (Unix) <install-root>/etc/mercurial/hgrc::
27 27 Per-installation configuration files, searched for in the
28 directory where Mercurial is installed. <install-root> is the
28 directory where Mercurial is installed. <install-root> is the
29 29 parent directory of the hg executable (or symlink) being run.
30 30 For example, if installed in /shared/tools/bin/hg, Mercurial will
31 look in /shared/tools/etc/mercurial/hgrc. Options in these files
31 look in /shared/tools/etc/mercurial/hgrc. Options in these files
32 32 apply to all Mercurial commands executed by any user in any
33 33 directory.
34 34
35 35 (Unix) /etc/mercurial/hgrc.d/*.rc::
36 36 (Unix) /etc/mercurial/hgrc::
37 37 Per-system configuration files, for the system on which Mercurial
38 is running. Options in these files apply to all Mercurial
39 commands executed by any user in any directory. Options in these
38 is running. Options in these files apply to all Mercurial
39 commands executed by any user in any directory. Options in these
40 40 files override per-installation options.
41 41
42 42 (Windows) <install-dir>\Mercurial.ini::
@@ -45,7 +45,7 b' earlier ones.'
45 45 or else::
46 46 (Windows) C:\Mercurial\Mercurial.ini::
47 47 Per-installation/system configuration files, for the system on
48 which Mercurial is running. Options in these files apply to all
48 which Mercurial is running. Options in these files apply to all
49 49 Mercurial commands executed by any user in any directory.
50 50 Registry keys contain PATH-like strings, every part of which must
51 51 reference a Mercurial.ini file or be a directory where *.rc files
@@ -59,16 +59,16 b' earlier ones.'
59 59 Per-user configuration file(s), for the user running Mercurial.
60 60 On Windows 9x, %HOME% is replaced by %APPDATA%.
61 61 Options in these files apply to all Mercurial commands executed
62 by this user in any directory. Options in thes files override
62 by this user in any directory. Options in thes files override
63 63 per-installation and per-system options.
64 64
65 65 (Unix, Windows) <repo>/.hg/hgrc::
66 66 Per-repository configuration options that only apply in a
67 particular repository. This file is not version-controlled, and
68 will not get transferred during a "clone" operation. Options in
67 particular repository. This file is not version-controlled, and
68 will not get transferred during a "clone" operation. Options in
69 69 this file override options in all other configuration files.
70 70 On Unix, most of this file will be ignored if it doesn't belong
71 to a trusted user or to a trusted group. See the documentation
71 to a trusted user or to a trusted group. See the documentation
72 72 for the trusted section below for more details.
73 73
74 74 SYNTAX
@@ -82,10 +82,10 b' and followed by "name: value" entries; "'
82 82 green=
83 83 eggs
84 84
85 Each line contains one entry. If the lines that follow are indented,
85 Each line contains one entry. If the lines that follow are indented,
86 86 they are treated as continuations of that entry.
87 87
88 Leading whitespace is removed from values. Empty lines are skipped.
88 Leading whitespace is removed from values. Empty lines are skipped.
89 89
90 90 The optional values can contain format strings which refer to other
91 91 values in the same section, or values in a special DEFAULT section.
@@ -107,12 +107,12 b' decode/encode::'
107 107
108 108 Filters consist of a filter pattern followed by a filter command.
109 109 Filter patterns are globs by default, rooted at the repository
110 root. For example, to match any file ending in ".txt" in the root
111 directory only, use the pattern "*.txt". To match any file ending
110 root. For example, to match any file ending in ".txt" in the root
111 directory only, use the pattern "*.txt". To match any file ending
112 112 in ".c" anywhere in the repository, use the pattern "**.c".
113 113
114 114 The filter command can start with a specifier, either "pipe:" or
115 "tempfile:". If no specifier is given, "pipe:" is used by default.
115 "tempfile:". If no specifier is given, "pipe:" is used by default.
116 116
117 117 A "pipe:" command must accept data on stdin and return the
118 118 transformed data on stdout.
@@ -129,9 +129,9 b' decode/encode::'
129 129 # can safely omit "pipe:", because it's the default)
130 130 *.gz = gzip
131 131
132 A "tempfile:" command is a template. The string INFILE is replaced
132 A "tempfile:" command is a template. The string INFILE is replaced
133 133 with the name of a temporary file that contains the data to be
134 filtered by the command. The string OUTFILE is replaced with the
134 filtered by the command. The string OUTFILE is replaced with the
135 135 name of an empty temporary file, where the filtered data must be
136 136 written by the command.
137 137
@@ -192,22 +192,22 b' diff::'
192 192 email::
193 193 Settings for extensions that send email messages.
194 194 from;;
195 Optional. Email address to use in "From" header and SMTP envelope
195 Optional. Email address to use in "From" header and SMTP envelope
196 196 of outgoing messages.
197 197 to;;
198 Optional. Comma-separated list of recipients' email addresses.
198 Optional. Comma-separated list of recipients' email addresses.
199 199 cc;;
200 Optional. Comma-separated list of carbon copy recipients'
200 Optional. Comma-separated list of carbon copy recipients'
201 201 email addresses.
202 202 bcc;;
203 Optional. Comma-separated list of blind carbon copy
204 recipients' email addresses. Cannot be set interactively.
203 Optional. Comma-separated list of blind carbon copy
204 recipients' email addresses. Cannot be set interactively.
205 205 method;;
206 Optional. Method to use to send email messages. If value is
206 Optional. Method to use to send email messages. If value is
207 207 "smtp" (default), use SMTP (see section "[smtp]" for
208 configuration). Otherwise, use as name of program to run that
208 configuration). Otherwise, use as name of program to run that
209 209 acts like sendmail (takes "-f" option for sender, list of
210 recipients on command line, message on stdin). Normally, setting
210 recipients on command line, message on stdin). Normally, setting
211 211 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
212 212 sendmail to send messages.
213 213
@@ -281,6 +281,7 b' merge-tools::'
281 281 myHtmlTool.priority = 1
282 282
283 283 Supported arguments:
284
284 285 priority;;
285 286 The priority in which to evaluate this tool.
286 287 Default: 0.
@@ -297,10 +298,10 b' merge-tools::'
297 298 launching external tool.
298 299 Default: True
299 300 binary;;
300 This tool can merge binary files. Defaults to False, unless tool
301 This tool can merge binary files. Defaults to False, unless tool
301 302 was selected by file pattern match.
302 303 symlink;;
303 This tool can merge symlinks. Defaults to False, even if tool was
304 This tool can merge symlinks. Defaults to False, even if tool was
304 305 selected by file pattern match.
305 306 checkconflicts;;
306 307 Check whether there are conflicts even though the tool reported
@@ -313,18 +314,18 b' merge-tools::'
313 314 fixeol;;
314 315 Attempt to fix up EOL changes caused by the merge tool.
315 316 Default: False
316 gui:;
317 gui;;
317 318 This tool requires a graphical interface to run. Default: False
318 319 regkey;;
319 320 Windows registry key which describes install location of this tool.
320 321 Mercurial will search for this key first under HKEY_CURRENT_USER and
321 then under HKEY_LOCAL_MACHINE. Default: None
322 then under HKEY_LOCAL_MACHINE. Default: None
322 323 regname;;
323 Name of value to read from specified registry key. Defaults to the
324 Name of value to read from specified registry key. Defaults to the
324 325 unnamed (default) value.
325 326 regappend;;
326 327 String to append to the value read from the registry, typically the
327 executable name of the tool. Default: None
328 executable name of the tool. Default: None
328 329
329 330 hooks::
330 331 Commands or Python functions that get automatically executed by
@@ -342,24 +343,24 b' hooks::'
342 343 incoming.autobuild = /my/build/hook
343 344
344 345 Most hooks are run with environment variables set that give added
345 useful information. For each hook below, the environment variables
346 useful information. For each hook below, the environment variables
346 347 it is passed are listed with names of the form "$HG_foo".
347 348
348 349 changegroup;;
349 350 Run after a changegroup has been added via push, pull or
350 unbundle. ID of the first new changeset is in $HG_NODE. URL from
351 unbundle. ID of the first new changeset is in $HG_NODE. URL from
351 352 which changes came is in $HG_URL.
352 353 commit;;
353 354 Run after a changeset has been created in the local repository.
354 ID of the newly created changeset is in $HG_NODE. Parent
355 ID of the newly created changeset is in $HG_NODE. Parent
355 356 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
356 357 incoming;;
357 358 Run after a changeset has been pulled, pushed, or unbundled into
358 the local repository. The ID of the newly arrived changeset is in
359 $HG_NODE. URL that was source of changes came is in $HG_URL.
359 the local repository. The ID of the newly arrived changeset is in
360 $HG_NODE. URL that was source of changes came is in $HG_URL.
360 361 outgoing;;
361 Run after sending changes from local repository to another. ID of
362 first changeset sent is in $HG_NODE. Source of operation is in
362 Run after sending changes from local repository to another. ID of
363 first changeset sent is in $HG_NODE. Source of operation is in
363 364 $HG_SOURCE; see "preoutgoing" hook for description.
364 365 post-<command>;;
365 366 Run after successful invocations of the associated command. The
@@ -371,56 +372,56 b' hooks::'
371 372 the command doesn't execute and Mercurial returns the failure code.
372 373 prechangegroup;;
373 374 Run before a changegroup is added via push, pull or unbundle.
374 Exit status 0 allows the changegroup to proceed. Non-zero status
375 will cause the push, pull or unbundle to fail. URL from which
375 Exit status 0 allows the changegroup to proceed. Non-zero status
376 will cause the push, pull or unbundle to fail. URL from which
376 377 changes will come is in $HG_URL.
377 378 precommit;;
378 Run before starting a local commit. Exit status 0 allows the
379 commit to proceed. Non-zero status will cause the commit to fail.
379 Run before starting a local commit. Exit status 0 allows the
380 commit to proceed. Non-zero status will cause the commit to fail.
380 381 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
381 382 preoutgoing;;
382 383 Run before collecting changes to send from the local repository to
383 another. Non-zero status will cause failure. This lets you
384 prevent pull over http or ssh. Also prevents against local pull,
384 another. Non-zero status will cause failure. This lets you
385 prevent pull over http or ssh. Also prevents against local pull,
385 386 push (outbound) or bundle commands, but not effective, since you
386 can just copy files instead then. Source of operation is in
387 $HG_SOURCE. If "serve", operation is happening on behalf of
388 remote ssh or http repository. If "push", "pull" or "bundle",
387 can just copy files instead then. Source of operation is in
388 $HG_SOURCE. If "serve", operation is happening on behalf of
389 remote ssh or http repository. If "push", "pull" or "bundle",
389 390 operation is happening on behalf of repository on same system.
390 391 pretag;;
391 Run before creating a tag. Exit status 0 allows the tag to be
392 created. Non-zero status will cause the tag to fail. ID of
393 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
392 Run before creating a tag. Exit status 0 allows the tag to be
393 created. Non-zero status will cause the tag to fail. ID of
394 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
394 395 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
395 396 pretxnchangegroup;;
396 397 Run after a changegroup has been added via push, pull or unbundle,
397 but before the transaction has been committed. Changegroup is
398 visible to hook program. This lets you validate incoming changes
399 before accepting them. Passed the ID of the first new changeset
400 in $HG_NODE. Exit status 0 allows the transaction to commit.
398 but before the transaction has been committed. Changegroup is
399 visible to hook program. This lets you validate incoming changes
400 before accepting them. Passed the ID of the first new changeset
401 in $HG_NODE. Exit status 0 allows the transaction to commit.
401 402 Non-zero status will cause the transaction to be rolled back and
402 the push, pull or unbundle will fail. URL that was source of
403 the push, pull or unbundle will fail. URL that was source of
403 404 changes is in $HG_URL.
404 405 pretxncommit;;
405 406 Run after a changeset has been created but the transaction not yet
406 committed. Changeset is visible to hook program. This lets you
407 validate commit message and changes. Exit status 0 allows the
408 commit to proceed. Non-zero status will cause the transaction to
409 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
407 committed. Changeset is visible to hook program. This lets you
408 validate commit message and changes. Exit status 0 allows the
409 commit to proceed. Non-zero status will cause the transaction to
410 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
410 411 IDs are in $HG_PARENT1 and $HG_PARENT2.
411 412 preupdate;;
412 Run before updating the working directory. Exit status 0 allows
413 the update to proceed. Non-zero status will prevent the update.
414 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
413 Run before updating the working directory. Exit status 0 allows
414 the update to proceed. Non-zero status will prevent the update.
415 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
415 416 of second new parent is in $HG_PARENT2.
416 417 tag;;
417 Run after a tag is created. ID of tagged changeset is in
418 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
418 Run after a tag is created. ID of tagged changeset is in
419 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
419 420 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
420 421 update;;
421 Run after updating the working directory. Changeset ID of first
422 new parent is in $HG_PARENT1. If merge, ID of second new parent
423 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
422 Run after updating the working directory. Changeset ID of first
423 new parent is in $HG_PARENT1. If merge, ID of second new parent
424 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
424 425 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
425 426
426 427 Note: it is generally better to use standard hooks rather than the
@@ -438,10 +439,10 b' hooks::'
438 439
439 440 hookname = python:modulename.submodule.callable
440 441
441 Python hooks are run within the Mercurial process. Each hook is
442 Python hooks are run within the Mercurial process. Each hook is
442 443 called with at least three keyword arguments: a ui object (keyword
443 444 "ui"), a repository object (keyword "repo"), and a "hooktype"
444 keyword that tells what kind of hook is used. Arguments listed as
445 keyword that tells what kind of hook is used. Arguments listed as
445 446 environment variables above are passed as keyword arguments, with no
446 447 "HG_" prefix, and names in lower case.
447 448
@@ -455,68 +456,68 b' http_proxy::'
455 456 Host name and (optional) port of the proxy server, for example
456 457 "myproxy:8000".
457 458 no;;
458 Optional. Comma-separated list of host names that should bypass
459 Optional. Comma-separated list of host names that should bypass
459 460 the proxy.
460 461 passwd;;
461 Optional. Password to authenticate with at the proxy server.
462 Optional. Password to authenticate with at the proxy server.
462 463 user;;
463 Optional. User name to authenticate with at the proxy server.
464 Optional. User name to authenticate with at the proxy server.
464 465
465 466 smtp::
466 467 Configuration for extensions that need to send email messages.
467 468 host;;
468 469 Host name of mail server, e.g. "mail.example.com".
469 470 port;;
470 Optional. Port to connect to on mail server. Default: 25.
471 Optional. Port to connect to on mail server. Default: 25.
471 472 tls;;
472 Optional. Whether to connect to mail server using TLS. True or
473 False. Default: False.
473 Optional. Whether to connect to mail server using TLS. True or
474 False. Default: False.
474 475 username;;
475 Optional. User name to authenticate to SMTP server with.
476 Optional. User name to authenticate to SMTP server with.
476 477 If username is specified, password must also be specified.
477 478 Default: none.
478 479 password;;
479 Optional. Password to authenticate to SMTP server with.
480 Optional. Password to authenticate to SMTP server with.
480 481 If username is specified, password must also be specified.
481 482 Default: none.
482 483 local_hostname;;
483 Optional. It's the hostname that the sender can use to identify itself
484 Optional. It's the hostname that the sender can use to identify itself
484 485 to the MTA.
485 486
486 487 paths::
487 Assigns symbolic names to repositories. The left side is the
488 Assigns symbolic names to repositories. The left side is the
488 489 symbolic name, and the right gives the directory or URL that is the
489 location of the repository. Default paths can be declared by
490 location of the repository. Default paths can be declared by
490 491 setting the following entries.
491 492 default;;
492 493 Directory or URL to use when pulling if no source is specified.
493 494 Default is set to repository from which the current repository
494 495 was cloned.
495 496 default-push;;
496 Optional. Directory or URL to use when pushing if no destination
497 Optional. Directory or URL to use when pushing if no destination
497 498 is specified.
498 499
499 500 server::
500 501 Controls generic server settings.
501 502 uncompressed;;
502 503 Whether to allow clients to clone a repo using the uncompressed
503 streaming protocol. This transfers about 40% more data than a
504 streaming protocol. This transfers about 40% more data than a
504 505 regular clone, but uses less memory and CPU on both server and
505 client. Over a LAN (100Mbps or better) or a very fast WAN, an
506 client. Over a LAN (100Mbps or better) or a very fast WAN, an
506 507 uncompressed streaming clone is a lot faster (~10x) than a regular
507 clone. Over most WAN connections (anything slower than about
508 clone. Over most WAN connections (anything slower than about
508 509 6Mbps), uncompressed streaming is slower, because of the extra
509 data transfer overhead. Default is False.
510 data transfer overhead. Default is False.
510 511
511 512 trusted::
512 513 For security reasons, Mercurial will not use the settings in
513 514 the .hg/hgrc file from a repository if it doesn't belong to a
514 trusted user or to a trusted group. The main exception is the
515 trusted user or to a trusted group. The main exception is the
515 516 web interface, which automatically uses some safe settings, since
516 517 it's common to serve repositories from different users.
517 518
518 This section specifies what users and groups are trusted. The
519 current user is always trusted. To trust everybody, list a user
519 This section specifies what users and groups are trusted. The
520 current user is always trusted. To trust everybody, list a user
520 521 or a group with name "*".
521 522
522 523 users;;
@@ -532,12 +533,12 b' ui::'
532 533 the hg archive command or downloaded via hgweb.
533 534 Default is true.
534 535 debug;;
535 Print debugging information. True or False. Default is False.
536 Print debugging information. True or False. Default is False.
536 537 editor;;
537 The editor to use during a commit. Default is $EDITOR or "vi".
538 The editor to use during a commit. Default is $EDITOR or "vi".
538 539 fallbackencoding;;
539 540 Encoding to try if it's not possible to decode the changelog using
540 UTF-8. Default is ISO-8859-1.
541 UTF-8. Default is ISO-8859-1.
541 542 ignore;;
542 543 A file to read per-user ignore patterns from. This file should be in
543 544 the same format as a repository-wide .hgignore file. This option
@@ -546,7 +547,7 b' ui::'
546 547 "ignore.other = ~/.hgignore2". For details of the ignore file
547 548 format, see the hgignore(5) man page.
548 549 interactive;;
549 Allow to prompt the user. True or False. Default is True.
550 Allow to prompt the user. True or False. Default is True.
550 551 logtemplate;;
551 552 Template string for commands that print changesets.
552 553 merge;;
@@ -563,18 +564,19 b' ui::'
563 564 fail to merge
564 565
565 566 See the merge-tools section for more information on configuring tools.
567
566 568 patch;;
567 569 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
568 570 unset.
569 571 quiet;;
570 Reduce the amount of output printed. True or False. Default is False.
572 Reduce the amount of output printed. True or False. Default is False.
571 573 remotecmd;;
572 574 remote command to use for clone/push/pull operations. Default is 'hg'.
573 575 report_untrusted;;
574 576 Warn if a .hg/hgrc file is ignored due to not being owned by a
575 trusted user or group. True or False. Default is True.
577 trusted user or group. True or False. Default is True.
576 578 slash;;
577 Display paths using a slash ("/") as the path separator. This only
579 Display paths using a slash ("/") as the path separator. This only
578 580 makes a difference on systems where the default path separator is not
579 581 the slash character (e.g. Windows uses the backslash character ("\")).
580 582 Default is False.
@@ -582,7 +584,7 b' ui::'
582 584 command to use for SSH connections. Default is 'ssh'.
583 585 strict;;
584 586 Require exact command names, instead of allowing unambiguous
585 abbreviations. True or False. Default is False.
587 abbreviations. True or False. Default is False.
586 588 style;;
587 589 Name of style to use for command output.
588 590 timeout;;
@@ -591,12 +593,12 b' ui::'
591 593 username;;
592 594 The committer of a changeset created when running "commit".
593 595 Typically a person's name and email address, e.g. "Fred Widget
594 <fred@example.com>". Default is $EMAIL or username@hostname.
596 <fred@example.com>". Default is $EMAIL or username@hostname.
595 597 If the username in hgrc is empty, it has to be specified manually or
596 598 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
597 599 in the system hgrc).
598 600 verbose;;
599 Increase the amount of output printed. True or False. Default is False.
601 Increase the amount of output printed. True or False. Default is False.
600 602
601 603
602 604 web::
@@ -617,9 +619,9 b' web::'
617 619 allowpull;;
618 620 Whether to allow pulling from the repository. Default is true.
619 621 allow_push;;
620 Whether to allow pushing to the repository. If empty or not set,
621 push is not allowed. If the special value "*", any remote user
622 can push, including unauthenticated users. Otherwise, the remote
622 Whether to allow pushing to the repository. If empty or not set,
623 push is not allowed. If the special value "*", any remote user
624 can push, including unauthenticated users. Otherwise, the remote
623 625 user must have been authenticated, and the authenticated user name
624 626 must be present in this list (separated by whitespace or ",").
625 627 The contents of the allow_push list are examined after the
@@ -635,11 +637,11 b' web::'
635 637 Name or email address of the person in charge of the repository.
636 638 Defaults to ui.username or $EMAIL or "unknown" if unset or empty.
637 639 deny_push;;
638 Whether to deny pushing to the repository. If empty or not set,
639 push is not denied. If the special value "*", all remote users
640 are denied push. Otherwise, unauthenticated users are all denied,
640 Whether to deny pushing to the repository. If empty or not set,
641 push is not denied. If the special value "*", all remote users
642 are denied push. Otherwise, unauthenticated users are all denied,
641 643 and any authenticated user name present in this list (separated by
642 whitespace or ",") is also denied. The contents of the deny_push
644 whitespace or ",") is also denied. The contents of the deny_push
643 645 list are examined before the allow_push list.
644 646 description;;
645 647 Textual description of the repository's purpose or contents.
@@ -666,7 +668,7 b' web::'
666 668 Prefix path to serve from. Default is '' (server root).
667 669 push_ssl;;
668 670 Whether to require that inbound pushes be transported over SSL to
669 prevent password sniffing. Default is true.
671 prevent password sniffing. Default is true.
670 672 staticurl;;
671 673 Base URL to use for static files. If unset, static files (e.g.
672 674 the hgicon.png favicon) will be served by the CGI script itself.
@@ -387,7 +387,7 b' class svn_source(converter_source):'
387 387 try:
388 388 for entry in get_log(self.url, [self.tags], start, self.startrev):
389 389 origpaths, revnum, author, date, message = entry
390 copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p,e
390 copies = [(e.copyfrom_path, e.copyfrom_rev, p) for p, e
391 391 in origpaths.iteritems() if e.copyfrom_path]
392 392 copies.sort()
393 393 # Apply moves/copies from more specific to general
@@ -20,18 +20,13 b' file should be re-generated by running'
20 20
21 21 # pygmentize -f html -S <newstyle>
22 22
23
24 23 -- Adam Hupp <adam@hupp.org>
25
26
27 24 """
28 25
29 26 from mercurial import demandimport
30 demandimport.ignore.extend(['pkgutil',
31 'pkg_resources',
32 '__main__',])
27 demandimport.ignore.extend(['pkgutil', 'pkg_resources', '__main__',])
33 28
34 from mercurial.hgweb.hgweb_mod import hgweb
29 from mercurial.hgweb import webcommands, webutil
35 30 from mercurial import util
36 31 from mercurial.templatefilters import filters
37 32
@@ -43,7 +38,8 b' from pygments.formatters import HtmlForm'
43 38 SYNTAX_CSS = ('\n<link rel="stylesheet" href="#staticurl#highlight.css" '
44 39 'type="text/css" />')
45 40
46 def pygmentize(self, tmpl, fctx, field):
41 def pygmentize(field, fctx, style, tmpl):
42
47 43 # append a <link ...> to the syntax highlighting css
48 44 old_header = ''.join(tmpl('header'))
49 45 if SYNTAX_CSS not in old_header:
@@ -54,7 +50,6 b' def pygmentize(self, tmpl, fctx, field):'
54 50 if util.binary(text):
55 51 return
56 52
57 style = self.config("web", "pygments_style", "colorful")
58 53 # To get multi-line strings right, we can't format line-by-line
59 54 try:
60 55 lexer = guess_lexer_for_filename(fctx.path(), text,
@@ -79,20 +74,21 b' def pygmentize(self, tmpl, fctx, field):'
79 74 newl = oldl.replace('line|escape', 'line|colorize')
80 75 tmpl.cache[field] = newl
81 76
82 def filerevision_highlight(self, tmpl, fctx):
83 pygmentize(self, tmpl, fctx, 'fileline')
84
85 return realrevision(self, tmpl, fctx)
77 web_filerevision = webcommands._filerevision
78 web_annotate = webcommands.annotate
86 79
87 def fileannotate_highlight(self, tmpl, fctx):
88 pygmentize(self, tmpl, fctx, 'annotateline')
80 def filerevision_highlight(web, tmpl, fctx):
81 style = web.config('web', 'pygments_style', 'colorful')
82 pygmentize('fileline', fctx, style, tmpl)
83 return web_filerevision(web, tmpl, fctx)
89 84
90 return realannotate(self, tmpl, fctx)
85 def annotate_highlight(web, req, tmpl):
86 fctx = webutil.filectx(web.repo, req)
87 style = web.config('web', 'pygments_style', 'colorful')
88 pygmentize('annotateline', fctx, style, tmpl)
89 return web_annotate(web, req, tmpl)
91 90
92 91 # monkeypatch in the new version
93 # should be safer than overriding the method in a derived class
94 # and then patching the class
95 realrevision = hgweb.filerevision
96 hgweb.filerevision = filerevision_highlight
97 realannotate = hgweb.fileannotate
98 hgweb.fileannotate = fileannotate_highlight
92
93 webcommands._filerevision = filerevision_highlight
94 webcommands.annotate = annotate_highlight
@@ -108,6 +108,8 b" kwtools = {'templater': None, 'hgcmd': N"
108 108 _patchfile_init = patch.patchfile.__init__
109 109 _patch_diff = patch.diff
110 110 _dispatch_parse = dispatch._parse
111 _webcommands_changeset = webcommands.changeset
112 _webcommands_filediff = webcommands.filediff
111 113
112 114 def _kwpatchfile_init(self, ui, fname, missing=False):
113 115 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
@@ -131,12 +133,12 b' def _kw_diff(repo, node1=None, node2=Non'
131 133 def _kwweb_changeset(web, req, tmpl):
132 134 '''Wraps webcommands.changeset turning off keyword expansion.'''
133 135 kwtools['templater'].matcher = util.never
134 return web.changeset(tmpl, web.changectx(req))
136 return _webcommands_changeset(web, req, tmpl)
135 137
136 138 def _kwweb_filediff(web, req, tmpl):
137 139 '''Wraps webcommands.filediff turning off keyword expansion.'''
138 140 kwtools['templater'].matcher = util.never
139 return web.filediff(tmpl, web.filectx(req))
141 return _webcommands_filediff(web, req, tmpl)
140 142
141 143 def _kwdispatch_parse(ui, args):
142 144 '''Monkeypatch dispatch._parse to obtain running hg command.'''
@@ -145,6 +147,7 b' def _kwdispatch_parse(ui, args):'
145 147 return cmd, func, args, options, cmdoptions
146 148
147 149 # dispatch._parse is run before reposetup, so wrap it here
150 # all other actual monkey patching is done at end of reposetup
148 151 dispatch._parse = _kwdispatch_parse
149 152
150 153
@@ -24,12 +24,37 b''
24 24 #
25 25 # [pager]
26 26 # quiet = True
27 #
28 # You can disable the pager for certain commands by adding them to the
29 # pager.ignore list:
30 #
31 # [pager]
32 # ignore = version, help, update
33 #
34 # You can also enable the pager only for certain commands using pager.attend:
35 #
36 # [pager]
37 # attend = log
38 #
39 # If pager.attend is present, pager.ignore will be ignored.
40 #
41 # To ignore global commands like 'hg version' or 'hg help', you have to specify them
42 # in the global .hgrc
27 43
28 44 import sys, os, signal
45 from mercurial import dispatch
29 46
30 47 def uisetup(ui):
31 p = ui.config("pager", "pager", os.environ.get("PAGER"))
32 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
33 if ui.configbool('pager', 'quiet'):
34 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
35 sys.stderr = sys.stdout = os.popen(p, "wb")
48 def pagecmd(ui, options, cmd, cmdfunc):
49 p = ui.config("pager", "pager", os.environ.get("PAGER"))
50 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
51 attend = ui.configlist('pager', 'attend')
52 if (cmd in attend or
53 (cmd not in ui.configlist('pager', 'ignore') and not attend)):
54 sys.stderr = sys.stdout = os.popen(p, "wb")
55 if ui.configbool('pager', 'quiet'):
56 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
57 return oldrun(ui, options, cmd, cmdfunc)
58
59 oldrun = dispatch._runcommand
60 dispatch._runcommand = pagecmd
@@ -66,7 +66,8 b''
66 66
67 67 import os, errno, socket, tempfile
68 68 import email.MIMEMultipart, email.MIMEText, email.MIMEBase
69 import email.Utils, email.Encoders
69 import email.Utils, email.Encoders, email.Generator
70 import cStringIO.StringIO
70 71 from mercurial import cmdutil, commands, hg, mail, patch, util
71 72 from mercurial.i18n import _
72 73 from mercurial.node import bin
@@ -407,8 +408,9 b' def patchbomb(ui, repo, *revs, **opts):'
407 408 fp = os.popen(os.environ['PAGER'], 'w')
408 409 else:
409 410 fp = ui
411 generator = email.Generator.Generator(fp, mangle_from_=False)
410 412 try:
411 fp.write(m.as_string(0))
413 generator.flatten(m, 0)
412 414 fp.write('\n')
413 415 except IOError, inst:
414 416 if inst.errno != errno.EPIPE:
@@ -418,9 +420,10 b' def patchbomb(ui, repo, *revs, **opts):'
418 420 elif opts.get('mbox'):
419 421 ui.status('Writing ', m['Subject'], ' ...\n')
420 422 fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+')
423 generator = email.Generator.Generator(fp, mangle_from_=True)
421 424 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y')
422 425 fp.write('From %s %s\n' % (sender_addr, date))
423 fp.write(m.as_string(0))
426 generator.flatten(m, 0)
424 427 fp.write('\n\n')
425 428 fp.close()
426 429 else:
@@ -429,7 +432,10 b' def patchbomb(ui, repo, *revs, **opts):'
429 432 ui.status('Sending ', m['Subject'], ' ...\n')
430 433 # Exim does not remove the Bcc field
431 434 del m['Bcc']
432 sendmail(sender, to + bcc + cc, m.as_string(0))
435 fp = cStringIO.StringIO()
436 generator = email.Generator.Generator(fp, mangle_from_=False)
437 generator.flatten(m, 0)
438 sendmail(sender, to + bcc + cc, fp.getvalue())
433 439
434 440 cmdtable = {
435 441 "email":
@@ -53,11 +53,11 b' def addremove(ui, repo, *pats, **opts):'
53 53 New files are ignored if they match any of the patterns in .hgignore. As
54 54 with add, these changes take effect at the next commit.
55 55
56 Use the -s option to detect renamed files. With a parameter > 0,
56 Use the -s option to detect renamed files. With a parameter > 0,
57 57 this compares every removed file with every added file and records
58 those similar enough as renames. This option takes a percentage
58 those similar enough as renames. This option takes a percentage
59 59 between 0 (disabled) and 100 (files must be identical) as its
60 parameter. Detecting renamed files this way can be expensive.
60 parameter. Detecting renamed files this way can be expensive.
61 61 """
62 62 try:
63 63 sim = float(opts.get('similarity') or 0)
@@ -134,7 +134,7 b' def archive(ui, repo, dest, **opts):'
134 134 By default, the revision used is the parent of the working
135 135 directory; use "-r" to specify a different revision.
136 136
137 To specify the type of archive to create, use "-t". Valid
137 To specify the type of archive to create, use "-t". Valid
138 138 types are:
139 139
140 140 "files" (default): a directory full of files
@@ -148,7 +148,7 b' def archive(ui, repo, dest, **opts):'
148 148 using a format string; see "hg help export" for details.
149 149
150 150 Each member added to an archive file has a directory prefix
151 prepended. Use "-p" to specify a format string for the prefix.
151 prepended. Use "-p" to specify a format string for the prefix.
152 152 The default is the basename of the archive, with suffixes removed.
153 153 '''
154 154
@@ -174,17 +174,17 b' def archive(ui, repo, dest, **opts):'
174 174 def backout(ui, repo, node=None, rev=None, **opts):
175 175 '''reverse effect of earlier changeset
176 176
177 Commit the backed out changes as a new changeset. The new
177 Commit the backed out changes as a new changeset. The new
178 178 changeset is a child of the backed out changeset.
179 179
180 180 If you back out a changeset other than the tip, a new head is
181 created. This head will be the new tip and you should merge this
181 created. This head will be the new tip and you should merge this
182 182 backout changeset with another head (current one by default).
183 183
184 184 The --merge option remembers the parent of the working directory
185 185 before starting the backout, then merges the new head with that
186 changeset afterwards. This saves you from doing the merge by
187 hand. The result of this merge is not committed, as for a normal
186 changeset afterwards. This saves you from doing the merge by
187 hand. The result of this merge is not committed, as for a normal
188 188 merge.
189 189
190 190 See 'hg help dates' for a list of formats valid for -d/--date.
@@ -369,7 +369,7 b' def branches(ui, repo, active=False):'
369 369 """list repository named branches
370 370
371 371 List the repository's named branches, indicating which ones are
372 inactive. If active is specified, only show active branches.
372 inactive. If active is specified, only show active branches.
373 373
374 374 A branch is considered active if it contains unmerged heads.
375 375
@@ -404,7 +404,7 b' def bundle(ui, repo, fname, dest=None, *'
404 404
405 405 If no destination repository is specified the destination is
406 406 assumed to have all the nodes specified by one or more --base
407 parameters. To create a bundle containing all changesets, use
407 parameters. To create a bundle containing all changesets, use
408 408 --all (or --base null).
409 409
410 410 The bundle file can then be transferred using conventional means and
@@ -469,7 +469,7 b' def cat(ui, repo, file1, *pats, **opts):'
469 469 or tip if no revision is checked out.
470 470
471 471 Output may be to a file, in which case the name of the file is
472 given using a format string. The formatting rules are the same as
472 given using a format string. The formatting rules are the same as
473 473 for the export command, with the following additions:
474 474
475 475 %s basename of file being printed
@@ -501,9 +501,9 b' def clone(ui, source, dest=None, **opts)'
501 501
502 502 For efficiency, hardlinks are used for cloning whenever the source
503 503 and destination are on the same filesystem (note this applies only
504 to the repository data, not to the checked out files). Some
504 to the repository data, not to the checked out files). Some
505 505 filesystems, such as AFS, implement hardlinking incorrectly, but
506 do not report errors. In these cases, use the --pull option to
506 do not report errors. In these cases, use the --pull option to
507 507 avoid hardlinking.
508 508
509 509 You can safely clone repositories and checked out files using full
@@ -571,12 +571,12 b' def commit(ui, repo, *pats, **opts):'
571 571 def copy(ui, repo, *pats, **opts):
572 572 """mark files as copied for the next commit
573 573
574 Mark dest as having copies of source files. If dest is a
575 directory, copies are put in that directory. If dest is a file,
574 Mark dest as having copies of source files. If dest is a
575 directory, copies are put in that directory. If dest is a file,
576 576 there can only be one source.
577 577
578 578 By default, this command copies the contents of files as they
579 stand in the working directory. If invoked with --after, the
579 stand in the working directory. If invoked with --after, the
580 580 operation is recorded, but no copying is performed.
581 581
582 582 This command takes effect in the next commit. To undo a copy
@@ -963,7 +963,7 b' def export(ui, repo, *changesets, **opts'
963 963 as it will compare the merge changeset against its first parent only.
964 964
965 965 Output may be to a file, in which case the name of the file is
966 given using a format string. The formatting rules are as follows:
966 given using a format string. The formatting rules are as follows:
967 967
968 968 %% literal "%" character
969 969 %H changeset hash (40 bytes of hexadecimal)
@@ -997,13 +997,13 b' def grep(ui, repo, pattern, *pats, **opt'
997 997
998 998 Search revisions of files for a regular expression.
999 999
1000 This command behaves differently than Unix grep. It only accepts
1001 Python/Perl regexps. It searches repository history, not the
1002 working directory. It always prints the revision number in which
1000 This command behaves differently than Unix grep. It only accepts
1001 Python/Perl regexps. It searches repository history, not the
1002 working directory. It always prints the revision number in which
1003 1003 a match appears.
1004 1004
1005 1005 By default, grep only prints output for the first revision of a
1006 file in which it finds a match. To get it to print every revision
1006 file in which it finds a match. To get it to print every revision
1007 1007 that contains a change in match status ("-" for a match that
1008 1008 becomes a non-match, or "+" for a non-match that becomes a match),
1009 1009 use the --all flag.
@@ -1173,7 +1173,7 b' def heads(ui, repo, *branchrevs, **opts)'
1173 1173 are the usual targets for update and merge operations.
1174 1174
1175 1175 Branch heads are changesets that have a given branch tag, but have
1176 no child changesets with that tag. They are usually where
1176 no child changesets with that tag. They are usually where
1177 1177 development on the given branch takes place.
1178 1178 """
1179 1179 if opts['rev']:
@@ -1466,15 +1466,15 b' def import_(ui, repo, patch1, *patches, '
1466 1466 If there are outstanding changes in the working directory, import
1467 1467 will abort unless given the -f flag.
1468 1468
1469 You can import a patch straight from a mail message. Even patches
1469 You can import a patch straight from a mail message. Even patches
1470 1470 as attachments work (body part must be type text/plain or
1471 text/x-patch to be used). From and Subject headers of email
1472 message are used as default committer and commit message. All
1471 text/x-patch to be used). From and Subject headers of email
1472 message are used as default committer and commit message. All
1473 1473 text/plain body parts before first diff are added to commit
1474 1474 message.
1475 1475
1476 1476 If the imported patch was generated by hg export, user and description
1477 from patch override values from message headers and body. Values
1477 from patch override values from message headers and body. Values
1478 1478 given on command line with -m and -u override these.
1479 1479
1480 1480 If --exact is specified, import will set the working directory
@@ -1643,7 +1643,7 b' def incoming(ui, repo, source="default",'
1643 1643 def init(ui, dest=".", **opts):
1644 1644 """create a new repository in the given directory
1645 1645
1646 Initialize a new repository in the given directory. If the given
1646 Initialize a new repository in the given directory. If the given
1647 1647 directory does not exist, it is created.
1648 1648
1649 1649 If no directory is given, the current directory is used.
@@ -1661,7 +1661,7 b' def locate(ui, repo, *pats, **opts):'
1661 1661 Print all files under Mercurial control whose names match the
1662 1662 given patterns.
1663 1663
1664 This command searches the entire repository by default. To search
1664 This command searches the entire repository by default. To search
1665 1665 just the current directory and its subdirectories, use
1666 1666 "--include .".
1667 1667
@@ -1703,7 +1703,7 b' def log(ui, repo, *pats, **opts):'
1703 1703 project.
1704 1704
1705 1705 File history is shown without following rename or copy history of
1706 files. Use -f/--follow with a file name to follow history across
1706 files. Use -f/--follow with a file name to follow history across
1707 1707 renames and copies. --follow without a file name will only show
1708 1708 ancestors or descendants of the starting revision. --follow-first
1709 1709 only follows the first parent of merge revisions.
@@ -1862,7 +1862,7 b' def merge(ui, repo, node=None, force=Non'
1862 1862
1863 1863 If no revision is specified, the working directory's parent is a
1864 1864 head revision, and the repository contains exactly one other head,
1865 the other head is merged with by default. Otherwise, an explicit
1865 the other head is merged with by default. Otherwise, an explicit
1866 1866 revision to merge with must be provided.
1867 1867 """
1868 1868
@@ -1973,7 +1973,7 b' def paths(ui, repo, search=None):'
1973 1973 definition of available names.
1974 1974
1975 1975 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1976 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1976 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1977 1977 """
1978 1978 if search:
1979 1979 for name, path in ui.configitems("paths"):
@@ -2214,12 +2214,12 b' def remove(ui, repo, *pats, **opts):'
2214 2214 def rename(ui, repo, *pats, **opts):
2215 2215 """rename files; equivalent of copy + remove
2216 2216
2217 Mark dest as copies of sources; mark sources for deletion. If
2218 dest is a directory, copies are put in that directory. If dest is
2217 Mark dest as copies of sources; mark sources for deletion. If
2218 dest is a directory, copies are put in that directory. If dest is
2219 2219 a file, there can only be one source.
2220 2220
2221 2221 By default, this command copies the contents of files as they
2222 stand in the working directory. If invoked with --after, the
2222 stand in the working directory. If invoked with --after, the
2223 2223 operation is recorded, but no copying is performed.
2224 2224
2225 2225 This command takes effect in the next commit. To undo a rename
@@ -2249,13 +2249,13 b' def revert(ui, repo, *pats, **opts):'
2249 2249 back" some or all of an earlier change.
2250 2250 See 'hg help dates' for a list of formats valid for -d/--date.
2251 2251
2252 Revert modifies the working directory. It does not commit any
2253 changes, or change the parent of the working directory. If you
2252 Revert modifies the working directory. It does not commit any
2253 changes, or change the parent of the working directory. If you
2254 2254 revert to a revision other than the parent of the working
2255 2255 directory, the reverted files will thus appear modified
2256 2256 afterwards.
2257 2257
2258 If a file has been deleted, it is restored. If the executable
2258 If a file has been deleted, it is restored. If the executable
2259 2259 mode of a file was changed, it is reset.
2260 2260
2261 2261 If names are given, all files matching the names are reverted.
@@ -2491,7 +2491,7 b' def serve(ui, repo, **opts):'
2491 2491 Start a local HTTP repository browser and pull server.
2492 2492
2493 2493 By default, the server logs accesses to stdout and errors to
2494 stderr. Use the "-A" and "-E" options to log to files.
2494 stderr. Use the "-A" and "-E" options to log to files.
2495 2495 """
2496 2496
2497 2497 if opts["stdio"]:
@@ -2530,8 +2530,17 b' def serve(ui, repo, **opts):'
2530 2530 if port == ':80':
2531 2531 port = ''
2532 2532
2533 ui.status(_('listening at http://%s%s/%s (%s:%d)\n') %
2534 (self.httpd.fqaddr, port, prefix, self.httpd.addr, self.httpd.port))
2533 bindaddr = self.httpd.addr
2534 if bindaddr == '0.0.0.0':
2535 bindaddr = '*'
2536 elif ':' in bindaddr: # IPv6
2537 bindaddr = '[%s]' % bindaddr
2538
2539 fqaddr = self.httpd.fqaddr
2540 if ':' in fqaddr:
2541 fqaddr = '[%s]' % fqaddr
2542 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2543 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2535 2544
2536 2545 def run(self):
2537 2546 self.httpd.serve_forever()
@@ -2543,10 +2552,10 b' def serve(ui, repo, **opts):'
2543 2552 def status(ui, repo, *pats, **opts):
2544 2553 """show changed files in the working directory
2545 2554
2546 Show status of files in the repository. If names are given, only
2547 files that match are shown. Files that are clean or ignored or
2555 Show status of files in the repository. If names are given, only
2556 files that match are shown. Files that are clean or ignored or
2548 2557 source of a copy/move operation, are not listed unless -c (clean),
2549 -i (ignored), -C (copies) or -A is given. Unless options described
2558 -i (ignored), -C (copies) or -A is given. Unless options described
2550 2559 with "show only ..." are given, the options -mardu are used.
2551 2560
2552 2561 Option -q/--quiet hides untracked (unknown and ignored) files
@@ -2646,7 +2655,7 b' def tag(ui, repo, name1, *names, **opts)'
2646 2655 To facilitate version control, distribution, and merging of tags,
2647 2656 they are stored as a file named ".hgtags" which is managed
2648 2657 similarly to other project files and can be hand-edited if
2649 necessary. The file '.hg/localtags' is used for local tags (not
2658 necessary. The file '.hg/localtags' is used for local tags (not
2650 2659 shared among repositories).
2651 2660
2652 2661 See 'hg help dates' for a list of formats valid for -d/--date.
This diff has been collapsed as it changes many lines, (630 lines changed) Show them Hide them
@@ -6,16 +6,15 b''
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 import os, mimetypes, re, mimetools, cStringIO
10 from mercurial.node import hex, nullid, short
9 import os, mimetypes
10 from mercurial.node import hex, nullid
11 11 from mercurial.repo import RepoError
12 from mercurial import mdiff, ui, hg, util, archival, patch, hook
12 from mercurial import mdiff, ui, hg, util, patch, hook
13 13 from mercurial import revlog, templater, templatefilters, changegroup
14 from common import get_mtime, style_map, paritygen, countgen, get_contact
15 from common import ErrorResponse
14 from common import get_mtime, style_map, paritygen, countgen, ErrorResponse
16 15 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
17 16 from request import wsgirequest
18 import webcommands, protocol
17 import webcommands, protocol, webutil
19 18
20 19 shortcuts = {
21 20 'cl': [('cmd', ['changelog']), ('rev', None)],
@@ -32,54 +31,6 b' shortcuts = {'
32 31 'static': [('cmd', ['static']), ('file', None)]
33 32 }
34 33
35 def _up(p):
36 if p[0] != "/":
37 p = "/" + p
38 if p[-1] == "/":
39 p = p[:-1]
40 up = os.path.dirname(p)
41 if up == "/":
42 return "/"
43 return up + "/"
44
45 def revnavgen(pos, pagelen, limit, nodefunc):
46 def seq(factor, limit=None):
47 if limit:
48 yield limit
49 if limit >= 20 and limit <= 40:
50 yield 50
51 else:
52 yield 1 * factor
53 yield 3 * factor
54 for f in seq(factor * 10):
55 yield f
56
57 def nav(**map):
58 l = []
59 last = 0
60 for f in seq(1, pagelen):
61 if f < pagelen or f <= last:
62 continue
63 if f > limit:
64 break
65 last = f
66 if pos + f < limit:
67 l.append(("+%d" % f, hex(nodefunc(pos + f).node())))
68 if pos - f >= 0:
69 l.insert(0, ("-%d" % f, hex(nodefunc(pos - f).node())))
70
71 try:
72 yield {"label": "(0)", "node": hex(nodefunc('0').node())}
73
74 for label, node in l:
75 yield {"label": label, "node": node}
76
77 yield {"label": "tip", "node": "tip"}
78 except RepoError:
79 pass
80
81 return nav
82
83 34 class hgweb(object):
84 35 def __init__(self, repo, name=None):
85 36 if isinstance(repo, str):
@@ -226,17 +177,8 b' class hgweb(object):'
226 177 try:
227 178
228 179 tmpl = self.templater(req)
229 try:
230 ctype = tmpl('mimetype', encoding=self.encoding)
231 ctype = templater.stringify(ctype)
232 except KeyError:
233 # old templates with inline HTTP headers?
234 if 'mimetype' in tmpl:
235 raise
236 header = tmpl('header', encoding=self.encoding)
237 header_file = cStringIO.StringIO(templater.stringify(header))
238 msg = mimetools.Message(header_file, 0)
239 ctype = msg['content-type']
180 ctype = tmpl('mimetype', encoding=self.encoding)
181 ctype = templater.stringify(ctype)
240 182
241 183 if cmd == '':
242 184 req.form['cmd'] = [tmpl.cache['default']]
@@ -291,13 +233,7 b' class hgweb(object):'
291 233 # some functions for the templater
292 234
293 235 def header(**map):
294 header = tmpl('header', encoding=self.encoding, **map)
295 if 'mimetype' not in tmpl:
296 # old template with inline HTTP headers
297 header_file = cStringIO.StringIO(templater.stringify(header))
298 msg = mimetools.Message(header_file, 0)
299 header = header_file.read()
300 yield header
236 yield tmpl('header', encoding=self.encoding, **map)
301 237
302 238 def footer(**map):
303 239 yield tmpl("footer", **map)
@@ -355,54 +291,6 b' class hgweb(object):'
355 291 if len(files) > self.maxfiles:
356 292 yield tmpl("fileellipses")
357 293
358 def siblings(self, siblings=[], hiderev=None, **args):
359 siblings = [s for s in siblings if s.node() != nullid]
360 if len(siblings) == 1 and siblings[0].rev() == hiderev:
361 return
362 for s in siblings:
363 d = {'node': hex(s.node()), 'rev': s.rev()}
364 if hasattr(s, 'path'):
365 d['file'] = s.path()
366 d.update(args)
367 yield d
368
369 def renamelink(self, fl, node):
370 r = fl.renamed(node)
371 if r:
372 return [dict(file=r[0], node=hex(r[1]))]
373 return []
374
375 def nodetagsdict(self, node):
376 return [{"name": i} for i in self.repo.nodetags(node)]
377
378 def nodebranchdict(self, ctx):
379 branches = []
380 branch = ctx.branch()
381 # If this is an empty repo, ctx.node() == nullid,
382 # ctx.branch() == 'default', but branchtags() is
383 # an empty dict. Using dict.get avoids a traceback.
384 if self.repo.branchtags().get(branch) == ctx.node():
385 branches.append({"name": branch})
386 return branches
387
388 def nodeinbranch(self, ctx):
389 branches = []
390 branch = ctx.branch()
391 if branch != 'default' and self.repo.branchtags().get(branch) != ctx.node():
392 branches.append({"name": branch})
393 return branches
394
395 def nodebranchnodefault(self, ctx):
396 branches = []
397 branch = ctx.branch()
398 if branch != 'default':
399 branches.append({"name": branch})
400 return branches
401
402 def showtag(self, tmpl, t1, node=nullid, **args):
403 for t in self.repo.nodetags(node):
404 yield tmpl(t1, tag=t, **args)
405
406 294 def diff(self, tmpl, node1, node2, files):
407 295 def filterfiles(filters, files):
408 296 l = [x for x in files if x in filters]
@@ -470,514 +358,12 b' class hgweb(object):'
470 358 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
471 359 opts=diffopts), f, tn)
472 360
473 def changelog(self, tmpl, ctx, shortlog=False):
474 def changelist(limit=0,**map):
475 cl = self.repo.changelog
476 l = [] # build a list in forward order for efficiency
477 for i in xrange(start, end):
478 ctx = self.repo.changectx(i)
479 n = ctx.node()
480 showtags = self.showtag(tmpl, 'changelogtag', n)
481
482 l.insert(0, {"parity": parity.next(),
483 "author": ctx.user(),
484 "parent": self.siblings(ctx.parents(), i - 1),
485 "child": self.siblings(ctx.children(), i + 1),
486 "changelogtag": showtags,
487 "desc": ctx.description(),
488 "date": ctx.date(),
489 "files": self.listfilediffs(tmpl, ctx.files(), n),
490 "rev": i,
491 "node": hex(n),
492 "tags": self.nodetagsdict(n),
493 "inbranch": self.nodeinbranch(ctx),
494 "branches": self.nodebranchdict(ctx)})
495
496 if limit > 0:
497 l = l[:limit]
498
499 for e in l:
500 yield e
501
502 maxchanges = shortlog and self.maxshortchanges or self.maxchanges
503 cl = self.repo.changelog
504 count = cl.count()
505 pos = ctx.rev()
506 start = max(0, pos - maxchanges + 1)
507 end = min(count, start + maxchanges)
508 pos = end - 1
509 parity = paritygen(self.stripecount, offset=start-end)
510
511 changenav = revnavgen(pos, maxchanges, count, self.repo.changectx)
512
513 return tmpl(shortlog and 'shortlog' or 'changelog',
514 changenav=changenav,
515 node=hex(cl.tip()),
516 rev=pos, changesets=count,
517 entries=lambda **x: changelist(limit=0,**x),
518 latestentry=lambda **x: changelist(limit=1,**x),
519 archives=self.archivelist("tip"))
520
521 def search(self, tmpl, query):
522
523 def changelist(**map):
524 cl = self.repo.changelog
525 count = 0
526 qw = query.lower().split()
527
528 def revgen():
529 for i in xrange(cl.count() - 1, 0, -100):
530 l = []
531 for j in xrange(max(0, i - 100), i + 1):
532 ctx = self.repo.changectx(j)
533 l.append(ctx)
534 l.reverse()
535 for e in l:
536 yield e
537
538 for ctx in revgen():
539 miss = 0
540 for q in qw:
541 if not (q in ctx.user().lower() or
542 q in ctx.description().lower() or
543 q in " ".join(ctx.files()).lower()):
544 miss = 1
545 break
546 if miss:
547 continue
548
549 count += 1
550 n = ctx.node()
551 showtags = self.showtag(tmpl, 'changelogtag', n)
552
553 yield tmpl('searchentry',
554 parity=parity.next(),
555 author=ctx.user(),
556 parent=self.siblings(ctx.parents()),
557 child=self.siblings(ctx.children()),
558 changelogtag=showtags,
559 desc=ctx.description(),
560 date=ctx.date(),
561 files=self.listfilediffs(tmpl, ctx.files(), n),
562 rev=ctx.rev(),
563 node=hex(n),
564 tags=self.nodetagsdict(n),
565 inbranch=self.nodeinbranch(ctx),
566 branches=self.nodebranchdict(ctx))
567
568 if count >= self.maxchanges:
569 break
570
571 cl = self.repo.changelog
572 parity = paritygen(self.stripecount)
573
574 return tmpl('search',
575 query=query,
576 node=hex(cl.tip()),
577 entries=changelist,
578 archives=self.archivelist("tip"))
579
580 def changeset(self, tmpl, ctx):
581 n = ctx.node()
582 showtags = self.showtag(tmpl, 'changesettag', n)
583 parents = ctx.parents()
584 p1 = parents[0].node()
585
586 files = []
587 parity = paritygen(self.stripecount)
588 for f in ctx.files():
589 files.append(tmpl("filenodelink",
590 node=hex(n), file=f,
591 parity=parity.next()))
592
593 def diff(**map):
594 yield self.diff(tmpl, p1, n, None)
595
596 return tmpl('changeset',
597 diff=diff,
598 rev=ctx.rev(),
599 node=hex(n),
600 parent=self.siblings(parents),
601 child=self.siblings(ctx.children()),
602 changesettag=showtags,
603 author=ctx.user(),
604 desc=ctx.description(),
605 date=ctx.date(),
606 files=files,
607 archives=self.archivelist(hex(n)),
608 tags=self.nodetagsdict(n),
609 branch=self.nodebranchnodefault(ctx),
610 inbranch=self.nodeinbranch(ctx),
611 branches=self.nodebranchdict(ctx))
612
613 def filelog(self, tmpl, fctx):
614 f = fctx.path()
615 fl = fctx.filelog()
616 count = fl.count()
617 pagelen = self.maxshortchanges
618 pos = fctx.filerev()
619 start = max(0, pos - pagelen + 1)
620 end = min(count, start + pagelen)
621 pos = end - 1
622 parity = paritygen(self.stripecount, offset=start-end)
623
624 def entries(limit=0, **map):
625 l = []
626
627 for i in xrange(start, end):
628 ctx = fctx.filectx(i)
629 n = fl.node(i)
630
631 l.insert(0, {"parity": parity.next(),
632 "filerev": i,
633 "file": f,
634 "node": hex(ctx.node()),
635 "author": ctx.user(),
636 "date": ctx.date(),
637 "rename": self.renamelink(fl, n),
638 "parent": self.siblings(fctx.parents()),
639 "child": self.siblings(fctx.children()),
640 "desc": ctx.description()})
641
642 if limit > 0:
643 l = l[:limit]
644
645 for e in l:
646 yield e
647
648 nodefunc = lambda x: fctx.filectx(fileid=x)
649 nav = revnavgen(pos, pagelen, count, nodefunc)
650 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
651 entries=lambda **x: entries(limit=0, **x),
652 latestentry=lambda **x: entries(limit=1, **x))
653
654 def filerevision(self, tmpl, fctx):
655 f = fctx.path()
656 text = fctx.data()
657 fl = fctx.filelog()
658 n = fctx.filenode()
659 parity = paritygen(self.stripecount)
660
661 if util.binary(text):
662 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
663 text = '(binary:%s)' % mt
664
665 def lines():
666 for lineno, t in enumerate(text.splitlines(1)):
667 yield {"line": t,
668 "lineid": "l%d" % (lineno + 1),
669 "linenumber": "% 6d" % (lineno + 1),
670 "parity": parity.next()}
671
672 return tmpl("filerevision",
673 file=f,
674 path=_up(f),
675 text=lines(),
676 rev=fctx.rev(),
677 node=hex(fctx.node()),
678 author=fctx.user(),
679 date=fctx.date(),
680 desc=fctx.description(),
681 branch=self.nodebranchnodefault(fctx),
682 parent=self.siblings(fctx.parents()),
683 child=self.siblings(fctx.children()),
684 rename=self.renamelink(fl, n),
685 permissions=fctx.manifest().flags(f))
686
687 def fileannotate(self, tmpl, fctx):
688 f = fctx.path()
689 n = fctx.filenode()
690 fl = fctx.filelog()
691 parity = paritygen(self.stripecount)
692
693 def annotate(**map):
694 last = None
695 if util.binary(fctx.data()):
696 mt = (mimetypes.guess_type(fctx.path())[0]
697 or 'application/octet-stream')
698 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
699 '(binary:%s)' % mt)])
700 else:
701 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
702 for lineno, ((f, targetline), l) in lines:
703 fnode = f.filenode()
704 name = self.repo.ui.shortuser(f.user())
705
706 if last != fnode:
707 last = fnode
708
709 yield {"parity": parity.next(),
710 "node": hex(f.node()),
711 "rev": f.rev(),
712 "author": name,
713 "file": f.path(),
714 "targetline": targetline,
715 "line": l,
716 "lineid": "l%d" % (lineno + 1),
717 "linenumber": "% 6d" % (lineno + 1)}
718
719 return tmpl("fileannotate",
720 file=f,
721 annotate=annotate,
722 path=_up(f),
723 rev=fctx.rev(),
724 node=hex(fctx.node()),
725 author=fctx.user(),
726 date=fctx.date(),
727 desc=fctx.description(),
728 rename=self.renamelink(fl, n),
729 branch=self.nodebranchnodefault(fctx),
730 parent=self.siblings(fctx.parents()),
731 child=self.siblings(fctx.children()),
732 permissions=fctx.manifest().flags(f))
733
734 def manifest(self, tmpl, ctx, path):
735 mf = ctx.manifest()
736 node = ctx.node()
737
738 files = {}
739 parity = paritygen(self.stripecount)
740
741 if path and path[-1] != "/":
742 path += "/"
743 l = len(path)
744 abspath = "/" + path
745
746 for f, n in mf.items():
747 if f[:l] != path:
748 continue
749 remain = f[l:]
750 if "/" in remain:
751 short = remain[:remain.index("/") + 1] # bleah
752 files[short] = (f, None)
753 else:
754 short = os.path.basename(remain)
755 files[short] = (f, n)
756
757 if not files:
758 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
759
760 def filelist(**map):
761 fl = files.keys()
762 fl.sort()
763 for f in fl:
764 full, fnode = files[f]
765 if not fnode:
766 continue
767
768 fctx = ctx.filectx(full)
769 yield {"file": full,
770 "parity": parity.next(),
771 "basename": f,
772 "date": fctx.changectx().date(),
773 "size": fctx.size(),
774 "permissions": mf.flags(full)}
775
776 def dirlist(**map):
777 fl = files.keys()
778 fl.sort()
779 for f in fl:
780 full, fnode = files[f]
781 if fnode:
782 continue
783
784 yield {"parity": parity.next(),
785 "path": "%s%s" % (abspath, f),
786 "basename": f[:-1]}
787
788 return tmpl("manifest",
789 rev=ctx.rev(),
790 node=hex(node),
791 path=abspath,
792 up=_up(abspath),
793 upparity=parity.next(),
794 fentries=filelist,
795 dentries=dirlist,
796 archives=self.archivelist(hex(node)),
797 tags=self.nodetagsdict(node),
798 inbranch=self.nodeinbranch(ctx),
799 branches=self.nodebranchdict(ctx))
800
801 def tags(self, tmpl):
802 i = self.repo.tagslist()
803 i.reverse()
804 parity = paritygen(self.stripecount)
805
806 def entries(notip=False,limit=0, **map):
807 count = 0
808 for k, n in i:
809 if notip and k == "tip":
810 continue
811 if limit > 0 and count >= limit:
812 continue
813 count = count + 1
814 yield {"parity": parity.next(),
815 "tag": k,
816 "date": self.repo.changectx(n).date(),
817 "node": hex(n)}
818
819 return tmpl("tags",
820 node=hex(self.repo.changelog.tip()),
821 entries=lambda **x: entries(False,0, **x),
822 entriesnotip=lambda **x: entries(True,0, **x),
823 latestentry=lambda **x: entries(True,1, **x))
824
825 def summary(self, tmpl):
826 i = self.repo.tagslist()
827 i.reverse()
828
829 def tagentries(**map):
830 parity = paritygen(self.stripecount)
831 count = 0
832 for k, n in i:
833 if k == "tip": # skip tip
834 continue;
835
836 count += 1
837 if count > 10: # limit to 10 tags
838 break;
839
840 yield tmpl("tagentry",
841 parity=parity.next(),
842 tag=k,
843 node=hex(n),
844 date=self.repo.changectx(n).date())
845
846
847 def branches(**map):
848 parity = paritygen(self.stripecount)
849
850 b = self.repo.branchtags()
851 l = [(-self.repo.changelog.rev(n), n, t) for t, n in b.items()]
852 l.sort()
853
854 for r,n,t in l:
855 ctx = self.repo.changectx(n)
856
857 yield {'parity': parity.next(),
858 'branch': t,
859 'node': hex(n),
860 'date': ctx.date()}
861
862 def changelist(**map):
863 parity = paritygen(self.stripecount, offset=start-end)
864 l = [] # build a list in forward order for efficiency
865 for i in xrange(start, end):
866 ctx = self.repo.changectx(i)
867 n = ctx.node()
868 hn = hex(n)
869
870 l.insert(0, tmpl(
871 'shortlogentry',
872 parity=parity.next(),
873 author=ctx.user(),
874 desc=ctx.description(),
875 date=ctx.date(),
876 rev=i,
877 node=hn,
878 tags=self.nodetagsdict(n),
879 inbranch=self.nodeinbranch(ctx),
880 branches=self.nodebranchdict(ctx)))
881
882 yield l
883
884 cl = self.repo.changelog
885 count = cl.count()
886 start = max(0, count - self.maxchanges)
887 end = min(count, start + self.maxchanges)
888
889 return tmpl("summary",
890 desc=self.config("web", "description", "unknown"),
891 owner=get_contact(self.config) or "unknown",
892 lastchange=cl.read(cl.tip())[2],
893 tags=tagentries,
894 branches=branches,
895 shortlog=changelist,
896 node=hex(cl.tip()),
897 archives=self.archivelist("tip"))
898
899 def filediff(self, tmpl, fctx):
900 n = fctx.node()
901 path = fctx.path()
902 parents = fctx.parents()
903 p1 = parents and parents[0].node() or nullid
904
905 def diff(**map):
906 yield self.diff(tmpl, p1, n, [path])
907
908 return tmpl("filediff",
909 file=path,
910 node=hex(n),
911 rev=fctx.rev(),
912 branch=self.nodebranchnodefault(fctx),
913 parent=self.siblings(parents),
914 child=self.siblings(fctx.children()),
915 diff=diff)
916
917 361 archive_specs = {
918 362 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
919 363 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
920 364 'zip': ('application/zip', 'zip', '.zip', None),
921 365 }
922 366
923 def archive(self, tmpl, req, key, type_):
924 reponame = re.sub(r"\W+", "-", os.path.basename(self.reponame))
925 cnode = self.repo.lookup(key)
926 arch_version = key
927 if cnode == key or key == 'tip':
928 arch_version = short(cnode)
929 name = "%s-%s" % (reponame, arch_version)
930 mimetype, artype, extension, encoding = self.archive_specs[type_]
931 headers = [
932 ('Content-Type', mimetype),
933 ('Content-Disposition', 'attachment; filename=%s%s' %
934 (name, extension))
935 ]
936 if encoding:
937 headers.append(('Content-Encoding', encoding))
938 req.header(headers)
939 req.respond(HTTP_OK)
940 archival.archive(self.repo, req, cnode, artype, prefix=name)
941
942 # add tags to things
943 # tags -> list of changesets corresponding to tags
944 # find tag, changeset, file
945
946 def cleanpath(self, path):
947 path = path.lstrip('/')
948 return util.canonpath(self.repo.root, '', path)
949
950 def changectx(self, req):
951 if 'node' in req.form:
952 changeid = req.form['node'][0]
953 elif 'manifest' in req.form:
954 changeid = req.form['manifest'][0]
955 else:
956 changeid = self.repo.changelog.count() - 1
957
958 try:
959 ctx = self.repo.changectx(changeid)
960 except RepoError:
961 man = self.repo.manifest
962 mn = man.lookup(changeid)
963 ctx = self.repo.changectx(man.linkrev(mn))
964
965 return ctx
966
967 def filectx(self, req):
968 path = self.cleanpath(req.form['file'][0])
969 if 'node' in req.form:
970 changeid = req.form['node'][0]
971 else:
972 changeid = req.form['filenode'][0]
973 try:
974 ctx = self.repo.changectx(changeid)
975 fctx = ctx.filectx(path)
976 except RepoError:
977 fctx = self.repo.filectx(path, fileid=changeid)
978
979 return fctx
980
981 367 def check_perm(self, req, op, default):
982 368 '''check permission for operation based on user auth.
983 369 return true if op allowed, else false.
@@ -6,7 +6,7 b''
6 6 # This software may be used and distributed according to the terms
7 7 # of the GNU General Public License, incorporated herein by reference.
8 8
9 import os, mimetools, cStringIO
9 import os
10 10 from mercurial.i18n import gettext as _
11 11 from mercurial.repo import RepoError
12 12 from mercurial import ui, hg, util, templater, templatefilters
@@ -81,17 +81,8 b' class hgwebdir(object):'
81 81
82 82 virtual = req.env.get("PATH_INFO", "").strip('/')
83 83 tmpl = self.templater(req)
84 try:
85 ctype = tmpl('mimetype', encoding=util._encoding)
86 ctype = templater.stringify(ctype)
87 except KeyError:
88 # old templates with inline HTTP headers?
89 if 'mimetype' in tmpl:
90 raise
91 header = tmpl('header', encoding=util._encoding)
92 header_file = cStringIO.StringIO(templater.stringify(header))
93 msg = mimetools.Message(header_file, 0)
94 ctype = msg['content-type']
84 ctype = tmpl('mimetype', encoding=util._encoding)
85 ctype = templater.stringify(ctype)
95 86
96 87 # a static file
97 88 if virtual.startswith('static/') or 'static' in req.form:
@@ -255,13 +246,7 b' class hgwebdir(object):'
255 246 def templater(self, req):
256 247
257 248 def header(**map):
258 header = tmpl('header', encoding=util._encoding, **map)
259 if 'mimetype' not in tmpl:
260 # old template with inline HTTP headers
261 header_file = cStringIO.StringIO(templater.stringify(header))
262 msg = mimetools.Message(header_file, 0)
263 header = header_file.read()
264 yield header
249 yield tmpl('header', encoding=util._encoding, **map)
265 250
266 251 def footer(**map):
267 252 yield tmpl("footer", **map)
@@ -268,12 +268,7 b' def create_server(ui, repo):'
268 268
269 269 self.addr, self.port = self.socket.getsockname()[0:2]
270 270 self.prefix = prefix
271
272 271 self.fqaddr = socket.getfqdn(address)
273 try:
274 socket.getaddrbyhost(self.fqaddr)
275 except:
276 fqaddr = address
277 272
278 273 class IPv6HTTPServer(MercurialHTTPServer):
279 274 address_family = getattr(socket, 'AF_INET6', None)
This diff has been collapsed as it changes many lines, (501 lines changed) Show them Hide them
@@ -5,10 +5,14 b''
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 import os, mimetypes
9 from mercurial import revlog, util
8 import os, mimetypes, re
9 import webutil
10 from mercurial import revlog, archival
11 from mercurial.node import short, hex, nullid
12 from mercurial.util import binary
10 13 from mercurial.repo import RepoError
11 from common import staticfile, ErrorResponse, HTTP_OK, HTTP_NOT_FOUND
14 from common import paritygen, staticfile, get_contact, ErrorResponse
15 from common import HTTP_OK, HTTP_NOT_FOUND
12 16
13 17 # __all__ is populated with the allowed commands. Be sure to add to it if
14 18 # you're adding a new command, or the new command won't work.
@@ -26,17 +30,17 b' def log(web, req, tmpl):'
26 30 return changelog(web, req, tmpl)
27 31
28 32 def rawfile(web, req, tmpl):
29 path = web.cleanpath(req.form.get('file', [''])[0])
33 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
30 34 if not path:
31 content = web.manifest(tmpl, web.changectx(req), path)
35 content = manifest(web, req, tmpl)
32 36 req.respond(HTTP_OK, web.ctype)
33 37 return content
34 38
35 39 try:
36 fctx = web.filectx(req)
40 fctx = webutil.filectx(web.repo, req)
37 41 except revlog.LookupError, inst:
38 42 try:
39 content = web.manifest(tmpl, web.changectx(req), path)
43 content = manifest(web, req, tmpl)
40 44 req.respond(HTTP_OK, web.ctype)
41 45 return content
42 46 except ErrorResponse:
@@ -45,28 +49,120 b' def rawfile(web, req, tmpl):'
45 49 path = fctx.path()
46 50 text = fctx.data()
47 51 mt = mimetypes.guess_type(path)[0]
48 if mt is None or util.binary(text):
52 if mt is None or binary(text):
49 53 mt = mt or 'application/octet-stream'
50 54
51 55 req.respond(HTTP_OK, mt, path, len(text))
52 56 return [text]
53 57
58 def _filerevision(web, tmpl, fctx):
59 f = fctx.path()
60 text = fctx.data()
61 fl = fctx.filelog()
62 n = fctx.filenode()
63 parity = paritygen(web.stripecount)
64
65 if binary(text):
66 mt = mimetypes.guess_type(f)[0] or 'application/octet-stream'
67 text = '(binary:%s)' % mt
68
69 def lines():
70 for lineno, t in enumerate(text.splitlines(1)):
71 yield {"line": t,
72 "lineid": "l%d" % (lineno + 1),
73 "linenumber": "% 6d" % (lineno + 1),
74 "parity": parity.next()}
75
76 return tmpl("filerevision",
77 file=f,
78 path=webutil.up(f),
79 text=lines(),
80 rev=fctx.rev(),
81 node=hex(fctx.node()),
82 author=fctx.user(),
83 date=fctx.date(),
84 desc=fctx.description(),
85 branch=webutil.nodebranchnodefault(fctx),
86 parent=webutil.siblings(fctx.parents()),
87 child=webutil.siblings(fctx.children()),
88 rename=webutil.renamelink(fctx),
89 permissions=fctx.manifest().flags(f))
90
54 91 def file(web, req, tmpl):
55 path = web.cleanpath(req.form.get('file', [''])[0])
92 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
56 93 if path:
57 94 try:
58 return web.filerevision(tmpl, web.filectx(req))
95 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
59 96 except revlog.LookupError, inst:
60 97 pass
61 98
62 99 try:
63 return web.manifest(tmpl, web.changectx(req), path)
100 return manifest(web, req, tmpl)
64 101 except ErrorResponse:
65 102 raise inst
66 103
104 def _search(web, tmpl, query):
105
106 def changelist(**map):
107 cl = web.repo.changelog
108 count = 0
109 qw = query.lower().split()
110
111 def revgen():
112 for i in xrange(cl.count() - 1, 0, -100):
113 l = []
114 for j in xrange(max(0, i - 100), i + 1):
115 ctx = web.repo.changectx(j)
116 l.append(ctx)
117 l.reverse()
118 for e in l:
119 yield e
120
121 for ctx in revgen():
122 miss = 0
123 for q in qw:
124 if not (q in ctx.user().lower() or
125 q in ctx.description().lower() or
126 q in " ".join(ctx.files()).lower()):
127 miss = 1
128 break
129 if miss:
130 continue
131
132 count = 1
133 n = ctx.node()
134 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
135
136 yield tmpl('searchentry',
137 parity=parity.next(),
138 author=ctx.user(),
139 parent=webutil.siblings(ctx.parents()),
140 child=webutil.siblings(ctx.children()),
141 changelogtag=showtags,
142 desc=ctx.description(),
143 date=ctx.date(),
144 files=web.listfilediffs(tmpl, ctx.files(), n),
145 rev=ctx.rev(),
146 node=hex(n),
147 tags=webutil.nodetagsdict(web.repo, n),
148 inbranch=webutil.nodeinbranch(web.repo, ctx),
149 branches=webutil.nodebranchdict(web.repo, ctx))
150
151 if count >= web.maxchanges:
152 break
153
154 cl = web.repo.changelog
155 parity = paritygen(web.stripecount)
156
157 return tmpl('search',
158 query=query,
159 node=hex(cl.tip()),
160 entries=changelist,
161 archives=web.archivelist("tip"))
162
67 163 def changelog(web, req, tmpl, shortlog = False):
68 164 if 'node' in req.form:
69 ctx = web.changectx(req)
165 ctx = webutil.changectx(web.repo, req)
70 166 else:
71 167 if 'rev' in req.form:
72 168 hi = req.form['rev'][0]
@@ -75,47 +171,400 b' def changelog(web, req, tmpl, shortlog ='
75 171 try:
76 172 ctx = web.repo.changectx(hi)
77 173 except RepoError:
78 return web.search(tmpl, hi) # XXX redirect to 404 page?
174 return _search(web, tmpl, hi) # XXX redirect to 404 page?
175
176 def changelist(limit=0, **map):
177 cl = web.repo.changelog
178 l = [] # build a list in forward order for efficiency
179 for i in xrange(start, end):
180 ctx = web.repo.changectx(i)
181 n = ctx.node()
182 showtags = webutil.showtag(web.repo, tmpl, 'changelogtag', n)
183
184 l.insert(0, {"parity": parity.next(),
185 "author": ctx.user(),
186 "parent": webutil.siblings(ctx.parents(), i - 1),
187 "child": webutil.siblings(ctx.children(), i + 1),
188 "changelogtag": showtags,
189 "desc": ctx.description(),
190 "date": ctx.date(),
191 "files": web.listfilediffs(tmpl, ctx.files(), n),
192 "rev": i,
193 "node": hex(n),
194 "tags": webutil.nodetagsdict(web.repo, n),
195 "inbranch": webutil.nodeinbranch(web.repo, ctx),
196 "branches": webutil.nodebranchdict(web.repo, ctx)
197 })
79 198
80 return web.changelog(tmpl, ctx, shortlog = shortlog)
199 if limit > 0:
200 l = l[:limit]
201
202 for e in l:
203 yield e
204
205 maxchanges = shortlog and web.maxshortchanges or web.maxchanges
206 cl = web.repo.changelog
207 count = cl.count()
208 pos = ctx.rev()
209 start = max(0, pos - maxchanges + 1)
210 end = min(count, start + maxchanges)
211 pos = end - 1
212 parity = paritygen(web.stripecount, offset=start-end)
213
214 changenav = webutil.revnavgen(pos, maxchanges, count, web.repo.changectx)
215
216 return tmpl(shortlog and 'shortlog' or 'changelog',
217 changenav=changenav,
218 node=hex(ctx.node()),
219 rev=pos, changesets=count,
220 entries=lambda **x: changelist(limit=0,**x),
221 latestentry=lambda **x: changelist(limit=1,**x),
222 archives=web.archivelist("tip"))
81 223
82 224 def shortlog(web, req, tmpl):
83 225 return changelog(web, req, tmpl, shortlog = True)
84 226
85 227 def changeset(web, req, tmpl):
86 return web.changeset(tmpl, web.changectx(req))
228 ctx = webutil.changectx(web.repo, req)
229 n = ctx.node()
230 showtags = webutil.showtag(web.repo, tmpl, 'changesettag', n)
231 parents = ctx.parents()
232 p1 = parents[0].node()
233
234 files = []
235 parity = paritygen(web.stripecount)
236 for f in ctx.files():
237 files.append(tmpl("filenodelink",
238 node=hex(n), file=f,
239 parity=parity.next()))
240
241 diffs = web.diff(tmpl, p1, n, None)
242 return tmpl('changeset',
243 diff=diffs,
244 rev=ctx.rev(),
245 node=hex(n),
246 parent=webutil.siblings(parents),
247 child=webutil.siblings(ctx.children()),
248 changesettag=showtags,
249 author=ctx.user(),
250 desc=ctx.description(),
251 date=ctx.date(),
252 files=files,
253 archives=web.archivelist(hex(n)),
254 tags=webutil.nodetagsdict(web.repo, n),
255 branch=webutil.nodebranchnodefault(ctx),
256 inbranch=webutil.nodeinbranch(web.repo, ctx),
257 branches=webutil.nodebranchdict(web.repo, ctx))
87 258
88 259 rev = changeset
89 260
90 261 def manifest(web, req, tmpl):
91 return web.manifest(tmpl, web.changectx(req),
92 web.cleanpath(req.form['path'][0]))
262 ctx = webutil.changectx(web.repo, req)
263 path = webutil.cleanpath(web.repo, req.form.get('file', [''])[0])
264 mf = ctx.manifest()
265 node = ctx.node()
266
267 files = {}
268 parity = paritygen(web.stripecount)
269
270 if path and path[-1] != "/":
271 path += "/"
272 l = len(path)
273 abspath = "/" + path
274
275 for f, n in mf.items():
276 if f[:l] != path:
277 continue
278 remain = f[l:]
279 if "/" in remain:
280 short = remain[:remain.index("/") + 1] # bleah
281 files[short] = (f, None)
282 else:
283 short = os.path.basename(remain)
284 files[short] = (f, n)
285
286 if not files:
287 raise ErrorResponse(HTTP_NOT_FOUND, 'path not found: ' + path)
288
289 def filelist(**map):
290 fl = files.keys()
291 fl.sort()
292 for f in fl:
293 full, fnode = files[f]
294 if not fnode:
295 continue
296
297 fctx = ctx.filectx(full)
298 yield {"file": full,
299 "parity": parity.next(),
300 "basename": f,
301 "date": fctx.changectx().date(),
302 "size": fctx.size(),
303 "permissions": mf.flags(full)}
304
305 def dirlist(**map):
306 fl = files.keys()
307 fl.sort()
308 for f in fl:
309 full, fnode = files[f]
310 if fnode:
311 continue
312
313 yield {"parity": parity.next(),
314 "path": "%s%s" % (abspath, f),
315 "basename": f[:-1]}
316
317 return tmpl("manifest",
318 rev=ctx.rev(),
319 node=hex(node),
320 path=abspath,
321 up=webutil.up(abspath),
322 upparity=parity.next(),
323 fentries=filelist,
324 dentries=dirlist,
325 archives=web.archivelist(hex(node)),
326 tags=webutil.nodetagsdict(web.repo, node),
327 inbranch=webutil.nodeinbranch(web.repo, ctx),
328 branches=webutil.nodebranchdict(web.repo, ctx))
93 329
94 330 def tags(web, req, tmpl):
95 return web.tags(tmpl)
331 i = web.repo.tagslist()
332 i.reverse()
333 parity = paritygen(web.stripecount)
334
335 def entries(notip=False,limit=0, **map):
336 count = 0
337 for k, n in i:
338 if notip and k == "tip":
339 continue
340 if limit > 0 and count >= limit:
341 continue
342 count = count + 1
343 yield {"parity": parity.next(),
344 "tag": k,
345 "date": web.repo.changectx(n).date(),
346 "node": hex(n)}
347
348 return tmpl("tags",
349 node=hex(web.repo.changelog.tip()),
350 entries=lambda **x: entries(False,0, **x),
351 entriesnotip=lambda **x: entries(True,0, **x),
352 latestentry=lambda **x: entries(True,1, **x))
96 353
97 354 def summary(web, req, tmpl):
98 return web.summary(tmpl)
355 i = web.repo.tagslist()
356 i.reverse()
357
358 def tagentries(**map):
359 parity = paritygen(web.stripecount)
360 count = 0
361 for k, n in i:
362 if k == "tip": # skip tip
363 continue
364
365 count = 1
366 if count > 10: # limit to 10 tags
367 break
368
369 yield tmpl("tagentry",
370 parity=parity.next(),
371 tag=k,
372 node=hex(n),
373 date=web.repo.changectx(n).date())
374
375 def branches(**map):
376 parity = paritygen(web.stripecount)
377
378 b = web.repo.branchtags()
379 l = [(-web.repo.changelog.rev(n), n, t) for t, n in b.items()]
380 l.sort()
381
382 for r,n,t in l:
383 ctx = web.repo.changectx(n)
384 yield {'parity': parity.next(),
385 'branch': t,
386 'node': hex(n),
387 'date': ctx.date()}
388
389 def changelist(**map):
390 parity = paritygen(web.stripecount, offset=start-end)
391 l = [] # build a list in forward order for efficiency
392 for i in xrange(start, end):
393 ctx = web.repo.changectx(i)
394 n = ctx.node()
395 hn = hex(n)
396
397 l.insert(0, tmpl(
398 'shortlogentry',
399 parity=parity.next(),
400 author=ctx.user(),
401 desc=ctx.description(),
402 date=ctx.date(),
403 rev=i,
404 node=hn,
405 tags=webutil.nodetagsdict(web.repo, n),
406 inbranch=webutil.nodeinbranch(web.repo, ctx),
407 branches=webutil.nodebranchdict(web.repo, ctx)))
408
409 yield l
410
411 cl = web.repo.changelog
412 count = cl.count()
413 start = max(0, count - web.maxchanges)
414 end = min(count, start + web.maxchanges)
415
416 return tmpl("summary",
417 desc=web.config("web", "description", "unknown"),
418 owner=get_contact(web.config) or "unknown",
419 lastchange=cl.read(cl.tip())[2],
420 tags=tagentries,
421 branches=branches,
422 shortlog=changelist,
423 node=hex(cl.tip()),
424 archives=web.archivelist("tip"))
99 425
100 426 def filediff(web, req, tmpl):
101 return web.filediff(tmpl, web.filectx(req))
427 fctx = webutil.filectx(web.repo, req)
428 n = fctx.node()
429 path = fctx.path()
430 parents = fctx.parents()
431 p1 = parents and parents[0].node() or nullid
432
433 diffs = web.diff(tmpl, p1, n, [path])
434 return tmpl("filediff",
435 file=path,
436 node=hex(n),
437 rev=fctx.rev(),
438 date=fctx.date(),
439 desc=fctx.description(),
440 author=fctx.user(),
441 rename=webutil.renamelink(fctx),
442 branch=webutil.nodebranchnodefault(fctx),
443 parent=webutil.siblings(parents),
444 child=webutil.siblings(fctx.children()),
445 diff=diffs)
102 446
103 447 diff = filediff
104 448
105 449 def annotate(web, req, tmpl):
106 return web.fileannotate(tmpl, web.filectx(req))
450 fctx = webutil.filectx(web.repo, req)
451 f = fctx.path()
452 n = fctx.filenode()
453 fl = fctx.filelog()
454 parity = paritygen(web.stripecount)
455
456 def annotate(**map):
457 last = None
458 if binary(fctx.data()):
459 mt = (mimetypes.guess_type(fctx.path())[0]
460 or 'application/octet-stream')
461 lines = enumerate([((fctx.filectx(fctx.filerev()), 1),
462 '(binary:%s)' % mt)])
463 else:
464 lines = enumerate(fctx.annotate(follow=True, linenumber=True))
465 for lineno, ((f, targetline), l) in lines:
466 fnode = f.filenode()
467 name = web.repo.ui.shortuser(f.user())
468
469 if last != fnode:
470 last = fnode
471
472 yield {"parity": parity.next(),
473 "node": hex(f.node()),
474 "rev": f.rev(),
475 "author": name,
476 "file": f.path(),
477 "targetline": targetline,
478 "line": l,
479 "lineid": "l%d" % (lineno + 1),
480 "linenumber": "% 6d" % (lineno + 1)}
481
482 return tmpl("fileannotate",
483 file=f,
484 annotate=annotate,
485 path=webutil.up(f),
486 rev=fctx.rev(),
487 node=hex(fctx.node()),
488 author=fctx.user(),
489 date=fctx.date(),
490 desc=fctx.description(),
491 rename=webutil.renamelink(fctx),
492 branch=webutil.nodebranchnodefault(fctx),
493 parent=webutil.siblings(fctx.parents()),
494 child=webutil.siblings(fctx.children()),
495 permissions=fctx.manifest().flags(f))
107 496
108 497 def filelog(web, req, tmpl):
109 return web.filelog(tmpl, web.filectx(req))
498 fctx = webutil.filectx(web.repo, req)
499 f = fctx.path()
500 fl = fctx.filelog()
501 count = fl.count()
502 pagelen = web.maxshortchanges
503 pos = fctx.filerev()
504 start = max(0, pos - pagelen + 1)
505 end = min(count, start + pagelen)
506 pos = end - 1
507 parity = paritygen(web.stripecount, offset=start-end)
508
509 def entries(limit=0, **map):
510 l = []
511
512 for i in xrange(start, end):
513 ctx = fctx.filectx(i)
514 n = fl.node(i)
515
516 l.insert(0, {"parity": parity.next(),
517 "filerev": i,
518 "file": f,
519 "node": hex(ctx.node()),
520 "author": ctx.user(),
521 "date": ctx.date(),
522 "rename": webutil.renamelink(fctx),
523 "parent": webutil.siblings(fctx.parents()),
524 "child": webutil.siblings(fctx.children()),
525 "desc": ctx.description()})
526
527 if limit > 0:
528 l = l[:limit]
529
530 for e in l:
531 yield e
532
533 nodefunc = lambda x: fctx.filectx(fileid=x)
534 nav = webutil.revnavgen(pos, pagelen, count, nodefunc)
535 return tmpl("filelog", file=f, node=hex(fctx.node()), nav=nav,
536 entries=lambda **x: entries(limit=0, **x),
537 latestentry=lambda **x: entries(limit=1, **x))
538
110 539
111 540 def archive(web, req, tmpl):
112 541 type_ = req.form['type'][0]
113 542 allowed = web.configlist("web", "allow_archive")
114 if (type_ in web.archives and (type_ in allowed or
543 key = req.form['node'][0]
544
545 if not (type_ in web.archives and (type_ in allowed or
115 546 web.configbool("web", "allow" + type_, False))):
116 web.archive(tmpl, req, req.form['node'][0], type_)
117 return []
118 raise ErrorResponse(HTTP_NOT_FOUND, 'unsupported archive type: %s' % type_)
547 msg = 'Unsupported archive type: %s' % type_
548 raise ErrorResponse(HTTP_NOT_FOUND, msg)
549
550 reponame = re.sub(r"\W+", "-", os.path.basename(web.reponame))
551 cnode = web.repo.lookup(key)
552 arch_version = key
553 if cnode == key or key == 'tip':
554 arch_version = short(cnode)
555 name = "%s-%s" % (reponame, arch_version)
556 mimetype, artype, extension, encoding = web.archive_specs[type_]
557 headers = [
558 ('Content-Type', mimetype),
559 ('Content-Disposition', 'attachment; filename=%s%s' % (name, extension))
560 ]
561 if encoding:
562 headers.append(('Content-Encoding', encoding))
563 req.header(headers)
564 req.respond(HTTP_OK)
565 archival.archive(web.repo, req, cnode, artype, prefix=name)
566 return []
567
119 568
120 569 def static(web, req, tmpl):
121 570 fname = req.form['file'][0]
@@ -8,7 +8,7 b''
8 8 from node import bin, hex, nullid
9 9 from revlog import revlog, RevlogError
10 10 from i18n import _
11 import array, struct, mdiff
11 import array, struct, mdiff, parsers
12 12
13 13 class manifestdict(dict):
14 14 def __init__(self, mapping=None, flags=None):
@@ -39,14 +39,7 b' class manifest(revlog):'
39 39
40 40 def parse(self, lines):
41 41 mfdict = manifestdict()
42 fdict = mfdict._flags
43 for l in lines.splitlines():
44 f, n = l.split('\0')
45 if len(n) > 40:
46 fdict[f] = n[40:]
47 mfdict[f] = bin(n[:40])
48 else:
49 mfdict[f] = bin(n)
42 parsers.parse_manifest(mfdict, mfdict._flags, lines)
50 43 return mfdict
51 44
52 45 def readdelta(self, node):
@@ -72,7 +72,6 b' def _collectextranodes(repo, files, link'
72 72 def strip(ui, repo, node, backup="all"):
73 73 cl = repo.changelog
74 74 # TODO delete the undo files, and handle undo of merge sets
75 pp = cl.parents(node)
76 75 striprev = cl.rev(node)
77 76
78 77 # Some revisions with rev > striprev may not be descendants of striprev.
@@ -114,7 +114,7 b' class templater(object):'
114 114 v = v(**map)
115 115 if format:
116 116 if not hasattr(v, '__iter__'):
117 raise SyntaxError(_("Error expanding '%s%s'")
117 raise SyntaxError(_("Error expanding '%s%%%s'")
118 118 % (key, format))
119 119 lm = map.copy()
120 120 for i in v:
@@ -96,9 +96,13 b' def rollback(opener, file):'
96 96 files = {}
97 97 for l in open(file).readlines():
98 98 f, o = l.split('\0')
99 files[f] = o
99 files[f] = int(o)
100 100 for f in files:
101 101 o = files[f]
102 opener(f, "a").truncate(int(o))
102 if o:
103 opener(f, "a").truncate(int(o))
104 else:
105 fn = opener(f).name
106 os.unlink(fn)
103 107 os.unlink(file)
104 108
@@ -88,10 +88,11 b' mercurial.version.remember_version(versi'
88 88 cmdclass = {'install_data': install_package_data}
89 89
90 90 ext_modules=[
91 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
91 Extension('mercurial.base85', ['mercurial/base85.c']),
92 92 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
93 Extension('mercurial.base85', ['mercurial/base85.c']),
94 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c'])
93 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
94 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
95 Extension('mercurial.parsers', ['mercurial/parsers.c']),
95 96 ]
96 97
97 98 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert']
1 NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
@@ -3,6 +3,8 b''
3 3 echo "[extensions]" >> $HGRCPATH
4 4 echo "churn=" >> $HGRCPATH
5 5
6 COLUMNS=80; export COLUMNS
7
6 8 echo % create test repository
7 9 hg init repo
8 10 cd repo
@@ -10,7 +10,7 b' output the current or given revision of '
10 10 or tip if no revision is checked out.
11 11
12 12 Output may be to a file, in which case the name of the file is
13 given using a format string. The formatting rules are the same as
13 given using a format string. The formatting rules are the same as
14 14 for the export command, with the following additions:
15 15
16 16 %s basename of file being printed
@@ -216,10 +216,10 b' aliases: st'
216 216
217 217 show changed files in the working directory
218 218
219 Show status of files in the repository. If names are given, only
220 files that match are shown. Files that are clean or ignored or
219 Show status of files in the repository. If names are given, only
220 files that match are shown. Files that are clean or ignored or
221 221 source of a copy/move operation, are not listed unless -c (clean),
222 -i (ignored), -C (copies) or -A is given. Unless options described
222 -i (ignored), -C (copies) or -A is given. Unless options described
223 223 with "show only ..." are given, the options -mardu are used.
224 224
225 225 Option -q/--quiet hides untracked (unknown and ignored) files
@@ -1,12 +1,12 b''
1 1 % Without -v
2 2 access log created - .hg/hgrc respected
3 3 % With -v
4 listening at http://localhost/ (127.0.0.1)
4 listening at http://localhost/ (bound to 127.0.0.1)
5 5 % With --prefix foo
6 listening at http://localhost/foo/ (127.0.0.1)
6 listening at http://localhost/foo/ (bound to 127.0.0.1)
7 7 % With --prefix /foo
8 listening at http://localhost/foo/ (127.0.0.1)
8 listening at http://localhost/foo/ (bound to 127.0.0.1)
9 9 % With --prefix foo/
10 listening at http://localhost/foo/ (127.0.0.1)
10 listening at http://localhost/foo/ (bound to 127.0.0.1)
11 11 % With --prefix /foo/
12 listening at http://localhost/foo/ (127.0.0.1)
12 listening at http://localhost/foo/ (bound to 127.0.0.1)
General Comments 0
You need to be logged in to leave comments. Login now