-
-
Save ajvpot/cdec7bdc5f1da6d82da65a0257f19db2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from re import match, split | |
from subprocess import check_output | |
from debian.deb822 import Deb822 | |
from graph_tool.all import * | |
graph = Graph() | |
package_nodes = {} | |
package_info = {} | |
def get_package_list(): | |
"""Return a list of packages, both installed and uninstalled.""" | |
output = check_output(['dpkg', '-l', '*']) | |
packages = [] | |
for line in output.split('\n'): | |
parts = line.split() | |
if not parts or not match('[uirph][nicurhWt]', parts[0]): | |
continue | |
packages.append(parts[1]) | |
return packages | |
def get_package_info(pkg_name): | |
"""Get a dict-like object containing information for a specified package.""" | |
global package_info | |
if pkg_name in package_info: | |
return package_info.get(pkg_name) | |
else: | |
try: | |
yaml_stream = check_output(['apt-cache', 'show', pkg_name]) | |
except: | |
print "Unable to find info for package: '%s'" % pkg_name | |
package_info[pkg_name] = {} | |
return {} | |
d = Deb822(yaml_stream) | |
package_info[pkg_name] = d | |
return d | |
def get_graph_node_for_package(pkg_name): | |
"""Given a package name, return the graph node for that package. If the graph | |
node does not exist, it is created, and it's meta-data filled. | |
""" | |
global graph | |
global package_nodes | |
if pkg_name not in package_nodes: | |
n = graph.add_vertex() | |
package_nodes[pkg_name] = n | |
# add node properties: | |
pkg_info = get_package_info(pkg_name) | |
graph.vertex_properties["package-name"][n] = pkg_name | |
graph.vertex_properties["installed-size"][n] = int(pkg_info.get('Installed-Size', 0)) | |
return n | |
else: | |
return package_nodes.get(pkg_name) | |
def get_sanitised_depends_list(depends_string): | |
"""Given a Depends string, return a list of package names. Versions are | |
stripped, and alternatives are all shown. | |
""" | |
if depends_string == '': | |
return [] | |
parts = split('[,\|]', depends_string) | |
return [match('(\S*)', p.strip()).groups()[0] for p in parts] | |
if __name__ == '__main__': | |
# Create property lists we need: | |
graph.vertex_properties["package-name"] = graph.new_vertex_property("string") | |
graph.vertex_properties["installed-size"] = graph.new_vertex_property("int") | |
# get list of packages: | |
packages = get_package_list() | |
n = 0 | |
for pkg_name in packages: | |
node = get_graph_node_for_package(pkg_name) | |
pkg_info = get_package_info(pkg_name) | |
# purely virtual packages won't have a package info object: | |
if pkg_info: | |
depends = pkg_info.get('Depends', '') | |
depends = get_sanitised_depends_list(depends) | |
for dependancy in depends: | |
graph.add_edge(node, get_graph_node_for_package(dependancy)) | |
n += 1 | |
if n % 10 == 0: | |
print "%d / /%d" % (n, len(packages)) | |
graph.save('graph.gml') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment