Skip to content

Instantly share code, notes, and snippets.

@blais
Last active July 7, 2023 03:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save blais/c521de989528cd095155c13788974bc6 to your computer and use it in GitHub Desktop.
Save blais/c521de989528cd095155c13788974bc6 to your computer and use it in GitHub Desktop.
apt-tree
#!/usr/bin/env python3
"""Display a graph of dependencies between Ubuntu packages.
Reads a list of packages from either a file or stdin.
Outputs a PDF.
"""
__author__ = "Martin Blais <blais@furius.ca>"
import argparse
import logging
import random
import re
import sys
import tempfile
from concurrent import futures
import networkx as nx
import subprocess
def main():
parser = argparse.ArgumentParser(description=__doc__.strip())
parser.add_argument(
"--filename", "-f", help="A filename with package names, one per line."
)
parser.add_argument(
"--output", "-o", help="Output filename."
)
parser.add_argument("packages", nargs=argparse.REMAINDER)
args = parser.parse_args()
packages = args.packages
if args.filename:
packages.extend(x.strip() for x in open(args.filename).readlines())
elif not args.packages:
packages.extend(x.strip() for x in sys.stdin.readlines())
random.shuffle(packages)
g = nx.DiGraph()
with futures.ProcessPoolExecutor() as executor:
for package, deps in zip(packages, executor.map(get_dependencies, packages)):
g.add_node(package)
g.add_nodes_from(deps)
g.add_edges_from((package, dep) for dep in deps)
agraph = nx.nx_agraph.to_agraph(g)
filename = args.output or tempfile.mkstemp(prefix="apt-tree.", suffix=".pdf")[1]
agraph.draw(filename, prog="dot")
if not args.output:
print(f"Wrote: '{filename}'")
def get_dependencies(package: str):
cp = subprocess.run(
["apt-cache", "depends", package], stdout=subprocess.PIPE, encoding="utf8"
)
if cp.returncode != 0:
return {}
else:
deps = []
for line in cp.stdout.splitlines():
match = re.search(r".*Depends: (.*)", line)
if match:
deps.append(match.group(1))
return deps
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment