swift
updateinfo.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/updateinfo.h"
5 
6 #include <QJsonArray>
7 #include <QJsonDocument>
8 #include <QJsonObject>
9 #include <QStringBuilder>
10 
11 #include "config/buildconfig.h"
12 #include "misc/stringutils.h"
13 
14 using namespace swift::config;
15 
16 SWIFT_DEFINE_VALUEOBJECT_MIXINS(swift::misc::db, CUpdateInfo)
17 
18 namespace swift::misc::db
19 {
20  CUpdateInfo::CUpdateInfo(const CArtifactList &artifacts, const CDistributionList &distributions)
21  : m_artifactsPilotClient(artifacts.findByType(CArtifact::PilotClientInstaller)),
22  m_artifactsXSwiftBus(artifacts.findByType(CArtifact::XSwiftBus)), m_distributions(distributions)
23  {
24  // void
25  }
26 
28  {
30  CDistributionList distributions = artifacts.getDistributions();
31  distributions.sortByStability();
32  return distributions;
33  }
34 
36  {
37  CArtifactList artifacts = m_artifactsPilotClient.findMatchingForCurrentPlatform();
38  artifacts.sortByVersion(Qt::DescendingOrder);
39  return artifacts;
40  }
41 
43  {
44  CArtifactList artifacts(m_artifactsXSwiftBus);
45  artifacts.sortByVersion(Qt::DescendingOrder);
46  return artifacts;
47  }
48 
50  {
51  CArtifactList artifacts(m_artifactsXSwiftBus);
52  artifacts.sortByVersion(Qt::DescendingOrder);
53  return artifacts;
54  }
55 
57  {
58  CArtifactList artifacts = m_artifactsXSwiftBus.findMatchingForCurrentPlatform();
59  artifacts.sortByVersion(Qt::DescendingOrder);
60  return artifacts;
61  }
62 
64  {
65  if (this->isEmpty()) { return CDistribution(); }
66  const CArtifactList ownArtifacts = this->getArtifactsPilotClientForCurrentPlatform();
67  if (ownArtifacts.isEmpty()) { return CDistribution(); }
68 
69  const QVersionNumber myVersion = CBuildConfig::getVersion();
70  const QVersionNumber latestVersion = ownArtifacts.getLatestQVersion();
71  if (myVersion > latestVersion)
72  {
73  // dev. version
74  return ownArtifacts.getDistributions().getLeastStableOrDefault();
75  }
76 
77  const CArtifact exactVersion = ownArtifacts.findFirstByVersionOrDefault(myVersion);
78  if (!exactVersion.isUnknown()) { return exactVersion.getDistributions().getMostStableOrDefault(); }
79 
81  }
82 
84  {
86  const CDistribution mostStable = myArtifacts.getDistributions().getMostStableOrDefault();
87  return QStringList({ mostStable.getClassName(), CPlatform::currentPlatform().getPlatformName() });
88  }
89 
90  QString CUpdateInfo::convertToQString(bool i18n) const { return this->convertToQString(", ", i18n); }
91 
92  QString CUpdateInfo::convertToQString(const QString &separator, bool i18n) const
93  {
94  Q_UNUSED(i18n);
95  return u"artifacts (PC): " % this->getArtifactsPilotClient().toQString(i18n) % separator %
96  u"artifacts (XSB): " % this->getArtifactsXSwiftBus().toQString(i18n) % separator % u"distributions: " %
97  this->getDistributions().toQString(i18n);
98  }
99 
101  {
102  if (index.isMyself()) { return QVariant::fromValue(*this); }
103  const ColumnIndex i = index.frontCasted<ColumnIndex>();
104  switch (i)
105  {
106  case IndexArtifactsPilotClient: return QVariant::fromValue(m_artifactsPilotClient);
107  case IndexArtifactsXSwiftBus: return QVariant::fromValue(m_artifactsXSwiftBus);
108  case IndexDistributions: return QVariant::fromValue(m_distributions);
109  default: return CValueObject::propertyByIndex(index);
110  }
111  }
112 
113  void CUpdateInfo::setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
114  {
115  if (index.isMyself())
116  {
117  (*this) = variant.value<CUpdateInfo>();
118  return;
119  }
120  const ColumnIndex i = index.frontCasted<ColumnIndex>();
121  switch (i)
122  {
123  case IndexArtifactsPilotClient: m_artifactsPilotClient = variant.value<CArtifactList>(); break;
124  case IndexArtifactsXSwiftBus: m_artifactsXSwiftBus = variant.value<CArtifactList>(); break;
125  case IndexDistributions: m_distributions = variant.value<CDistributionList>(); break;
126  default: CValueObject::setPropertyByIndex(index, variant); break;
127  }
128  }
129 
130  CUpdateInfo CUpdateInfo::fromDatabaseJson(const QJsonObject &json, const QString &prefix)
131  {
132  Q_UNUSED(prefix); // not nested
133  const QJsonArray jsonDistributions = json.value("distributions").toArray();
134  const QJsonArray jsonArtifacts = json.value("artifacts").toArray();
135  const CDistributionList distributions = CDistributionList::fromDatabaseJson(jsonDistributions);
136  const CArtifactList artifacts = CArtifactList::fromDatabaseJson(jsonArtifacts);
137  Q_ASSERT_X(jsonDistributions.size() == distributions.size(), Q_FUNC_INFO, "size mismatch");
138  Q_ASSERT_X(artifacts.size() == artifacts.size(), Q_FUNC_INFO, "size mismatch");
139  return CUpdateInfo(artifacts, distributions);
140  }
141 
142  CUpdateInfo CUpdateInfo::fromDatabaseJson(const QString &jsonString)
143  {
144  if (jsonString.isEmpty()) { return CUpdateInfo(); }
146  }
147 
149  {
150  // https://docs.github.com/en/rest/reference/repos#releases
151 
152  const QString url = CBuildConfig::gitHubRepoUrl() + QStringLiteral("releases/download");
153  CDistribution alphaDistribution("ALPHA", 5, false);
154  CDistribution betaDistribution("BETA", 10, false);
155  alphaDistribution.setDownloadUrl(url);
156  betaDistribution.setDownloadUrl(url);
157 
158  CUpdateInfo result;
159  result.m_distributions = { alphaDistribution, betaDistribution };
160 
161  for (const QJsonValue release : QJsonDocument::fromJson(jsonData).array())
162  {
163  QString version = release[QLatin1String("tag_name")].toString();
164  if (version.isEmpty() || version[0] != 'v') { continue; }
165  version.remove(0, 1);
166  if (containsChar(version, [](QChar c) { return c != '.' && !is09(c); })) { continue; }
167 
168  bool existing = !release[QLatin1String("draft")].toBool();
169  bool alpha = release[QLatin1String("prerelease")].toBool();
170 
171  for (const QJsonValue asset : release[QLatin1String("assets")].toArray())
172  {
173  QString name = asset[QLatin1String("name")].toString();
174  QString filename = QStringLiteral("v%1/%2").arg(version, name);
175  int size = asset[QLatin1String("size")].toInt();
176 
177  CArtifact::ArtifactType type = CArtifact::UnknownArtifact;
178  if (name.startsWith(QStringLiteral("swiftinstaller"))) { type = CArtifact::PilotClientInstaller; }
179  else if (name.startsWith(QStringLiteral("swiftsymbols"))) { type = CArtifact::Symbols; }
180  else if (name.startsWith(QStringLiteral("xswiftbus"))) { type = CArtifact::XSwiftBus; }
181 
182  CPlatform platform;
183  if (name.contains(QStringLiteral("windows-32"))) { platform = CPlatform::win32Platform(); }
184  else if (name.contains(QStringLiteral("windows-64"))) { platform = CPlatform::win64Platform(); }
185  else if (name.contains(QStringLiteral("linux-64"))) { platform = CPlatform::linuxPlatform(); }
186  else if (name.contains(QStringLiteral("macos-64"))) { platform = CPlatform::macOSPlatform(); }
187  else if (name.contains(QStringLiteral("allos"))) { platform = CPlatform::allOs(); }
188 
189  CArtifact artifact(filename, version, {}, type, size, existing, platform);
190  artifact.setDistributions({ alpha ? alphaDistribution : betaDistribution });
191 
192  if (type == CArtifact::PilotClientInstaller) { result.m_artifactsPilotClient.push_back(artifact); }
193  else if (type == CArtifact::XSwiftBus) { result.m_artifactsXSwiftBus.push_back(artifact); }
194  }
195  }
196  return result;
197  }
198 } // namespace swift::misc::db
Platform (i.e.
Definition: platform.h:24
static const CPlatform & linuxPlatform()
Linux.
Definition: platform.cpp:193
static const CPlatform & macOSPlatform()
Mac OS.
Definition: platform.cpp:199
static const CPlatform & win32Platform()
Win32.
Definition: platform.cpp:181
static const CPlatform & currentPlatform()
Current platform.
Definition: platform.cpp:158
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.
CastType frontCasted() const
First element casted to given type, usually the PropertIndex enum.
bool isMyself() const
Myself index, used with nesting.
size_type size() const
Returns number of elements in the sequence.
Definition: sequence.h:273
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
bool isEmpty() const
Synonym for empty.
Definition: sequence.h:285
Artifacts ("our software" products)
Definition: artifact.h:23
bool isUnknown() const
Unknown.
Definition: artifact.h:71
void setDistributions(const CDistributionList &distributions)
Related distributions.
Definition: artifact.h:104
const CDistributionList & getDistributions() const
Related distributions.
Definition: artifact.h:98
void sortByVersion(Qt::SortOrder order=Qt::AscendingOrder)
Sort by version.
CArtifact findFirstByVersionOrDefault(const QVersionNumber &version) const
Find by version.
QVersionNumber getLatestQVersion() const
Latest version.
CArtifactList findMatchingForCurrentPlatform() const
Find for my platform.
CDistributionList getDistributions() const
All distributions related to these artifacts.
static CArtifactList fromDatabaseJson(const QJsonArray &array)
From database JSON by array.
Distributions for channel.
Definition: distribution.h:27
static const CDistribution & localDeveloperBuild()
Pseudo distribution for local builds.
void setDownloadUrl(const swift::misc::network::CUrl &url)
Set URL, ignored if empty.
Multiple distributions for different channels:
CDistribution getMostStableOrDefault() const
Most stable or default.
void sortByStability(Qt::SortOrder order=Qt::AscendingOrder)
Stability.
CDistribution getLeastStableOrDefault() const
Least stable or default.
static CDistributionList fromDatabaseJson(const QJsonArray &array)
From database JSON by array.
Update info, i.e. artifacts and distributions.
Definition: updateinfo.h:24
QVariant propertyByIndex(swift::misc::CPropertyIndexRef index) const
Property by index.
Definition: updateinfo.cpp:100
bool isEmpty() const
Empty (no data)
Definition: updateinfo.h:76
const CDistributionList & getDistributions() const
Distributions (all)
Definition: updateinfo.h:64
CArtifactList getArtifactsXSwiftBusLatestVersionFirst() const
Artifacts (xswiftbus)
Definition: updateinfo.cpp:42
QStringList anticipateMyDefaultChannelAndPlatform() const
Default channel, OS.
Definition: updateinfo.cpp:83
CDistribution anticipateOwnDistribution() const
Own distribution.
Definition: updateinfo.cpp:63
CDistributionList getDistributionsPilotClientForCurrentPlatform() const
Distributions for current platform.
Definition: updateinfo.cpp:27
static CUpdateInfo fromDatabaseJson(const QJsonObject &json, const QString &prefix={})
Object from database JSON format.
Definition: updateinfo.cpp:130
const CArtifactList & getArtifactsXSwiftBus() const
Artifacts (xswiftbus)
Definition: updateinfo.h:51
QString convertToQString(bool i18n=false) const
Cast as QString.
Definition: updateinfo.cpp:90
CArtifactList getArtifactsXSwiftBusOldestVersionFirst() const
Artifacts (xswiftbus)
Definition: updateinfo.cpp:49
CArtifactList getArtifactsXSwiftBusForCurrentPlatform() const
Artifacts for current platform.
Definition: updateinfo.cpp:56
const CArtifactList & getArtifactsPilotClient() const
Artifacts (pilot client)
Definition: updateinfo.h:44
CArtifactList getArtifactsPilotClientForCurrentPlatform() const
Artifacts for current platform.
Definition: updateinfo.cpp:35
ColumnIndex
Properties by index.
Definition: updateinfo.h:28
static CUpdateInfo fromGitHubReleasesJson(const QByteArray &jsonData)
Object from GitHub Releases REST API JSON format.
Definition: updateinfo.cpp:148
void setPropertyByIndex(swift::misc::CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: updateinfo.cpp:113
void setPropertyByIndex(CPropertyIndexRef index, const QVariant &variant)
Set property by index.
Definition: mixinindex.h:160
QVariant propertyByIndex(CPropertyIndexRef index) const
Property by index.
Definition: mixinindex.h:167
QString getClassName() const
Class name.
Definition: mixinmetatype.h:68
QString toQString(bool i18n=false) const
Cast as QString.
Definition: mixinstring.h:76
QJsonObject jsonObjectFromString(const QString &json, bool acceptCacheFormat)
JSON Object from string.
Definition: json.cpp:413
Plugin loaded by X-Plane which publishes a DBus service.
Definition: command.h:14
bool is09(const QChar &c)
Is 0-9 char, isDigit allows a bunch of more characters.
Definition: stringutils.h:154
bool containsChar(const QString &s, F predicate)
True if any character in the string matches the given predicate.
Definition: stringutils.h:65
#define SWIFT_DEFINE_VALUEOBJECT_MIXINS(Namespace, Class)
Explicit template definition of mixins for a CValueObject subclass.
Definition: valueobject.h:67