From 20e8bbe8ce63ebc333f8805cfadb4f24a10b9ce2 Mon Sep 17 00:00:00 2001 From: renbin Date: Wed, 27 Nov 2024 16:25:38 +0800 Subject: [PATCH] feat: uab installation add authentication Linglong's backend DBus interface is unstable, may change frequently in the near future. We currently choose the cli interface, use the DBus interface in the future. Log: UAB installation add authentication. Task: https://pms.uniontech.com/story-view-36033.html Influence: uab-package --- src/AptInstallDepend/CMakeLists.txt | 32 +-- src/AptInstallDepend/installDebThread.cpp | 54 ++++- src/AptInstallDepend/installDebThread.h | 8 +- .../compatible_process_controller.h | 2 +- .../immutable/immutable_process_controller.h | 2 +- .../uab/uab_dbus_package_manager.cpp | 224 ------------------ .../uab/uab_dbus_package_manager.h | 69 ------ src/deb-installer/uab/uab_defines.h | 2 +- src/deb-installer/uab/uab_package.cpp | 4 + .../uab/uab_package_list_model.cpp | 5 + .../uab/uab_process_controller.cpp | 100 +++++--- .../uab/uab_process_controller.h | 18 +- tests/src/uab/ut_uab_process_controller.cpp | 8 +- translations/deepin-deb-installer.ts | 166 +++++++------ translations/deepin-deb-installer_zh_CN.ts | 170 ++++++------- translations/deepin-deb-installer_zh_HK.ts | 166 +++++++------ translations/deepin-deb-installer_zh_TW.ts | 182 +++++++------- 17 files changed, 516 insertions(+), 696 deletions(-) delete mode 100644 src/deb-installer/uab/uab_dbus_package_manager.cpp delete mode 100644 src/deb-installer/uab/uab_dbus_package_manager.h diff --git a/src/AptInstallDepend/CMakeLists.txt b/src/AptInstallDepend/CMakeLists.txt index c76e6cfb..5f9ff8bb 100644 --- a/src/AptInstallDepend/CMakeLists.txt +++ b/src/AptInstallDepend/CMakeLists.txt @@ -1,15 +1,15 @@ -# SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +# SPDX-FileCopyrightText: 2022 - 2024 UnionTech Software Technology Co., Ltd. # # SPDX-License-Identifier: CC0-1.0 cmake_minimum_required(VERSION 3.13) -if (NOT DEFINED VERSION) +if(NOT DEFINED VERSION) set(VERSION 5.3.9) -endif () +endif() project(AptInstallDepend) -set (EXE_NAME deepin-deb-installer-dependsInstall) +set(EXE_NAME deepin-deb-installer-dependsInstall) set(LINK_LIBS Qt5::Core ) @@ -19,31 +19,33 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") -#安全测试加固编译参数 +# 安全测试加固编译参数 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -z relro -z now -z noexecstack -pie") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -z relro -z now -z noexecstack -pie") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fstack-protector-all") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fstack-protector-all") -#add process directories -string(REGEX REPLACE "(.*)/(.*)" "\\1" PROJECT_INIT_PATH ${PROJECT_SOURCE_DIR}) +# add process directories +string(REGEX REPLACE "(.*)/(.*)" "\\1" PROJECT_INIT_PATH ${PROJECT_SOURCE_DIR}) include_directories(${PROJECT_INIT_PATH}/deb-installer/process) -file(GLOB_RECURSE AUTH_CPP_FILES ${CMAKE_CURRENT_LIST_DIR}/*.h ${CMAKE_CURRENT_LIST_DIR}/*.cpp ${PROJECT_INIT_PATH}/deb-installer/process/*.cpp) -add_executable (${EXE_NAME} +file(GLOB_RECURSE AUTH_CPP_FILES + ${CMAKE_CURRENT_LIST_DIR}/*.h + ${CMAKE_CURRENT_LIST_DIR}/*.cpp + ${PROJECT_INIT_PATH}/deb-installer/process/*.cpp) +add_executable(${EXE_NAME} ${AUTH_CPP_FILES} ) # Find the library -find_package(PkgConfig REQUIRED) -find_package(Qt5Widgets REQUIRED) -find_package(Qt5Gui REQUIRED) -find_package(Qt5Core REQUIRED) +find_package(Qt5 REQUIRED Core Gui Widgets) set(CMAKE_INSTALL_PREFIX /usr) + # Install files install(TARGETS ${EXE_NAME} DESTINATION bin) -target_link_libraries(${EXE_NAME} ${LINK_LIBS} ) +target_link_libraries(${EXE_NAME} ${LINK_LIBS}) target_link_libraries(${EXE_NAME} Qt5::Core + Qt5::Gui Qt5::Widgets - Qt5::Gui) +) diff --git a/src/AptInstallDepend/installDebThread.cpp b/src/AptInstallDepend/installDebThread.cpp index cd6648aa..357003b6 100644 --- a/src/AptInstallDepend/installDebThread.cpp +++ b/src/AptInstallDepend/installDebThread.cpp @@ -10,6 +10,7 @@ static const QString kParamInstallWine = "install_wine"; static const QString kParamInstallConfig = "install_config"; static const QString kParamInstallComaptible = "install_compatible"; static const QString kParamInstallImmutable = "install_immutable"; +static const QString kParamInstallUab = "uab"; static const QString kInstall = "install"; static const QString kRemove = "remove"; @@ -38,6 +39,9 @@ InstallDebThread::InstallDebThread() connect(m_proc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(onFinished(int, QProcess::ExitStatus))); connect(m_proc, SIGNAL(readyReadStandardOutput()), this, SLOT(onReadoutput())); + connect(m_proc, &KProcess::readyReadStandardError, this, [this](){ + qWarning() << m_proc->readAllStandardError(); + }); } InstallDebThread::~InstallDebThread() @@ -52,11 +56,12 @@ void InstallDebThread::setParam(const QStringList &arguments) return; } - // normal command; + // normal command static QMap kParamMap{{kParamInstallWine, InstallWine}, {kParamInstallConfig, InstallConfig}, {kParamInstallComaptible, Compatible}, {kParamInstallImmutable, Immutable}, + {kParamInstallUab, LinglongUab}, {kInstall, Install}, {kRemove, Remove}}; @@ -149,6 +154,8 @@ void InstallDebThread::run() } else if (m_cmds.testFlag(InstallConfig)) { // InstallConfig must last, Compatible and Immutable maybe set InstallConfig too. installConfig(); + } else if (m_cmds.testFlag(LinglongUab)) { + uabProcessCli(); } } @@ -167,9 +174,7 @@ void InstallDebThread::installWine() // On immutable system: --fix-missing not support, apt command will transport to deepin-immutable-ctl system("echo 'libpam-runtime libpam-runtime/override boolean false' | debconf-set-selections"); system("echo 'libc6 libraries/restart-without-asking boolean true' | sudo debconf-set-selections\n"); - m_proc->setProgram("sudo", - QStringList() << "apt-get" - << "install" << m_listParam << "-y"); + m_proc->setProgram("apt-get", QStringList() << "install" << m_listParam << "-y"); m_proc->start(); m_proc->waitForFinished(-1); m_proc->close(); @@ -322,6 +327,47 @@ void InstallDebThread::immutableProcess() } } +/** + @brief Install / unisntall uab package in Linglong. + + @todo Linglong's backend DBus interface is unstable, may change frequently in the near future. + We currently choose the cli interface, use the DBus interface in the future. + */ +void InstallDebThread::uabProcessCli() +{ + if (m_listParam.isEmpty()) { + return; + } + // The Linglong params + static const QString kUabBin = "ll-cli"; + static const QString kUabInstall = "install"; + static const QString kUabUninstall = "uninstall"; + static const QString kUabJson = "--json"; + static const QString kUabForce = "--force"; // Force install the application + static const QString kUabPass = "-y"; // Automatically answer yes to all questions + + QStringList params; + + if (m_cmds.testFlag(Install)) { + // e.g.: ll-cli install --json --force -y [uab file] + params << kUabInstall << kUabJson << kUabForce << kUabPass << m_listParam.first(); + + } else if (m_cmds.testFlag(Remove)) { + // e.g.: ll-cli uninstall --json [id/version] + params << kUabUninstall << kUabJson << m_listParam.first(); + + } else { + return; + } + + m_proc->setProgram(kUabBin, params); + qInfo() << "Exec:" << qPrintable(m_proc->program().join(' ')); + + m_proc->start(); + m_proc->waitForFinished(-1); + m_proc->close(); +} + /** * @brief PackagesManager::SymbolicLink 创建软连接 * @param previousName 原始路径 diff --git a/src/AptInstallDepend/installDebThread.h b/src/AptInstallDepend/installDebThread.h index e9caa393..973de256 100644 --- a/src/AptInstallDepend/installDebThread.h +++ b/src/AptInstallDepend/installDebThread.h @@ -28,11 +28,12 @@ class InstallDebThread : public QThread InstallWine = 1 << 3, InstallConfig = 1 << 4, // DebConf install - Compatible = 1 << 5, // compatible mode - Immutable = 1 << 6, // immutable system + Compatible = 1 << 5, // compatible mode + Immutable = 1 << 6, // immutable system + LinglongUab = 1 << 7, // linglong app(lingyaps) }; Q_DECLARE_FLAGS(Commands, Command) - Q_FLAG(Commands); + Q_FLAG(Commands) InstallDebThread(); virtual ~InstallDebThread(); @@ -53,6 +54,7 @@ public slots: void installConfig(); void compatibleProcess(); void immutableProcess(); + void uabProcessCli(); // 使用软连接方式解决文件路径中存在空格的问题。 QString SymbolicLink(const QString &previousName, const QString &packageName); diff --git a/src/deb-installer/compatible/compatible_process_controller.h b/src/deb-installer/compatible/compatible_process_controller.h index 9790afe8..9b12e09d 100644 --- a/src/deb-installer/compatible/compatible_process_controller.h +++ b/src/deb-installer/compatible/compatible_process_controller.h @@ -11,7 +11,7 @@ namespace Konsole { class Pty; -}; // namespace Konsole +} // namespace Konsole namespace Compatible { diff --git a/src/deb-installer/immutable/immutable_process_controller.h b/src/deb-installer/immutable/immutable_process_controller.h index 8d261b3b..4ecc66af 100644 --- a/src/deb-installer/immutable/immutable_process_controller.h +++ b/src/deb-installer/immutable/immutable_process_controller.h @@ -11,7 +11,7 @@ namespace Konsole { class Pty; -}; // namespace Konsole +} // namespace Konsole namespace Immutable { diff --git a/src/deb-installer/uab/uab_dbus_package_manager.cpp b/src/deb-installer/uab/uab_dbus_package_manager.cpp deleted file mode 100644 index 2394f745..00000000 --- a/src/deb-installer/uab/uab_dbus_package_manager.cpp +++ /dev/null @@ -1,224 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "uab_dbus_package_manager.h" - -#include -#include -#include -#include -#include -#include - -namespace Uab { - -const QString kllDBusService = "org.deepin.linglong.PackageManager"; -const QString kllDBusPath = "/org/deepin/linglong/PackageManager"; -const QString kllDBusInterface = "org.deepin.linglong.PackageManager1"; -// method -const QString kllDBusInstallFromFile = "InstallFromFile"; -const QString kllDBusInstall = "Install"; -const QString kllDBusUninstall = "Uninstall"; -const QString kllDBusUpdate = "Update"; -const QString kllDBusSearch = "Search"; -const QString kllDBusCancelTask = "CancelTask"; -// signal -const QString kllDBusSignalTaskChanged = "TaskChanged"; - -// uninstall param keys -const QString kllParamPackage = "package"; -const QString kllParamId = "id"; -const QString kllParamVersion = "version"; -const QString kllParamChannel = "channel"; -const QString kllParamModule = "packageManager1PackageModule"; - -// result tag -const QString kllRetCode = "code"; -const QString kllRetTaskId = "taskID"; -const QString kllRetMessage = "message"; - -UabDBusPackageManager::UabDBusPackageManager() {} - -void UabDBusPackageManager::ensureInterface() -{ - if (!m_interface.isNull()) { - return; - } - - QDBusConnection connection = QDBusConnection::systemBus(); - connection.connect(kllDBusService, - kllDBusPath, - kllDBusInterface, - kllDBusSignalTaskChanged, - this, - SLOT(onTaskChanged(const QString &, const QString &, const QString &, int))); - - m_interface.reset(new QDBusInterface(kllDBusService, kllDBusPath, kllDBusInterface, connection)); - if (!m_interface->isValid()) { - qInfo() << qPrintable("LinglongPM dbus create fails:") << m_interface->lastError().message(); - } -} - -bool UabDBusPackageManager::isRunning() const -{ - return !m_currentTask.taskId.isEmpty(); -} - -void UabDBusPackageManager::onTaskChanged(const QString &recTaskID, const QString &percentage, const QString &message, int status) -{ - qInfo() << QString("From LinglingPM, [task]: %1 [percentage]: %2 [message]: %3 [status]: %4") - .arg(recTaskID) - .arg(percentage) - .arg(message) - .arg(status); - - if (recTaskID != m_currentTask.taskId) { - return; - } - - Q_EMIT progressChanged(percentage.toInt(), message); - - switch (status) { - case UabDBusPackageManager::Success: - m_currentTask.taskId.clear(); - Q_EMIT packageFinished(true); - break; - case UabDBusPackageManager::Failed: - m_currentTask.taskId.clear(); - Q_EMIT packageFinished(false); - break; - case UabDBusPackageManager::Canceled: - m_currentTask.taskId.clear(); - break; - default: - break; - } -} - -UabDBusPackageManager *UabDBusPackageManager::instance() -{ - static UabDBusPackageManager ins; - return &ins; -} - -bool UabDBusPackageManager::isValid() -{ - ensureInterface(); - return m_interface->isValid(); -} - -/** - @brief Install package \a installPtr , - @return True if call Linglong package manager install package file start. otherwise false. - */ -bool UabDBusPackageManager::installFormFile(const UabPackage::Ptr &installPtr) -{ - if (!installPtr || !installPtr->isValid() || isRunning()) { - return false; - } - ensureInterface(); - - QFile file(installPtr->info()->filePath); - if (!file.open(QFile::ReadOnly | QFile::ExistingOnly)) { - return false; - } - - const QDBusUnixFileDescriptor dbusFd(file.handle()); - QDBusReply reply = - m_interface->call(kllDBusInstallFromFile, QVariant::fromValue(dbusFd), QFileInfo(file.fileName()).suffix()); - if (reply.error().isValid()) { - qWarning() << qPrintable("call LinglongPM dbus fails:") << reply.error().message(); - return false; - } - - const QVariantMap data = reply.value(); - const int code = data.value(kllRetCode).toInt(); - if (Uab::UabSuccess != code) { - qWarning() << QString("LinglingPM return error: [%1] %2").arg(code).arg(data.value(kllRetMessage).toString()); - return false; - } - - m_currentTask.taskId = data.value(kllRetTaskId).toString(); - m_currentTask.code = code; - m_currentTask.message = data.value(kllRetMessage).toString(); - - qInfo() << QString("Requset LinglingPM install: %1/%2 [task]: %3 [message]: %4") - .arg(installPtr->info()->id) - .arg(installPtr->info()->version) - .arg(m_currentTask.taskId) - .arg(m_currentTask.message); - - Q_EMIT progressChanged(0, m_currentTask.message); - return true; -} - -/** - @brief Uninstall \a uninstallPtr package. - This function will return immediately, and the uninstall process will run in the thread-pool, - avoid the dbus interface blocks threads. - @return True if uninstall start, false if \a uninstallPtr invalid or is running - */ -bool UabDBusPackageManager::uninstall(const UabPackage::Ptr &uninstallPtr) -{ - if (!uninstallPtr || !uninstallPtr->isValid() || isRunning()) { - return false; - } - ensureInterface(); - - m_currentTask.taskId = "mark uninstall"; - - QtConcurrent::run([this, uninstallPtr]() { - bool callRet{false}; - QString message; - - do { - QVariantMap pkgParams; - pkgParams[kllParamId] = uninstallPtr->info()->id; - pkgParams[kllParamVersion] = uninstallPtr->info()->version; - pkgParams[kllParamChannel] = uninstallPtr->info()->channel; - pkgParams[kllParamModule] = uninstallPtr->info()->module; - QVariantMap params; - params[kllParamPackage] = pkgParams; - - QDBusReply reply = m_interface->call(kllDBusUninstall, params); - if (reply.error().isValid()) { - qWarning() << qPrintable("call LinglongPM dbus fails:") << reply.error().message(); - break; - } - - const QVariantMap data = reply.value(); - const int code = data.value(kllRetCode).toInt(); - if (Uab::UabSuccess != code) { - message = data.value(kllRetMessage).toString(); - qWarning() << QString("LinglingPM return error: [%1] %2").arg(code).arg(message); - break; - } - - const QString taskId = data.value(kllRetTaskId).toString(); - message = data.value(kllRetMessage).toString(); - - qInfo() << QString("Requset LinglingPM uninstall: %1/%2 [message]: %3") - .arg(uninstallPtr->info()->id) - .arg(uninstallPtr->info()->version) - .arg(message); - - callRet = true; - } while (false); - - // notify on package manager thread - QMetaObject::invokeMethod( - this, - [this, message, callRet]() { - m_currentTask.taskId.clear(); - Q_EMIT progressChanged(callRet ? 100 : 0, message); - Q_EMIT packageFinished(callRet); - }, - Qt::QueuedConnection); - }); - - // uninstall not need receive task info, remove imdealtly and fast - return true; -} - -} // namespace Uab diff --git a/src/deb-installer/uab/uab_dbus_package_manager.h b/src/deb-installer/uab/uab_dbus_package_manager.h deleted file mode 100644 index bb80fcf5..00000000 --- a/src/deb-installer/uab/uab_dbus_package_manager.h +++ /dev/null @@ -1,69 +0,0 @@ -// SPDX-FileCopyrightText: 2024 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef UAB_DBUS_PACKAGE_MANAGER_H -#define UAB_DBUS_PACKAGE_MANAGER_H - -#include -#include -#include - -#include "uab_package.h" - -namespace Uab { - -// DBus interface: org.deepin.linglong.PackageManager -class UabDBusPackageManager : public QObject -{ - Q_OBJECT -public: - static UabDBusPackageManager *instance(); - - [[nodiscard]] bool isValid(); - - [[nodiscard]] bool installFormFile(const UabPackage::Ptr &installPtr); - [[nodiscard]] bool uninstall(const UabPackage::Ptr &uninstallPtr); - - Q_SIGNAL void progressChanged(int progress, const QString &message); - Q_SIGNAL void packageFinished(bool success); - -private: - // from linyaps task.h linglong::service::InstallTask::Status - enum Status { - Queued, - preInstall, - installRuntime, - installBase, - installApplication, - postInstall, - Success, - Failed, - Canceled // manualy cancel - }; - - UabDBusPackageManager(); - ~UabDBusPackageManager() override = default; - - void ensureInterface(); - [[nodiscard]] bool isRunning() const; - - Q_SLOT void onTaskChanged(const QString &recTaskID, const QString &percentage, const QString &message, int status); - - // linglnog dbus interface result - struct DBusResult - { - QString taskId; - int code{0}; - QString message; - }; - DBusResult m_currentTask; - - QScopedPointer m_interface; - - Q_DISABLE_COPY(UabDBusPackageManager) -}; - -} // namespace Uab - -#endif // UAB_DBUS_PACKAGE_MANAGER_H diff --git a/src/deb-installer/uab/uab_defines.h b/src/deb-installer/uab/uab_defines.h index a6e2c2ba..f703e6e8 100644 --- a/src/deb-installer/uab/uab_defines.h +++ b/src/deb-installer/uab/uab_defines.h @@ -31,7 +31,7 @@ struct UabPkgInfo QString module; }; -}; // namespace Uab +} // namespace Uab QT_BEGIN_NAMESPACE #ifndef QT_NO_DEBUG_STREAM diff --git a/src/deb-installer/uab/uab_package.cpp b/src/deb-installer/uab/uab_package.cpp index cb7ad46e..c79c7e7a 100644 --- a/src/deb-installer/uab/uab_package.cpp +++ b/src/deb-installer/uab/uab_package.cpp @@ -92,6 +92,10 @@ QString UabPackage::installedVersion() const QString UabPackage::failedReason() const { + if (m_failReason.isEmpty()) { + return m_processError; + } + return m_failReason; } diff --git a/src/deb-installer/uab/uab_package_list_model.cpp b/src/deb-installer/uab/uab_package_list_model.cpp index d99924a3..a764c8bd 100644 --- a/src/deb-installer/uab/uab_package_list_model.cpp +++ b/src/deb-installer/uab/uab_package_list_model.cpp @@ -434,6 +434,11 @@ void UabPackageListModel::setCurrentOperation(Pkg::PackageOperationStatus s) auto &uabPtr = m_uabPkgList[m_operatingIndex]; uabPtr->m_operationStatus = s; + // mark error info + if (Pkg::Failed == s) { + uabPtr->setProcessError(Pkg::UnknownError, tr("Installation Failed")); + } + Q_EMIT dataChanged(index(m_operatingIndex), index(m_operatingIndex), {PackageOperateStatusRole}); } diff --git a/src/deb-installer/uab/uab_process_controller.cpp b/src/deb-installer/uab/uab_process_controller.cpp index 8791c577..56306aa1 100644 --- a/src/deb-installer/uab/uab_process_controller.cpp +++ b/src/deb-installer/uab/uab_process_controller.cpp @@ -12,7 +12,7 @@ #include #include "uab_backend.h" -#include "uab_dbus_package_manager.h" +#include "process/Pty.h" namespace Uab { @@ -28,16 +28,19 @@ const QString kJsonState = "state"; const QString kJsonCode = "code"; const QString kJsonMessage = "messsage"; +// transport install/uninstall task to higher level permission process. +static const QString kPkexecBin = "pkexec"; +static const QString kInstallProcessorBin = "deepin-deb-installer-dependsInstall"; +static const QString kParamUab = "--uab"; +static const QString kParamInstall = "--install"; +static const QString kParamRemove = "--remove"; + const int kInitedIndex = -1; UabProcessController::UabProcessController(QObject *parent) : QObject{parent} { - if (UabDBusPackageManager::instance()->isValid()) { - setProcessType(DBus); - } else { - setProcessType(Cli); - } + setProcessType(BackendCli); } void UabProcessController::setProcessType(ProcessType type) @@ -46,20 +49,6 @@ void UabProcessController::setProcessType(ProcessType type) return; } m_type = type; - - if (DBus == type) { - QObject::connect(UabDBusPackageManager::instance(), - &UabDBusPackageManager::progressChanged, - this, - &UabProcessController::onDBusProgressChanged); - QObject::connect(UabDBusPackageManager::instance(), &UabDBusPackageManager::packageFinished, this, [this](bool success) { - const int ret = success ? UabSuccess : UabError; - onFinished(ret, ret); - }); - - } else { - QObject::disconnect(UabDBusPackageManager::instance(), nullptr, this, nullptr); - } } UabProcessController::ProcessType UabProcessController::processType() const @@ -137,9 +126,9 @@ bool UabProcessController::commitChanges() bool Uab::UabProcessController::ensureProcess() { if (!m_process) { - m_process = new QProcess(this); + m_process = new Konsole::Pty(this); - connect(m_process, &QProcess::readyRead, this, &UabProcessController::onReadOutput); + connect(m_process, &Konsole::Pty::receivedData, this, &UabProcessController::onReadOutput); connect( m_process, QOverload::of(&QProcess::finished), this, &UabProcessController::onFinished); } else if (QProcess::NotRunning != m_process->state()) { @@ -189,9 +178,14 @@ void UabProcessController::parseProgressFromJson(const QByteArray &jsonData) } } else if (doc.isObject()) { - // maybe code info + // maybe percentage / code info const QJsonObject obj = doc.object(); - if (UabError == obj.value(kJsonCode).toInt()) { + + if (obj.contains(kJsonPercentage)) { + float progress = obj.value(kJsonPercentage).toDouble(); + updateWholeProgress(progress); + + } else if (UabError == obj.value(kJsonCode).toInt()) { const QString errorString = obj.value(kJsonMessage).toString(); auto currUabPtr = currentPackagePtr(); if (currUabPtr) { @@ -231,9 +225,10 @@ void UabProcessController::updateWholeProgress(float currentTaskProgress) Q_EMIT progressChanged(currentTaskProgress); } -void UabProcessController::onReadOutput() +void UabProcessController::onReadOutput(const char *buffer, int length, bool isCommandExec) { - QByteArray output = m_process->readAllStandardOutput(); + Q_UNUSED(isCommandExec) + QByteArray output = QByteArray::fromRawData(buffer, length); Q_EMIT processOutput(output); // e.g: ll-cli --json install /path/to/file @@ -288,9 +283,9 @@ bool UabProcessController::nextProcess() const auto ¤tProc = m_procList.at(m_currentIndex); switch (currentProc.first) { case Installing: - return (DBus == m_type) ? installDBusImpl(currentProc.second) : installCliImpl(currentProc.second); + return (BackendCli == m_type) ? installBackendCliImpl(currentProc.second) : installCliImpl(currentProc.second); case Uninstalling: - return (DBus == m_type) ? uninstallDBusImpl(currentProc.second) : uninstallCliImpl(currentProc.second); + return (BackendCli == m_type) ? uninstallBackendCliImpl(currentProc.second) : uninstallCliImpl(currentProc.second); default: break; } @@ -299,24 +294,47 @@ bool UabProcessController::nextProcess() return false; } -bool UabProcessController::installDBusImpl(const UabPackage::Ptr &installPtr) +bool UabProcessController::installBackendCliImpl(const UabPackage::Ptr &installPtr) { if (!installPtr || !installPtr->isValid() || installPtr->info()->filePath.isEmpty()) { return false; } m_procFlag.setFlag(Installing); - return UabDBusPackageManager::instance()->installFormFile(installPtr); + + // e.g.: pkexec deepin-deb-installer-dependsInstall --uab --install [file to package].uab + m_process->start( + kPkexecBin, {kPkexecBin, kInstallProcessorBin, kParamUab, kParamInstall, installPtr->info()->filePath}, {}, 0, false); + + const QString recordCommand = QString("command: %1 %2 %3 %4/%5[uab package]") + .arg(kInstallProcessorBin) + .arg(kParamUab) + .arg(kParamInstall) + .arg(installPtr->info()->id) + .arg(installPtr->info()->version); + qInfo() << recordCommand; + + return true; } -bool UabProcessController::uninstallDBusImpl(const UabPackage::Ptr &uninstallPtr) +bool UabProcessController::uninstallBackendCliImpl(const UabPackage::Ptr &uninstallPtr) { if (!uninstallPtr || !uninstallPtr->isValid()) { return false; } m_procFlag.setFlag(Uninstalling); - return UabDBusPackageManager::instance()->uninstall(uninstallPtr); + + // e.g.: pkexec deepin-deb-installer-dependsInstall --uab --remove [id/version] + const QString mergeInfo = QString("%1/%2").arg(uninstallPtr->info()->id).arg(uninstallPtr->info()->version); + m_process->start(kPkexecBin, {kPkexecBin, kInstallProcessorBin, kParamUab, kParamRemove, mergeInfo}, {}, 0, false); + + const QString recordCommand = + QString("command: %1 %2 %3 %4").arg(kInstallProcessorBin).arg(kParamUab).arg(kParamRemove).arg(mergeInfo); + Q_EMIT processOutput(recordCommand); + qInfo() << recordCommand; + + return true; } bool Uab::UabProcessController::installCliImpl(const Uab::UabPackage::Ptr &installPtr) @@ -328,9 +346,7 @@ bool Uab::UabProcessController::installCliImpl(const Uab::UabPackage::Ptr &insta m_procFlag.setFlag(Installing); // e.g.: ll-cli --json install ./path/to/file/uab_package.uab - m_process->setProgram(kLinglongBin); - m_process->setArguments({kLinglongJson, kLinglongInstall, installPtr->info()->filePath}); - m_process->start(); + m_process->start(kLinglongBin, {kLinglongBin, kLinglongJson, kLinglongInstall, installPtr->info()->filePath}, {}, 0, false); const QString recordCommand = QString("command: %1 %2 %3 %4/%5[uab package]") .arg(kLinglongBin) @@ -339,6 +355,7 @@ bool Uab::UabProcessController::installCliImpl(const Uab::UabPackage::Ptr &insta .arg(installPtr->info()->id) .arg(installPtr->info()->version); Q_EMIT processOutput(recordCommand); + qInfo() << recordCommand; return true; } @@ -352,10 +369,14 @@ bool Uab::UabProcessController::uninstallCliImpl(const Uab::UabPackage::Ptr &uni m_procFlag.setFlag(Uninstalling); // e.g.: ll-cli --json uninstall org.deepin.package/1.0.0 - m_process->setProgram(kLinglongBin); - m_process->setArguments( - {kLinglongJson, kLinglongUninstall, QString("%1/%2").arg(uninstallPtr->info()->id).arg(uninstallPtr->info()->version)}); - m_process->start(); + m_process->start(kLinglongBin, + {kLinglongBin, + kLinglongJson, + kLinglongUninstall, + QString("%1/%2").arg(uninstallPtr->info()->id).arg(uninstallPtr->info()->version)}, + {}, + 0, + false); const QString recordCommand = QString("command: %1 %2 %3 %4/%5") .arg(kLinglongBin) @@ -364,6 +385,7 @@ bool Uab::UabProcessController::uninstallCliImpl(const Uab::UabPackage::Ptr &uni .arg(uninstallPtr->info()->id) .arg(uninstallPtr->info()->version); Q_EMIT processOutput(recordCommand); + qInfo() << recordCommand; return true; } diff --git a/src/deb-installer/uab/uab_process_controller.h b/src/deb-installer/uab/uab_process_controller.h index 2d30f76c..3a0c673d 100644 --- a/src/deb-installer/uab/uab_process_controller.h +++ b/src/deb-installer/uab/uab_process_controller.h @@ -9,7 +9,9 @@ #include "uab_package.h" -class QProcess; +namespace Konsole { +class Pty; +} // namespace Konsole namespace Uab { @@ -23,8 +25,8 @@ class UabProcessController : public QObject enum ProcessType { Unknown, - DBus, // call Linglong package manager DBus interface - Cli, // means qprocess execute, command line interface + BackendCli, // transport to deepin-deb-installer-dependsInstall, use ll-cli interface + DirectCli, // means direct qprocess execute, command line interface }; void setProcessType(ProcessType type); [[nodiscard]] ProcessType processType() const; @@ -57,14 +59,14 @@ class UabProcessController : public QObject void parseProgressFromJson(const QByteArray &jsonData); void parseProgressFromRawOutput(const QByteArray &output); void updateWholeProgress(float currentTaskProgress); - Q_SLOT void onReadOutput(); + Q_SLOT void onReadOutput(const char *buffer, int length, bool isCommandExec); Q_SLOT void onFinished(int exitCode, int exitStatus); Q_SLOT void onDBusProgressChanged(int progress, const QString &message); bool nextProcess(); - bool installDBusImpl(const UabPackage::Ptr &installPtr); - bool uninstallDBusImpl(const UabPackage::Ptr &uninstallPtr); + bool installBackendCliImpl(const UabPackage::Ptr &installPtr); + bool uninstallBackendCliImpl(const UabPackage::Ptr &uninstallPtr); bool installCliImpl(const UabPackage::Ptr &installPtr); bool uninstallCliImpl(const UabPackage::Ptr &uninstallPtr); @@ -74,14 +76,14 @@ class UabProcessController : public QObject void commitCurrentChangeToBackend(); private: - QProcess *m_process{nullptr}; + Konsole::Pty *m_process{nullptr}; ProcessType m_type{Unknown}; ProcFlags m_procFlag{Prepare}; int m_currentIndex{-1}; QList> m_procList; // install/uninstall package list - Q_DISABLE_COPY(UabProcessController); + Q_DISABLE_COPY(UabProcessController) }; } // namespace Uab diff --git a/tests/src/uab/ut_uab_process_controller.cpp b/tests/src/uab/ut_uab_process_controller.cpp index 8e7b393b..e261f96c 100644 --- a/tests/src/uab/ut_uab_process_controller.cpp +++ b/tests/src/uab/ut_uab_process_controller.cpp @@ -10,6 +10,7 @@ #include "../stub.h" #include "../deb-installer/uab/uab_process_controller.h" +#include "../deb-installer/process/Pty.h" class utDebProcessController : public ::testing::Test { @@ -38,7 +39,7 @@ bool stub_isValid_true() return true; } -bool stub_installDBusImpl_true(const Uab::UabPackage::Ptr &) +bool stub_installBackendCliImpl_true(const Uab::UabPackage::Ptr &) { return true; } @@ -47,7 +48,7 @@ TEST_F(utDebProcessController, installExecSuccess) { Stub s; s.set(ADDR(Uab::UabPackage, isValid), stub_isValid_true); - s.set(ADDR(Uab::UabProcessController, installDBusImpl), stub_installDBusImpl_true); + s.set(ADDR(Uab::UabProcessController, installBackendCliImpl), stub_installBackendCliImpl_true); Uab::UabProcessController uabController; auto uabPtr = Uab::UabPkgInfo::Ptr::create(); @@ -56,8 +57,5 @@ TEST_F(utDebProcessController, installExecSuccess) uabController.markInstall(Uab::UabPackage::fromInfo(uabPtr)); EXPECT_TRUE(uabController.commitChanges()); - if (Uab::UabProcessController::Cli == uabController.processType()) { - EXPECT_EQ(uabController.m_process->program(), uabPtr->filePath); - } EXPECT_TRUE(uabController.m_procFlag.testFlag(Uab::UabProcessController::Processing)); } diff --git a/translations/deepin-deb-installer.ts b/translations/deepin-deb-installer.ts index 75932aae..c93da09a 100644 --- a/translations/deepin-deb-installer.ts +++ b/translations/deepin-deb-installer.ts @@ -118,63 +118,63 @@ DebListModel - - + + Installation failed, please check your network connection Installation failed, please check your network connection - + Installation failed, please check for updates in Control Center Installation failed, please check for updates in Control Center - - - + + + Installation failed, insufficient disk space Installation failed, insufficient disk space - + No digital signature No digital signature - - + + Invalid digital signature Invalid digital signature - - - + + + The administrator has set policies to prevent installation of this package The administrator has set policies to prevent installation of this package - + Installation Failed Installation Failed - + current system - + %2 has been installed in %1, please uninstall this package before installing it - + Broken dependencies, try installing the app in compatibility mode - + Failed to install %1 Failed to install %1 @@ -183,81 +183,81 @@ Failed to install %1: no valid digital singature - + Unable to install - no digital signature Unable to install - no digital signature - + Please go to Control Center to enable developer mode and try again. Proceed? Please go to Control Center to enable developer mode and try again. Proceed? - + Cancel button Cancel - + Proceed button Proceed - - - + + + OK button OK - + Failed to install %1: no valid digital signature - + This package does not have a valid digital signature. Continue with the installation? This package does not have a valid digital signature. Continue with the installation? - + Cancel Cancel - + Continue button Continue - - - + + + Unable to install Unable to install - + This package does not have a valid digital signature This package does not have a valid digital signature - - + + Broken dependencies: %1 Broken dependencies: %1 - + Authentication failed Authentication failed - + Unmatched package architecture Unmatched package architecture @@ -307,22 +307,22 @@ Back - + Install %1 will remove: - + Dependencies in the repository Dependencies in the repository - + Missing dependencies Missing dependencies - + Installing dependencies: %1 Installing dependencies: %1 @@ -479,156 +479,156 @@ SingleInstallPage - + Collapse Collapse - - - + + + Reinstall Reinstall - - + + Later version installed: %1 Later version installed: %1 - - + + Downgrade Downgrade - - + + Earlier version installed: %1 Earlier version installed: %1 - + Installing dependencies: %1 Installing dependencies: %1 - + Failed to install %1 Failed to install %1 - + Version: Version: - + Select a compatibility mode: - + Install button Install - + Remove button Remove - + OK button OK - + Back button Back - + Done button Done - + Trying to install %2 in %1 compatibility mode - + Uninstalling %2 from %1 compatibility mode - + %2 was successfully installed to %1 compatibility mode - + Installed successfully Installed successfully - + %2 has been successfully uninstalled from %1 compatibility mode - + Uninstalled successfully Uninstalled successfully - + Uninstall Failed Uninstall Failed - + Install %1 will remove: - + Dependencies in the repository Dependencies in the repository - + Missing dependencies Missing dependencies - - + + Update button Update - + Invalid digital signature Invalid digital signature - + Name: Name: - - + + Same version installed Same version installed @@ -637,9 +637,9 @@ SingleInstallPage_Install - - - + + + Show details Show details @@ -654,11 +654,19 @@ SingleInstallPage_Uninstall - + Show details Show details + + Uab::UabPackageListModel + + + Installation Failed + Installation Failed + + UninstallConfirmPage diff --git a/translations/deepin-deb-installer_zh_CN.ts b/translations/deepin-deb-installer_zh_CN.ts index c00d795b..683158e5 100644 --- a/translations/deepin-deb-installer_zh_CN.ts +++ b/translations/deepin-deb-installer_zh_CN.ts @@ -116,63 +116,63 @@ DebListModel - - + + Installation failed, please check your network connection 安装失败,请检查您的网络连接 - + Installation failed, please check for updates in Control Center 安装失败,请在控制中心检查更新 - - - + + + Installation failed, insufficient disk space 安装失败,磁盘空间不足 - + No digital signature 无数字签名 - - + + Invalid digital signature 数字签名无效 - - - + + + The administrator has set policies to prevent installation of this package 管理员已限制,该软件禁止安装 - + Installation Failed 安装失败 - + current system 当前系统环境 - + %2 has been installed in %1, please uninstall this package before installing it - 已在%1中安装%2, 请先卸载后再安装此包 + 已在%1中安装%2,请先卸载后再安装此包 - + Broken dependencies, try installing the app in compatibility mode - 依赖关系不满足,请尝试使用兼容模式安装该应用 + 依赖关系不满足,请尝试使用兼容模式安装该应用 - + Failed to install %1 %1安装失败 @@ -181,81 +181,81 @@ 无法安装%1,安装包无有效的数字签名 - + Unable to install - no digital signature 无法安装,安装包无数字签名 - + Please go to Control Center to enable developer mode and try again. Proceed? 请进入控制中心,开启开发者模式后,再尝试继续安装。是否前往? - + Cancel button 取 消 - + Proceed button 前 往 - - - + + + OK button 确 定 - + Failed to install %1: no valid digital signature 无法安装%1,安装包无有效的数字签名 - + This package does not have a valid digital signature. Continue with the installation? 此安装包没有有效的数字签名,是否继续安装? - + Cancel 取 消 - + Continue button 继续 - - - + + + Unable to install 无法安装 - + This package does not have a valid digital signature 此安装包没有有效的数字签名 - - + + Broken dependencies: %1 依赖关系不满足:%1 - + Authentication failed 配置授权失败 - + Unmatched package architecture 软件包架构不匹配 @@ -305,22 +305,22 @@ 返 回 - + Install %1 will remove: 安装%1将会卸载: - + Dependencies in the repository 仓库中存在的依赖包 - + Missing dependencies 仓库中缺失的依赖包 - + Installing dependencies: %1 正在安装依赖:%1 @@ -477,156 +477,156 @@ SingleInstallPage - + Collapse 收起 - - - + + + Reinstall 重新安装 - - + + Later version installed: %1 已安装较新的版本:%1 - - + + Downgrade 安装旧版本 - - + + Earlier version installed: %1 已安装较早的版本:%1 - + Installing dependencies: %1 正在安装依赖:%1 - + Failed to install %1 %1安装失败 - + Version: 版本: - + Select a compatibility mode: 选择兼容模式: - + Install button 安 装 - + Remove button 卸 载 - + OK button 确 定 - + Back button 返 回 - + Done button 完 成 - + Trying to install %2 in %1 compatibility mode 正在尝试使用%1兼容模式安装%2 - + Uninstalling %2 from %1 compatibility mode 正在从%1兼容模式卸载%2 - + %2 was successfully installed to %1 compatibility mode %2已成功安装到%1兼容模式 - + Installed successfully 安装成功 - + %2 has been successfully uninstalled from %1 compatibility mode %2已从%1兼容模式成功卸载 - + Uninstalled successfully 卸载成功 - + Uninstall Failed 卸载失败 - + Install %1 will remove: 安装%1将会卸载: - + Dependencies in the repository 仓库中存在的依赖包 - + Missing dependencies 仓库中缺失的依赖包 - - + + Update button 更 新 - + Invalid digital signature 数字签名无效 - + Name: 名称: - - + + Same version installed 已安装相同版本 @@ -635,9 +635,9 @@ SingleInstallPage_Install - - - + + + Show details 显示详细信息 @@ -652,11 +652,19 @@ SingleInstallPage_Uninstall - + Show details 显示卸载进程 + + Uab::UabPackageListModel + + + Installation Failed + 安装失败 + + UninstallConfirmPage diff --git a/translations/deepin-deb-installer_zh_HK.ts b/translations/deepin-deb-installer_zh_HK.ts index 124b9556..12ccfa12 100644 --- a/translations/deepin-deb-installer_zh_HK.ts +++ b/translations/deepin-deb-installer_zh_HK.ts @@ -116,63 +116,63 @@ DebListModel - - + + Installation failed, please check your network connection 安裝失敗,請檢查您的網絡連接 - + Installation failed, please check for updates in Control Center 安裝失敗,請在控制中心檢查更新 - - - + + + Installation failed, insufficient disk space 安裝失敗,磁盤空間不足 - + No digital signature 無數字簽名 - - + + Invalid digital signature 數字簽名無效 - - - + + + The administrator has set policies to prevent installation of this package 管理員已限制,該軟件禁止安裝 - + Installation Failed 安裝失敗 - + current system 當前系統環境 - + %2 has been installed in %1, please uninstall this package before installing it 已在%1中安裝%2,請先卸載後再安裝此包 - + Broken dependencies, try installing the app in compatibility mode 依賴關係不滿足,請嘗試使用兼容模式安裝該應用 - + Failed to install %1 %1安裝失敗 @@ -181,81 +181,81 @@ 無法安裝%1,安裝包無有效的數字簽名 - + Unable to install - no digital signature 無法安裝,安裝包無數字簽名 - + Please go to Control Center to enable developer mode and try again. Proceed? 請進入控制中心,開啟開發者模式後,再嘗試繼續安裝。是否前往? - + Cancel button 取 消 - + Proceed button 前 往 - - - + + + OK button 確 定 - + Failed to install %1: no valid digital signature 無法安裝%1,安裝包無有效的數字簽名 - + This package does not have a valid digital signature. Continue with the installation? 此安裝包沒有有效的數字簽名,是否繼續安裝? - + Cancel 取 消 - + Continue button 繼續 - - - + + + Unable to install 無法安裝 - + This package does not have a valid digital signature 此安裝包沒有有效的數字簽名 - - + + Broken dependencies: %1 依賴關係不滿足:%1 - + Authentication failed 配置授權失敗 - + Unmatched package architecture 軟件包架構不匹配 @@ -305,22 +305,22 @@ 返 回 - + Install %1 will remove: 安裝%1將會卸載: - + Dependencies in the repository 倉庫中存在的依賴包 - + Missing dependencies 倉庫中缺失的依賴包 - + Installing dependencies: %1 正在安裝依賴:%1 @@ -477,156 +477,156 @@ SingleInstallPage - + Collapse 收起 - - - + + + Reinstall 重新安裝 - - + + Later version installed: %1 已安裝較新的版本:%1 - - + + Downgrade 安裝舊版本 - - + + Earlier version installed: %1 已安裝較早的版本:%1 - + Installing dependencies: %1 正在安裝依賴:%1 - + Failed to install %1 %1安裝失敗 - + Version: 版本: - + Select a compatibility mode: 選擇兼容模式: - + Install button 安 裝 - + Remove button 卸 載 - + OK button 確 定 - + Back button 返 回 - + Done button 完 成 - + Trying to install %2 in %1 compatibility mode 正在嘗試使用%1兼容模式安裝%2 - + Uninstalling %2 from %1 compatibility mode 正在從%1兼容模式卸載%2 - + %2 was successfully installed to %1 compatibility mode %2已成功安裝到%1兼容模式 - + Installed successfully 安裝成功 - + %2 has been successfully uninstalled from %1 compatibility mode %2已從%1兼容模式成功卸載 - + Uninstalled successfully 卸載成功 - + Uninstall Failed 卸載失敗 - + Install %1 will remove: 安裝%1將會卸載: - + Dependencies in the repository 倉庫中存在的依賴包 - + Missing dependencies 倉庫中缺失的依賴包 - - + + Update button 更 新 - + Invalid digital signature 數字簽名無效 - + Name: 名稱: - - + + Same version installed 已安裝相同版本 @@ -635,9 +635,9 @@ SingleInstallPage_Install - - - + + + Show details 顯示詳細訊息 @@ -652,11 +652,19 @@ SingleInstallPage_Uninstall - + Show details 顯示卸載進程 + + Uab::UabPackageListModel + + + Installation Failed + 安裝失敗 + + UninstallConfirmPage diff --git a/translations/deepin-deb-installer_zh_TW.ts b/translations/deepin-deb-installer_zh_TW.ts index aad6eb21..4891477d 100644 --- a/translations/deepin-deb-installer_zh_TW.ts +++ b/translations/deepin-deb-installer_zh_TW.ts @@ -116,63 +116,63 @@ DebListModel - - + + Installation failed, please check your network connection 安裝失敗,請檢查網路連線 - + Installation failed, please check for updates in Control Center 安裝失敗,請於控制中心檢查更新 - - - + + + Installation failed, insufficient disk space 安裝失敗,磁碟機空間不足 - + No digital signature 無數位簽章 - - + + Invalid digital signature 數位簽章無效 - - - + + + The administrator has set policies to prevent installation of this package 管理員已限制,該軟體禁止安裝 - + Installation Failed 安裝失敗 - + current system - 當前系統環境 + 目前系統環境 - + %2 has been installed in %1, please uninstall this package before installing it - 已在%1中安裝%2,請先卸載後再安裝此包 + 已在%1中安裝%2,請先移除後再安裝此包 - + Broken dependencies, try installing the app in compatibility mode 依賴關係不滿足,請嘗試使用相容模式安裝該應用 - + Failed to install %1 %1安裝失敗 @@ -181,81 +181,81 @@ 無法安裝%1,安裝包無有效的數位簽章 - + Unable to install - no digital signature 無法安裝,安裝包無數位簽章 - + Please go to Control Center to enable developer mode and try again. Proceed? 請進入控制中心,開啟開發者模式後,再嘗試繼續安裝。是否前往? - + Cancel button 取 消 - + Proceed button 前 往 - - - + + + OK button 確 定 - + Failed to install %1: no valid digital signature 無法安裝%1,安裝包無有效的數位簽章 - + This package does not have a valid digital signature. Continue with the installation? 此安裝包沒有有效的數位簽章,是否繼續安裝? - + Cancel 取 消 - + Continue button 繼續 - - - + + + Unable to install 無法安裝 - + This package does not have a valid digital signature 此安裝包沒有有效的數位簽章 - - + + Broken dependencies: %1 缺少依賴軟體:%1 - + Authentication failed 配置授權失敗 - + Unmatched package architecture 軟體套件結構不符合規範 @@ -305,22 +305,22 @@ 返 回 - + Install %1 will remove: - 安裝%1將會卸載: + 安裝%1將會移除: - + Dependencies in the repository 倉庫中存在的依賴包 - + Missing dependencies 倉庫中缺失的依賴包 - + Installing dependencies: %1 正在安裝依賴:%1 @@ -471,162 +471,162 @@ Will remove: - 將會卸載: + 將會移除: SingleInstallPage - + Collapse 隱藏 - - - + + + Reinstall 重 裝 - - + + Later version installed: %1 已安裝較新的版本:%1 - - + + Downgrade 安裝舊版本 - - + + Earlier version installed: %1 已安裝舊版本:%1 - + Installing dependencies: %1 正在安裝依賴:%1 - + Failed to install %1 %1安裝失敗 - + Version: 版本: - + Select a compatibility mode: 選擇相容模式: - + Install button 安 裝 - + Remove button 移 除 - + OK button 確 定 - + Back button 返 回 - + Done button 完 成 - + Trying to install %2 in %1 compatibility mode 正在嘗試使用%1相容模式安裝%2 - + Uninstalling %2 from %1 compatibility mode - 正在從%1相容模式卸載%2 + 正在從%1相容模式移除%2 - + %2 was successfully installed to %1 compatibility mode %2已成功安裝到%1相容模式 - + Installed successfully 安裝成功 - + %2 has been successfully uninstalled from %1 compatibility mode - %2已從%1相容模式成功卸載 + %2已從%1相容模式成功移除 - + Uninstalled successfully 解除安裝成功 - + Uninstall Failed 解除安裝失敗 - + Install %1 will remove: - 安裝%1將會卸載: + 安裝%1將會移除: - + Dependencies in the repository 倉庫中存在的依賴包 - + Missing dependencies 倉庫中缺失的依賴包 - - + + Update button 更 新 - + Invalid digital signature 數位簽章無效 - + Name: 名稱: - - + + Same version installed 已安裝相同版本 @@ -635,9 +635,9 @@ SingleInstallPage_Install - - - + + + Show details 顯示詳細訊息 @@ -652,11 +652,19 @@ SingleInstallPage_Uninstall - + Show details 顯示卸載進程 + + Uab::UabPackageListModel + + + Installation Failed + 安裝失敗 + + UninstallConfirmPage @@ -700,7 +708,7 @@ The system or other applications may not work properly Are you sure you want to uninstall %2 from %1 compatibility mode? 您確定要從%1相容模式 -卸載%2嗎? +移除%2嗎?