--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jamesa/get_deps.py Wed Nov 04 17:40:17 2009 +0000
@@ -0,0 +1,174 @@
+# Copyright (c) 2009 Symbian Foundation Ltd
+# This component and the accompanying materials are made available
+# under the terms of the License "Eclipse Public License v1.0"
+# which accompanies this distribution, and is available
+# at the URL "http://www.eclipse.org/legal/epl-v10.html".
+#
+# Initial Contributors:
+# Symbian Foundation Ltd - initial contribution.
+#
+# Contributors:
+#
+# Description:
+# Walk all nodes in the dependency graph to create a dependency report.
+
+"""Walk a dependency graph to find dependencies for a particular set of
+components. This script uses the output of build_graph.py to trace
+dependencies.
+
+The directory_list refer to diretories in the source tree for which
+you wish to trace dependencies. The script will find all components
+in the graph file under these directories and trace dependencies from
+that point.
+"""
+
+from optparse import OptionParser
+from _common import Node
+
+import sys
+import pickle
+import logging
+
+__author__ = 'James Aley'
+__email__ = 'jamesa@symbian.org'
+__version__ = '1.0'
+
+_LOG_FORMAT = '%(levelname)s: %(message)s'
+logging.basicConfig(format=_LOG_FORMAT, level=logging.WARNING, stream=sys.stdout)
+
+# Internalized graph object
+graph = {}
+
+# Report formatting
+_REPORT_HEADER = """// Generated by get_deps.py
+//
+// Dependency information for:
+//
+%s
+
+"""
+
+_DEPENDENCY_FORMAT = """
+// Required components:
+
+%s
+
+"""
+
+_MISSING_FORMAT = """
+// The following binary objects were referenced from the build files for
+// components required by your specified root components. However, there
+// were no build files for these objects found in the source tree parsing,
+// so dependencies for them may be missing in the above listing.
+
+%s
+
+"""
+
+def load_graph(path):
+ """Return the internalized graph dictionary object.
+ """
+ graph_file = None
+ graph_loaded = {}
+
+ try:
+ graph_file = open(path, 'rb')
+ except IOError, e:
+ logging.critical('Unable to open graph from file: %s: %s' % (path, repr(e)))
+ exit(1)
+ try:
+ graph_loaded = pickle.load(graph_file)
+ except Exception, e:
+ logging.critical('File %s does not contain a valid graph: %s' % (path, repr(e)))
+ return graph_loaded
+
+def find_roots(root_dirs):
+ """Return a list of root nodes from the graph for tracing, based on
+ the specified component directories in the root_dirs list.
+ """
+ roots = []
+ for root in root_dirs:
+ for node in graph.keys():
+ if node.startswith(root.lower()):
+ if node not in roots:
+ roots.append(node)
+ return roots
+
+def trace(root, visited = set()):
+ """Return a list of components required to support root.
+ """
+ node = graph[root]
+ visited |= set([node.node_path]) | set(node.dependencies)
+ for dep in node.dependencies:
+ if dep not in visited:
+ return trace(dep, visited)
+ return visited
+
+def unresolved(deps):
+ """Return a set of components with unknown dependencies from a
+ provided list of node names.
+ """
+ unresolved = set()
+ for dep in deps:
+ node = graph[dep]
+ unresolved |= set(node.unresolved)
+ return unresolved
+
+def report(out_path, roots, dependencies, missing):
+ """Output the dependency information to file.
+ """
+ # open report file
+ out_file = None
+ try:
+ out_file = open(out_path, 'w')
+ except IOError, e:
+ logging.critical('Unable to write report: %s' % (repr(e)))
+ exit(1)
+
+ # easier to read report with these sorted
+ roots.sort()
+ dependencies.sort()
+ missing.sort()
+
+ # format report
+ formatted_header = _REPORT_HEADER % ('\n'.join(['// %s' % (line, ) for line in roots]), )
+ formatted_body = _DEPENDENCY_FORMAT % ('\n'.join(dependencies))
+ formatted_missing = _MISSING_FORMAT % ('\n'.join(['// %s' % (line, ) for line in missing]), )
+
+ # write report
+ out_file.write(formatted_header)
+ out_file.write(formatted_body)
+ out_file.write(formatted_missing)
+
+ out_file.close()
+
+if __name__ == '__main__':
+ # Options config
+ parser = OptionParser()
+ parser.set_description(__doc__)
+ parser.set_usage('python get_deps.py [options] directory_list')
+ parser.add_option('-g', '--graph', dest='graph_file',
+ help='File name to write the graph to.',
+ metavar='GRAPH_FILE', default='dependencies.graph')
+ parser.add_option('-o', '--output', dest='output_file',
+ help='File to write the dependency report to.',
+ metavar='OUT_FILE', default='dependencies.txt')
+ (options, args) = parser.parse_args()
+
+ # Intenalize the graph file
+ print 'Loading graph from %s' % (options.graph_file, )
+ graph = load_graph(options.graph_file)
+
+ # Extract relevant slices and merge dependencies
+ roots = find_roots(args)
+ print 'Tracing dependencies for %d components under %s' % (len(roots), ', '.join(args))
+ deps = set()
+ for root in roots:
+ deps |= trace(root)
+ print 'Dependency graph slice yields %d of %d components.' % (len(deps), len(graph))
+ unresolved_deps = unresolved(deps)
+ print 'Component dependencies for %d binaries are unresolved' % (len(unresolved_deps, ))
+
+ # Write the report to the output file
+ report(options.output_file, roots, list(deps), list(unresolved_deps))
+ print 'Report written to: %s' % (options.output_file, )