##// 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
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 ;; This code has been developed under XEmacs 21.5, and may not work as
35 ;; This code has been developed under XEmacs 21.5, and may not work as
36 ;; well under GNU Emacs (albeit tested under 21.4). Patches to
36 ;; well under GNU Emacs (albeit tested under 21.4). Patches to
37 ;; enhance the portability of this code, fix bugs, and add features
37 ;; enhance the portability of this code, fix bugs, and add features
38 ;; are most welcome. You can clone a Mercurial repository for this
38 ;; are most welcome.
39 ;; package from http://www.serpentine.com/hg/hg-emacs
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 ;; Please send problem reports and suggestions to bos@serpentine.com.
43 ;; Please send problem reports and suggestions to bos@serpentine.com.
42
44
@@ -30,7 +30,7 b' revision::'
30
30
31 repository path::
31 repository path::
32 either the pathname of a local repository or the URI of a remote
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 fast and the static-http:// protocol which is much slower but does not
34 fast and the static-http:// protocol which is much slower but does not
35 require a special server on the web host.
35 require a special server on the web host.
36
36
@@ -43,7 +43,7 b' SPECIFYING SINGLE REVISIONS'
43 Mercurial accepts several notations for identifying individual
43 Mercurial accepts several notations for identifying individual
44 revisions.
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 integers are treated as offsets from the tip, with -1 denoting the
47 integers are treated as offsets from the tip, with -1 denoting the
48 tip.
48 tip.
49
49
@@ -52,11 +52,11 b' SPECIFYING SINGLE REVISIONS'
52
52
53 A hexadecimal string less than 40 characters long is treated as a
53 A hexadecimal string less than 40 characters long is treated as a
54 unique revision identifier, and referred to as a short-form
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 prefix of one full-length identifier.
56 prefix of one full-length identifier.
57
57
58 Any other string is treated as a tag name, which is a symbolic
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 contain the ":" character.
60 contain the ":" character.
61
61
62 The reserved name "tip" is a special tag that always identifies
62 The reserved name "tip" is a special tag that always identifies
@@ -78,16 +78,16 b' SPECIFYING MULTIPLE REVISIONS'
78 separated by the ":" character.
78 separated by the ":" character.
79
79
80 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
80 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
81 are revision identifiers. Both BEGIN and END are optional. If
81 are revision identifiers. Both BEGIN and END are optional. If
82 BEGIN is not specified, it defaults to revision number 0. If END
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
83 is not specified, it defaults to the tip. The range ":" thus
84 means "all revisions".
84 means "all revisions".
85
85
86 If BEGIN is greater than END, revisions are treated in reverse
86 If BEGIN is greater than END, revisions are treated in reverse
87 order.
87 order.
88
88
89 A range acts as a closed interval. This means that a range of 3:5
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.
90 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
91
91
92 FILES
92 FILES
93 -----
93 -----
@@ -103,7 +103,7 b' FILES'
103 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
103 /etc/mercurial/hgrc, $HOME/.hgrc, .hg/hgrc::
104 This file contains defaults and configuration. Values in .hg/hgrc
104 This file contains defaults and configuration. Values in .hg/hgrc
105 override those in $HOME/.hgrc, and these override settings made in the
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 the contents and format of these files.
107 the contents and format of these files.
108
108
109 Some commands (e.g. revert) produce backup files ending in .orig, if
109 Some commands (e.g. revert) produce backup files ending in .orig, if
@@ -17,25 +17,25 b' DESCRIPTION'
17 -----------
17 -----------
18
18
19 Mercurial ignores every unmanaged file that matches any pattern in an
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
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
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"
22 it manages, see the hg(1) man page. Look for the "-I" and "-X"
23 options.
23 options.
24
24
25 In addition, a Mercurial configuration file can point to a set of
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
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
27 of how to configure these files. Look for the "ignore" entry in the
28 "ui" section.
28 "ui" section.
29
29
30 SYNTAX
30 SYNTAX
31 ------
31 ------
32
32
33 An ignore file is a plain text file consisting of a list of patterns,
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 character is treated as a comment character, and the "\" character is
35 character is treated as a comment character, and the "\" character is
36 treated as an escape character.
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 is Python/Perl-style regular expressions.
39 is Python/Perl-style regular expressions.
40
40
41 To change the syntax used, use a line of the following form:
41 To change the syntax used, use a line of the following form:
@@ -52,9 +52,9 b' glob::'
52 The chosen syntax stays in effect when parsing all patterns that
52 The chosen syntax stays in effect when parsing all patterns that
53 follow, until another syntax is selected.
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 the form "*.c" will match a file ending in ".c" in any directory, and
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 regexp pattern, start it with "^".
58 regexp pattern, start it with "^".
59
59
60 EXAMPLE
60 EXAMPLE
@@ -17,26 +17,26 b' FILES'
17
17
18 Mercurial reads configuration data from several files, if they exist.
18 Mercurial reads configuration data from several files, if they exist.
19 The names of these files depend on the system on which Mercurial is
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
20 installed. *.rc files from a single directory are read in
21 alphabetical order, later ones overriding earlier ones. Where
21 alphabetical order, later ones overriding earlier ones. Where
22 multiple paths are given below, settings from later paths override
22 multiple paths are given below, settings from later paths override
23 earlier ones.
23 earlier ones.
24
24
25 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
25 (Unix) <install-root>/etc/mercurial/hgrc.d/*.rc::
26 (Unix) <install-root>/etc/mercurial/hgrc::
26 (Unix) <install-root>/etc/mercurial/hgrc::
27 Per-installation configuration files, searched for in the
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 parent directory of the hg executable (or symlink) being run.
29 parent directory of the hg executable (or symlink) being run.
30 For example, if installed in /shared/tools/bin/hg, Mercurial will
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 apply to all Mercurial commands executed by any user in any
32 apply to all Mercurial commands executed by any user in any
33 directory.
33 directory.
34
34
35 (Unix) /etc/mercurial/hgrc.d/*.rc::
35 (Unix) /etc/mercurial/hgrc.d/*.rc::
36 (Unix) /etc/mercurial/hgrc::
36 (Unix) /etc/mercurial/hgrc::
37 Per-system configuration files, for the system on which Mercurial
37 Per-system configuration files, for the system on which Mercurial
38 is running. Options in these files apply to all Mercurial
38 is running. Options in these files apply to all Mercurial
39 commands executed by any user in any directory. Options in these
39 commands executed by any user in any directory. Options in these
40 files override per-installation options.
40 files override per-installation options.
41
41
42 (Windows) <install-dir>\Mercurial.ini::
42 (Windows) <install-dir>\Mercurial.ini::
@@ -45,7 +45,7 b' earlier ones.'
45 or else::
45 or else::
46 (Windows) C:\Mercurial\Mercurial.ini::
46 (Windows) C:\Mercurial\Mercurial.ini::
47 Per-installation/system configuration files, for the system on
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 Mercurial commands executed by any user in any directory.
49 Mercurial commands executed by any user in any directory.
50 Registry keys contain PATH-like strings, every part of which must
50 Registry keys contain PATH-like strings, every part of which must
51 reference a Mercurial.ini file or be a directory where *.rc files
51 reference a Mercurial.ini file or be a directory where *.rc files
@@ -59,16 +59,16 b' earlier ones.'
59 Per-user configuration file(s), for the user running Mercurial.
59 Per-user configuration file(s), for the user running Mercurial.
60 On Windows 9x, %HOME% is replaced by %APPDATA%.
60 On Windows 9x, %HOME% is replaced by %APPDATA%.
61 Options in these files apply to all Mercurial commands executed
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 per-installation and per-system options.
63 per-installation and per-system options.
64
64
65 (Unix, Windows) <repo>/.hg/hgrc::
65 (Unix, Windows) <repo>/.hg/hgrc::
66 Per-repository configuration options that only apply in a
66 Per-repository configuration options that only apply in a
67 particular repository. This file is not version-controlled, and
67 particular repository. This file is not version-controlled, and
68 will not get transferred during a "clone" operation. Options in
68 will not get transferred during a "clone" operation. Options in
69 this file override options in all other configuration files.
69 this file override options in all other configuration files.
70 On Unix, most of this file will be ignored if it doesn't belong
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 for the trusted section below for more details.
72 for the trusted section below for more details.
73
73
74 SYNTAX
74 SYNTAX
@@ -82,10 +82,10 b' and followed by "name: value" entries; "'
82 green=
82 green=
83 eggs
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 they are treated as continuations of that entry.
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 The optional values can contain format strings which refer to other
90 The optional values can contain format strings which refer to other
91 values in the same section, or values in a special DEFAULT section.
91 values in the same section, or values in a special DEFAULT section.
@@ -107,12 +107,12 b' decode/encode::'
107
107
108 Filters consist of a filter pattern followed by a filter command.
108 Filters consist of a filter pattern followed by a filter command.
109 Filter patterns are globs by default, rooted at the repository
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
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
111 directory only, use the pattern "*.txt". To match any file ending
112 in ".c" anywhere in the repository, use the pattern "**.c".
112 in ".c" anywhere in the repository, use the pattern "**.c".
113
113
114 The filter command can start with a specifier, either "pipe:" or
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 A "pipe:" command must accept data on stdin and return the
117 A "pipe:" command must accept data on stdin and return the
118 transformed data on stdout.
118 transformed data on stdout.
@@ -129,9 +129,9 b' decode/encode::'
129 # can safely omit "pipe:", because it's the default)
129 # can safely omit "pipe:", because it's the default)
130 *.gz = gzip
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 with the name of a temporary file that contains the data to be
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 name of an empty temporary file, where the filtered data must be
135 name of an empty temporary file, where the filtered data must be
136 written by the command.
136 written by the command.
137
137
@@ -192,22 +192,22 b' diff::'
192 email::
192 email::
193 Settings for extensions that send email messages.
193 Settings for extensions that send email messages.
194 from;;
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 of outgoing messages.
196 of outgoing messages.
197 to;;
197 to;;
198 Optional. Comma-separated list of recipients' email addresses.
198 Optional. Comma-separated list of recipients' email addresses.
199 cc;;
199 cc;;
200 Optional. Comma-separated list of carbon copy recipients'
200 Optional. Comma-separated list of carbon copy recipients'
201 email addresses.
201 email addresses.
202 bcc;;
202 bcc;;
203 Optional. Comma-separated list of blind carbon copy
203 Optional. Comma-separated list of blind carbon copy
204 recipients' email addresses. Cannot be set interactively.
204 recipients' email addresses. Cannot be set interactively.
205 method;;
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 "smtp" (default), use SMTP (see section "[smtp]" for
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 acts like sendmail (takes "-f" option for sender, list of
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 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
211 this to "sendmail" or "/usr/sbin/sendmail" is enough to use
212 sendmail to send messages.
212 sendmail to send messages.
213
213
@@ -281,6 +281,7 b' merge-tools::'
281 myHtmlTool.priority = 1
281 myHtmlTool.priority = 1
282
282
283 Supported arguments:
283 Supported arguments:
284
284 priority;;
285 priority;;
285 The priority in which to evaluate this tool.
286 The priority in which to evaluate this tool.
286 Default: 0.
287 Default: 0.
@@ -297,10 +298,10 b' merge-tools::'
297 launching external tool.
298 launching external tool.
298 Default: True
299 Default: True
299 binary;;
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 was selected by file pattern match.
302 was selected by file pattern match.
302 symlink;;
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 selected by file pattern match.
305 selected by file pattern match.
305 checkconflicts;;
306 checkconflicts;;
306 Check whether there are conflicts even though the tool reported
307 Check whether there are conflicts even though the tool reported
@@ -313,18 +314,18 b' merge-tools::'
313 fixeol;;
314 fixeol;;
314 Attempt to fix up EOL changes caused by the merge tool.
315 Attempt to fix up EOL changes caused by the merge tool.
315 Default: False
316 Default: False
316 gui:;
317 gui;;
317 This tool requires a graphical interface to run. Default: False
318 This tool requires a graphical interface to run. Default: False
318 regkey;;
319 regkey;;
319 Windows registry key which describes install location of this tool.
320 Windows registry key which describes install location of this tool.
320 Mercurial will search for this key first under HKEY_CURRENT_USER and
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 regname;;
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 unnamed (default) value.
325 unnamed (default) value.
325 regappend;;
326 regappend;;
326 String to append to the value read from the registry, typically the
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 hooks::
330 hooks::
330 Commands or Python functions that get automatically executed by
331 Commands or Python functions that get automatically executed by
@@ -342,24 +343,24 b' hooks::'
342 incoming.autobuild = /my/build/hook
343 incoming.autobuild = /my/build/hook
343
344
344 Most hooks are run with environment variables set that give added
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 it is passed are listed with names of the form "$HG_foo".
347 it is passed are listed with names of the form "$HG_foo".
347
348
348 changegroup;;
349 changegroup;;
349 Run after a changegroup has been added via push, pull or
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 which changes came is in $HG_URL.
352 which changes came is in $HG_URL.
352 commit;;
353 commit;;
353 Run after a changeset has been created in the local repository.
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 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
356 changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
356 incoming;;
357 incoming;;
357 Run after a changeset has been pulled, pushed, or unbundled into
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 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.
360 $HG_NODE. URL that was source of changes came is in $HG_URL.
360 outgoing;;
361 outgoing;;
361 Run after sending changes from local repository to another. ID of
362 Run after sending changes from local repository to another. ID of
362 first changeset sent is in $HG_NODE. Source of operation is in
363 first changeset sent is in $HG_NODE. Source of operation is in
363 $HG_SOURCE; see "preoutgoing" hook for description.
364 $HG_SOURCE; see "preoutgoing" hook for description.
364 post-<command>;;
365 post-<command>;;
365 Run after successful invocations of the associated command. The
366 Run after successful invocations of the associated command. The
@@ -371,56 +372,56 b' hooks::'
371 the command doesn't execute and Mercurial returns the failure code.
372 the command doesn't execute and Mercurial returns the failure code.
372 prechangegroup;;
373 prechangegroup;;
373 Run before a changegroup is added via push, pull or unbundle.
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 Exit status 0 allows the changegroup to proceed. Non-zero status
375 will cause the push, pull or unbundle to fail. URL from which
376 will cause the push, pull or unbundle to fail. URL from which
376 changes will come is in $HG_URL.
377 changes will come is in $HG_URL.
377 precommit;;
378 precommit;;
378 Run before starting a local commit. Exit status 0 allows the
379 Run before starting a local commit. Exit status 0 allows the
379 commit to proceed. Non-zero status will cause the commit to fail.
380 commit to proceed. Non-zero status will cause the commit to fail.
380 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
381 Parent changeset IDs are in $HG_PARENT1 and $HG_PARENT2.
381 preoutgoing;;
382 preoutgoing;;
382 Run before collecting changes to send from the local repository to
383 Run before collecting changes to send from the local repository to
383 another. Non-zero status will cause failure. This lets you
384 another. Non-zero status will cause failure. This lets you
384 prevent pull over http or ssh. Also prevents against local pull,
385 prevent pull over http or ssh. Also prevents against local pull,
385 push (outbound) or bundle commands, but not effective, since you
386 push (outbound) or bundle commands, but not effective, since you
386 can just copy files instead then. Source of operation is in
387 can just copy files instead then. Source of operation is in
387 $HG_SOURCE. If "serve", operation is happening on behalf of
388 $HG_SOURCE. If "serve", operation is happening on behalf of
388 remote ssh or http repository. If "push", "pull" or "bundle",
389 remote ssh or http repository. If "push", "pull" or "bundle",
389 operation is happening on behalf of repository on same system.
390 operation is happening on behalf of repository on same system.
390 pretag;;
391 pretag;;
391 Run before creating a tag. Exit status 0 allows the tag to be
392 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 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
394 changeset to tag is in $HG_NODE. Name of tag is in $HG_TAG. Tag
394 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
395 is local if $HG_LOCAL=1, in repo if $HG_LOCAL=0.
395 pretxnchangegroup;;
396 pretxnchangegroup;;
396 Run after a changegroup has been added via push, pull or unbundle,
397 Run after a changegroup has been added via push, pull or unbundle,
397 but before the transaction has been committed. Changegroup is
398 but before the transaction has been committed. Changegroup is
398 visible to hook program. This lets you validate incoming changes
399 visible to hook program. This lets you validate incoming changes
399 before accepting them. Passed the ID of the first new changeset
400 before accepting them. Passed the ID of the first new changeset
400 in $HG_NODE. Exit status 0 allows the transaction to commit.
401 in $HG_NODE. Exit status 0 allows the transaction to commit.
401 Non-zero status will cause the transaction to be rolled back and
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 changes is in $HG_URL.
404 changes is in $HG_URL.
404 pretxncommit;;
405 pretxncommit;;
405 Run after a changeset has been created but the transaction not yet
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 committed. Changeset is visible to hook program. This lets you
407 validate commit message and changes. Exit status 0 allows the
408 validate commit message and changes. Exit status 0 allows the
408 commit to proceed. Non-zero status will cause the transaction to
409 commit to proceed. Non-zero status will cause the transaction to
409 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
410 be rolled back. ID of changeset is in $HG_NODE. Parent changeset
410 IDs are in $HG_PARENT1 and $HG_PARENT2.
411 IDs are in $HG_PARENT1 and $HG_PARENT2.
411 preupdate;;
412 preupdate;;
412 Run before updating the working directory. Exit status 0 allows
413 Run before updating the working directory. Exit status 0 allows
413 the update to proceed. Non-zero status will prevent the update.
414 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
415 Changeset ID of first new parent is in $HG_PARENT1. If merge, ID
415 of second new parent is in $HG_PARENT2.
416 of second new parent is in $HG_PARENT2.
416 tag;;
417 tag;;
417 Run after a tag is created. ID of tagged changeset is in
418 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
419 $HG_NODE. Name of tag is in $HG_TAG. Tag is local if
419 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
420 $HG_LOCAL=1, in repo if $HG_LOCAL=0.
420 update;;
421 update;;
421 Run after updating the working directory. Changeset ID of first
422 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 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
424 is in $HG_PARENT2. If update succeeded, $HG_ERROR=0. If update
424 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
425 failed (e.g. because conflicts not resolved), $HG_ERROR=1.
425
426
426 Note: it is generally better to use standard hooks rather than the
427 Note: it is generally better to use standard hooks rather than the
@@ -438,10 +439,10 b' hooks::'
438
439
439 hookname = python:modulename.submodule.callable
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 called with at least three keyword arguments: a ui object (keyword
443 called with at least three keyword arguments: a ui object (keyword
443 "ui"), a repository object (keyword "repo"), and a "hooktype"
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 environment variables above are passed as keyword arguments, with no
446 environment variables above are passed as keyword arguments, with no
446 "HG_" prefix, and names in lower case.
447 "HG_" prefix, and names in lower case.
447
448
@@ -455,68 +456,68 b' http_proxy::'
455 Host name and (optional) port of the proxy server, for example
456 Host name and (optional) port of the proxy server, for example
456 "myproxy:8000".
457 "myproxy:8000".
457 no;;
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 the proxy.
460 the proxy.
460 passwd;;
461 passwd;;
461 Optional. Password to authenticate with at the proxy server.
462 Optional. Password to authenticate with at the proxy server.
462 user;;
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 smtp::
466 smtp::
466 Configuration for extensions that need to send email messages.
467 Configuration for extensions that need to send email messages.
467 host;;
468 host;;
468 Host name of mail server, e.g. "mail.example.com".
469 Host name of mail server, e.g. "mail.example.com".
469 port;;
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 tls;;
472 tls;;
472 Optional. Whether to connect to mail server using TLS. True or
473 Optional. Whether to connect to mail server using TLS. True or
473 False. Default: False.
474 False. Default: False.
474 username;;
475 username;;
475 Optional. User name to authenticate to SMTP server with.
476 Optional. User name to authenticate to SMTP server with.
476 If username is specified, password must also be specified.
477 If username is specified, password must also be specified.
477 Default: none.
478 Default: none.
478 password;;
479 password;;
479 Optional. Password to authenticate to SMTP server with.
480 Optional. Password to authenticate to SMTP server with.
480 If username is specified, password must also be specified.
481 If username is specified, password must also be specified.
481 Default: none.
482 Default: none.
482 local_hostname;;
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 to the MTA.
485 to the MTA.
485
486
486 paths::
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 symbolic name, and the right gives the directory or URL that is the
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 setting the following entries.
491 setting the following entries.
491 default;;
492 default;;
492 Directory or URL to use when pulling if no source is specified.
493 Directory or URL to use when pulling if no source is specified.
493 Default is set to repository from which the current repository
494 Default is set to repository from which the current repository
494 was cloned.
495 was cloned.
495 default-push;;
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 is specified.
498 is specified.
498
499
499 server::
500 server::
500 Controls generic server settings.
501 Controls generic server settings.
501 uncompressed;;
502 uncompressed;;
502 Whether to allow clients to clone a repo using the uncompressed
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 regular clone, but uses less memory and CPU on both server and
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 uncompressed streaming clone is a lot faster (~10x) than a regular
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 6Mbps), uncompressed streaming is slower, because of the extra
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 trusted::
512 trusted::
512 For security reasons, Mercurial will not use the settings in
513 For security reasons, Mercurial will not use the settings in
513 the .hg/hgrc file from a repository if it doesn't belong to a
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 web interface, which automatically uses some safe settings, since
516 web interface, which automatically uses some safe settings, since
516 it's common to serve repositories from different users.
517 it's common to serve repositories from different users.
517
518
518 This section specifies what users and groups are trusted. The
519 This section specifies what users and groups are trusted. The
519 current user is always trusted. To trust everybody, list a user
520 current user is always trusted. To trust everybody, list a user
520 or a group with name "*".
521 or a group with name "*".
521
522
522 users;;
523 users;;
@@ -532,12 +533,12 b' ui::'
532 the hg archive command or downloaded via hgweb.
533 the hg archive command or downloaded via hgweb.
533 Default is true.
534 Default is true.
534 debug;;
535 debug;;
535 Print debugging information. True or False. Default is False.
536 Print debugging information. True or False. Default is False.
536 editor;;
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 fallbackencoding;;
539 fallbackencoding;;
539 Encoding to try if it's not possible to decode the changelog using
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 ignore;;
542 ignore;;
542 A file to read per-user ignore patterns from. This file should be in
543 A file to read per-user ignore patterns from. This file should be in
543 the same format as a repository-wide .hgignore file. This option
544 the same format as a repository-wide .hgignore file. This option
@@ -546,7 +547,7 b' ui::'
546 "ignore.other = ~/.hgignore2". For details of the ignore file
547 "ignore.other = ~/.hgignore2". For details of the ignore file
547 format, see the hgignore(5) man page.
548 format, see the hgignore(5) man page.
548 interactive;;
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 logtemplate;;
551 logtemplate;;
551 Template string for commands that print changesets.
552 Template string for commands that print changesets.
552 merge;;
553 merge;;
@@ -563,18 +564,19 b' ui::'
563 fail to merge
564 fail to merge
564
565
565 See the merge-tools section for more information on configuring tools.
566 See the merge-tools section for more information on configuring tools.
567
566 patch;;
568 patch;;
567 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
569 command to use to apply patches. Look for 'gpatch' or 'patch' in PATH if
568 unset.
570 unset.
569 quiet;;
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 remotecmd;;
573 remotecmd;;
572 remote command to use for clone/push/pull operations. Default is 'hg'.
574 remote command to use for clone/push/pull operations. Default is 'hg'.
573 report_untrusted;;
575 report_untrusted;;
574 Warn if a .hg/hgrc file is ignored due to not being owned by a
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 slash;;
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 makes a difference on systems where the default path separator is not
580 makes a difference on systems where the default path separator is not
579 the slash character (e.g. Windows uses the backslash character ("\")).
581 the slash character (e.g. Windows uses the backslash character ("\")).
580 Default is False.
582 Default is False.
@@ -582,7 +584,7 b' ui::'
582 command to use for SSH connections. Default is 'ssh'.
584 command to use for SSH connections. Default is 'ssh'.
583 strict;;
585 strict;;
584 Require exact command names, instead of allowing unambiguous
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 style;;
588 style;;
587 Name of style to use for command output.
589 Name of style to use for command output.
588 timeout;;
590 timeout;;
@@ -591,12 +593,12 b' ui::'
591 username;;
593 username;;
592 The committer of a changeset created when running "commit".
594 The committer of a changeset created when running "commit".
593 Typically a person's name and email address, e.g. "Fred Widget
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 If the username in hgrc is empty, it has to be specified manually or
597 If the username in hgrc is empty, it has to be specified manually or
596 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
598 in a different hgrc file (e.g. $HOME/.hgrc, if the admin set "username ="
597 in the system hgrc).
599 in the system hgrc).
598 verbose;;
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 web::
604 web::
@@ -617,9 +619,9 b' web::'
617 allowpull;;
619 allowpull;;
618 Whether to allow pulling from the repository. Default is true.
620 Whether to allow pulling from the repository. Default is true.
619 allow_push;;
621 allow_push;;
620 Whether to allow pushing to the repository. If empty or not set,
622 Whether to allow pushing to the repository. If empty or not set,
621 push is not allowed. If the special value "*", any remote user
623 push is not allowed. If the special value "*", any remote user
622 can push, including unauthenticated users. Otherwise, the remote
624 can push, including unauthenticated users. Otherwise, the remote
623 user must have been authenticated, and the authenticated user name
625 user must have been authenticated, and the authenticated user name
624 must be present in this list (separated by whitespace or ",").
626 must be present in this list (separated by whitespace or ",").
625 The contents of the allow_push list are examined after the
627 The contents of the allow_push list are examined after the
@@ -635,11 +637,11 b' web::'
635 Name or email address of the person in charge of the repository.
637 Name or email address of the person in charge of the repository.
636 Defaults to ui.username or $EMAIL or "unknown" if unset or empty.
638 Defaults to ui.username or $EMAIL or "unknown" if unset or empty.
637 deny_push;;
639 deny_push;;
638 Whether to deny pushing to the repository. If empty or not set,
640 Whether to deny pushing to the repository. If empty or not set,
639 push is not denied. If the special value "*", all remote users
641 push is not denied. If the special value "*", all remote users
640 are denied push. Otherwise, unauthenticated users are all denied,
642 are denied push. Otherwise, unauthenticated users are all denied,
641 and any authenticated user name present in this list (separated by
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 list are examined before the allow_push list.
645 list are examined before the allow_push list.
644 description;;
646 description;;
645 Textual description of the repository's purpose or contents.
647 Textual description of the repository's purpose or contents.
@@ -666,7 +668,7 b' web::'
666 Prefix path to serve from. Default is '' (server root).
668 Prefix path to serve from. Default is '' (server root).
667 push_ssl;;
669 push_ssl;;
668 Whether to require that inbound pushes be transported over SSL to
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 staticurl;;
672 staticurl;;
671 Base URL to use for static files. If unset, static files (e.g.
673 Base URL to use for static files. If unset, static files (e.g.
672 the hgicon.png favicon) will be served by the CGI script itself.
674 the hgicon.png favicon) will be served by the CGI script itself.
@@ -387,7 +387,7 b' class svn_source(converter_source):'
387 try:
387 try:
388 for entry in get_log(self.url, [self.tags], start, self.startrev):
388 for entry in get_log(self.url, [self.tags], start, self.startrev):
389 origpaths, revnum, author, date, message = entry
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 in origpaths.iteritems() if e.copyfrom_path]
391 in origpaths.iteritems() if e.copyfrom_path]
392 copies.sort()
392 copies.sort()
393 # Apply moves/copies from more specific to general
393 # Apply moves/copies from more specific to general
@@ -20,18 +20,13 b' file should be re-generated by running'
20
20
21 # pygmentize -f html -S <newstyle>
21 # pygmentize -f html -S <newstyle>
22
22
23
24 -- Adam Hupp <adam@hupp.org>
23 -- Adam Hupp <adam@hupp.org>
25
26
27 """
24 """
28
25
29 from mercurial import demandimport
26 from mercurial import demandimport
30 demandimport.ignore.extend(['pkgutil',
27 demandimport.ignore.extend(['pkgutil', 'pkg_resources', '__main__',])
31 'pkg_resources',
32 '__main__',])
33
28
34 from mercurial.hgweb.hgweb_mod import hgweb
29 from mercurial.hgweb import webcommands, webutil
35 from mercurial import util
30 from mercurial import util
36 from mercurial.templatefilters import filters
31 from mercurial.templatefilters import filters
37
32
@@ -43,7 +38,8 b' from pygments.formatters import HtmlForm'
43 SYNTAX_CSS = ('\n<link rel="stylesheet" href="#staticurl#highlight.css" '
38 SYNTAX_CSS = ('\n<link rel="stylesheet" href="#staticurl#highlight.css" '
44 'type="text/css" />')
39 'type="text/css" />')
45
40
46 def pygmentize(self, tmpl, fctx, field):
41 def pygmentize(field, fctx, style, tmpl):
42
47 # append a <link ...> to the syntax highlighting css
43 # append a <link ...> to the syntax highlighting css
48 old_header = ''.join(tmpl('header'))
44 old_header = ''.join(tmpl('header'))
49 if SYNTAX_CSS not in old_header:
45 if SYNTAX_CSS not in old_header:
@@ -54,7 +50,6 b' def pygmentize(self, tmpl, fctx, field):'
54 if util.binary(text):
50 if util.binary(text):
55 return
51 return
56
52
57 style = self.config("web", "pygments_style", "colorful")
58 # To get multi-line strings right, we can't format line-by-line
53 # To get multi-line strings right, we can't format line-by-line
59 try:
54 try:
60 lexer = guess_lexer_for_filename(fctx.path(), text,
55 lexer = guess_lexer_for_filename(fctx.path(), text,
@@ -79,20 +74,21 b' def pygmentize(self, tmpl, fctx, field):'
79 newl = oldl.replace('line|escape', 'line|colorize')
74 newl = oldl.replace('line|escape', 'line|colorize')
80 tmpl.cache[field] = newl
75 tmpl.cache[field] = newl
81
76
82 def filerevision_highlight(self, tmpl, fctx):
77 web_filerevision = webcommands._filerevision
83 pygmentize(self, tmpl, fctx, 'fileline')
78 web_annotate = webcommands.annotate
84
85 return realrevision(self, tmpl, fctx)
86
79
87 def fileannotate_highlight(self, tmpl, fctx):
80 def filerevision_highlight(web, tmpl, fctx):
88 pygmentize(self, tmpl, fctx, 'annotateline')
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 # monkeypatch in the new version
91 # monkeypatch in the new version
93 # should be safer than overriding the method in a derived class
92
94 # and then patching the class
93 webcommands._filerevision = filerevision_highlight
95 realrevision = hgweb.filerevision
94 webcommands.annotate = annotate_highlight
96 hgweb.filerevision = filerevision_highlight
97 realannotate = hgweb.fileannotate
98 hgweb.fileannotate = fileannotate_highlight
@@ -108,6 +108,8 b" kwtools = {'templater': None, 'hgcmd': N"
108 _patchfile_init = patch.patchfile.__init__
108 _patchfile_init = patch.patchfile.__init__
109 _patch_diff = patch.diff
109 _patch_diff = patch.diff
110 _dispatch_parse = dispatch._parse
110 _dispatch_parse = dispatch._parse
111 _webcommands_changeset = webcommands.changeset
112 _webcommands_filediff = webcommands.filediff
111
113
112 def _kwpatchfile_init(self, ui, fname, missing=False):
114 def _kwpatchfile_init(self, ui, fname, missing=False):
113 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
115 '''Monkeypatch/wrap patch.patchfile.__init__ to avoid
@@ -131,12 +133,12 b' def _kw_diff(repo, node1=None, node2=Non'
131 def _kwweb_changeset(web, req, tmpl):
133 def _kwweb_changeset(web, req, tmpl):
132 '''Wraps webcommands.changeset turning off keyword expansion.'''
134 '''Wraps webcommands.changeset turning off keyword expansion.'''
133 kwtools['templater'].matcher = util.never
135 kwtools['templater'].matcher = util.never
134 return web.changeset(tmpl, web.changectx(req))
136 return _webcommands_changeset(web, req, tmpl)
135
137
136 def _kwweb_filediff(web, req, tmpl):
138 def _kwweb_filediff(web, req, tmpl):
137 '''Wraps webcommands.filediff turning off keyword expansion.'''
139 '''Wraps webcommands.filediff turning off keyword expansion.'''
138 kwtools['templater'].matcher = util.never
140 kwtools['templater'].matcher = util.never
139 return web.filediff(tmpl, web.filectx(req))
141 return _webcommands_filediff(web, req, tmpl)
140
142
141 def _kwdispatch_parse(ui, args):
143 def _kwdispatch_parse(ui, args):
142 '''Monkeypatch dispatch._parse to obtain running hg command.'''
144 '''Monkeypatch dispatch._parse to obtain running hg command.'''
@@ -145,6 +147,7 b' def _kwdispatch_parse(ui, args):'
145 return cmd, func, args, options, cmdoptions
147 return cmd, func, args, options, cmdoptions
146
148
147 # dispatch._parse is run before reposetup, so wrap it here
149 # dispatch._parse is run before reposetup, so wrap it here
150 # all other actual monkey patching is done at end of reposetup
148 dispatch._parse = _kwdispatch_parse
151 dispatch._parse = _kwdispatch_parse
149
152
150
153
@@ -24,12 +24,37 b''
24 #
24 #
25 # [pager]
25 # [pager]
26 # quiet = True
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 import sys, os, signal
44 import sys, os, signal
45 from mercurial import dispatch
29
46
30 def uisetup(ui):
47 def uisetup(ui):
31 p = ui.config("pager", "pager", os.environ.get("PAGER"))
48 def pagecmd(ui, options, cmd, cmdfunc):
32 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
49 p = ui.config("pager", "pager", os.environ.get("PAGER"))
33 if ui.configbool('pager', 'quiet'):
50 if p and sys.stdout.isatty() and '--debugger' not in sys.argv:
34 signal.signal(signal.SIGPIPE, signal.SIG_DFL)
51 attend = ui.configlist('pager', 'attend')
35 sys.stderr = sys.stdout = os.popen(p, "wb")
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 import os, errno, socket, tempfile
67 import os, errno, socket, tempfile
68 import email.MIMEMultipart, email.MIMEText, email.MIMEBase
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 from mercurial import cmdutil, commands, hg, mail, patch, util
71 from mercurial import cmdutil, commands, hg, mail, patch, util
71 from mercurial.i18n import _
72 from mercurial.i18n import _
72 from mercurial.node import bin
73 from mercurial.node import bin
@@ -407,8 +408,9 b' def patchbomb(ui, repo, *revs, **opts):'
407 fp = os.popen(os.environ['PAGER'], 'w')
408 fp = os.popen(os.environ['PAGER'], 'w')
408 else:
409 else:
409 fp = ui
410 fp = ui
411 generator = email.Generator.Generator(fp, mangle_from_=False)
410 try:
412 try:
411 fp.write(m.as_string(0))
413 generator.flatten(m, 0)
412 fp.write('\n')
414 fp.write('\n')
413 except IOError, inst:
415 except IOError, inst:
414 if inst.errno != errno.EPIPE:
416 if inst.errno != errno.EPIPE:
@@ -418,9 +420,10 b' def patchbomb(ui, repo, *revs, **opts):'
418 elif opts.get('mbox'):
420 elif opts.get('mbox'):
419 ui.status('Writing ', m['Subject'], ' ...\n')
421 ui.status('Writing ', m['Subject'], ' ...\n')
420 fp = open(opts.get('mbox'), 'In-Reply-To' in m and 'ab+' or 'wb+')
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 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y')
424 date = util.datestr(start_time, '%a %b %d %H:%M:%S %Y')
422 fp.write('From %s %s\n' % (sender_addr, date))
425 fp.write('From %s %s\n' % (sender_addr, date))
423 fp.write(m.as_string(0))
426 generator.flatten(m, 0)
424 fp.write('\n\n')
427 fp.write('\n\n')
425 fp.close()
428 fp.close()
426 else:
429 else:
@@ -429,7 +432,10 b' def patchbomb(ui, repo, *revs, **opts):'
429 ui.status('Sending ', m['Subject'], ' ...\n')
432 ui.status('Sending ', m['Subject'], ' ...\n')
430 # Exim does not remove the Bcc field
433 # Exim does not remove the Bcc field
431 del m['Bcc']
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 cmdtable = {
440 cmdtable = {
435 "email":
441 "email":
@@ -53,11 +53,11 b' def addremove(ui, repo, *pats, **opts):'
53 New files are ignored if they match any of the patterns in .hgignore. As
53 New files are ignored if they match any of the patterns in .hgignore. As
54 with add, these changes take effect at the next commit.
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 this compares every removed file with every added file and records
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 between 0 (disabled) and 100 (files must be identical) as its
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 try:
62 try:
63 sim = float(opts.get('similarity') or 0)
63 sim = float(opts.get('similarity') or 0)
@@ -134,7 +134,7 b' def archive(ui, repo, dest, **opts):'
134 By default, the revision used is the parent of the working
134 By default, the revision used is the parent of the working
135 directory; use "-r" to specify a different revision.
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 types are:
138 types are:
139
139
140 "files" (default): a directory full of files
140 "files" (default): a directory full of files
@@ -148,7 +148,7 b' def archive(ui, repo, dest, **opts):'
148 using a format string; see "hg help export" for details.
148 using a format string; see "hg help export" for details.
149
149
150 Each member added to an archive file has a directory prefix
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 The default is the basename of the archive, with suffixes removed.
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 def backout(ui, repo, node=None, rev=None, **opts):
174 def backout(ui, repo, node=None, rev=None, **opts):
175 '''reverse effect of earlier changeset
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 changeset is a child of the backed out changeset.
178 changeset is a child of the backed out changeset.
179
179
180 If you back out a changeset other than the tip, a new head is
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 backout changeset with another head (current one by default).
182 backout changeset with another head (current one by default).
183
183
184 The --merge option remembers the parent of the working directory
184 The --merge option remembers the parent of the working directory
185 before starting the backout, then merges the new head with that
185 before starting the backout, then merges the new head with that
186 changeset afterwards. This saves you from doing the merge by
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
187 hand. The result of this merge is not committed, as for a normal
188 merge.
188 merge.
189
189
190 See 'hg help dates' for a list of formats valid for -d/--date.
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 """list repository named branches
369 """list repository named branches
370
370
371 List the repository's named branches, indicating which ones are
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 A branch is considered active if it contains unmerged heads.
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 If no destination repository is specified the destination is
405 If no destination repository is specified the destination is
406 assumed to have all the nodes specified by one or more --base
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 --all (or --base null).
408 --all (or --base null).
409
409
410 The bundle file can then be transferred using conventional means and
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 or tip if no revision is checked out.
469 or tip if no revision is checked out.
470
470
471 Output may be to a file, in which case the name of the file is
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 for the export command, with the following additions:
473 for the export command, with the following additions:
474
474
475 %s basename of file being printed
475 %s basename of file being printed
@@ -501,9 +501,9 b' def clone(ui, source, dest=None, **opts)'
501
501
502 For efficiency, hardlinks are used for cloning whenever the source
502 For efficiency, hardlinks are used for cloning whenever the source
503 and destination are on the same filesystem (note this applies only
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 filesystems, such as AFS, implement hardlinking incorrectly, but
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 avoid hardlinking.
507 avoid hardlinking.
508
508
509 You can safely clone repositories and checked out files using full
509 You can safely clone repositories and checked out files using full
@@ -571,12 +571,12 b' def commit(ui, repo, *pats, **opts):'
571 def copy(ui, repo, *pats, **opts):
571 def copy(ui, repo, *pats, **opts):
572 """mark files as copied for the next commit
572 """mark files as copied for the next commit
573
573
574 Mark dest as having copies of source files. If dest is a
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,
575 directory, copies are put in that directory. If dest is a file,
576 there can only be one source.
576 there can only be one source.
577
577
578 By default, this command copies the contents of files as they
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 operation is recorded, but no copying is performed.
580 operation is recorded, but no copying is performed.
581
581
582 This command takes effect in the next commit. To undo a copy
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 as it will compare the merge changeset against its first parent only.
963 as it will compare the merge changeset against its first parent only.
964
964
965 Output may be to a file, in which case the name of the file is
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 %% literal "%" character
968 %% literal "%" character
969 %H changeset hash (40 bytes of hexadecimal)
969 %H changeset hash (40 bytes of hexadecimal)
@@ -997,13 +997,13 b' def grep(ui, repo, pattern, *pats, **opt'
997
997
998 Search revisions of files for a regular expression.
998 Search revisions of files for a regular expression.
999
999
1000 This command behaves differently than Unix grep. It only accepts
1000 This command behaves differently than Unix grep. It only accepts
1001 Python/Perl regexps. It searches repository history, not the
1001 Python/Perl regexps. It searches repository history, not the
1002 working directory. It always prints the revision number in which
1002 working directory. It always prints the revision number in which
1003 a match appears.
1003 a match appears.
1004
1004
1005 By default, grep only prints output for the first revision of a
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 that contains a change in match status ("-" for a match that
1007 that contains a change in match status ("-" for a match that
1008 becomes a non-match, or "+" for a non-match that becomes a match),
1008 becomes a non-match, or "+" for a non-match that becomes a match),
1009 use the --all flag.
1009 use the --all flag.
@@ -1173,7 +1173,7 b' def heads(ui, repo, *branchrevs, **opts)'
1173 are the usual targets for update and merge operations.
1173 are the usual targets for update and merge operations.
1174
1174
1175 Branch heads are changesets that have a given branch tag, but have
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 development on the given branch takes place.
1177 development on the given branch takes place.
1178 """
1178 """
1179 if opts['rev']:
1179 if opts['rev']:
@@ -1466,15 +1466,15 b' def import_(ui, repo, patch1, *patches, '
1466 If there are outstanding changes in the working directory, import
1466 If there are outstanding changes in the working directory, import
1467 will abort unless given the -f flag.
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 as attachments work (body part must be type text/plain or
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
1471 text/x-patch to be used). From and Subject headers of email
1472 message are used as default committer and commit message. All
1472 message are used as default committer and commit message. All
1473 text/plain body parts before first diff are added to commit
1473 text/plain body parts before first diff are added to commit
1474 message.
1474 message.
1475
1475
1476 If the imported patch was generated by hg export, user and description
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 given on command line with -m and -u override these.
1478 given on command line with -m and -u override these.
1479
1479
1480 If --exact is specified, import will set the working directory
1480 If --exact is specified, import will set the working directory
@@ -1643,7 +1643,7 b' def incoming(ui, repo, source="default",'
1643 def init(ui, dest=".", **opts):
1643 def init(ui, dest=".", **opts):
1644 """create a new repository in the given directory
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 directory does not exist, it is created.
1647 directory does not exist, it is created.
1648
1648
1649 If no directory is given, the current directory is used.
1649 If no directory is given, the current directory is used.
@@ -1661,7 +1661,7 b' def locate(ui, repo, *pats, **opts):'
1661 Print all files under Mercurial control whose names match the
1661 Print all files under Mercurial control whose names match the
1662 given patterns.
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 just the current directory and its subdirectories, use
1665 just the current directory and its subdirectories, use
1666 "--include .".
1666 "--include .".
1667
1667
@@ -1703,7 +1703,7 b' def log(ui, repo, *pats, **opts):'
1703 project.
1703 project.
1704
1704
1705 File history is shown without following rename or copy history of
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 renames and copies. --follow without a file name will only show
1707 renames and copies. --follow without a file name will only show
1708 ancestors or descendants of the starting revision. --follow-first
1708 ancestors or descendants of the starting revision. --follow-first
1709 only follows the first parent of merge revisions.
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 If no revision is specified, the working directory's parent is a
1863 If no revision is specified, the working directory's parent is a
1864 head revision, and the repository contains exactly one other head,
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 revision to merge with must be provided.
1866 revision to merge with must be provided.
1867 """
1867 """
1868
1868
@@ -1973,7 +1973,7 b' def paths(ui, repo, search=None):'
1973 definition of available names.
1973 definition of available names.
1974
1974
1975 Path names are defined in the [paths] section of /etc/mercurial/hgrc
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 if search:
1978 if search:
1979 for name, path in ui.configitems("paths"):
1979 for name, path in ui.configitems("paths"):
@@ -2214,12 +2214,12 b' def remove(ui, repo, *pats, **opts):'
2214 def rename(ui, repo, *pats, **opts):
2214 def rename(ui, repo, *pats, **opts):
2215 """rename files; equivalent of copy + remove
2215 """rename files; equivalent of copy + remove
2216
2216
2217 Mark dest as copies of sources; mark sources for deletion. If
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
2218 dest is a directory, copies are put in that directory. If dest is
2219 a file, there can only be one source.
2219 a file, there can only be one source.
2220
2220
2221 By default, this command copies the contents of files as they
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 operation is recorded, but no copying is performed.
2223 operation is recorded, but no copying is performed.
2224
2224
2225 This command takes effect in the next commit. To undo a rename
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 back" some or all of an earlier change.
2249 back" some or all of an earlier change.
2250 See 'hg help dates' for a list of formats valid for -d/--date.
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
2252 Revert modifies the working directory. It does not commit any
2253 changes, or change the parent of the working directory. If you
2253 changes, or change the parent of the working directory. If you
2254 revert to a revision other than the parent of the working
2254 revert to a revision other than the parent of the working
2255 directory, the reverted files will thus appear modified
2255 directory, the reverted files will thus appear modified
2256 afterwards.
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 mode of a file was changed, it is reset.
2259 mode of a file was changed, it is reset.
2260
2260
2261 If names are given, all files matching the names are reverted.
2261 If names are given, all files matching the names are reverted.
@@ -2491,7 +2491,7 b' def serve(ui, repo, **opts):'
2491 Start a local HTTP repository browser and pull server.
2491 Start a local HTTP repository browser and pull server.
2492
2492
2493 By default, the server logs accesses to stdout and errors to
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 if opts["stdio"]:
2497 if opts["stdio"]:
@@ -2530,8 +2530,17 b' def serve(ui, repo, **opts):'
2530 if port == ':80':
2530 if port == ':80':
2531 port = ''
2531 port = ''
2532
2532
2533 ui.status(_('listening at http://%s%s/%s (%s:%d)\n') %
2533 bindaddr = self.httpd.addr
2534 (self.httpd.fqaddr, port, prefix, self.httpd.addr, self.httpd.port))
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 def run(self):
2545 def run(self):
2537 self.httpd.serve_forever()
2546 self.httpd.serve_forever()
@@ -2543,10 +2552,10 b' def serve(ui, repo, **opts):'
2543 def status(ui, repo, *pats, **opts):
2552 def status(ui, repo, *pats, **opts):
2544 """show changed files in the working directory
2553 """show changed files in the working directory
2545
2554
2546 Show status of files in the repository. If names are given, only
2555 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
2556 files that match are shown. Files that are clean or ignored or
2548 source of a copy/move operation, are not listed unless -c (clean),
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 with "show only ..." are given, the options -mardu are used.
2559 with "show only ..." are given, the options -mardu are used.
2551
2560
2552 Option -q/--quiet hides untracked (unknown and ignored) files
2561 Option -q/--quiet hides untracked (unknown and ignored) files
@@ -2646,7 +2655,7 b' def tag(ui, repo, name1, *names, **opts)'
2646 To facilitate version control, distribution, and merging of tags,
2655 To facilitate version control, distribution, and merging of tags,
2647 they are stored as a file named ".hgtags" which is managed
2656 they are stored as a file named ".hgtags" which is managed
2648 similarly to other project files and can be hand-edited if
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 shared among repositories).
2659 shared among repositories).
2651
2660
2652 See 'hg help dates' for a list of formats valid for -d/--date.
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 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os, mimetypes, re, mimetools, cStringIO
9 import os, mimetypes
10 from mercurial.node import hex, nullid, short
10 from mercurial.node import hex, nullid
11 from mercurial.repo import RepoError
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 from mercurial import revlog, templater, templatefilters, changegroup
13 from mercurial import revlog, templater, templatefilters, changegroup
14 from common import get_mtime, style_map, paritygen, countgen, get_contact
14 from common import get_mtime, style_map, paritygen, countgen, ErrorResponse
15 from common import ErrorResponse
16 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
15 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
17 from request import wsgirequest
16 from request import wsgirequest
18 import webcommands, protocol
17 import webcommands, protocol, webutil
19
18
20 shortcuts = {
19 shortcuts = {
21 'cl': [('cmd', ['changelog']), ('rev', None)],
20 'cl': [('cmd', ['changelog']), ('rev', None)],
@@ -32,54 +31,6 b' shortcuts = {'
32 'static': [('cmd', ['static']), ('file', None)]
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 class hgweb(object):
34 class hgweb(object):
84 def __init__(self, repo, name=None):
35 def __init__(self, repo, name=None):
85 if isinstance(repo, str):
36 if isinstance(repo, str):
@@ -226,17 +177,8 b' class hgweb(object):'
226 try:
177 try:
227
178
228 tmpl = self.templater(req)
179 tmpl = self.templater(req)
229 try:
180 ctype = tmpl('mimetype', encoding=self.encoding)
230 ctype = tmpl('mimetype', encoding=self.encoding)
181 ctype = templater.stringify(ctype)
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']
240
182
241 if cmd == '':
183 if cmd == '':
242 req.form['cmd'] = [tmpl.cache['default']]
184 req.form['cmd'] = [tmpl.cache['default']]
@@ -291,13 +233,7 b' class hgweb(object):'
291 # some functions for the templater
233 # some functions for the templater
292
234
293 def header(**map):
235 def header(**map):
294 header = tmpl('header', encoding=self.encoding, **map)
236 yield 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
301
237
302 def footer(**map):
238 def footer(**map):
303 yield tmpl("footer", **map)
239 yield tmpl("footer", **map)
@@ -355,54 +291,6 b' class hgweb(object):'
355 if len(files) > self.maxfiles:
291 if len(files) > self.maxfiles:
356 yield tmpl("fileellipses")
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 def diff(self, tmpl, node1, node2, files):
294 def diff(self, tmpl, node1, node2, files):
407 def filterfiles(filters, files):
295 def filterfiles(filters, files):
408 l = [x for x in files if x in filters]
296 l = [x for x in files if x in filters]
@@ -470,514 +358,12 b' class hgweb(object):'
470 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
358 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
471 opts=diffopts), f, tn)
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 archive_specs = {
361 archive_specs = {
918 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
362 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
919 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
363 'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
920 'zip': ('application/zip', 'zip', '.zip', None),
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 def check_perm(self, req, op, default):
367 def check_perm(self, req, op, default):
982 '''check permission for operation based on user auth.
368 '''check permission for operation based on user auth.
983 return true if op allowed, else false.
369 return true if op allowed, else false.
@@ -6,7 +6,7 b''
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 import os, mimetools, cStringIO
9 import os
10 from mercurial.i18n import gettext as _
10 from mercurial.i18n import gettext as _
11 from mercurial.repo import RepoError
11 from mercurial.repo import RepoError
12 from mercurial import ui, hg, util, templater, templatefilters
12 from mercurial import ui, hg, util, templater, templatefilters
@@ -81,17 +81,8 b' class hgwebdir(object):'
81
81
82 virtual = req.env.get("PATH_INFO", "").strip('/')
82 virtual = req.env.get("PATH_INFO", "").strip('/')
83 tmpl = self.templater(req)
83 tmpl = self.templater(req)
84 try:
84 ctype = tmpl('mimetype', encoding=util._encoding)
85 ctype = tmpl('mimetype', encoding=util._encoding)
85 ctype = templater.stringify(ctype)
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']
95
86
96 # a static file
87 # a static file
97 if virtual.startswith('static/') or 'static' in req.form:
88 if virtual.startswith('static/') or 'static' in req.form:
@@ -255,13 +246,7 b' class hgwebdir(object):'
255 def templater(self, req):
246 def templater(self, req):
256
247
257 def header(**map):
248 def header(**map):
258 header = tmpl('header', encoding=util._encoding, **map)
249 yield 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
265
250
266 def footer(**map):
251 def footer(**map):
267 yield tmpl("footer", **map)
252 yield tmpl("footer", **map)
@@ -268,12 +268,7 b' def create_server(ui, repo):'
268
268
269 self.addr, self.port = self.socket.getsockname()[0:2]
269 self.addr, self.port = self.socket.getsockname()[0:2]
270 self.prefix = prefix
270 self.prefix = prefix
271
272 self.fqaddr = socket.getfqdn(address)
271 self.fqaddr = socket.getfqdn(address)
273 try:
274 socket.getaddrbyhost(self.fqaddr)
275 except:
276 fqaddr = address
277
272
278 class IPv6HTTPServer(MercurialHTTPServer):
273 class IPv6HTTPServer(MercurialHTTPServer):
279 address_family = getattr(socket, 'AF_INET6', None)
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 # This software may be used and distributed according to the terms
5 # This software may be used and distributed according to the terms
6 # of the GNU General Public License, incorporated herein by reference.
6 # of the GNU General Public License, incorporated herein by reference.
7
7
8 import os, mimetypes
8 import os, mimetypes, re
9 from mercurial import revlog, util
9 import webutil
10 from mercurial import revlog, archival
11 from mercurial.node import short, hex, nullid
12 from mercurial.util import binary
10 from mercurial.repo import RepoError
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 # __all__ is populated with the allowed commands. Be sure to add to it if
17 # __all__ is populated with the allowed commands. Be sure to add to it if
14 # you're adding a new command, or the new command won't work.
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 return changelog(web, req, tmpl)
30 return changelog(web, req, tmpl)
27
31
28 def rawfile(web, req, tmpl):
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 if not path:
34 if not path:
31 content = web.manifest(tmpl, web.changectx(req), path)
35 content = manifest(web, req, tmpl)
32 req.respond(HTTP_OK, web.ctype)
36 req.respond(HTTP_OK, web.ctype)
33 return content
37 return content
34
38
35 try:
39 try:
36 fctx = web.filectx(req)
40 fctx = webutil.filectx(web.repo, req)
37 except revlog.LookupError, inst:
41 except revlog.LookupError, inst:
38 try:
42 try:
39 content = web.manifest(tmpl, web.changectx(req), path)
43 content = manifest(web, req, tmpl)
40 req.respond(HTTP_OK, web.ctype)
44 req.respond(HTTP_OK, web.ctype)
41 return content
45 return content
42 except ErrorResponse:
46 except ErrorResponse:
@@ -45,28 +49,120 b' def rawfile(web, req, tmpl):'
45 path = fctx.path()
49 path = fctx.path()
46 text = fctx.data()
50 text = fctx.data()
47 mt = mimetypes.guess_type(path)[0]
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 mt = mt or 'application/octet-stream'
53 mt = mt or 'application/octet-stream'
50
54
51 req.respond(HTTP_OK, mt, path, len(text))
55 req.respond(HTTP_OK, mt, path, len(text))
52 return [text]
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 def file(web, req, tmpl):
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 if path:
93 if path:
57 try:
94 try:
58 return web.filerevision(tmpl, web.filectx(req))
95 return _filerevision(web, tmpl, webutil.filectx(web.repo, req))
59 except revlog.LookupError, inst:
96 except revlog.LookupError, inst:
60 pass
97 pass
61
98
62 try:
99 try:
63 return web.manifest(tmpl, web.changectx(req), path)
100 return manifest(web, req, tmpl)
64 except ErrorResponse:
101 except ErrorResponse:
65 raise inst
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 def changelog(web, req, tmpl, shortlog = False):
163 def changelog(web, req, tmpl, shortlog = False):
68 if 'node' in req.form:
164 if 'node' in req.form:
69 ctx = web.changectx(req)
165 ctx = webutil.changectx(web.repo, req)
70 else:
166 else:
71 if 'rev' in req.form:
167 if 'rev' in req.form:
72 hi = req.form['rev'][0]
168 hi = req.form['rev'][0]
@@ -75,47 +171,400 b' def changelog(web, req, tmpl, shortlog ='
75 try:
171 try:
76 ctx = web.repo.changectx(hi)
172 ctx = web.repo.changectx(hi)
77 except RepoError:
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 def shortlog(web, req, tmpl):
224 def shortlog(web, req, tmpl):
83 return changelog(web, req, tmpl, shortlog = True)
225 return changelog(web, req, tmpl, shortlog = True)
84
226
85 def changeset(web, req, tmpl):
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 rev = changeset
259 rev = changeset
89
260
90 def manifest(web, req, tmpl):
261 def manifest(web, req, tmpl):
91 return web.manifest(tmpl, web.changectx(req),
262 ctx = webutil.changectx(web.repo, req)
92 web.cleanpath(req.form['path'][0]))
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 def tags(web, req, tmpl):
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 def summary(web, req, tmpl):
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 def filediff(web, req, tmpl):
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 diff = filediff
447 diff = filediff
104
448
105 def annotate(web, req, tmpl):
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 def filelog(web, req, tmpl):
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 def archive(web, req, tmpl):
540 def archive(web, req, tmpl):
112 type_ = req.form['type'][0]
541 type_ = req.form['type'][0]
113 allowed = web.configlist("web", "allow_archive")
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 web.configbool("web", "allow" + type_, False))):
546 web.configbool("web", "allow" + type_, False))):
116 web.archive(tmpl, req, req.form['node'][0], type_)
547 msg = 'Unsupported archive type: %s' % type_
117 return []
548 raise ErrorResponse(HTTP_NOT_FOUND, msg)
118 raise ErrorResponse(HTTP_NOT_FOUND, 'unsupported archive type: %s' % type_)
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 def static(web, req, tmpl):
569 def static(web, req, tmpl):
121 fname = req.form['file'][0]
570 fname = req.form['file'][0]
@@ -8,7 +8,7 b''
8 from node import bin, hex, nullid
8 from node import bin, hex, nullid
9 from revlog import revlog, RevlogError
9 from revlog import revlog, RevlogError
10 from i18n import _
10 from i18n import _
11 import array, struct, mdiff
11 import array, struct, mdiff, parsers
12
12
13 class manifestdict(dict):
13 class manifestdict(dict):
14 def __init__(self, mapping=None, flags=None):
14 def __init__(self, mapping=None, flags=None):
@@ -39,14 +39,7 b' class manifest(revlog):'
39
39
40 def parse(self, lines):
40 def parse(self, lines):
41 mfdict = manifestdict()
41 mfdict = manifestdict()
42 fdict = mfdict._flags
42 parsers.parse_manifest(mfdict, mfdict._flags, lines)
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)
50 return mfdict
43 return mfdict
51
44
52 def readdelta(self, node):
45 def readdelta(self, node):
@@ -72,7 +72,6 b' def _collectextranodes(repo, files, link'
72 def strip(ui, repo, node, backup="all"):
72 def strip(ui, repo, node, backup="all"):
73 cl = repo.changelog
73 cl = repo.changelog
74 # TODO delete the undo files, and handle undo of merge sets
74 # TODO delete the undo files, and handle undo of merge sets
75 pp = cl.parents(node)
76 striprev = cl.rev(node)
75 striprev = cl.rev(node)
77
76
78 # Some revisions with rev > striprev may not be descendants of striprev.
77 # Some revisions with rev > striprev may not be descendants of striprev.
@@ -114,7 +114,7 b' class templater(object):'
114 v = v(**map)
114 v = v(**map)
115 if format:
115 if format:
116 if not hasattr(v, '__iter__'):
116 if not hasattr(v, '__iter__'):
117 raise SyntaxError(_("Error expanding '%s%s'")
117 raise SyntaxError(_("Error expanding '%s%%%s'")
118 % (key, format))
118 % (key, format))
119 lm = map.copy()
119 lm = map.copy()
120 for i in v:
120 for i in v:
@@ -96,9 +96,13 b' def rollback(opener, file):'
96 files = {}
96 files = {}
97 for l in open(file).readlines():
97 for l in open(file).readlines():
98 f, o = l.split('\0')
98 f, o = l.split('\0')
99 files[f] = o
99 files[f] = int(o)
100 for f in files:
100 for f in files:
101 o = files[f]
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 os.unlink(file)
107 os.unlink(file)
104
108
@@ -88,10 +88,11 b' mercurial.version.remember_version(versi'
88 cmdclass = {'install_data': install_package_data}
88 cmdclass = {'install_data': install_package_data}
89
89
90 ext_modules=[
90 ext_modules=[
91 Extension('mercurial.mpatch', ['mercurial/mpatch.c']),
91 Extension('mercurial.base85', ['mercurial/base85.c']),
92 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
92 Extension('mercurial.bdiff', ['mercurial/bdiff.c']),
93 Extension('mercurial.base85', ['mercurial/base85.c']),
93 Extension('mercurial.diffhelpers', ['mercurial/diffhelpers.c']),
94 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 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert']
98 packages = ['mercurial', 'mercurial.hgweb', 'hgext', 'hgext.convert']
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -3,6 +3,8 b''
3 echo "[extensions]" >> $HGRCPATH
3 echo "[extensions]" >> $HGRCPATH
4 echo "churn=" >> $HGRCPATH
4 echo "churn=" >> $HGRCPATH
5
5
6 COLUMNS=80; export COLUMNS
7
6 echo % create test repository
8 echo % create test repository
7 hg init repo
9 hg init repo
8 cd repo
10 cd repo
@@ -10,7 +10,7 b' output the current or given revision of '
10 or tip if no revision is checked out.
10 or tip if no revision is checked out.
11
11
12 Output may be to a file, in which case the name of the file is
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 for the export command, with the following additions:
14 for the export command, with the following additions:
15
15
16 %s basename of file being printed
16 %s basename of file being printed
@@ -216,10 +216,10 b' aliases: st'
216
216
217 show changed files in the working directory
217 show changed files in the working directory
218
218
219 Show status of files in the repository. If names are given, only
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
220 files that match are shown. Files that are clean or ignored or
221 source of a copy/move operation, are not listed unless -c (clean),
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 with "show only ..." are given, the options -mardu are used.
223 with "show only ..." are given, the options -mardu are used.
224
224
225 Option -q/--quiet hides untracked (unknown and ignored) files
225 Option -q/--quiet hides untracked (unknown and ignored) files
@@ -1,12 +1,12 b''
1 % Without -v
1 % Without -v
2 access log created - .hg/hgrc respected
2 access log created - .hg/hgrc respected
3 % With -v
3 % With -v
4 listening at http://localhost/ (127.0.0.1)
4 listening at http://localhost/ (bound to 127.0.0.1)
5 % With --prefix foo
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 % With --prefix /foo
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 % With --prefix foo/
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 % With --prefix /foo/
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