refactor: Simplify update mechanism

This commit is contained in:
Petr Mironychev 2025-04-04 17:37:32 +02:00
parent 032c9bbbf3
commit 26731d3cfe
6 changed files with 47 additions and 216 deletions

View File

@ -52,10 +52,10 @@ void UpdateStatusWidget::setDefaultAction(QAction *action)
void UpdateStatusWidget::showUpdateAvailable(const QString &version)
{
m_versionLabel->setText(tr("new version: v%1").arg(version));
m_versionLabel->setText(tr("New version: v%1").arg(version));
m_versionLabel->setVisible(true);
m_updateButton->setVisible(true);
m_updateButton->setToolTip(tr("Update QodeAssist to version %1").arg(version));
m_updateButton->setToolTip(tr("Check update information"));
}
void UpdateStatusWidget::hideUpdateInfo()

View File

@ -179,9 +179,7 @@ private:
void handleUpdateCheckResult(const PluginUpdater::UpdateInfo &info)
{
if (!info.isUpdateAvailable
|| QVersionNumber::fromString(info.currentIdeVersion)
> QVersionNumber::fromString(info.targetIdeVersion))
if (!info.isUpdateAvailable)
return;
if (m_statusWidget)

View File

@ -25,7 +25,6 @@
#include <extensionsystem/pluginspec.h>
#include <QJsonArray>
#include <QJsonDocument>
#include <QStandardPaths>
namespace QodeAssist {
@ -57,7 +56,7 @@ void PluginUpdater::handleUpdateResponse(QNetworkReply *reply)
UpdateInfo info;
if (reply->error() != QNetworkReply::NoError) {
emit downloadError(reply->errorString());
emit updateCheckFinished(info);
return;
}
@ -68,45 +67,8 @@ void PluginUpdater::handleUpdateResponse(QNetworkReply *reply)
if (info.version.startsWith('v'))
info.version.remove(0, 1);
QString qtcVersionStr = Core::ICore::versionString().split(' ').last();
QVersionNumber qtcVersion = QVersionNumber::fromString(qtcVersionStr);
info.currentIdeVersion = qtcVersionStr;
auto assets = obj["assets"].toArray();
for (const auto &asset : assets) {
QString name = asset.toObject()["name"].toString();
if (name.startsWith("QodeAssist-")) {
QString assetVersionStr = name.section('-', 1, 1);
QVersionNumber assetVersion = QVersionNumber::fromString(assetVersionStr);
info.targetIdeVersion = assetVersionStr;
if (assetVersion != qtcVersion) {
continue;
}
#if defined(Q_OS_WIN)
if (name.contains("Windows"))
#elif defined(Q_OS_MACOS)
if (name.contains("macOS"))
#else
if (name.contains("Linux") && !name.contains("experimental"))
#endif
{
info.downloadUrl = asset.toObject()["browser_download_url"].toString();
info.fileName = name;
break;
}
}
}
if (info.downloadUrl.isEmpty()) {
info.incompatibleIdeVersion = true;
emit updateCheckFinished(info);
return;
}
info.changeLog = obj["body"].toString();
info.isUpdateAvailable = QVersionNumber::fromString(info.version)
> QVersionNumber::fromString(currentVersion());
@ -114,15 +76,6 @@ void PluginUpdater::handleUpdateResponse(QNetworkReply *reply)
emit updateCheckFinished(info);
}
void PluginUpdater::downloadUpdate(const QString &url)
{
QNetworkRequest request(url);
QNetworkReply *reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::downloadProgress, this, &PluginUpdater::handleDownloadProgress);
connect(reply, &QNetworkReply::finished, this, &PluginUpdater::handleDownloadFinished);
}
QString PluginUpdater::currentVersion() const
{
const auto pluginSpecs = ExtensionSystem::PluginManager::plugins();
@ -143,46 +96,4 @@ QString PluginUpdater::getUpdateUrl() const
return "https://api.github.com/repos/Palm1r/qodeassist/releases/latest";
}
void PluginUpdater::handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
emit downloadProgress(bytesReceived, bytesTotal);
}
void PluginUpdater::handleDownloadFinished()
{
auto reply = qobject_cast<QNetworkReply *>(sender());
QTC_ASSERT(reply, return);
if (reply->error() != QNetworkReply::NoError) {
emit downloadError(reply->errorString());
reply->deleteLater();
return;
}
QString downloadPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)
+ QDir::separator() + "QodeAssist_v" + m_lastUpdateInfo.version;
QDir().mkpath(downloadPath);
QString filePath = downloadPath + QDir::separator() + m_lastUpdateInfo.fileName;
if (QFile::exists(filePath)) {
emit downloadError(tr("Update file already exists: %1").arg(filePath));
reply->deleteLater();
return;
}
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly)) {
emit downloadError(tr("Could not save the update file"));
reply->deleteLater();
return;
}
file.write(reply->readAll());
file.close();
emit downloadFinished(filePath);
reply->deleteLater();
}
} // namespace QodeAssist

View File

