OILS / test / lint.sh View on Github | oils.pub

313 lines, 174 significant
1#!/usr/bin/env bash
2#
3# Run tools to maintain the coding style.
4#
5# Usage:
6# test/lint.sh <function name>
7
8: ${LIB_OSH=stdlib/osh}
9source $LIB_OSH/bash-strict.sh
10source $LIB_OSH/task-five.sh
11
12REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
13readonly REPO_ROOT
14
15source build/common.sh
16source build/dev-shell.sh # python2 and python3
17source devtools/common.sh # banner
18
19#
20# C++
21#
22
23get-cpplint() {
24 mkdir -p _tmp
25 wget --directory _tmp \
26 https://raw.githubusercontent.com/google/styleguide/gh-pages/cpplint/cpplint.py
27 chmod +x _tmp/cpplint.py
28}
29
30cpplint() {
31 # we don't have subdir names on the header guard
32 _tmp/cpplint.py --filter \
33 -readability/todo,-legal/copyright,-build/header_guard,-build/include,-whitespace/comments "$@"
34}
35
36#
37# Space checks
38#
39
40find-tabs() {
41 devtools/repo.sh find-src-files \
42 | egrep -v 'tools/(xargs|find)' \
43 | xargs grep -n $'\t'
44}
45
46find-long-lines() {
47 # Exclude URLs
48 devtools/repo.sh find-src-files \
49 | xargs grep -n '^.\{81\}' | grep -v 'http'
50}
51
52#
53# pyflakes-based lint
54#
55
56oils-lint() {
57 local lang=$1 # py2 or py3
58 shift
59
60 PYTHONPATH=.:~/wedge/oils-for-unix.org/pkg/pyflakes/2.4.0 test/${lang}_lint.py "$@"
61 #PYTHONPATH=.:vendor/pyflakes-2.4.0 test/oils_lint.py "$@"
62}
63
64py2-lint() {
65 oils-lint py2 "$@"
66}
67
68py3-lint() {
69 oils-lint py3 "$@"
70}
71
72# TODO: Use devtools/repo.sh instead of this hard-coded list
73readonly -a CODE_DIRS=(
74 asdl bin builtin core data_lang display doctools frontend osh tools yaks ysh
75
76 prebuilt
77 pyext
78 benchmarks
79 build
80
81 #pylib
82 #test
83)
84
85py2-files-to-lint() {
86 if false; then
87 # TODO: This is better
88 # Although we should filter by $2
89
90 devtools/repo.sh py-manifest \
91 | egrep -v 'opy/|tools/find/|tools/xargs/' \
92 | awk '$1 == "py2" { print $2 }'
93 return
94 fi
95
96 for dir in "${CODE_DIRS[@]}"; do
97 for name in $dir/*.py; do
98 echo $name
99 done
100 done | grep -v 'NINJA_subgraph' # leave out for now
101}
102
103py2() {
104 banner 'Linting Python 2 code'
105
106 # syntax_abbrev.py doesn't stand alone
107 py2-files-to-lint | grep -v '_abbrev.py' | xargs $0 py2-lint
108}
109
110py3-files() {
111 for f in mycpp/*.py pea/*.py; do
112 echo $f
113 done
114}
115
116py3() {
117 banner 'Linting Python 3 code'
118
119 py3-files | xargs $0 py3-lint
120}
121
122all-py() {
123 py2
124 py3
125}
126
127#
128# More Python, including Python 3
129#
130
131mycpp-files() {
132 for f in mycpp/*.py; do
133 case $f in
134 */NINJA_subgraph.py)
135 continue
136 ;;
137 esac
138
139 echo $f
140 done
141}
142
143#
144# Main
145#
146
147# Hook for soil
148soil-run() {
149 if test -n "${TRAVIS_SKIP:-}"; then
150 echo "TRAVIS_SKIP: Skipping $0"
151 return
152 fi
153
154 #flake8-all
155
156 # Our new lint script
157 all-py
158
159 check-shebangs
160}
161
162#
163# Adjust and Check shebang lines. It matters for developers on different distros.
164#
165
166find-files-to-lint() {
167 ### Similar to find-prune / find-src-files
168
169 # don't touch mycpp yet because it's in Python 3
170 # build has build/dynamic_deps.py which needs the -S
171 find . \
172 -name '_*' -a -prune -o \
173 -name 'Python-*' -a -prune -o \
174 "$@"
175}
176
177find-py() {
178 find-files-to-lint \
179 -name 'build' -a -prune -o \
180 -name '*.py' -a -print "$@"
181}
182
183find-sh() {
184 find-files-to-lint -name '*.sh' -a -print "$@"
185}
186
187print-if-has-shebang() {
188 read first < $1
189 [[ "$first" == '#!'* ]] && echo $1
190}
191
192not-executable() {
193 find-py -a ! -executable -a -print | xargs -n 1 -- $0 print-if-has-shebang
194}
195
196executable-py() {
197 find-py -a -executable -a -print | xargs -n 1 -- echo
198}
199
200# Make all shebangs consistent.
201# - Specify python2 because on some distros 'python' is python3
202# - Use /usr/bin/env because it works better with virtualenv?
203#
204# https://stackoverflow.com/questions/9309940/sed-replace-first-line
205#
206# e.g. cat edit.list, change the first line
207
208replace-py-shebang() {
209 sed -i '1c#!/usr/bin/env python2' "$@"
210}
211
212replace-bash-shebang() {
213 sed -i '1c#!/usr/bin/env bash' "$@"
214}
215
216# NOTE: no ^ anchor because of print-first-line
217
218readonly BAD_PY='#!.*/usr/bin/python'
219readonly BAD_BASH='#!.*/bin/bash'
220
221bad-py() {
222 find-py -a -print | xargs -- egrep "$BAD_PY"
223 #grep '^#!.*/bin/bash ' */*.sh
224
225 find-py -a -print | xargs -- egrep -l "$BAD_PY" | xargs $0 replace-py-shebang
226}
227
228bad-bash() {
229 # these files don't need shebangs
230 #grep -l '^#!' spec/*.test.sh | xargs -- sed -i '1d'
231
232 #find-sh -a -print | xargs -- grep "$BAD_BASH"
233
234 find-sh -a -print | xargs -- egrep -l "$BAD_BASH" | xargs $0 replace-bash-shebang
235}
236
237print-first-line() {
238 local path=$1
239
240 read line < "$path"
241 echo "$path: $line" # like grep output
242}
243
244check-shebangs() {
245 banner 'Checking Python and shell shebang lines'
246
247 set +o errexit
248
249 if true; then
250 find-py | xargs -d $'\n' -n 1 -- $0 print-first-line | egrep "$BAD_PY"
251 if test $? -ne 1; then
252 die "FAIL: Found bad Python shebangs"
253 fi
254 fi
255
256 find-sh | xargs -d $'\n' -n 1 -- $0 print-first-line | egrep "$BAD_BASH"
257 if test $? -ne 1; then
258 die "FAIL: Found bad bash shebangs"
259 fi
260
261 echo 'PASS: check-shebangs'
262}
263
264#
265# sprintf -- What do we need in mycpp?
266#
267
268sp-formats() {
269 egrep --no-filename --only-matching '%.' */*.py | sort | uniq -c | sort -n
270}
271
272# 122 instances of these. %() for named
273sp-rare() {
274 egrep --color=always '%[^srd ]' */*.py | egrep -v 'Python-|_test.py'
275}
276
277#
278# inherit
279#
280
281# 56 instances of inheritance
282inheritance() {
283 grep ^class {osh,core,ysh,frontend}/*.py \
284 | egrep -v '_test|object'
285}
286
287# 18 unique base classes.
288# TODO: Maybe extract this automatically with OPy?
289# Or does the MyPy AST have enough?
290# You can collect method defs in the decl phase. Or in the forward_decl phase?
291
292base-classes() {
293 inheritance | egrep -o '\(.*\)' | sort | uniq -c | sort -n
294}
295
296translation() {
297 set +o errexit
298
299 metrics/source-code.sh osh-files \
300 | xargs egrep -n 'IndexError|KeyError'
301 local status=$?
302
303 echo
304
305 # 4 occurrences
306 # source builtin, core/process.py, etc.
307
308 metrics/source-code.sh osh-files \
309 | xargs egrep -n 'finally:'
310 #| xargs egrep -n -A 1 'finally:'
311}
312
313task-five "$@"