poky/scripts/oe-depends-dot
Richard Purdie ffae400179 meta/lib+scripts: Convert to SPDX license headers
This adds SPDX license headers in place of the wide assortment of things
currently in our script headers. We default to GPL-2.0-only except for the
oeqa code where it was clearly submitted and marked as MIT on the most part
or some scripts which had the "or later" GPL versioning.

The patch also drops other obsolete bits of file headers where they were
encoountered such as editor modelines, obsolete maintainer information or
the phrase "All rights reserved" which is now obsolete and not required in
copyright headers (in this case its actually confusing for licensing as all
rights were not reserved).

More work is needed for OE-Core but this takes care of the bulk of the scripts
and meta/lib directories.

The top level LICENSE files are tweaked to match the new structure and the
SPDX naming.

(From OE-Core rev: f8c9c511b5f1b7dbd45b77f345cb6c048ae6763e)

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2019-05-09 16:31:55 +01:00

5.6 KiB
Executable File

#!/usr/bin/env python3

Copyright (C) 2018 Wind River Systems, Inc.

SPDX-License-Identifier: GPL-2.0-only

import os import sys import argparse import logging import re

class Dot(object): def init(self): parser = argparse.ArgumentParser( description="Analyse recipe-depends.dot generated by bitbake -g", epilog="Use %(prog)s --help to get help") parser.add_argument("dotfile", help = "Specify the dotfile", nargs = 1, action='store', default='') parser.add_argument("-k", "--key", help = "Specify the key, e.g., recipe name", action="store", default='') parser.add_argument("-d", "--depends", help = "Print the key's dependencies", action="store_true", default=False) parser.add_argument("-w", "--why", help = "Print why the key is built", action="store_true", default=False) parser.add_argument("-r", "--remove", help = "Remove duplicated dependencies to reduce the size of the dot files." " For example, A->B, B->C, A->C, then A->C can be removed.", action="store_true", default=False)

    self.args = parser.parse_args()

    if len(sys.argv) != 3 and len(sys.argv) < 5:
        print('ERROR: Not enough args, see --help for usage')

@staticmethod
def insert_dep_chain(chain, rdeps, alldeps):
    """
    insert elements to chain from rdeps, according to alldeps
    """
    # chain should at least contain one element
    if len(chain) == 0:
        raise

    inserted_elements = []
    for rdep in rdeps:
        if rdep in chain:
            continue
        else:
            for i in range(0, len(chain)-1):
                if chain[i] in alldeps[rdep] and rdep in alldeps[chain[i+1]]:
                    chain.insert(i+1, rdep)
                    inserted_elements.append(rdep)
                    break
            if chain[-1] in alldeps[rdep] and rdep not in chain:
                chain.append(rdep)
                inserted_elements.append(rdep)
    return inserted_elements

@staticmethod
def print_dep_chains(key, rdeps, alldeps):
    rlist = rdeps.copy()
    chain = []
    removed_rdeps = [] # hold rdeps removed from rlist

    chain.append(key)
    while (len(rlist) != 0):
        # insert chain from rlist
        inserted_elements = Dot.insert_dep_chain(chain, rlist, alldeps)
        if not inserted_elements:
            if chain[-1] in rlist:
                rlist.remove(chain[-1])
                removed_rdeps.append(chain[-1])
            chain.pop()
            continue
        else:
            # insert chain from removed_rdeps
            Dot.insert_dep_chain(chain, removed_rdeps, alldeps)
            print(' -> '.join(list(reversed(chain))))

def main(self):
    #print(self.args.dotfile[0])
    # The format is {key: depends}
    depends = {}
    with open(self.args.dotfile[0], 'r') as f:
        for line in f.readlines():
            if ' -> ' not in line:
                continue
            line_no_quotes = line.replace('"', '')
            m = re.match("(.*) -> (.*)", line_no_quotes)
            if not m:
                print('WARNING: Found unexpected line: %s' % line)
                continue
            key = m.group(1)
            if key == "meta-world-pkgdata":
                continue
            dep = m.group(2)
            if key in depends:
                if not key in depends[key]:
                    depends[key].add(dep)
                else:
                    print('WARNING: Fonud duplicated line: %s' % line)
            else:
                depends[key] = set()
                depends[key].add(dep)

    if self.args.remove:
        reduced_depends = {}
        for k, deps in depends.items():
            child_deps = set()
            added = set()
            # Both direct and indirect depends are already in the dict, so
            # we don't have to do this recursively.
            for dep in deps:
                if dep in depends:
                    child_deps |= depends[dep]

            reduced_depends[k] = deps - child_deps
            outfile= '%s-reduced%s' % (self.args.dotfile[0][:-4], self.args.dotfile[0][-4:])
        with open(outfile, 'w') as f:
            print('Saving reduced dot file to %s' % outfile)
            f.write('digraph depends {\n')
            for k, v in reduced_depends.items():
                for dep in v:
                    f.write('"%s" -> "%s"\n' % (k, dep))
            f.write('}\n')
        sys.exit(0)

    if self.args.key not in depends:
        print("ERROR: Can't find key %s in %s" % (self.args.key, self.args.dotfile[0]))
        sys.exit(1)

    if self.args.depends:
        if self.args.key in depends:
            print('Depends: %s' % ' '.join(depends[self.args.key]))

    reverse_deps = []
    if self.args.why:
        for k, v in depends.items():
            if self.args.key in v and not k in reverse_deps:
                reverse_deps.append(k)
        print('Because: %s' % ' '.join(reverse_deps))
        Dot.print_dep_chains(self.args.key, reverse_deps, depends)

if name == "main": try: dot = Dot() ret = dot.main() except Exception as esc: ret = 1 import traceback traceback.print_exc() sys.exit(ret)