mirror of
https://github.com/Lime3DS/Lime3DS.git
synced 2025-03-13 09:12:27 +01:00
Drop old Citra updater code
Due to differences with how updates are handled, none of this code can really be reused for Azahar
This commit is contained in:
parent
ac7671e247
commit
d86dfba7b8
@ -68,7 +68,6 @@ option(USE_SYSTEM_SDL2 "Use the system SDL2 lib (instead of the bundled one)" OF
|
|||||||
# Set bundled qt as dependent options.
|
# Set bundled qt as dependent options.
|
||||||
option(ENABLE_QT "Enable the Qt frontend" ON)
|
option(ENABLE_QT "Enable the Qt frontend" ON)
|
||||||
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
option(ENABLE_QT_TRANSLATION "Enable translations for the Qt frontend" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(ENABLE_QT_UPDATER "Enable built-in updater for the Qt frontend" ON "NOT IOS" OFF)
|
|
||||||
|
|
||||||
CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT IOS" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_TESTS "Enable generating tests executable" ON "NOT IOS" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(ENABLE_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
|
CMAKE_DEPENDENT_OPTION(ENABLE_ROOM "Enable generating dedicated room executable" ON "NOT ANDROID AND NOT IOS" OFF)
|
||||||
|
@ -196,15 +196,6 @@ file(GLOB COMPAT_LIST
|
|||||||
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
|
file(GLOB_RECURSE ICONS ${PROJECT_SOURCE_DIR}/dist/icons/*)
|
||||||
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
|
file(GLOB_RECURSE THEMES ${PROJECT_SOURCE_DIR}/dist/qt_themes/*)
|
||||||
|
|
||||||
if (ENABLE_QT_UPDATER)
|
|
||||||
target_sources(citra_qt PRIVATE
|
|
||||||
updater/updater.cpp
|
|
||||||
updater/updater.h
|
|
||||||
updater/updater_p.h
|
|
||||||
)
|
|
||||||
target_compile_definitions(citra_qt PUBLIC ENABLE_QT_UPDATER)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (ENABLE_QT_TRANSLATION)
|
if (ENABLE_QT_TRANSLATION)
|
||||||
set(CITRA_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
|
set(CITRA_QT_LANGUAGES "${PROJECT_SOURCE_DIR}/dist/languages" CACHE PATH "Path to the translation bundle for the Qt frontend")
|
||||||
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
|
option(GENERATE_QT_TRANSLATION "Generate en.ts as the translation source file" OFF)
|
||||||
|
@ -69,7 +69,6 @@
|
|||||||
#include "citra_qt/play_time_manager.h"
|
#include "citra_qt/play_time_manager.h"
|
||||||
#include "citra_qt/qt_image_interface.h"
|
#include "citra_qt/qt_image_interface.h"
|
||||||
#include "citra_qt/uisettings.h"
|
#include "citra_qt/uisettings.h"
|
||||||
#include "citra_qt/updater/updater.h"
|
|
||||||
#include "citra_qt/util/clickable_label.h"
|
#include "citra_qt/util/clickable_label.h"
|
||||||
#include "citra_qt/util/graphics_device_info.h"
|
#include "citra_qt/util/graphics_device_info.h"
|
||||||
#include "citra_qt/util/util.h"
|
#include "citra_qt/util/util.h"
|
||||||
@ -353,12 +352,6 @@ GMainWindow::GMainWindow(Core::System& system_)
|
|||||||
InitializeRecentFileMenuActions();
|
InitializeRecentFileMenuActions();
|
||||||
InitializeSaveStateMenuActions();
|
InitializeSaveStateMenuActions();
|
||||||
InitializeHotkeys();
|
InitializeHotkeys();
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
ShowUpdaterWidgets();
|
|
||||||
#else
|
|
||||||
ui->action_Check_For_Updates->setVisible(false);
|
|
||||||
ui->action_Open_Maintenance_Tool->setVisible(false);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
SetDefaultUIGeometry();
|
SetDefaultUIGeometry();
|
||||||
RestoreUIState();
|
RestoreUIState();
|
||||||
@ -429,12 +422,6 @@ GMainWindow::GMainWindow(Core::System& system_)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
if (UISettings::values.check_for_update_on_start) {
|
|
||||||
CheckForUpdates();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!game_path.isEmpty()) {
|
if (!game_path.isEmpty()) {
|
||||||
BootGame(game_path);
|
BootGame(game_path);
|
||||||
}
|
}
|
||||||
@ -486,12 +473,6 @@ void GMainWindow::InitializeWidgets() {
|
|||||||
ui->action_Leave_Room, ui->action_Show_Room);
|
ui->action_Leave_Room, ui->action_Show_Room);
|
||||||
multiplayer_state->setVisible(false);
|
multiplayer_state->setVisible(false);
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
// Setup updater
|
|
||||||
updater = new Updater(this);
|
|
||||||
UISettings::values.updater_found = updater->HasUpdater();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
UpdateBootHomeMenuState();
|
UpdateBootHomeMenuState();
|
||||||
|
|
||||||
// Create status bar
|
// Create status bar
|
||||||
@ -1079,11 +1060,6 @@ void GMainWindow::ConnectMenuEvents() {
|
|||||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://azahar-emu.org/pages/faq/")));
|
QDesktopServices::openUrl(QUrl(QStringLiteral("https://azahar-emu.org/pages/faq/")));
|
||||||
});
|
});
|
||||||
connect_menu(ui->action_About, &GMainWindow::OnMenuAboutCitra);
|
connect_menu(ui->action_About, &GMainWindow::OnMenuAboutCitra);
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
connect_menu(ui->action_Check_For_Updates, &GMainWindow::OnCheckForUpdates);
|
|
||||||
connect_menu(ui->action_Open_Maintenance_Tool, &GMainWindow::OnOpenUpdater);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::UpdateMenuState() {
|
void GMainWindow::UpdateMenuState() {
|
||||||
@ -1137,81 +1113,6 @@ void GMainWindow::OnDisplayTitleBars(bool show) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
void GMainWindow::OnCheckForUpdates() {
|
|
||||||
explicit_update_check = true;
|
|
||||||
CheckForUpdates();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::CheckForUpdates() {
|
|
||||||
if (updater->CheckForUpdates()) {
|
|
||||||
LOG_INFO(Frontend, "Update check started");
|
|
||||||
} else {
|
|
||||||
LOG_WARNING(Frontend, "Unable to start check for updates");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::OnUpdateFound(bool found, bool error) {
|
|
||||||
if (error) {
|
|
||||||
LOG_WARNING(Frontend, "Update check failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
LOG_INFO(Frontend, "No updates found");
|
|
||||||
|
|
||||||
// If the user explicitly clicked the "Check for Updates" button, we are
|
|
||||||
// going to want to show them a prompt anyway.
|
|
||||||
if (explicit_update_check) {
|
|
||||||
explicit_update_check = false;
|
|
||||||
ShowNoUpdatePrompt();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (emulation_running && !explicit_update_check) {
|
|
||||||
LOG_INFO(Frontend, "Update found, deferring as application is running");
|
|
||||||
defer_update_prompt = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG_INFO(Frontend, "Update found!");
|
|
||||||
explicit_update_check = false;
|
|
||||||
|
|
||||||
ShowUpdatePrompt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::ShowUpdatePrompt() {
|
|
||||||
defer_update_prompt = false;
|
|
||||||
|
|
||||||
auto result =
|
|
||||||
QMessageBox::question(this, tr("Update Available"),
|
|
||||||
tr("An update is available. Would you like to install it now?"),
|
|
||||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
|
||||||
|
|
||||||
if (result == QMessageBox::Yes) {
|
|
||||||
updater->LaunchUIOnExit();
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::ShowNoUpdatePrompt() {
|
|
||||||
QMessageBox::information(this, tr("No Update Found"), tr("No update is found."),
|
|
||||||
QMessageBox::Ok, QMessageBox::Ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::OnOpenUpdater() {
|
|
||||||
updater->LaunchUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GMainWindow::ShowUpdaterWidgets() {
|
|
||||||
ui->action_Check_For_Updates->setVisible(UISettings::values.updater_found);
|
|
||||||
ui->action_Open_Maintenance_Tool->setVisible(UISettings::values.updater_found);
|
|
||||||
|
|
||||||
connect(updater, &Updater::CheckUpdatesDone, this, &GMainWindow::OnUpdateFound);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GMainWindow::ShowMigrationCancelledMessage() {
|
void GMainWindow::ShowMigrationCancelledMessage() {
|
||||||
QMessageBox::information(
|
QMessageBox::information(
|
||||||
this, tr("Migration"),
|
this, tr("Migration"),
|
||||||
@ -1721,12 +1622,6 @@ void GMainWindow::ShutdownGame() {
|
|||||||
|
|
||||||
emulation_running = false;
|
emulation_running = false;
|
||||||
|
|
||||||
#if ENABLE_QT_UDPATER
|
|
||||||
if (defer_update_prompt) {
|
|
||||||
ShowUpdatePrompt();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
game_title.clear();
|
game_title.clear();
|
||||||
UpdateWindowTitle();
|
UpdateWindowTitle();
|
||||||
|
|
||||||
|
@ -53,9 +53,6 @@ class QProgressBar;
|
|||||||
class QPushButton;
|
class QPushButton;
|
||||||
class QSlider;
|
class QSlider;
|
||||||
class RegistersWidget;
|
class RegistersWidget;
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
class Updater;
|
|
||||||
#endif
|
|
||||||
class WaitTreeWidget;
|
class WaitTreeWidget;
|
||||||
|
|
||||||
namespace Camera {
|
namespace Camera {
|
||||||
@ -166,13 +163,6 @@ private:
|
|||||||
void SetDiscordEnabled(bool state);
|
void SetDiscordEnabled(bool state);
|
||||||
void LoadAmiibo(const QString& filename);
|
void LoadAmiibo(const QString& filename);
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
void ShowUpdaterWidgets();
|
|
||||||
void ShowUpdatePrompt();
|
|
||||||
void ShowNoUpdatePrompt();
|
|
||||||
void CheckForUpdates();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum LegacyEmu {
|
enum LegacyEmu {
|
||||||
Citra,
|
Citra,
|
||||||
Lime3DS,
|
Lime3DS,
|
||||||
@ -298,12 +288,6 @@ private slots:
|
|||||||
/// Called whenever a user selects Help->About Azahar
|
/// Called whenever a user selects Help->About Azahar
|
||||||
void OnMenuAboutCitra();
|
void OnMenuAboutCitra();
|
||||||
|
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
void OnUpdateFound(bool found, bool error);
|
|
||||||
void OnCheckForUpdates();
|
|
||||||
void OnOpenUpdater();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void OnLanguageChanged(const QString& locale);
|
void OnLanguageChanged(const QString& locale);
|
||||||
void OnMouseActivity();
|
void OnMouseActivity();
|
||||||
|
|
||||||
@ -408,12 +392,6 @@ private:
|
|||||||
IPCRecorderWidget* ipcRecorderWidget;
|
IPCRecorderWidget* ipcRecorderWidget;
|
||||||
LLEServiceModulesWidget* lleServiceModulesWidget;
|
LLEServiceModulesWidget* lleServiceModulesWidget;
|
||||||
WaitTreeWidget* waitTreeWidget;
|
WaitTreeWidget* waitTreeWidget;
|
||||||
#if ENABLE_QT_UPDATER
|
|
||||||
Updater* updater;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool explicit_update_check = false;
|
|
||||||
bool defer_update_prompt = false;
|
|
||||||
|
|
||||||
QAction* actions_recent_files[max_recent_files_item];
|
QAction* actions_recent_files[max_recent_files_item];
|
||||||
std::array<QAction*, Core::SaveStateSlotCount> actions_load_state;
|
std::array<QAction*, Core::SaveStateSlotCount> actions_load_state;
|
||||||
|
@ -209,8 +209,6 @@
|
|||||||
<property name="title">
|
<property name="title">
|
||||||
<string>&Help</string>
|
<string>&Help</string>
|
||||||
</property>
|
</property>
|
||||||
<addaction name="action_Check_For_Updates"/>
|
|
||||||
<addaction name="action_Open_Maintenance_Tool"/>
|
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="action_Report_Compatibility"/>
|
<addaction name="action_Report_Compatibility"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
@ -494,14 +492,6 @@
|
|||||||
<string>Opens the Citra Log folder</string>
|
<string>Opens the Citra Log folder</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Open_Maintenance_Tool">
|
|
||||||
<property name="text">
|
|
||||||
<string>Modify Citra Install</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Opens the maintenance tool to modify your Citra installation</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_Screen_Layout_Default">
|
<action name="action_Screen_Layout_Default">
|
||||||
<property name="checkable">
|
<property name="checkable">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
@ -638,11 +628,6 @@
|
|||||||
<string>Rotate Upright</string>
|
<string>Rotate Upright</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="action_Check_For_Updates">
|
|
||||||
<property name="text">
|
|
||||||
<string>Check for Updates</string>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="action_Report_Compatibility">
|
<action name="action_Report_Compatibility">
|
||||||
<property name="enabled">
|
<property name="enabled">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
|
@ -1,315 +0,0 @@
|
|||||||
// Copyright 2017 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
//
|
|
||||||
// Based on the original work by Felix Barx
|
|
||||||
// Copyright (c) 2015, Felix Barz
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QFileInfo>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QXmlStreamReader>
|
|
||||||
#include "citra_qt/uisettings.h"
|
|
||||||
#include "citra_qt/updater/updater.h"
|
|
||||||
#include "citra_qt/updater/updater_p.h"
|
|
||||||
#include "common/file_util.h"
|
|
||||||
#include "common/logging/log.h"
|
|
||||||
|
|
||||||
#ifdef Q_OS_MACOS
|
|
||||||
#define DEFAULT_TOOL_PATH QStringLiteral("../../../../maintenancetool")
|
|
||||||
#else
|
|
||||||
#define DEFAULT_TOOL_PATH QStringLiteral("../maintenancetool")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Updater::Updater(QObject* parent) : Updater(DEFAULT_TOOL_PATH, parent) {}
|
|
||||||
|
|
||||||
Updater::Updater(const QString& maintenance_tool_path, QObject* parent)
|
|
||||||
: QObject(parent), backend(std::make_unique<UpdaterPrivate>(this)) {
|
|
||||||
backend->tool_path = UpdaterPrivate::ToSystemExe(maintenance_tool_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Updater::~Updater() = default;
|
|
||||||
|
|
||||||
bool Updater::ExitedNormally() const {
|
|
||||||
return backend->normal_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Updater::ErrorCode() const {
|
|
||||||
return backend->last_error_code;
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray Updater::ErrorLog() const {
|
|
||||||
return backend->last_error_log;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Updater::IsRunning() const {
|
|
||||||
return backend->running;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<Updater::UpdateInfo> Updater::LatestUpdateInfo() const {
|
|
||||||
return backend->update_info;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Updater::HasUpdater() const {
|
|
||||||
return backend->HasUpdater();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Updater::CheckForUpdates() {
|
|
||||||
return backend->StartUpdateCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Updater::AbortUpdateCheck(int max_delay, bool async) {
|
|
||||||
backend->StopUpdateCheck(max_delay, async);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Updater::LaunchUI() {
|
|
||||||
backend->LaunchUI();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Updater::SilentlyUpdate() {
|
|
||||||
backend->SilentlyUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Updater::LaunchUIOnExit() {
|
|
||||||
backend->LaunchUIOnExit();
|
|
||||||
}
|
|
||||||
|
|
||||||
Updater::UpdateInfo::UpdateInfo() = default;
|
|
||||||
|
|
||||||
Updater::UpdateInfo::UpdateInfo(const Updater::UpdateInfo&) = default;
|
|
||||||
|
|
||||||
Updater::UpdateInfo::UpdateInfo(QString name, QString version, quint64 size)
|
|
||||||
: name(std::move(name)), version(std::move(version)), size(size) {}
|
|
||||||
|
|
||||||
UpdaterPrivate::UpdaterPrivate(Updater* parent_ptr) : QObject(nullptr), parent(parent_ptr) {
|
|
||||||
connect(qApp, &QCoreApplication::aboutToQuit, this, &UpdaterPrivate::AboutToExit,
|
|
||||||
Qt::DirectConnection);
|
|
||||||
qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus");
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdaterPrivate::~UpdaterPrivate() {
|
|
||||||
if (main_process && main_process->state() != QProcess::NotRunning) {
|
|
||||||
main_process->kill();
|
|
||||||
main_process->waitForFinished(1000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QString UpdaterPrivate::ToSystemExe(QString base_path) {
|
|
||||||
#if defined(Q_OS_WIN32)
|
|
||||||
if (!base_path.endsWith(QStringLiteral(".exe")))
|
|
||||||
return base_path + QStringLiteral(".exe");
|
|
||||||
else
|
|
||||||
return base_path;
|
|
||||||
#elif defined(Q_OS_MACOS)
|
|
||||||
if (base_path.endsWith(QStringLiteral(".app")))
|
|
||||||
base_path.truncate(base_path.lastIndexOf(QStringLiteral(".")));
|
|
||||||
return base_path + QStringLiteral(".app/Contents/MacOS/") + QFileInfo(base_path).fileName();
|
|
||||||
#elif defined(Q_OS_UNIX)
|
|
||||||
return base_path;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo UpdaterPrivate::GetMaintenanceTool() const {
|
|
||||||
#if defined(Q_OS_UNIX) && !defined(Q_OS_MACOS)
|
|
||||||
const auto appimage_path = QProcessEnvironment::systemEnvironment()
|
|
||||||
.value(QStringLiteral("APPIMAGE"), {})
|
|
||||||
.toStdString();
|
|
||||||
if (!appimage_path.empty()) {
|
|
||||||
const auto appimage_dir = FileUtil::GetParentPath(appimage_path);
|
|
||||||
LOG_DEBUG(Frontend, "Detected app image directory: {}", appimage_dir);
|
|
||||||
return QFileInfo(QString::fromStdString(std::string(appimage_dir)), tool_path);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return QFileInfo(QCoreApplication::applicationDirPath(), tool_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UpdaterPrivate::HasUpdater() const {
|
|
||||||
return GetMaintenanceTool().exists();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UpdaterPrivate::StartUpdateCheck() {
|
|
||||||
if (running || !HasUpdater()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
update_info.clear();
|
|
||||||
normal_exit = true;
|
|
||||||
last_error_code = EXIT_SUCCESS;
|
|
||||||
last_error_log.clear();
|
|
||||||
|
|
||||||
main_process = new QProcess(this);
|
|
||||||
main_process->setProgram(GetMaintenanceTool().absoluteFilePath());
|
|
||||||
main_process->setArguments({QStringLiteral("--checkupdates")});
|
|
||||||
|
|
||||||
connect(main_process, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), this,
|
|
||||||
&UpdaterPrivate::UpdaterReady, Qt::QueuedConnection);
|
|
||||||
connect(main_process, qOverload<QProcess::ProcessError>(&QProcess::errorOccurred), this,
|
|
||||||
&UpdaterPrivate::UpdaterError, Qt::QueuedConnection);
|
|
||||||
|
|
||||||
main_process->start(QIODevice::ReadOnly);
|
|
||||||
running = true;
|
|
||||||
|
|
||||||
emit parent->UpdateInfoChanged(update_info);
|
|
||||||
emit parent->RunningChanged(true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::StopUpdateCheck(int delay, bool async) {
|
|
||||||
if (main_process == nullptr || main_process->state() == QProcess::NotRunning) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (delay > 0) {
|
|
||||||
main_process->terminate();
|
|
||||||
if (async) {
|
|
||||||
QTimer* timer = new QTimer(this);
|
|
||||||
timer->setSingleShot(true);
|
|
||||||
|
|
||||||
connect(timer, &QTimer::timeout, this, [this, timer]() {
|
|
||||||
StopUpdateCheck(0, false);
|
|
||||||
timer->deleteLater();
|
|
||||||
});
|
|
||||||
|
|
||||||
timer->start(delay);
|
|
||||||
} else {
|
|
||||||
if (!main_process->waitForFinished(delay)) {
|
|
||||||
main_process->kill();
|
|
||||||
main_process->waitForFinished(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
main_process->kill();
|
|
||||||
main_process->waitForFinished(100);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
XMLParseResult UpdaterPrivate::ParseResult(const QByteArray& output,
|
|
||||||
QList<Updater::UpdateInfo>& out) {
|
|
||||||
const auto out_string = QString::fromUtf8(output);
|
|
||||||
const auto xml_begin = out_string.indexOf(QStringLiteral("<updates>"));
|
|
||||||
if (xml_begin < 0)
|
|
||||||
return XMLParseResult::NoUpdate;
|
|
||||||
const auto xml_end = out_string.indexOf(QStringLiteral("</updates>"), xml_begin);
|
|
||||||
if (xml_end < 0)
|
|
||||||
return XMLParseResult::NoUpdate;
|
|
||||||
|
|
||||||
QList<Updater::UpdateInfo> updates;
|
|
||||||
QXmlStreamReader reader(out_string.mid(xml_begin, (xml_end + 10) - xml_begin));
|
|
||||||
|
|
||||||
reader.readNextStartElement();
|
|
||||||
// should always work because it was search for
|
|
||||||
if (reader.name() != QStringLiteral("updates")) {
|
|
||||||
return XMLParseResult::InvalidXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (reader.readNextStartElement()) {
|
|
||||||
if (reader.name() != QStringLiteral("update"))
|
|
||||||
return XMLParseResult::InvalidXML;
|
|
||||||
|
|
||||||
auto ok = false;
|
|
||||||
Updater::UpdateInfo info(
|
|
||||||
reader.attributes().value(QStringLiteral("name")).toString(),
|
|
||||||
reader.attributes().value(QStringLiteral("version")).toString(),
|
|
||||||
reader.attributes().value(QStringLiteral("size")).toULongLong(&ok));
|
|
||||||
|
|
||||||
if (info.name.isEmpty() || info.version.isNull() || !ok)
|
|
||||||
return XMLParseResult::InvalidXML;
|
|
||||||
if (reader.readNextStartElement())
|
|
||||||
return XMLParseResult::InvalidXML;
|
|
||||||
|
|
||||||
updates.append(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reader.hasError()) {
|
|
||||||
LOG_ERROR(Frontend, "Cannot read xml for update: {}", reader.errorString().toStdString());
|
|
||||||
return XMLParseResult::InvalidXML;
|
|
||||||
}
|
|
||||||
|
|
||||||
out = updates;
|
|
||||||
return XMLParseResult::Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::UpdaterReady(int exit_code, QProcess::ExitStatus exit_status) {
|
|
||||||
if (main_process == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exit_status != QProcess::NormalExit) {
|
|
||||||
UpdaterError(QProcess::Crashed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
normal_exit = true;
|
|
||||||
last_error_code = exit_code;
|
|
||||||
last_error_log = main_process->readAllStandardError();
|
|
||||||
const auto update_out = main_process->readAllStandardOutput();
|
|
||||||
main_process->deleteLater();
|
|
||||||
main_process = nullptr;
|
|
||||||
|
|
||||||
running = false;
|
|
||||||
emit parent->RunningChanged(false);
|
|
||||||
|
|
||||||
QList<Updater::UpdateInfo> update_info;
|
|
||||||
auto err = ParseResult(update_out, update_info);
|
|
||||||
bool has_error = false;
|
|
||||||
|
|
||||||
if (err == XMLParseResult::Success) {
|
|
||||||
if (!update_info.isEmpty())
|
|
||||||
emit parent->UpdateInfoChanged(update_info);
|
|
||||||
} else if (err == XMLParseResult::InvalidXML) {
|
|
||||||
has_error = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit parent->CheckUpdatesDone(!update_info.isEmpty(), has_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::UpdaterError(QProcess::ProcessError error) {
|
|
||||||
if (main_process) {
|
|
||||||
normal_exit = false;
|
|
||||||
last_error_code = error;
|
|
||||||
last_error_log = main_process->errorString().toUtf8();
|
|
||||||
main_process->deleteLater();
|
|
||||||
main_process = nullptr;
|
|
||||||
|
|
||||||
running = false;
|
|
||||||
emit parent->RunningChanged(false);
|
|
||||||
emit parent->CheckUpdatesDone(false, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::LaunchWithArguments(const QStringList& args) {
|
|
||||||
if (!HasUpdater()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QFileInfo tool_info = GetMaintenanceTool();
|
|
||||||
|
|
||||||
if (!QProcess::startDetached(tool_info.absoluteFilePath(), args, tool_info.absolutePath())) {
|
|
||||||
LOG_WARNING(Frontend, "Unable to start program {}",
|
|
||||||
tool_info.absoluteFilePath().toStdString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::LaunchUI() {
|
|
||||||
LOG_INFO(Frontend, "Launching update UI...");
|
|
||||||
LaunchWithArguments(run_arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::SilentlyUpdate() {
|
|
||||||
LOG_INFO(Frontend, "Launching silent update...");
|
|
||||||
LaunchWithArguments(silent_arguments);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::AboutToExit() {
|
|
||||||
if (launch_ui_on_exit) {
|
|
||||||
LaunchUI();
|
|
||||||
} else if (UISettings::values.update_on_close) {
|
|
||||||
SilentlyUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterPrivate::LaunchUIOnExit() {
|
|
||||||
launch_ui_on_exit = true;
|
|
||||||
}
|
|
@ -1,169 +0,0 @@
|
|||||||
// Copyright 2017 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
//
|
|
||||||
// Based on the original work by Felix Barx
|
|
||||||
// Copyright (c) 2015, Felix Barz
|
|
||||||
// All rights reserved.
|
|
||||||
//
|
|
||||||
// Redistribution and use in source and binary forms, with or without
|
|
||||||
// modification, are permitted provided that the following conditions are met:
|
|
||||||
//
|
|
||||||
// * Redistributions of source code must retain the above copyright notice, this
|
|
||||||
// list of conditions and the following disclaimer.
|
|
||||||
//
|
|
||||||
// * Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
// this list of conditions and the following disclaimer in the documentation
|
|
||||||
// and/or other materials provided with the distribution.
|
|
||||||
//
|
|
||||||
// * Neither the name of QtAutoUpdater nor the names of its
|
|
||||||
// contributors may be used to endorse or promote products derived from
|
|
||||||
// this software without specific prior written permission.
|
|
||||||
//
|
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <QDateTime>
|
|
||||||
#include <QList>
|
|
||||||
#include <QScopedPointer>
|
|
||||||
#include <QString>
|
|
||||||
#include <QStringList>
|
|
||||||
|
|
||||||
class UpdaterPrivate;
|
|
||||||
|
|
||||||
/// The main updater. Can check for updates and run the maintenancetool as updater
|
|
||||||
class Updater : public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
/// Specifies whether the updater is currently checking for updates or not
|
|
||||||
Q_PROPERTY(bool running READ IsRunning NOTIFY RunningChanged);
|
|
||||||
/// Holds extended information about the last update check
|
|
||||||
Q_PROPERTY(QList<UpdateInfo> update_info READ LatestUpdateInfo NOTIFY UpdateInfoChanged);
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// Provides information about updates for components
|
|
||||||
struct UpdateInfo {
|
|
||||||
/// The name of the component that has an update
|
|
||||||
QString name;
|
|
||||||
/// The new version for that compontent
|
|
||||||
QString version;
|
|
||||||
/// The update download size (in Bytes)
|
|
||||||
quint64 size = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default Constructor
|
|
||||||
*/
|
|
||||||
UpdateInfo();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy Constructor
|
|
||||||
*/
|
|
||||||
UpdateInfo(const UpdateInfo& other);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor that takes name, version and size.
|
|
||||||
*/
|
|
||||||
UpdateInfo(QString name, QString version, quint64 size);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default constructor
|
|
||||||
**/
|
|
||||||
explicit Updater(QObject* parent = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor with an explicitly set path
|
|
||||||
**/
|
|
||||||
explicit Updater(const QString& maintenance_tool_path, QObject* parent = nullptr);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroys the updater and kills the update check (if running)
|
|
||||||
**/
|
|
||||||
~Updater();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns `true`, if the updater exited normally
|
|
||||||
**/
|
|
||||||
bool ExitedNormally() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mainetancetools error code from the last update check, if any.
|
|
||||||
**/
|
|
||||||
int ErrorCode() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the error output (stderr) of the last update
|
|
||||||
**/
|
|
||||||
QByteArray ErrorLog() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if a update check is running.
|
|
||||||
**/
|
|
||||||
bool IsRunning() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the latest update information available, if any.
|
|
||||||
**/
|
|
||||||
QList<UpdateInfo> LatestUpdateInfo() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launches the updater UI formally
|
|
||||||
**/
|
|
||||||
void LaunchUI();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Silently updates the application in the background
|
|
||||||
**/
|
|
||||||
void SilentlyUpdate();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks to see if a updater application is available
|
|
||||||
**/
|
|
||||||
bool HasUpdater() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instead of silently updating, explictly open the UI on shutdown
|
|
||||||
**/
|
|
||||||
void LaunchUIOnExit();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
/**
|
|
||||||
* Starts checking for updates
|
|
||||||
**/
|
|
||||||
bool CheckForUpdates();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Aborts checking for updates
|
|
||||||
**/
|
|
||||||
void AbortUpdateCheck(int max_delay = 5000, bool async = false);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
/**
|
|
||||||
* Will be emitted as soon as the updater finished checking for updates
|
|
||||||
**/
|
|
||||||
void CheckUpdatesDone(bool has_updates, bool has_error);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when a update check operation changes stage
|
|
||||||
**/
|
|
||||||
void RunningChanged(bool running);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Emitted when new update information has been found
|
|
||||||
**/
|
|
||||||
void UpdateInfoChanged(QList<Updater::UpdateInfo> update_info);
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<UpdaterPrivate> backend;
|
|
||||||
};
|
|
@ -1,67 +0,0 @@
|
|||||||
// Copyright 2017 Citra Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
//
|
|
||||||
// Based on the original work by Felix Barx
|
|
||||||
// Copyright (c) 2015, Felix Barz
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QtCore/QProcess>
|
|
||||||
#include "citra_qt/updater/updater.h"
|
|
||||||
|
|
||||||
enum class XMLParseResult {
|
|
||||||
Success,
|
|
||||||
NoUpdate,
|
|
||||||
InvalidXML,
|
|
||||||
};
|
|
||||||
|
|
||||||
class UpdaterPrivate : public QObject {
|
|
||||||
Q_OBJECT;
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit UpdaterPrivate(Updater* parent_ptr);
|
|
||||||
~UpdaterPrivate();
|
|
||||||
|
|
||||||
static QString ToSystemExe(QString base_path);
|
|
||||||
|
|
||||||
QFileInfo GetMaintenanceTool() const;
|
|
||||||
bool HasUpdater() const;
|
|
||||||
|
|
||||||
bool StartUpdateCheck();
|
|
||||||
void StopUpdateCheck(int delay, bool async);
|
|
||||||
|
|
||||||
void LaunchWithArguments(const QStringList& args);
|
|
||||||
void LaunchUI();
|
|
||||||
void SilentlyUpdate();
|
|
||||||
|
|
||||||
void LaunchUIOnExit();
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
void UpdaterReady(int exit_code, QProcess::ExitStatus exit_status);
|
|
||||||
void UpdaterError(QProcess::ProcessError error);
|
|
||||||
|
|
||||||
void AboutToExit();
|
|
||||||
|
|
||||||
private:
|
|
||||||
XMLParseResult ParseResult(const QByteArray& output, QList<Updater::UpdateInfo>& out);
|
|
||||||
|
|
||||||
Updater* parent;
|
|
||||||
|
|
||||||
QString tool_path{};
|
|
||||||
QList<Updater::UpdateInfo> update_info{};
|
|
||||||
bool normal_exit = true;
|
|
||||||
int last_error_code = 0;
|
|
||||||
QByteArray last_error_log = EXIT_SUCCESS;
|
|
||||||
|
|
||||||
bool running = false;
|
|
||||||
QProcess* main_process = nullptr;
|
|
||||||
|
|
||||||
bool launch_ui_on_exit = false;
|
|
||||||
|
|
||||||
QStringList run_arguments{QStringLiteral("--updater")};
|
|
||||||
QStringList silent_arguments{QStringLiteral("--silentUpdate")};
|
|
||||||
|
|
||||||
friend class Updater;
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user