我似乎意外地将 Pop!_OS 的 system76 ppa 添加到了我的 Ubuntu 20.04 安装中。(真正奇怪的是,我还没有意识到这一点……)
与此同时,我删除了 ppa 和我能找到的 repos 列表中的条目。系统几乎恢复正常。不过,我认为我还剩下一些剩余的东西,至少这是我对以下输出的解释:
$ apt list --installed | grep pop[0-9]
accountsservice/now 0.6.55-0ubuntu13.2pop0~1605745773~20.04~d9482b1 amd64 [installed,local]
gnome-settings-daemon-common/now 3.36.1-0ubuntu1pop0~1596026424~20.04~8296153 all [installed,local]
gnome-terminal-data/now 3.36.2-1ubuntu1~20.04pop0~1594780610~20.04~8048ed7 all [installed,local]
gnome-terminal/now 3.36.2-1ubuntu1~20.04pop0~1594780610~20.04~8048ed7 amd64 [installed,local]
...
我现在如何确定这些属于哪个存储库,以及如何将这些包降级为当前活动存储库中包含的版本?
例如,我看到:
$ apt policy gnome-settings-daemon-common
gnome-settings-daemon-common:
Installed: 3.36.1-0ubuntu1pop0~1596026424~20.04~8296153
Candidate: 3.36.1-0ubuntu1pop0~1596026424~20.04~8296153
Version table:
*** 3.36.1-0ubuntu1pop0~1596026424~20.04~8296153 100
100 /var/lib/dpkg/status
3.36.1-0ubuntu1 500
500 http://xx.archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages
500 http://xx.archive.ubuntu.com/ubuntu focal-updates/main i386 Packages
3.36.0-1ubuntu2 500
500 http://xx.archive.ubuntu.com/ubuntu focal/main amd64 Packages
500 http://xx.archive.ubuntu.com/ubuntu focal/main i386 Packages
和:
$ apt-cache madison gnome-settings-daemon-common
gnome-settings-daemon-common | 3.36.1-0ubuntu1 | http://xx.archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages
gnome-settings-daemon-common | 3.36.1-0ubuntu1 | http://xx.archive.ubuntu.com/ubuntu focal-updates/main i386 Packages
gnome-settings-daemon-common | 3.36.0-1ubuntu2 | http://xx.archive.ubuntu.com/ubuntu focal/main amd64 Packages
gnome-settings-daemon-common | 3.36.0-1ubuntu2 | http://xx.archive.ubuntu.com/ubuntu focal/main i386 Packages
gnome-settings-daemon | 3.36.0-1ubuntu2 | http://xx.archive.ubuntu.com/ubuntu focal/main Sources
gnome-settings-daemon | 3.36.1-0ubuntu1 | http://xx.archive.ubuntu.com/ubuntu focal-updates/main Sources
我将其解释为表明当前安装的版本不包含在存储库中。
但是我如何恢复存储库中的版本?理想情况下,我想这样做全部包裹……
更新现在,我已经使用 手动将所有软件包替换为我想要的软件包apt-get install package=version
。这非常麻烦,因为我必须查找apt policy
每个软件包所需的版本,有时还要一次性替换一大堆软件包以满足依赖关系。虽然我的问题已经解决,但我仍然非常想知道如何更有效地进行这种清理。
答案1
除了所有这些繁琐的手动清理工作之外,最后我还编写了一个 Python 脚本来识别所有不在活动存储库中的包,或者安装的版本比存储库中的版本更新的包。
下面的代码是一个快速修复,不会赢得选美比赛,但对我来说它完成了工作。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Identify all packages that are not in active repositories or for
which newer versions are installed.
"""
import re
import subprocess
from pprint import pprint
def get_packages():
vers = subprocess.run("apt-show-versions", shell=True, capture_output=True)
vers = vers.stdout.decode("utf-8").splitlines()
vers = [y for y in (x.strip() for x in vers) if y]
not_in_archive = {}
newer_than_archive = {}
others = {}
for pkg in vers:
p = [x.strip() for x in pkg.split(' ', 2)]
name = p[0]
vers = p[1]
status = p[2] if len(p) == 3 else ''
if vers == 'not' and status == 'installed':
continue
if status == 'uptodate':
continue
tmp = {name: {'vers': vers}}
if status == 'installed: No available version in archive':
not_in_archive.update(tmp)
elif status == 'newer than version in archive':
newer_than_archive.update(tmp)
else:
others.update(tmp)
others[name][status] = status
return not_in_archive, newer_than_archive, others
def get_version(pkg):
vers = subprocess.run("apt policy {}".format(pkg),
shell=True, capture_output=True)
vers = vers.stdout.decode("utf-8").splitlines()
vt = re.compile(r'^ +version table:', re.IGNORECASE)
stars = re.compile(r'^ \*\*\* *')
res = []
while True:
line = vers.pop(0)
if vt.match(line):
break
for i, line in enumerate(vers):
if line[:8].strip():
s = line[:5]
v = line[5:].split(' ', 1)[0]
installed = bool(stars.match(s))
else:
p, a = line[8:].split(' ', 1)
res.append({'installed': installed,
'version': v,
'prio': p,
'archive': a})
return res
if __name__ == '__main__':
missing, newer, rest = get_packages()
url = re.compile(r'^https?://', re.IGNORECASE)
res = {}
for p in newer:
v = get_version(p)
for x in v:
if url.match(x['archive']):
res[p] = x['version']
break
if missing:
print("===== packages not in repositories =====")
print(' '.join(p for p in missing))
print()
if rest:
print("===== packages with other status =====")
pprint(rest)
print()
if res:
print("===== command to downgrade =====")
print('sudo apt-get install {}'.format(
' '.join('{}={}'.format(p, v) for p, v in res.items())))
例如,禁用 darktable 和 kicad PPA 后,我得到
===== packages not in repositories =====
darktable-dbg:amd64 libpng12-0:amd64 zoom:amd64
===== command to downgrade =====
sudo apt-get install darktable:amd64=3.0.1-0ubuntu1 kicad:amd64=5.1.5+dfsg1-2build2 kicad-demos:all=5.1.5+dfsg1-2build2 kicad-doc-en:all=5.1.5+dfsg1-2build2 kicad-footprints:all=5.1.5-1 kicad-libraries:all=5.1.5+dfsg1-2build2 kicad-packages3d:all=5.1.5-1 kicad-symbols:all=5.1.5-1 kicad-templates:all=5.1.5-1
最后一个命令会降级已安装的软件包,并且上面的软件包必须被删除apt-get remove ...
。
(我理解如果只是删除 ppa 并且系统中的其他一切都是“干净的”,那么 ppa-purge 是可行的方法,但情况可能并非总是如此)