Skip to content

Commit

Permalink
fix: Check for dependency architecture error.
Browse files Browse the repository at this point in the history
添加判断是否指定安装包架构类型,未指定的依赖包
将按照安装包架构进行判断。
部分软件包提供多架构支持,例如部分 amd64 软件包
同样提供 i386 支持。

Log: 修复未正确检查依赖包架构。
Bug: https://pms.uniontech.com/bug-view-220019.html
Influence: Dependency
Change-Id: I4893d316048eb3245030a864dccb6071b7a8e838
  • Loading branch information
rb-union committed Sep 22, 2023
1 parent aa7be62 commit 6d3d8bb
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/deb-installer/manager/DealDependThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
112 changes: 106 additions & 6 deletions src/deb-installer/manager/packagesmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 系统架构
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -858,23 +866,27 @@ 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());
} else {
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) {
Expand All @@ -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)
Expand Down Expand Up @@ -1783,6 +1795,91 @@ const PackageDependsStatus PackagesManager::checkDependsPackageStatus(QSet<QStri
}
}

/**
* @brief 检测通过包名 \a packageName 获取的软件包 \a package 架构是否支持建议架构 \a suggestArch 。
* 判断是否指定安装包架构类型,未指定的依赖包将按照安装包架构进行判断,注意,部分软件包提供多架构支持,
* 例如部分 amd64 软件包同样提供 i386 支持。
*
* @bug https://pms.uniontech.com/bug-view-220019.html
*
* @note 此函数期望查找包架构能满足架构依赖,参考 apt 实际行为处理,后续底层改造为 apt-pkg 后,建议重构为调用 apt-pkg 借口。
* 1. 通过命令行指令 `apt-cache showpkg [package name]` 在字段 `Provides` 中可以取得软件包支持的包别名,
* `Provides` 会展示软件包提供的包名列表,这些包名会包含支持的虚包、不同的架构等;
* 2. 部分软件包架构标注 all/any , 但实际并未提供多架构支持,通过 multiArchType() 类型过滤;
* 3. 部分软件包虽然架构未标注 all/any ,但同样提供其他架构的支持,多出现于 amd64/i386 架构软件包互补;
* 4. 如果传入的建议架构 \a suggestArch 为空或支持多架构,同样允许此类架构支持。
*/
bool PackagesManager::checkPackageArchValid(const QApt::Package *package, const QString &packageName, const QString &suggestArch)
{
QString resloveArch = suggestArch;
resloveArch.remove(':');
if (!package) {
// 不打印信息,由后续错误信息提示
return false;
} else if (resloveArch.isEmpty()
|| (package->architecture() == 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)
{
Expand All @@ -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;
}

Expand Down
10 changes: 10 additions & 0 deletions src/deb-installer/manager/packagesmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 50 additions & 2 deletions src/deb-installer/model/deblistmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Transaction *>(sender());
Expand Down Expand Up @@ -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<Transaction *>(sender());
if (!transaction)
Expand Down Expand Up @@ -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正在运行的信息。
Expand Down Expand Up @@ -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")) { //依赖安装失败
Expand All @@ -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)
Expand Down Expand Up @@ -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<int, QString> 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<int, QStringList> 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()
{
}
Expand Down
5 changes: 5 additions & 0 deletions src/deb-installer/model/deblistmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,11 @@ private slots:
*/
void initRefreshPageConnecions();

/**
@brief printDependsChanges 打印安装的依赖包变更
*/
void printDependsChanges();

private:
//当前工作状态
int m_workerStatus = 0;
Expand Down

0 comments on commit 6d3d8bb

Please sign in to comment.