diff --git a/constants.h b/constants.h index 0826cc8..c4e4be6 100644 --- a/constants.h +++ b/constants.h @@ -16,6 +16,8 @@ #define SSU_BOARD_MAPPING_CONFIGURATION "/usr/share/ssu/board-mappings.ini" /// Path to config.d for board mappings #define SSU_BOARD_MAPPING_CONFIGURATION_DIR "/usr/share/ssu/board-mappings.d" +/// Directory where all the non-user modifiable data sits +#define SSU_DATA_DIR "/usr/share/ssu/" /// The SSU protocol version used by the ssu client libraries #define SSU_PROTOCOL_VERSION "1" /// Maximum recursion level for resolving variables diff --git a/rpm/ssu.changes b/rpm/ssu.changes index bd17994..d484fca 100644 --- a/rpm/ssu.changes +++ b/rpm/ssu.changes @@ -1,3 +1,6 @@ +* Mon Apr 01 2013 Bernd Wachter - 0.29 +- Add prototype kickstart generator + * Sun Mar 31 2013 Bernd Wachter - 0.28.1 - Enable repo listing for ssu CLI diff --git a/rpm/ssu.spec b/rpm/ssu.spec index d8bb2e2..a8c7a9f 100644 --- a/rpm/ssu.spec +++ b/rpm/ssu.spec @@ -1,5 +1,5 @@ Name: ssu -Version: 0.28.1 +Version: 0.29 Release: 1 Summary: SSU enabler for RND Group: System/Base @@ -45,6 +45,18 @@ Group: System/Base %{_datadir}/ssu/*.ini +%package ks +Summary: Kickstart generator using %{name} data +Group: System/Base + +%description ks +%{summary}. With ponies! + +%files ks +%defattr(-,root,root,-) +%{_bindir}/ssuks + + %package rnd-ui Summary: Shiny user interface for %{name} Group: System/Base diff --git a/ssu.pro b/ssu.pro index 3341a45..46523be 100644 --- a/ssu.pro +++ b/ssu.pro @@ -4,7 +4,7 @@ contains(QT_VERSION, ^4\\.[0-7]\\..*) { TEMPLATE = subdirs SUBDIRS = libssu -SUBDIRS += rndssucli rndregisterui ssuurlresolver +SUBDIRS += rndssucli rndregisterui ssuurlresolver ssuks ssuconfhack { SUBDIRS += ssuconfperm @@ -16,6 +16,7 @@ rndssucli.depends = libssu rndregisterui.depends = libssu ssuurlresolver.depends = libssu tests.depends = libssu +ssuks.depends = libssu config.files = ssu.ini config.path = /etc/ssu diff --git a/ssuks/ssukickstarter.cpp b/ssuks/ssukickstarter.cpp new file mode 100644 index 0000000..f7f4582 --- /dev/null +++ b/ssuks/ssukickstarter.cpp @@ -0,0 +1,205 @@ +/** + * @file ssukickstarter.cpp + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#include +#include +#include + +#include "ssukickstarter.h" + +#include "../constants.h" + +/* TODO: + * - rnd/release handling. + * repo --name=adaptation0-@RNDRELEASE@ + * --baseurl=https://releases.jollamobile.com/nemo/@RELEASE@-devel/adaptation-n9xx-common/@ARCH@/ + * @RELEASE@ should be @RNDRELEASE@ in this case as well + * - commands from the command section should be verified + * - go through the variable lookup process for non-url variables as well + * - allow overriding brand key + * - use (and expand) filename key if no filename is given on command line + */ + + +SsuKickstarter::SsuKickstarter() { + 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; + + QHash h = deviceInfo.variableSection("kickstart-commands"); + + // read commands from variable, ... + + QHash::const_iterator it = h.constBegin(); + while (it != h.constEnd()){ + result.append(it.key() + " " + it.value()); + it++; + } + + return result; +} + +QStringList SsuKickstarter::repos(){ + QStringList result; + SsuDeviceInfo deviceInfo(deviceModel); + + QStringList repos = deviceInfo.repos(rndMode, SsuDeviceInfo::BoardFilter); + + foreach (const QString &repo, repos){ + QString repoUrl = ssu.repoUrl(repo, rndMode, QHash(), repoOverride); + result.append(QString("repo --name=%1-%2 --baseurl=%3") + .arg(repo) + .arg((rndMode ? repoOverride.value("rndRelease") + : repoOverride.value("release"))) + .arg(repoUrl) + ); + } + + return result; +} + +QStringList SsuKickstarter::packages(){ + QStringList result; + + // insert @vendor configuration device + QString configuration = QString("@%1 Configuration %2") + .arg("Jolla") + .arg(deviceModel); + result.append(configuration); + + // check if there's a kernel, and if so, append it as well + + result.sort(); + result.removeDuplicates(); + result.prepend("%packages"); + result.append("%end"); + return result; +} + +QStringList SsuKickstarter::partitions(){ + QStringList result; + SsuDeviceInfo deviceInfo(deviceModel); + QString partitionFile; + QFile part; + + QDir dir(QString("%1/kickstart/part/").arg(SSU_DATA_DIR)); + + if (dir.exists(deviceInfo.deviceVariant(true))) + partitionFile = deviceInfo.deviceVariant(true); + else if (dir.exists(deviceModel)) + partitionFile = deviceModel; + else if (dir.exists("default")) + partitionFile = "default"; + else { + result.append("## No partition configuration found."); + return result; + } + + QFile file(dir.path() + "/" + partitionFile); + result.append("### partition setup from " + partitionFile); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)){ + QTextStream in(&file); + while (!in.atEnd()) + result.append(in.readLine()); + } + + return result; +} + +// we intentionally don't support device-specific post scriptlets +QStringList SsuKickstarter::scriptletSection(QString name, bool chroot){ + QStringList result; + QString path; + QDir dir; + + if (chroot) + path = QString("%1/kickstart/%2/") + .arg(SSU_DATA_DIR) + .arg(name); + else + path = QString("%1/kickstart/%2_nochroot/") + .arg(SSU_DATA_DIR) + .arg(name); + + dir.setPath(path); + QStringList scriptlets = dir.entryList(QDir::AllEntries|QDir::NoDot|QDir::NoDotDot, + QDir::Name); + + foreach (const QString &scriptlet, scriptlets){ + QFile file(path + scriptlet); + 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()){ + if (chroot) + result.prepend("%" + name); + else + result.prepend("%" + name + " --nochroot"); + result.append("%end"); + } + + return result; +} + +void SsuKickstarter::setRepoParameters(QHash parameters){ + repoOverride = parameters; + + if (repoOverride.contains("model")) + deviceModel = repoOverride.value("model"); +/* + else + repoOverride.insert("model", deviceInfo.deviceModel()); +*/ +} + +void SsuKickstarter::write(QString kickstart){ + QFile ks; + QTextStream kout; + SsuDeviceInfo deviceInfo; + + if (kickstart.isEmpty()) + ks.open(stdout, QIODevice::WriteOnly); + else { + ks.setFileName(kickstart); + ks.open(QIODevice::WriteOnly); + } + + kout.setDevice(&ks); + + QHash defaults = deviceInfo.variableSection("kickstart-defaults"); + QHash::const_iterator it = defaults.constBegin(); + while (it != defaults.constEnd()){ + if (!repoOverride.contains(it.key())) + repoOverride.insert(it.key(), it.value()); + it++; + } + + kout << commands().join("\n") << endl << endl; + kout << partitions().join("\n") << endl << endl; + kout << repos().join("\n") << endl << endl; + kout << packages().join("\n") << endl << endl; + kout << scriptletSection("pre", false).join("\n") << endl << endl; + kout << scriptletSection("post").join("\n") << endl << endl; + kout << scriptletSection("post").join("\n") << endl << endl; + // add flags as bitmask? + // POST, die-on-error +} diff --git a/ssuks/ssukickstarter.h b/ssuks/ssukickstarter.h new file mode 100644 index 0000000..f8f9909 --- /dev/null +++ b/ssuks/ssukickstarter.h @@ -0,0 +1,40 @@ +/** + * @file ssukickstarter.h + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#ifndef _SSUKICKSTARTER_H +#define _SSUKICKSTARTER_H + +#include +#include +#include + +#include +#include + +/* +class Q_CORE_EXPORT SsuKickstarter: public QObject { + Q_OBJECT +*/ +class SsuKickstarter { + public: + SsuKickstarter(); + void setRepoParameters(QHash parameters); + void write(QString kickstart=""); + + private: + QHash repoOverride; + Ssu ssu; + bool rndMode; + QString deviceModel; + QStringList commands(); + QStringList packages(); + QStringList partitions(); + QStringList repos(); + QStringList scriptletSection(QString name, bool chroot=true); +}; + +#endif diff --git a/ssuks/ssuks.cpp b/ssuks/ssuks.cpp new file mode 100644 index 0000000..570010d --- /dev/null +++ b/ssuks/ssuks.cpp @@ -0,0 +1,79 @@ +/** + * @file ssuks.cpp + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#include +#include +#include +#include +#include +#include + +#include "ssukickstarter.h" + +#include "ssuks.h" + +void SsuKs::run(){ + QStringList arguments = QCoreApplication::arguments(); + // get rid of the binary name + arguments.removeFirst(); + + QTextStream qout(stdout); + QHash repoParameters; + + SsuKickstarter kickstarter; + + QString fileName; + if (arguments.count() >= 1 && !arguments.at(0).contains("=")){ + fileName = arguments.at(0); + arguments.removeFirst(); + } + + if (arguments.count() >= 1){ + for (int i=0; i " << endl + << endl + << "Flags are in the form key=value. 'model' and 'rnd' keys have special meanings." << endl + << "To do a kickstart for N9 do 'ssuks model=N9'" << endl + << endl; + qout.flush(); + QCoreApplication::exit(1); +} + +int main(int argc, char** argv){ + QCoreApplication app(argc, argv); + QCoreApplication::setOrganizationName("Jolla"); + QCoreApplication::setOrganizationDomain("http://www.jollamobile.com"); + QCoreApplication::setApplicationName("ssuks"); + + QTranslator qtTranslator; + qtTranslator.load("qt_" + QLocale::system().name(), + QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + app.installTranslator(&qtTranslator); + + SsuKs mw; + QTimer::singleShot(0, &mw, SLOT(run())); + + return app.exec(); +} diff --git a/ssuks/ssuks.h b/ssuks/ssuks.h new file mode 100644 index 0000000..af20909 --- /dev/null +++ b/ssuks/ssuks.h @@ -0,0 +1,28 @@ +/** + * @file ssuks.h + * @copyright 2013 Jolla Ltd. + * @author Bernd Wachter + * @date 2013 + */ + +#ifndef _SSUKS_H +#define _SSUKS_H + +#include +#include + +class SsuKs: public QObject { + Q_OBJECT +//class SsuKs { + + public: + SsuKs(){}; + + public slots: + void run(); + + private: + void usage(); +}; + +#endif diff --git a/ssuks/ssuks.pro b/ssuks/ssuks.pro new file mode 100644 index 0000000..6cc0858 --- /dev/null +++ b/ssuks/ssuks.pro @@ -0,0 +1,16 @@ +HEADERS = ssuks.h \ + ssukickstarter.h +SOURCES = ssuks.cpp \ + ssukickstarter.cpp +TEMPLATE = app +TARGET = ssuks +LIBS += -lssu +CONFIG -= app_bundle +CONFIG += console +QT -= gui +QT += network + +unix:target.path = $${PREFIX}/usr/bin +INSTALLS += target + +!include( ../buildpath.pri ) { error("Unable to find build path specification") }