Initial self update implementation
This commit is contained in:
@@ -12,7 +12,7 @@ qmake=$(wine) $(pwd)/Qt/5.11.1/mingw53_32/bin/qmake.exe
|
|||||||
|
|
||||||
.PHONY: build
|
.PHONY: build
|
||||||
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:
|
cmake-3.12.0-rc3-win32-x86.msi:
|
||||||
wget https://cmake.org/files/v3.12/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)
|
$(wine) mingw32-make -C libgit2-0.27.2/build -j $(shell nproc)
|
||||||
|
|
||||||
build_win32/GitAddonsManager.exe: Qt libgit2-0.27.2/build/libgit2.dll
|
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
|
$(wine) mingw32-make -C build_win32
|
||||||
|
|
||||||
winbuild: build_win32/GitAddonsManager.exe
|
winbuild: build_win32/GitAddonsManager.exe
|
||||||
|
|||||||
+74
@@ -20,13 +20,19 @@
|
|||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
|
#include <QDesktopServices>
|
||||||
#include "addon.h"
|
#include "addon.h"
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtConcurrent>
|
#include <QtConcurrent>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
#include <QNetworkRequest>
|
||||||
|
#include <QNetworkReply>
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
Control *Control::m_instance = nullptr;
|
Control *Control::m_instance = nullptr;
|
||||||
|
QNetworkAccessManager nam;
|
||||||
|
|
||||||
Control::Control(QObject *parent) : QObject(parent),
|
Control::Control(QObject *parent) : QObject(parent),
|
||||||
m_progress(0), m_total(0), m_status(Status::Ready), m_statusMessage(""), m_pool(new QThreadPool(this)),
|
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::scanForAddons);
|
||||||
connect(this, &Control::addonsPathChanged, this, &Control::saveAddonsPath);
|
connect(this, &Control::addonsPathChanged, this, &Control::saveAddonsPath);
|
||||||
delegate("Initializing libgit2...", [](){git_libgit2_init();},[this](){scanForAddons();});
|
delegate("Initializing libgit2...", [](){git_libgit2_init();},[this](){scanForAddons();});
|
||||||
|
checkForUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Control::delegate(QString taskname, auto work, auto callback)
|
void Control::delegate(QString taskname, auto work, auto callback)
|
||||||
@@ -147,6 +154,11 @@ QStringList Control::availableStyles() const
|
|||||||
return m_availableStyles;
|
return m_availableStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Control::UpdateStatus Control::updateStatus() const
|
||||||
|
{
|
||||||
|
return m_updateStatus;
|
||||||
|
}
|
||||||
|
|
||||||
void Control::setAddons(QList<QObject *> addons)
|
void Control::setAddons(QList<QObject *> addons)
|
||||||
{
|
{
|
||||||
if (m_addons == addons)
|
if (m_addons == addons)
|
||||||
@@ -326,3 +338,65 @@ void Control::setAvailableStyles(QStringList availableStyles)
|
|||||||
m_availableStyles = availableStyles;
|
m_availableStyles = availableStyles;
|
||||||
emit availableStylesChanged(m_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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -63,6 +63,16 @@ public:
|
|||||||
Q_ENUM(MinimizeToTray)
|
Q_ENUM(MinimizeToTray)
|
||||||
Q_PROPERTY(MinimizeToTray minimizeToTray READ minimizeToTray WRITE setMinimizeToTray NOTIFY minimizeToTrayChanged)
|
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;
|
QList<QObject *> addons() const;
|
||||||
|
|
||||||
QString addonsPath() const;
|
QString addonsPath() const;
|
||||||
@@ -85,6 +95,8 @@ public:
|
|||||||
|
|
||||||
QStringList availableStyles() const;
|
QStringList availableStyles() const;
|
||||||
|
|
||||||
|
UpdateStatus updateStatus() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static Control *m_instance;
|
static Control *m_instance;
|
||||||
explicit Control(QObject *parent = nullptr);
|
explicit Control(QObject *parent = nullptr);
|
||||||
@@ -110,6 +122,8 @@ private:
|
|||||||
|
|
||||||
QStringList m_availableStyles;
|
QStringList m_availableStyles;
|
||||||
|
|
||||||
|
UpdateStatus m_updateStatus = UpdateStatus::NoUpdate;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void addonsChanged(QList<QObject *> addons);
|
void addonsChanged(QList<QObject *> addons);
|
||||||
|
|
||||||
@@ -131,6 +145,8 @@ signals:
|
|||||||
|
|
||||||
void availableStylesChanged(QStringList availableStyles);
|
void availableStylesChanged(QStringList availableStyles);
|
||||||
|
|
||||||
|
void updateStatusChanged(UpdateStatus updateStatus);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setAddons(QList<QObject *> addons);
|
void setAddons(QList<QObject *> addons);
|
||||||
void setAddonsPath(QString addonsPath);
|
void setAddonsPath(QString addonsPath);
|
||||||
@@ -145,6 +161,10 @@ public slots:
|
|||||||
void setMinimizeToTray(MinimizeToTray minimizeToTray);
|
void setMinimizeToTray(MinimizeToTray minimizeToTray);
|
||||||
void setStyle(QString style);
|
void setStyle(QString style);
|
||||||
void setAvailableStyles(QStringList availableStyles);
|
void setAvailableStyles(QStringList availableStyles);
|
||||||
|
void checkForUpdates();
|
||||||
|
void downloadUpdate();
|
||||||
|
void executeUpdate();
|
||||||
|
void setUpdateStatus(UpdateStatus updateStatus);
|
||||||
};
|
};
|
||||||
Q_DECLARE_METATYPE(Control::MinimizeToTray)
|
Q_DECLARE_METATYPE(Control::MinimizeToTray)
|
||||||
|
|
||||||
|
|||||||
@@ -149,6 +149,37 @@ ApplicationWindow {
|
|||||||
selectByMouse: true
|
selectByMouse: true
|
||||||
onFocusChanged: if (focus) selectAll()
|
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
|
modal: true
|
||||||
standardButtons: Dialog.Close
|
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 & 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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user