Skip to content

Commit

Permalink
fix: failed to detect replaceable packages
Browse files Browse the repository at this point in the history
The current version only detects the 'replace' field,
'or depends', 'provides depends' of reverse dependency packages
not recognized.

Add targetPackageCanReplace() to detect 'or depends',
'provides depends'. If the installed package can be replaced,
continue installation.

Log: Fix uable to install replaceable packages.
Bug: https://pms.uniontech.com/bug-view-275221.html
  • Loading branch information
rb-union committed Oct 16, 2024
1 parent a89f8b0 commit abb0f1d
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 15 deletions.
93 changes: 90 additions & 3 deletions src/deb-installer/manager/packagesmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ const ConflictResult PackagesManager::isConflictSatisfy(const QString &arch, Pac
return ret_installed;
}

const auto conflictStatus = isConflictSatisfy(arch, package->conflicts(), package->replaces());
const auto conflictStatus = isConflictSatisfy(arch, package->conflicts(), package->replaces(), package);

return conflictStatus;
}
Expand Down Expand Up @@ -484,7 +484,8 @@ const ConflictResult PackagesManager::isInstalledConflict(const QString &package

const ConflictResult PackagesManager::isConflictSatisfy(const QString &arch,
const QList<DependencyItem> &conflicts,
const QList<DependencyItem> &replaces)
const QList<DependencyItem> &replaces,
QApt::Package *targetPackage)
{
for (const auto &conflict_list : conflicts) {
for (const auto &conflict : conflict_list) {
Expand Down Expand Up @@ -550,6 +551,11 @@ const ConflictResult PackagesManager::isConflictSatisfy(const QString &arch,
}
}

// check current package and conflict package provides same package, can be replaced
if (conflict_yes && targetPackage) {
conflict_yes = !targetPackageCanReplace(targetPackage, package);
}

if (!conflict_yes) {
package = nullptr;
continue;
Expand All @@ -566,6 +572,87 @@ const ConflictResult PackagesManager::isConflictSatisfy(const QString &arch,
return ConflictResult::ok(QString());
}

/**
@brief Check if \a targetPackage can replace conflict package \a installedPackage.
If \a targetPackage provides \a installedPackage 's reverse depends package dependencies,
@return True if \a targetPackage meets provides depends or or depends, otherwise false.
*/
bool PackagesManager::targetPackageCanReplace(QApt::Package *targetPackage, QApt::Package *installedPackage)
{
if (!targetPackage || !installedPackage) {
return false;
}

Backend *backend = PackageAnalyzer::instance().backendPtr();
if (!backend) {
return false;
}

auto rdepends = installedPackage->requiredByList().toSet();
// itself package
rdepends.remove(targetPackage->name());
// conflict package
rdepends.remove(installedPackage->name());

// provides package
auto targetProvides = targetPackage->providesList().toSet();
auto installedProvides = installedPackage->providesList().toSet();
auto canReplaceProvides = targetProvides.subtract(installedProvides);

bool replaceable = false;
bool containsInstalledProvides = false;

// requiredByList contains depends, conflicts, recommends, etc.
// we focus on depends, so only check provides depends and or depends.
for (const QString &rdependName: rdepends) {
QApt::Package *rdependPackage = backend->package(rdependName);
if (!rdependPackage || !rdependPackage->isInstalled()) {
continue;
}

QList<DependencyItem> rdependsDep = rdependPackage->depends();
for (const DependencyItem &item : rdependsDep) {
replaceable = false;

// or depends
for (const DependencyInfo &info : item) {
// support provides
if (canReplaceProvides.contains(info.packageName())) {
replaceable = true;
containsInstalledProvides = true;
break;
}

// support depends
if (info.packageName() == targetPackage->name()) {
replaceable = true;
break;
}

if (info.packageName() == installedPackage->name()) {
containsInstalledProvides = true;
}
}

// current or depends contains installedPackage but not contains targetPackage.
if (!replaceable && containsInstalledProvides) {
qWarning() << QString("Package (%1) can't replace (%2), not support (%3)")
.arg(targetPackage->name())
.arg(installedPackage->name())
.arg(rdependPackage->name());
return false;
}

// the current package satisfies the constraint
if (replaceable) {
break;
}
}
}

return true;
}

const ConflictResult PackagesManager::isConflictSatisfy(const QString &arch, const QList<DependencyItem> &conflicts)
{
for (const auto &conflict_list : conflicts) {
Expand Down Expand Up @@ -1857,9 +1944,9 @@ const PackageDependsStatus PackagesManager::checkDependsPackageStatus(QSet<QStri
}
}
}

// let's check conflicts
if (!isConflictSatisfy(realArch, package).is_ok()) {

Backend *backend = PackageAnalyzer::instance().backendPtr();
for (auto *availablePackage : backend->availablePackages()) {
if (!availablePackage->providesList().contains(package->name())) {
Expand Down
6 changes: 5 additions & 1 deletion src/deb-installer/manager/packagesmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,11 @@ public slots:
//带replaces的检查,如果判定待安装包可以替换冲突包,则认为不构成冲突
const ConflictResult isConflictSatisfy(const QString &arch,
const QList<DependencyItem> &conflicts,
const QList<DependencyItem> &replaces);
const QList<DependencyItem> &replaces,
QApt::Package *targetPackage = nullptr);

// detect if targetPackage can replace installedPackage
bool targetPackageCanReplace(QApt::Package *targetPackage, QApt::Package *installedPackage);

//// 依赖查找 获取查找包是否为消极的反向依赖
private:
Expand Down
24 changes: 13 additions & 11 deletions tests/src/manager/ut_packagemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -827,12 +827,14 @@ TEST_F(UT_packagesManager, PackageManager_UT_isConflictSatisfy_0003)
ASSERT_FALSE(cr.is_ok());
}

const ConflictResult stub_isConflictSatisfy(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &)
const ConflictResult stub_isConflictSatisfy(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &,
QApt::Package *)
{
return ConflictResult::ok("1");
}

const ConflictResult stub_isConflictSatisfy_error(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &)
const ConflictResult stub_isConflictSatisfy_error(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &,
QApt::Package *)
{
return ConflictResult::err("1");
}
Expand All @@ -855,7 +857,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_isConflictSatisfy_0004)
stub.set(ADDR(Package, replaces), deb_replaces_null);

stub.set(ADDR(PackagesManager, isInstalledConflict), stub_isInstalledConflict_ok);
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

ConflictResult cr = m_packageManager->isConflictSatisfy("i386", &package);
Expand Down Expand Up @@ -1167,7 +1169,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_getPackageDependsStatus_05)
stub.set(ADDR(Package, isInstalled), stub_isInstalled);


stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy_error);

PackageDependsStatus pd = m_packageManager->getPackageDependsStatus(0);
Expand Down Expand Up @@ -1224,7 +1226,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_getPackageDependsStatus_06)
stub.set(ADDR(PackagesManager, dealInvalidPackage), stub_dealInvalidPackage);
stub.set(ADDR(PackagesManager, isBlackApplication), stub_isBlackApplication_false);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
Expand Down Expand Up @@ -1290,7 +1292,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_getPackageDependsStatus_07)
stub.set(ADDR(PackagesManager, dealInvalidPackage), stub_dealInvalidPackage);
stub.set(ADDR(PackagesManager, isBlackApplication), stub_isBlackApplication_false);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &,
Expand Down Expand Up @@ -2025,7 +2027,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_packageCandidateChoose)
stub.set(ADDR(Package, depends), deb_conflicts_null);
stub.set((QApt::Package * (QApt::Backend::*)(const QString & name) const)ADDR(Backend, package), packagesManager_package);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
Expand Down Expand Up @@ -2061,7 +2063,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_packageCandidateChoose_1)
stub.set(ADDR(Package, depends), deb_conflicts_null);
stub.set((QApt::Package * (QApt::Backend::*)(const QString & name) const)ADDR(Backend, package), packagesManager_package);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
Expand Down Expand Up @@ -2097,7 +2099,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_packageCandidateChoose_2)
stub.set(ADDR(Package, depends), deb_conflicts_null);
stub.set((QApt::Package * (QApt::Backend::*)(const QString & name) const)ADDR(Backend, package), package_package);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
Expand Down Expand Up @@ -2133,7 +2135,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_packageCandidateChoose_3)
stub.set(ADDR(Package, depends), deb_conflicts_null);
stub.set((QApt::Package * (QApt::Backend::*)(const QString & name) const)ADDR(Backend, package), package_package);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy_error);
stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
const QList<QApt::DependencyItem> &))
Expand Down Expand Up @@ -2168,7 +2170,7 @@ TEST_F(UT_packagesManager, PackageManager_UT_packageCandidateChoose_4)
stub.set(ADDR(Package, depends), deb_conflicts_null);
stub.set((QApt::Package * (QApt::Backend::*)(const QString & name) const)ADDR(Backend, package), package_package);

stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &))
stub.set((const ConflictResult(PackagesManager::*)(const QString &, const QList<QApt::DependencyItem> &, const QList<QApt::DependencyItem> &, QApt::Package*))
ADDR(PackagesManager, isConflictSatisfy), stub_isConflictSatisfy_error);

stub.set((const PackageDependsStatus(PackagesManager::*)(QSet<QString> &, const QString &,
Expand Down

0 comments on commit abb0f1d

Please sign in to comment.