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

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