summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xscripts/verify-bashisms56
1 files changed, 36 insertions, 20 deletions
diff --git a/scripts/verify-bashisms b/scripts/verify-bashisms
index df071e3b90..7283980ed5 100755
--- a/scripts/verify-bashisms
+++ b/scripts/verify-bashisms
@@ -22,7 +22,9 @@ def is_whitelisted(s):
22 return True 22 return True
23 return False 23 return False
24 24
25def process(recipe, function, script): 25SCRIPT_LINENO_RE = re.compile(r' line (\d+) ')
26
27def process(filename, function, lineno, script):
26 import tempfile 28 import tempfile
27 29
28 if not script.startswith("#!"): 30 if not script.startswith("#!"):
@@ -45,13 +47,25 @@ def process(recipe, function, script):
45 print("Unexpected output from checkbashism: %s" % str(output)) 47 print("Unexpected output from checkbashism: %s" % str(output))
46 return 48 return
47 49
48 # Turn the output into a list of (message, source) values 50 # Turn the output into a single string like this:
51 # /.../foobar.bb
52 # possible bashism in updatercd_postrm line 2 (type):
53 # if ${@use_updatercd(d)} && type update-rc.d >/dev/null 2>/dev/null; then
54 # ...
55 # ...
49 result = [] 56 result = []
50 # Check the results against the whitelist 57 # Check the results against the whitelist
51 for message, source in zip(output[0::2], output[1::2]): 58 for message, source in zip(output[0::2], output[1::2]):
52 if not is_whitelisted(source): 59 if not is_whitelisted(source):
53 result.append((message, source)) 60 if lineno is not None:
54 return result 61 message = SCRIPT_LINENO_RE.sub(lambda m: ' line %d ' % (int(m.group(1)) + int(lineno) - 1),
62 message)
63 result.extend([' ' + message, ' ' + source])
64 if result:
65 result.insert(0, filename)
66 return '\n'.join(result)
67 else:
68 return None
55 69
56def get_tinfoil(): 70def get_tinfoil():
57 scripts_path = os.path.dirname(os.path.realpath(__file__)) 71 scripts_path = os.path.dirname(os.path.realpath(__file__))
@@ -75,12 +89,8 @@ if __name__=='__main__':
75 # initializing the pool and connecting to the 89 # initializing the pool and connecting to the
76 # bitbake server is crucial, don't change it. 90 # bitbake server is crucial, don't change it.
77 def func(item): 91 def func(item):
78 fn, scripts = item 92 (filename, key, lineno), script = item
79 result = [] 93 return process(filename, key, lineno, script)
80 for key, script in scripts:
81 r = process(fn, key, script)
82 if r: result.extend(r)
83 return fn, result
84 94
85 import multiprocessing 95 import multiprocessing
86 pool = multiprocessing.Pool() 96 pool = multiprocessing.Pool()
@@ -97,27 +107,33 @@ if __name__=='__main__':
97 else: 107 else:
98 initial_pns = sorted(pkg_pn) 108 initial_pns = sorted(pkg_pn)
99 109
100 pns = {} 110 pns = set()
111 scripts = {}
101 print("Generating scripts...") 112 print("Generating scripts...")
102 for pn in initial_pns: 113 for pn in initial_pns:
103 for fn in pkg_pn[pn]: 114 for fn in pkg_pn[pn]:
104 # There's no point checking multiple BBCLASSEXTENDed variants of the same recipe 115 # There's no point checking multiple BBCLASSEXTENDed variants of the same recipe
116 # (at least in general - there is some risk that the variants contain different scripts)
105 realfn, _, _ = bb.cache.virtualfn2realfn(fn) 117 realfn, _, _ = bb.cache.virtualfn2realfn(fn)
106 if realfn not in pns: 118 if realfn not in pns:
119 pns.add(realfn)
107 data = tinfoil.parse_recipe_file(realfn) 120 data = tinfoil.parse_recipe_file(realfn)
108 scripts = []
109 for key in data.keys(): 121 for key in data.keys():
110 if data.getVarFlag(key, "func") and not data.getVarFlag(key, "python"): 122 if data.getVarFlag(key, "func") and not data.getVarFlag(key, "python"):
111 script = data.getVar(key, False) 123 script = data.getVar(key, False)
112 if script: 124 if script:
113 scripts.append((key, script)) 125 filename = data.getVarFlag(key, "filename")
114 pns[realfn] = scripts 126 lineno = data.getVarFlag(key, "lineno")
127 # There's no point in checking a function multiple
128 # times just because different recipes include it.
129 # We identify unique scripts by file, name, and (just in case)
130 # line number.
131 attributes = (filename or realfn, key, lineno)
132 scripts.setdefault(attributes, script)
133
115 134
116 print("Scanning scripts...\n") 135 print("Scanning scripts...\n")
117 for pn, results in pool.imap(func, pns.items()): 136 for result in pool.imap(func, scripts.items()):
118 if results: 137 if result:
119 print(pn) 138 print(result)
120 for message,source in results:
121 print(" %s\n %s" % (message, source))
122 print()
123 tinfoil.shutdown() 139 tinfoil.shutdown()