Files
edgetx-gx12/companion/src/updates/updateinterface.cpp
T
Neil HorneandGitHub fec64a964d fix(cpn): Selection of sound packs in update process (#3848)
* chore(cpn): increase github REST api page size for sound packs

* chore(cpn): add selection mode parameter to chooser dialog

* chore(cpn): remove cli debug messages when progress dialog available

* chore(cpn): carve out filterAssets from setFilteredAssets and call new function

* fix(cpn): refactor update sounds asset filtering

* chore(cpn): move code block

* fix(cpn): remove trailing hyphen from default sounds asset filter
2023-09-07 21:23:02 +10:00

1046 lines
28 KiB
C++

/*
* Copyright (C) EdgeTX
*
* Based on code named
* opentx - https://github.com/opentx/opentx
* th9x - http://code.google.com/p/th9x
* er9x - http://code.google.com/p/er9x
* gruvin9x - http://code.google.com/p/gruvin9x
*
* License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
#include "updateinterface.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>
#include <QFileDialog>
#include <QFileInfo>
#include <QRegularExpression>
#include <QValidator>
UpdateInterface::UpdateInterface(QWidget * parent, ComponentIdentity id, QString name) :
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))
{
}
UpdateInterface::~UpdateInterface()
{
delete m_params;
delete m_repo;
delete m_network;
delete m_status;
}
void UpdateInterface::appSettingsInit()
{
if (!isSettingsIndexValid()) {
m_status->reportProgress(tr("Component id: %1 exceeds maximum application settings components: %2!").arg(m_id).arg(MAX_COMPONENTS), QtCriticalMsg);
return;
}
if (!g.component[m_id].existsOnDisk()) {
g.component[m_id].init();
}
if (!g.component[m_id].asset[0].existsOnDisk())
assetSettingsInit();
}
void UpdateInterface::assetSettingsLoad()
{
if (!isSettingsIndexValid())
return;
m_params->assets.clear();
for (int i = 0; i < MAX_COMPONENT_ASSETS && g.component[m_id].asset[i].existsOnDisk(); i++) {
UpdateParameters::AssetParams &ap = m_params->addAsset();
ComponentAssetData &cad = g.component[m_id].asset[i];
ap.processes = cad.processes();
ap.flags = cad.flags();
ap.filterType = (UpdateParameters::UpdateFilterType)cad.filterType();
ap.filter = cad.filter();
ap.maxExpected = cad.maxExpected();
ap.destSubDir = cad.destSubDir();
ap.copyFilterType = (UpdateParameters::UpdateFilterType)cad.copyFilterType();
ap.copyFilter = cad.copyFilter();
}
}
void UpdateInterface::assetSettingsSave()
{
if (!isSettingsIndexValid())
return;
for (int i = 0; i < MAX_COMPONENT_ASSETS && g.component[m_id].asset[i].existsOnDisk(); i++) {
const UpdateParameters::AssetParams &ap = m_params->assets.at(i);
ComponentAssetData &cad = g.component[m_id].asset[i];
// DO NOT overwrite cad.processes
cad.flags(ap.flags);
cad.filterType(ap.filterType);
cad.filter(ap.filter);
cad.maxExpected(ap.maxExpected);
cad.destSubDir(ap.destSubDir);
cad.copyFilterType(ap.copyFilterType);
cad.copyFilter(ap.copyFilter);
}
}
bool UpdateInterface::asyncInstall()
{
return true;
}
bool UpdateInterface::checkCreateDirectory(const QString & dir, const UpdateFlags flag)
{
if (m_params->flags & flag) {
if (dir.isEmpty()) {
m_status->reportProgress(tr("%1 directory not configured in application settings!").arg(updateFlagToString(flag)), QtCriticalMsg);
return false;
}
else if (!QDir().mkpath(dir)) {
m_status->reportProgress(tr("Failed to create %1 directory %2!").arg(updateFlagToString(flag)).arg(dir), QtCriticalMsg);
return false;
}
}
return true;
}
bool UpdateInterface::copyAsset()
{
if (m_repo->assets()->flags() & UPDFLG_CopyStructure)
return copyStructure();
else if (m_repo->assets()->flags() & UPDFLG_CopyFiles)
return copyFiles();
return true;
}
bool UpdateInterface::copyFiles()
{
//m_status->reportProgress(tr("Copy files"), QtDebugMsg);
m_status->setValue(0);
m_status->setMaximum(100);
QString srcPath;
if (m_repo->assets()->flags() & UPDFLG_Decompress)
srcPath = QString("%1/A%2/%3").arg(m_decompressDir).arg(m_repo->assets()->id()).arg(QFileInfo(m_repo->assets()->name()).completeBaseName());
else if (m_repo->assets()->flags() & UPDFLG_Download)
srcPath = QString("%1/A%2").arg(m_downloadDir).arg(m_repo->assets()->id());
else {
m_status->reportProgress(tr("Unable to determine source directory for asset %1").arg(m_repo->assets()->name()), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Copy files from %1").arg(srcPath), QtDebugMsg);
QString destPath = m_updateDir;
if (!m_repo->assets()->subDirectory().isEmpty())
destPath.append("/" % m_repo->assets()->subDirectory());
if (!QDir().mkpath(destPath)) {
m_status->reportProgress(tr("Failed to create directory %1").arg(QDir::toNativeSeparators(destPath)), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Check/create directory: %1").arg(destPath), QtDebugMsg);
m_status->reportProgress(tr("Directories checked/created: %1").arg(1), QtDebugMsg);
QRegularExpression filter(m_repo->assets()->copyFilter(), QRegularExpression::CaseInsensitiveOption);
m_status->reportProgress(tr("Copy filter pattern: %1").arg(filter.pattern()), QtDebugMsg);
QDirIterator itcnt(srcPath, QDir::Files, QDirIterator::Subdirectories);
int cnt = 0;
//m_status->reportProgress(tr("Calculating number of files"), QtDebugMsg);
while (itcnt.hasNext())
{
QFileInfo src(itcnt.next());
if ((!filter.pattern().isEmpty()) && (!src.fileName().contains(filter)))
continue;
cnt++;
}
m_status->setMaximum(cnt);
QDirIterator itfiles(srcPath, QDir::Files, QDirIterator::Subdirectories);
cnt = 0;
while (itfiles.hasNext())
{
QFileInfo src(itfiles.next());
if ((!filter.pattern().isEmpty()) && (!src.fileName().contains(filter)))
continue;
QFile dest(destPath % "/" % src.fileName());
if (dest.exists()) {
if (!dest.remove()) {
m_status->reportProgress(tr("Failed to delete existing file %1").arg(dest.fileName()), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Deleted file: %1").arg(dest.fileName()), QtDebugMsg);
}
if (!QFile::copy(src.absoluteFilePath(), dest.fileName())) {
m_status->reportProgress(tr("Failed to copy file %1").arg(src.absoluteFilePath()), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Copied %1 to %2").arg(src.fileName()).arg(dest.fileName()), QtDebugMsg);
cnt++;
m_status->setValue(cnt);
}
if (!cnt) {
m_status->reportProgress(tr("No downloaded or decompressed files matched filter '%1'").arg(m_repo->assets()->copyFilter()), QtCriticalMsg);
return false;
}
m_status->setValue(m_status->maximum());
m_status->reportProgress(tr("Files copied: %1").arg(cnt), QtInfoMsg);
return true;
}
bool UpdateInterface::copyFlaggedAssets()
{
m_repo->assets()->setFilterFlags(UPDFLG_CopyDest);
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_CopyDest)).arg(m_repo->assets()->count()), QtDebugMsg);
for (int i = 0; i < m_repo->assets()->count(); ++i) {
m_repo->assets()->getSetId(i);
if (!copyAsset())
return false;
}
return true;
}
bool UpdateInterface::copyStructure()
{
m_status->reportProgress(tr("Copy directory structure"), QtDebugMsg);
m_status->setValue(0);
m_status->setMaximum(100);
QDir srcPath(QString("%1/A%2/%3").arg(m_decompressDir).arg(m_repo->assets()->id()).arg(QFileInfo(m_repo->assets()->name()).completeBaseName()));
if (!srcPath.exists()) {
m_status->reportProgress(tr("Decompressed file structure not found at %1").arg(QDir::toNativeSeparators(srcPath.path())), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Copy file structure from: %1").arg(QDir::toNativeSeparators(srcPath.path())), QtDebugMsg);
QString baseDir = m_updateDir;
if (!m_repo->assets()->subDirectory().isEmpty())
baseDir.append("/" % m_repo->assets()->subDirectory());
// create directory structure first as there is no order to QDirIterator if both files and directories selected
// also supports creation of empty directories
QDirIterator itdirs(srcPath.path(), QDir::AllDirs | QDir::NoDot | QDir::NoDotDot, QDirIterator::Subdirectories);
int cnt = 0;
while (itdirs.hasNext())
{
QFileInfo src(itdirs.next());
QString subPath(src.absoluteFilePath());
subPath.replace(srcPath.path(), "");
QString dir = baseDir % subPath;
if (!QDir().mkpath(dir)) {
m_status->reportProgress(tr("Failed to create directory %1").arg(dir), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Check/create directory: %1").arg(dir), QtDebugMsg);
cnt++;
}
m_status->reportProgress(tr("Directories checked/created: %1").arg(cnt), QtInfoMsg);
QRegularExpression filter(m_repo->assets()->copyFilter(), QRegularExpression::CaseInsensitiveOption);
//m_status->reportProgress(tr("Copy filter pattern: %1").arg(filter.pattern()), QtDebugMsg);
QDirIterator itcnt(srcPath.path(), QDir::Files, QDirIterator::Subdirectories);
cnt = 0;
//m_status->reportProgress(tr("Calculating number of files"), QtDebugMsg);
while (itcnt.hasNext())
{
QFileInfo src(itcnt.next());
if ((!filter.pattern().isEmpty()) && (!src.fileName().contains(filter)))
continue;
cnt++;
}
m_status->setMaximum(cnt);
QDirIterator itfiles(srcPath.path(), QDir::Files, QDirIterator::Subdirectories);
cnt = 0;
while (itfiles.hasNext())
{
QFileInfo src(itfiles.next());
if ((!filter.pattern().isEmpty()) && (!src.fileName().contains(filter)))
continue;
QString subPath(src.absoluteFilePath());
subPath.replace(srcPath.path(), "");
QFile dest(baseDir % subPath);
if (dest.exists()) {
if (!dest.remove()) {
m_status->reportProgress(tr("Failed to delete existing file %1").arg(dest.fileName()), QtCriticalMsg);
return false;
}
}
if (!QFile::copy(src.absoluteFilePath(), dest.fileName())) {
m_status->reportProgress(tr("Failed to copy file %1").arg(src.absoluteFilePath()), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("Copied %1 to %2").arg(src.fileName()).arg(dest.fileName()), QtDebugMsg);
cnt++;
m_status->setValue(cnt);
}
m_status->setValue(m_status->maximum());
m_status->reportProgress(tr("Files copied: %1").arg(cnt), QtInfoMsg);
return true;
}
bool UpdateInterface::copyToDestination()
{
m_status->progressMessage(tr("Copying to destination"));
if (!copyFlaggedAssets()) {
m_status->reportProgress(tr("Unable to copy assets"), QtDebugMsg);
return false;
}
return true;
}
const QString UpdateInterface::decompressDir() const
{
return m_decompressDir;
}
bool UpdateInterface::decompressFlaggedAssets()
{
m_repo->assets()->setFilterFlags(UPDFLG_Decompress);
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(updateFlagToString(UPDFLG_Decompress)).arg(m_repo->assets()->count()), QtDebugMsg);
for (int i = 0; i < m_repo->assets()->count(); ++i) {
if (!decompressAsset(i))
return false;
}
return true;
}
bool UpdateInterface::decompressAsset(int row)
{
m_repo->assets()->getSetId(row);
if (!(m_repo->assets()->flags() & UPDFLG_Decompress))
return true;
QString filename = m_repo->assets()->name();
if (filename.isEmpty())
return false;
QFileInfo f(QString("%1/A%2/%3").arg(m_downloadDir).arg(m_repo->assets()->id()).arg(filename));
if (!f.exists())
return false;
m_status->progressMessage(tr("Decompressing %1").arg(filename));
m_status->reportProgress(tr("Decompress: %1").arg(filename), QtInfoMsg);
return decompressArchive(f.absoluteFilePath(), QString("%1/A%2").arg(m_decompressDir).arg(m_repo->assets()->id()));
}
bool UpdateInterface::decompressArchive(const QString & archivePath, const QString & destDir)
{
QString dest = destDir;
if (!dest.endsWith("/"))
dest.append("/");
dest.append(QFileInfo(archivePath).completeBaseName());
MinizInterface mIface(m_status->progress(), MinizInterface::PCM_SIZE, m_params->logLevel);
if (!mIface.unzipArchiveToPath(archivePath, dest)) {
m_status->reportProgress(tr("Failed to decompress %1").arg(archivePath), QtCriticalMsg);
return false;
}
return true;
}
const QString UpdateInterface::downloadDir() const
{
return m_downloadDir;
}
bool UpdateInterface::downloadFlaggedAssets()
{
m_repo->assets()->setFilterFlags(UPDFLG_Download);
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))
return false;
}
return true;
}
bool UpdateInterface::download()
{
m_status->progressMessage(tr("Downloading assets"));
if (!downloadFlaggedAssets()) {
m_status->reportProgress(tr("Unable to download flagged assets"), QtDebugMsg);
return false;
}
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));
m_repo->assets()->setFilterPattern(pattern);
m_status->reportProgress(tr("Asset filter applied: %1 - %2 found").arg(pattern).arg(m_repo->assets()->count()), QtDebugMsg);
if (m_repo->assets()->count() < 1) {
m_status->reportProgress(tr("No assets found in release '%1' using filter '%2'").arg(m_repo->releases()->name()).arg(pattern), QtCriticalMsg);
return false;
}
else if (ap.maxExpected > 0 && m_repo->assets()->count() > ap.maxExpected) {
m_status->reportProgress(tr("%1 assets found when %2 expected in release '%3' using filter '%4'")
.arg(m_repo->assets()->count() + 1).arg(ap.maxExpected).arg(m_repo->releases()->name().arg(pattern)), QtCriticalMsg);
return false;
}
return true;
}
bool UpdateInterface::flagAssets()
{
m_status->progressMessage(tr("Flagging assets"));
for (int i = 0; i < m_params->assets.size(); i++) {
const UpdateParameters::AssetParams & ap = m_params->assets.at(i);
if (!setFilteredAssets(ap))
return false;
}
return true;
}
bool UpdateInterface::housekeeping()
{
m_status->progressMessage(tr("Housekeeping"));
int cnt = 0;
m_status->setValue(cnt);
m_status->setMaximum(2);
m_status->setValue(++cnt);
g.lastUpdateDir(m_params->updateDir); // used by sdsync
if (m_params->flags & UPDFLG_DelDownloads) {
m_status->reportProgress(tr("Delete download directory: %1").arg(m_downloadDir), QtDebugMsg);
QDir d(m_downloadDir);
if (!d.removeRecursively())
m_status->reportProgress(tr("Failed to delete downloads folder %1").arg(m_downloadDir), QtCriticalMsg);
}
m_status->setValue(++cnt);
if (m_params->flags & UPDFLG_DelDecompress) {
if (!m_params->decompressDirUseDwnld) {
m_status->reportProgress(tr("Delete decompress directory: %1").arg(m_decompressDir), QtDebugMsg);
QDir d(m_decompressDir);
if (!d.removeRecursively())
m_status->reportProgress(tr("Failed to delete decompress folder %1").arg(m_decompressDir), QtCriticalMsg);
}
else if (!(m_params->flags & UPDFLG_DelDownloads)) {
m_repo->assets()->setFilterFlags(UPDFLG_Decompress);
for (int i = 0; i < m_repo->assets()->count(); i++) {
m_repo->assets()->getSetId(i);
QString path = QString("%1/A%2/%3").arg(m_decompressDir).arg(m_repo->assets()->id()).arg(QFileInfo(m_repo->assets()->name()).completeBaseName());
m_status->reportProgress(tr("Delete decompress folder: %1").arg(path), QtDebugMsg);
if (!QDir(path).removeRecursively())
m_status->reportProgress(tr("Failed to delete decompress folder %1").arg(path), QtCriticalMsg);
}
}
}
m_status->setValue(++cnt);
return true;
}
const int UpdateInterface::id() const
{
return (int)m_id;
}
void UpdateInterface::init(QString repoPath, QString nightly, int resultsPerPage)
{
appSettingsInit();
m_repo->init(repoPath, nightly, resultsPerPage);
releaseCurrent();
}
const bool UpdateInterface::isReleaseLatest()
{
if (!m_repo->releases()->retrieveMetaDataAll())
return false;
// release metadata and variables are cached so ensure referencing latest release for channel
m_repo->releases()->getSetId();
// nightlies often have the same version so also check id
if (isVersionLatest(versionCurrent(), m_repo->releases()->version()) &&
g.component[m_id].releaseId() == m_repo->releases()->id())
return true;
return false;
}
const bool UpdateInterface::isSettingsIndexValid() const
{
return (int)m_id > -1 && (int)m_id < MAX_COMPONENTS;
}
const bool UpdateInterface::isUpdateAvailable()
{
if (g.component[m_id].checkForUpdate())
return !isReleaseLatest();
else {
return false;
}
}
const bool UpdateInterface::isVersionLatest(const QString & installed, const QString & latest)
{
QStringList a = versionToStringList(installed);
QStringList b = versionToStringList(latest);
// not equal comparision used as version identifiers are inconsistent eg release vs nightly vs older
for (int i = 0; i < 4; i++) {
if (a.at(i) != b.at(i)) {
return false;
}
}
return true;
}
const bool UpdateInterface::isUpdateable() const
{
if (!isSettingsIndexValid())
return false;
return g.component[m_id].checkForUpdate();
}
const QString UpdateInterface::releaseLatest()
{
if (!m_repo->releases()->retrieveMetaDataAll())
return tr("unknown");
return m_repo->releases()->name();
}
const QString UpdateInterface::name() const
{
return m_name;
}
UpdateNetwork* const UpdateInterface::network() const
{
return m_network;
}
UpdateParameters* const UpdateInterface::params() const
{
return m_params;
}
bool UpdateInterface::preparation()
{
m_status->progressMessage(tr("Preparing"));
int cnt = 0;
m_status->setValue(cnt);
m_status->setMaximum(5);
if (!setRunFolders()) {
m_status->reportProgress(tr("Set run folders failed"), QtDebugMsg);
return false;
}
m_status->setValue(++cnt);
if (!m_repo->releases()->retrieveMetaDataAll()) {
return false;
}
m_status->setValue(++cnt);
if (!m_repo->releases()->getSetId(m_params->releaseUpdate)) {
m_status->reportProgress(tr("Set release id from update release '%1' failed").arg(m_params->releaseUpdate), QtCriticalMsg);
return false;
}
m_status->setValue(++cnt);
if (!m_repo->assets()->retrieveMetaDataAll())
return false;
m_status->setValue(++cnt);
if (!flagAssets())
return false;
m_status->setValue(++cnt);
return true;
}
void UpdateInterface::releaseClear()
{
g.component[m_id].releaseClear();
releaseCurrent();
}
const QString UpdateInterface::releaseCurrent()
{
m_params->releaseCurrent = g.component[m_id].release();
return m_params->releaseCurrent;
}
const QStringList UpdateInterface::releaseList()
{
if (!m_repo->releases()->retrieveMetaDataAll())
return QStringList();
return m_repo->releases()->list();
}
bool UpdateInterface::releaseSettingsSave()
{
m_status->reportProgress(tr("Save release settings"), QtDebugMsg);
g.component[m_id].release(m_repo->releases()->name());
g.component[m_id].version(m_repo->releases()->version());
g.component[m_id].releaseId(m_repo->releases()->id());
g.component[m_id].date(m_repo->releases()->date());
return true;
}
const QString UpdateInterface::releaseUpdate()
{
if (m_params->releaseUpdate.isEmpty())
m_params->releaseUpdate = releaseLatest();
return m_params->releaseUpdate;
}
Repo* const UpdateInterface::repo() const
{
return m_repo;
}
void UpdateInterface::resetEnvironment()
{
// reset from previous run if any
m_params->flags &= ~UPDFLG_Update;
m_params->logLevel = g.updLogLevel();
m_status->setProgress(nullptr);
m_status->setLogLevel(m_params->logLevel);
setReleaseChannel(g.component[m_id].releaseChannel());
m_params->releaseUpdate = "";
setFirmwareFlavour();
setLanguage();
assetSettingsLoad();
setParamFolders();
if (g.updDelDownloads())
m_params->flags |= UpdateInterface::UPDFLG_DelDownloads;
else
m_params->flags &= ~UpdateInterface::UPDFLG_DelDownloads;
if (g.updDelDecompress())
m_params->flags |= UpdateInterface::UPDFLG_DelDecompress;
else
m_params->flags &= ~UpdateInterface::UPDFLG_DelDecompress;
}
bool UpdateInterface::retrieveAssetsJsonFile(const QString & assetName, QJsonDocument * json)
{
m_repo->assets()->setFilterPattern(assetName);
return m_repo->assets()->getJson(assetName, json);
}
bool UpdateInterface::retrieveRepoJsonFile(const QString & filename, QJsonDocument * json)
{
return m_repo->getJson(filename, json);
}
bool UpdateInterface::setFilteredAssets(const UpdateParameters::AssetParams & ap)
{
if (!filterAssets(ap))
return false;
for (int i = 0; i < m_repo->assets()->count(); i++) {
m_repo->assets()->getSetId(i);
if (!m_repo->assets()->setFlags(ap.flags)) {
m_status->reportProgress(tr("Unable to set processing flags for asset %1").arg(m_repo->assets()->name()), QtCriticalMsg);
return false;
}
if (!m_repo->assets()->setSubDirectory(ap.destSubDir)) {
m_status->reportProgress(tr("Unable to set sub directory for asset %1").arg(m_repo->assets()->name()), QtCriticalMsg);
return false;
}
if (!m_repo->assets()->setCopyFilter(m_params->buildFilterPattern(ap.copyFilterType, ap.copyFilter))) {
m_status->reportProgress(tr("Unable to set copy filter for asset %1").arg(m_repo->assets()->name()), QtCriticalMsg);
return false;
}
}
return true;
}
void UpdateInterface::setFirmwareFlavour()
{
m_params->fwFlavour = getCurrentFirmware()->getDownloadId();
}
void UpdateInterface::setLanguage()
{
const Firmware * baseFw = getCurrentFirmware()->getFirmwareBase();
const QStringList currVariant = getCurrentFirmware()->getId().split('-');
m_params->language = "";
for (const char *lang : baseFw->languageList()) {
if (currVariant.last() == lang) {
m_params->language = currVariant.last();
break;
}
}
}
void UpdateInterface::setParamFolders()
{
if (g.downloadDir().trimmed().isEmpty())
g.downloadDirReset(true);
m_params->downloadDir = g.downloadDir().trimmed();
m_params->decompressDirUseDwnld = g.decompressDirUseDwnld();
if (m_params->decompressDirUseDwnld)
m_params->decompressDir = m_params->downloadDir;
else {
if (g.decompressDir().trimmed().isEmpty())
g.decompressDirReset(true);
m_params->decompressDir = g.decompressDir().trimmed();
}
if (g.currentProfile().sdPath().trimmed().isEmpty())
m_params->updateDirUseSD = false;
else
m_params->updateDirUseSD = g.updateDirUseSD();
if (m_params->updateDirUseSD) {
m_params->sdDir = g.currentProfile().sdPath().trimmed();
m_params->updateDir = m_params->sdDir;
}
else {
if (g.updateDir().trimmed().isEmpty())
g.updateDirReset(true);
m_params->updateDir = g.updateDir().trimmed();
}
}
void UpdateInterface::setReleaseChannel(const int channel)
{
m_params->releaseChannel = channel;
m_repo->releases()->setChannel(channel);
}
void UpdateInterface::setReleaseId(QString name)
{
m_repo->releases()->getSetId(name);
}
bool UpdateInterface::setRunFolders()
{
QRegularExpression rx("[0-9a-zA-Z_\\-.]+");
// the validator treats the regexp as "^[0-9a-zA-Z_\-.]+$"
QRegularExpressionValidator v(rx);
int pos = 0;
QString fldr(m_repo->releases()->name().trimmed());
if (v.validate(fldr, pos) != QValidator::Acceptable) {
fldr.replace("\"", "");
fldr.replace("'", "");
fldr.replace("(", "_");
fldr.replace(")", "_");
fldr.replace("[", "_");
fldr.replace("]", "_");
fldr.replace(" ", "_");
fldr.replace("__", "_");
if (v.validate(fldr, pos) != QValidator::Acceptable) {
//m_status->reportProgress(tr("Unable to use release name %1 for directory name using default %2")
// .arg(m_repo->releases()->name().trimmed()).arg(QString("R%1").arg(m_repo->releases()->id())), QtDebugMsg);
fldr = QString("R%1").arg(m_repo->releases()->id());
}
}
m_downloadDir = QString("%1/%2/%3").arg(m_params->downloadDir).arg(m_name).arg(fldr);
if (!checkCreateDirectory(m_downloadDir, UPDFLG_Download))
return false;
//m_status->reportProgress(tr("Download directory: %1").arg(m_downloadDir), QtDebugMsg);
m_decompressDir = QString("%1/%2/%3").arg(m_params->decompressDir).arg(m_name).arg(fldr);
if (!checkCreateDirectory(m_decompressDir, UPDFLG_Decompress))
return false;
//m_status->reportProgress(tr("Decompress directory: %1").arg(m_decompressDir), QtDebugMsg);
m_updateDir = m_params->updateDir;
if (!checkCreateDirectory(m_updateDir, UPDFLG_CopyDest))
return false;
//m_status->reportProgress(tr("Update directory: %1").arg(m_updateDir), QtDebugMsg);
return true;
}
void UpdateInterface::setRunUpdate()
{
m_params->flags |= UPDFLG_Update;
}
UpdateStatus* const UpdateInterface::status() const
{
return m_status;
}
bool UpdateInterface::update(ProgressWidget * progress)
{
if (!(m_params->flags & UPDFLG_Update))
return true;
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);
if (!preparation()) {
m_status->reportProgress(tr("%1 preparation failed").arg(m_name), QtCriticalMsg);
return false;
}
if (!download()) {
m_status->reportProgress(tr("%1 download failed").arg(m_name), QtCriticalMsg);
return false;
}
if (!decompress()) {
m_status->reportProgress(tr("%1 decompress failed").arg(m_name), QtCriticalMsg);
return false;
}
if (!copyToDestination()) {
m_status->reportProgress(tr("%1 copy to destination failed").arg(m_name), QtCriticalMsg);
return false;
}
// perform before async install in case Companion restarted
if (!releaseSettingsSave()) {
m_status->reportProgress(tr("Failed to save release settings"), QtDebugMsg);
return false;
}
if (!asyncInstall()) {
m_status->reportProgress(tr("%1 start async failed").arg(m_name), QtCriticalMsg);
return false;
}
if (!housekeeping()) {
m_status->reportProgress(tr("%1 housekeeping failed").arg(m_name), QtCriticalMsg);
return false;
}
m_status->reportProgress(tr("%1 update successful").arg(m_name), QtInfoMsg);
if (!m_status->progress())
QMessageBox::information(m_status->progress(), CPN_STR_APP_NAME, tr("%1 update successful").arg(m_name));
return true;
}
const QString UpdateInterface::updateDir() const
{
return m_updateDir;
}
// static
const QString UpdateInterface::updateFlagsToString(const int flags)
{
QString str;
for (int i = 0; i < 32; i++) {
int flag = flags & (1 << i);
if (flag) {
if (!str.isEmpty())
str.append(";");
str.append(updateFlagToString(flag));
}
}
return str;
}
// static
const QString UpdateInterface::updateFlagToString(const int flag)
{
switch (flag) {
case UPDFLG_None:
return "None";
case UPDFLG_Update:
return "Update";
case UPDFLG_Locked:
return "Locked";
case UPDFLG_Preparation:
return "Preparation";
case UPDFLG_Download:
return "Download";
case UPDFLG_Decompress:
return "Decompress";
case UPDFLG_CopyDest:
return "Copy to Destination";
case UPDFLG_CopyFiles:
return "Copy Files";
case UPDFLG_CopyStructure:
return "Copy Structure";
case UPDFLG_Housekeeping:
return "Housekeeping";
case UPDFLG_AsyncInstall:
return "Async Install";
case UPDFLG_DelDownloads:
return "Delete Downloads";
case UPDFLG_DelDecompress:
return "Delete Decompress";
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
const QString UpdateInterface::versionCurrent()
{
return g.component[m_id].version();
}
// static
QStringList UpdateInterface::versionToStringList(QString version)
{
QStringList strl = version.split(".");
while (strl.count() < 4) {
strl.append("0");
}
return strl;
}