diff --git a/CMakeLists.txt b/CMakeLists.txt index 8b90191..a2a3b49 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2023-2026 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: CC0-1.0 @@ -77,6 +77,7 @@ target_link_libraries(${BIN_NAME} PRIVATE install(TARGETS ${BIN_NAME} DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) install(FILES scripts/dde-appwiz-uninstaller.sh DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) install(FILES scripts/dde-appwiz-linglong-uninstaller.sh DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) +install(FILES scripts/dde-appwiz-apm-uninstaller.sh DESTINATION ${CMAKE_INSTALL_LIBEXECDIR}) install(FILES polkit-1/actions/org.deepin.dde.appwiz.uninstall.policy DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/actions) install(FILES polkit-1/rules.d/org.deepin.dde.application-wizard.rules DESTINATION ${CMAKE_INSTALL_DATADIR}/polkit-1/rules.d) install(FILES ${TRANSLATED_FILES} DESTINATION ${CMAKE_INSTALL_DATADIR}/dde-application-wizard/translations) diff --git a/dbus/launcher1compat.cpp b/dbus/launcher1compat.cpp index 472f420..681195b 100644 --- a/dbus/launcher1compat.cpp +++ b/dbus/launcher1compat.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -88,7 +88,13 @@ bool uninstallLinglongBundle(const DDesktopEntry & entry) QProcess process; qDebug() << "Uninstalling Linglong bundle" << appId << "via script"; process.start("pkexec", QStringList{"/usr/libexec/dde-appwiz-linglong-uninstaller.sh", appId}); - process.waitForFinished(); + + bool finished = process.waitForFinished(300000); // 5 minutes timeout + if (!finished) { + qDebug() << "Process timed out or failed to finish"; + process.kill(); + return false; + } return process.exitCode() == 0; } @@ -146,7 +152,15 @@ void Launcher1Compat::uninstallDCMPackage(const QString & pkgDisplayName, const args.prepend("env"); process.start("pkexec", args); - process.waitForFinished(); + + bool finished = process.waitForFinished(300000); // 5 minutes timeout + if (!finished) { + qDebug() << "Process timed out or failed to finish"; + process.kill(); + sendNotification(pkgDisplayName, false, m_base64Icon); + return; + } + if (process.exitCode() != 0) { sendNotification(pkgDisplayName, false, m_base64Icon); } else { @@ -163,7 +177,14 @@ void Launcher1Compat::uninstallPackageByScript(const QString & pkgDisplayName, c qDebug() << "Calling dde-appwiz-uninstaller.sh to uninstall" << pkgDisplayName << packageDesktopFilePath << "via script"; QProcess process; process.start("pkexec", QStringList{"/usr/libexec/dde-appwiz-uninstaller.sh", packageDesktopFilePath}); - process.waitForFinished(); + + bool finished = process.waitForFinished(300000); // 5 minutes timeout + if (!finished) { + qDebug() << "Process timed out or failed to finish"; + process.kill(); + sendNotification(pkgDisplayName, false, m_base64Icon); + return; + } QString standardOutput = process.readAllStandardOutput(); QString standardError = process.readAllStandardError(); @@ -174,12 +195,42 @@ void Launcher1Compat::uninstallPackageByScript(const QString & pkgDisplayName, c sendNotification(pkgDisplayName, false, m_base64Icon); } else { sendNotification(pkgDisplayName, true, m_base64Icon); - QFileInfo fi(m_desktopFilePath); + QFileInfo fi(packageDesktopFilePath); // FIXME: THIS IS NOT DESKTOP ID postUninstallCleanUp(fi.fileName(), PackageType::Deb); } } +void Launcher1Compat::uninstallAPMPackage(const QString & pkgDisplayName, const QString & packageDesktopFilePath) +{ + // call `/usr/libexec/dde-appwiz-apm-uninstaller.sh ` and check the return code. + qDebug() << "Calling dde-appwiz-apm-uninstaller.sh to uninstall" << pkgDisplayName << packageDesktopFilePath << "via script"; + QProcess process; + process.start("pkexec", QStringList{"/usr/libexec/dde-appwiz-apm-uninstaller.sh", packageDesktopFilePath}); + + bool finished = process.waitForFinished(300000); // 5 minutes timeout + if (!finished) { + qDebug() << "Process timed out or failed to finish"; + process.kill(); + sendNotification(pkgDisplayName, false, m_base64Icon); + return; + } + + QString standardOutput = process.readAllStandardOutput(); + QString standardError = process.readAllStandardError(); + qDebug() << "stdout:" << standardOutput; + qDebug() << "stderr:" << standardError; + + if (process.exitCode() != 0) { + sendNotification(pkgDisplayName, false, m_base64Icon); + } else { + sendNotification(pkgDisplayName, true, m_base64Icon); + QFileInfo fi(packageDesktopFilePath); + // FIXME: THIS IS NOT DESKTOP ID + postUninstallCleanUp(fi.fileName(), PackageType::APM); + } +} + // the 1st argument is the full path of a desktop file. void Launcher1Compat::RequestUninstall(const QString & desktop, bool skipPreinstallHook) { @@ -259,6 +310,8 @@ void Launcher1Compat::RequestUninstall(const QString & desktop, bool skipPreinst } } + m_packageDisplayName = desktopEntry.ddeDisplayName(); + // Check and do uninstallation if (desktopFilePath.contains("/persistent/linglong") || desktopFilePath.contains("/var/lib/linglong")) { // Uninstall Linglong Bundle @@ -274,10 +327,11 @@ void Launcher1Compat::RequestUninstall(const QString & desktop, bool skipPreinst emit UninstallSuccess(desktopFilePath); sendNotification(desktopEntry.ddeDisplayName(), true, m_base64Icon); } + } else if (!desktopEntry.stringValue("X-APM-APPID").isEmpty()) { + // Uninstall APM Package + uninstallAPMPackage(m_packageDisplayName, desktopFilePath); // TODO: check if it's a flatpak or snap bundle and do the uninstallation? } else { - m_packageDisplayName = desktopEntry.ddeDisplayName(); - const QString compatibleDesktopJsonPath("/var/lib/deepin-compatible/compatibleDesktop.json"); if (QFile::exists(compatibleDesktopJsonPath)) { qDebug() << "Found compatibleDesktop.json, checking if" << m_packageDisplayName << "is a compatible-mode application."; diff --git a/dbus/launcher1compat.h b/dbus/launcher1compat.h index a1b461c..b0a5349 100644 --- a/dbus/launcher1compat.h +++ b/dbus/launcher1compat.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2023-2026 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: GPL-3.0-or-later @@ -12,7 +12,8 @@ enum class PackageType { Linglong, // 玲珑包 Flatpak, // Flatpak包 Deb, // deb包/PackageKit包 - DCM // DCM兼容模式包 + DCM, // DCM兼容模式包 + APM // APM包 }; class Launcher1Adaptor; @@ -41,6 +42,7 @@ class Launcher1Compat : public QObject, protected QDBusContext void uninstallPackageKitPackage(const QString & pkgDisplayName, const QString & pkPackageId); void uninstallDCMPackage(const QString & pkgDisplayName, const QString & uninstallCmd); void uninstallPackageByScript(const QString & pkgDisplayName, const QString & packageDesktopFilePath); + void uninstallAPMPackage(const QString & pkgDisplayName, const QString & packageDesktopFilePath); Launcher1Adaptor * m_daemonLauncher1Adapter; diff --git a/polkit-1/actions/org.deepin.dde.appwiz.uninstall.policy b/polkit-1/actions/org.deepin.dde.appwiz.uninstall.policy index 52c1074..878ec85 100644 --- a/polkit-1/actions/org.deepin.dde.appwiz.uninstall.policy +++ b/polkit-1/actions/org.deepin.dde.appwiz.uninstall.policy @@ -23,4 +23,15 @@ /usr/libexec/dde-appwiz-linglong-uninstaller.sh true + + Uninstall a APM application + Authentication is required to uninstall a APM bundle application. + + auth_admin + auth_admin + auth_admin + + /usr/libexec/dde-appwiz-apm-uninstaller.sh + true + diff --git a/polkit-1/rules.d/org.deepin.dde.application-wizard.rules b/polkit-1/rules.d/org.deepin.dde.application-wizard.rules index a4fab9d..88dc255 100644 --- a/polkit-1/rules.d/org.deepin.dde.application-wizard.rules +++ b/polkit-1/rules.d/org.deepin.dde.application-wizard.rules @@ -4,6 +4,7 @@ polkit.addRule(function(action, subject) { if ((action.id == "org.deepin.dde.appwiz.uninstall" || + action.id == "org.deepin.dde.appwiz.uninstall.apm" || action.id == "org.deepin.dde.appwiz.uninstall.linglong") && subject.active == true && subject.local == true && subject.isInGroup("sudo")) { diff --git a/scripts/dde-appwiz-apm-uninstaller.sh b/scripts/dde-appwiz-apm-uninstaller.sh new file mode 100755 index 0000000..80a618d --- /dev/null +++ b/scripts/dde-appwiz-apm-uninstaller.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# 检查是否提供了文件参数 +if [ $# -eq 0 ]; then + echo "错误: 请提供一个文件作为参数" + echo "用法: $0 <文件路径>" + exit 1 +fi + +FILE="$1" + +# 检查文件是否存在 +if [ ! -f "$FILE" ]; then + echo "错误: 文件 '$FILE' 不存在" + exit 1 +fi + +# 检查文件中是否包含 X-APM-APPID= +if ! grep -q "X-APM-APPID=" "$FILE"; then + echo "错误: 文件中未找到 'X-APM-APPID=' 内容" + exit 1 +fi + +# 提取 X-APM-APPID= 的值 +APPID=$(grep -o "X-APM-APPID=[^ ]*" "$FILE" | head -1 | cut -d'=' -f2) + +# 检查是否成功提取到值 +if [ -z "$APPID" ]; then + echo "错误: 无法提取 X-APM-APPID 的值" + exit 1 +fi + +echo "找到 APM ID: $APPID" + +# 如果不是root用户,则使用pkexec +if [ "$EUID" -ne 0 ]; then + echo "当前不是root用户,使用 pkexec 提升权限..." + exec pkexec apm autoremove "$APPID" -y +else + echo "以root用户身份执行命令..." + exec apm autoremove "$APPID" -y +fi \ No newline at end of file