##// END OF EJS Templates
tests: use 'do sleep 0' instead of 'do true', also on first line of command...
Mads Kiilerich -
r16496:abbabbbe stable
parent child Browse files
Show More
@@ -1,438 +1,437 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # check-code - a style and portability checker for Mercurial
3 # check-code - a style and portability checker for Mercurial
4 #
4 #
5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 import re, glob, os, sys
10 import re, glob, os, sys
11 import keyword
11 import keyword
12 import optparse
12 import optparse
13
13
14 def repquote(m):
14 def repquote(m):
15 t = re.sub(r"\w", "x", m.group('text'))
15 t = re.sub(r"\w", "x", m.group('text'))
16 t = re.sub(r"[^\s\nx]", "o", t)
16 t = re.sub(r"[^\s\nx]", "o", t)
17 return m.group('quote') + t + m.group('quote')
17 return m.group('quote') + t + m.group('quote')
18
18
19 def reppython(m):
19 def reppython(m):
20 comment = m.group('comment')
20 comment = m.group('comment')
21 if comment:
21 if comment:
22 return "#" * len(comment)
22 return "#" * len(comment)
23 return repquote(m)
23 return repquote(m)
24
24
25 def repcomment(m):
25 def repcomment(m):
26 return m.group(1) + "#" * len(m.group(2))
26 return m.group(1) + "#" * len(m.group(2))
27
27
28 def repccomment(m):
28 def repccomment(m):
29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
29 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
30 return m.group(1) + t + "*/"
30 return m.group(1) + t + "*/"
31
31
32 def repcallspaces(m):
32 def repcallspaces(m):
33 t = re.sub(r"\n\s+", "\n", m.group(2))
33 t = re.sub(r"\n\s+", "\n", m.group(2))
34 return m.group(1) + t
34 return m.group(1) + t
35
35
36 def repinclude(m):
36 def repinclude(m):
37 return m.group(1) + "<foo>"
37 return m.group(1) + "<foo>"
38
38
39 def rephere(m):
39 def rephere(m):
40 t = re.sub(r"\S", "x", m.group(2))
40 t = re.sub(r"\S", "x", m.group(2))
41 return m.group(1) + t
41 return m.group(1) + t
42
42
43
43
44 testpats = [
44 testpats = [
45 [
45 [
46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
46 (r'pushd|popd', "don't use 'pushd' or 'popd', use 'cd'"),
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
47 (r'\W\$?\(\([^\)\n]*\)\)', "don't use (()) or $(()), use 'expr'"),
48 (r'^function', "don't use 'function', use old style"),
48 (r'^function', "don't use 'function', use old style"),
49 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
50 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
50 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
51 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
51 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
52 (r'echo -n', "don't use 'echo -n', use printf"),
52 (r'echo -n', "don't use 'echo -n', use printf"),
53 (r'^diff.*-\w*N', "don't use 'diff -N'"),
53 (r'^diff.*-\w*N', "don't use 'diff -N'"),
54 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
54 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
55 (r'head -c', "don't use 'head -c', use 'dd'"),
55 (r'head -c', "don't use 'head -c', use 'dd'"),
56 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
56 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
57 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
57 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
58 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
58 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
59 (r'printf.*\\x', "don't use printf \\x, use Python"),
59 (r'printf.*\\x', "don't use printf \\x, use Python"),
60 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
60 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
61 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
61 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
62 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
62 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
63 "use egrep for extended grep syntax"),
63 "use egrep for extended grep syntax"),
64 (r'/bin/', "don't use explicit paths for tools"),
64 (r'/bin/', "don't use explicit paths for tools"),
65 (r'\$PWD', "don't use $PWD, use `pwd`"),
65 (r'\$PWD', "don't use $PWD, use `pwd`"),
66 (r'[^\n]\Z', "no trailing newline"),
66 (r'[^\n]\Z', "no trailing newline"),
67 (r'export.*=', "don't export and assign at once"),
67 (r'export.*=', "don't export and assign at once"),
68 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
68 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
69 (r'^source\b', "don't use 'source', use '.'"),
69 (r'^source\b', "don't use 'source', use '.'"),
70 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
70 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
71 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
71 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
72 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
72 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
73 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
73 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
74 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
74 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
75 (r'^alias\b.*=', "don't use alias, use a function"),
75 (r'^alias\b.*=', "don't use alias, use a function"),
76 (r'if\s*!', "don't use '!' to negate exit status"),
76 (r'if\s*!', "don't use '!' to negate exit status"),
77 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
77 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
78 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
78 ],
79 ],
79 # warnings
80 # warnings
80 []
81 []
81 ]
82 ]
82
83
83 testfilters = [
84 testfilters = [
84 (r"( *)(#([^\n]*\S)?)", repcomment),
85 (r"( *)(#([^\n]*\S)?)", repcomment),
85 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
86 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
86 ]
87 ]
87
88
88 uprefix = r"^ \$ "
89 uprefix = r"^ \$ "
89 uprefixc = r"^ > "
90 uprefixc = r"^ > "
90 utestpats = [
91 utestpats = [
91 [
92 [
92 (r'^(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"),
93 (r'^(\S| $ ).*(\S[ \t]+|^[ \t]+)\n', "trailing whitespace on non-output"),
93 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
94 (uprefix + r'.*\|\s*sed', "use regex test output patterns instead of sed"),
94 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
95 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
95 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
96 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
96 (uprefix + r'.*\|\| echo.*(fail|error)',
97 (uprefix + r'.*\|\| echo.*(fail|error)',
97 "explicit exit code checks unnecessary"),
98 "explicit exit code checks unnecessary"),
98 (uprefix + r'set -e', "don't use set -e"),
99 (uprefix + r'set -e', "don't use set -e"),
99 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
100 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
100 (uprefixc + r'( *)\t', "don't use tabs to indent"),
101 (uprefixc + r'( *)\t', "don't use tabs to indent"),
101 (uprefixc + r'.*do\s*true;\s*done',
102 "don't use true as loop body, use sleep 0"),
103 ],
102 ],
104 # warnings
103 # warnings
105 []
104 []
106 ]
105 ]
107
106
108 for i in [0, 1]:
107 for i in [0, 1]:
109 for p, m in testpats[i]:
108 for p, m in testpats[i]:
110 if p.startswith(r'^'):
109 if p.startswith(r'^'):
111 p = r"^ \$ (%s)" % p[1:]
110 p = r"^ \$ (%s)" % p[1:]
112 else:
111 else:
113 p = r"^ \$ .*(%s)" % p
112 p = r"^ \$ .*(%s)" % p
114 utestpats[i].append((p, m))
113 utestpats[i].append((p, m))
115
114
116 utestfilters = [
115 utestfilters = [
117 (r"( *)(#([^\n]*\S)?)", repcomment),
116 (r"( *)(#([^\n]*\S)?)", repcomment),
118 ]
117 ]
119
118
120 pypats = [
119 pypats = [
121 [
120 [
122 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
121 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
123 "tuple parameter unpacking not available in Python 3+"),
122 "tuple parameter unpacking not available in Python 3+"),
124 (r'lambda\s*\(.*,.*\)',
123 (r'lambda\s*\(.*,.*\)',
125 "tuple parameter unpacking not available in Python 3+"),
124 "tuple parameter unpacking not available in Python 3+"),
126 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
125 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
127 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
126 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
128 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
127 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
129 (r'^\s*\t', "don't use tabs"),
128 (r'^\s*\t', "don't use tabs"),
130 (r'\S;\s*\n', "semicolon"),
129 (r'\S;\s*\n', "semicolon"),
131 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
130 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
132 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
131 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
133 (r'\w,\w', "missing whitespace after ,"),
132 (r'\w,\w', "missing whitespace after ,"),
134 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
133 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
135 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
134 (r'^\s+\w+=\w+[^,)\n]$', "missing whitespace in assignment"),
136 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
135 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
137 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
136 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Py2.4'),
138 (r'.{85}', "line too long"),
137 (r'.{85}', "line too long"),
139 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
138 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
140 (r'[^\n]\Z', "no trailing newline"),
139 (r'[^\n]\Z', "no trailing newline"),
141 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
140 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
142 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
141 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=', "don't use underbars in identifiers"),
143 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
142 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
144 "don't use camelcase in identifiers"),
143 "don't use camelcase in identifiers"),
145 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
144 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
146 "linebreak after :"),
145 "linebreak after :"),
147 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
146 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
148 (r'class\s[^( \n]+\(\):',
147 (r'class\s[^( \n]+\(\):',
149 "class foo() not available in Python 2.4, use class foo(object)"),
148 "class foo() not available in Python 2.4, use class foo(object)"),
150 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
149 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
151 "Python keyword is not a function"),
150 "Python keyword is not a function"),
152 (r',]', "unneeded trailing ',' in list"),
151 (r',]', "unneeded trailing ',' in list"),
153 # (r'class\s[A-Z][^\(]*\((?!Exception)',
152 # (r'class\s[A-Z][^\(]*\((?!Exception)',
154 # "don't capitalize non-exception classes"),
153 # "don't capitalize non-exception classes"),
155 # (r'in range\(', "use xrange"),
154 # (r'in range\(', "use xrange"),
156 # (r'^\s*print\s+', "avoid using print in core and extensions"),
155 # (r'^\s*print\s+', "avoid using print in core and extensions"),
157 (r'[\x80-\xff]', "non-ASCII character literal"),
156 (r'[\x80-\xff]', "non-ASCII character literal"),
158 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
157 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
159 (r'^\s*with\s+', "with not available in Python 2.4"),
158 (r'^\s*with\s+', "with not available in Python 2.4"),
160 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
159 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
161 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
160 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
162 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
161 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
163 (r'(?<!def)\s+(any|all|format)\(',
162 (r'(?<!def)\s+(any|all|format)\(',
164 "any/all/format not available in Python 2.4"),
163 "any/all/format not available in Python 2.4"),
165 (r'(?<!def)\s+(callable)\(',
164 (r'(?<!def)\s+(callable)\(',
166 "callable not available in Python 3, use getattr(f, '__call__', None)"),
165 "callable not available in Python 3, use getattr(f, '__call__', None)"),
167 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
166 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
168 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
167 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
169 "gratuitous whitespace after Python keyword"),
168 "gratuitous whitespace after Python keyword"),
170 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
169 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
171 # (r'\s\s=', "gratuitous whitespace before ="),
170 # (r'\s\s=', "gratuitous whitespace before ="),
172 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
171 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
173 "missing whitespace around operator"),
172 "missing whitespace around operator"),
174 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
173 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s',
175 "missing whitespace around operator"),
174 "missing whitespace around operator"),
176 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
175 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S',
177 "missing whitespace around operator"),
176 "missing whitespace around operator"),
178 (r'[^^+=*/!<>&| -](\s=|=\s)[^= ]',
177 (r'[^^+=*/!<>&| -](\s=|=\s)[^= ]',
179 "wrong whitespace around ="),
178 "wrong whitespace around ="),
180 (r'raise Exception', "don't raise generic exceptions"),
179 (r'raise Exception', "don't raise generic exceptions"),
181 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
180 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
182 (r' [=!]=\s+(True|False|None)',
181 (r' [=!]=\s+(True|False|None)',
183 "comparison with singleton, use 'is' or 'is not' instead"),
182 "comparison with singleton, use 'is' or 'is not' instead"),
184 (r'^\s*(while|if) [01]:',
183 (r'^\s*(while|if) [01]:',
185 "use True/False for constant Boolean expression"),
184 "use True/False for constant Boolean expression"),
186 (r'(?:(?<!def)\s+|\()hasattr',
185 (r'(?:(?<!def)\s+|\()hasattr',
187 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
186 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
188 (r'opener\([^)]*\).read\(',
187 (r'opener\([^)]*\).read\(',
189 "use opener.read() instead"),
188 "use opener.read() instead"),
190 (r'BaseException', 'not in Py2.4, use Exception'),
189 (r'BaseException', 'not in Py2.4, use Exception'),
191 (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'),
190 (r'os\.path\.relpath', 'os.path.relpath is not in Py2.5'),
192 (r'opener\([^)]*\).write\(',
191 (r'opener\([^)]*\).write\(',
193 "use opener.write() instead"),
192 "use opener.write() instead"),
194 (r'[\s\(](open|file)\([^)]*\)\.read\(',
193 (r'[\s\(](open|file)\([^)]*\)\.read\(',
195 "use util.readfile() instead"),
194 "use util.readfile() instead"),
196 (r'[\s\(](open|file)\([^)]*\)\.write\(',
195 (r'[\s\(](open|file)\([^)]*\)\.write\(',
197 "use util.readfile() instead"),
196 "use util.readfile() instead"),
198 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
197 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
199 "always assign an opened file to a variable, and close it afterwards"),
198 "always assign an opened file to a variable, and close it afterwards"),
200 (r'[\s\(](open|file)\([^)]*\)\.',
199 (r'[\s\(](open|file)\([^)]*\)\.',
201 "always assign an opened file to a variable, and close it afterwards"),
200 "always assign an opened file to a variable, and close it afterwards"),
202 (r'(?i)descendent', "the proper spelling is descendAnt"),
201 (r'(?i)descendent', "the proper spelling is descendAnt"),
203 (r'\.debug\(\_', "don't mark debug messages for translation"),
202 (r'\.debug\(\_', "don't mark debug messages for translation"),
204 ],
203 ],
205 # warnings
204 # warnings
206 [
205 [
207 (r'.{81}', "warning: line over 80 characters"),
206 (r'.{81}', "warning: line over 80 characters"),
208 (r'^\s*except:$', "warning: naked except clause"),
207 (r'^\s*except:$', "warning: naked except clause"),
209 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
208 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
210 "warning: unwrapped ui message"),
209 "warning: unwrapped ui message"),
211 ]
210 ]
212 ]
211 ]
213
212
214 pyfilters = [
213 pyfilters = [
215 (r"""(?msx)(?P<comment>\#.*?$)|
214 (r"""(?msx)(?P<comment>\#.*?$)|
216 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
215 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
217 (?P<text>(([^\\]|\\.)*?))
216 (?P<text>(([^\\]|\\.)*?))
218 (?P=quote))""", reppython),
217 (?P=quote))""", reppython),
219 ]
218 ]
220
219
221 cpats = [
220 cpats = [
222 [
221 [
223 (r'//', "don't use //-style comments"),
222 (r'//', "don't use //-style comments"),
224 (r'^ ', "don't use spaces to indent"),
223 (r'^ ', "don't use spaces to indent"),
225 (r'\S\t', "don't use tabs except for indent"),
224 (r'\S\t', "don't use tabs except for indent"),
226 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
225 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
227 (r'.{85}', "line too long"),
226 (r'.{85}', "line too long"),
228 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
227 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
229 (r'return\(', "return is not a function"),
228 (r'return\(', "return is not a function"),
230 (r' ;', "no space before ;"),
229 (r' ;', "no space before ;"),
231 (r'\w+\* \w+', "use int *foo, not int* foo"),
230 (r'\w+\* \w+', "use int *foo, not int* foo"),
232 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
231 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
233 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
232 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
234 (r'\w,\w', "missing whitespace after ,"),
233 (r'\w,\w', "missing whitespace after ,"),
235 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
234 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
236 (r'^#\s+\w', "use #foo, not # foo"),
235 (r'^#\s+\w', "use #foo, not # foo"),
237 (r'[^\n]\Z', "no trailing newline"),
236 (r'[^\n]\Z', "no trailing newline"),
238 (r'^\s*#import\b', "use only #include in standard C code"),
237 (r'^\s*#import\b', "use only #include in standard C code"),
239 ],
238 ],
240 # warnings
239 # warnings
241 []
240 []
242 ]
241 ]
243
242
244 cfilters = [
243 cfilters = [
245 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
244 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
246 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
245 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
247 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
246 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
248 (r'(\()([^)]+\))', repcallspaces),
247 (r'(\()([^)]+\))', repcallspaces),
249 ]
248 ]
250
249
251 inutilpats = [
250 inutilpats = [
252 [
251 [
253 (r'\bui\.', "don't use ui in util"),
252 (r'\bui\.', "don't use ui in util"),
254 ],
253 ],
255 # warnings
254 # warnings
256 []
255 []
257 ]
256 ]
258
257
259 inrevlogpats = [
258 inrevlogpats = [
260 [
259 [
261 (r'\brepo\.', "don't use repo in revlog"),
260 (r'\brepo\.', "don't use repo in revlog"),
262 ],
261 ],
263 # warnings
262 # warnings
264 []
263 []
265 ]
264 ]
266
265
267 checks = [
266 checks = [
268 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
267 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
269 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
268 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
270 ('c', r'.*\.c$', cfilters, cpats),
269 ('c', r'.*\.c$', cfilters, cpats),
271 ('unified test', r'.*\.t$', utestfilters, utestpats),
270 ('unified test', r'.*\.t$', utestfilters, utestpats),
272 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
271 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
273 inrevlogpats),
272 inrevlogpats),
274 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
273 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
275 inutilpats),
274 inutilpats),
276 ]
275 ]
277
276
278 class norepeatlogger(object):
277 class norepeatlogger(object):
279 def __init__(self):
278 def __init__(self):
280 self._lastseen = None
279 self._lastseen = None
281
280
282 def log(self, fname, lineno, line, msg, blame):
281 def log(self, fname, lineno, line, msg, blame):
283 """print error related a to given line of a given file.
282 """print error related a to given line of a given file.
284
283
285 The faulty line will also be printed but only once in the case
284 The faulty line will also be printed but only once in the case
286 of multiple errors.
285 of multiple errors.
287
286
288 :fname: filename
287 :fname: filename
289 :lineno: line number
288 :lineno: line number
290 :line: actual content of the line
289 :line: actual content of the line
291 :msg: error message
290 :msg: error message
292 """
291 """
293 msgid = fname, lineno, line
292 msgid = fname, lineno, line
294 if msgid != self._lastseen:
293 if msgid != self._lastseen:
295 if blame:
294 if blame:
296 print "%s:%d (%s):" % (fname, lineno, blame)
295 print "%s:%d (%s):" % (fname, lineno, blame)
297 else:
296 else:
298 print "%s:%d:" % (fname, lineno)
297 print "%s:%d:" % (fname, lineno)
299 print " > %s" % line
298 print " > %s" % line
300 self._lastseen = msgid
299 self._lastseen = msgid
301 print " " + msg
300 print " " + msg
302
301
303 _defaultlogger = norepeatlogger()
302 _defaultlogger = norepeatlogger()
304
303
305 def getblame(f):
304 def getblame(f):
306 lines = []
305 lines = []
307 for l in os.popen('hg annotate -un %s' % f):
306 for l in os.popen('hg annotate -un %s' % f):
308 start, line = l.split(':', 1)
307 start, line = l.split(':', 1)
309 user, rev = start.split()
308 user, rev = start.split()
310 lines.append((line[1:-1], user, rev))
309 lines.append((line[1:-1], user, rev))
311 return lines
310 return lines
312
311
313 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
312 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
314 blame=False, debug=False, lineno=True):
313 blame=False, debug=False, lineno=True):
315 """checks style and portability of a given file
314 """checks style and portability of a given file
316
315
317 :f: filepath
316 :f: filepath
318 :logfunc: function used to report error
317 :logfunc: function used to report error
319 logfunc(filename, linenumber, linecontent, errormessage)
318 logfunc(filename, linenumber, linecontent, errormessage)
320 :maxerr: number of error to display before arborting.
319 :maxerr: number of error to display before arborting.
321 Set to false (default) to report all errors
320 Set to false (default) to report all errors
322
321
323 return True if no error is found, False otherwise.
322 return True if no error is found, False otherwise.
324 """
323 """
325 blamecache = None
324 blamecache = None
326 result = True
325 result = True
327 for name, match, filters, pats in checks:
326 for name, match, filters, pats in checks:
328 if debug:
327 if debug:
329 print name, f
328 print name, f
330 fc = 0
329 fc = 0
331 if not re.match(match, f):
330 if not re.match(match, f):
332 if debug:
331 if debug:
333 print "Skipping %s for %s it doesn't match %s" % (
332 print "Skipping %s for %s it doesn't match %s" % (
334 name, match, f)
333 name, match, f)
335 continue
334 continue
336 fp = open(f)
335 fp = open(f)
337 pre = post = fp.read()
336 pre = post = fp.read()
338 fp.close()
337 fp.close()
339 if "no-" + "check-code" in pre:
338 if "no-" + "check-code" in pre:
340 if debug:
339 if debug:
341 print "Skipping %s for %s it has no- and check-code" % (
340 print "Skipping %s for %s it has no- and check-code" % (
342 name, f)
341 name, f)
343 break
342 break
344 for p, r in filters:
343 for p, r in filters:
345 post = re.sub(p, r, post)
344 post = re.sub(p, r, post)
346 if warnings:
345 if warnings:
347 pats = pats[0] + pats[1]
346 pats = pats[0] + pats[1]
348 else:
347 else:
349 pats = pats[0]
348 pats = pats[0]
350 # print post # uncomment to show filtered version
349 # print post # uncomment to show filtered version
351
350
352 if debug:
351 if debug:
353 print "Checking %s for %s" % (name, f)
352 print "Checking %s for %s" % (name, f)
354
353
355 prelines = None
354 prelines = None
356 errors = []
355 errors = []
357 for p, msg in pats:
356 for p, msg in pats:
358 # fix-up regexes for multiline searches
357 # fix-up regexes for multiline searches
359 po = p
358 po = p
360 # \s doesn't match \n
359 # \s doesn't match \n
361 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
360 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
362 # [^...] doesn't match newline
361 # [^...] doesn't match newline
363 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
362 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
364
363
365 #print po, '=>', p
364 #print po, '=>', p
366
365
367 pos = 0
366 pos = 0
368 n = 0
367 n = 0
369 for m in re.finditer(p, post, re.MULTILINE):
368 for m in re.finditer(p, post, re.MULTILINE):
370 if prelines is None:
369 if prelines is None:
371 prelines = pre.splitlines()
370 prelines = pre.splitlines()
372 postlines = post.splitlines(True)
371 postlines = post.splitlines(True)
373
372
374 start = m.start()
373 start = m.start()
375 while n < len(postlines):
374 while n < len(postlines):
376 step = len(postlines[n])
375 step = len(postlines[n])
377 if pos + step > start:
376 if pos + step > start:
378 break
377 break
379 pos += step
378 pos += step
380 n += 1
379 n += 1
381 l = prelines[n]
380 l = prelines[n]
382
381
383 if "check-code" + "-ignore" in l:
382 if "check-code" + "-ignore" in l:
384 if debug:
383 if debug:
385 print "Skipping %s for %s:%s (check-code -ignore)" % (
384 print "Skipping %s for %s:%s (check-code -ignore)" % (
386 name, f, n)
385 name, f, n)
387 continue
386 continue
388 bd = ""
387 bd = ""
389 if blame:
388 if blame:
390 bd = 'working directory'
389 bd = 'working directory'
391 if not blamecache:
390 if not blamecache:
392 blamecache = getblame(f)
391 blamecache = getblame(f)
393 if n < len(blamecache):
392 if n < len(blamecache):
394 bl, bu, br = blamecache[n]
393 bl, bu, br = blamecache[n]
395 if bl == l:
394 if bl == l:
396 bd = '%s@%s' % (bu, br)
395 bd = '%s@%s' % (bu, br)
397 errors.append((f, lineno and n + 1, l, msg, bd))
396 errors.append((f, lineno and n + 1, l, msg, bd))
398 result = False
397 result = False
399
398
400 errors.sort()
399 errors.sort()
401 for e in errors:
400 for e in errors:
402 logfunc(*e)
401 logfunc(*e)
403 fc += 1
402 fc += 1
404 if maxerr and fc >= maxerr:
403 if maxerr and fc >= maxerr:
405 print " (too many errors, giving up)"
404 print " (too many errors, giving up)"
406 break
405 break
407
406
408 return result
407 return result
409
408
410 if __name__ == "__main__":
409 if __name__ == "__main__":
411 parser = optparse.OptionParser("%prog [options] [files]")
410 parser = optparse.OptionParser("%prog [options] [files]")
412 parser.add_option("-w", "--warnings", action="store_true",
411 parser.add_option("-w", "--warnings", action="store_true",
413 help="include warning-level checks")
412 help="include warning-level checks")
414 parser.add_option("-p", "--per-file", type="int",
413 parser.add_option("-p", "--per-file", type="int",
415 help="max warnings per file")
414 help="max warnings per file")
416 parser.add_option("-b", "--blame", action="store_true",
415 parser.add_option("-b", "--blame", action="store_true",
417 help="use annotate to generate blame info")
416 help="use annotate to generate blame info")
418 parser.add_option("", "--debug", action="store_true",
417 parser.add_option("", "--debug", action="store_true",
419 help="show debug information")
418 help="show debug information")
420 parser.add_option("", "--nolineno", action="store_false",
419 parser.add_option("", "--nolineno", action="store_false",
421 dest='lineno', help="don't show line numbers")
420 dest='lineno', help="don't show line numbers")
422
421
423 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
422 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
424 lineno=True)
423 lineno=True)
425 (options, args) = parser.parse_args()
424 (options, args) = parser.parse_args()
426
425
427 if len(args) == 0:
426 if len(args) == 0:
428 check = glob.glob("*")
427 check = glob.glob("*")
429 else:
428 else:
430 check = args
429 check = args
431
430
432 ret = 0
431 ret = 0
433 for f in check:
432 for f in check:
434 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
433 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
435 blame=options.blame, debug=options.debug,
434 blame=options.blame, debug=options.debug,
436 lineno=options.lineno):
435 lineno=options.lineno):
437 ret = 1
436 ret = 1
438 sys.exit(ret)
437 sys.exit(ret)
@@ -1,27 +1,27 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 $ hg clone http://localhost:$HGPORT/ copy
3 $ hg clone http://localhost:$HGPORT/ copy
4 abort: error: Connection refused
4 abort: error: Connection refused
5 [255]
5 [255]
6
6
7 $ test -d copy
7 $ test -d copy
8 [1]
8 [1]
9
9
10 $ cat > dumb.py <<EOF
10 $ cat > dumb.py <<EOF
11 > import BaseHTTPServer, SimpleHTTPServer, os, signal
11 > import BaseHTTPServer, SimpleHTTPServer, os, signal
12 > def run(server_class=BaseHTTPServer.HTTPServer,
12 > def run(server_class=BaseHTTPServer.HTTPServer,
13 > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
13 > handler_class=SimpleHTTPServer.SimpleHTTPRequestHandler):
14 > server_address = ('localhost', int(os.environ['HGPORT']))
14 > server_address = ('localhost', int(os.environ['HGPORT']))
15 > httpd = server_class(server_address, handler_class)
15 > httpd = server_class(server_address, handler_class)
16 > open("listening", "w")
16 > open("listening", "w")
17 > httpd.handle_request()
17 > httpd.handle_request()
18 > run()
18 > run()
19 > EOF
19 > EOF
20
20
21 $ python dumb.py 2> log &
21 $ python dumb.py 2> log &
22 $ P=$!
22 $ P=$!
23 $ while [ ! -f listening ]; do true; done
23 $ while [ ! -f listening ]; do sleep 0; done
24 $ hg clone http://localhost:$HGPORT/foo copy2
24 $ hg clone http://localhost:$HGPORT/foo copy2
25 abort: HTTP Error 404: * (glob)
25 abort: HTTP Error 404: * (glob)
26 [255]
26 [255]
27 $ wait $P
27 $ wait $P
@@ -1,58 +1,58 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 Test raw style of hgweb
3 Test raw style of hgweb
4
4
5 $ hg init test
5 $ hg init test
6 $ cd test
6 $ cd test
7 $ mkdir sub
7 $ mkdir sub
8 $ cat >'sub/some "text".txt' <<ENDSOME
8 $ cat >'sub/some "text".txt' <<ENDSOME
9 > This is just some random text
9 > This is just some random text
10 > that will go inside the file and take a few lines.
10 > that will go inside the file and take a few lines.
11 > It is very boring to read, but computers don't
11 > It is very boring to read, but computers don't
12 > care about things like that.
12 > care about things like that.
13 > ENDSOME
13 > ENDSOME
14 $ hg add 'sub/some "text".txt'
14 $ hg add 'sub/some "text".txt'
15 warning: filename contains '"', which is reserved on Windows: 'sub/some "text".txt'
15 warning: filename contains '"', which is reserved on Windows: 'sub/some "text".txt'
16 $ hg commit -d "1 0" -m "Just some text"
16 $ hg commit -d "1 0" -m "Just some text"
17
17
18 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
18 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid
19
19
20 $ cat hg.pid >> $DAEMON_PIDS
20 $ cat hg.pid >> $DAEMON_PIDS
21 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
21 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
22
22
23 $ while kill `cat hg.pid` 2>/dev/null; do true; done
23 $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
24
24
25 $ cat getoutput.txt
25 $ cat getoutput.txt
26 200 Script output follows
26 200 Script output follows
27 content-type: application/binary
27 content-type: application/binary
28 content-length: 157
28 content-length: 157
29 content-disposition: inline; filename="some \"text\".txt"
29 content-disposition: inline; filename="some \"text\".txt"
30
30
31 This is just some random text
31 This is just some random text
32 that will go inside the file and take a few lines.
32 that will go inside the file and take a few lines.
33 It is very boring to read, but computers don't
33 It is very boring to read, but computers don't
34 care about things like that.
34 care about things like that.
35 $ cat access.log error.log
35 $ cat access.log error.log
36 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
36 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
37
37
38 $ rm access.log error.log
38 $ rm access.log error.log
39 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
39 $ hg serve -p $HGPORT -A access.log -E error.log -d --pid-file=hg.pid \
40 > --config web.guessmime=True
40 > --config web.guessmime=True
41
41
42 $ cat hg.pid >> $DAEMON_PIDS
42 $ cat hg.pid >> $DAEMON_PIDS
43 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
43 $ ("$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw' content-type content-length content-disposition) >getoutput.txt
44 $ while kill `cat hg.pid` 2>/dev/null; do true; done
44 $ while kill `cat hg.pid` 2>/dev/null; do sleep 0; done
45
45
46 $ cat getoutput.txt
46 $ cat getoutput.txt
47 200 Script output follows
47 200 Script output follows
48 content-type: text/plain; charset="ascii"
48 content-type: text/plain; charset="ascii"
49 content-length: 157
49 content-length: 157
50 content-disposition: inline; filename="some \"text\".txt"
50 content-disposition: inline; filename="some \"text\".txt"
51
51
52 This is just some random text
52 This is just some random text
53 that will go inside the file and take a few lines.
53 that will go inside the file and take a few lines.
54 It is very boring to read, but computers don't
54 It is very boring to read, but computers don't
55 care about things like that.
55 care about things like that.
56 $ cat access.log error.log
56 $ cat access.log error.log
57 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
57 127.0.0.1 - - [*] "GET /?f=a23bf1310f6e;file=sub/some%20%22text%22.txt;style=raw HTTP/1.1" 200 - (glob)
58
58
@@ -1,124 +1,124 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 $ hg init a
3 $ hg init a
4 $ cd a
4 $ cd a
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -Ama -d '1123456789 0'
6 $ hg ci -Ama -d '1123456789 0'
7 adding a
7 adding a
8 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
8 $ hg --config server.uncompressed=True serve -p $HGPORT -d --pid-file=hg.pid
9 $ cat hg.pid >> $DAEMON_PIDS
9 $ cat hg.pid >> $DAEMON_PIDS
10 $ cd ..
10 $ cd ..
11 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
11 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log 2>&1 </dev/null &
12 $ while [ ! -f proxy.pid ]; do true; done
12 $ while [ ! -f proxy.pid ]; do sleep 0; done
13 $ cat proxy.pid >> $DAEMON_PIDS
13 $ cat proxy.pid >> $DAEMON_PIDS
14
14
15 url for proxy, stream
15 url for proxy, stream
16
16
17 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
17 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone --uncompressed http://localhost:$HGPORT/ b
18 streaming all changes
18 streaming all changes
19 3 files to transfer, 303 bytes of data
19 3 files to transfer, 303 bytes of data
20 transferred * bytes in * seconds (*/sec) (glob)
20 transferred * bytes in * seconds (*/sec) (glob)
21 updating to branch default
21 updating to branch default
22 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 $ cd b
23 $ cd b
24 $ hg verify
24 $ hg verify
25 checking changesets
25 checking changesets
26 checking manifests
26 checking manifests
27 crosschecking files in changesets and manifests
27 crosschecking files in changesets and manifests
28 checking files
28 checking files
29 1 files, 1 changesets, 1 total revisions
29 1 files, 1 changesets, 1 total revisions
30 $ cd ..
30 $ cd ..
31
31
32 url for proxy, pull
32 url for proxy, pull
33
33
34 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
34 $ http_proxy=http://localhost:$HGPORT1/ hg --config http_proxy.always=True clone http://localhost:$HGPORT/ b-pull
35 requesting all changes
35 requesting all changes
36 adding changesets
36 adding changesets
37 adding manifests
37 adding manifests
38 adding file changes
38 adding file changes
39 added 1 changesets with 1 changes to 1 files
39 added 1 changesets with 1 changes to 1 files
40 updating to branch default
40 updating to branch default
41 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 $ cd b-pull
42 $ cd b-pull
43 $ hg verify
43 $ hg verify
44 checking changesets
44 checking changesets
45 checking manifests
45 checking manifests
46 crosschecking files in changesets and manifests
46 crosschecking files in changesets and manifests
47 checking files
47 checking files
48 1 files, 1 changesets, 1 total revisions
48 1 files, 1 changesets, 1 total revisions
49 $ cd ..
49 $ cd ..
50
50
51 host:port for proxy
51 host:port for proxy
52
52
53 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
53 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ c
54 requesting all changes
54 requesting all changes
55 adding changesets
55 adding changesets
56 adding manifests
56 adding manifests
57 adding file changes
57 adding file changes
58 added 1 changesets with 1 changes to 1 files
58 added 1 changesets with 1 changes to 1 files
59 updating to branch default
59 updating to branch default
60 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
60 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
61
61
62 proxy url with user name and password
62 proxy url with user name and password
63
63
64 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
64 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ d
65 requesting all changes
65 requesting all changes
66 adding changesets
66 adding changesets
67 adding manifests
67 adding manifests
68 adding file changes
68 adding file changes
69 added 1 changesets with 1 changes to 1 files
69 added 1 changesets with 1 changes to 1 files
70 updating to branch default
70 updating to branch default
71 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
72
72
73 url with user name and password
73 url with user name and password
74
74
75 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
75 $ http_proxy=http://user:passwd@localhost:$HGPORT1 hg clone --config http_proxy.always=True http://user:passwd@localhost:$HGPORT/ e
76 requesting all changes
76 requesting all changes
77 adding changesets
77 adding changesets
78 adding manifests
78 adding manifests
79 adding file changes
79 adding file changes
80 added 1 changesets with 1 changes to 1 files
80 added 1 changesets with 1 changes to 1 files
81 updating to branch default
81 updating to branch default
82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
82 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83
83
84 bad host:port for proxy
84 bad host:port for proxy
85
85
86 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
86 $ http_proxy=localhost:$HGPORT2 hg clone --config http_proxy.always=True http://localhost:$HGPORT/ f
87 abort: error: Connection refused
87 abort: error: Connection refused
88 [255]
88 [255]
89
89
90 do not use the proxy if it is in the no list
90 do not use the proxy if it is in the no list
91
91
92 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
92 $ http_proxy=localhost:$HGPORT1 hg clone --config http_proxy.no=localhost http://localhost:$HGPORT/ g
93 requesting all changes
93 requesting all changes
94 adding changesets
94 adding changesets
95 adding manifests
95 adding manifests
96 adding file changes
96 adding file changes
97 added 1 changesets with 1 changes to 1 files
97 added 1 changesets with 1 changes to 1 files
98 updating to branch default
98 updating to branch default
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 $ cat proxy.log
100 $ cat proxy.log
101 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
101 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
102 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
102 * - - [*] "GET http://localhost:$HGPORT/?cmd=stream_out HTTP/1.1" - - (glob)
103 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
103 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
104 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
104 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
105 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
105 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
106 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
106 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
107 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
107 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
108 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
108 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
109 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
110 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
110 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
111 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
111 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
112 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
112 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
113 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
113 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
114 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
114 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
115 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
115 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
116 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
116 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
117 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
117 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
118 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
119 * - - [*] "GET http://localhost:$HGPORT/?cmd=capabilities HTTP/1.1" - - (glob)
120 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
120 * - - [*] "GET http://localhost:$HGPORT/?cmd=batch HTTP/1.1" - - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D (glob)
121 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
121 * - - [*] "GET http://localhost:$HGPORT/?cmd=getbundle HTTP/1.1" - - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=83180e7845de420a1bb46896fd5fe05294f8d629 (glob)
122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
122 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=phases (glob)
123 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
123 * - - [*] "GET http://localhost:$HGPORT/?cmd=listkeys HTTP/1.1" - - x-hgarg-1:namespace=bookmarks (glob)
124
124
@@ -1,275 +1,275 b''
1 Proper https client requires the built-in ssl from Python 2.6.
1 Proper https client requires the built-in ssl from Python 2.6.
2
2
3 $ "$TESTDIR/hghave" serve ssl || exit 80
3 $ "$TESTDIR/hghave" serve ssl || exit 80
4
4
5 Certificates created with:
5 Certificates created with:
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
6 printf '.\n.\n.\n.\n.\nlocalhost\nhg@localhost\n' | \
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
7 openssl req -newkey rsa:512 -keyout priv.pem -nodes -x509 -days 9000 -out pub.pem
8 Can be dumped with:
8 Can be dumped with:
9 openssl x509 -in pub.pem -text
9 openssl x509 -in pub.pem -text
10
10
11 $ cat << EOT > priv.pem
11 $ cat << EOT > priv.pem
12 > -----BEGIN PRIVATE KEY-----
12 > -----BEGIN PRIVATE KEY-----
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
13 > MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEApjCWeYGrIa/Vo7LH
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
14 > aRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
15 > j/xgSwIDAQABAkBxHC6+Qlf0VJXGlb6NL16yEVVTQxqDS6hA9zqu6TZjrr0YMfzc
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
16 > EGNIiZGt7HCBL0zO+cPDg/LeCZc6HQhf0KrhAiEAzlJq4hWWzvguWFIJWSoBeBUG
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
17 > MF1ACazQO7PYE8M0qfECIQDONHHP0SKZzz/ZwBZcAveC5K61f/v9hONFwbeYulzR
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
18 > +wIgc9SvbtgB/5Yzpp//4ZAEnR7oh5SClCvyB+KSx52K3nECICbhQphhoXmI10wy
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
19 > aMTellaq0bpNMHFDziqH9RsqAHhjAiEAgYGxfzkftt5IUUn/iFK89aaIpyrpuaAh
20 > HY8gUVkVRVs=
20 > HY8gUVkVRVs=
21 > -----END PRIVATE KEY-----
21 > -----END PRIVATE KEY-----
22 > EOT
22 > EOT
23
23
24 $ cat << EOT > pub.pem
24 $ cat << EOT > pub.pem
25 > -----BEGIN CERTIFICATE-----
25 > -----BEGIN CERTIFICATE-----
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
26 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
27 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
28 > MTAxNDIwMzAxNFoXDTM1MDYwNTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
29 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
30 > ADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnKEUm34rDaXQd4lxxX
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
31 > 6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA+amm
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
32 > r24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQw
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
33 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAFArvQFiAZJgQczRsbYlG1xl
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
34 > t+truk37w5B3m3Ick1ntRcQrqs+hf0CO1q6Squ144geYaQ8CDirSR92fICELI1c=
35 > -----END CERTIFICATE-----
35 > -----END CERTIFICATE-----
36 > EOT
36 > EOT
37 $ cat priv.pem pub.pem >> server.pem
37 $ cat priv.pem pub.pem >> server.pem
38 $ PRIV=`pwd`/server.pem
38 $ PRIV=`pwd`/server.pem
39
39
40 $ cat << EOT > pub-other.pem
40 $ cat << EOT > pub-other.pem
41 > -----BEGIN CERTIFICATE-----
41 > -----BEGIN CERTIFICATE-----
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
42 > MIIBqzCCAVWgAwIBAgIJALwZS731c/ORMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNV
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
43 > BAMMCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEw
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
44 > MTAxNDIwNDUxNloXDTM1MDYwNTIwNDUxNlowMTESMBAGA1UEAwwJbG9jYWxob3N0
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
45 > MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhvc3QwXDANBgkqhkiG9w0BAQEFAANL
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
46 > ADBIAkEAsxsapLbHrqqUKuQBxdpK4G3m2LjtyrTSdpzzzFlecxd5yhNP6AyWrufo
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
47 > K4VMGo2xlu9xOo88nDSUNSKPuD09MwIDAQABo1AwTjAdBgNVHQ4EFgQUoIB1iMhN
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
48 > y868rpQ2qk9dHnU6ebswHwYDVR0jBBgwFoAUoIB1iMhNy868rpQ2qk9dHnU6ebsw
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
49 > DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJ544f125CsE7J2t55PdFaF6
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
50 > bBlNBb91FCywBgSjhBjf+GG3TNPwrPdc3yqeq+hzJiuInqbOBv9abmMyq8Wsoig=
51 > -----END CERTIFICATE-----
51 > -----END CERTIFICATE-----
52 > EOT
52 > EOT
53
53
54 pub.pem patched with other notBefore / notAfter:
54 pub.pem patched with other notBefore / notAfter:
55
55
56 $ cat << EOT > pub-not-yet.pem
56 $ cat << EOT > pub-not-yet.pem
57 > -----BEGIN CERTIFICATE-----
57 > -----BEGIN CERTIFICATE-----
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
58 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
59 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTM1MDYwNTIwMzAxNFoXDTM1MDYw
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
60 > NTIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
61 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
62 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
63 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
64 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJXV41gWnkgC7jcpPpFRSUSZaxyzrXmD1CIqQf0WgVDb
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
65 > /12E0vR2DuZitgzUYtBaofM81aTtc0a2/YsrmqePGm0=
66 > -----END CERTIFICATE-----
66 > -----END CERTIFICATE-----
67 > EOT
67 > EOT
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
68 $ cat priv.pem pub-not-yet.pem > server-not-yet.pem
69
69
70 $ cat << EOT > pub-expired.pem
70 $ cat << EOT > pub-expired.pem
71 > -----BEGIN CERTIFICATE-----
71 > -----BEGIN CERTIFICATE-----
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
72 > MIIBqzCCAVWgAwIBAgIJANAXFFyWjGnRMA0GCSqGSIb3DQEBBQUAMDExEjAQBgNVBAMMCWxvY2Fs
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
73 > aG9zdDEbMBkGCSqGSIb3DQEJARYMaGdAbG9jYWxob3N0MB4XDTEwMTAxNDIwMzAxNFoXDTEwMTAx
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
74 > NDIwMzAxNFowMTESMBAGA1UEAwwJbG9jYWxob3N0MRswGQYJKoZIhvcNAQkBFgxoZ0Bsb2NhbGhv
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
75 > c3QwXDANBgkqhkiG9w0BAQEFAANLADBIAkEApjCWeYGrIa/Vo7LHaRF8ou0tbgHKE33Use/whCnK
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
76 > EUm34rDaXQd4lxxX6aDWg06n9tiVStAKTgQAHJY8j/xgSwIDAQABo1AwTjAdBgNVHQ4EFgQUE6sA
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
77 > +ammr24dGX0kpjxOgO45hzQwHwYDVR0jBBgwFoAUE6sA+ammr24dGX0kpjxOgO45hzQwDAYDVR0T
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
78 > BAUwAwEB/zANBgkqhkiG9w0BAQUFAANBAJfk57DTRf2nUbYaMSlVAARxMNbFGOjQhAUtY400GhKt
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
79 > 2uiKCNGKXVXD3AHWe13yHc5KttzbHQStE5Nm/DlWBWQ=
80 > -----END CERTIFICATE-----
80 > -----END CERTIFICATE-----
81 > EOT
81 > EOT
82 $ cat priv.pem pub-expired.pem > server-expired.pem
82 $ cat priv.pem pub-expired.pem > server-expired.pem
83
83
84 $ hg init test
84 $ hg init test
85 $ cd test
85 $ cd test
86 $ echo foo>foo
86 $ echo foo>foo
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
87 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
88 $ echo foo>foo.d/foo
88 $ echo foo>foo.d/foo
89 $ echo bar>foo.d/bAr.hg.d/BaR
89 $ echo bar>foo.d/bAr.hg.d/BaR
90 $ echo bar>foo.d/baR.d.hg/bAR
90 $ echo bar>foo.d/baR.d.hg/bAR
91 $ hg commit -A -m 1
91 $ hg commit -A -m 1
92 adding foo
92 adding foo
93 adding foo.d/bAr.hg.d/BaR
93 adding foo.d/bAr.hg.d/BaR
94 adding foo.d/baR.d.hg/bAR
94 adding foo.d/baR.d.hg/bAR
95 adding foo.d/foo
95 adding foo.d/foo
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
96 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
97 $ cat ../hg0.pid >> $DAEMON_PIDS
97 $ cat ../hg0.pid >> $DAEMON_PIDS
98
98
99 cacert not found
99 cacert not found
100
100
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
101 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
102 abort: could not find web.cacerts: no-such.pem
102 abort: could not find web.cacerts: no-such.pem
103 [255]
103 [255]
104
104
105 Test server address cannot be reused
105 Test server address cannot be reused
106
106
107 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
107 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
108 abort: cannot start server at ':$HGPORT': Address already in use
108 abort: cannot start server at ':$HGPORT': Address already in use
109 [255]
109 [255]
110 $ cd ..
110 $ cd ..
111
111
112 clone via pull
112 clone via pull
113
113
114 $ hg clone https://localhost:$HGPORT/ copy-pull
114 $ hg clone https://localhost:$HGPORT/ copy-pull
115 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
115 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
116 requesting all changes
116 requesting all changes
117 adding changesets
117 adding changesets
118 adding manifests
118 adding manifests
119 adding file changes
119 adding file changes
120 added 1 changesets with 4 changes to 4 files
120 added 1 changesets with 4 changes to 4 files
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
121 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
122 updating to branch default
122 updating to branch default
123 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
123 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
124 $ hg verify -R copy-pull
124 $ hg verify -R copy-pull
125 checking changesets
125 checking changesets
126 checking manifests
126 checking manifests
127 crosschecking files in changesets and manifests
127 crosschecking files in changesets and manifests
128 checking files
128 checking files
129 4 files, 1 changesets, 4 total revisions
129 4 files, 1 changesets, 4 total revisions
130 $ cd test
130 $ cd test
131 $ echo bar > bar
131 $ echo bar > bar
132 $ hg commit -A -d '1 0' -m 2
132 $ hg commit -A -d '1 0' -m 2
133 adding bar
133 adding bar
134 $ cd ..
134 $ cd ..
135
135
136 pull without cacert
136 pull without cacert
137
137
138 $ cd copy-pull
138 $ cd copy-pull
139 $ echo '[hooks]' >> .hg/hgrc
139 $ echo '[hooks]' >> .hg/hgrc
140 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
140 $ echo "changegroup = python '$TESTDIR'/printenv.py changegroup" >> .hg/hgrc
141 $ hg pull
141 $ hg pull
142 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
142 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
143 pulling from https://localhost:$HGPORT/
143 pulling from https://localhost:$HGPORT/
144 searching for changes
144 searching for changes
145 adding changesets
145 adding changesets
146 adding manifests
146 adding manifests
147 adding file changes
147 adding file changes
148 added 1 changesets with 1 changes to 1 files
148 added 1 changesets with 1 changes to 1 files
149 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
149 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
150 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
150 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=https://localhost:$HGPORT/
151 (run 'hg update' to get a working copy)
151 (run 'hg update' to get a working copy)
152 $ cd ..
152 $ cd ..
153
153
154 cacert configured in local repo
154 cacert configured in local repo
155
155
156 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
156 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
157 $ echo "[web]" >> copy-pull/.hg/hgrc
157 $ echo "[web]" >> copy-pull/.hg/hgrc
158 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
158 $ echo "cacerts=`pwd`/pub.pem" >> copy-pull/.hg/hgrc
159 $ hg -R copy-pull pull --traceback
159 $ hg -R copy-pull pull --traceback
160 pulling from https://localhost:$HGPORT/
160 pulling from https://localhost:$HGPORT/
161 searching for changes
161 searching for changes
162 no changes found
162 no changes found
163 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
163 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
164
164
165 cacert configured globally, also testing expansion of environment
165 cacert configured globally, also testing expansion of environment
166 variables in the filename
166 variables in the filename
167
167
168 $ echo "[web]" >> $HGRCPATH
168 $ echo "[web]" >> $HGRCPATH
169 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
169 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
170 $ P=`pwd` hg -R copy-pull pull
170 $ P=`pwd` hg -R copy-pull pull
171 pulling from https://localhost:$HGPORT/
171 pulling from https://localhost:$HGPORT/
172 searching for changes
172 searching for changes
173 no changes found
173 no changes found
174 $ P=`pwd` hg -R copy-pull pull --insecure
174 $ P=`pwd` hg -R copy-pull pull --insecure
175 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
175 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
176 pulling from https://localhost:$HGPORT/
176 pulling from https://localhost:$HGPORT/
177 searching for changes
177 searching for changes
178 no changes found
178 no changes found
179
179
180 cacert mismatch
180 cacert mismatch
181
181
182 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
182 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/
183 abort: 127.0.0.1 certificate error: certificate is for localhost
183 abort: 127.0.0.1 certificate error: certificate is for localhost
184 (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
184 (configure hostfingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca or use --insecure to connect insecurely)
185 [255]
185 [255]
186 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
186 $ hg -R copy-pull pull --config web.cacerts=pub.pem https://127.0.0.1:$HGPORT/ --insecure
187 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
187 warning: 127.0.0.1 certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
188 pulling from https://127.0.0.1:$HGPORT/
188 pulling from https://127.0.0.1:$HGPORT/
189 searching for changes
189 searching for changes
190 no changes found
190 no changes found
191 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
191 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem
192 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
192 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
193 [255]
193 [255]
194 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
194 $ hg -R copy-pull pull --config web.cacerts=pub-other.pem --insecure
195 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
195 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
196 pulling from https://localhost:$HGPORT/
196 pulling from https://localhost:$HGPORT/
197 searching for changes
197 searching for changes
198 no changes found
198 no changes found
199
199
200 Test server cert which isn't valid yet
200 Test server cert which isn't valid yet
201
201
202 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
202 $ hg -R test serve -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
203 $ cat hg1.pid >> $DAEMON_PIDS
203 $ cat hg1.pid >> $DAEMON_PIDS
204 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
204 $ hg -R copy-pull pull --config web.cacerts=pub-not-yet.pem https://localhost:$HGPORT1/
205 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
205 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
206 [255]
206 [255]
207
207
208 Test server cert which no longer is valid
208 Test server cert which no longer is valid
209
209
210 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
210 $ hg -R test serve -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
211 $ cat hg2.pid >> $DAEMON_PIDS
211 $ cat hg2.pid >> $DAEMON_PIDS
212 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
212 $ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
213 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
213 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
214 [255]
214 [255]
215
215
216 Fingerprints
216 Fingerprints
217
217
218 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
218 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
219 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
219 $ echo "localhost = 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca" >> copy-pull/.hg/hgrc
220 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
220 $ echo "127.0.0.1 = 914f1aff87249c09b6859b88b1906d30756491ca" >> copy-pull/.hg/hgrc
221
221
222 - works without cacerts
222 - works without cacerts
223 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
223 $ hg -R copy-pull id https://localhost:$HGPORT/ --config web.cacerts=
224 5fed3813f7f5
224 5fed3813f7f5
225
225
226 - fails when cert doesn't match hostname (port is ignored)
226 - fails when cert doesn't match hostname (port is ignored)
227 $ hg -R copy-pull id https://localhost:$HGPORT1/
227 $ hg -R copy-pull id https://localhost:$HGPORT1/
228 abort: certificate for localhost has unexpected fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
228 abort: certificate for localhost has unexpected fingerprint 28:ff:71:bf:65:31:14:23:ad:62:92:b4:0e:31:99:18:fc:83:e3:9b
229 (check hostfingerprint configuration)
229 (check hostfingerprint configuration)
230 [255]
230 [255]
231
231
232 - ignores that certificate doesn't match hostname
232 - ignores that certificate doesn't match hostname
233 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
233 $ hg -R copy-pull id https://127.0.0.1:$HGPORT/
234 5fed3813f7f5
234 5fed3813f7f5
235
235
236 $ while kill `cat hg1.pid` 2>/dev/null; do true; done
236 $ while kill `cat hg1.pid` 2>/dev/null; do sleep 0; done
237
237
238 Prepare for connecting through proxy
238 Prepare for connecting through proxy
239
239
240 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
240 $ "$TESTDIR/tinyproxy.py" $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
241 $ while [ ! -f proxy.pid ]; do true; done
241 $ while [ ! -f proxy.pid ]; do sleep 0; done
242 $ cat proxy.pid >> $DAEMON_PIDS
242 $ cat proxy.pid >> $DAEMON_PIDS
243
243
244 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
244 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
245 $ echo "always=True" >> copy-pull/.hg/hgrc
245 $ echo "always=True" >> copy-pull/.hg/hgrc
246 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
246 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
247 $ echo "localhost =" >> copy-pull/.hg/hgrc
247 $ echo "localhost =" >> copy-pull/.hg/hgrc
248
248
249 Test unvalidated https through proxy
249 Test unvalidated https through proxy
250
250
251 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
251 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure --traceback
252 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
252 warning: localhost certificate with fingerprint 91:4f:1a:ff:87:24:9c:09:b6:85:9b:88:b1:90:6d:30:75:64:91:ca not verified (check hostfingerprints or web.cacerts config setting)
253 pulling from https://localhost:$HGPORT/
253 pulling from https://localhost:$HGPORT/
254 searching for changes
254 searching for changes
255 no changes found
255 no changes found
256
256
257 Test https with cacert and fingerprint through proxy
257 Test https with cacert and fingerprint through proxy
258
258
259 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
259 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub.pem
260 pulling from https://localhost:$HGPORT/
260 pulling from https://localhost:$HGPORT/
261 searching for changes
261 searching for changes
262 no changes found
262 no changes found
263 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
263 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://127.0.0.1:$HGPORT/
264 pulling from https://127.0.0.1:$HGPORT/
264 pulling from https://127.0.0.1:$HGPORT/
265 searching for changes
265 searching for changes
266 no changes found
266 no changes found
267
267
268 Test https with cert problems through proxy
268 Test https with cert problems through proxy
269
269
270 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
270 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-other.pem
271 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
271 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
272 [255]
272 [255]
273 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
273 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --config web.cacerts=pub-expired.pem https://localhost:$HGPORT2/
274 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
274 abort: error: *:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed (glob)
275 [255]
275 [255]
General Comments 0
You need to be logged in to leave comments. Login now