Допилил до рабочего состояния скрипт для p6 с apt-cache.
Получилось как-то так:
#!/usr/bin/python3
# -*- coding: utf-8 -*-
# this work for ru_RU.UTF-8 locale only
import subprocess
import sys
import copy
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
def getDependency(package):
if package == "":
return None
resp = subprocess.check_output(["/bin/sh", "-c", "apt-cache depends "+ package +" | grep -E -v '(Д|К|В|<.*>)' | sed 's/[0-9]\+://;s/^.*: //;s/^ \+//;s/ .*$//' | sort | uniq | tr '\n' ' ' | (read za; rpm -q --qf '%{NAME}\n' $za 2>/dev/null) | sed 's/^ //'"],universal_newlines=True);
s = str(resp);
# eprint(s)
if s and len(s.strip()) > 0:
return s.replace("'", "").split("\n")
else:
return None
def getAllpackages():
resp = subprocess.check_output(["rpm", "-qa", "--qf", "'%{NAME}\n'"], universal_newlines=True);
s = str(resp)
return s.replace("'", "").split("\n")
def getWhatReq(package):
args = ["/bin/sh", "-c", "rpm -e --test " + package + " 2>&1 >/dev/null | grep -E -o 'для.+' | sed 's/для //' | tr '\n' ' ' | (read zb; rpm -q --qf '%{NAME}\n' $zb 2>/dev/null) | sed 's/^ //'"]
resp = subprocess.check_output(args, universal_newlines=True, stderr=None)
s = str(resp).strip("\n");
# eprint(s)
if s and len(s.strip()) > 0:
return s.replace("'", "").split("\n")
else:
return None
candidats = {}
all = getAllpackages()
blacklist = set()
whitelist = set()
def process_pckg_list(pckg_list):
# eprint(blacklist)
for package in pckg_list:
try:
dep = candidats[package]
hasBefore = True
except KeyError:
dep = set()
candidats[package] = dep
hasBefore = False
try:
list = getDependency(package)
if list == None:
return True
except subprocess.CalledProcessError:
eprint("error while processing :", package)
# xtree.pop(package)
return False
for s in list:
s = s.strip()
if len(s) == 0:
continue
if "(" in s:
continue
if "/" in s:
continue
try:
pname = s.strip().split()[0].strip()
except IndexError:
eprint("index error:", s)
continue;
if pname in blacklist:
continue
# print(package, "::", s,"->",pname)
dep.add(pname)
if pname not in candidats:
status = process_pckg_list([pname])
if not status:
try:
if not hasBefore:
eprint("blacklist:", pname);
blacklist.add(pname)
del candidats[pname]
except KeyError:
pass
return True
def main():
args = sys.argv # [-1]
args.pop(0)
args1 = set(copy.copy(args))
for p in args:
if p[-1]== '+':
whitelist.add(p[0:-1])
try :
args1.remove(p)
except KeyError:
pass
continue
deps = getWhatReq(p)
if deps:
args1 = args1.union(set(deps))
# args1 = deps(set(args1))
args1 -= whitelist
eprint(args1)
# eprint(blacklist)
eprint(whitelist)
process_pckg_list(args1)
# main(["Ristetto"])
# print(len(candidats))
# print(candidats)
# print("------------------")
needNextPass = False
passCount = 1
class NeedPassException(Exception):
pass
dep_cache = {}
# eprint(candidats)
while (True):
# eprint ("------------pass ", passCount)
passCount += 1
needNextPass = False
try:
for p in candidats:
try:
deps = dep_cache[p]
except KeyError:
try:
deps = getWhatReq(p)
dep_cache[p] = deps
except subprocess.CalledProcessError:
# eprint("p=",p)
dep_cache[p] = []
continue
if deps == None:
# eprint("getWhatReq(",p ,") return None" )
continue
for r in deps:
r = r.strip()
if len(r) == 0:
continue
if r == p:
# eprint("skip [" + r + "]")
continue
if r in whitelist:
continue
if r not in all:
continue
if r not in candidats:
needNextPass = True
xlist = candidats[p]
for c1 in xlist:
try:
del candidats[c1]
# eprint("removed ",c1)
except KeyError:
pass
try:
del candidats[p]
# eprint("removed ", p)
except KeyError:
pass
raise NeedPassException
pass
pass
except NeedPassException:
continue
if not needNextPass:
break
pass
result = ''
eprint("Всего найдено пакетов для удаления:", len(candidats.keys()))
for s in candidats.keys():
result = result + s + " ";
print(result)
if __name__ == "__main__":
main()
Работает, конечно, не шибко быстро, но вполне терпимо. Время работы для medit 8мин, firefox 9 мин, gimp 16 мин.
Захотелось посмотреть для большого количества пакетов — для удаления glibc-core комп пыхтел 2 часа 10 минут, выдал на удаление 593 пакета из установленных 1800. Вспоминая, как у нас один из админов на прошлой неделе обновлял win10 (не на новую версию, а просто обновлял) где-то часа четыре с половиной, не сказал бы, что два часа это так уж плохо. Тем более, что для всех вменяемых задач которые пробовал, наподобие удаления какого-либо приложения, скрипт укладывается в 5...20 мин. Это на машине 1 ядро 2ГГц 2Гб памяти.