@ -20,7 +20,6 @@
#pragma once
#include <coreplugin/icore.h>
#include <coreplugin/plugininstallwizard.h>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QObject>
@ -35,38 +34,27 @@ public:
struct UpdateInfo
{
QString version;
QString downloadUrl;
QString changeLog;
QString fileName;
bool isUpdateAvailable;
bool incompatibleIdeVersion{false};
QString targetIdeVersion;
QString currentIdeVersion;
bool isUpdateAvailable = false;
};
explicit PluginUpdater(QObject *parent = nullptr);
~PluginUpdater() = default;
void checkForUpdates();
void downloadUpdate(const QString &url);
QString currentVersion() const;
bool isUpdateAvailable() const;
signals:
void updateCheckFinished(const UpdateInfo &info);
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void downloadFinished(const QString &filePath);
void downloadError(const QString &error);
private:
void handleUpdateResponse(QNetworkReply *reply);
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void handleDownloadFinished();
QString getUpdateUrl() const;
QNetworkAccessManager *m_networkManager;
UpdateInfo m_lastUpdateInfo;
bool m_isCheckingUpdate{false};
bool m_isCheckingUpdate = false;
};
} // namespace QodeAssist

View File

@ -23,6 +23,8 @@
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
#include <QDesktopServices>
#include <QHBoxLayout>
#include <QVBoxLayout>
namespace QodeAssist {
@ -32,7 +34,7 @@ UpdateDialog::UpdateDialog(QWidget *parent)
{
setWindowTitle(tr("QodeAssist Update"));
setMinimumWidth(400);
setMinimumHeight(500);
setMinimumHeight(300);
m_layout = new QVBoxLayout(this);
m_layout->setSpacing(12);
@ -61,34 +63,24 @@ UpdateDialog::UpdateDialog(QWidget *parent)
m_layout->addWidget(m_titleLabel);
m_versionLabel = new QLabel(
tr("Version %1 is now available - you have %2").arg(m_updater->currentVersion()), this);
tr("Version %1 is now available - you have %2").arg("", m_updater->currentVersion()), this);
m_versionLabel->setAlignment(Qt::AlignCenter);
m_layout->addWidget(m_versionLabel);
m_releaseLink = new QLabel(this);
m_releaseLink->setOpenExternalLinks(true);
m_releaseLink->setTextFormat(Qt::RichText);
m_releaseLink->setAlignment(Qt::AlignCenter);
m_layout->addWidget(m_releaseLink);
m_changelogLabel = new QLabel(tr("Release Notes:"), this);
m_layout->addWidget(m_changelogLabel);
if (!m_changelogLabel) {
m_changelogLabel = new QLabel(tr("Release Notes:"), this);
m_layout->addWidget(m_changelogLabel);
m_changelogText = new QTextEdit(this);
m_changelogText->setReadOnly(true);
m_changelogText->setMinimumHeight(100);
m_layout->addWidget(m_changelogText);
}
m_progress = new QProgressBar(this);
m_progress->setVisible(false);
m_layout->addWidget(m_progress);
m_changelogText = new QTextEdit(this);
m_changelogText->setReadOnly(true);
m_changelogText->setMinimumHeight(100);
m_layout->addWidget(m_changelogText);
auto *buttonLayout = new QHBoxLayout;
m_downloadButton = new QPushButton(tr("Download"), this);
m_downloadButton->setEnabled(false);
buttonLayout->addWidget(m_downloadButton);
m_buttonOpenReleasePage = new QPushButton(tr("Open Release Page"), this);
buttonLayout->addWidget(m_buttonOpenReleasePage);
m_buttonOpenPluginFolder = new QPushButton(tr("Open Plugin Folder"), this);
buttonLayout->addWidget(m_buttonOpenPluginFolder);
m_closeButton = new QPushButton(tr("Close"), this);
buttonLayout->addWidget(m_closeButton);
@ -96,11 +88,8 @@ UpdateDialog::UpdateDialog(QWidget *parent)
m_layout->addLayout(buttonLayout);
connect(m_updater, &PluginUpdater::updateCheckFinished, this, &UpdateDialog::handleUpdateInfo);
connect(m_updater, &PluginUpdater::downloadProgress, this, &UpdateDialog::updateProgress);
connect(m_updater, &PluginUpdater::downloadFinished, this, &UpdateDialog::handleDownloadFinished);
connect(m_updater, &PluginUpdater::downloadError, this, &UpdateDialog::handleDownloadError);
connect(m_downloadButton, &QPushButton::clicked, this, &UpdateDialog::startDownload);
connect(m_buttonOpenReleasePage, &QPushButton::clicked, this, &UpdateDialog::openReleasePage);
connect(m_buttonOpenPluginFolder, &QPushButton::clicked, this, &UpdateDialog::openPluginFolder);
connect(m_closeButton, &QPushButton::clicked, this, &QDialog::reject);
m_updater->checkForUpdates();
@ -115,22 +104,12 @@ void UpdateDialog::checkForUpdatesAndShow(QWidget *parent)
void UpdateDialog::handleUpdateInfo(const PluginUpdater::UpdateInfo &info)
{
m_releaseLink->setText(
tr("<a href='https://github.com/Palm1r/QodeAssist/releases'>You can also download "
"from GitHub Releases</a>"));
if (info.incompatibleIdeVersion) {
m_titleLabel->setText(tr("Incompatible Qt Creator Version"));
m_versionLabel->setText(tr("This update requires Qt Creator %1, current is %2.\n"
"Please upgrade Qt Creator to use this version of QodeAssist.")
.arg(info.targetIdeVersion, info.currentIdeVersion));
m_downloadButton->setEnabled(false);
return;
}
m_updateInfo = info;
if (!info.isUpdateAvailable) {
m_titleLabel->setText(tr("QodeAssist is up to date"));
m_downloadButton->setEnabled(false);
m_versionLabel->setText(
tr("You are using the latest version: %1").arg(m_updater->currentVersion()));
return;
}
@ -139,72 +118,31 @@ void UpdateDialog::handleUpdateInfo(const PluginUpdater::UpdateInfo &info)
.arg(info.version, m_updater->currentVersion()));
if (!info.changeLog.isEmpty()) {
if (!m_changelogLabel) {
m_changelogLabel = new QLabel(tr("Release Notes:"), this);
m_layout->insertWidget(2, m_changelogLabel);
m_changelogText = new QTextEdit(this);
m_changelogText->setReadOnly(true);
m_changelogText->setMaximumHeight(200);
m_layout->insertWidget(3, m_changelogText);
}
m_changelogText->setText(info.changeLog);
} else {
m_changelogText->setText(
tr("No release notes available. Check the release page for more information."));
}
m_downloadButton->setEnabled(true);
m_updateInfo = info;
}
void UpdateDialog::startDownload()
void UpdateDialog::openReleasePage()
{
m_downloadButton->setEnabled(false);
m_progress->setVisible(true);
m_updater->downloadUpdate(m_updateInfo.downloadUrl);
QDesktopServices::openUrl(QUrl("https://github.com/Palm1r/QodeAssist/releases/latest"));
accept();
}
void UpdateDialog::updateProgress(qint64 received, qint64 total)
void UpdateDialog::openPluginFolder()
{
m_progress->setMaximum(total);
m_progress->setValue(received);
}
void UpdateDialog::handleDownloadFinished(const QString &path)
{
m_progress->setVisible(false);
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Update Downloaded"));
msgBox.setText(tr("The update has been downloaded successfully.\n"
"Would you like to close Qt Creator now and open the plugin folder?"));
msgBox.setInformativeText(tr("To complete the update:\n\n"
"1. Close Qt Creator completely\n"
"2. Navigate to the plugin folder\n"
"3. Remove the old version of QodeAssist plugin\n"
"4. Install plugin as usual via About plugin menu"));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
msgBox.setDefaultButton(QMessageBox::Yes);
msgBox.setIcon(QMessageBox::Information);
if (msgBox.exec() == QMessageBox::Yes) {
const auto pluginSpecs = ExtensionSystem::PluginManager::plugins();
for (const ExtensionSystem::PluginSpec *spec : pluginSpecs) {
if (spec->name() == QLatin1String("QodeAssist")) {
const auto pluginPath = spec->filePath().path();
QFileInfo fileInfo(pluginPath);
QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absolutePath()));
Core::ICore::exit();
break;
}
const auto pluginSpecs = ExtensionSystem::PluginManager::plugins();
for (const ExtensionSystem::PluginSpec *spec : pluginSpecs) {
if (spec->name() == QLatin1String("QodeAssist")) {
const auto pluginPath = spec->filePath().path();
QFileInfo fileInfo(pluginPath);
QDesktopServices::openUrl(QUrl::fromLocalFile(fileInfo.absolutePath()));
break;
}
}
accept();
}
void UpdateDialog::handleDownloadError(const QString &error)
{
m_progress->setVisible(false);
m_downloadButton->setEnabled(true);
QMessageBox::critical(this, tr("Update Error"), tr("Failed to update: %1").arg(error));
}
} // namespace QodeAssist

View File

@ -23,7 +23,6 @@
#include <QHBoxLayout>
#include <QLabel>
#include <QMessageBox>
#include <QProgressBar>
#include <QPushButton>
#include <QTextEdit>
#include <QVBoxLayout>
@ -42,21 +41,18 @@ public:
private slots:
void handleUpdateInfo(const PluginUpdater::UpdateInfo &info);
void startDownload();
void updateProgress(qint64 received, qint64 total);
void handleDownloadFinished(const QString &path);
void handleDownloadError(const QString &error);
void openReleasePage();
void openPluginFolder();
private:
PluginUpdater *m_updater;
QVBoxLayout *m_layout;
QLabel *m_titleLabel;
QLabel *m_versionLabel;
QLabel *m_releaseLink;
QLabel *m_changelogLabel{nullptr};
QTextEdit *m_changelogText{nullptr};
QProgressBar *m_progress;
QPushButton *m_downloadButton;
QLabel *m_changelogLabel;
QTextEdit *m_changelogText;
QPushButton *m_buttonOpenReleasePage;
QPushButton *m_buttonOpenPluginFolder;
QPushButton *m_closeButton;
PluginUpdater::UpdateInfo m_updateInfo;
};