Skip to content

Instantly share code, notes, and snippets.

@jrabbit
Created March 1, 2010 17:02
Show Gist options
  • Save jrabbit/318556 to your computer and use it in GitHub Desktop.
Save jrabbit/318556 to your computer and use it in GitHub Desktop.
#!/usr/bin/python
# This program reads a directory containing Fink package descriptions
# and generates a graph of the dependencies among the packages. The
# graph is in the DOT language and can be displayed by Graphviz.
# The pydot and pyparsing modules must be installed.
# Version 1.0
# Written by Trevor Harmon <trevor@vocaro.com>
# License: GPL - http://www.gnu.org/copyleft/gpl.html
import sys, os
from string import *
from pydot import *
packages = 0
multiline_deps = 0
graph = Dot()
# Reads the given file (which is assumed to be a valid Fink package description)
# and returns a dictionary containing the package name ('package') and an array
# of dependencies ('dependencies') as defined in the file.
def get_package_info(filename):
global multiline_deps
# Read the file
infile = open(filename, 'r')
inlines = infile.readlines()
package = None;
dependencies = None;
# Walk through the file line by line
for line in inlines:
# Check for package name definition
if line.startswith('Package:'):
# Strip out everything but the name
package = line[len('Package:'):].lower().strip()
# If this package contains %n, then it must be a split-off. Skip it.
if package.find('%n') == -1:
# Strip out everything after (and including) the % symbol. This is to handle
# packages defined like "svn-swig-pm%type_pkg[perl]"
package = package.split('%')[0]
# Check for dependency definitions
if line.startswith('Depends:'):
# We don't handle multi-line dependencies (yet). Abort.
if line.find('<<') >= 0:
multiline_deps += 1
return None
# Convert the dependency list into an array of dependencies
deps = line[len('Depends:'):].strip().split(',')
dependencies = []
for dep in deps:
# Ignore everything after (and including) the first whitespace
dep = dep.lower().split()
# Make sure the dependency actually was defined and is not just whitespace
if len(dep) > 0:
# Do percent expansion
dep[0] = dep[0].replace('%n', package)
# Strip out everything after (and including) the % symbol. This is to handle
# packages defined like "svn-swig-pm%type_pkg[perl]"
dep[0] = dep[0].split('%')[0]
# Add the dependency to the array
dependencies.append(dep[0])
# We're done; quit now to avoid picking up splitoffs
return {'package' : package, 'dependencies' : dependencies}
# No dependencies were found
return {'package' : package, 'dependencies' : dependencies}
# Retrieves the name and dependency information in the given Fink package
# description and adds it to the PyDOT graph instance.
def add_package_to_graph(filename):
info = get_package_info(filename)
if info != None:
global packages;
packages += 1
# Add the package name as a node in the graph
graph.add_node(Node(info['package']))
# Add each dependency as an edge in the graph
deps = info['dependencies']
if deps != None:
for dep in deps:
graph.add_edge(Edge(info['package'], dep))
# Searches for all .info files in the given directory and adds them to the graph.
def add_directory_to_graph(directory):
if os.path.isdir(sys.argv[1]):
# Remove the trailing slash
if directory.endswith('/'):
directory = rstrip(directory, '/')
print 'Parsing', directory
# Search for all files in the given directory and clean each one
for root, dirs, files in os.walk(directory):
for filename in files:
if filename.endswith('.info'):
add_package_to_graph(root + '/' + filename)
else:
print 'Error:', directory, 'is not a directory.'
if len(sys.argv) < 2:
print 'Usage: fink-dep-graph <directory> [directory2, directory3, ...]'
else:
print 'Parsing package descriptions...'
outfile = 'fink-dependencies.dot';
for directory in sys.argv[1:]:
add_directory_to_graph(directory)
print 'Found', packages, 'packages. (Split-offs are ignored.)'
if multiline_deps > 0:
print 'Skipped', multiline_deps, 'packages due to multi-line dependency declarations, which are not supported in this version.'
graph.write(outfile)
print 'Wrote dependency graph to', outfile
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment