poky/scripts/verify-bashisms
Joshua Lock 6bba41832b scripts: remove True option to getVarFlag calls
getVarFlag() now defaults to expanding by default, thus remove the
True option from getVarFlag() calls with a regex search and
replace.

Search made with the following regex:
getVarFlag ?\(( ?[^,()]*, ?[^,()]*), True\)

(From OE-Core rev: 3e4806063fe11092b2307f113a6c0b0f04104091)

Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2016-12-16 10:23:23 +00:00

3.7 KiB
Executable File

#!/usr/bin/env python3

import sys, os, subprocess, re, shutil

whitelist = ( # type is supported by dash 'if type systemctl >/dev/null 2>/dev/null; then', 'if type systemd-tmpfiles >/dev/null 2>/dev/null; then', 'if type update-rc.d >/dev/null 2>/dev/null; then', 'command -v', # HOSTNAME is set locally 'buildhistory_single_commit "$CMDLINE" "$HOSTNAME"', # False-positive, match is a grep not shell expression 'grep "^$groupname:[^:]:[^:]:\([^,],\)$username\(,[^,]\)"', # TODO verify dash's '. script args' behaviour '. $target_sdk_dir/${oe_init_build_env_path} $target_sdk_dir >> $LOGFILE' )

def is_whitelisted(s): for w in whitelist: if w in s: return True return False

def process(recipe, function, script): import tempfile

if not script.startswith("#!"):
    script = "#! /bin/sh\n" + script

fn = tempfile.NamedTemporaryFile(mode="w+t")
fn.write(script)
fn.flush()

try:
    subprocess.check_output(("checkbashisms.pl", fn.name), universal_newlines=True, stderr=subprocess.STDOUT)
    # No bashisms, so just return
    return
except subprocess.CalledProcessError as e:
    # TODO check exit code is 1

    # Replace the temporary filename with the function and split it
    output = e.output.replace(fn.name, function).splitlines()
    if len(results) % 2 != 0:
        print("Unexpected output from checkbashism: %s" % str(output))
        return

    # Turn the output into a list of (message, source) values
    result = []
    # Check the results against the whitelist
    for message, source in zip(output[0::2], output[1::2]):
        if not is_whitelisted(source):
            result.append((message, source))
    return result

def get_tinfoil(): scripts_path = os.path.dirname(os.path.realpath(file)) lib_path = scripts_path + '/lib' sys.path = sys.path + [lib_path] import scriptpath scriptpath.add_bitbake_lib_path() import bb.tinfoil tinfoil = bb.tinfoil.Tinfoil() tinfoil.prepare() # tinfoil.logger.setLevel(logging.WARNING) return tinfoil

if name=='main': import shutil if shutil.which("checkbashisms.pl") is None: print("Cannot find checkbashisms.pl on $PATH") sys.exit(1)

tinfoil = get_tinfoil()

# This is only the default configuration and should iterate over
# recipecaches to handle multiconfig environments
pkg_pn = tinfoil.cooker.recipecaches[""].pkg_pn

# TODO: use argparse and have --help
if len(sys.argv) > 1:
    initial_pns = sys.argv[1:]
else:
    initial_pns = sorted(pkg_pn)

pns = []
print("Generating file list...")
for pn in initial_pns:
    for fn in pkg_pn[pn]:
        # There's no point checking multiple BBCLASSEXTENDed variants of the same recipe
        realfn, _, _ = bb.cache.virtualfn2realfn(fn)
        if realfn not in pns:
            pns.append(realfn)


def func(fn):
    result = []
    data = tinfoil.parse_recipe_file(fn)
    for key in data.keys():
        if data.getVarFlag(key, "func") and not data.getVarFlag(key, "python"):
            script = data.getVar(key, False)
            if not script: continue
            #print ("%s:%s" % (fn, key))
            r = process(fn, key, script)
            if r: result.extend(r)
    return fn, result

print("Scanning scripts...\n")
import multiprocessing
pool = multiprocessing.Pool()
for pn,results in pool.imap(func, pns):
    if results:
        print(pn)
        for message,source in results:
            print(" %s\n  %s" % (message, source))
        print()