Changeset View
Changeset View
Standalone View
Standalone View
Modules/about-distro/src/OSRelease.cpp
Show All 19 Lines | |||||
20 | 20 | | |||
21 | #include "OSRelease.h" | 21 | #include "OSRelease.h" | ||
22 | 22 | | |||
23 | #include <QDebug> | 23 | #include <QDebug> | ||
24 | #include <QFile> | 24 | #include <QFile> | ||
25 | 25 | | |||
26 | #include <KShell> | 26 | #include <KShell> | ||
27 | 27 | | |||
28 | // Sets a QString var | ||||
28 | static void setVar(QString *var, const QString &value) | 29 | static void setVar(QString *var, const QString &value) | ||
29 | { | 30 | { | ||
30 | // Values may contain quotation marks, strip them as we have no use for them. | 31 | // Values may contain quotation marks, strip them as we have no use for them. | ||
31 | KShell::Errors error; | 32 | KShell::Errors error; | ||
32 | QStringList args = KShell::splitArgs(value, KShell::NoOptions, &error); | 33 | QStringList args = KShell::splitArgs(value, KShell::NoOptions, &error); | ||
33 | if (error != KShell::NoError) { // Failed to parse. | 34 | if (error != KShell::NoError) { // Failed to parse. | ||
34 | return; | 35 | return; | ||
35 | } | 36 | } | ||
36 | *var = args.join(QLatin1Char(' ')); | 37 | *var = args.join(QLatin1Char(' ')); | ||
37 | } | 38 | } | ||
38 | 39 | | |||
40 | // Sets a QStringList var (i.e. splits a string value) | ||||
39 | static void setVar(QStringList *var, const QString &value) | 41 | static void setVar(QStringList *var, const QString &value) | ||
40 | { | 42 | { | ||
41 | // Instead of passing the verbatim value we manually strip any initial quotes | 43 | // Instead of passing the verbatim value we manually strip any initial quotes | ||
42 | // and then run it through KShell. At this point KShell will actually split | 44 | // and then run it through KShell. At this point KShell will actually split | ||
43 | // by spaces giving us the final QStringList. | 45 | // by spaces giving us the final QStringList. | ||
44 | // NOTE: Splitting like this does not actually allow escaped substrings to | 46 | // NOTE: Splitting like this does not actually allow escaped substrings to | ||
45 | // be handled correctly, so "kitteh \"french fries\"" would result in | 47 | // be handled correctly, so "kitteh \"french fries\"" would result in | ||
46 | // three list entries. I'd argue that if someone makes an id like that | 48 | // three list entries. I'd argue that if someone makes an id like that | ||
47 | // they are at fault for the bogus parsing here though as id explicitly | 49 | // they are at fault for the bogus parsing here though as id explicitly | ||
48 | // is required to not contain spaces even if more advanced shell escaping | 50 | // is required to not contain spaces even if more advanced shell escaping | ||
49 | // is also allowed... | 51 | // is also allowed... | ||
50 | QString value_ = value; | 52 | QString value_ = value; | ||
51 | if (value_.at(0) == QLatin1Char('"') && value_.at(value_.size()-1) == QLatin1Char('"')) { | 53 | if (value_.at(0) == QLatin1Char('"') && value_.at(value_.size()-1) == QLatin1Char('"')) { | ||
52 | value_.remove(0, 1); | 54 | value_.remove(0, 1); | ||
53 | value_.remove(-1, 1); | 55 | value_.remove(-1, 1); | ||
54 | } | 56 | } | ||
55 | KShell::Errors error; | 57 | KShell::Errors error; | ||
56 | QStringList args = KShell::splitArgs(value_, KShell::NoOptions, &error); | 58 | QStringList args = KShell::splitArgs(value_, KShell::NoOptions, &error); | ||
57 | if (error != KShell::NoError) { // Failed to parse. | 59 | if (error != KShell::NoError) { // Failed to parse. | ||
58 | return; | 60 | return; | ||
59 | } | 61 | } | ||
60 | *var = args; | 62 | *var = args; | ||
61 | } | 63 | } | ||
62 | 64 | | |||
63 | OSRelease::OSRelease(const QString &filePath) | 65 | class Q_DECL_HIDDEN OSRelease::Private | ||
66 | { | ||||
67 | public: | ||||
68 | Private(const QString &filePath) | ||||
69 | : name(QStringLiteral("Linux")) | ||||
70 | , id(QStringLiteral("linux")) | ||||
71 | , prettyName(QStringLiteral("Linux")) | ||||
64 | { | 72 | { | ||
65 | // Set default values for non-optional fields. | 73 | // Default values for non-optional fields set above ^. | ||
66 | name = QStringLiteral("Linux"); | | |||
67 | id = QStringLiteral("linux"); | | |||
68 | prettyName = QStringLiteral("Linux"); | | |||
69 | 74 | | |||
70 | if (filePath.isEmpty()) { | 75 | if (filePath.isEmpty()) { | ||
71 | return; | 76 | return; | ||
72 | } | 77 | } | ||
73 | 78 | | |||
74 | QHash<QString, QString *> stringHash = { | 79 | QHash<QString, QString *> stringHash = { | ||
75 | { QStringLiteral("NAME"), &name }, | 80 | { QStringLiteral("NAME"), &name }, | ||
76 | { QStringLiteral("VERSION"), &version }, | 81 | { QStringLiteral("VERSION"), &version }, | ||
Show All 18 Lines | |||||
95 | QFile file(filePath); | 100 | QFile file(filePath); | ||
96 | // NOTE: The os-release specification defines default values for specific | 101 | // NOTE: The os-release specification defines default values for specific | ||
97 | // fields which means that even if we can not read the os-release file | 102 | // fields which means that even if we can not read the os-release file | ||
98 | // we have sort of expected default values to use. | 103 | // we have sort of expected default values to use. | ||
99 | // TODO: it might still be handy to indicate to the outside whether | 104 | // TODO: it might still be handy to indicate to the outside whether | ||
100 | // fallback values are being used or not. | 105 | // fallback values are being used or not. | ||
101 | file.open(QIODevice::ReadOnly | QIODevice::Text); | 106 | file.open(QIODevice::ReadOnly | QIODevice::Text); | ||
102 | QString line; | 107 | QString line; | ||
103 | QStringList comps; | 108 | QStringList parts; | ||
104 | while (!file.atEnd()) { | 109 | while (!file.atEnd()) { | ||
105 | line = QString::fromLatin1(file.readLine()); | 110 | // Trimmed to handle indented comment lines properly | ||
111 | line = QString::fromLatin1(file.readLine()).trimmed(); | ||||
106 | 112 | | |||
107 | if (line.startsWith(QLatin1Char('#'))) { | 113 | if (line.startsWith(QLatin1Char('#'))) { | ||
108 | // Comment line | 114 | // Comment line | ||
109 | continue; | 115 | continue; | ||
110 | } | 116 | } | ||
111 | 117 | | |||
112 | comps = line.split(QLatin1Char('=')); | 118 | parts = line.split(QLatin1Char('=')); | ||
113 | 119 | | |||
114 | if (comps.size() != 2) { | 120 | if (parts.size() != 2 || line.contains(QChar('#'))) { | ||
115 | // Invalid line. | 121 | // Invalid line... | ||
122 | // For the purposes of simple parsing we'll not support >2 = | ||||
123 | // or >1 # characters. | ||||
124 | // The former makes splitting and the latter makes comment | ||||
125 | // stripping difficult. | ||||
116 | continue; | 126 | continue; | ||
117 | } | 127 | } | ||
118 | 128 | | |||
119 | QString key = comps.at(0); | 129 | QString key = parts.at(0); | ||
120 | QString value = comps.at(1).trimmed(); | 130 | QString value = parts.at(1).trimmed(); | ||
121 | 131 | | |||
122 | if (QString *var = stringHash.value(key, nullptr)) { | 132 | if (QString *var = stringHash.value(key, nullptr)) { | ||
123 | setVar(var, value); | 133 | setVar(var, value); | ||
134 | continue; | ||||
124 | } | 135 | } | ||
125 | 136 | | |||
126 | // ID_LIKE is a list and parsed as such (rather than a QString). | 137 | // ID_LIKE is a list and parsed as such (rather than a QString). | ||
127 | if (key == QLatin1String("ID_LIKE")) { | 138 | if (key == QLatin1String("ID_LIKE")) { | ||
128 | setVar(&idLike, value); | 139 | setVar(&idLike, value); | ||
140 | continue; | ||||
129 | } | 141 | } | ||
130 | 142 | | |||
131 | // os-release explicitly allows for vendor specific aditions. We have no | 143 | // os-release explicitly allows for vendor specific aditions. We have no | ||
132 | // interest in those right now. | 144 | // interest in those right now. | ||
133 | } | 145 | } | ||
134 | } | 146 | } | ||
135 | 147 | | |||
148 | QString name; | ||||
149 | QString version; | ||||
150 | QString id; | ||||
151 | QStringList idLike; | ||||
152 | QString versionCodename; | ||||
153 | QString versionId; | ||||
154 | QString prettyName; | ||||
155 | QString ansiColor; | ||||
156 | QString cpeName; | ||||
157 | QString homeUrl; | ||||
158 | QString documentationUrl; | ||||
159 | QString supportUrl; | ||||
160 | QString bugReportUrl; | ||||
161 | QString privacyPolicyUrl; | ||||
162 | QString buildId; | ||||
163 | QString variant; | ||||
164 | QString variantId; | ||||
165 | QString logo; | ||||
166 | }; | ||||
167 | | ||||
168 | OSRelease::OSRelease(const QString &filePath) | ||||
169 | : d(new Private(filePath)) | ||||
170 | { | ||||
171 | } | ||||
172 | | ||||
173 | OSRelease::~OSRelease() | ||||
174 | { | ||||
175 | delete d; | ||||
176 | } | ||||
177 | | ||||
178 | QString OSRelease::name() const | ||||
179 | { | ||||
180 | return d->name; | ||||
181 | } | ||||
182 | | ||||
183 | QString OSRelease::version() const | ||||
184 | { | ||||
185 | return d->version; | ||||
186 | } | ||||
187 | | ||||
188 | QString OSRelease::id() const | ||||
189 | { | ||||
190 | return d->id; | ||||
191 | } | ||||
192 | | ||||
193 | QStringList OSRelease::idLike() const | ||||
194 | { | ||||
195 | return d->idLike; | ||||
196 | } | ||||
197 | | ||||
198 | QString OSRelease::versionCodename() const | ||||
199 | { | ||||
200 | return d->versionCodename; | ||||
201 | } | ||||
202 | | ||||
203 | QString OSRelease::versionId() const | ||||
204 | { | ||||
205 | return d->versionId; | ||||
206 | } | ||||
207 | | ||||
208 | QString OSRelease::prettyName() const | ||||
209 | { | ||||
210 | return d->prettyName; | ||||
211 | } | ||||
212 | | ||||
213 | QString OSRelease::ansiColor() const | ||||
214 | { | ||||
215 | return d->ansiColor; | ||||
216 | } | ||||
217 | | ||||
218 | QString OSRelease::cpeName() const | ||||
219 | { | ||||
220 | return d->cpeName; | ||||
221 | } | ||||
222 | | ||||
223 | QString OSRelease::homeUrl() const | ||||
224 | { | ||||
225 | return d->homeUrl; | ||||
226 | } | ||||
227 | | ||||
228 | QString OSRelease::documentationUrl() const | ||||
229 | { | ||||
230 | return d->documentationUrl; | ||||
231 | } | ||||
232 | | ||||
233 | QString OSRelease::supportUrl() const | ||||
234 | { | ||||
235 | return d->supportUrl; | ||||
236 | } | ||||
237 | | ||||
238 | QString OSRelease::bugReportUrl() const | ||||
239 | { | ||||
240 | return d->bugReportUrl; | ||||
241 | } | ||||
242 | | ||||
243 | QString OSRelease::privacyPolicyUrl() const | ||||
244 | { | ||||
245 | return d->privacyPolicyUrl; | ||||
246 | } | ||||
247 | | ||||
248 | QString OSRelease::buildId() const | ||||
249 | { | ||||
250 | return d->buildId; | ||||
251 | } | ||||
252 | | ||||
253 | QString OSRelease::variant() const | ||||
254 | { | ||||
255 | return d->variant; | ||||
256 | } | ||||
257 | | ||||
258 | QString OSRelease::variantId() const | ||||
259 | { | ||||
260 | return d->variantId; | ||||
261 | } | ||||
262 | | ||||
263 | QString OSRelease::logo() const | ||||
264 | { | ||||
265 | return d->logo; | ||||
266 | } | ||||
267 | | ||||
136 | QString OSRelease::defaultFilePath() | 268 | QString OSRelease::defaultFilePath() | ||
137 | { | 269 | { | ||
138 | if (QFile::exists(QStringLiteral("/etc/os-release"))) { | 270 | if (QFile::exists(QStringLiteral("/etc/os-release"))) { | ||
139 | return QStringLiteral("/etc/os-release"); | 271 | return QStringLiteral("/etc/os-release"); | ||
140 | } else if (QFile::exists(QStringLiteral("/usr/lib/os-release"))) { | 272 | } else if (QFile::exists(QStringLiteral("/usr/lib/os-release"))) { | ||
141 | return QStringLiteral("/usr/lib/os-release"); | 273 | return QStringLiteral("/usr/lib/os-release"); | ||
142 | } else { | 274 | } else { | ||
143 | return QString(); | 275 | return QString(); | ||
144 | } | 276 | } | ||
145 | } | 277 | } |