Initial self update implementation

This commit is contained in:
woblight
2018-07-17 22:43:58 +02:00
parent 5ee2fce3aa
commit d6bb799e61
4 changed files with 170 additions and 2 deletions
+2 -2
View File
@@ -12,7 +12,7 @@ qmake=$(wine) $(pwd)/Qt/5.11.1/mingw53_32/bin/qmake.exe
.PHONY: build
build:
mkdir -p GitAddonsManager && cd GitAddonsManager && qmake-qt5 .. -spec linux-g++ && make
mkdir -p GitAddonsManager && cd GitAddonsManager && qmake-qt5 .. -spec linux-g++ GAM_BUILD_NAME="Linux_x64" && make
cmake-3.12.0-rc3-win32-x86.msi:
wget https://cmake.org/files/v3.12/cmake-3.12.0-rc3-win32-x86.msi
@@ -75,7 +75,7 @@ libgit2-0.27.2/build/libgit2.dll: wine/drive_c/Program\ Files\ (x86)/CMake libgi
$(wine) mingw32-make -C libgit2-0.27.2/build -j $(shell nproc)
build_win32/GitAddonsManager.exe: Qt libgit2-0.27.2/build/libgit2.dll
mkdir -p build_win32 && cd build_win32 && $(qmake) $(qmake_opts) ../GitAddonsManager.pro GIT_DESCRIBE="$(shell git describe --tags)"
mkdir -p build_win32 && cd build_win32 && $(qmake) $(qmake_opts) ../GitAddonsManager.pro GIT_DESCRIBE="$(shell git describe --tags)" GAM_BUILD_NAME="Win32"
$(wine) mingw32-make -C build_win32
winbuild: build_win32/GitAddonsManager.exe
+74
View File
@@ -20,13 +20,19 @@
#include <QFutureWatcher>
#include <QQuickStyle>
#include <QQuickStyle>
#include <QDesktopServices>
#include "addon.h"
#include <git2.h>
#include <QDebug>
#include <QtConcurrent>
#include <type_traits>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QApplication>
Control *Control::m_instance = nullptr;
QNetworkAccessManager nam;
Control::Control(QObject *parent) : QObject(parent),
m_progress(0), m_total(0), m_status(Status::Ready), m_statusMessage(""), m_pool(new QThreadPool(this)),
@@ -39,6 +45,7 @@ Control::Control(QObject *parent) : QObject(parent),
connect(this, &Control::addonsPathChanged, this, &Control::scanForAddons);
connect(this, &Control::addonsPathChanged, this, &Control::saveAddonsPath);
delegate("Initializing libgit2...", [](){git_libgit2_init();},[this](){scanForAddons();});
checkForUpdates();
}
void Control::delegate(QString taskname, auto work, auto callback)
@@ -147,6 +154,11 @@ QStringList Control::availableStyles() const
return m_availableStyles;
}
Control::UpdateStatus Control::updateStatus() const
{
return m_updateStatus;
}
void Control::setAddons(QList<QObject *> addons)
{
if (m_addons == addons)
@@ -326,3 +338,65 @@ void Control::setAvailableStyles(QStringList availableStyles)
m_availableStyles = availableStyles;
emit availableStylesChanged(m_availableStyles);
}
void Control::checkForUpdates()
{
#ifdef GAM_BUILD_NAME
QNetworkRequest req(QUrl(QString("https://gitlab.com/woblight/GitAddonsManager/-/jobs/artifacts/master/download?job=%1").arg(GAM_BUILD_NAME)));
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
auto reply = nam.head(req);
setUpdateStatus(UpdateStatus::CheckingForUpdate);
connect(reply, &QNetworkReply::finished,[this, reply](){
QRegExp shaCapt(QString("GitAddonsManager_%1-(\\w{40})\\.zip").arg(GAM_BUILD_NAME));
if (shaCapt.indexIn(reply->url().toString()) != -1) {
if (!QString(GIT_DESCRIBE).endsWith(shaCapt.cap(1).chopped(33)))
setUpdateStatus(UpdateStatus::UpdateAvailable);
else setUpdateStatus(UpdateStatus::NoUpdate);
};
});
#endif
}
void Control::downloadUpdate()
{
#ifdef GAM_BUILD_NAME
QFile *zip = new QFile("GitAddonsManager.zip");
if (!zip->open(QFile::WriteOnly)) {
setUpdateStatus(UpdateStatus::UpdateError);
return;
}
QNetworkRequest req(QUrl(QString("https://gitlab.com/woblight/GitAddonsManager/-/jobs/artifacts/master/download?job=%1").arg(GAM_BUILD_NAME)));
req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
auto reply = nam.get(req);
setUpdateStatus(UpdateStatus::DownloadingUpdate);
connect(reply, &QNetworkReply::readyRead,[reply, zip]() {
zip->write(reply->readAll());
});
connect(reply, &QNetworkReply::finished, [this, reply, zip]() {
zip->close();
delete zip;
setUpdateStatus(reply->error() == QNetworkReply::NoError ? UpdateStatus::UpdateReady : UpdateStatus::UpdateError);
reply->deleteLater();
});
connect(reply, &QNetworkReply::downloadProgress, [this](qint64 recieved, qint64 bytesTotal) {
setTotal(bytesTotal);
setProgress(recieved);
});
#endif
}
void Control::executeUpdate()
{
QDesktopServices::openUrl(QDir().absolutePath());
QApplication::exit(2);
}
void Control::setUpdateStatus(Control::UpdateStatus updateStatus)
{
if (m_updateStatus == updateStatus)
return;
m_updateStatus = updateStatus;
emit updateStatusChanged(m_updateStatus);
}
+20
View File
@@ -63,6 +63,16 @@ public:
Q_ENUM(MinimizeToTray)
Q_PROPERTY(MinimizeToTray minimizeToTray READ minimizeToTray WRITE setMinimizeToTray NOTIFY minimizeToTrayChanged)
enum class UpdateStatus {
UpdateError = -1,
NoUpdate,
UpdateAvailable,
DownloadingUpdate,
UpdateReady,
CheckingForUpdate
};
Q_ENUM(UpdateStatus)
Q_PROPERTY(UpdateStatus updateStatus READ updateStatus WRITE setUpdateStatus NOTIFY updateStatusChanged)
QList<QObject *> addons() const;
QString addonsPath() const;
@@ -85,6 +95,8 @@ public:
QStringList availableStyles() const;
UpdateStatus updateStatus() const;
private:
static Control *m_instance;
explicit Control(QObject *parent = nullptr);
@@ -110,6 +122,8 @@ private:
QStringList m_availableStyles;
UpdateStatus m_updateStatus = UpdateStatus::NoUpdate;
signals:
void addonsChanged(QList<QObject *> addons);
@@ -131,6 +145,8 @@ signals:
void availableStylesChanged(QStringList availableStyles);
void updateStatusChanged(UpdateStatus updateStatus);
public slots:
void setAddons(QList<QObject *> addons);
void setAddonsPath(QString addonsPath);
@@ -145,6 +161,10 @@ public slots:
void setMinimizeToTray(MinimizeToTray minimizeToTray);
void setStyle(QString style);
void setAvailableStyles(QStringList availableStyles);
void checkForUpdates();
void downloadUpdate();
void executeUpdate();
void setUpdateStatus(UpdateStatus updateStatus);
};
Q_DECLARE_METATYPE(Control::MinimizeToTray)
+74
View File
@@ -149,6 +149,37 @@ ApplicationWindow {
selectByMouse: true
onFocusChanged: if (focus) selectAll()
}
Button {
id: updateButton
contentItem: RowLayout {
BusyIndicator {
implicitHeight: parent.height
implicitWidth: implicitHeight
running: !updateButton.enabled
visible: running
}
Label {
text:
Engine.updateStatus === Engine.NoUpdate ?
qsTr("Check for update") :
Engine.updateStatus === Engine.CheckingForUpdate ?
qsTr("Checking for update...") :
Engine.updateStatus === Engine.UpdateAvailable ?
qsTr("Download update") :
Engine.updateStatus === Engine.DownloadingUpdate ?
qsTr("Downloading update...") :
Engine.updateStatus === Engine.UpdateReady ?
qsTr("Apply update") : qsTr("error")
}
}
onClicked: Engine.updateStatus === Engine.NoUpdate ?
Engine.checkForUpdates() :
Engine.updateStatus === Engine.UpdateAvailable ?
Engine.downloadUpdate() :
Engine.updateStatus === Engine.UpdateReady ?
Engine.executeUpdate() : {}
enabled: Engine.updateStatus === Engine.NoUpdate || Engine.updateStatus === Engine.UpdateAvailable || Engine.updateStatus === Engine.UpdateReady
}
}
}
}
@@ -315,4 +346,47 @@ ApplicationWindow {
modal: true
standardButtons: Dialog.Close
}
Dialog {
x: (parent.width - width) / 2
y: (parent.height - height) / 2
visible: Engine.updateStatus === Engine.UpdateAvailable || Engine.updateStatus === Engine.DownloadingUpdate || Engine.updateStatus === Engine.UpdateReady
id: updateDialog
ColumnLayout {
anchors.fill: parent
Label {
Layout.fillWidth: true
id: updateMessage
text: Engine.updateStatus === Engine.UpdateAvailable ?
qsTr("<h1>A newer version of GitAddonsManager is available</h1>") :
Engine.updateStatus === Engine.DownloadingUpdate ?
qsTr("Downloading update...") : qsTr("Download finished.<br/>To complete the update click \"Close &amp; Update\", then extract GitAddonsManager.zip and replace old files.")
textFormat: Text.RichText
wrapMode: Text.WordWrap
}
ProgressBar {
Layout.fillWidth: true
id: updateProgress
to: Engine.total
value: Engine.progress
indeterminate: to == -1
visible: Engine.updateStatus === Engine.DownloadingUpdate
}
}
modal: true
footer: DialogButtonBox {
Button {
visible: Engine.updateStatus === Engine.UpdateAvailable
text: qsTr("Download")
onClicked: Engine.downloadUpdate()
}
Button {
visible: Engine.updateStatus === Engine.UpdateReady
text: qsTr("Close && Update")
onClicked: Engine.executeUpdate()
}
}
closePolicy: Engine.updateStatus !== Engine.DownloadingUpdate ? Dialog.CloseOnPressOutside | Dialog.CloseOnEscape : Dialog.NoAutoClose
standardButtons: Engine.updateStatus !== Engine.DownloadingUpdate ? Dialog.Close : Dialog.NoButton
}
}