From 0b91b76010ced9a4ff16aba714444a5941d3f30a Mon Sep 17 00:00:00 2001 From: renbin Date: Wed, 20 Sep 2023 19:51:20 +0800 Subject: [PATCH] fix: Check for dependency architecture error. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加判断是否指定安装包架构类型,未指定的依赖包 将按照安装包架构进行判断。 部分软件包提供多架构支持,例如部分 amd64 软件包 同样提供 i386 支持。 Log: 修复未正确检查依赖包架构。 Bug: https://pms.uniontech.com/bug-view-220019.html Influence: Dependency Change-Id: I4893d316048eb3245030a864dccb6071b7a8e838 --- .../manager/DealDependThread.cpp | 2 + src/deb-installer/manager/packagesmanager.cpp | 112 +++++++++++++++++- src/deb-installer/manager/packagesmanager.h | 10 ++ src/deb-installer/model/deblistmodel.cpp | 52 +++++++- src/deb-installer/model/deblistmodel.h | 5 + 5 files changed, 173 insertions(+), 8 deletions(-) diff --git a/src/deb-installer/manager/DealDependThread.cpp b/src/deb-installer/manager/DealDependThread.cpp index 9ff722b1..f4ab3bb8 100644 --- a/src/deb-installer/manager/DealDependThread.cpp +++ b/src/deb-installer/manager/DealDependThread.cpp @@ -86,4 +86,6 @@ void DealDependThread::slotInstallFinished(int num = -1) emit signalDependResult(DebListModel::AuthDependsErr, m_index, m_brokenDepend); } emit signalEnableCloseButton(true); + + qInfo() << qPrintable("Process(apt) install finished, num: ") << num << qPrintable("Depends list:") << m_dependsList; } diff --git a/src/deb-installer/manager/packagesmanager.cpp b/src/deb-installer/manager/packagesmanager.cpp index 7069f0b3..6ec59597 100644 --- a/src/deb-installer/manager/packagesmanager.cpp +++ b/src/deb-installer/manager/packagesmanager.cpp @@ -31,6 +31,14 @@ static const QString g_Tagi386 = "i386"; static const QString g_TagDeepinWine = "deepin-wine"; static const QString g_DeepinWineHelper = "deepin-wine-helper"; +/** + * @brief 检测传入软件包架构是否支持多架构 + */ +bool archMultiSupport(const QString &arch) +{ + return "native" == arch || "all" == arch || "any" == arch; +} + /** * @brief isArchMatches 判断包的架构是否符合系统要求 * @param sysArch 系统架构 @@ -822,7 +830,7 @@ PackageDependsStatus PackagesManager::getPackageDependsStatus(const int index) installWineDepends = true; if (!m_installWineThread->isRunning()) { m_dependInstallMark.append(currentPackageMd5); //依赖错误的软件包的标记 更改为md5取代验证下标 - qInfo() << "PackagesManager:" << "command install depends:" << dependList; + qInfo() << "PackagesManager:" << "wine command install depends:" << dependList; m_installWineThread->setDependsList(dependList, index); if (m_brokenDepend.isEmpty()) m_brokenDepend = dependsStatus.package; @@ -858,11 +866,14 @@ void PackagesManager::getPackageOrDepends(const QString &package, const QString } } }; + + QString packageName; QString controlDepends; if (flag) { DebFile debFile(package); if (!debFile.isValid()) return; + packageName = debFile.packageName(); controlDepends = debFile.controlField("Depends"); //软件包 insertToDependsInfo(debFile.depends()); @@ -870,11 +881,12 @@ void PackagesManager::getPackageOrDepends(const QString &package, const QString QApt::Package *pkg = packageWithArch(package, arch); if (!pkg) return; + packageName = pkg->name(); controlDepends = pkg->controlField("Depends"); //子依赖 insertToDependsInfo(pkg->depends()); } - qInfo() << __func__ << controlDepends; + qInfo() << qPrintable("Package:") << packageName << qPrintable("controlDepends") << controlDepends; QStringList dependsList = controlDepends.split(","); auto removedIter = std::remove_if(dependsList.begin(), dependsList.end(), [](const QString & str) { @@ -898,7 +910,7 @@ void PackagesManager::getPackageOrDepends(const QString &package, const QString m_orDepends.append(dependStatus); m_unCheckedOrDepends.append(dependStatus); } - qInfo() << __func__ << m_orDepends; + qInfo() << qPrintable("Package:") << packageName << qPrintable("orDepends") << m_orDepends; } const QString PackagesManager::packageInstalledVersion(const int index) @@ -1783,6 +1795,91 @@ const PackageDependsStatus PackagesManager::checkDependsPackageStatus(QSetarchitecture() == resloveArch) + || archMultiSupport(resloveArch)) { + // 部分传入包名写携带了版本,若版本一致,则无需继续判断 + // 建议架构为多架构支持,则同样允许安装 + return true; + } + + QApt::MultiArchType multiType = package->multiArchType(); + QString pkgArch = package->architecture(); + // 判断传入包是否符合多架构兼容校验 + bool archMatch = isArchMatches(resloveArch, pkgArch, multiType); + // 部分软件包虽然标识 "all" "any", 但仍需进一步判断包支持类型是否为多架构支持。 + bool archTypeMatch = bool(InvalidMultiArchType != multiType); + + bool archIsValidRet = false; + if (archMatch && archTypeMatch) { + archIsValidRet = true; + } else if (archMatch /* && !archTypeMatch */) { + // 软件包标识 "all" "any",但不支持多架构 + Backend *backend = PackageAnalyzer::instance().backendPtr(); + if (!backend) { + return false; + } + + // 如果建议架构是当前架构,同样认为支持 + archIsValidRet = bool(resloveArch == backend->nativeArchitecture()); + } else if (/* !archMatch && */ archTypeMatch) { + // 部分软件包虽然架构和建议架构不同,但软件包提供多架构支持,多为 amd64/i386 相互支持 + QStringList providesList = package->providesList(); + Backend *backend = PackageAnalyzer::instance().backendPtr(); + if (!backend) { + return false; + } + // 判断建议架构是否为当前系统架构,当前系统架构默认无后缀,同时若应用已包含架构名,则不再插入 + bool isNativeArch = bool(resloveArch == backend->nativeArchitecture()); + QString findPackage = (isNativeArch || packageName.contains(":")) + ? packageName : (packageName + ":" + resloveArch); + + // 查找当前软件包支持的包名中是否包含对应架构软件包 + if (providesList.contains(findPackage)) { + qInfo() << QString("Package %1 %2 provides %3, all provides: ").arg(package->name()) + .arg(package->architecture()).arg(findPackage) << providesList; + archIsValidRet = true; + } + } else /* !archTypeMatch && !archMatch */ { + // 等同 archIsValid = false; + } + + if (archIsValidRet) { + qInfo() << QString("Auto detect multi arch package %1 (arch:%2, ver:%3), suggestArch: %4 multiArchType: %5") + .arg(packageName).arg(package->architecture()).arg(package->version()) + .arg(resloveArch).arg(package->multiArchType()); + } else { + qWarning() << QString("Find package %1 (arch:%2, ver:%3)").arg(packageName) + .arg(package->architecture()).arg(package->version()); + qWarning() << QString("but not compitable with %1, multiArchType: %2(%3)").arg(resloveArch) + .arg(package->multiArchTypeString()).arg(package->multiArchType()); + } + + return archIsValidRet; +} + + Package *PackagesManager::packageWithArch(const QString &packageName, const QString &sysArch, const QString &annotation) { @@ -1792,15 +1889,18 @@ Package *PackagesManager::packageWithArch(const QString &packageName, const QStr return nullptr; } - Package *package = backend->package(packageName + resolvMultiArchAnnotation(annotation, sysArch)); + QString suggestArch = resolvMultiArchAnnotation(annotation, sysArch); + Package *package = backend->package(packageName + suggestArch); + // change: 按照当前支持的CPU架构进行打包。取消对deepin-wine的特殊处理 if (!package) package = backend->package(packageName); - if (package) + + if (checkPackageArchValid(package, packageName, suggestArch)) return package; for (QString arch : backend->architectures()) { package = backend->package(packageName + ":" + arch); - if (package) + if (checkPackageArchValid(package, packageName, suggestArch)) return package; } diff --git a/src/deb-installer/manager/packagesmanager.h b/src/deb-installer/manager/packagesmanager.h index 4d337dca..b8c1adfd 100644 --- a/src/deb-installer/manager/packagesmanager.h +++ b/src/deb-installer/manager/packagesmanager.h @@ -394,6 +394,16 @@ public slots: QApt::Package *packageWithArch(const QString &packageName, const QString &sysArch, const QString &annotation = QString()); + /** + * @brief checkPackageArchValid 检测通过包名 \a packageName 获取的软件包 \a package 架构 + * 是否支持建议架构 \a suggestArch + * @param package 软件包 + * @param packageName 软件包名称 + * @param resloveArch 解析建议的软件包名称 + * @return 软件包 \a package 支持 \a suggestArch 架构 + */ + bool checkPackageArchValid(const QApt::Package *package, const QString &packageName, const QString &suggestArch); + private: // 卸载deepin-wine-plugin-virture 时无法卸载deepin-wine-helper. Temporary solution:Special treatment for these package diff --git a/src/deb-installer/model/deblistmodel.cpp b/src/deb-installer/model/deblistmodel.cpp index 370dd044..16077b69 100644 --- a/src/deb-installer/model/deblistmodel.cpp +++ b/src/deb-installer/model/deblistmodel.cpp @@ -657,7 +657,7 @@ QString DebListModel::packageFailedReason(const int idx) const void DebListModel::slotTransactionFinished() { if (m_workerStatus == WorkerProcessing) { - qWarning() << "installer status error"; + qWarning() << "installer status still processing"; } // 获取trans指针 Transaction *transaction = qobject_cast(sender()); @@ -722,7 +722,7 @@ void DebListModel::slotTransactionFinished() void DebListModel::slotDependsInstallTransactionFinished()//依赖安装关系满足 { if (m_workerStatus == WorkerProcessing) { - qWarning() << "installer status error"; + qWarning() << "installer status still processing"; } Transaction *transaction = qobject_cast(sender()); if (!transaction) @@ -794,6 +794,8 @@ void DebListModel::installDebs() DebFile deb(m_packagesManager->package(m_operatingIndex)) ; if (!deb.isValid()) return; + qInfo() << QString("Prepare to install %1, ver: %2, arch: %3").arg(deb.packageName()).arg(deb.version()).arg(deb.architecture()); + Q_ASSERT_X(m_workerStatus == WorkerProcessing, Q_FUNC_INFO, "installer status error"); Q_ASSERT_X(m_currentTransaction.isNull(), Q_FUNC_INFO, "previous transaction not finished"); //在判断dpkg启动之前就发送开始安装的信号,并在安装信息中输出 dpkg正在运行的信息。 @@ -835,6 +837,8 @@ void DebListModel::installDebs() // 获取到所有的依赖包 准备安装 const QStringList availableDepends = m_packagesManager->packageAvailableDepends(m_operatingIndex); + qInfo() << QString("Prepare install package: %1 , install depends: ").arg(deb.packageName()) << availableDepends; + //获取到可用的依赖包并根据后端返回的结果判断依赖包的安装结果 for (auto const &p : availableDepends) { if (p.contains(" not found")) { //依赖安装失败 @@ -844,10 +848,14 @@ void DebListModel::installDebs() m_packageFailReason.insert(m_operatingPackageMd5, p); emit signalAppendOutputInfo(m_packagesManager->package(m_operatingIndex) + "\'s depend " + " " + p); //输出错误原因 bumpInstallIndex(); //开始安装下一个包或结束安装 + + qWarning() << QString("Packge %1 install failed, not found depend package: %2").arg(deb.packageName()).arg(p); return; } backend->markPackageForInstall(p); //开始安装依赖包 } + // 打印待安装的软件包信息 + printDependsChanges(); transaction = backend->commitChanges(); if (!transaction) @@ -1688,6 +1696,46 @@ DebListModel::~DebListModel() delete m_procInstallConfig; } +/** + @brief 打印待安装的软件包信息,将根据安装、升级、卸载等分类分别打印对应变更的软件包 + */ +void DebListModel::printDependsChanges() +{ + auto *const backend = PackageAnalyzer::instance().backendPtr(); + if (!backend) { + return; + } + + auto changeList = backend->markedPackages(); + if (changeList.isEmpty()) { + return; + } + + static QMap tagTable = { {Package::IsManuallyHeld, "Package::IsManuallyHeld"}, + {Package::NewInstall, "Package::NewInstall"}, + {Package::ToReInstall, "Package::ToReInstall"}, + {Package::ToUpgrade, "Package::ToUpgrade"}, + {Package::ToDowngrade, "Package::ToDowngrade"}, + {Package::ToRemove, "Package::ToRemove"} }; + QMap changeInfo; + + for (const Package *package : changeList) { + int flags = package->state(); + int status = flags & (Package::IsManuallyHeld | + Package::NewInstall | + Package::ToReInstall | + Package::ToUpgrade | + Package::ToDowngrade | + Package::ToRemove); + changeInfo[status] << QString("%1, %2, %3").arg(package->name()).arg(package->version()).arg(package->architecture()); + } + + qInfo() << "Install depends details:"; + for (auto info = changeInfo.begin(); info != changeInfo.end(); info++) { + qInfo() << tagTable[info.key()] << info.value(); + } +} + Dialog::Dialog() { } diff --git a/src/deb-installer/model/deblistmodel.h b/src/deb-installer/model/deblistmodel.h index 6e2f6498..42544d5f 100644 --- a/src/deb-installer/model/deblistmodel.h +++ b/src/deb-installer/model/deblistmodel.h @@ -747,6 +747,11 @@ private slots: */ void initRefreshPageConnecions(); + /** + @brief printDependsChanges 打印安装的依赖包变更 + */ + void printDependsChanges(); + private: //当前工作状态 int m_workerStatus = 0;