cpn(fix): Release list order use version when available otherwise use date (#2823)

This commit is contained in:
Neil Horne
2022-12-07 09:37:14 +10:00
committed by GitHub
parent 5d3e37e08c
commit 85c098f11c
6 changed files with 191 additions and 59 deletions
+146 -39
View File
@@ -38,6 +38,7 @@
#include <QLabel>
#include <QMessageBox>
#include <QDir>
#include <QRegularExpression>
using namespace Helpers;
@@ -306,22 +307,22 @@ void Helpers::exportAppSettings(QWidget * dlgParent)
}
unsigned int Helpers::getBitmappedValue(const unsigned int & field, const unsigned int index, const unsigned int numbits, const unsigned int offset)
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
return (field >> (numbits * index + offset)) & (unsigned int)mask;
}
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
return (field >> (numbits * index + offset)) & (unsigned int)mask;
}
void Helpers::setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index, unsigned int numbits, unsigned int offset)
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
void Helpers::setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index, unsigned int numbits, unsigned int offset)
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
unsigned int fieldmask = ((unsigned int)mask << (numbits * index + offset));
field = (field & ~fieldmask) | (value << (numbits * index + offset));
}
unsigned int fieldmask = ((unsigned int)mask << (numbits * index + offset));
field = (field & ~fieldmask) | (value << (numbits * index + offset));
}
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
{
@@ -727,42 +728,131 @@ QString Helpers::removeAccents(const QString & str)
return result;
}
SemanticVersion::SemanticVersion(QString vers)
/*
SemanticVersion
Based on Semantic Versioning 2.0.0 refer https://semver.org/
*/
SemanticVersion::SemanticVersion(const QString vers)
{
fromString(vers);
}
bool SemanticVersion::fromString(QString vers)
{
if (!isValid(vers))
return;
return false;
vers = vers.trimmed();
if (vers.toLower().startsWith("v"))
vers = vers.mid(1);
QStringList strl = vers.split(".");
version.major = strl.at(0).toInt();
version.minor = strl.at(1).toInt();
if (strl.count() > 2) {
if (!strl.at(2).contains("-")) {
version.patch = strl.at(2).toInt();
} else {
QStringList ptch = strl.at(2).toLower().split("-");
version.patch = ptch.at(0).toInt();
if (ptch.at(1).left(2) == "rc") {
version.preReleaseType = PR_RC;
version.preReleaseNumber = ptch.at(1).mid(2).toInt();
} else if (ptch.at(1).left(5) == "alpha") {
version.preReleaseType = PR_ALPHA;
version.preReleaseNumber = ptch.at(1).mid(5).toInt();
} else if (ptch.at(1).left(4) == "beta") {
version.preReleaseType = PR_BETA;
version.preReleaseNumber = ptch.at(1).mid(4).toInt();
int offset = 0;
QString relType;
for (int i = 0; i < ptch.at(1).size(); i++) {
QString c(ptch.at(1).mid(i, 1));
if (c >= "0" && c <= "9") {
break;
} else if (c == ".") {
offset++;
break;
}
offset++;
relType.append(c);
}
version.preReleaseType = preReleaseTypeToInt(relType);
if (version.preReleaseType > -1 && offset < ptch.at(1).size())
version.preReleaseNumber = ptch.at(1).mid(offset).toInt();
else
version.preReleaseType = PR_NONE;
}
}
//qDebug() << "vers:" << vers << "toString:" << toString() << "toInt:" << toInt();
return true;
}
bool SemanticVersion::isValid(QString vers)
SemanticVersion& SemanticVersion::operator=(const SemanticVersion& rhs)
{
if (vers.trimmed().isEmpty())
return false;
version.major = rhs.version.major;
version.minor = rhs.version.minor;
version.patch = rhs.version.patch;
version.preReleaseType = rhs.version.preReleaseType;
version.preReleaseNumber = rhs.version.preReleaseNumber;
return *this;
}
QStringList strl = vers.split(".");
if (strl.count() < 2)
bool SemanticVersion::isValid(const QString vers)
{
QString v(vers);
v = v.trimmed();
if (v.toLower().startsWith("v"))
v = v.mid(1);
#if 0
// Keep for testing full standard
// Note: regexp adapted for Qt ie extra escaping
QRegularExpression rx1("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$");
// Qt only test as not all patterns supported and can change in later releases
if (!rx1.isValid()) {
qDebug() << "Full standard is an invalid Qt regular expression";
return false;
}
if (!rx1.match(v).hasMatch()) {
qDebug() << vers << "is not a valid Semantic Version - ";
return false;
}
#endif // 0
// we only support a subset of the standard alpha, beta, rc with period optional and number optional
// format: major.minor.patch[-[alpha|beta|rc][.|][n|]]
QRegularExpression rx2("^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-(alpha|beta|rc)\\.?(0|[1-9]\\d*)?)*$");
// Qt only test as not all patterns supported and can change in later releases
if (!rx2.isValid()) {
qDebug() << "Standard subset is an invalid Qt regular expression";
return false;
}
if (!rx2.match(v.toLower()).hasMatch()) {
//qDebug() << vers << "is not a valid Semantic Version subset - ";
return false;
}
return isValid();
}
bool SemanticVersion::isValid()
{
// range checks to support 32 bit OS when components compounded
if (version.major < 0 || version.major > 255 || version.minor < 0 || version.minor > 255 || version.patch < 0 || version.patch > 255 ||
version.preReleaseType < 0 || version.preReleaseType > PR_NONE || version.preReleaseNumber < 0 || version.preReleaseNumber > 15) {
qDebug() << "Cannot convert to supported Semantec Version";
version = SemanticVersion().version;
return false;
}
return true;
}
@@ -772,15 +862,9 @@ QString SemanticVersion::toString() const
QString ret(QString("%1.%2.%3").arg(version.major).arg(version.minor).arg(version.patch));
if (version.preReleaseType != PR_NONE) {
ret.append("-");
if (version.preReleaseType == PR_RC)
ret.append("RC");
else if (version.preReleaseType == PR_ALPHA)
ret.append("ALPHA");
else if (version.preReleaseType == PR_BETA)
ret.append("BETA");
ret.append(QString::number(version.preReleaseNumber));
ret = QString("%1-%2").arg(ret).arg(preReleaseTypeToString());
if (version.preReleaseNumber > 0)
ret = QString("%1.%2").arg(ret).arg(version.preReleaseNumber);
}
return ret;
@@ -810,3 +894,26 @@ int SemanticVersion::compare(const SemanticVersion& other)
return 0;
}
unsigned int SemanticVersion::toInt() const
{
// limit to 32 bits for OS backward compatibility
unsigned int val = 0;
setBitmappedValue(val, version.major, 0, 8, 24);
setBitmappedValue(val, version.minor, 0, 8, 16);
setBitmappedValue(val, version.patch, 0, 8, 8);
setBitmappedValue(val, version.preReleaseType, 0, 4, 4);
setBitmappedValue(val, version.preReleaseNumber, 0, 4);
return val;
}
bool SemanticVersion::fromInt(const unsigned int val)
{
// assumption val was generated by toInt() but validate anyway
version.major = Helpers::getBitmappedValue(val, 0, 8, 24);
version.minor = Helpers::getBitmappedValue(val, 0, 8, 16);
version.patch = Helpers::getBitmappedValue(val, 0, 8, 8);
version.preReleaseType = Helpers::getBitmappedValue(val, 0, 4, 4);
version.preReleaseNumber = Helpers::getBitmappedValue(val, 0, 4);
return isValid();
}
+24 -13
View File
@@ -113,8 +113,8 @@ namespace Helpers
QString getChecklistFilename(const ModelData * model);
QString getChecklistFilePath(const ModelData * model);
QString removeAccents(const QString & str);
unsigned int getBitmappedValue(const unsigned int & field, const unsigned int index, const unsigned int numbits = 1, const unsigned int offset = 0);
void setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index, unsigned int numbits = 1, unsigned int offset = 0);
unsigned int getBitmappedValue(const unsigned int & field, const unsigned int index = 0, const unsigned int numbits = 1, const unsigned int offset = 0);
void setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index = 0, unsigned int numbits = 1, unsigned int offset = 0);
} // namespace Helpers
@@ -244,11 +244,18 @@ extern Stopwatch gStopwatch;
class SemanticVersion
{
public:
explicit SemanticVersion(QString vers);
~SemanticVersion() = default;;
explicit SemanticVersion(const QString vers);
explicit SemanticVersion() {}
~SemanticVersion() {}
bool isValid(const QString vers);
bool isValid();
bool fromString(const QString vers);
QString toString() const;
unsigned int toInt() const;
bool fromInt(const unsigned int val);
SemanticVersion& operator=(const SemanticVersion& rhs);
bool operator==(const SemanticVersion& rhs) {
return compare(rhs) == 0;
@@ -275,23 +282,27 @@ class SemanticVersion
}
private:
enum PreRelease {
enum PreReleaseTypes {
PR_ALPHA = 0,
PR_BETA = 1,
PR_RC = 2,
PR_NONE = 3
PR_BETA,
PR_RC,
PR_NONE
};
const QStringList PreReleaseTypesStringList = { "alpha", "beta", "rc"};
struct Version {
int major = 0;
int minor = 1;
int patch = 0;
PreRelease preReleaseType = PR_NONE;
int preReleaseNumber = 0;
int major = 0;
int minor = 0;
int patch = 0;
int preReleaseType = PR_NONE;
int preReleaseNumber = 0;
};
Version version;
int compare(const SemanticVersion& other);
inline QString preReleaseTypeToString() const { return PreReleaseTypesStringList.value(version.preReleaseType, ""); }
inline int preReleaseTypeToInt(QString preRelType) const { return PreReleaseTypesStringList.indexOf(preRelType); }
};
+14 -1
View File
@@ -21,6 +21,7 @@
#include "repomodels.h"
#include "appdata.h"
#include "helpers.h"
#include <QStandardItem>
#include <QJsonDocument>
@@ -52,7 +53,7 @@ ReleasesItemModel::ReleasesItemModel() :
m_releaseChannel(-1),
m_refreshRequired(true)
{
setSortRole(UpdatesItemModel::IMDR_Date);
setSortRole(UpdatesItemModel::IMDR_SortOrder);
}
void ReleasesItemModel::setReleaseChannel(const int channel)
@@ -137,6 +138,18 @@ void ReleasesItemModel::parseJsonObject(const QJsonObject & obj)
setDynamicItemData(item);
SemanticVersion sv;
if (tag.toLower() == m_nightlyName)
sv.fromString("255.255.255");
else
sv.fromString(tag);
if (sv.isValid())
item->setData(sv.toInt(), UpdatesItemModel::IMDR_SortOrder);
else
item->setData(item->data(IMDR_Date).toInt(), UpdatesItemModel::IMDR_SortOrder);
appendRow(item);
}
+1
View File
@@ -49,6 +49,7 @@ class UpdatesItemModel : public QStandardItemModel
enum ItemModelDataRoles {
IMDR_Id = Qt::UserRole,
IMDR_Date,
IMDR_SortOrder,
IMDR_Tag,
IMDR_Prerelease,
IMDR_Content,
+5 -5
View File
@@ -317,7 +317,7 @@ QString UpdateInterface::downloadDataTypeToString(DownloadDataType val)
}
// static
QString UpdateInterface::semanticVersion(QString version)
QStringList UpdateInterface::versionToStringList(QString version)
{
QStringList strl = version.split(".");
@@ -325,7 +325,7 @@ QString UpdateInterface::semanticVersion(QString version)
strl.append("0");
}
return strl.join(".");
return strl;
}
void UpdateInterface::reportProgress(const QString & text, const int type)
@@ -493,10 +493,10 @@ const bool UpdateInterface::isUpdateAvailable()
const bool UpdateInterface::isLatestVersion(const QString & installed, const QString & latest)
{
QStringList a = semanticVersion(installed).split(".");
QStringList b = semanticVersion(latest).split(".");
QStringList a = versionToStringList(installed);
QStringList b = versionToStringList(latest);
// not equal comparision used to force update if client upgraded and the release is subsequently withdrawn or subscribed to nightlies
// 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;
+1 -1
View File
@@ -239,7 +239,7 @@ class UpdateInterface : public QWidget
bool downloadSuccess;
static QString semanticVersion(QString version);
static QStringList versionToStringList(QString version);
void initAppSettings();
bool setRunFolders();