diff --git a/CI.mk b/CI.mk
index 4cdec5a..a047ac2 100644
--- a/CI.mk
+++ b/CI.mk
@@ -7,12 +7,12 @@ winepath=$(wineenv) winepath
wine=$(WINEPATH) $(wineenv) wine
WINEPREFIX=WINEPREFIX="$(pwd)/wine"
WINEPATH=WINEPATH='C:\Program Files (x86)\CMake\bin;$(shell $(winepath) -w "$(pwd)/mingw32/bin");$(shell $(winepath) -w "$(pwd)/Qt/5.11.1/mingw53_32/bin")' QTDIR="Z:$(pwd)/Qt/5.11.1/mingw53_32/"
-qmake_opts="QMAKE_INCDIR+=Z:$(pwd)/libgit2-0.27.2/include" "QMAKE_LIBDIR+=Z:$(pwd)/libgit2-0.27.2/build/" -spec win32-g++
+qmake_opts="QMAKE_INCDIR+=Z:$(pwd)/libgit2-0.27.2/include Z:$(pwd)/quazip/quazip" "QMAKE_LIBDIR+=Z:$(pwd)/libgit2-0.27.2/build/ Z:$(pwd)/quazip/build/release Z:$(pwd)/libz/build" -spec win32-g++ LIBS+=-lquazip
qmake=$(wine) $(pwd)/Qt/5.11.1/mingw53_32/bin/qmake.exe
.PHONY: build winbuild windeploy
build:
- mkdir -p GitAddonsManager && cd GitAddonsManager && qmake-qt5 .. -spec linux-g++ DEFINES+='GAM_BUILD_NAME=\\\"Linux_x64\\\"' && make
+ mkdir -p GitAddonsManager && cd GitAddonsManager && qmake-qt5 .. -spec linux-g++ DEFINES+='GAM_BUILD_NAME=\\\"Linux_x64\\\"' LIBS+=-lquazip5 INCLUDEPATH+=/usr/include/quazip5 && make
cmake-3.12.0-rc3-win32-x86.msi:
wget https://cmake.org/files/v3.12/cmake-3.12.0-rc3-win32-x86.msi
@@ -74,7 +74,23 @@ libgit2-0.27.2/build/libgit2.dll: wine/drive_c/Program\ Files\ (x86)/CMake libgi
cd libgit2-0.27.2/build && $(wine) cmake .. -DCMAKE_BINARY_DIR=libgit2-0.27.2/build -G"MinGW Makefiles" -DBUILD_CLAR=OFF
$(wine) mingw32-make -C libgit2-0.27.2/build -j $(shell nproc)
-build_win32/GitAddonsManager.exe: Qt libgit2-0.27.2/build/libgit2.dll
+zlib/CMakeLists.txt:
+ git clone https://github.com/madler/zlib.git
+
+zlib/build/libzlib.dll: zlib/CMakeLists.txt
+ mkdir -p zlib/build
+ cd zlib/build && $(wine) cmake .. -DCMAKE_BINARY_DIR=zlib/build -G"MinGW Makefiles"
+ $(wine) mingw32-make -C zlib/build -j $(shell nproc)
+
+quazip/quazip.pro:
+ git clone https://github.com/stachenov/quazip.git
+
+quazip/build/release/quazip.dll: quazip/quazip.pro
+ mkdir -p quazip/build
+ cd quazip/build && $(qmake) ../quazip/quazip.pro QMAKE_LIBDIR+="Z:$(pwd)/zlib/build" LIBS+=-lzlib QMAKE_INCDIR+="Z:$(pwd)/zlib" -spec win32-g++
+ $(wine) mingw32-make -C quazip/build
+
+build_win32/GitAddonsManager.exe: Qt libgit2-0.27.2/build/libgit2.dll zlib/build/libzlib.dll quazip/build/release/quazip.dll
mkdir -p build_win32 && cd build_win32 && $(qmake) $(qmake_opts) ../GitAddonsManager.pro GIT_DESCRIBE="$(shell git describe --tags)" DEFINES+='GAM_BUILD_NAME=\\\"Win32\\\"'
$(wine) mingw32-make -C build_win32
@@ -85,6 +101,10 @@ build_win32/release/GitAddonsManager.exe: winbuild
windeploy: build_win32/release/GitAddonsManager.exe libgit2-0.27.2/build/libgit2.dll
mkdir -p GitAddonsManager/
cp libgit2-0.27.2/build/libgit2.dll -f GitAddonsManager/libgit2.dll
+ cp zlib/build/libzlib.dll -f GitAddonsManager/libzlib.dll
+ cp quazip/build/release/quazip.dll -f GitAddonsManager/quazip.dll
+ cp mingw32/opt/bin/libeay32.dll -f GitAddonsManager/libeay32.dll
+ cp mingw32/opt/bin/ssleay32.dll -f GitAddonsManager/ssleay32.dll
cp build_win32/release/GitAddonsManager.exe -f GitAddonsManager/
mkdir -p tmpqmls && cp -f *.qml tmpqmls/
$(wine) Qt/5.11.1/mingw53_32/bin/windeployqt.exe --qmldir tmpqmls GitAddonsManager/GitAddonsManager.exe
diff --git a/Update.qml b/Update.qml
new file mode 100644
index 0000000..c0bd532
--- /dev/null
+++ b/Update.qml
@@ -0,0 +1,49 @@
+/* Copyright 2018 WobLight
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+import QtQuick 2.9
+import GitAddonsManager.engine 1.0
+import QtQuick.Controls 2.4
+import QtQuick.Layouts 1.3
+
+ApplicationWindow {
+ visible: true
+ title: "Updating..."
+ width: errorDialog.visible?errorDialog.implicitWidth:bar.implicitWidth
+ height: errorDialog.visible?errorDialog.implicitHeight:bar.implicitHeight
+ flags: Qt.FramelessWindowHint
+ color: "transparent"
+ ProgressBar {
+ visible: Engine.status !== Engine.Error
+ id: bar
+ anchors.fill: parent
+ to: Engine.total
+ value: Engine.progress
+ indeterminate: to <= 0
+ }
+ Dialog {
+ id: errorDialog
+ visible: Engine.status === Engine.Error
+ standardButtons: Dialog.Close
+ onClosed: Qt.exit(-2)
+ title: qsTr("GitAddonsManager update error")
+ Label {
+ text: Engine.statusMessage
+ }
+ }
+
+ onClosing: {}
+}
diff --git a/control.cpp b/control.cpp
index 4e5ff1c..25be0d0 100644
--- a/control.cpp
+++ b/control.cpp
@@ -30,21 +30,28 @@
#include
#include
#include
+#include
+#include
Control *Control::m_instance = nullptr;
-QNetworkAccessManager nam;
+QNetworkAccessManager *nam = nullptr;
Control::Control(QObject *parent) : QObject(parent),
m_progress(0), m_total(0), m_status(Status::Ready), m_statusMessage(""), m_pool(new QThreadPool(this)),
m_style(QQuickStyle::name()),m_availableStyles(QQuickStyle::availableStyles())
{
+ connect(this, &Control::addonsPathChanged, this, &Control::scanForAddons);
+ connect(this, &Control::addonsPathChanged, this, &Control::saveAddonsPath);
+}
+
+void Control::init() {
QSettings settings;
setAddonsPath(settings.value("addonsPath").toString());
setFirstBoot(settings.value("firstBoot",true).toBool());
setMinimizeToTray((MinimizeToTray)settings.value("minimizeToTray",(int)MinimizeToTrayAsk).toInt());
- connect(this, &Control::addonsPathChanged, this, &Control::scanForAddons);
- connect(this, &Control::addonsPathChanged, this, &Control::saveAddonsPath);
- delegate("Initializing libgit2...", [](){git_libgit2_init();},[this](){scanForAddons();});
+ git_libgit2_init();
+ scanForAddons();
+ nam = new QNetworkAccessManager(this);
checkForUpdates();
}
@@ -159,6 +166,68 @@ Control::UpdateStatus Control::updateStatus() const
return m_updateStatus;
}
+
+void walkFoldersIf(const QFileInfo &info, auto f, auto t){
+ int ret = t(info);
+ if (ret <= 0) {
+ if (info.isDir() && !info.isSymLink()) {
+ foreach (QFileInfo sub, QDir(info.absoluteFilePath()).entryInfoList(QDir::AllEntries|QDir::NoDotAndDotDot|QDir::Hidden))
+ walkFoldersIf(sub, f, t);
+ }
+ }
+ if (ret >= 0)
+ f(info);
+}
+
+void Control::completeUpdate(const QString &path)
+{
+ delegate("Update Application",[this, path](){
+ QStringList files;
+ QStringList oldFiles;
+ QDir root(QApplication::applicationDirPath());
+ QDir newRoot(path);
+ if (!newRoot.mkpath(newRoot.absolutePath())) return false;
+ walkFoldersIf({root.absolutePath()},[&newRoot, &files, &root, &oldFiles](const QFileInfo &info){
+ QFileInfo dest(newRoot.absoluteFilePath(root.relativeFilePath(info.absoluteFilePath())));
+ files << info.absoluteFilePath();
+ if (dest.exists())
+ walkFoldersIf(dest,[&oldFiles](const QFileInfo &info){
+ oldFiles << info.absoluteFilePath();
+ }, [](const auto&){return 0;});
+
+ }, [&path, &root](const QFileInfo &info){
+ QFileInfo dest(path + "/" + root.relativeFilePath(info.absoluteFilePath()));
+ return !dest.exists() ? 1 : dest.isDir() && info.isDir() && !info.isSymLink() && !dest.isSymLink() ? -1 : 1;
+ });
+ setTotal(files.size() + oldFiles.size());
+ int count = 0;
+ bool success = true;
+ foreach (auto file, oldFiles) {
+ QFileInfo info(file);
+ if (info.isDir() && !info.isSymLink())
+ success &= newRoot.rmdir(file);
+ else
+ success &= newRoot.remove(file);
+ setProgress(++count);
+ }
+ foreach (auto file, files) {
+ success &= root.rename(file, newRoot.absoluteFilePath(root.relativeFilePath(file))) || root.rmdir(file);
+ setProgress(++count);
+ }
+ setTotal(-1);
+ if (success)
+ root.removeRecursively();
+ return success;
+ },[this, &path](bool success){
+ if (success)
+ QApplication::exit(3);
+ else {
+ setStatusMessage(tr("Failed to move files to %1.").arg(path));
+ setStatus(Status::Error);
+ }
+ });
+}
+
void Control::setAddons(QList addons)
{
if (m_addons == addons)
@@ -344,7 +413,10 @@ 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);
+ connect(nam, &QNetworkAccessManager::finished, [](auto reply){
+ QApplication::setApplicationDisplayName(reply->errorString());
+ });
+ 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));
@@ -360,7 +432,7 @@ void Control::checkForUpdates()
void Control::downloadUpdate()
{
#ifdef GAM_BUILD_NAME
- QFile *zip = new QFile("GitAddonsManager.zip");
+ QFile *zip = new QFile(QApplication::applicationDirPath() + "/GitAddonsManager.zip");
if (!zip->open(QFile::WriteOnly)) {
setUpdateStatus(UpdateStatus::UpdateError);
return;
@@ -368,7 +440,7 @@ void Control::downloadUpdate()
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);
+ auto reply = nam->get(req);
setUpdateStatus(UpdateStatus::DownloadingUpdate);
connect(reply, &QNetworkReply::readyRead,[reply, zip]() {
zip->write(reply->readAll());
@@ -388,8 +460,36 @@ void Control::downloadUpdate()
void Control::executeUpdate()
{
- QDesktopServices::openUrl(QDir().absolutePath());
- QApplication::exit(2);
+ delegate("Apply Update", [this](){
+ QuaZip zip("GitAddonsManager.zip");
+ if (!zip.open(QuaZip::mdUnzip))
+ return;
+ QDir root(QApplication::applicationDirPath());
+ unsigned int size = 0;
+ foreach (const QuaZipFileInfo &info, zip.getFileInfoList())
+ size += info.uncompressedSize;
+ setTotal(size);
+ size = 0;
+ foreach (const QuaZipFileInfo &info, zip.getFileInfoList()) {
+ QuaZipFile z(zip.getZipName(), info.name);
+ z.open(QuaZipFile::ReadOnly);
+ QFileInfo finfo(root.absolutePath() + "/" + info.name);
+ QFile f(finfo.absoluteFilePath());
+ root.mkpath(finfo.absolutePath());
+ f.open(QFile::WriteOnly);
+ QByteArray chunk;
+ while (!(chunk = z.read(32*1024)).isEmpty()) {
+ f.write(chunk);
+ size += chunk.size();
+ setProgress(size);
+ }
+ f.close();
+ }
+
+ },[this](){
+ setUpdateStatus(UpdateStatus::UpdateDone);
+ exit(2);
+ });
}
void Control::setUpdateStatus(Control::UpdateStatus updateStatus)
diff --git a/control.h b/control.h
index 4e78941..d4dc824 100644
--- a/control.h
+++ b/control.h
@@ -69,7 +69,8 @@ public:
UpdateAvailable,
DownloadingUpdate,
UpdateReady,
- CheckingForUpdate
+ CheckingForUpdate,
+ UpdateDone
};
Q_ENUM(UpdateStatus)
Q_PROPERTY(UpdateStatus updateStatus READ updateStatus WRITE setUpdateStatus NOTIFY updateStatusChanged)
@@ -97,6 +98,10 @@ public:
UpdateStatus updateStatus() const;
+ void completeUpdate(const QString &path);
+
+ void init();
+
private:
static Control *m_instance;
explicit Control(QObject *parent = nullptr);
diff --git a/main.cpp b/main.cpp
index 07f9fa1..e6ebc14 100644
--- a/main.cpp
+++ b/main.cpp
@@ -25,49 +25,67 @@
#include
#include
#include
+#include
int main(int argc, char *argv[])
{
- int res;
-
- qmlClearTypeRegistrations();
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication app(argc, argv);
+
+
+ QCommandLineParser parser;
+ parser.addOption({"update", "directory to update", "updateLocation"});
+ parser.process(app);
+ QString update = parser.value("update");
app.setApplicationDisplayName(QObject::tr("Git Addons Manager"));
QCoreApplication::setOrganizationName("GitAddonsManager");
QCoreApplication::setApplicationName("Git Addons Manager");
-
QFontDatabase::addApplicationFont(":/fonts/Hack-Bold.ttf");
QFontDatabase::addApplicationFont(":/fonts/Hack-BoldItalic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Hack-Italic.ttf");
QFontDatabase::addApplicationFont(":/fonts/Hack-Regular.ttf");
QIcon::setThemeName("breeze");
- QQmlApplicationEngine engine;
- bool ok;
- QSettings setts;
- QStringList styles = QQuickStyle::availableStyles();
- QString style = setts.value("style").toString();
- if (style.isNull())
- style = QInputDialog::getItem(nullptr, QObject::tr("Choose a style"), QObject::tr("You will be able to pick another style later by visiting the Options tab."), styles, styles.indexOf(QQuickStyle::name()), false, &ok);
- QQuickStyle::setStyle(style);
- if (ok) {
- setts.setValue("style", style);
- setts.sync();
- }
- qmlRegisterSingletonType("GitAddonsManager.engine",1,0,"Engine",[](QQmlEngine *, QJSEngine *)->QObject*{
- return Control::instance();
- });
- qmlRegisterUncreatableType("GitAddonsManager.engine",1,0,"Addon","");
- engine.rootContext()->setContextProperty("gitVersion", GIT_DESCRIBE);
- engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
- if (engine.rootObjects().isEmpty())
- return -1;
- QObject::connect(Control::instance(), &Control::styleChanged,[&setts](const QString &style){
- setts.setValue("style", style);
- });
+ int res;
+ do {
+ qmlClearTypeRegistrations();
- res = app.exec();
- if (res == 1)
- QProcess().startDetached(app.arguments()[0],app.arguments().mid(1));
+ QQmlApplicationEngine engine;
+ bool ok;
+ QSettings setts;
+ QStringList styles = QQuickStyle::availableStyles();
+ QString style = setts.value("style").toString();
+ if (style.isNull())
+ style = QInputDialog::getItem(nullptr, QObject::tr("Choose a style"), QObject::tr("You will be able to pick another style later by visiting the Options tab."), styles, styles.indexOf(QQuickStyle::name()), false, &ok);
+ QQuickStyle::setStyle(style);
+ if (ok) {
+ setts.setValue("style", style);
+ setts.sync();
+ }
+ qmlRegisterSingletonType("GitAddonsManager.engine",1,0,"Engine",[](QQmlEngine *, QJSEngine *)->QObject*{
+ return Control::instance();
+ });
+ if (!update.isEmpty()) {
+ Control::instance()->completeUpdate(update);
+ engine.load(QUrl(QStringLiteral("qrc:/Update.qml")));
+ } else {
+ Control::instance()->init();
+ qmlRegisterUncreatableType("GitAddonsManager.engine",1,0,"Addon","");
+ engine.rootContext()->setContextProperty("gitVersion", GIT_DESCRIBE);
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ }
+ if (engine.rootObjects().isEmpty())
+ return -1;
+ QObject::connect(Control::instance(), &Control::styleChanged,[&setts](const QString &style){
+ setts.setValue("style", style);
+ });
+ res = app.exec();
+ } while (res == 1);
+ if (res == 2) {
+ QStringList args = app.arguments().mid(1);
+ args << "--update" << QString("\"%1\"").arg(app.applicationDirPath());
+ QProcess().startDetached(app.applicationDirPath()+"/GitAddonsManager/GitAddonsManager", args);
+ }
+ if (res == 3)
+ QProcess().startDetached(update + "/GitAddonsManager", QApplication::arguments().mid(1) << "--update" << "");
return res;
}
diff --git a/qml.qrc b/qml.qrc
index c8b2577..a14a573 100644
--- a/qml.qrc
+++ b/qml.qrc
@@ -25,5 +25,6 @@
fonts/Hack-BoldItalic.ttf
fonts/Hack-Italic.ttf
fonts/Hack-Regular.ttf
+ Update.qml