-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcheck-bin-depends.py
executable file
·103 lines (80 loc) · 3.19 KB
/
check-bin-depends.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Hacky script to determine redundant dependencies of an AUR package."""
import sys
from collections import defaultdict
from functools import partial
from subprocess import DEVNULL, PIPE, run, STDOUT
from pprint import pprint
__prog__ = "check-bin-depends"
err = partial(print, file=sys.stderr)
def pipe(cmd, input='', stderr=None, **kwargs):
kwargs['stdout'] = PIPE
kwargs['stderr'] = {'redirect': STDOUT, 'capture': PIPE, 'drop': DEVNULL}.get(stderr, stderr)
kwargs.setdefault('encoding', 'utf-8' if isinstance(input, str) else None)
res = run(cmd, input=input, **kwargs)
return (res.stdout, res.stderr) if stderr == 'capture' else res.stdout
def main(args):
if not args:
sys.exit("Usage: %s [-e <pkg>] <binary>..." % __prog__)
excludes = set()
while True:
if len(args) >= 3 and args[0] == "-e":
excludes.add(args[1])
args.pop(0)
args.pop(0)
else:
break
depends = set()
base_devel = set(line.strip() for line in pipe(['pacman', '-Qqg', 'base-devel']).splitlines())
#err("\n".join(sorted(base_devel)))
for pkg in base_devel:
depends.update(p.strip() for p in pipe(['pactree', '-l', pkg]).splitlines())
depends.update(base_devel)
for fn in args:
libs = set()
for line in pipe(['ldd', fn]).splitlines():
line = line.strip()
if line and not (line.startswith('linux-vdso') or 'ld-linux' in line):
libs.add(line.split()[2])
#err("\n".join(sorted(libs)))
err("\nCollecting packages...\n")
packages = set()
for path in libs:
package = pipe(['pkgfile', path]).splitlines()[0].strip()
if package:
#err("{} => '{}'".format(lib, package))
package = package.split('/')[1]
if package in packages:
continue
if package in depends:
err("Package '{}' in 'base-devel' group (and dependencies).".format(package))
elif package in excludes:
err("Package '{}' ignored by exclude list.".format(package))
continue
packages.add(package)
else:
err("Library file '{}' is not owned by any package.".format(path))
err("\nCollecting dependencies...\n")
depends = defaultdict(set)
for pkg in sorted(packages):
for dep in set(p.strip() for p in pipe(['pactree', '-l', pkg]).splitlines()):
if dep != pkg:
depends[dep].add(pkg)
#pprint(depends)
maxcount = 10
err("\nRemoving indirect dependencies...\n")
while True:
toremove = set()
for pkg in sorted(packages):
if depends[pkg]:
toremove.add(pkg)
err("Dependency '{}' already included by packages '{}'. "
"Removing it.".format(pkg, ", ".join(depends[pkg])))
maxcount -= 1
if not toremove or not packages or maxcount <= 0:
break
packages.difference_update(toremove)
print("depends: ({})".format(" ".join("'{}'".format(pkg) for pkg in sorted(packages))))
if __name__ == '__main__':
sys.exit(main(sys.argv[1:]) or 0)