diff options
Diffstat (limited to 'scripts/contrib/graph-tool')
| -rwxr-xr-x | scripts/contrib/graph-tool | 118 |
1 files changed, 0 insertions, 118 deletions
diff --git a/scripts/contrib/graph-tool b/scripts/contrib/graph-tool deleted file mode 100755 index 26488930e0..0000000000 --- a/scripts/contrib/graph-tool +++ /dev/null | |||
| @@ -1,118 +0,0 @@ | |||
| 1 | #!/usr/bin/env python3 | ||
| 2 | |||
| 3 | # Simple graph query utility | ||
| 4 | # useful for getting answers from .dot files produced by bitbake -g | ||
| 5 | # | ||
| 6 | # Written by: Paul Eggleton <paul.eggleton@linux.intel.com> | ||
| 7 | # | ||
| 8 | # Copyright 2013 Intel Corporation | ||
| 9 | # | ||
| 10 | # SPDX-License-Identifier: GPL-2.0-only | ||
| 11 | # | ||
| 12 | |||
| 13 | import sys | ||
| 14 | import os | ||
| 15 | import argparse | ||
| 16 | |||
| 17 | scripts_lib_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'lib')) | ||
| 18 | sys.path.insert(0, scripts_lib_path) | ||
| 19 | import argparse_oe | ||
| 20 | |||
| 21 | |||
| 22 | def get_path_networkx(dotfile, fromnode, tonode): | ||
| 23 | try: | ||
| 24 | import networkx | ||
| 25 | except ImportError: | ||
| 26 | print('ERROR: Please install the networkx python module') | ||
| 27 | sys.exit(1) | ||
| 28 | |||
| 29 | graph = networkx.DiGraph(networkx.nx_pydot.read_dot(dotfile)) | ||
| 30 | def node_missing(node): | ||
| 31 | import difflib | ||
| 32 | close_matches = difflib.get_close_matches(node, graph.nodes(), cutoff=0.7) | ||
| 33 | if close_matches: | ||
| 34 | print('ERROR: no node "%s" in graph. Close matches:\n %s' % (node, '\n '.join(close_matches))) | ||
| 35 | sys.exit(1) | ||
| 36 | |||
| 37 | if not fromnode in graph: | ||
| 38 | node_missing(fromnode) | ||
| 39 | if not tonode in graph: | ||
| 40 | node_missing(tonode) | ||
| 41 | return networkx.all_simple_paths(graph, source=fromnode, target=tonode) | ||
| 42 | |||
| 43 | |||
| 44 | def find_paths(args): | ||
| 45 | path = None | ||
| 46 | for path in get_path_networkx(args.dotfile, args.fromnode, args.tonode): | ||
| 47 | print(" -> ".join(map(str, path))) | ||
| 48 | if not path: | ||
| 49 | print("ERROR: no path from %s to %s in graph" % (args.fromnode, args.tonode)) | ||
| 50 | return 1 | ||
| 51 | |||
| 52 | |||
| 53 | def filter_graph(args): | ||
| 54 | import fnmatch | ||
| 55 | |||
| 56 | exclude_tasks = [] | ||
| 57 | if args.exclude_tasks: | ||
| 58 | for task in args.exclude_tasks.split(','): | ||
| 59 | if not task.startswith('do_'): | ||
| 60 | task = 'do_%s' % task | ||
| 61 | exclude_tasks.append(task) | ||
| 62 | |||
| 63 | def checkref(strval): | ||
| 64 | strval = strval.strip().strip('"') | ||
| 65 | target, taskname = strval.rsplit('.', 1) | ||
| 66 | if exclude_tasks: | ||
| 67 | for extask in exclude_tasks: | ||
| 68 | if fnmatch.fnmatch(taskname, extask): | ||
| 69 | return False | ||
| 70 | if strval in args.ref or target in args.ref: | ||
| 71 | return True | ||
| 72 | return False | ||
| 73 | |||
| 74 | with open(args.infile, 'r') as f: | ||
| 75 | for line in f: | ||
| 76 | line = line.rstrip() | ||
| 77 | if line.startswith(('digraph', '}')): | ||
| 78 | print(line) | ||
| 79 | elif '->' in line: | ||
| 80 | linesplit = line.split('->') | ||
| 81 | if checkref(linesplit[0]) and checkref(linesplit[1]): | ||
| 82 | print(line) | ||
| 83 | elif (not args.no_nodes) and checkref(line.split()[0]): | ||
| 84 | print(line) | ||
| 85 | |||
| 86 | |||
| 87 | def main(): | ||
| 88 | parser = argparse_oe.ArgumentParser(description='Small utility for working with .dot graph files') | ||
| 89 | |||
| 90 | subparsers = parser.add_subparsers(title='subcommands', metavar='<subcommand>') | ||
| 91 | subparsers.required = True | ||
| 92 | |||
| 93 | parser_find_paths = subparsers.add_parser('find-paths', | ||
| 94 | help='Find all of the paths between two nodes in a dot graph', | ||
| 95 | description='Finds all of the paths between two nodes in a dot graph') | ||
| 96 | parser_find_paths.add_argument('dotfile', help='.dot graph to search in') | ||
| 97 | parser_find_paths.add_argument('fromnode', help='starting node name') | ||
| 98 | parser_find_paths.add_argument('tonode', help='ending node name') | ||
| 99 | parser_find_paths.set_defaults(func=find_paths) | ||
| 100 | |||
| 101 | parser_filter = subparsers.add_parser('filter', | ||
| 102 | help='Pare down a task graph to contain only the specified references', | ||
| 103 | description='Pares down a task-depends.dot graph produced by bitbake -g to contain only the specified references') | ||
| 104 | parser_filter.add_argument('infile', help='Input file') | ||
| 105 | parser_filter.add_argument('ref', nargs='+', help='Reference to include (either recipe/target name or full target.taskname specification)') | ||
| 106 | parser_filter.add_argument('-n', '--no-nodes', action='store_true', help='Skip node formatting lines') | ||
| 107 | parser_filter.add_argument('-x', '--exclude-tasks', help='Comma-separated list of tasks to exclude (do_ prefix optional, wildcards allowed)') | ||
| 108 | parser_filter.set_defaults(func=filter_graph) | ||
| 109 | |||
| 110 | args = parser.parse_args() | ||
| 111 | |||
| 112 | ret = args.func(args) | ||
| 113 | return ret | ||
| 114 | |||
| 115 | |||
| 116 | if __name__ == "__main__": | ||
| 117 | ret = main() | ||
| 118 | sys.exit(ret) | ||
