Skip to content

Latest commit

 

History

History
336 lines (277 loc) · 10.4 KB

ssukickstarter.cpp

File metadata and controls

336 lines (277 loc) · 10.4 KB
 
1
2
3
4
5
6
7
8
9
10
11
12
/**
* @file ssukickstarter.cpp
* @copyright 2013 Jolla Ltd.
* @author Bernd Wachter <bwachter@lart.info>
* @date 2013
*/
#include <QStringList>
#include <QRegExp>
#include <QDirIterator>
#include "ssukickstarter.h"
May 24, 2013
May 24, 2013
13
#include "libssu/sandbox_p.h"
Apr 5, 2013
Apr 5, 2013
14
15
#include "libssu/ssurepomanager.h"
#include "libssu/ssuvariables.h"
16
17
18
19
20
21
22
23
24
#include "../constants.h"
/* TODO:
* - commands from the command section should be verified
* - allow overriding brand key
*/
May 23, 2013
May 23, 2013
25
SsuKickstarter::SsuKickstarter() {
26
27
28
29
30
31
32
33
34
35
36
37
38
SsuDeviceInfo deviceInfo;
deviceModel = deviceInfo.deviceModel();
if ((ssu.deviceMode() & Ssu::RndMode) == Ssu::RndMode)
rndMode = true;
else
rndMode = false;
}
QStringList SsuKickstarter::commands(){
SsuDeviceInfo deviceInfo(deviceModel);
QStringList result;
Apr 5, 2013
Apr 5, 2013
39
40
41
QHash<QString, QString> h;
deviceInfo.variableSection("kickstart-commands", &h);
42
43
44
45
46
47
48
49
50
51
52
53
// read commands from variable, ...
QHash<QString, QString>::const_iterator it = h.constBegin();
while (it != h.constEnd()){
result.append(it.key() + " " + it.value());
it++;
}
return result;
}
Jun 13, 2013
Jun 13, 2013
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
QStringList SsuKickstarter::commandSection(const QString &section, const QString &description){
QStringList result;
SsuDeviceInfo deviceInfo(deviceModel);
QString commandFile;
QFile part;
QDir dir(Sandbox::map(QString("/%1/kickstart/%2/")
.arg(SSU_DATA_DIR)
.arg(section)));
if (dir.exists(replaceSpaces(deviceModel.toLower())))
commandFile = replaceSpaces(deviceModel.toLower());
else if (dir.exists(replaceSpaces(deviceInfo.deviceVariant(true).toLower())))
commandFile = replaceSpaces(deviceInfo.deviceVariant(true).toLower());
else if (dir.exists("default"))
commandFile = "default";
else {
if (description.isEmpty())
result.append("## No suitable configuration found in " + dir.path());
else
result.append("## No configuration for " + description + " found.");
return result;
}
QFile file(dir.path() + "/" + commandFile);
if (description.isEmpty())
result.append("### Commands from " + dir.path() + "/" + commandFile);
else
result.append("### " + description + " from " + commandFile);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
QTextStream in(&file);
while (!in.atEnd())
result.append(in.readLine());
}
return result;
}
QString SsuKickstarter::replaceSpaces(const QString &value){
QString retval = value;
return retval.replace(" ", "_");
}
99
100
101
102
QStringList SsuKickstarter::repos(){
QStringList result;
SsuDeviceInfo deviceInfo(deviceModel);
Jul 5, 2013
Jul 5, 2013
103
QStringList repos = deviceInfo.repos(rndMode, SsuRepoManager::BoardFilter);
104
105
106
foreach (const QString &repo, repos){
QString repoUrl = ssu.repoUrl(repo, rndMode, QHash<QString, QString>(), repoOverride);
Jun 12, 2013
Jun 12, 2013
107
108
109
// Adaptation repos need to have separate naming so that when images are done
// the repository caches will not be mixed with each other.
if (repo.startsWith("adaptation")) {
Apr 24, 2013
Apr 24, 2013
110
111
result.append(QString("repo --name=%1-%2-%3 --baseurl=%4")
.arg(repo)
Jun 13, 2013
Jun 13, 2013
112
.arg(replaceSpaces(deviceModel))
Apr 24, 2013
Apr 24, 2013
113
114
115
116
.arg((rndMode ? repoOverride.value("rndRelease")
: repoOverride.value("release")))
.arg(repoUrl)
);
Jun 12, 2013
Jun 12, 2013
117
}
Apr 24, 2013
Apr 24, 2013
118
119
120
121
122
123
124
else
result.append(QString("repo --name=%1-%2 --baseurl=%3")
.arg(repo)
.arg((rndMode ? repoOverride.value("rndRelease")
: repoOverride.value("release")))
.arg(repoUrl)
);
125
126
127
128
129
130
131
132
133
134
}
return result;
}
QStringList SsuKickstarter::packages(){
QStringList result;
// insert @vendor configuration device
QString configuration = QString("@%1 Configuration %2")
Jun 13, 2013
Jun 13, 2013
135
.arg(repoOverride.value("brand"))
136
137
138
139
140
141
142
143
144
145
146
.arg(deviceModel);
result.append(configuration);
result.sort();
result.removeDuplicates();
result.prepend("%packages");
result.append("%end");
return result;
}
// we intentionally don't support device-specific post scriptlets
Aug 30, 2013
Aug 30, 2013
147
QStringList SsuKickstarter::scriptletSection(QString name, int flags){
148
149
150
151
QStringList result;
QString path;
QDir dir;
Aug 30, 2013
Aug 30, 2013
152
153
if ((flags & NoChroot) == NoChroot)
path = Sandbox::map(QString("/%1/kickstart/%2_nochroot/")
154
.arg(SSU_DATA_DIR)
May 24, 2013
May 24, 2013
155
.arg(name));
156
else
Aug 30, 2013
Aug 30, 2013
157
path = Sandbox::map(QString("/%1/kickstart/%2/")
158
.arg(SSU_DATA_DIR)
May 24, 2013
May 24, 2013
159
.arg(name));
160
Aug 30, 2013
Aug 30, 2013
161
162
163
164
165
166
167
if ((flags & DeviceSpecific) == DeviceSpecific){
if (dir.exists(path + "/" + replaceSpaces(deviceModel.toLower())))
path = path + "/" + replaceSpaces(deviceModel.toLower());
else
path = path + "/default";
}
168
169
170
171
172
dir.setPath(path);
QStringList scriptlets = dir.entryList(QDir::AllEntries|QDir::NoDot|QDir::NoDotDot,
QDir::Name);
foreach (const QString &scriptlet, scriptlets){
May 27, 2013
May 27, 2013
173
QFile file(dir.filePath(scriptlet));
174
175
176
177
178
179
180
181
182
183
result.append("### begin " + scriptlet);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)){
QTextStream in(&file);
while (!in.atEnd())
result.append(in.readLine());
}
result.append("### end " + scriptlet);
}
if (!result.isEmpty()){
Apr 2, 2013
Apr 2, 2013
184
185
186
result.prepend(QString("export SSU_RELEASE_TYPE=%1")
.arg(rndMode ? "rnd" : "release"));
Aug 30, 2013
Aug 30, 2013
187
if ((flags & NoChroot) == NoChroot)
188
result.prepend("%" + name + " --nochroot");
Aug 30, 2013
Aug 30, 2013
189
190
191
else
result.prepend("%" + name);
192
193
194
195
196
197
198
199
200
201
202
203
204
result.append("%end");
}
return result;
}
void SsuKickstarter::setRepoParameters(QHash<QString, QString> parameters){
repoOverride = parameters;
if (repoOverride.contains("model"))
deviceModel = repoOverride.value("model");
}
Apr 5, 2013
Apr 5, 2013
205
bool SsuKickstarter::write(QString kickstart){
206
207
QFile ks;
QTextStream kout;
Apr 5, 2013
Apr 5, 2013
208
209
210
211
QTextStream qerr(stderr);
SsuDeviceInfo deviceInfo(deviceModel);
SsuRepoManager repoManager;
SsuVariables var;
Jun 13, 2013
Jun 13, 2013
212
213
214
215
216
217
QStringList commandSections;
// initialize with default 'part' for compatibility, as partitions
// used to work without configuration. It'll get replaced with
// configuration values, if found
commandSections.append("part");
218
Apr 5, 2013
Apr 5, 2013
219
220
221
222
223
224
// rnd mode should not come from the defaults
if (repoOverride.contains("rnd")){
if (repoOverride.value("rnd") == "true")
rndMode = true;
else if (repoOverride.value("rnd") == "false")
rndMode = false;
225
226
}
Apr 5, 2013
Apr 5, 2013
227
228
229
230
231
232
233
QHash<QString, QString> defaults;
// get generic repo variables; domain and adaptation specific bits are not interesting
// in the kickstart
repoManager.repoVariables(&defaults, rndMode);
// overwrite with kickstart defaults
deviceInfo.variableSection("kickstart-defaults", &defaults);
Jun 13, 2013
Jun 13, 2013
234
235
236
237
238
if (deviceInfo.variable("kickstart-defaults", "commandSections")
.canConvert(QMetaType::QStringList)){
commandSections =
deviceInfo.variable("kickstart-defaults", "commandSections").toStringList();
}
239
240
241
242
243
244
245
246
QHash<QString, QString>::const_iterator it = defaults.constBegin();
while (it != defaults.constEnd()){
if (!repoOverride.contains(it.key()))
repoOverride.insert(it.key(), it.value());
it++;
}
Apr 1, 2013
Apr 1, 2013
247
248
249
250
251
// in rnd mode both rndRelease an release should be the same,
// as the variable name used is %(release)
if (rndMode && repoOverride.contains("rndRelease"))
repoOverride.insert("release", repoOverride.value("rndRelease"));
Apr 5, 2013
Apr 5, 2013
252
253
254
255
256
257
258
259
// release mode variables should not contain flavourName
if (!rndMode && repoOverride.contains("flavourName"))
repoOverride.remove("flavourName");
//TODO: check for mandatory keys, brand, ..
if (!repoOverride.contains("deviceModel"))
repoOverride.insert("deviceModel", deviceInfo.deviceModel());
Jun 13, 2013
Jun 13, 2013
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// do sanity checking on the model
if (deviceInfo.contains() == false) {
qerr << "Device model '" << deviceInfo.deviceModel() << "' does not exist" << endl;
if (repoOverride.value("force") != "true")
return false;
}
QRegExp regex(" {2,}", Qt::CaseSensitive, QRegExp::RegExp2);
if (regex.indexIn(deviceInfo.deviceModel(), 0) != -1){
qerr << "Device model '" << deviceInfo.deviceModel()
<< "' contains multiple consecutive spaces." << endl;
if (deviceInfo.contains())
qerr << "Since the model exists it looks like your configuration is broken." << endl;
return false;
}
Jun 13, 2013
Jun 13, 2013
277
278
279
280
281
if (!repoOverride.contains("brand")){
qerr << "No brand set. Check your configuration." << endl;
return false;
}
Apr 6, 2013
Apr 6, 2013
282
283
284
285
bool opened = false;
QString outputDir = repoOverride.value("outputdir");
if (!outputDir.isEmpty()) outputDir.append("/");
Apr 5, 2013
Apr 5, 2013
286
287
if (kickstart.isEmpty()){
if (repoOverride.contains("filename")){
Apr 6, 2013
Apr 6, 2013
288
QString fileName = QString("%1%2")
Jun 13, 2013
Jun 13, 2013
289
290
291
.arg(outputDir)
.arg(replaceSpaces(var.resolveString(repoOverride.value("filename"),
&repoOverride)));
Apr 5, 2013
Apr 5, 2013
292
Apr 5, 2013
Apr 5, 2013
293
ks.setFileName(fileName);
Apr 6, 2013
Apr 6, 2013
294
opened = ks.open(QIODevice::WriteOnly);
Apr 5, 2013
Apr 5, 2013
295
296
297
298
299
} else {
qerr << "No filename specified, and no default filename configured" << endl;
return false;
}
} else if (kickstart == "-")
Apr 6, 2013
Apr 6, 2013
300
opened = ks.open(stdout, QIODevice::WriteOnly);
Apr 5, 2013
Apr 5, 2013
301
else {
Apr 6, 2013
Apr 6, 2013
302
303
304
305
306
307
308
ks.setFileName(outputDir + kickstart);
opened = ks.open(QIODevice::WriteOnly);
}
if (!opened) {
qerr << "Unable to write output file " << ks.fileName() << ": " << ks.errorString() << endl;
return false;
Jun 13, 2013
Jun 13, 2013
309
310
} else if (!ks.fileName().isEmpty())
qerr << "Writing kickstart to " << ks.fileName() << endl;
Apr 5, 2013
Apr 5, 2013
311
Apr 5, 2013
Apr 5, 2013
312
313
314
315
316
317
318
319
QString displayName = QString("# DisplayName: %1 %2/%3 (%4) %5")
.arg(repoOverride.value("brand"))
.arg(deviceInfo.deviceModel())
.arg(repoOverride.value("arch"))
.arg((rndMode ? "rnd"
: "release"))
.arg(repoOverride.value("version"));
Apr 5, 2013
Apr 5, 2013
320
kout.setDevice(&ks);
Apr 5, 2013
Apr 5, 2013
321
kout << displayName << endl << endl;
322
kout << commands().join("\n") << endl << endl;
Jun 13, 2013
Jun 13, 2013
323
324
325
foreach (const QString &section, commandSections){
kout << commandSection(section).join("\n") << endl << endl;
}
326
327
kout << repos().join("\n") << endl << endl;
kout << packages().join("\n") << endl << endl;
Aug 30, 2013
Aug 30, 2013
328
329
330
331
332
// TODO: now that extending scriptlet section is might make sense to make it configurable
kout << scriptletSection("pre", Chroot).join("\n") << endl << endl;
kout << scriptletSection("post", Chroot).join("\n") << endl << endl;
kout << scriptletSection("post", NoChroot).join("\n") << endl << endl;
kout << scriptletSection("pack", DeviceSpecific).join("\n") << endl << endl;
333
// POST, die-on-error
Apr 5, 2013
Apr 5, 2013
334
335
return true;
336
}