From de7312a8692cd4a2ff0d6f1206e5551e31a670fc Mon Sep 17 00:00:00 2001 From: Klaus Basan Date: Sat, 9 Dec 2017 19:38:35 +0100 Subject: [PATCH] Ref T203, adjustments for distribution class * distribution is just the channel, no more the concrete file * masterdir no longer part of distribution * using QStringList instead of QSet in some place so sort order is kept * new utility functions --- src/blackmisc/db/distribution.cpp | 208 ++++---------------------- src/blackmisc/db/distribution.h | 83 +++++----- src/blackmisc/db/distributionlist.cpp | 76 ++++------ src/blackmisc/db/distributionlist.h | 57 +++---- 4 files changed, 123 insertions(+), 301 deletions(-) diff --git a/src/blackmisc/db/distribution.cpp b/src/blackmisc/db/distribution.cpp index 0d9276ee7..ed4f86880 100644 --- a/src/blackmisc/db/distribution.cpp +++ b/src/blackmisc/db/distribution.cpp @@ -22,8 +22,8 @@ namespace BlackMisc CDistribution::CDistribution() { } - CDistribution::CDistribution(const QString &channel, bool restricted) : - m_channel(channel.trimmed().toUpper()), m_restricted(restricted) + CDistribution::CDistribution(const QString &channel, int stability, bool restricted) : + m_channel(channel.trimmed().toUpper()), m_stability(stability), m_restricted(restricted) { } void CDistribution::setChannel(const QString &channel) @@ -31,99 +31,6 @@ namespace BlackMisc m_channel = channel.trimmed().toUpper(); } - QStringList CDistribution::getPlatforms() const - { - QStringList platforms = m_platformFiles.keys(); - platforms.sort(); - return platforms; - } - - bool CDistribution::supportsPlatform(const QString &platform) const - { - QStringList platforms = m_platformFiles.keys(); - return !platform.isEmpty() && platforms.contains(platform); - } - - QString CDistribution::guessMyPlatform() const - { - const QStringList platforms(getPlatforms()); - if (platforms.isEmpty()) { return ""; } - QStringList reduced; - for (const QString &p : platforms) - { - if (CBuildConfig::isRunningOnWindowsNtPlatform()) - { - if (!p.contains("win", Qt::CaseInsensitive)) continue; - } - else if (CBuildConfig::isRunningOnLinuxPlatform()) - { - if (!p.contains("linux", Qt::CaseInsensitive)) continue; - } - else if (CBuildConfig::isRunningOnMacOSPlatform()) - { - if (!(p.contains("mac", Qt::CaseInsensitive) || - p.contains("macos", Qt::CaseInsensitive) || - p.contains("osx", Qt::CaseInsensitive))) - { - continue; - } - } - reduced << p; - } - - if (reduced.size() > 1) - { - // further reduce by VATSIM flag - QStringList furtherReduced; - for (const QString &p : as_const(reduced)) - { - if (CBuildConfig::isVatsimVersion()) - { - if (p.contains("vatsim")) { furtherReduced << p; } - } - else - { - if (!p.contains("vatsim")) { furtherReduced << p; } - } - } - if (!furtherReduced.isEmpty()) { reduced = furtherReduced; } - } - - int wordSize = CBuildConfig::buildWordSize(); - if (wordSize >= 32 && reduced.size() > 1) - { - // further reduce by word size 32/64 - QStringList furtherReduced; - const QString wsString = QString::number(wordSize); - for (const QString &p : as_const(reduced)) - { - if (!p.contains(wsString)) { continue; } - furtherReduced << p; - } - if (!furtherReduced.isEmpty()) { reduced = furtherReduced; } - } - - if (reduced.isEmpty()) { return ""; } - return reduced.front(); - } - - QString CDistribution::getVersionString(const QString &platform) const - { - if (platform.isEmpty()) { return ""; } - return m_platformVersions.value(platform); - } - - QVersionNumber CDistribution::getQVersion(const QString &platform) const - { - return QVersionNumber::fromString(getVersionString(platform)); - } - - QString CDistribution::getFilename(const QString &platform) const - { - if (platform.isEmpty()) { return ""; } - return m_platformFiles.value(platform); - } - void CDistribution::addDownloadUrl(const CUrl &url) { if (url.isEmpty()) { return; } @@ -135,6 +42,21 @@ namespace BlackMisc return !m_downloadUrls.isEmpty(); } + CIcon CDistribution::getRestrictionIcon() const + { + return CIcon::iconByIndex(m_restricted ? CIcons::StandardIconLockClosed16 : CIcons::StandardIconLockOpen16); + } + + bool CDistribution::isStabilitySameOrBetter(const CDistribution &otherDistribution) const + { + return m_stability >= otherDistribution.m_stability; + } + + bool CDistribution::isStabilityBetter(const CDistribution &otherDistribution) const + { + return m_stability > otherDistribution.m_stability; + } + QString CDistribution::convertToQString(bool i18n) const { return convertToQString(", ", i18n); @@ -148,13 +70,15 @@ namespace BlackMisc QLatin1String("download URLs: ") % getDownloadUrls().toQString(i18n) % separator % - QLatin1String("platforms: ") % - getPlatforms().join(", ") % - separator % QLatin1String("timestamp: ") % this->getFormattedUtcTimestampYmdhms(); } + CIcon CDistribution::toIcon() const + { + return this->getRestrictionIcon(); + } + CVariant CDistribution::propertyByIndex(const BlackMisc::CPropertyIndex &index) const { if (index.isMyself()) { return CVariant::from(*this); } @@ -164,10 +88,9 @@ namespace BlackMisc switch (i) { case IndexChannel: return CVariant::fromValue(m_channel); + case IndexStability : return CVariant::fromValue(m_stability); case IndexDownloadUrls: return CVariant::fromValue(m_downloadUrls); case IndexRestricted: return CVariant::fromValue(m_restricted); - case IndexPlatforms: return CVariant::fromValue(this->getPlatforms()); - case IndexPlatformFiles: return CVariant::fromValue(m_platformFiles); default: return CValueObject::propertyByIndex(index); } } @@ -185,9 +108,9 @@ namespace BlackMisc switch (i) { case IndexChannel: this->setChannel(variant.value()); break; + case IndexStability: m_stability = variant.toInt(); break; case IndexDownloadUrls: m_downloadUrls = variant.value(); break; case IndexRestricted: m_restricted = variant.toBool(); break; - case IndexPlatformFiles: m_platformFiles = variant.value(); break; default: CValueObject::setPropertyByIndex(index, variant); break; } } @@ -197,8 +120,10 @@ namespace BlackMisc Q_UNUSED(prefix); // not nested const QString channel(json.value("channel").toString()); - const bool restricted(json.value("restricted").toBool()); - CDistribution distribution(channel, restricted); + const bool restricted = json.value("restricted").toBool(); + const int stability = json.value("stability").toInt(); + CDistribution distribution(channel, stability, restricted); + distribution.setKeyAndTimestampFromDatabaseJson(json); // add the URLs for (int i = 0; i < 5; i++) @@ -208,84 +133,7 @@ namespace BlackMisc if (url.isEmpty()) { continue; } distribution.addDownloadUrl(CUrl(url)); } - - const QJsonObject platforms = json.value("platforms").toObject(); - const QStringList platformsKeys = platforms.keys(); - if (platformsKeys.isEmpty()) { return CDistribution(); } // no platforms, then the whole distribution is useless - for (const QString platformKey : as_const(platformsKeys)) - { - QStringList platformFileNames; - QJsonArray platformFiles = platforms.value(platformKey).toArray(); - for (const QJsonValue &platformFile : platformFiles) - { - const QString filename = platformFile.toString(); - if (filename.isEmpty()) { continue; } - platformFileNames << filename; - } - - const QPair latestFileInfo = findLatestVersion(platformFileNames); - if (!latestFileInfo.first.isEmpty()) - { - distribution.m_platformFiles.insert(platformKey, latestFileInfo.first); - distribution.m_platformVersions.insert(platformKey, latestFileInfo.second.toString()); - } - } - - distribution.setKeyAndTimestampFromDatabaseJson(json); return distribution; } - - QVersionNumber CDistribution::versionNumberFromFilename(const QString &filename) - { - if (filename.isEmpty()) { return QVersionNumber(); } - - // swift-installer-linux-64-0.7.3_2017-03-25_11-24-50.run - thread_local const QRegularExpression firstSegments("\\d+\\.\\d+\\.\\d+"); - QRegularExpressionMatch firstSegmentsMatch = firstSegments.match(filename); - if (!firstSegmentsMatch.hasMatch()) - { - return QVersionNumber(); // no version, invalid - } - QString v = firstSegmentsMatch.captured(0); // first 3 segments, like 0.9.3 - if (!v.endsWith('.')) { v += '.'; } - - thread_local const QRegularExpression ts1("\\d{4}.?\\d{2}.?\\d{2}.?\\d{2}.?\\d{2}.?\\d{2}"); - QRegularExpressionMatch ts1Match = ts1.match(filename); - if (!ts1Match.hasMatch()) - { - // version without timestamp - v += "0"; - return QVersionNumber::fromString(v); - } - - const QString lastSegment = BlackMisc::digitOnlyString(ts1Match.captured(0)); - v += lastSegment; - return QVersionNumber::fromString(v); - } - - QPair CDistribution::findLatestVersion(const QStringList &filenames) - { - if (filenames.isEmpty()) return QPair(); - if (filenames.size() == 1) return QPair(filenames.first(), versionNumberFromFilename(filenames.first())); - QString latest; - QVersionNumber latestVersion; - for (const QString &fn : filenames) - { - if (latest.isEmpty()) - { - latest = fn; - latestVersion = versionNumberFromFilename(fn); - continue; - } - - const QVersionNumber version = versionNumberFromFilename(fn); - if (version > latestVersion) - { - latest = fn; - latestVersion = versionNumberFromFilename(fn); - } - } - return QPair(latest, latestVersion); - } } // ns } // ns diff --git a/src/blackmisc/db/distribution.h b/src/blackmisc/db/distribution.h index 7b0ab33d5..44ca456ca 100644 --- a/src/blackmisc/db/distribution.h +++ b/src/blackmisc/db/distribution.h @@ -29,30 +29,26 @@ namespace BlackMisc { namespace Db { - //! Dictionary for files per platform - using CPlatformDictionary = BlackMisc::CDictionary; - //! Distributions for channel class BLACKMISC_EXPORT CDistribution : - public BlackMisc::CValueObject, - public BlackMisc::Db::IDatastoreObjectWithIntegerKey + public CValueObject, + public IDatastoreObjectWithIntegerKey { public: //! Properties by index enum ColumnIndex { - IndexChannel = BlackMisc::CPropertyIndex::GlobalIndexCDistribution, + IndexChannel = CPropertyIndex::GlobalIndexCDistribution, + IndexStability, IndexRestricted, - IndexDownloadUrls, - IndexPlatforms, - IndexPlatformFiles, + IndexDownloadUrls }; //! Default constructor CDistribution(); //! Constructor - CDistribution(const QString &channel, bool restricted); + CDistribution(const QString &channel, int stability, bool restricted); //! Destructor. ~CDistribution() {} @@ -63,29 +59,17 @@ namespace BlackMisc //! Set the channel void setChannel(const QString &channel); - //! Get platforms - QStringList getPlatforms() const; + //! Stability (higher is more stable) + int getStability() const { return m_stability; } - //! Supports platform? - bool supportsPlatform(const QString &platform) const; - - //! Guess platform for this distribution channel and this version of swift - QString guessMyPlatform() const; - - //! Version for platform - QString getVersionString(const QString &platform) const; - - //! Version as QVersion - QVersionNumber getQVersion(const QString &platform) const; - - //! File for platform - QString getFilename(const QString &platform) const; + //! Order + void setStability(int stability) { m_stability = stability; } //! Download URLs, i.e. here one can download installer - const BlackMisc::Network::CUrlList &getDownloadUrls() const { return m_downloadUrls; } + const Network::CUrlList &getDownloadUrls() const { return m_downloadUrls; } //! Add URL, ignored if empty - void addDownloadUrl(const BlackMisc::Network::CUrl &url); + void addDownloadUrl(const Network::CUrl &url); //! At least one download URL? bool hasDownloadUrls() const; @@ -93,48 +77,57 @@ namespace BlackMisc //! Restricted channel? bool isRestricted() const { return m_restricted; } + //! Restricted channel + void setRestricted(bool r) { m_restricted = r; } + + //! Get the restrict icon + CIcon getRestrictionIcon() const; + + //! "this" having same or better stability than other distribution? + bool isStabilitySameOrBetter(const CDistribution &otherDistribution) const; + + //! "this" having better stability than other distribution? + bool isStabilityBetter(const CDistribution &otherDistribution) const; + + //! Empty? + bool isEmpty() const { return m_channel.isEmpty(); } + //! \copydoc BlackMisc::Mixin::String::toQString QString convertToQString(bool i18n = false) const; //! To string QString convertToQString(const QString &separator, bool i18n = false) const; + //! Representing icon + CIcon toIcon() const; + //! \copydoc BlackMisc::Mixin::Index::propertyByIndex - BlackMisc::CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const; + CVariant propertyByIndex(const CPropertyIndex &index) const; //! \copydoc BlackMisc::Mixin::Index::setPropertyByIndex - void setPropertyByIndex(const BlackMisc::CPropertyIndex &index, const BlackMisc::CVariant &variant); + void setPropertyByIndex(const CPropertyIndex &index, const CVariant &variant); //! Object from database JSON format static CDistribution fromDatabaseJson(const QJsonObject &json, const QString &prefix = {}); private: - QString m_channel; //!< channel the files belong to - bool m_restricted = false; //!< restricted access (i.e. password for download needed) - BlackMisc::Network::CUrlList m_downloadUrls; //!< download URLs, here I get the installer - CPlatformDictionary m_platformFiles; //!< the latest file version per platform - CPlatformDictionary m_platformVersions; //!< the version per platform - - //! Extract version number from a file name - static QVersionNumber versionNumberFromFilename(const QString &filename); - - //! Find the file representing the latest version - static QPair findLatestVersion(const QStringList &filenames); + QString m_channel; //!< channel the files belong to + int m_stability; //!< stability + bool m_restricted = false; //!< restricted access (i.e. password for download needed) + Network::CUrlList m_downloadUrls; //!< download URLs, here I get the installer BLACK_METACLASS( CDistribution, BLACK_METAMEMBER(dbKey), BLACK_METAMEMBER(timestampMSecsSinceEpoch), BLACK_METAMEMBER(channel), - BLACK_METAMEMBER(downloadUrls), - BLACK_METAMEMBER(platformFiles, 0, DisabledForComparison | DisabledForHashing), - BLACK_METAMEMBER(platformVersions, 0, DisabledForComparison | DisabledForHashing) + BLACK_METAMEMBER(stability), + BLACK_METAMEMBER(downloadUrls) ); }; } // ns } // ns Q_DECLARE_METATYPE(BlackMisc::Db::CDistribution) -Q_DECLARE_METATYPE(BlackMisc::Db::CPlatformDictionary) #endif // guard diff --git a/src/blackmisc/db/distributionlist.cpp b/src/blackmisc/db/distributionlist.cpp index f36f174fc..62488b5c5 100644 --- a/src/blackmisc/db/distributionlist.cpp +++ b/src/blackmisc/db/distributionlist.cpp @@ -20,9 +20,9 @@ namespace BlackMisc CSequence(other) { } - QSet CDistributionList::getChannels() const + QStringList CDistributionList::getChannels() const { - QSet channels; + QStringList channels; for (const CDistribution &distribution : *this) { if (distribution.getChannel().isEmpty()) { continue; } @@ -31,65 +31,55 @@ namespace BlackMisc return channels; } - QSet CDistributionList::findChannelsForPlatform(const QString &platform) const + void CDistributionList::sortByStability(Qt::SortOrder order) { - QSet channels; - if (platform.isEmpty()) { return channels; } - for (const CDistribution &distribution : *this) + this->sort([order](const CDistribution & a, const CDistribution & b) { - if (distribution.getChannel().isEmpty()) { continue; } - if (distribution.supportsPlatform(platform)) - { - channels.insert(distribution.getChannel()); - } - } - return channels; + const int as = a.getStability(); + const int bs = b.getStability(); + return order == Qt::AscendingOrder ? as < bs : bs < as; + }); } - QSet CDistributionList::getPlatforms() const + bool CDistributionList::containsEqualOrMoreStable(CDistribution &distribution) const { - QSet platforms; - for (const CDistribution &distribution : *this) - { - if (distribution.getChannel().isEmpty()) { continue; } - platforms << distribution.getChannel(); - } - return platforms; + return containsBy([&distribution](const CDistribution & dist) { return dist.isStabilitySameOrBetter(distribution); }); } - CDistribution CDistributionList::findByChannelOrDefault(const QString &channel) const + bool CDistributionList::containsUnrestricted() const + { + return this->contains(&CDistribution::isRestricted, true); + } + + bool CDistributionList::containsChannel(const QString &channel) const + { + return this->contains(&CDistribution::getChannel, channel); + } + + CDistribution CDistributionList::findFirstByChannelOrDefault(const QString &channel) const { return this->findFirstByOrDefault(&CDistribution::getChannel, channel); } - QString CDistributionList::getVersionForChannelAndPlatform(const QString &channel, const QString &platform) const + CDistributionList CDistributionList::findByRestriction(bool restricted) const { - const CDistribution dist = this->findByChannelOrDefault(channel); - return dist.getVersionString(platform); + return this->findBy(&CDistribution::isRestricted, restricted); } - QVersionNumber CDistributionList::getQVersionForChannelAndPlatform(const QString &channel, const QString &platform) const + CDistribution CDistributionList::getMostStableOrDefault() const { - const CDistribution dist = this->findByChannelOrDefault(channel); - return dist.getQVersion(platform); + if (this->size() < 2) { return this->frontOrDefault(); } + CDistributionList copy(*this); + copy.sortByStability(); + return copy.back(); } - QString CDistributionList::getVersionForChannelAndPlatform(const QStringList &channelPlatform) const + CDistribution CDistributionList::getLeastStableOrDefault() const { - Q_ASSERT_X(channelPlatform.length() != 2, Q_FUNC_INFO, "Wrong size"); - return this->getVersionForChannelAndPlatform(channelPlatform.first(), channelPlatform.last()); - } - - QVersionNumber CDistributionList::getQVersionForChannelAndPlatform(const QStringList &channelPlatform) const - { - Q_ASSERT_X(channelPlatform.length() == 2, Q_FUNC_INFO, "Wrong size"); - return this->getQVersionForChannelAndPlatform(channelPlatform.first(), channelPlatform.last()); - } - - QStringList CDistributionList::guessMyDefaultChannelAndPlatform() const - { - //! \fixme will be further improved when we have added a public server and have more channels - return QStringList({"ALPHA", BlackConfig::CBuildConfig::guessMyPlatformString()}); // guessing + if (this->size() < 2) { return this->frontOrDefault(); } + CDistributionList copy(*this); + copy.sortByStability(); + return copy.front(); } CDistributionList CDistributionList::fromDatabaseJson(const QJsonArray &array) diff --git a/src/blackmisc/db/distributionlist.h b/src/blackmisc/db/distributionlist.h index d6ce4f5c6..6e78b8cd5 100644 --- a/src/blackmisc/db/distributionlist.h +++ b/src/blackmisc/db/distributionlist.h @@ -14,7 +14,7 @@ #include "distribution.h" #include "blackmisc/db/datastoreobjectlist.h" -#include "blackmisc/datacache.h" +#include "blackmisc/platform.h" #include "blackmisc/blackmiscexport.h" #include "blackmisc/collection.h" #include "blackmisc/sequence.h" @@ -27,12 +27,13 @@ namespace BlackMisc namespace Db { //! Multiple distributions for different channels: - //! - one CDistribution objects contains all versions for a channel - //! - a distribution list normally contains all distributions for all channels + //! - one CDistribution objects contains all artifacts for a channel + //! - a distribution list normally contains all artifacts for all channels + //! \sa CArtifact class BLACKMISC_EXPORT CDistributionList : - public BlackMisc::CSequence, - public BlackMisc::Db::IDatastoreObjectList, - public BlackMisc::Mixin::MetaType + public CSequence, + public IDatastoreObjectList, + public Mixin::MetaType { public: BLACKMISC_DECLARE_USING_MIXIN_METATYPE(CDistributionList) @@ -44,31 +45,31 @@ namespace BlackMisc CDistributionList(const CSequence &other); //! All channels - QSet getChannels() const; + QStringList getChannels() const; - //! Find channels for platform - QSet findChannelsForPlatform(const QString &platform) const; + //! Stability + void sortByStability(Qt::SortOrder order = Qt::AscendingOrder); - //! All platforms for all channels - QSet getPlatforms() const; + //! Contains distributions considered of same stability or more stable + bool containsEqualOrMoreStable(CDistribution &distribution) const; - //! Find distribution by channels - CDistribution findByChannelOrDefault(const QString &channel) const; + //! Contains any unrestricted + bool containsUnrestricted() const; - //! Version for specific channel and platform - QString getVersionForChannelAndPlatform(const QString &channel, const QString &platform) const; + //! Contains channel? + bool containsChannel(const QString &channel) const; - //! Version for specific channel and platform - QVersionNumber getQVersionForChannelAndPlatform(const QString &channel, const QString &platform) const; + //! Find by channel + CDistribution findFirstByChannelOrDefault(const QString &channel) const; - //! Version for specific channel and platform - QString getVersionForChannelAndPlatform(const QStringList &channelPlatform) const; + //! Find by restriction flag + CDistributionList findByRestriction(bool restricted) const; - //! Version for specific channel and platform - QVersionNumber getQVersionForChannelAndPlatform(const QStringList &channelPlatform) const; + //! Most stable or default + CDistribution getMostStableOrDefault() const; - //! Guess the best channel/platform - QStringList guessMyDefaultChannelAndPlatform() const; + //! Least stable or default + CDistribution getLeastStableOrDefault() const; //! From database JSON by array static CDistributionList fromDatabaseJson(const QJsonArray &array); @@ -76,16 +77,6 @@ namespace BlackMisc //! From database JSON by string static CDistributionList fromDatabaseJson(const QString &json); }; - - //! Trait for distributions - struct TDistributionsInfo : public BlackMisc::TDataTrait - { - //! Key in data cache - static const char *key() { return "distributions"; } - - //! First load is synchronous - static constexpr bool isPinned() { return true; } - }; } // ns } // ns