swift
artifact.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2017 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "misc/db/artifact.h"
5 
6 #include <QRegularExpression>
7 #include <QStringBuilder>
8 
9 #include "config/buildconfig.h"
10 #include "misc/stringutils.h"
11 
12 using namespace swift::config;
13 using namespace swift::misc::network;
14 
15 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::db, CArtifact)
16 
17 namespace swift::misc::db
18 {
19  CArtifact::CArtifact(const QString &name, const QString &version, const QString &md5, CArtifact::ArtifactType type,
20  int size, bool existing, const CPlatform &platform)
21  : m_name(name.trimmed()), m_md5(md5), m_type(static_cast<int>(type)), m_size(size), m_existing(existing),
22  m_platform(platform)
23  {
24  this->setVersion(trimVersionString(version));
25  if (!name.isEmpty() && version.isEmpty()) { m_version = versionNumberFromFilename(name); }
26  }
27 
29  {
30  const bool m =
31  (cs == Qt::CaseInsensitive) ? caseInsensitiveStringCompare(this->getName(), name) : name == this->getName();
32  if (m) { return true; }
33  return name.startsWith(this->getName(), cs);
34  }
35 
37  {
38  if (m_size < 0) { return {}; }
39  return CFileUtils::humanReadableFileSize(m_size);
40  }
41 
42  bool CArtifact::matchesAnyPlatform(const CPlatform &platform) const { return m_platform.matchesAny(platform); }
43 
44  bool CArtifact::hasUnrestrictedDistribution() const { return m_distributions.containsUnrestricted(); }
45 
46  bool CArtifact::isWithDistribution(const CDistribution &distribution, bool acceptMoreStableDistributions) const
47  {
48  if (distribution.isEmpty() || !this->hasDistributions()) { return false; }
49  return std::any_of(
50  this->getDistributions().cbegin(), this->getDistributions().cend(), [&](const CDistribution &dist) {
51  return dist == distribution || (acceptMoreStableDistributions && dist.isStabilityBetter(distribution));
52  });
53  }
54 
56  {
57  if (!this->hasDistributions()) { return {}; }
58  CRemoteFile rf(this->getName(), this->getFileSize());
59  const CDistribution d = this->getMostStableDistribution();
60  const CUrl url = d.getDownloadUrl();
61  if (url.isEmpty()) { return {}; }
62  rf.setUtcTimestamp(this->getUtcTimestamp());
63  rf.setUrl(url);
64  rf.setDescription(this->getPlatform().toQString() + " " + d.getChannel());
65  return rf;
66  }
67 
69  {
70  if (this->isUnknown()) { return false; }
71  if (!this->hasVersion()) { return false; }
72  return this->getQVersion() > CBuildConfig::getVersion();
73  }
74 
75  QString CArtifact::convertToQString(bool i18n) const { return this->convertToQString(", ", i18n); }
76 
77  QString CArtifact::convertToQString(const QString &separator, bool i18n) const
78  {
79  Q_UNUSED(i18n);
80  return u"name: " % this->getName() % separator % u"size: " % this->getFileSizeHumanReadable() % separator %
81  u"OS: " % this->getPlatform().toQString(i18n) % separator % u"timestamp: " %
83  }
84 
86  {
87  if (index.isMyself()) { return QVariant::fromValue(*this); }
89  {
91  }
92 
93  const auto i = index.frontCasted<ColumnIndex>();
94  switch (i)
95  {
96  case IndexName: return QVariant::fromValue(m_name);
97  case IndexMd5: return QVariant::fromValue(m_md5);
98  case IndexPlatform: return m_platform.propertyByIndex(index.copyFrontRemoved());
99  case IndexType: return QVariant::fromValue(m_type);
100  case IndexSize: return QVariant::fromValue(m_size);
101  case IndexSizeHumanReadable: return QVariant::fromValue(this->getFileSizeHumanReadable());
102  case IndexVersionString: return QVariant::fromValue(m_version);
103  case IndexQVersion: return QVariant::fromValue(this->getQVersion());
104  case IndexDistributions: return QVariant::fromValue(m_distributions);
105  default: return CValueObject::propertyByIndex(index);
106  }
107  }
108 
110  {
111  if (index.isMyself())
112  {
113  (*this) = variant.value<CArtifact>();
114  return;
115  }
117  {
119  return;
120  }
121 
122  const auto i = index.frontCasted<ColumnIndex>();
123  switch (i)
124  {
125  case IndexName: this->setName(variant.toString()); break;
126  case IndexMd5: m_md5 = variant.toString(); break;
127  case IndexPlatform: m_platform.setPropertyByIndex(index.copyFrontRemoved(), variant); break;
128  case IndexType: m_type = variant.toInt(); break;
129  case IndexSize: m_size = variant.toInt(); break;
130  case IndexVersionString: m_version = variant.toString(); break;
131  case IndexDistributions: m_distributions = variant.value<CDistributionList>(); break;
132  default: CValueObject::setPropertyByIndex(index, variant); break;
133  }
134  }
135 
137  {
138  Q_UNUSED(prefix); // not nested
139 
140  const QString name = json.value("name").toString();
141  const QString md5 = json.value("md5").toString();
142  const QString version = json.value("version").toString();
143  const CPlatform platform = CPlatform(json.value("os").toString());
144  const CArtifact::ArtifactType type = stringToType(json.value("type").toString());
145  const int size = json.value("size").toInt(-1);
146  const bool existing = json.value("existing").toBool();
147 
148  CArtifact artifact(name, version, md5, type, size, existing, platform);
150  if (json.contains("distributions"))
151  {
152  const QJsonObject distJson = json.value("distributions").toObject();
153  if (!distJson.isEmpty() && distJson.contains("distributionArray"))
154  {
155  const CDistributionList distributions =
156  CDistributionList::fromDatabaseJson(distJson.value("distributionArray").toArray());
157  artifact.setDistributions(distributions);
158  }
159  }
160  return artifact;
161  }
162 
164  {
165  static const QString xswb("xswiftbus");
166  static const QString installer("pilot client installer");
167  static const QString symbols("symbols");
168  static const QString unknown("unknown");
169 
170  switch (type)
171  {
172  case XSwiftBus: return xswb;
173  case PilotClientInstaller: return installer;
174  case Symbols: return symbols;
175  case UnknownArtifact:
176  default: break;
177  }
178  return unknown;
179  }
180 
182  {
183  if (name.isEmpty()) { return CPlatform::unknownOs(); }
184  const QString n(name.toLower().trimmed());
185  if (n.contains("-windows-") || n.endsWith(".exe"))
186  {
187  if (n.contains("-64-")) { return CPlatform::win64Platform(); }
188  if (n.contains("-32-")) { return CPlatform::win32Platform(); }
189  return CPlatform::unknownOs();
190  }
191 
192  if (n.contains("-macos-") || n.endsWith(".dmg")) { return CPlatform::macOSPlatform(); }
193  if (n.contains("-linux-") || n.endsWith(".run")) { return CPlatform::linuxPlatform(); }
194  if (n.contains("-allos-")) { return CPlatform::allOs(); }
195 
196  return CPlatform::unknownOs();
197  }
198 
199  QString CArtifact::versionNumberFromFilename(const QString &filename)
200  {
201  if (filename.isEmpty()) { return {}; }
202 
203  // swiftinstaller-linux-64-0.9.2.123.run
204  thread_local const QRegularExpression regex { R"(\d+\.\d+\.\d+\.\d+)" };
205  const QRegularExpressionMatch match = regex.match(filename);
206  return match.captured();
207  }
208 
209  CArtifact::ArtifactType CArtifact::stringToType(const QString &str)
210  {
211  const QString s(str.trimmed().toLower());
212  if (s.contains("installer")) return CArtifact::PilotClientInstaller;
213  if (s.contains("client")) return CArtifact::PilotClientInstaller;
214  if (s.contains("symb")) return CArtifact::Symbols;
215  if (s.contains("bus")) return CArtifact::XSwiftBus;
216  return CArtifact::UnknownArtifact;
217  }
218 
219  QString CArtifact::trimVersionString(const QString &version)
220  {
221  if (version.count('.') != 3) return version; // no 4th segment
222  QStringList parts = version.split('.');
223  const QString p4 = trim4thSegment(parts[3]);
224  if (p4 == parts[3]) { return version; } // nothing changed
225  parts[3] = p4;
226  const QString v = parts.join('.');
227  return v;
228  }
229 
230  QString CArtifact::trim4thSegment(const QString &seg)
231  {
232  // old schema: yMMddHHmm (9)
233  if (seg.length() >= 9) { return QStringLiteral("0"); }
234  return seg;
235  }
236 } // namespace swift::misc::db
static QString humanReadableFileSize(qint64 size)
Human readable (GB, MB, ..) file size.
Definition: fileutils.cpp:510
Platform (i.e.
Definition: platform.h:24
bool matchesAny(const CPlatform &otherPlatform) const
Matches any other platform.
Definition: platform.cpp:29
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: platform.cpp:82
static const CPlatform & linuxPlatform()
Linux.
Definition: platform.cpp:193
static const CPlatform & macOSPlatform()
Mac OS.
Definition: platform.cpp:199
static const CPlatform & unknownOs()
Unknown OS.
Definition: platform.cpp:205
static const CPlatform & win32Platform()
Win32.
Definition: platform.cpp:181
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: platform.cpp:71
static const CPlatform & win64Platform()
Win64.
Definition: platform.cpp:187
static const CPlatform & allOs()
All OS.
Definition: platform.cpp:211
Non-owning reference to a CPropertyIndex with a subset of its features.
Q_REQUIRED_RESULT CPropertyIndexRef copyFrontRemoved() const
Copy with first element removed.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
QString getFormattedUtcTimestampYmdhms() const
As yyyy MM dd HH mm ss.
QDateTime getUtcTimestamp() const
Get timestamp.
void setUtcTimestamp(const QDateTime &timestamp)
Set timestamp.
Artifacts ("our software" products)
Definition: artifact.h:23
ColumnIndex
Properties by index.
Definition: artifact.h:27
bool hasUnrestrictedDistribution() const
Has unrestricted distribution.
Definition: artifact.cpp:44
bool isWithDistribution(const CDistribution &distribution, bool acceptMoreStableDistributions) const
Is distributed with given distribution?
Definition: artifact.cpp:46
bool hasDistributions() const
Has distributions?
Definition: artifact.h:107
void setName(const QString &name)
Set the name.
Definition: artifact.h:62
bool matchesAnyPlatform(const CPlatform &platform) const
Matches any platform.
Definition: artifact.cpp:42
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: artifact.cpp:109
QString getFileSizeHumanReadable() const
Human readable (GB, MB, ..) file size.
Definition: artifact.cpp:36
network::CRemoteFile asRemoteFile() const
Turn into remote file.
Definition: artifact.cpp:55
bool isUnknown() const
Unknown.
Definition: artifact.h:71
int getFileSize() const
File size.
Definition: artifact.h:77
const CPlatform & getPlatform() const
OS.
Definition: artifact.h:89
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: artifact.cpp:85
static CPlatform artifactNameToPlatform(const QString &name)
Name to platform.
Definition: artifact.cpp:181
bool isNewerThanCurrentBuild() const
Newer than the current build.
Definition: artifact.cpp:68
void setDistributions(const CDistributionList &distributions)
Related distributions.
Definition: artifact.h:104
static const QString & typeToString(ArtifactType type)
Type as string.
Definition: artifact.cpp:163
static CArtifact fromDatabaseJson(const QJsonObject &json, const QString &prefix={})
Object from database JSON format.
Definition: artifact.cpp:136
bool matchesName(const QString &name, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Matching name?
Definition: artifact.cpp:28
CDistribution getMostStableDistribution() const
Most stable distribution if any.
Definition: artifact.h:101
const CDistributionList & getDistributions() const
Related distributions.
Definition: artifact.h:98
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: artifact.cpp:75
const QString & getName() const
Name (i.e. installer name, symbol name)
Definition: artifact.h:59
Distributions for channel.
Definition: distribution.h:27
bool isStabilityBetter(const CDistribution &otherDistribution) const
"this" having better stability than other distribution?
const QString & getChannel() const
Version channel (Alpha, Beta, Stable ..)
Definition: distribution.h:45
bool isEmpty() const
Empty?
Definition: distribution.h:81
const network::CUrl & getDownloadUrl() const
Download URL, i.e. here one can download installer.
Definition: distribution.h:57
Multiple distributions for different channels:
bool containsUnrestricted() const
Contains any unrestricted.
static CDistributionList fromDatabaseJson(const QJsonArray &array)
From database JSON by array.
QVersionNumber getQVersion() const
Version as QVersion.
Definition: datastore.cpp:16
QString m_version
version info
Definition: datastore.h:63
bool hasVersion() const
Having a version?s.
Definition: datastore.h:54
void setVersion(const QString &version)
Version info.
Definition: datastore.h:57
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: datastore.cpp:94
static bool canHandleIndex(swift::misc::CPropertyIndexRef index)
Can given index be handled?
Definition: datastore.cpp:147
void setKeyVersionTimestampFromDatabaseJson(const QJsonObject &json, const QString &prefix=QString())
Set key and timestamp values.
Definition: datastore.cpp:79
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: datastore.cpp:110
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:158
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:165
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:74
void setDescription(const QString &description)
Description.
Definition: remotefile.h:73
void setUrl(const CUrl &url)
Set URL.
Definition: remotefile.h:94
Value object encapsulating information of a location, kind of simplified CValueObject compliant versi...
Definition: url.h:27
bool isEmpty() const
Empty.
Definition: url.cpp:54
Plugin loaded by X-Plane which publishes a DBus service.
Definition: command.h:14
SWIFT_MISC_EXPORT bool caseInsensitiveStringCompare(const QString &c1, const QString &c2)
Case insensitive string compare.
bool contains(QLatin1StringView key) const const
bool isEmpty() const const
QJsonValue value(QLatin1StringView key) const const
QJsonArray toArray() const const
bool toBool(bool defaultValue) const const
int toInt(int defaultValue) const const
QJsonObject toObject() const const
QString toString() const const
QString captured(QAnyStringView name) const const
qsizetype count() const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype length() const const
QStringList split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QString toLower() const const
QString trimmed() const const
QString join(QChar separator) const const
CaseSensitivity
QVariant fromValue(T &&value)
int toInt(bool *ok) const const
QString toString() const const
T value() const &const
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67