OILS / test / lint.sh View on Github | oilshell.org

312 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 lazylex
79 benchmarks
80 build
81
82 #pylib
83 #test
84)
85
86py2-files-to-lint() {
87 if false; then
88 # TODO: This is better
89 # Although we should filter by $2
90
91 devtools/repo.sh py-manifest \
92 | egrep -v 'opy/|tools/find/|tools/xargs/' \
93 | awk '$1 == "py2" { print $2 }'
94 return
95 fi
96
97 for dir in "${CODE_DIRS[@]}"; do
98 for name in $dir/*.py; do
99 echo $name
100 done
101 done | grep -v 'NINJA_subgraph' # leave out for now
102}
103
104py2() {
105 banner 'Linting Python 2 code'
106
107 # syntax_abbrev.py doesn't stand alone
108 py2-files-to-lint | grep -v '_abbrev.py' | xargs $0 py2-lint
109}
110
111py3-files() {
112 for f in mycpp/*.py; do
113 echo $f
114 done
115}
116
117py3() {
118 banner 'Linting Python 3 code'
119
120 py3-files | xargs $0 py3-lint
121}
122
123all-py() {
124 py2
125 py3
126}
127
128#
129# More Python, including Python 3
130#
131
132mycpp-files() {
133 for f in mycpp/*.py; do
134 case $f in
135 */NINJA_subgraph.py)
136 continue
137 ;;
138 esac
139
140 echo $f
141 done
142}
143
144#
145# Main
146#
147
148# Hook for soil
149soil-run() {
150 if test -n "${TRAVIS_SKIP:-}"; then
151 echo "TRAVIS_SKIP: Skipping $0"
152 return
153 fi
154
155 #flake8-all
156
157 # Our new lint script
158 all-py
159
160 check-shebangs
161}
162
163#
164# Adjust and Check shebang lines. It matters for developers on different distros.
165#
166
167find-files-to-lint() {
168 ### Similar to find-prune / find-src-files
169
170 # don't touch mycpp yet because it's in Python 3
171 # build has build/dynamic_deps.py which needs the -S
172 find . \
173 -name '_*' -a -prune -o \
174 -name 'Python-*' -a -prune -o \
175 "$@"
176}
177
178find-py() {
179 find-files-to-lint \
180 -name 'build' -a -prune -o \
181 -name '*.py' -a -print "$@"
182}
183
184find-sh() {
185 find-files-to-lint -name '*.sh' -a -print "$@"
186}
187
188print-if-has-shebang() {
189 read first < $1
190 [[ "$first" == '#!'* ]] && echo $1
191}
192
193not-executable() {
194 find-py -a ! -executable -a -print | xargs -n 1 -- $0 print-if-has-shebang
195}
196
197executable-py() {
198 find-py -a -executable -a -print | xargs -n 1 -- echo
199}
200
201# Make all shebangs consistent.
202# - Specify python2 because on some distros 'python' is python3
203# - Use /usr/bin/env because it works better with virtualenv?
204#
205# https://stackoverflow.com/questions/9309940/sed-replace-first-line
206#
207# e.g. cat edit.list, change the first line
208
209replace-py-shebang() {
210 sed -i '1c#!/usr/bin/env python2' "$@"
211}
212
213replace-bash-shebang() {
214 sed -i '1c#!/usr/bin/env bash' "$@"
215}
216
217# NOTE: no ^ anchor because of print-first-line
218
219readonly BAD_PY='#!.*/usr/bin/python'
220readonly BAD_BASH='#!.*/bin/bash'
221
222bad-py() {
223 find-py -a -print | xargs -- egrep "$BAD_PY"
224 #grep '^#!.*/bin/bash ' */*.sh
225
226 find-py -a -print | xargs -- egrep -l "$BAD_PY" | xargs $0 replace-py-shebang
227}
228
229bad-bash() {
230 # these files don't need shebangs
231 #grep -l '^#!' spec/*.test.sh | xargs -- sed -i '1d'
232
233 #find-sh -a -print | xargs -- grep "$BAD_BASH"
234
235 find-sh -a -print | xargs -- egrep -l "$BAD_BASH" | xargs $0 replace-bash-shebang
236}
237
238print-first-line() {
239 local path=$1
240
241 read line < "$path"
242 echo "$path: $line" # like grep output
243}
244
245check-shebangs() {
246 set +o errexit
247
248 if true; then
249 find-py | xargs -d $'\n' -n 1 -- $0 print-first-line | egrep "$BAD_PY"
250 if test $? -ne 1; then
251 die "FAIL: Found bad Python shebangs"
252 fi
253 fi
254
255 find-sh | xargs -d $'\n' -n 1 -- $0 print-first-line | egrep "$BAD_BASH"
256 if test $? -ne 1; then
257 die "FAIL: Found bad bash shebangs"
258 fi
259
260 echo 'PASS: check-shebangs'
261}
262
263#
264# sprintf -- What do we need in mycpp?
265#
266
267sp-formats() {
268 egrep --no-filename --only-matching '%.' */*.py | sort | uniq -c | sort -n
269}
270
271# 122 instances of these. %() for named
272sp-rare() {
273 egrep --color=always '%[^srd ]' */*.py | egrep -v 'Python-|_test.py'
274}
275
276#
277# inherit
278#
279
280# 56 instances of inheritance
281inheritance() {
282 grep ^class {osh,core,ysh,frontend}/*.py \
283 | egrep -v '_test|object'
284}
285
286# 18 unique base classes.
287# TODO: Maybe extract this automatically with OPy?
288# Or does the MyPy AST have enough?
289# You can collect method defs in the decl phase. Or in the forward_decl phase?
290
291base-classes() {
292 inheritance | egrep -o '\(.*\)' | sort | uniq -c | sort -n
293}
294
295translation() {
296 set +o errexit
297
298 metrics/source-code.sh osh-files \
299 | xargs egrep -n 'IndexError|KeyError'
300 local status=$?
301
302 echo
303
304 # 4 occurrences
305 # source builtin, core/process.py, etc.
306
307 metrics/source-code.sh osh-files \
308 | xargs egrep -n 'finally:'
309 #| xargs egrep -n -A 1 'finally:'
310}
311
312task-five "$@"