enh(cpn): Cloudbuild support - phase 1 (#4856)

This commit is contained in:
Neil Horne
2024-05-28 10:50:02 +10:00
committed by GitHub
parent e033da999c
commit 27f53ff195
51 changed files with 2088 additions and 977 deletions
+187 -54
View File
@@ -20,13 +20,9 @@
*/
#include "updateinterface.h"
#include "repobuild.h"
#include "repogithub.h"
#include "helpers.h"
#include "updatefirmware.h"
#include "updatecompanion.h"
#include "updatesdcard.h"
#include "updatesounds.h"
#include "updatethemes.h"
#include "updatemultiprotocol.h"
#include "minizinterface.h"
#include <QMessageBox>
@@ -34,17 +30,20 @@
#include <QFileInfo>
#include <QRegularExpression>
#include <QValidator>
#include <QEventLoop>
#include <QTimer>
UpdateInterface::UpdateInterface(QWidget * parent, ComponentIdentity id, QString name) :
UpdateInterface::UpdateInterface(QWidget * parent, ComponentIdentity id, QString name, Repo::RepoType repoType,
const QString & path, const QString & nightly, const int resultsPerPage) :
QWidget(parent),
m_id(id),
m_name(name),
m_params(new UpdateParameters(this)),
m_status(new UpdateStatus(this)),
m_network(new UpdateNetwork(this, m_status)),
m_repo(new Repo(this, m_status, m_network))
m_repo(repoType == Repo::REPO_TYPE_GITHUB ? static_cast<Repo*>(new RepoGitHub(this, m_status, m_network, path, nightly, resultsPerPage)) :
static_cast<Repo*>(new RepoBuild(this, m_status, m_network, path, nightly, resultsPerPage)))
{
}
UpdateInterface::~UpdateInterface()
@@ -112,7 +111,37 @@ void UpdateInterface::assetSettingsSave()
}
}
bool UpdateInterface::asyncInstall()
int UpdateInterface::asyncInstall()
{
return true;
}
int UpdateInterface::build()
{
m_status->progressMessage(tr("Building assets"));
if (!buildFlaggedAssets()) {
m_status->reportProgress(tr("Unable to build flagged assets"), QtCriticalMsg);
return false;
}
return true;
}
bool UpdateInterface::buildFlaggedAssets()
{
m_repo->assets()->setFilterFlags(UPDFLG_Build);
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Build)).arg(m_repo->assets()->count()), QtDebugMsg);
for (int i = 0; i < m_repo->assets()->count(); ++i) {
if (!buildFlaggedAsset(i))
return false;
}
return true;
}
bool UpdateInterface::buildFlaggedAsset(const int row)
{
return true;
}
@@ -358,7 +387,7 @@ bool UpdateInterface::copyStructure()
return true;
}
bool UpdateInterface::copyToDestination()
int UpdateInterface::copyToDestination()
{
m_status->progressMessage(tr("Copying to destination"));
@@ -370,6 +399,18 @@ bool UpdateInterface::copyToDestination()
return true;
}
int UpdateInterface::decompress()
{
m_status->progressMessage(tr("Decompressing assets"));
if (!decompressFlaggedAssets()) {
m_status->reportProgress(tr("Unable to decompress flagged assets"), QtDebugMsg);
return false;
}
return true;
}
const QString UpdateInterface::decompressDir() const
{
return m_decompressDir;
@@ -441,16 +482,21 @@ bool UpdateInterface::downloadFlaggedAssets()
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Download)).arg(m_repo->assets()->count()), QtDebugMsg);
for (int i = 0; i < m_repo->assets()->count(); ++i) {
if (!m_repo->assets()->downloadToFile(i, m_downloadDir))
if (!downloadFlaggedAsset(i))
return false;
}
return true;
}
bool UpdateInterface::download()
bool UpdateInterface::downloadFlaggedAsset(const int row)
{
m_status->progressMessage(tr("Downloading assets"));
return m_repo->assets()->downloadToFile(row, m_downloadDir);
}
int UpdateInterface::download()
{
m_status->progressMessage(tr("Downloading..."));
if (!downloadFlaggedAssets()) {
m_status->reportProgress(tr("Unable to download flagged assets"), QtDebugMsg);
@@ -460,18 +506,6 @@ bool UpdateInterface::download()
return true;
}
bool UpdateInterface::decompress()
{
m_status->progressMessage(tr("Decompressing assets"));
if (!decompressFlaggedAssets()) {
m_status->reportProgress(tr("Unable to decompress flagged assets"), QtDebugMsg);
return false;
}
return true;
}
bool UpdateInterface::filterAssets(const UpdateParameters::AssetParams & ap)
{
QString pattern(m_params->buildFilterPattern(ap.filterType, ap.filter));
@@ -504,7 +538,7 @@ bool UpdateInterface::flagAssets()
return true;
}
bool UpdateInterface::housekeeping()
int UpdateInterface::housekeeping()
{
m_status->progressMessage(tr("Housekeeping"));
int cnt = 0;
@@ -554,10 +588,9 @@ const int UpdateInterface::id() const
return (int)m_id;
}
void UpdateInterface::init(QString repoPath, QString nightly, int resultsPerPage)
void UpdateInterface::init()
{
appSettingsInit();
m_repo->init(repoPath, nightly, resultsPerPage);
releaseCurrent();
}
@@ -632,12 +665,20 @@ UpdateNetwork* const UpdateInterface::network() const
return m_network;
}
void UpdateInterface::onStatusCancelled()
{
m_status->setMaximum(0);
m_stopping = true;
emit stop();
m_status->reportProgress(tr("Update cancelled"), QtWarningMsg);
}
UpdateParameters* const UpdateInterface::params() const
{
return m_params;
}
bool UpdateInterface::preparation()
int UpdateInterface::preparation()
{
m_status->progressMessage(tr("Preparing"));
int cnt = 0;
@@ -678,6 +719,12 @@ bool UpdateInterface::preparation()
return true;
}
void UpdateInterface::radioProfileChanged()
{
resetEnvironment();
m_repo->releases()->invalidate();
}
void UpdateInterface::releaseClear()
{
g.component[m_id].releaseClear();
@@ -698,7 +745,7 @@ const QStringList UpdateInterface::releaseList()
return m_repo->releases()->list();
}
bool UpdateInterface::releaseSettingsSave()
int UpdateInterface::releaseSettingsSave()
{
m_status->reportProgress(tr("Save release settings"), QtDebugMsg);
g.component[m_id].release(m_repo->releases()->name());
@@ -760,6 +807,62 @@ bool UpdateInterface::retrieveRepoJsonFile(const QString & filename, QJsonDocume
return m_repo->getJson(filename, json);
}
void UpdateInterface::runAsyncInstall()
{
m_result = asyncInstall();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 start async failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runBuild()
{
m_result = build();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runCopyToDestination()
{
m_result = copyToDestination();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 copy to destination failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runDecompress()
{
m_result = decompress();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 decompress failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runDownload()
{
m_result = download();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 download failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runHousekeeping()
{
m_result = housekeeping();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 housekeeping failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runPreparation()
{
m_result = preparation();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
emit finished();
}
void UpdateInterface::runReleaseSettingsSave()
{
m_result = releaseSettingsSave();
if (m_result == PROC_RESULT_FAIL) m_status->reportProgress(tr("%1 save release settings failed").arg(m_name), QtCriticalMsg);
emit finished();
}
bool UpdateInterface::setFilteredAssets(const UpdateParameters::AssetParams & ap)
{
if (!filterAssets(ap))
@@ -917,51 +1020,79 @@ bool UpdateInterface::update(ProgressWidget * progress)
if (!(m_params->flags & UPDFLG_Update))
return true;
m_result = PROC_RESULT_SUCCESS;
m_stopping = false;
m_status->setProgress(progress);
m_status->setLogLevel(m_params->logLevel);
m_status->setInfo(tr("Processing updates for: %1").arg(m_name));
m_status->setValue(0);
m_status->setMaximum(100);
m_status->reportProgress(tr("Processing updates for: %1").arg(m_name), QtInfoMsg);
// the default behaviour of the dialog is to close on clicking the cancel button
// but need to keep it open to display the current process until it can be interrupted
// and then display close button
status()->keepOpen(true);
if (!preparation()) {
m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
return false;
connect(m_status, &UpdateStatus::cancelled, this, &UpdateInterface::onStatusCancelled);
// need to create a separate thread for the processes so that the cancel request can be handled asap
QEventLoop loop;
// EXTREMELY IMPORTANT: every process within the event loop MUST emit finished() otherwise the loop will not exit
// Note: finished does not indicate the exit status
connect(this, &UpdateInterface::finished, [&]() { if (loop.isRunning()) loop.quit(); });
if (okToRun()) {
// pause before starting next process to allow time for queued events to be processed ie like the cancel request
QTimer::singleShot(100, this, &UpdateInterface::runPreparation);
// NOTE: this will not exit until the finished signal is detected and processed
loop.exec();
}
if (!download()) {
m_status->reportProgress(tr("%1 download failed").arg(m_name), QtCriticalMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runBuild);
loop.exec();
}
if (!decompress()) {
m_status->reportProgress(tr("%1 decompress failed").arg(m_name), QtCriticalMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runDownload);
loop.exec();
}
if (!copyToDestination()) {
m_status->reportProgress(tr("%1 copy to destination failed").arg(m_name), QtCriticalMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runDecompress);
loop.exec();
}
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runCopyToDestination);
loop.exec();
}
// perform before async install in case Companion restarted
if (!releaseSettingsSave()) {
m_status->reportProgress(tr("Failed to save release settings"), QtDebugMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runReleaseSettingsSave);
loop.exec();
}
if (!asyncInstall()) {
m_status->reportProgress(tr("%1 start async failed").arg(m_name), QtCriticalMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runAsyncInstall);
loop.exec();
}
if (!housekeeping()) {
m_status->reportProgress(tr("%1 housekeeping failed").arg(m_name), QtCriticalMsg);
return false;
if (okToRun()) {
QTimer::singleShot(100, this, &UpdateInterface::runHousekeeping);
loop.exec();
}
disconnect(m_status, &UpdateStatus::cancelled, this, &UpdateInterface::onStatusCancelled);
// allow the dialog to be closed by clicking the close button
status()->keepOpen(false);
if (!okToRun())
return false;
m_status->reportProgress(tr("%1 update successful").arg(m_name), QtInfoMsg);
if (!m_status->progress())
@@ -1004,6 +1135,8 @@ const QString UpdateInterface::updateFlagToString(const int flag)
return "Locked";
case UPDFLG_Preparation:
return "Preparation";
case UPDFLG_Build:
return "Build";
case UPDFLG_Download:
return "Download";
case UPDFLG_Decompress: