##// END OF EJS Templates
check-code.py: Check for bare ^...
Mads Kiilerich -
r10802:6e4cf831 stable
parent child Browse files
Show More
@@ -1,168 +1,169
1 1 #!/usr/bin/env python
2 2 #
3 3 # check-code - a style and portability checker for Mercurial
4 4 #
5 5 # Copyright 2010 Matt Mackall <mpm@selenic.com>
6 6 #
7 7 # This software may be used and distributed according to the terms of the
8 8 # GNU General Public License version 2 or any later version.
9 9
10 10 import sys, re, glob
11 11
12 12 def repquote(m):
13 13 t = re.sub(r"\w", "x", m.group(2))
14 14 t = re.sub(r"[^\sx]", "o", t)
15 15 return m.group(1) + t + m.group(1)
16 16
17 17 def repcomment(m):
18 18 return m.group(1) + "#" * len(m.group(2))
19 19
20 20 def repccomment(m):
21 21 t = re.sub(r"((?<=\n) )|\S", "x", m.group(2))
22 22 return m.group(1) + t + "*/"
23 23
24 24 def repcallspaces(m):
25 25 t = re.sub(r"\n\s+", "\n", m.group(2))
26 26 return m.group(1) + t
27 27
28 28 def repinclude(m):
29 29 return m.group(1) + "<foo>"
30 30
31 31 def rephere(m):
32 32 t = re.sub(r"\S", "x", m.group(2))
33 33 return m.group(1) + t
34 34
35 35
36 36 testpats = [
37 37 (r'(pushd|popd)', "don't use 'pushd' or 'popd', use 'cd'"),
38 38 (r'\W\$?\(\([^\)]*\)\)', "don't use (()) or $(()), use 'expr'"),
39 39 (r'^function', "don't use 'function', use old style"),
40 40 (r'grep.*-q', "don't use 'grep -q', redirect to /dev/null"),
41 41 (r'echo.*\\n', "don't use 'echo \\n', use printf"),
42 42 (r'^diff.*-\w*N', "don't use 'diff -N'"),
43 43 (r'(^| )wc[^|]*$', "filter wc output"),
44 44 (r'head -c', "don't use 'head -c', use 'dd'"),
45 45 (r'ls.*-\w*R', "don't use 'ls -R', use 'find'"),
46 46 (r'printf.*\\\d\d\d', "don't use 'printf \NNN', use Python"),
47 47 (r'printf.*\\x', "don't use printf \\x, use Python"),
48 48 (r'\$\(.*\)', "don't use $(expr), use `expr`"),
49 49 (r'rm -rf \*', "don't use naked rm -rf, target a directory"),
50 50 (r'(^|\|\s*)grep (-\w\s+)*[^|]*[(|]\w',
51 51 "use egrep for extended grep syntax"),
52 52 (r'/bin/', "don't use explicit paths for tools"),
53 53 (r'\$PWD', "don't use $PWD, use `pwd`"),
54 54 (r'[^\n]\Z', "no trailing newline"),
55 55 (r'export.*=', "don't export and assign at once"),
56 ('^([^"\']|("[^"]*")|(\'[^\']*\'))*\\^', "^ must be quoted"),
56 57 ]
57 58
58 59 testfilters = [
59 60 (r"( *)(#([^\n]*\S)?)", repcomment),
60 61 (r"<<(\S+)((.|\n)*?\n\1)", rephere),
61 62 ]
62 63
63 64 pypats = [
64 65 (r'^\s*\t', "don't use tabs"),
65 66 (r'\S;\s*\n', "semicolon"),
66 67 (r'\w,\w', "missing whitespace after ,"),
67 68 (r'\w[+/*\-<>]\w', "missing whitespace in expression"),
68 69 (r'^\s+\w+=\w+[^,)]$', "missing whitespace in assignment"),
69 70 (r'.{85}', "line too long"),
70 71 (r'[^\n]\Z', "no trailing newline"),
71 72 # (r'^\s+[^_ ][^_. ]+_[^_]+\s*=', "don't use underbars in identifiers"),
72 73 # (r'\w*[a-z][A-Z]\w*\s*=', "don't use camelcase in identifiers"),
73 74 (r'^\s*(if|while|def|class|except|try)\s[^[]*:\s*[^\]#\s]+',
74 75 "linebreak after :"),
75 76 (r'class\s[^(]:', "old-style class, use class foo(object)"),
76 77 (r'^\s+del\(', "del isn't a function"),
77 78 (r'^\s+except\(', "except isn't a function"),
78 79 (r',]', "unneeded trailing ',' in list"),
79 80 # (r'class\s[A-Z][^\(]*\((?!Exception)',
80 81 # "don't capitalize non-exception classes"),
81 82 # (r'in range\(', "use xrange"),
82 83 # (r'^\s*print\s+', "avoid using print in core and extensions"),
83 84 (r'[\x80-\xff]', "non-ASCII character literal"),
84 85 (r'("\')\.format\(', "str.format() not available in Python 2.4"),
85 86 (r'^\s*with\s+', "with not available in Python 2.4"),
86 87 (r'if\s.*\selse', "if ... else form not available in Python 2.4"),
87 88 (r'([\(\[]\s\S)|(\S\s[\)\]])', "gratuitous whitespace in () or []"),
88 89 # (r'\s\s=', "gratuitous whitespace before ="),
89 90 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
90 91 (r'[^>< ](\+=|-=|!=|<>|<=|>=|<<=|>>=)\s', "missing whitespace around operator"),
91 92 (r'\s(\+=|-=|!=|<>|<=|>=|<<=|>>=)\S', "missing whitespace around operator"),
92 93 (r'[^+=*!<>&| -](\s=|=\s)[^= ]', "wrong whitespace around ="),
93 94 (r'raise Exception', "don't raise generic exceptions"),
94 95 (r'ui\.(status|progress|write|note)\([\'\"]x', "unwrapped ui message"),
95 96 ]
96 97
97 98 pyfilters = [
98 99 (r"""(''')(([^']|\\'|'{1,2}(?!'))*)'''""", repquote),
99 100 (r'''(""")(([^"]|\\"|"{1,2}(?!"))*)"""''', repquote),
100 101 (r'''(?<!")(")(([^"\n]|\\")+)"(?!")''', repquote),
101 102 (r"""(?<!')(')(([^'\n]|\\')+)'(?!')""", repquote),
102 103 (r"( *)(#([^\n]*\S)?)", repcomment),
103 104 ]
104 105
105 106 cpats = [
106 107 (r'//', "don't use //-style comments"),
107 108 (r'^ ', "don't use spaces to indent"),
108 109 (r'\S\t', "don't use tabs except for indent"),
109 110 (r'(\S\s+|^\s+)\n', "trailing whitespace"),
110 111 (r'.{85}', "line too long"),
111 112 (r'(while|if|do|for)\(', "use space after while/if/do/for"),
112 113 (r'return\(', "return is not a function"),
113 114 (r' ;', "no space before ;"),
114 115 (r'\w+\* \w+', "use int *foo, not int* foo"),
115 116 (r'\([^\)]+\) \w+', "use (int)foo, not (int) foo"),
116 117 (r'\S+ (\+\+|--)', "use foo++, not foo ++"),
117 118 (r'\w,\w', "missing whitespace after ,"),
118 119 (r'\w[+/*]\w', "missing whitespace in expression"),
119 120 (r'^#\s+\w', "use #foo, not # foo"),
120 121 (r'[^\n]\Z', "no trailing newline"),
121 122 ]
122 123
123 124 cfilters = [
124 125 (r'(/\*)(((\*(?!/))|[^*])*)\*/', repccomment),
125 126 (r'''(?<!")(")(([^"]|\\")+"(?!"))''', repquote),
126 127 (r'''(#\s*include\s+<)([^>]+)>''', repinclude),
127 128 (r'(\()([^)]+\))', repcallspaces),
128 129 ]
129 130
130 131 checks = [
131 132 ('python', r'.*\.(py|cgi)$', pyfilters, pypats),
132 133 ('test script', r'(.*/)?test-[^.~]*$', testfilters, testpats),
133 134 ('c', r'.*\.c$', cfilters, cpats),
134 135 ]
135 136
136 137 if len(sys.argv) == 1:
137 138 check = glob.glob("*")
138 139 else:
139 140 check = sys.argv[1:]
140 141
141 142 for f in check:
142 143 for name, match, filters, pats in checks:
143 144 fc = 0
144 145 if not re.match(match, f):
145 146 continue
146 147 pre = post = open(f).read()
147 148 if "no-" + "check-code" in pre:
148 149 break
149 150 for p, r in filters:
150 151 post = re.sub(p, r, post)
151 152 # print post # uncomment to show filtered version
152 153 z = enumerate(zip(pre.splitlines(), post.splitlines(True)))
153 154 for n, l in z:
154 155 if "check-code" + "-ignore" in l[0]:
155 156 continue
156 157 lc = 0
157 158 for p, msg in pats:
158 159 if re.search(p, l[1]):
159 160 if not lc:
160 161 print "%s:%d:" % (f, n + 1)
161 162 print " > %s" % l[0]
162 163 print " %s" % msg
163 164 lc += 1
164 165 fc += 1
165 166 if fc == 15:
166 167 print " (too many errors, giving up)"
167 168 break
168 169 break
@@ -1,83 +1,83
1 1 #!/bin/sh
2 2
3 3 "$TESTDIR/hghave" baz || exit 80
4 4
5 5 mkdir do_not_use_HOME_baz
6 6 cd do_not_use_HOME_baz
7 7 HOME=`pwd`; export HOME
8 8 cd ..
9 9 baz my-id "mercurial <mercurial@selenic.com>"
10 10
11 11 echo "[extensions]" >> $HGRCPATH
12 12 echo "convert=" >> $HGRCPATH
13 13 echo 'graphlog =' >> $HGRCPATH
14 14
15 15 echo % create baz archive
16 16 baz make-archive baz@mercurial--convert hg-test-convert-baz
17 17
18 18 echo % initialize baz repo
19 19 mkdir baz-repo
20 20 cd baz-repo/
21 21 baz init-tree baz@mercurial--convert/baz--test--0
22 22 baz import
23 23
24 24 echo % create initial files
25 25 echo 'this is a file' > a
26 26 baz add a
27 27 mkdir src
28 28 baz add src
29 29 cd src
30 30 dd count=1 if=/dev/zero of=b > /dev/null 2> /dev/null
31 31 baz add b
32 32 # HACK: hide GNU tar-1.22 "tar: The --preserve option is deprecated, use --preserve-permissions --preserve-order instead"
33 baz commit -s "added a file, src and src/b (binary)" 2>&1 | grep -v ^tar
33 baz commit -s "added a file, src and src/b (binary)" 2>&1 | grep -v '^tar'
34 34
35 35 echo % create link file and modify a
36 36 ln -s ../a a-link
37 37 baz add a-link
38 38 echo 'this a modification to a' >> ../a
39 39 baz commit -s "added link to a and modify a"
40 40
41 41 echo % create second link and modify b
42 42 ln -s ../a a-link-2
43 43 baz add a-link-2
44 44 dd count=1 seek=1 if=/dev/zero of=b > /dev/null 2> /dev/null
45 45 baz commit -s "added second link and modify b"
46 46
47 47 echo % b file to link and a-link-2 to regular file
48 48 rm -f a-link-2
49 49 echo 'this is now a regular file' > a-link-2
50 50 ln -sf ../a b
51 51 baz commit -s "file to link and link to file test"
52 52
53 53 echo % move a-link-2 file and src directory
54 54 cd ..
55 55 baz mv src/a-link-2 c
56 56 baz mv src test
57 57 baz commit -s "move and rename a-link-2 file and src directory"
58 58
59 59 echo % move and add the moved file again
60 60 echo e > e
61 61 baz add e
62 62 baz commit -s "add e"
63 63 baz mv e f
64 64 echo ee > e
65 65 baz add e
66 66 baz commit -s "move e and recreate it again"
67 67 cd ..
68 68
69 69 echo % converting baz repo to Mercurial
70 70 hg convert baz-repo baz-repo-hg
71 71
72 72 baz register-archive -d baz@mercurial--convert
73 73
74 74 glog()
75 75 {
76 76 hg glog --template '{rev} "{desc|firstline}" files: {files}\n' "$@"
77 77 }
78 78
79 79 echo % show graph log
80 80 glog -R baz-repo-hg
81 81 hg up -q -R baz-repo-hg
82 82 hg -R baz-repo-hg manifest --debug
83 83 hg -R baz-repo-hg log -r 5 -r 7 -C --debug | grep copies
@@ -1,118 +1,118
1 1 #!/bin/sh
2 2
3 3 # This feature requires use of builtin cvsps!
4 4 "$TESTDIR/hghave" cvs || exit 80
5 5
6 6 set -e
7 7
8 8 echo "[extensions]" >> $HGRCPATH
9 9 echo "convert = " >> $HGRCPATH
10 10 echo "graphlog = " >> $HGRCPATH
11 11
12 12 echo % create cvs repository with one project
13 13 mkdir cvsrepo
14 14 cd cvsrepo
15 15 CVSROOT=`pwd`
16 16 export CVSROOT
17 17 CVS_OPTIONS=-f
18 18 export CVS_OPTIONS
19 19 cd ..
20 20
21 21 filterpath()
22 22 {
23 23 eval "$@" | sed "s:$CVSROOT:*REPO*:g"
24 24 }
25 25
26 26 cvscall()
27 27 {
28 28 echo cvs -f "$@"
29 29 cvs -f "$@" 2>&1
30 30 }
31 31
32 32 # output of 'cvs ci' varies unpredictably, so just discard it
33 33 cvsci()
34 34 {
35 35 echo cvs -f ci "$@"
36 36 cvs -f ci "$@" >/dev/null 2>&1
37 37 }
38 38
39 39 filterpath cvscall -d "$CVSROOT" init
40 40 mkdir cvsrepo/proj
41 41
42 42 cvscall -q co proj
43 43
44 44 echo % create file1 on the trunk
45 45 cd proj
46 46 touch file1
47 47 cvscall -Q add file1
48 48 cvsci -m"add file1 on trunk" file1
49 49
50 50 echo % create two branches
51 51 cvscall -q tag -b v1_0
52 52 cvscall -q tag -b v1_1
53 53
54 54 echo % create file2 on branch v1_0
55 55 cvscall -Q up -rv1_0
56 56 touch file2
57 57 cvscall -Q add file2
58 58 cvsci -m"add file2" file2
59 59
60 60 echo % create file3, file4 on branch v1_1
61 61 cvscall -Q up -rv1_1
62 62 touch file3
63 63 touch file4
64 64 cvscall -Q add file3 file4
65 65 cvsci -m"add file3, file4 on branch v1_1" file3 file4
66 66
67 67 echo % merge file2 from v1_0 to v1_1
68 68 cvscall -Q up -jv1_0
69 69 cvsci -m"MERGE from v1_0: add file2"
70 70
71 71 # Step things up a notch: now we make the history really hairy, with
72 72 # changes bouncing back and forth between trunk and v1_2 and merges
73 73 # going both ways. (I.e., try to model the real world.)
74 74
75 75 echo "% create branch v1_2"
76 76 cvscall -Q up -A
77 77 cvscall -q tag -b v1_2
78 78
79 79 echo "% create file5 on branch v1_2"
80 80 cvscall -Q up -rv1_2
81 81 touch file5
82 82 cvs -Q add file5
83 83 cvsci -m"add file5 on v1_2"
84 84
85 85 echo "% create file6 on trunk post-v1_2"
86 86 cvscall -Q up -A
87 87 touch file6
88 88 cvscall -Q add file6
89 89 cvsci -m"add file6 on trunk post-v1_2"
90 90
91 91 echo "% merge file5 from v1_2 to trunk"
92 92 cvscall -Q up -A
93 93 cvscall -Q up -jv1_2 file5
94 94 cvsci -m"MERGE from v1_2: add file5"
95 95
96 96 echo "% merge file6 from trunk to v1_2"
97 97 cvscall -Q up -rv1_2
98 98 cvscall up -jHEAD file6
99 99 cvsci -m"MERGE from HEAD: add file6"
100 100
101 101 echo % cvs rlog output
102 102 filterpath cvscall -q rlog proj | egrep '^(RCS file|revision)'
103 103
104 104 echo "% convert to hg (#1)"
105 105 cd ..
106 106 filterpath hg convert --datesort proj proj.hg
107 107
108 108 echo "% hg glog output (#1)"
109 109 hg -R proj.hg glog --template "{rev} {desc}\n"
110 110
111 111 echo "% convert to hg (#2: with merge detection)"
112 112 filterpath hg convert \
113 --config convert.cvsps.mergefrom="\"^MERGE from (\S+):\"" \
113 --config convert.cvsps.mergefrom='"^MERGE from (\S+):"' \
114 114 --datesort \
115 115 proj proj.hg2
116 116
117 117 echo "% hg glog output (#2)"
118 118 hg -R proj.hg2 glog --template "{rev} {desc}\n"
General Comments 0
You need to be logged in to leave comments. Login now