摆脱意外安装的软件包

摆脱意外安装的软件包

我似乎意外地将 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 是可行的方法,但情况可能并非总是如此)

相关内容