##// END OF EJS Templates
tests: use `pwd` instead of ${PWD} in test-convert-git.t - because of Solaris
Mads Kiilerich -
r18508:813b7a1f stable
parent child Browse files
Show More
@@ -1,457 +1,457 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'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
48 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
49 (r'sed.*-i', "don't use 'sed -i', use a temporary file"),
50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
50 (r'\becho\b.*\\n', "don't use 'echo \\n', use printf"),
51 (r'echo -n', "don't use 'echo -n', use printf"),
51 (r'echo -n', "don't use 'echo -n', use printf"),
52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
52 (r'(^| )wc[^|]*$\n(?!.*\(re\))', "filter wc output"),
53 (r'head -c', "don't use 'head -c', use 'dd'"),
53 (r'head -c', "don't use 'head -c', use 'dd'"),
54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
54 (r'sha1sum', "don't use sha1sum, use $TESTDIR/md5sum.py"),
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
55 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
56 (r'printf.*\\([1-9]|0\d)', "don't use 'printf \NNN', use Python"),
57 (r'printf.*\\x', "don't use printf \\x, use Python"),
57 (r'printf.*\\x', "don't use printf \\x, use Python"),
58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
58 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
59 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
60 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
61 "use egrep for extended grep syntax"),
61 "use egrep for extended grep syntax"),
62 (r'/bin/', "don't use explicit paths for tools"),
62 (r'/bin/', "don't use explicit paths for tools"),
63 (r'[^\n]\Z', "no trailing newline"),
63 (r'[^\n]\Z', "no trailing newline"),
64 (r'export.*=', "don't export and assign at once"),
64 (r'export.*=', "don't export and assign at once"),
65 (r'^source\b', "don't use 'source', use '.'"),
65 (r'^source\b', "don't use 'source', use '.'"),
66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
66 (r'touch -d', "don't use 'touch -d', use 'touch -t' instead"),
67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
67 (r'ls +[^|\n-]+ +-', "options to 'ls' must come before filenames"),
68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
68 (r'[^>\n]>\s*\$HGRCPATH', "don't overwrite $HGRCPATH, append to it"),
69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
69 (r'^stop\(\)', "don't use 'stop' as a shell function name"),
70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
70 (r'(\[|\btest\b).*-e ', "don't use 'test -e', use 'test -f'"),
71 (r'^alias\b.*=', "don't use alias, use a function"),
71 (r'^alias\b.*=', "don't use alias, use a function"),
72 (r'if\s*!', "don't use '!' to negate exit status"),
72 (r'if\s*!', "don't use '!' to negate exit status"),
73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
73 (r'/dev/u?random', "don't use entropy, use /dev/zero"),
74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
74 (r'do\s*true;\s*done', "don't use true as loop body, use sleep 0"),
75 (r'^( *)\t', "don't use tabs to indent"),
75 (r'^( *)\t', "don't use tabs to indent"),
76 ],
76 ],
77 # warnings
77 # warnings
78 [
78 [
79 (r'^function', "don't use 'function', use old style"),
79 (r'^function', "don't use 'function', use old style"),
80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
80 (r'^diff.*-\w*N', "don't use 'diff -N'"),
81 (r'\$PWD', "don't use $PWD, use `pwd`"),
81 (r'\$PWD|\${PWD}', "don't use $PWD, use `pwd`"),
82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
82 (r'^([^"\'\n]|("[^"\n]*")|(\'[^\'\n]*\'))*\^', "^ must be quoted"),
83 ]
83 ]
84 ]
84 ]
85
85
86 testfilters = [
86 testfilters = [
87 (r"( *)(#([^\n]*\S)?)", repcomment),
87 (r"( *)(#([^\n]*\S)?)", repcomment),
88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
88 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
89 ]
89 ]
90
90
91 uprefix = r"^ \$ "
91 uprefix = r"^ \$ "
92 utestpats = [
92 utestpats = [
93 [
93 [
94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
94 (r'^(\S.*|| [$>] .*)[ \t]\n', "trailing whitespace on non-output"),
95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
95 (uprefix + r'.*\|\s*sed[^|>\n]*\n',
96 "use regex test output patterns instead of sed"),
96 "use regex test output patterns instead of sed"),
97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
97 (uprefix + r'(true|exit 0)', "explicit zero exit unnecessary"),
98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
98 (uprefix + r'.*(?<!\[)\$\?', "explicit exit code checks unnecessary"),
99 (uprefix + r'.*\|\| echo.*(fail|error)',
99 (uprefix + r'.*\|\| echo.*(fail|error)',
100 "explicit exit code checks unnecessary"),
100 "explicit exit code checks unnecessary"),
101 (uprefix + r'set -e', "don't use set -e"),
101 (uprefix + r'set -e', "don't use set -e"),
102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
102 (uprefix + r'\s', "don't indent commands, use > for continued lines"),
103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
103 (r'^ saved backup bundle to \$TESTTMP.*\.hg$',
104 "use (glob) to match Windows paths too"),
104 "use (glob) to match Windows paths too"),
105 ],
105 ],
106 # warnings
106 # warnings
107 []
107 []
108 ]
108 ]
109
109
110 for i in [0, 1]:
110 for i in [0, 1]:
111 for p, m in testpats[i]:
111 for p, m in testpats[i]:
112 if p.startswith(r'^'):
112 if p.startswith(r'^'):
113 p = r"^ [$>] (%s)" % p[1:]
113 p = r"^ [$>] (%s)" % p[1:]
114 else:
114 else:
115 p = r"^ [$>] .*(%s)" % p
115 p = r"^ [$>] .*(%s)" % p
116 utestpats[i].append((p, m))
116 utestpats[i].append((p, m))
117
117
118 utestfilters = [
118 utestfilters = [
119 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
119 (r"<<(\S+)((.|\n)*?\n > \1)", rephere),
120 (r"( *)(#([^\n]*\S)?)", repcomment),
120 (r"( *)(#([^\n]*\S)?)", repcomment),
121 ]
121 ]
122
122
123 pypats = [
123 pypats = [
124 [
124 [
125 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
125 (r'^\s*def\s*\w+\s*\(.*,\s*\(',
126 "tuple parameter unpacking not available in Python 3+"),
126 "tuple parameter unpacking not available in Python 3+"),
127 (r'lambda\s*\(.*,.*\)',
127 (r'lambda\s*\(.*,.*\)',
128 "tuple parameter unpacking not available in Python 3+"),
128 "tuple parameter unpacking not available in Python 3+"),
129 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
129 (r'(?<!def)\s+(cmp)\(', "cmp is not available in Python 3+"),
130 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
130 (r'\breduce\s*\(.*', "reduce is not available in Python 3+"),
131 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
131 (r'\.has_key\b', "dict.has_key is not available in Python 3+"),
132 (r'\s<>\s', '<> operator is not available in Python 3+, use !='),
132 (r'\s<>\s', '<> operator is not available in Python 3+, use !='),
133 (r'^\s*\t', "don't use tabs"),
133 (r'^\s*\t', "don't use tabs"),
134 (r'\S;\s*\n', "semicolon"),
134 (r'\S;\s*\n', "semicolon"),
135 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
135 (r'[^_]_\("[^"]+"\s*%', "don't use % inside _()"),
136 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
136 (r"[^_]_\('[^']+'\s*%", "don't use % inside _()"),
137 (r'(\w|\)),\w', "missing whitespace after ,"),
137 (r'(\w|\)),\w', "missing whitespace after ,"),
138 (r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
138 (r'(\w|\))[+/*\-<>]\w', "missing whitespace in expression"),
139 (r'^\s+(\w|\.)+=\w[^,()\n]*$', "missing whitespace in assignment"),
139 (r'^\s+(\w|\.)+=\w[^,()\n]*$', "missing whitespace in assignment"),
140 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
140 (r'(\s+)try:\n((?:\n|\1\s.*\n)+?)\1except.*?:\n'
141 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
141 r'((?:\n|\1\s.*\n)+?)\1finally:', 'no try/except/finally in Python 2.4'),
142 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
142 (r'(\s+)try:\n((?:\n|\1\s.*\n)*?)\1\s*yield\b.*?'
143 r'((?:\n|\1\s.*\n)+?)\1finally:',
143 r'((?:\n|\1\s.*\n)+?)\1finally:',
144 'no yield inside try/finally in Python 2.4'),
144 'no yield inside try/finally in Python 2.4'),
145 (r'.{81}', "line too long"),
145 (r'.{81}', "line too long"),
146 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
146 (r' x+[xo][\'"]\n\s+[\'"]x', 'string join across lines with no space'),
147 (r'[^\n]\Z', "no trailing newline"),
147 (r'[^\n]\Z', "no trailing newline"),
148 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
148 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
149 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
149 # (r'^\s+[^_ \n][^_. \n]+_[^_\n]+\s*=',
150 # "don't use underbars in identifiers"),
150 # "don't use underbars in identifiers"),
151 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
151 (r'^\s+(self\.)?[A-za-z][a-z0-9]+[A-Z]\w* = ',
152 "don't use camelcase in identifiers"),
152 "don't use camelcase in identifiers"),
153 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
153 (r'^\s*(if|while|def|class|except|try)\s[^[\n]*:\s*[^\\n]#\s]+',
154 "linebreak after :"),
154 "linebreak after :"),
155 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
155 (r'class\s[^( \n]+:', "old-style class, use class foo(object)"),
156 (r'class\s[^( \n]+\(\):',
156 (r'class\s[^( \n]+\(\):',
157 "class foo() not available in Python 2.4, use class foo(object)"),
157 "class foo() not available in Python 2.4, use class foo(object)"),
158 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
158 (r'\b(%s)\(' % '|'.join(keyword.kwlist),
159 "Python keyword is not a function"),
159 "Python keyword is not a function"),
160 (r',]', "unneeded trailing ',' in list"),
160 (r',]', "unneeded trailing ',' in list"),
161 # (r'class\s[A-Z][^\(]*\((?!Exception)',
161 # (r'class\s[A-Z][^\(]*\((?!Exception)',
162 # "don't capitalize non-exception classes"),
162 # "don't capitalize non-exception classes"),
163 # (r'in range\(', "use xrange"),
163 # (r'in range\(', "use xrange"),
164 # (r'^\s*print\s+', "avoid using print in core and extensions"),
164 # (r'^\s*print\s+', "avoid using print in core and extensions"),
165 (r'[\x80-\xff]', "non-ASCII character literal"),
165 (r'[\x80-\xff]', "non-ASCII character literal"),
166 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
166 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
167 (r'^\s*with\s+', "with not available in Python 2.4"),
167 (r'^\s*with\s+', "with not available in Python 2.4"),
168 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
168 (r'\.isdisjoint\(', "set.isdisjoint not available in Python 2.4"),
169 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
169 (r'^\s*except.* as .*:', "except as not available in Python 2.4"),
170 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
170 (r'^\s*os\.path\.relpath', "relpath not available in Python 2.4"),
171 (r'(?<!def)\s+(any|all|format)\(',
171 (r'(?<!def)\s+(any|all|format)\(',
172 "any/all/format not available in Python 2.4"),
172 "any/all/format not available in Python 2.4"),
173 (r'(?<!def)\s+(callable)\(',
173 (r'(?<!def)\s+(callable)\(',
174 "callable not available in Python 3, use getattr(f, '__call__', None)"),
174 "callable not available in Python 3, use getattr(f, '__call__', None)"),
175 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
175 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
176 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
176 (r'^\s*(%s)\s\s' % '|'.join(keyword.kwlist),
177 "gratuitous whitespace after Python keyword"),
177 "gratuitous whitespace after Python keyword"),
178 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
178 (r'([\(\[][ \t]\S)|(\S[ \t][\)\]])', "gratuitous whitespace in () or []"),
179 # (r'\s\s=', "gratuitous whitespace before ="),
179 # (r'\s\s=', "gratuitous whitespace before ="),
180 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
180 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
181 "missing whitespace around operator"),
181 "missing whitespace around operator"),
182 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
182 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\s',
183 "missing whitespace around operator"),
183 "missing whitespace around operator"),
184 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
184 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=|%=)\S',
185 "missing whitespace around operator"),
185 "missing whitespace around operator"),
186 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
186 (r'[^^+=*/!<>&| %-](\s=|=\s)[^= ]',
187 "wrong whitespace around ="),
187 "wrong whitespace around ="),
188 (r'raise Exception', "don't raise generic exceptions"),
188 (r'raise Exception', "don't raise generic exceptions"),
189 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$',
189 (r'raise [^,(]+, (\([^\)]+\)|[^,\(\)]+)$',
190 "don't use old-style two-argument raise, use Exception(message)"),
190 "don't use old-style two-argument raise, use Exception(message)"),
191 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
191 (r' is\s+(not\s+)?["\'0-9-]', "object comparison with literal"),
192 (r' [=!]=\s+(True|False|None)',
192 (r' [=!]=\s+(True|False|None)',
193 "comparison with singleton, use 'is' or 'is not' instead"),
193 "comparison with singleton, use 'is' or 'is not' instead"),
194 (r'^\s*(while|if) [01]:',
194 (r'^\s*(while|if) [01]:',
195 "use True/False for constant Boolean expression"),
195 "use True/False for constant Boolean expression"),
196 (r'(?:(?<!def)\s+|\()hasattr',
196 (r'(?:(?<!def)\s+|\()hasattr',
197 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
197 'hasattr(foo, bar) is broken, use util.safehasattr(foo, bar) instead'),
198 (r'opener\([^)]*\).read\(',
198 (r'opener\([^)]*\).read\(',
199 "use opener.read() instead"),
199 "use opener.read() instead"),
200 (r'BaseException', 'not in Python 2.4, use Exception'),
200 (r'BaseException', 'not in Python 2.4, use Exception'),
201 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
201 (r'os\.path\.relpath', 'os.path.relpath is not in Python 2.5'),
202 (r'opener\([^)]*\).write\(',
202 (r'opener\([^)]*\).write\(',
203 "use opener.write() instead"),
203 "use opener.write() instead"),
204 (r'[\s\(](open|file)\([^)]*\)\.read\(',
204 (r'[\s\(](open|file)\([^)]*\)\.read\(',
205 "use util.readfile() instead"),
205 "use util.readfile() instead"),
206 (r'[\s\(](open|file)\([^)]*\)\.write\(',
206 (r'[\s\(](open|file)\([^)]*\)\.write\(',
207 "use util.readfile() instead"),
207 "use util.readfile() instead"),
208 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
208 (r'^[\s\(]*(open(er)?|file)\([^)]*\)',
209 "always assign an opened file to a variable, and close it afterwards"),
209 "always assign an opened file to a variable, and close it afterwards"),
210 (r'[\s\(](open|file)\([^)]*\)\.',
210 (r'[\s\(](open|file)\([^)]*\)\.',
211 "always assign an opened file to a variable, and close it afterwards"),
211 "always assign an opened file to a variable, and close it afterwards"),
212 (r'(?i)descendent', "the proper spelling is descendAnt"),
212 (r'(?i)descendent', "the proper spelling is descendAnt"),
213 (r'\.debug\(\_', "don't mark debug messages for translation"),
213 (r'\.debug\(\_', "don't mark debug messages for translation"),
214 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
214 (r'\.strip\(\)\.split\(\)', "no need to strip before splitting"),
215 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
215 (r'^\s*except\s*:', "warning: naked except clause", r'#.*re-raises'),
216 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
216 (r':\n( )*( ){1,3}[^ ]', "must indent 4 spaces"),
217 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
217 (r'ui\.(status|progress|write|note|warn)\([\'\"]x',
218 "missing _() in ui message (use () to hide false-positives)"),
218 "missing _() in ui message (use () to hide false-positives)"),
219 ],
219 ],
220 # warnings
220 # warnings
221 [
221 [
222 ]
222 ]
223 ]
223 ]
224
224
225 pyfilters = [
225 pyfilters = [
226 (r"""(?msx)(?P<comment>\#.*?$)|
226 (r"""(?msx)(?P<comment>\#.*?$)|
227 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
227 ((?P<quote>('''|\"\"\"|(?<!')'(?!')|(?<!")"(?!")))
228 (?P<text>(([^\\]|\\.)*?))
228 (?P<text>(([^\\]|\\.)*?))
229 (?P=quote))""", reppython),
229 (?P=quote))""", reppython),
230 ]
230 ]
231
231
232 cpats = [
232 cpats = [
233 [
233 [
234 (r'//', "don't use //-style comments"),
234 (r'//', "don't use //-style comments"),
235 (r'^ ', "don't use spaces to indent"),
235 (r'^ ', "don't use spaces to indent"),
236 (r'\S\t', "don't use tabs except for indent"),
236 (r'\S\t', "don't use tabs except for indent"),
237 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
237 (r'(\S[ \t]+|^[ \t]+)\n', "trailing whitespace"),
238 (r'.{81}', "line too long"),
238 (r'.{81}', "line too long"),
239 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
239 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
240 (r'return\(', "return is not a function"),
240 (r'return\(', "return is not a function"),
241 (r' ;', "no space before ;"),
241 (r' ;', "no space before ;"),
242 (r'\w+\* \w+', "use int *foo, not int* foo"),
242 (r'\w+\* \w+', "use int *foo, not int* foo"),
243 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
243 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
244 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
244 (r'\w+ (\+\+|--)', "use foo++, not foo ++"),
245 (r'\w,\w', "missing whitespace after ,"),
245 (r'\w,\w', "missing whitespace after ,"),
246 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
246 (r'^[^#]\w[+/*]\w', "missing whitespace in expression"),
247 (r'^#\s+\w', "use #foo, not # foo"),
247 (r'^#\s+\w', "use #foo, not # foo"),
248 (r'[^\n]\Z', "no trailing newline"),
248 (r'[^\n]\Z', "no trailing newline"),
249 (r'^\s*#import\b', "use only #include in standard C code"),
249 (r'^\s*#import\b', "use only #include in standard C code"),
250 ],
250 ],
251 # warnings
251 # warnings
252 []
252 []
253 ]
253 ]
254
254
255 cfilters = [
255 cfilters = [
256 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
256 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
257 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
257 (r'''(?P<quote>(?<!")")(?P<text>([^"]|\\")+)"(?!")''', repquote),
258 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
258 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
259 (r'(\()([^)]+\))', repcallspaces),
259 (r'(\()([^)]+\))', repcallspaces),
260 ]
260 ]
261
261
262 inutilpats = [
262 inutilpats = [
263 [
263 [
264 (r'\bui\.', "don't use ui in util"),
264 (r'\bui\.', "don't use ui in util"),
265 ],
265 ],
266 # warnings
266 # warnings
267 []
267 []
268 ]
268 ]
269
269
270 inrevlogpats = [
270 inrevlogpats = [
271 [
271 [
272 (r'\brepo\.', "don't use repo in revlog"),
272 (r'\brepo\.', "don't use repo in revlog"),
273 ],
273 ],
274 # warnings
274 # warnings
275 []
275 []
276 ]
276 ]
277
277
278 checks = [
278 checks = [
279 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
279 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
280 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
280 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
281 ('c', r'.*\.c$', cfilters, cpats),
281 ('c', r'.*\.c$', cfilters, cpats),
282 ('unified test', r'.*\.t$', utestfilters, utestpats),
282 ('unified test', r'.*\.t$', utestfilters, utestpats),
283 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
283 ('layering violation repo in revlog', r'mercurial/revlog\.py', pyfilters,
284 inrevlogpats),
284 inrevlogpats),
285 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
285 ('layering violation ui in util', r'mercurial/util\.py', pyfilters,
286 inutilpats),
286 inutilpats),
287 ]
287 ]
288
288
289 class norepeatlogger(object):
289 class norepeatlogger(object):
290 def __init__(self):
290 def __init__(self):
291 self._lastseen = None
291 self._lastseen = None
292
292
293 def log(self, fname, lineno, line, msg, blame):
293 def log(self, fname, lineno, line, msg, blame):
294 """print error related a to given line of a given file.
294 """print error related a to given line of a given file.
295
295
296 The faulty line will also be printed but only once in the case
296 The faulty line will also be printed but only once in the case
297 of multiple errors.
297 of multiple errors.
298
298
299 :fname: filename
299 :fname: filename
300 :lineno: line number
300 :lineno: line number
301 :line: actual content of the line
301 :line: actual content of the line
302 :msg: error message
302 :msg: error message
303 """
303 """
304 msgid = fname, lineno, line
304 msgid = fname, lineno, line
305 if msgid != self._lastseen:
305 if msgid != self._lastseen:
306 if blame:
306 if blame:
307 print "%s:%d (%s):" % (fname, lineno, blame)
307 print "%s:%d (%s):" % (fname, lineno, blame)
308 else:
308 else:
309 print "%s:%d:" % (fname, lineno)
309 print "%s:%d:" % (fname, lineno)
310 print " > %s" % line
310 print " > %s" % line
311 self._lastseen = msgid
311 self._lastseen = msgid
312 print " " + msg
312 print " " + msg
313
313
314 _defaultlogger = norepeatlogger()
314 _defaultlogger = norepeatlogger()
315
315
316 def getblame(f):
316 def getblame(f):
317 lines = []
317 lines = []
318 for l in os.popen('hg annotate -un %s' % f):
318 for l in os.popen('hg annotate -un %s' % f):
319 start, line = l.split(':', 1)
319 start, line = l.split(':', 1)
320 user, rev = start.split()
320 user, rev = start.split()
321 lines.append((line[1:-1], user, rev))
321 lines.append((line[1:-1], user, rev))
322 return lines
322 return lines
323
323
324 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
324 def checkfile(f, logfunc=_defaultlogger.log, maxerr=None, warnings=False,
325 blame=False, debug=False, lineno=True):
325 blame=False, debug=False, lineno=True):
326 """checks style and portability of a given file
326 """checks style and portability of a given file
327
327
328 :f: filepath
328 :f: filepath
329 :logfunc: function used to report error
329 :logfunc: function used to report error
330 logfunc(filename, linenumber, linecontent, errormessage)
330 logfunc(filename, linenumber, linecontent, errormessage)
331 :maxerr: number of error to display before aborting.
331 :maxerr: number of error to display before aborting.
332 Set to false (default) to report all errors
332 Set to false (default) to report all errors
333
333
334 return True if no error is found, False otherwise.
334 return True if no error is found, False otherwise.
335 """
335 """
336 blamecache = None
336 blamecache = None
337 result = True
337 result = True
338 for name, match, filters, pats in checks:
338 for name, match, filters, pats in checks:
339 if debug:
339 if debug:
340 print name, f
340 print name, f
341 fc = 0
341 fc = 0
342 if not re.match(match, f):
342 if not re.match(match, f):
343 if debug:
343 if debug:
344 print "Skipping %s for %s it doesn't match %s" % (
344 print "Skipping %s for %s it doesn't match %s" % (
345 name, match, f)
345 name, match, f)
346 continue
346 continue
347 fp = open(f)
347 fp = open(f)
348 pre = post = fp.read()
348 pre = post = fp.read()
349 fp.close()
349 fp.close()
350 if "no-" + "check-code" in pre:
350 if "no-" + "check-code" in pre:
351 if debug:
351 if debug:
352 print "Skipping %s for %s it has no- and check-code" % (
352 print "Skipping %s for %s it has no- and check-code" % (
353 name, f)
353 name, f)
354 break
354 break
355 for p, r in filters:
355 for p, r in filters:
356 post = re.sub(p, r, post)
356 post = re.sub(p, r, post)
357 if warnings:
357 if warnings:
358 pats = pats[0] + pats[1]
358 pats = pats[0] + pats[1]
359 else:
359 else:
360 pats = pats[0]
360 pats = pats[0]
361 # print post # uncomment to show filtered version
361 # print post # uncomment to show filtered version
362
362
363 if debug:
363 if debug:
364 print "Checking %s for %s" % (name, f)
364 print "Checking %s for %s" % (name, f)
365
365
366 prelines = None
366 prelines = None
367 errors = []
367 errors = []
368 for pat in pats:
368 for pat in pats:
369 if len(pat) == 3:
369 if len(pat) == 3:
370 p, msg, ignore = pat
370 p, msg, ignore = pat
371 else:
371 else:
372 p, msg = pat
372 p, msg = pat
373 ignore = None
373 ignore = None
374
374
375 # fix-up regexes for multi-line searches
375 # fix-up regexes for multi-line searches
376 po = p
376 po = p
377 # \s doesn't match \n
377 # \s doesn't match \n
378 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
378 p = re.sub(r'(?<!\\)\\s', r'[ \\t]', p)
379 # [^...] doesn't match newline
379 # [^...] doesn't match newline
380 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
380 p = re.sub(r'(?<!\\)\[\^', r'[^\\n', p)
381
381
382 #print po, '=>', p
382 #print po, '=>', p
383
383
384 pos = 0
384 pos = 0
385 n = 0
385 n = 0
386 for m in re.finditer(p, post, re.MULTILINE):
386 for m in re.finditer(p, post, re.MULTILINE):
387 if prelines is None:
387 if prelines is None:
388 prelines = pre.splitlines()
388 prelines = pre.splitlines()
389 postlines = post.splitlines(True)
389 postlines = post.splitlines(True)
390
390
391 start = m.start()
391 start = m.start()
392 while n < len(postlines):
392 while n < len(postlines):
393 step = len(postlines[n])
393 step = len(postlines[n])
394 if pos + step > start:
394 if pos + step > start:
395 break
395 break
396 pos += step
396 pos += step
397 n += 1
397 n += 1
398 l = prelines[n]
398 l = prelines[n]
399
399
400 if "check-code" + "-ignore" in l:
400 if "check-code" + "-ignore" in l:
401 if debug:
401 if debug:
402 print "Skipping %s for %s:%s (check-code -ignore)" % (
402 print "Skipping %s for %s:%s (check-code -ignore)" % (
403 name, f, n)
403 name, f, n)
404 continue
404 continue
405 elif ignore and re.search(ignore, l, re.MULTILINE):
405 elif ignore and re.search(ignore, l, re.MULTILINE):
406 continue
406 continue
407 bd = ""
407 bd = ""
408 if blame:
408 if blame:
409 bd = 'working directory'
409 bd = 'working directory'
410 if not blamecache:
410 if not blamecache:
411 blamecache = getblame(f)
411 blamecache = getblame(f)
412 if n < len(blamecache):
412 if n < len(blamecache):
413 bl, bu, br = blamecache[n]
413 bl, bu, br = blamecache[n]
414 if bl == l:
414 if bl == l:
415 bd = '%s@%s' % (bu, br)
415 bd = '%s@%s' % (bu, br)
416 errors.append((f, lineno and n + 1, l, msg, bd))
416 errors.append((f, lineno and n + 1, l, msg, bd))
417 result = False
417 result = False
418
418
419 errors.sort()
419 errors.sort()
420 for e in errors:
420 for e in errors:
421 logfunc(*e)
421 logfunc(*e)
422 fc += 1
422 fc += 1
423 if maxerr and fc >= maxerr:
423 if maxerr and fc >= maxerr:
424 print " (too many errors, giving up)"
424 print " (too many errors, giving up)"
425 break
425 break
426
426
427 return result
427 return result
428
428
429 if __name__ == "__main__":
429 if __name__ == "__main__":
430 parser = optparse.OptionParser("%prog [options] [files]")
430 parser = optparse.OptionParser("%prog [options] [files]")
431 parser.add_option("-w", "--warnings", action="store_true",
431 parser.add_option("-w", "--warnings", action="store_true",
432 help="include warning-level checks")
432 help="include warning-level checks")
433 parser.add_option("-p", "--per-file", type="int",
433 parser.add_option("-p", "--per-file", type="int",
434 help="max warnings per file")
434 help="max warnings per file")
435 parser.add_option("-b", "--blame", action="store_true",
435 parser.add_option("-b", "--blame", action="store_true",
436 help="use annotate to generate blame info")
436 help="use annotate to generate blame info")
437 parser.add_option("", "--debug", action="store_true",
437 parser.add_option("", "--debug", action="store_true",
438 help="show debug information")
438 help="show debug information")
439 parser.add_option("", "--nolineno", action="store_false",
439 parser.add_option("", "--nolineno", action="store_false",
440 dest='lineno', help="don't show line numbers")
440 dest='lineno', help="don't show line numbers")
441
441
442 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
442 parser.set_defaults(per_file=15, warnings=False, blame=False, debug=False,
443 lineno=True)
443 lineno=True)
444 (options, args) = parser.parse_args()
444 (options, args) = parser.parse_args()
445
445
446 if len(args) == 0:
446 if len(args) == 0:
447 check = glob.glob("*")
447 check = glob.glob("*")
448 else:
448 else:
449 check = args
449 check = args
450
450
451 ret = 0
451 ret = 0
452 for f in check:
452 for f in check:
453 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
453 if not checkfile(f, maxerr=options.per_file, warnings=options.warnings,
454 blame=options.blame, debug=options.debug,
454 blame=options.blame, debug=options.debug,
455 lineno=options.lineno):
455 lineno=options.lineno):
456 ret = 1
456 ret = 1
457 sys.exit(ret)
457 sys.exit(ret)
@@ -1,347 +1,347 b''
1
1
2 $ "$TESTDIR/hghave" git || exit 80
2 $ "$TESTDIR/hghave" git || exit 80
3 $ echo "[core]" >> $HOME/.gitconfig
3 $ echo "[core]" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
4 $ echo "autocrlf = false" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
5 $ echo "[core]" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
6 $ echo "autocrlf = false" >> $HOME/.gitconfig
7 $ echo "[extensions]" >> $HGRCPATH
7 $ echo "[extensions]" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
8 $ echo "convert=" >> $HGRCPATH
9 $ echo 'hgext.graphlog =' >> $HGRCPATH
9 $ echo 'hgext.graphlog =' >> $HGRCPATH
10 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
10 $ GIT_AUTHOR_NAME='test'; export GIT_AUTHOR_NAME
11 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
11 $ GIT_AUTHOR_EMAIL='test@example.org'; export GIT_AUTHOR_EMAIL
12 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
12 $ GIT_AUTHOR_DATE="2007-01-01 00:00:00 +0000"; export GIT_AUTHOR_DATE
13 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
13 $ GIT_COMMITTER_NAME="$GIT_AUTHOR_NAME"; export GIT_COMMITTER_NAME
14 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
14 $ GIT_COMMITTER_EMAIL="$GIT_AUTHOR_EMAIL"; export GIT_COMMITTER_EMAIL
15 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
15 $ GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"; export GIT_COMMITTER_DATE
16 $ count=10
16 $ count=10
17 $ commit()
17 $ commit()
18 > {
18 > {
19 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
19 > GIT_AUTHOR_DATE="2007-01-01 00:00:$count +0000"
20 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
20 > GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"
21 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
21 > git commit "$@" >/dev/null 2>/dev/null || echo "git commit error"
22 > count=`expr $count + 1`
22 > count=`expr $count + 1`
23 > }
23 > }
24 $ mkdir git-repo
24 $ mkdir git-repo
25 $ cd git-repo
25 $ cd git-repo
26 $ git init-db >/dev/null 2>/dev/null
26 $ git init-db >/dev/null 2>/dev/null
27 $ echo a > a
27 $ echo a > a
28 $ mkdir d
28 $ mkdir d
29 $ echo b > d/b
29 $ echo b > d/b
30 $ git add a d
30 $ git add a d
31 $ commit -a -m t1
31 $ commit -a -m t1
32
32
33 Remove the directory, then try to replace it with a file
33 Remove the directory, then try to replace it with a file
34 (issue 754)
34 (issue 754)
35
35
36 $ git rm -f d/b
36 $ git rm -f d/b
37 rm 'd/b'
37 rm 'd/b'
38 $ commit -m t2
38 $ commit -m t2
39 $ echo d > d
39 $ echo d > d
40 $ git add d
40 $ git add d
41 $ commit -m t3
41 $ commit -m t3
42 $ echo b >> a
42 $ echo b >> a
43 $ commit -a -m t4.1
43 $ commit -a -m t4.1
44 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
44 $ git checkout -b other HEAD~ >/dev/null 2>/dev/null
45 $ echo c > a
45 $ echo c > a
46 $ echo a >> a
46 $ echo a >> a
47 $ commit -a -m t4.2
47 $ commit -a -m t4.2
48 $ git checkout master >/dev/null 2>/dev/null
48 $ git checkout master >/dev/null 2>/dev/null
49 $ git pull --no-commit . other > /dev/null 2>/dev/null
49 $ git pull --no-commit . other > /dev/null 2>/dev/null
50 $ commit -m 'Merge branch other'
50 $ commit -m 'Merge branch other'
51 $ cd ..
51 $ cd ..
52 $ hg convert --datesort git-repo
52 $ hg convert --datesort git-repo
53 assuming destination git-repo-hg
53 assuming destination git-repo-hg
54 initializing destination git-repo-hg repository
54 initializing destination git-repo-hg repository
55 scanning source...
55 scanning source...
56 sorting...
56 sorting...
57 converting...
57 converting...
58 5 t1
58 5 t1
59 4 t2
59 4 t2
60 3 t3
60 3 t3
61 2 t4.1
61 2 t4.1
62 1 t4.2
62 1 t4.2
63 0 Merge branch other
63 0 Merge branch other
64 updating bookmarks
64 updating bookmarks
65 $ hg up -q -R git-repo-hg
65 $ hg up -q -R git-repo-hg
66 $ hg -R git-repo-hg tip -v
66 $ hg -R git-repo-hg tip -v
67 changeset: 5:c78094926be2
67 changeset: 5:c78094926be2
68 bookmark: master
68 bookmark: master
69 tag: tip
69 tag: tip
70 parent: 3:f5f5cb45432b
70 parent: 3:f5f5cb45432b
71 parent: 4:4e174f80c67c
71 parent: 4:4e174f80c67c
72 user: test <test@example.org>
72 user: test <test@example.org>
73 date: Mon Jan 01 00:00:15 2007 +0000
73 date: Mon Jan 01 00:00:15 2007 +0000
74 files: a
74 files: a
75 description:
75 description:
76 Merge branch other
76 Merge branch other
77
77
78
78
79 $ count=10
79 $ count=10
80 $ mkdir git-repo2
80 $ mkdir git-repo2
81 $ cd git-repo2
81 $ cd git-repo2
82 $ git init-db >/dev/null 2>/dev/null
82 $ git init-db >/dev/null 2>/dev/null
83 $ echo foo > foo
83 $ echo foo > foo
84 $ git add foo
84 $ git add foo
85 $ commit -a -m 'add foo'
85 $ commit -a -m 'add foo'
86 $ echo >> foo
86 $ echo >> foo
87 $ commit -a -m 'change foo'
87 $ commit -a -m 'change foo'
88 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
88 $ git checkout -b Bar HEAD~ >/dev/null 2>/dev/null
89 $ echo quux >> quux
89 $ echo quux >> quux
90 $ git add quux
90 $ git add quux
91 $ commit -a -m 'add quux'
91 $ commit -a -m 'add quux'
92 $ echo bar > bar
92 $ echo bar > bar
93 $ git add bar
93 $ git add bar
94 $ commit -a -m 'add bar'
94 $ commit -a -m 'add bar'
95 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
95 $ git checkout -b Baz HEAD~ >/dev/null 2>/dev/null
96 $ echo baz > baz
96 $ echo baz > baz
97 $ git add baz
97 $ git add baz
98 $ commit -a -m 'add baz'
98 $ commit -a -m 'add baz'
99 $ git checkout master >/dev/null 2>/dev/null
99 $ git checkout master >/dev/null 2>/dev/null
100 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
100 $ git pull --no-commit . Bar Baz > /dev/null 2>/dev/null
101 $ commit -m 'Octopus merge'
101 $ commit -m 'Octopus merge'
102 $ echo bar >> bar
102 $ echo bar >> bar
103 $ commit -a -m 'change bar'
103 $ commit -a -m 'change bar'
104 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
104 $ git checkout -b Foo HEAD~ >/dev/null 2>/dev/null
105 $ echo >> foo
105 $ echo >> foo
106 $ commit -a -m 'change foo'
106 $ commit -a -m 'change foo'
107 $ git checkout master >/dev/null 2>/dev/null
107 $ git checkout master >/dev/null 2>/dev/null
108 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
108 $ git pull --no-commit -s ours . Foo > /dev/null 2>/dev/null
109 $ commit -m 'Discard change to foo'
109 $ commit -m 'Discard change to foo'
110 $ cd ..
110 $ cd ..
111 $ glog()
111 $ glog()
112 > {
112 > {
113 > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
113 > hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
114 > }
114 > }
115 $ splitrepo()
115 $ splitrepo()
116 > {
116 > {
117 > msg="$1"
117 > msg="$1"
118 > files="$2"
118 > files="$2"
119 > opts=$3
119 > opts=$3
120 > echo "% $files: $msg"
120 > echo "% $files: $msg"
121 > prefix=`echo "$files" | sed -e 's/ /-/g'`
121 > prefix=`echo "$files" | sed -e 's/ /-/g'`
122 > fmap="$prefix.fmap"
122 > fmap="$prefix.fmap"
123 > repo="$prefix.repo"
123 > repo="$prefix.repo"
124 > for i in $files; do
124 > for i in $files; do
125 > echo "include $i" >> "$fmap"
125 > echo "include $i" >> "$fmap"
126 > done
126 > done
127 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
127 > hg -q convert $opts --filemap "$fmap" --datesort git-repo2 "$repo"
128 > hg up -q -R "$repo"
128 > hg up -q -R "$repo"
129 > glog -R "$repo"
129 > glog -R "$repo"
130 > hg -R "$repo" manifest --debug
130 > hg -R "$repo" manifest --debug
131 > }
131 > }
132
132
133 full conversion
133 full conversion
134
134
135 $ hg -q convert --datesort git-repo2 fullrepo
135 $ hg -q convert --datesort git-repo2 fullrepo
136 $ hg up -q -R fullrepo
136 $ hg up -q -R fullrepo
137 $ glog -R fullrepo
137 $ glog -R fullrepo
138 @ 9 "Discard change to foo" files: foo
138 @ 9 "Discard change to foo" files: foo
139 |\
139 |\
140 | o 8 "change foo" files: foo
140 | o 8 "change foo" files: foo
141 | |
141 | |
142 o | 7 "change bar" files: bar
142 o | 7 "change bar" files: bar
143 |/
143 |/
144 o 6 "(octopus merge fixup)" files:
144 o 6 "(octopus merge fixup)" files:
145 |\
145 |\
146 | o 5 "Octopus merge" files: baz
146 | o 5 "Octopus merge" files: baz
147 | |\
147 | |\
148 o | | 4 "add baz" files: baz
148 o | | 4 "add baz" files: baz
149 | | |
149 | | |
150 +---o 3 "add bar" files: bar
150 +---o 3 "add bar" files: bar
151 | |
151 | |
152 o | 2 "add quux" files: quux
152 o | 2 "add quux" files: quux
153 | |
153 | |
154 | o 1 "change foo" files: foo
154 | o 1 "change foo" files: foo
155 |/
155 |/
156 o 0 "add foo" files: foo
156 o 0 "add foo" files: foo
157
157
158 $ hg -R fullrepo manifest --debug
158 $ hg -R fullrepo manifest --debug
159 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
159 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
160 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
160 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
161 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
161 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
162 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
162 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
163 $ splitrepo 'octopus merge' 'foo bar baz'
163 $ splitrepo 'octopus merge' 'foo bar baz'
164 % foo bar baz: octopus merge
164 % foo bar baz: octopus merge
165 @ 8 "Discard change to foo" files: foo
165 @ 8 "Discard change to foo" files: foo
166 |\
166 |\
167 | o 7 "change foo" files: foo
167 | o 7 "change foo" files: foo
168 | |
168 | |
169 o | 6 "change bar" files: bar
169 o | 6 "change bar" files: bar
170 |/
170 |/
171 o 5 "(octopus merge fixup)" files:
171 o 5 "(octopus merge fixup)" files:
172 |\
172 |\
173 | o 4 "Octopus merge" files: baz
173 | o 4 "Octopus merge" files: baz
174 | |\
174 | |\
175 o | | 3 "add baz" files: baz
175 o | | 3 "add baz" files: baz
176 | | |
176 | | |
177 +---o 2 "add bar" files: bar
177 +---o 2 "add bar" files: bar
178 | |
178 | |
179 | o 1 "change foo" files: foo
179 | o 1 "change foo" files: foo
180 |/
180 |/
181 o 0 "add foo" files: foo
181 o 0 "add foo" files: foo
182
182
183 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
183 245a3b8bc653999c2b22cdabd517ccb47aecafdf 644 bar
184 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
184 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
185 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
185 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
186 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
186 $ splitrepo 'only some parents of an octopus merge; "discard" a head' 'foo baz quux'
187 % foo baz quux: only some parents of an octopus merge; "discard" a head
187 % foo baz quux: only some parents of an octopus merge; "discard" a head
188 @ 6 "Discard change to foo" files: foo
188 @ 6 "Discard change to foo" files: foo
189 |
189 |
190 o 5 "change foo" files: foo
190 o 5 "change foo" files: foo
191 |
191 |
192 o 4 "Octopus merge" files:
192 o 4 "Octopus merge" files:
193 |\
193 |\
194 | o 3 "add baz" files: baz
194 | o 3 "add baz" files: baz
195 | |
195 | |
196 | o 2 "add quux" files: quux
196 | o 2 "add quux" files: quux
197 | |
197 | |
198 o | 1 "change foo" files: foo
198 o | 1 "change foo" files: foo
199 |/
199 |/
200 o 0 "add foo" files: foo
200 o 0 "add foo" files: foo
201
201
202 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
202 354ae8da6e890359ef49ade27b68bbc361f3ca88 644 baz
203 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
203 9277c9cc8dd4576fc01a17939b4351e5ada93466 644 foo
204 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
204 88dfeab657e8cf2cef3dec67b914f49791ae76b1 644 quux
205
205
206 test binary conversion (issue 1359)
206 test binary conversion (issue 1359)
207
207
208 $ mkdir git-repo3
208 $ mkdir git-repo3
209 $ cd git-repo3
209 $ cd git-repo3
210 $ git init-db >/dev/null 2>/dev/null
210 $ git init-db >/dev/null 2>/dev/null
211 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
211 $ python -c 'file("b", "wb").write("".join([chr(i) for i in range(256)])*16)'
212 $ git add b
212 $ git add b
213 $ commit -a -m addbinary
213 $ commit -a -m addbinary
214 $ cd ..
214 $ cd ..
215
215
216 convert binary file
216 convert binary file
217
217
218 $ hg convert git-repo3 git-repo3-hg
218 $ hg convert git-repo3 git-repo3-hg
219 initializing destination git-repo3-hg repository
219 initializing destination git-repo3-hg repository
220 scanning source...
220 scanning source...
221 sorting...
221 sorting...
222 converting...
222 converting...
223 0 addbinary
223 0 addbinary
224 updating bookmarks
224 updating bookmarks
225 $ cd git-repo3-hg
225 $ cd git-repo3-hg
226 $ hg up -C
226 $ hg up -C
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
227 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
228 $ python -c 'print len(file("b", "rb").read())'
228 $ python -c 'print len(file("b", "rb").read())'
229 4096
229 4096
230 $ cd ..
230 $ cd ..
231
231
232 test author vs committer
232 test author vs committer
233
233
234 $ mkdir git-repo4
234 $ mkdir git-repo4
235 $ cd git-repo4
235 $ cd git-repo4
236 $ git init-db >/dev/null 2>/dev/null
236 $ git init-db >/dev/null 2>/dev/null
237 $ echo >> foo
237 $ echo >> foo
238 $ git add foo
238 $ git add foo
239 $ commit -a -m addfoo
239 $ commit -a -m addfoo
240 $ echo >> foo
240 $ echo >> foo
241 $ GIT_AUTHOR_NAME="nottest"
241 $ GIT_AUTHOR_NAME="nottest"
242 $ commit -a -m addfoo2
242 $ commit -a -m addfoo2
243 $ cd ..
243 $ cd ..
244
244
245 convert author committer
245 convert author committer
246
246
247 $ hg convert git-repo4 git-repo4-hg
247 $ hg convert git-repo4 git-repo4-hg
248 initializing destination git-repo4-hg repository
248 initializing destination git-repo4-hg repository
249 scanning source...
249 scanning source...
250 sorting...
250 sorting...
251 converting...
251 converting...
252 1 addfoo
252 1 addfoo
253 0 addfoo2
253 0 addfoo2
254 updating bookmarks
254 updating bookmarks
255 $ hg -R git-repo4-hg log -v
255 $ hg -R git-repo4-hg log -v
256 changeset: 1:d63e967f93da
256 changeset: 1:d63e967f93da
257 bookmark: master
257 bookmark: master
258 tag: tip
258 tag: tip
259 user: nottest <test@example.org>
259 user: nottest <test@example.org>
260 date: Mon Jan 01 00:00:21 2007 +0000
260 date: Mon Jan 01 00:00:21 2007 +0000
261 files: foo
261 files: foo
262 description:
262 description:
263 addfoo2
263 addfoo2
264
264
265 committer: test <test@example.org>
265 committer: test <test@example.org>
266
266
267
267
268 changeset: 0:0735477b0224
268 changeset: 0:0735477b0224
269 user: test <test@example.org>
269 user: test <test@example.org>
270 date: Mon Jan 01 00:00:20 2007 +0000
270 date: Mon Jan 01 00:00:20 2007 +0000
271 files: foo
271 files: foo
272 description:
272 description:
273 addfoo
273 addfoo
274
274
275
275
276
276
277 --sourceorder should fail
277 --sourceorder should fail
278
278
279 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
279 $ hg convert --sourcesort git-repo4 git-repo4-sourcesort-hg
280 initializing destination git-repo4-sourcesort-hg repository
280 initializing destination git-repo4-sourcesort-hg repository
281 abort: --sourcesort is not supported by this data source
281 abort: --sourcesort is not supported by this data source
282 [255]
282 [255]
283
283
284 damage git repository and convert again
284 damage git repository and convert again
285
285
286 $ cat > damage.py <<EOF
286 $ cat > damage.py <<EOF
287 > import os
287 > import os
288 > import stat
288 > import stat
289 > for root, dirs, files in os.walk('git-repo4/.git/objects'):
289 > for root, dirs, files in os.walk('git-repo4/.git/objects'):
290 > if files:
290 > if files:
291 > path = os.path.join(root, files[0])
291 > path = os.path.join(root, files[0])
292 > if os.name == 'nt':
292 > if os.name == 'nt':
293 > os.chmod(path, stat.S_IWUSR)
293 > os.chmod(path, stat.S_IWUSR)
294 > os.remove(path)
294 > os.remove(path)
295 > break
295 > break
296 > EOF
296 > EOF
297 $ python damage.py
297 $ python damage.py
298 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
298 $ hg convert git-repo4 git-repo4-broken-hg 2>&1 | \
299 > grep 'abort:' | sed 's/abort:.*/abort:/g'
299 > grep 'abort:' | sed 's/abort:.*/abort:/g'
300 abort:
300 abort:
301
301
302 test sub modules
302 test sub modules
303
303
304 $ mkdir git-repo5
304 $ mkdir git-repo5
305 $ cd git-repo5
305 $ cd git-repo5
306 $ git init-db >/dev/null 2>/dev/null
306 $ git init-db >/dev/null 2>/dev/null
307 $ echo 'sub' >> foo
307 $ echo 'sub' >> foo
308 $ git add foo
308 $ git add foo
309 $ commit -a -m 'addfoo'
309 $ commit -a -m 'addfoo'
310 $ BASE=${PWD}
310 $ BASE=`pwd`
311 $ cd ..
311 $ cd ..
312 $ mkdir git-repo6
312 $ mkdir git-repo6
313 $ cd git-repo6
313 $ cd git-repo6
314 $ git init-db >/dev/null 2>/dev/null
314 $ git init-db >/dev/null 2>/dev/null
315 $ git submodule add ${BASE} >/dev/null 2>/dev/null
315 $ git submodule add ${BASE} >/dev/null 2>/dev/null
316 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
316 $ commit -a -m 'addsubmodule' >/dev/null 2>/dev/null
317 $ cd ..
317 $ cd ..
318
318
319 convert sub modules
319 convert sub modules
320 $ hg convert git-repo6 git-repo6-hg
320 $ hg convert git-repo6 git-repo6-hg
321 initializing destination git-repo6-hg repository
321 initializing destination git-repo6-hg repository
322 scanning source...
322 scanning source...
323 sorting...
323 sorting...
324 converting...
324 converting...
325 0 addsubmodule
325 0 addsubmodule
326 updating bookmarks
326 updating bookmarks
327 $ hg -R git-repo6-hg log -v
327 $ hg -R git-repo6-hg log -v
328 changeset: 0:* (glob)
328 changeset: 0:* (glob)
329 bookmark: master
329 bookmark: master
330 tag: tip
330 tag: tip
331 user: nottest <test@example.org>
331 user: nottest <test@example.org>
332 date: Mon Jan 01 00:00:23 2007 +0000
332 date: Mon Jan 01 00:00:23 2007 +0000
333 files: .hgsub .hgsubstate
333 files: .hgsub .hgsubstate
334 description:
334 description:
335 addsubmodule
335 addsubmodule
336
336
337 committer: test <test@example.org>
337 committer: test <test@example.org>
338
338
339
339
340
340
341 $ cd git-repo6-hg
341 $ cd git-repo6-hg
342 $ hg up >/dev/null 2>/dev/null
342 $ hg up >/dev/null 2>/dev/null
343 $ cat .hgsubstate
343 $ cat .hgsubstate
344 * git-repo5 (glob)
344 * git-repo5 (glob)
345 $ cd git-repo5
345 $ cd git-repo5
346 $ cat foo
346 $ cat foo
347 sub
347 sub
General Comments 0
You need to be logged in to leave comments. Login now