![无法在 ubuntu 14.04 上进行发布更新](https://linux22.com/image/1526647/%E6%97%A0%E6%B3%95%E5%9C%A8%20ubuntu%2014.04%20%E4%B8%8A%E8%BF%9B%E8%A1%8C%E5%8F%91%E5%B8%83%E6%9B%B4%E6%96%B0.png)
我目前正在尝试将 ubuntu 14.04 升级到 xenial。我尝试进行发布更新,但失败并出现错误,例如 UnicodeDecodeError: 'utf-8' codec can't decrypt byte 0x96 in position 382: invalid start byte
它看起来像已知错误- 我尝试过,但没有找到有问题的软件包,因此禁用/删除了 nodesource 和 veeam 存储库的 2 个非标准 package.lst 文件。
回溯内容如下
Traceback (most recent call last):
File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
sys.exit(main())
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
if app.run():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
return self.fullUpgrade()
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
if not self.doPostInitialUpdate():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
self.tasks = self.cache.installedTasks
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
Error in sys.excepthook:
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/problem_report.py", line 416, in add_to_existing
self.write(f)
File "/usr/lib/python3/dist-packages/problem_report.py", line 369, in write
block = f.read(1048576)
File "/usr/lib/python3.4/codecs.py", line 319, in decode
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
Original exception was:
Traceback (most recent call last):
File "/tmp/ubuntu-release-upgrader-woadaq_z/xenial", line 8, in <module>
sys.exit(main())
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeMain.py", line 242, in main
if app.run():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1876, in run
return self.fullUpgrade()
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 1757, in fullUpgrade
if not self.doPostInitialUpdate():
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeController.py", line 943, in doPostInitialUpdate
self.tasks = self.cache.installedTasks
File "/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py", line 806, in installedTasks
for line in pkg._pcache._records.record.split("\n"):
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x96 in position 382: invalid start byte
=== Command terminated with exit status 1 (Mon Apr 3 09:31:21 2017) ===
日志中没有任何真正有用的信息。我该如何让 do-release update 工作?
答案1
问题在于升级脚本本身在某处遇到了无效数据。您需要找到并删除无效数据。
在这种情况下,问题出在软件包上veeamsnap
。删除该软件包应该可以解决问题。但由于每种情况都不同,我将描述得出该结论所采取的步骤。这是一个相当复杂的过程。
这很有趣,因为 python3 字符串应该全部采用 UTF-8 编码。您在这里看到的(事后发现)是一个 C 模块 ( apt_pkg
) 以某种方式将非 UTF-8 数据插入到 python3 字符串中,因此中断了读取字符串的每次尝试 - 注意到错误处理程序本身也引发了异常吗?
走向未知 调试器我们去!
诊断此类问题的最佳方法是让调试器在失败的行之前暂停。使用 Python,当您有一系列这样的嵌套调用时,添加调试器暂停的最简单方法是编辑文件本身。
使用您的示例,我们可以看到有问题的故障位于文件
/tmp/ubuntu-release-upgrader-woadaq_z/DistUpgrade/DistUpgradeCache.py
第 806 行,因此让我们启动文本编辑器并转到该行。每次运行的临时路径都会不同,因此请确保使用错误输出中的临时路径!从这里我们可以首先在调试器中添加一个简单的暂停
import pdb; pdb.set_trace();
,在错误之前的第 806 行插入。因为这是 Python,所以缩进很重要!现在我们需要运行修改后的程序。不要
do-release-upgrade
再次运行;那样可能会下载一个新的。在错误日志中看到“Original exception was”后面的第一行?带有 的那行/tmp/ubuntu-release-upgrader-woadaq_z/xenial
?这就是您要运行的那个。因此,以 root(或 sudo)身份运行该文件。运行该程序你将进入调试器(pdb):
从这里,我们可以算出总共有多少个包裹。简单的方法是运行
sum(1 for _ in self)
。稍等片刻(这可能需要一段时间),它会打印一个数字。在本例中,它是76028
。现在,由于错误可能不会在前几个中发生,并且我们不想手动逐步浏览> 75000 个包,并且我们无法添加异常处理程序(因为错误太严重以至于破坏了 Python 本身),我们需要一种替代方案。
删除步骤 4 中添加的行。编辑代码以打印每个包的递增数字。例如,
foo = 0
在循环上方的第 802 行和foo += 1; print(foo)
第 807 行(就在出错行之前)添加。使用与步骤 3 相同的命令再次运行代码。它将打印一大串数字。让它继续运行,直到再次打印错误。您可能需要放大窗口:
最后一个数字应该是导致崩溃的软件包。记下该数字。
现在您知道了哪个程序包/编号导致崩溃,是时候添加调试器暂停并设置仅在该程序包上执行的条件了。例如,如果您在程序包上崩溃
72285
,请if foo == 72285: import pdb; pdb.set_trace()
在打印的行后添加foo
:再次运行代码。现在当你进入时,
pdb
它应该在导致崩溃的包上。你可以输入变量的名称pkg
来打印它的值,这将告诉你当前包的名称:更一般地说,输入任何变量的名称都会打印其输出。
删除有问题的软件包并再次尝试升级(从干净的 do-release-upgrade 开始)。