debdu.py (2102B)
1 #!/usr/bin/python3 2 3 import apt_pkg 4 5 apt_pkg.init() 6 cache = apt_pkg.Cache(None) 7 depcache = apt_pkg.DepCache(cache) 8 9 graph = {} 10 roots = [] 11 results = [] 12 13 def init(p): 14 if p not in graph.keys(): 15 graph[p] = {} 16 graph[p]['n_in'] = 0 17 18 def dfs(v): 19 if 'full' in graph[v].keys(): 20 return graph[v]['full'] 21 graph[v]['full'] = 0 # TODO this marking is wrong for cycles, think about it 22 s = graph[v]['size'] 23 expl = [(s, 'the package itself', True, 1)] 24 for d in graph[v]['deps']: 25 #print "%s -> %s" % (v, d) 26 dfs(d) 27 if graph[d]['auto']: 28 s += graph[d]['full'] / graph[d]['n_in'] 29 expl.append((graph[d]['full']/graph[d]['n_in'], d, 30 graph[d]['auto'], graph[d]['n_in'])) 31 else: 32 expl.append((0, d, graph[d]['auto'], 1)) 33 graph[v]['full'] = s 34 expl = sorted(expl, reverse=True) 35 if not graph[v]['auto']: 36 results.append((s, v, expl)) 37 38 for package in cache.packages: 39 if package.current_state != apt_pkg.CURSTATE_INSTALLED: 40 continue 41 version = package.current_ver 42 name = package.name 43 #print name 44 auto = depcache.is_auto_installed(package) 45 init(name) 46 graph[name]['auto'] = auto 47 if not auto: 48 roots.append(name) 49 graph[name]['size'] = version.installed_size 50 graph[name]['deps'] = set() 51 if 'Depends' not in version.depends_list_str.keys(): 52 continue 53 for dep in version.depends_list_str['Depends']: 54 # TODO of course this is wrong... 55 for or_dep in dep: 56 try: 57 if cache[or_dep[0]].current_state != apt_pkg.CURSTATE_INSTALLED: 58 continue 59 except KeyError: 60 continue # Wrong wrong wrong! 61 graph[name]['deps'].add(or_dep[0]) 62 init(or_dep[0]) 63 graph[or_dep[0]]['n_in'] += 1 64 65 for root in roots: 66 dfs(root) 67 68 for result in sorted(results, reverse=True): 69 print (str(result[0]) + ' ' + result[1]) 70 for e in result[2]: 71 # TODO shared should be between non-descendant packages 72 print (' %d from %s%s' % (e[0], e[1], 73 (" shared between "+str(e[3])+" package(s)" if e[3] != 1 else '') if 74 e[2] else ' manually installed and accounted in a separate entry')) 75 print() 76