10 #include <QDirIterator>
17 #include "../constants.h"
24 SsuKickstarter::SsuKickstarter()
35 QStringList SsuKickstarter::commands()
40 QHash<QString, QString> h;
46 QHash<QString, QString>::const_iterator it = h.constBegin();
47 while (it != h.constEnd()) {
48 result.append(it.key() +
" " + it.value());
55 QStringList SsuKickstarter::commandSection(
const QString §ion,
const QString &description)
62 QDir dir(Sandbox::map(QString(
"/%1/kickstart/%2/")
66 if (dir.exists(replaceSpaces(deviceModel.toLower()))) {
67 commandFile = replaceSpaces(deviceModel.toLower());
68 }
else if (dir.exists(replaceSpaces(deviceInfo.
deviceVariant(
true).toLower()))) {
69 commandFile = replaceSpaces(deviceInfo.
deviceVariant(
true).toLower());
70 }
else if (dir.exists(
"default")) {
71 commandFile =
"default";
73 if (description.isEmpty())
74 result.append(
"## No suitable configuration found in " + dir.path());
76 result.append(
"## No configuration for " + description +
" found.");
80 QFile file(dir.path() +
"/" + commandFile);
82 if (description.isEmpty())
83 result.append(
"### Commands from " + dir.path() +
"/" + commandFile);
85 result.append(
"### " + description +
" from " + commandFile);
87 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
88 QTextStream in(&file);
90 result.append(in.readLine());
96 QString SsuKickstarter::replaceSpaces(
const QString &value)
98 QString retval = value;
99 return retval.replace(
" ",
"_");
102 QStringList SsuKickstarter::repos()
107 QTextStream qerr(stderr);
111 foreach (
const QString &repo, repos) {
112 QString repoUrl = ssu.
repoUrl(repo, rndMode, QHash<QString, QString>(), repoOverride);
114 if (repoUrl.isEmpty()) {
115 qerr <<
"Repository " << repo <<
" does not have an URL, ignoring" << endl;
121 if (repo.startsWith(
"adaptation")) {
122 result.append(QString(
"repo --name=%1-%2-%3%4 --baseurl=%5")
124 .arg(replaceSpaces(deviceModel))
125 .arg((rndMode ? repoOverride.value(
"rndRelease")
126 : repoOverride.value(
"release")))
127 .arg((rndMode ?
"-" + repoOverride.value(
"flavourName")
132 result.append(QString(
"repo --name=%1-%2%3 --baseurl=%4")
134 .arg((rndMode ? repoOverride.value(
"rndRelease")
135 : repoOverride.value(
"release")))
136 .arg((rndMode ?
"-" + repoOverride.value(
"flavourName")
146 QStringList SsuKickstarter::packagesSection(
const QString &name)
150 if (name ==
"packages") {
152 QString configuration = QString(
"@%1 Configuration %2")
153 .arg(repoOverride.value(
"brand"))
155 result.append(configuration);
158 result.removeDuplicates();
160 result = commandSection(name);
163 result.prepend(
"%" + name);
164 result.append(
"%end");
169 QStringList SsuKickstarter::scriptletSection(
const QString &name,
int flags)
175 if ((flags & NoChroot) == NoChroot)
176 path = Sandbox::map(QString(
"/%1/kickstart/%2_nochroot/")
180 path = Sandbox::map(QString(
"/%1/kickstart/%2/")
184 if ((flags & DeviceSpecific) == DeviceSpecific) {
185 if (dir.exists(path +
"/" + replaceSpaces(deviceModel.toLower())))
186 path = path +
"/" + replaceSpaces(deviceModel.toLower());
188 path = path +
"/default";
192 QStringList scriptlets = dir.entryList(QDir::AllEntries | QDir::NoDot | QDir::NoDotDot,
195 foreach (
const QString &scriptlet, scriptlets) {
196 QFile file(dir.filePath(scriptlet));
197 result.append(
"### begin " + scriptlet);
198 if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
199 QTextStream in(&file);
201 result.append(in.readLine());
203 result.append(
"### end " + scriptlet);
206 if (!result.isEmpty()) {
207 result.prepend(QString(
"export SSU_RELEASE_TYPE=%1")
208 .arg(rndMode ?
"rnd" :
"release"));
210 if ((flags & NoChroot) == NoChroot)
211 result.prepend(
"%" + name +
" --nochroot --erroronfail");
213 result.prepend(
"%" + name +
" --erroronfail");
215 result.append(
"%end");
221 void SsuKickstarter::setRepoParameters(QHash<QString, QString> parameters)
223 repoOverride = parameters;
225 if (repoOverride.contains(
"model"))
226 deviceModel = repoOverride.value(
"model");
229 bool SsuKickstarter::write(
const QString &kickstart)
231 QTextStream qerr(stderr);
232 QStringList commandSections;
237 commandSections.append(
"part");
240 if (repoOverride.contains(
"rnd")) {
241 if (repoOverride.value(
"rnd") ==
"true")
243 else if (repoOverride.value(
"rnd") ==
"false")
247 if (repoOverride.contains(
"domain")) {
248 ssu.
setDomain(repoOverride.value(
"domain"));
251 QHash<QString, QString> defaults;
259 if (deviceInfo.
variable(
"kickstart-defaults",
"commandSections")
260 .canConvert(QMetaType::QStringList)) {
262 deviceInfo.
variable(
"kickstart-defaults",
"commandSections").toStringList();
265 QHash<QString, QString>::const_iterator it = defaults.constBegin();
266 while (it != defaults.constEnd()) {
267 if (!repoOverride.contains(it.key()))
268 repoOverride.insert(it.key(), it.value());
274 if (rndMode && repoOverride.contains(
"rndRelease"))
275 repoOverride.insert(
"release", repoOverride.value(
"rndRelease"));
278 if (!rndMode && repoOverride.contains(
"flavourName"))
279 repoOverride.remove(
"flavourName");
282 if (!repoOverride.contains(
"deviceModel"))
283 repoOverride.insert(
"deviceModel", deviceInfo.
deviceModel());
286 if (deviceInfo.
contains() ==
false) {
287 qerr <<
"Device model '" << deviceInfo.
deviceModel() <<
"' does not exist" << endl;
289 if (repoOverride.value(
"force") !=
"true")
293 QRegExp regex(
" {2,}", Qt::CaseSensitive, QRegExp::RegExp2);
294 if (regex.indexIn(deviceInfo.
deviceModel(), 0) != -1) {
295 qerr <<
"Device model '" << deviceInfo.
deviceModel()
296 <<
"' contains multiple consecutive spaces." << endl;
298 qerr <<
"Since the model exists it looks like your configuration is broken." << endl;
302 if (!repoOverride.contains(
"brand")) {
303 qerr <<
"Brand is missing in your configuration." << endl;
308 QString outputDir = repoOverride.value(
"outputdir");
309 if (!outputDir.isEmpty()) outputDir.append(
"/");
313 if (kickstart.isEmpty()) {
316 if (repoOverride.contains(
"filename")) {
317 QString fileName = QString(
"%1%2")
319 .arg(replaceSpaces(var.
resolveString(repoOverride.value(
"filename"),
322 ks.setFileName(fileName);
323 opened = ks.open(QIODevice::WriteOnly);
325 qerr <<
"No filename specified, and no default filename configured" << endl;
328 }
else if (kickstart ==
"-") {
329 opened = ks.open(stdout, QIODevice::WriteOnly);
331 ks.setFileName(outputDir + kickstart);
332 opened = ks.open(QIODevice::WriteOnly);
336 qerr <<
"Unable to write output file " << ks.fileName() <<
": " << ks.errorString() << endl;
338 }
else if (!ks.fileName().isEmpty()) {
339 qerr <<
"Writing kickstart to " << ks.fileName() << endl;
342 QString displayName = QString(
"# DisplayName: %1 %2/%3 (%4) %5")
343 .arg(repoOverride.value(
"brand"))
345 .arg(repoOverride.value(
"arch"))
346 .arg((rndMode ?
"rnd"
348 .arg(repoOverride.value(
"version"));
351 QStringList featuresList = deviceInfo.
value(
"img-features").toStringList();
354 if (rndMode && !featuresList.contains(
"-developer-mode"))
355 featuresList <<
"developer-mode";
357 featuresList = featuresList.filter(QRegExp(
"^[^-]"));
359 QString suggestedFeatures;
362 if (featuresList.count() == 1)
363 suggestedFeatures = QString(
"# SuggestedFeatures: %1,")
364 .arg(featuresList.join(
", "));
365 else if (featuresList.count() > 1)
366 suggestedFeatures = QString(
"# SuggestedFeatures: %1")
367 .arg(featuresList.join(
", "));
369 QString imageType =
"fs";
370 if (!deviceInfo.
value(
"img-type").toString().isEmpty())
371 imageType = deviceInfo.
value(
"img-type").toString();
373 QString imageArchitecture =
"armv7hl";
374 if (!deviceInfo.
value(
"img-arch").toString().isEmpty())
375 imageArchitecture = deviceInfo.
value(
"img-arch").toString();
377 QString kickstartType = QString(
"# KickstartType: %1")
378 .arg((rndMode ?
"rnd" :
"release"));
380 const QString deviceModel = deviceInfo.
deviceModel();
384 kout << displayName << endl;
385 kout << kickstartType << endl;
386 kout <<
"# DeviceModel: " << deviceModel << endl;
387 kout <<
"# DeviceVariant: " << deviceInfo.
deviceVariant(
true) << endl;
388 kout <<
"# Brand: " << repoOverride.value(
"brand") << endl;
391 for (
auto const &repo : deviceInfo.
value(
"repository-specific-variables").toStringList()) {
392 if (!repo.startsWith(deviceModel +
'-'))
395 QHash<QString, QString> section;
397 for (
auto var = section.cbegin(); var != section.cend(); ++var)
398 kout <<
"# Var@" << repo.mid(deviceModel.size() + 1) <<
'@' << var.key() <<
": " << var.value() << endl;
401 if (!suggestedFeatures.isEmpty())
402 kout << suggestedFeatures << endl;
403 kout <<
"# SuggestedImageType: " << imageType << endl;
404 kout <<
"# SuggestedArchitecture: " << imageArchitecture << endl << endl;
405 kout << commands().join(
"\n") << endl << endl;
406 foreach (
const QString §ion, commandSections) {
407 kout << commandSection(section).join(
"\n") << endl << endl;
414 QString repoSection = repos().join(
"\n");
415 if (deviceInfo.
variable(
"kickstart-defaults",
"urlPostprocess")
416 .canConvert(QMetaType::QVariantHash)) {
417 QHash<QString, QVariant> postproc =
418 deviceInfo.
variable(
"kickstart-defaults",
"urlPostprocess").toHash();
420 QHash<QString, QVariant>::const_iterator it = postproc.constBegin();
421 while (it != postproc.constEnd()) {
422 QRegExp regex(it.key(), Qt::CaseSensitive, QRegExp::RegExp2);
424 repoSection.replace(regex, it.value().toString());
429 kout << repoSection << endl << endl;
430 kout << packagesSection(
"packages").join(
"\n") << endl << endl;
431 kout << packagesSection(
"attachment").join(
"\n") << endl << endl;
433 kout << scriptletSection(
"pre",
Chroot).join(
"\n") << endl << endl;
434 kout << scriptletSection(
"post",
Chroot).join(
"\n") << endl << endl;
435 kout << scriptletSection(
"post", NoChroot).join(
"\n") << endl << endl;
436 kout << scriptletSection(
"pack", DeviceSpecific).join(
"\n") << endl << endl;