Commit 061a826e authored by Leander Schulten's avatar Leander Schulten
Browse files

Add updater, does not run in IDE. Checks for new version and download if...

Add updater, does not run in IDE. Checks for new version and download if exists. when exiting run update script
parent 39e4c62f
Pipeline #143968 passed with stage
in 2 minutes and 52 seconds
......@@ -47,6 +47,7 @@ SOURCES += \
test/testloopprogramm.cpp \
settings.cpp \
test/DriverDummy.cpp \
updater.cpp \
usermanagment.cpp \
modules/modulemanager.cpp \
modules/programblock.cpp \
......@@ -76,7 +77,8 @@ SOURCES += \
spotify/segmentobject.cpp \
spotify/audioanalysisobject.cpp \
spotify/userobject.cpp \
sortedmodelview.cpp
sortedmodelview.cpp \
zip.cpp
# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
......@@ -104,6 +106,7 @@ HEADERS += \
modules/controlpoint.hpp \
modules/scanner.hpp \
scanner.h \
updater.h \
usermanagment.h \
gui/channelprogrammeditor.h \
modelmanager.h \
......@@ -165,7 +168,8 @@ HEADERS += \
spotify/util.h \
modules/spotifyobjetcs.hpp \
modules/spotify.hpp \
sortedmodelview.h
sortedmodelview.h \
zip.h
# Default rules for deployment.
......
......@@ -44,9 +44,15 @@
#include "test/testsampleclass.h"
#include "spotify/spotify.h"
#include "modules/dmxconsumer.h"
#include "updater.h"
int main(int argc, char *argv[])
{
Updater updater;
QObject::connect(&updater,&Updater::needUpdate,[&](){
updater.update();
});
updater.checkForUpdate();
/*Test::TestModulSystem testModulSystem;
testModulSystem.runTest();
return 0;*/
......@@ -171,6 +177,7 @@ int main(int argc, char *argv[])
QFile savePath(settings.getJsonSettingsFilePath());
ApplicationData::saveData(savePath);
Driver::stopAndUnloadDriver();
updater.runUpdateInstaller();
});
settings.connect(&settings,&Settings::driverFilePathChanged,[&](){
Driver::loadAndStartDriver(settings.getDriverFilePath());
......@@ -208,6 +215,7 @@ int main(int argc, char *argv[])
engine.rootContext()->setContextProperty("UserManagment",UserManagment::get());
engine.rootContext()->setContextProperty("Settings",&settings);
engine.rootContext()->setContextProperty("spotify",&spotify);
engine.rootContext()->setContextProperty("updater",&updater);
QQmlEngine::setObjectOwnership(&Driver::dmxValueModel,QQmlEngine::CppOwnership);
engine.rootContext()->setContextProperty("dmxOutputValues",&Driver::dmxValueModel);
engine.load(QUrl(QLatin1String("qrc:/qml/main.qml")));
......
......@@ -27,6 +27,11 @@ ApplicationWindow {
}
}
ToolTip.visible: updater.progress >= 0 && updater.progress <= 100
ToolTip.delay: 0
ToolTip.timeout: 20000
ToolTip.text: updater.progress < 100 ? "Downloading update. Progress : " + updater.progress + "%" : "Downloading update finished. Restart to update."
VerticalTabBar{
id: tabBar
......
#include "updater.h"
#include "zip.h"
#include <QDir>
#include <QFileInfo>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QProcess>
#include <QTemporaryFile>
#include <thread>
Updater::Updater(){
if(!QFile::exists(QDir::currentPath() + "/Lichtsteuerung.exe")){
state = UpdaterState::IDE_ENV;
}
}
void Updater::checkForUpdate(){
if(state == UpdaterState::IDE_ENV){
return;
}
if(!QFile::exists(VERSION_FILE_NAME)){
qDebug() << "version file does not exists in application folder";
state = UpdaterState::UpdateAvailible;
emit needUpdate();
return;
}
auto redirect = http->get(QNetworkRequest(QUrl(versionDownloadURL)));
QObject::connect(redirect,&QNetworkReply::finished,[this,redirect](){
redirect->deleteLater();
auto redirectURL = redirect->header(QNetworkRequest::KnownHeaders::LocationHeader);
if(!redirectURL.isValid()){
qDebug() << "can not redirect version.zip";
return;
}
auto response = http->get(QNetworkRequest(redirectURL.toUrl()));
QObject::connect(response,&QNetworkReply::finished,[this,response](){
std::thread thread([this,response](){
QFile version(QDir::tempPath() + QStringLiteral("/version.zip"));
version.open(QFile::WriteOnly);
version.write(response->readAll());
version.close();
response->deleteLater();
if(!Zip::unzip(QFileInfo(version),QFileInfo(version).absolutePath())){
qDebug() << "not successful when unzipping";
state = UpdaterState::NoUpdateAvailible;
return;
}
if(!QFile::exists(QFileInfo(version).absolutePath() + "/" + VERSION_FILE_NAME)){
qDebug() << "version file does not exists in version.zip";
state = UpdaterState::NoUpdateAvailible;
return;
}
if(QFile(VERSION_FILE_NAME).readAll() != QFile(QFileInfo(version).absolutePath() + "/" + VERSION_FILE_NAME).readAll()){
state = UpdaterState::UpdateAvailible;
emit needUpdate();
}else{
state = UpdaterState::NoUpdateAvailible;
}
});
thread.detach();
});
});
}
void Updater::update(){
if(state != UpdaterState::UpdateAvailible) {
qDebug() << "we are not in a state to make updates";
return;
}
qDebug() << "Update";
state = UpdaterState::DownloadingUpdate;
auto redirect = http->get(QNetworkRequest(QUrl(deployDownloadURL)));
QObject::connect(redirect,&QNetworkReply::finished,[this,redirect](){
redirect->deleteLater();
auto redirectURL = redirect->header(QNetworkRequest::KnownHeaders::LocationHeader);
if(!redirectURL.isValid()){
qDebug() << "can not redirect deploy.zip";
return;
}
auto response = http->get(QNetworkRequest(redirectURL.toUrl()));
QFile * deploy = new QFile(QDir::tempPath() + QStringLiteral("/deploy.zip"));
deploy->open(QFile::WriteOnly);
QObject::connect(response,static_cast<void (QNetworkReply::*)(QNetworkReply::NetworkError)>(&QNetworkReply::error),[this,response,deploy](auto error){
qWarning() << "Error while downloading deploy.zip! " << error << response->errorString();
deploy->close();
deploy->deleteLater();
response->deleteLater();
state = UpdaterState::DownloadUpdateFailed;
});
QObject::connect(response,&QNetworkReply::readyRead,[response,deploy](){
deploy->write(response->readAll());
});
QObject::connect(response,&QNetworkReply::downloadProgress,[this](auto rec, auto max){
progress = 100 * rec / max;
qDebug() << progress;
emit updateProgressChanged();
});
QObject::connect(response,&QNetworkReply::finished,[this,response,deploy](){
std::thread thread([this,response,deploy](){
qDebug() << response->atEnd();
deploy->close();
std::unique_ptr<QFile> deleteMe(deploy);
response->deleteLater();
if(!Zip::unzip(QFileInfo(*deploy),QFileInfo(*deploy).absolutePath())){
qDebug() << "not successful when unzipping deploy.zip";
state = UpdaterState::DownloadUpdateFailed;
return;
}
deployPath = QFileInfo(*deploy).absolutePath() + "/" + NAME_OF_DEPLOY_FOLDER;
// all important files like QTJSONFile.json
auto entries = QDir(QDir::currentPath()).entryInfoList(QStringList() << QStringLiteral("QTJSONFile.json*"),QDir::Filter::Files);
for(const auto & e : entries){
QFile::copy(e.absoluteFilePath() , deployPath + "/" + e.fileName());
}
state = UpdaterState::UpdateDownloaded;
});
thread.detach();
});
});
}
void Updater::runUpdateInstaller(){
if(state != UpdaterState::UpdateDownloaded){
return;
}
QFile batchFile(QDir::tempPath() + "/installLichtsteuerung.bat");
batchFile.open(QFile::WriteOnly);
//https://stackoverflow.com/questions/1894967/how-to-request-administrator-access-inside-a-batch-file
auto content = "@echo off\r\n"
":: BatchGotAdmin\r\n"
":-------------------------------------\r\n"
"REM --> Check for permissions\r\n"
" IF \"%PROCESSOR_ARCHITECTURE%\" EQU \"amd64\" (\r\n"
">nul 2>&1 \"%SYSTEMROOT%\\SysWOW64\\cacls.exe\" \"%SYSTEMROOT%\\SysWOW64\\config\\system\"\r\n"
") ELSE (\r\n"
">nul 2>&1 \"%SYSTEMROOT%\\system32\\cacls.exe\" \"%SYSTEMROOT%\\system32\\config\\system\"\r\n"
")\r\n"
"\r\n"
"REM --> If error flag set, we do not have admin.\r\n"
"if '%errorlevel%' NEQ '0' (\r\n"
" echo Requesting administrative privileges...\r\n"
" goto UACPrompt\r\n"
") else ( goto gotAdmin )\r\n"
"\r\n"
":UACPrompt\r\n"
" echo Set UAC = CreateObject^(\"Shell.Application\"^) > \"%temp%\\getadmin.vbs\"\r\n"
" set params= %*\r\n"
" echo UAC.ShellExecute \"cmd.exe\", \"/c \"\"%~s0\"\" %params:\"=\"\"%\", \"\", \"runas\", 1 >> \"%temp%\\getadmin.vbs\"\r\n"
"\r\n"
" \"%temp%\\getadmin.vbs\"\r\n"
" del \"%temp%\\getadmin.vbs\"\r\n"
" exit /B\r\n"
"\r\n"
":gotAdmin\r\n"
" pushd \"%CD%\"\r\n"
" CD /D \"%~dp0\"\r\n"
":-------------------------------------- \r\n"
": Own Code\r\n"
"RMDIR /s /q \"" + QFileInfo(QDir::currentPath()).absoluteFilePath() + "\"\r\n"
"move \"" + deployPath + "\" \"" + QFileInfo(QDir::currentPath()).absoluteFilePath() + "\"\r\n";
batchFile.write(content.toUtf8());
batchFile.close();
qDebug () << "run " << QFileInfo(batchFile).absoluteFilePath();
QProcess::startDetached(QStringLiteral("cmd"), QStringList() << QStringLiteral("/c") << QFileInfo(batchFile).absoluteFilePath());
}
#ifndef UPDATER_H
#define UPDATER_H
#include <QNetworkAccessManager>
#include <QObject>
#include <QString>
#include <memory>
class Updater : public QObject{
Q_OBJECT
Q_PROPERTY(int progress READ getUpdateProgress NOTIFY updateProgressChanged)
const inline static QString VERSION_FILE_NAME = QStringLiteral("version.txt");
const inline static QString NAME_OF_DEPLOY_FOLDER = QStringLiteral("windows-release-5.12.3");
QString versionDownloadURL = QStringLiteral("https://git.rwth-aachen.de/leander.schulten/Lichtsteuerung/-/jobs/artifacts/windows-release/download?job=version");
QString deployDownloadURL = QStringLiteral("https://git.rwth-aachen.de/leander.schulten/Lichtsteuerung/-/jobs/artifacts/windows-release/download?job=deploy");
std::unique_ptr<QNetworkAccessManager> http = std::make_unique<QNetworkAccessManager>();
enum class UpdaterState {IDE_ENV, NotChecked, NoUpdateAvailible, UpdateAvailible, DownloadingUpdate, UpdateDownloaded, DownloadUpdateFailed} state = UpdaterState::NotChecked;
int progress = -1;
QString deployPath;
public:
Updater();
void checkForUpdate();
UpdaterState getState()const {return state;}
void update();
/**
* @brief runUpdateInstaller starts the installer script, call when the application is closing
*/
void runUpdateInstaller();
int getUpdateProgress()const{return progress;}
signals:
void needUpdate();
void updateProgressChanged();
};
#endif // UPDATER_H
#include "zip.h"
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
bool unzipPowershellNew(const QFileInfo& zip, const QFileInfo& unzip){
// https://www.reddit.com/r/Windows10/comments/71z96c/unzip_from_command_line/
// Expand-Archive "<PathToZIPFile>" "<FolderWhereToExtract>" -Force
QProcess p;
p.start(QStringLiteral("powershell.exe"), QStringList() << QStringLiteral("Expand-Archive") << QStringLiteral("-Force") << "\"" + zip.absoluteFilePath() + "\"" << "\"" + unzip.absoluteFilePath() + "\"");
p.waitForFinished();
if(p.exitCode() != 0){
qDebug() << "Failed to unzip " << zip << " to " << unzip << " with powershell new";
qDebug().noquote() << "stderr : " << p.readAllStandardError();
qDebug().noquote() << "stdout : " << p.readAllStandardOutput();
}
return !p.exitCode();
}
bool unzipPowershell(const QFileInfo& zip, const QFileInfo& unzip){
// from https://stackoverflow.com/questions/17546016/how-can-you-zip-or-unzip-from-the-script-using-only-windows-built-in-capabiliti/26843122#26843122
// powershell.exe -nologo -noprofile -command "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('foo.zip', 'bar'); }"
QProcess p;
p.start(QStringLiteral("powershell.exe"), QStringList() << QStringLiteral("-nologo") << QStringLiteral("-noprofile") << "& { Add-Type -A 'System.IO.Compression.FileSystem'; [IO.Compression.ZipFile]::ExtractToDirectory('"+zip.absoluteFilePath()+"', '"+unzip.absoluteFilePath()+"/unzippedDir'); }");
p.waitForFinished();
if(p.exitCode() != 0){
qDebug() << "Failed to unzip " << zip << " to " << unzip << " with powershell";
qDebug().noquote() << "stderr : " << p.readAllStandardError();
qDebug().noquote() << "stdout : " << p.readAllStandardOutput();
}
return !p.exitCode();
}
bool unzipWinrar(const QFileInfo& zip, const QFileInfo& unzip){
// from https://stackoverflow.com/questions/1315662/how-to-extract-zip-files-with-winrar-command-line
// "%ProgramFiles%\WinRAR\winrar.exe" x -ibck c:\file.zip *.* c:\folder
QProcess p;
p.start(QStringLiteral("C:\\Program Files\\WinRAR\\winrar.exe"), QStringList() << QStringLiteral("x") << QStringLiteral("-ibck") << zip.absoluteFilePath() << QStringLiteral("*.*") << unzip.absoluteFilePath());
p.waitForFinished();
if(p.exitCode() != 0){
qDebug() << "Failed to unzip " << zip << " to " << unzip << " with winrar";
qDebug().noquote() << "stderr : " << p.readAllStandardError();
qDebug().noquote() << "stdout : " << p.readAllStandardOutput();
}
return !p.exitCode();
}
bool unzip7Zip(const QFileInfo& zip, const QFileInfo& unzip){
// from https://superuser.com/questions/95902/7-zip-and-unzipping-from-command-line
// 7z x example.zip -oexample
QProcess p;
p.start(QStringLiteral("C:\\Program Files\\7-Zip\\7z.exe"), QStringList() << QStringLiteral("x") << QStringLiteral("-y") << zip.absoluteFilePath() << "-o" + unzip.absoluteFilePath());
p.waitForFinished();
if(p.exitCode() != 0){
qDebug() << "Failed to unzip " << zip << " to " << unzip << " with 7zip";
qDebug().noquote() << "stderr : " << p.readAllStandardError();
qDebug().noquote() << "stdout : " << p.readAllStandardOutput();
}
return !p.exitCode();
}
bool Zip::unzip(const QFileInfo& zip, const QFileInfo& unzip){
if(!zip.exists()){
return false;
}
QDir().mkpath(unzip.absoluteFilePath());
if(unzip7Zip(zip,unzip)){
return true;
}
if(unzipWinrar(zip,unzip)){
return true;
}
if(unzipPowershellNew(zip,unzip)){
return true;
}
if(unzipPowershell(zip,unzip)){
return true;
}
return false;
}
#ifndef ZIP_H
#define UZIP_H
#include <QFileInfo>
namespace Zip {
bool unzip(const QFileInfo& zip, const QFileInfo& unzip);
} // namespace Zip
#endif // UZIP_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment