summaryrefslogtreecommitdiff
path: root/app-admin/calamares
diff options
context:
space:
mode:
authorV3n3RiX <venerix@rogentos.ro>2016-10-16 18:24:22 +0100
committerV3n3RiX <venerix@rogentos.ro>2016-10-16 18:24:22 +0100
commitc739ae6af89cbe2c34848a10ac554f907f8e6757 (patch)
tree92208c31832f970cff71d791fc392ca89b439e66 /app-admin/calamares
parent92a9c462ce35236904efefeac1b82187bbb24c73 (diff)
prepare calamares 2.4.2 with dracut luks support
Diffstat (limited to 'app-admin/calamares')
-rw-r--r--app-admin/calamares/Manifest1
-rw-r--r--app-admin/calamares/calamares-2.4.2.ebuild78
-rw-r--r--app-admin/calamares/files/calamares-2.4.2-dracut-luks-fde.patch1918
3 files changed, 1997 insertions, 0 deletions
diff --git a/app-admin/calamares/Manifest b/app-admin/calamares/Manifest
index a584cfc5..251d3951 100644
--- a/app-admin/calamares/Manifest
+++ b/app-admin/calamares/Manifest
@@ -1,2 +1,3 @@
DIST calamares-1.1.tar.gz 3641655 SHA256 db0b5f09d62f43c433ff53462dc35bd43bbc4fd618fa1aac081ebb05b570edee SHA512 5b67f99e8a13f0147d510ddef2f6ba90ec81e65526159643fe3a577f62030e7a466d9dfbad0fb7befa22e59074222dd5123565b871c90c2ed25f3547ca1bb582 WHIRLPOOL c9de81bcdff03d85c98438d00fa925216e3c50670eb7354e4574c499c8b49d8fbb77e99c5733e5a9e5d97e6c9a1b795fcdf35df0cad0002227fc8b051ffc2406
DIST calamares-2.3.tar.gz 2029483 SHA256 c499a8a8ea1573c6f0323398fb092f8978958202e11c9d339202c35c73276f9f SHA512 be0b1e328ebd6bddab3a163bf38649fd4f64cfe74213946f00b0d05c76fba870662386328c0ccb7656dc63975a1b28058be7eda56b2cee792fba78443ab6d36e WHIRLPOOL aa1602aa06a4320f5a263c24e17c322bbdfcd83b7f11012e4b2cec895d6a18cdbf627d82f614ace60c62572374a9fb247216619fa0a4de207e3f8267bf51cd9e
+DIST calamares-2.4.2.tar.gz 2137039 SHA256 4620fd4e9c2d9868e6c20a5c600f123e91080f7ef3a7c6ea55314aa57841b96a SHA512 152857f256f15ff72c44087baf8d4d9d452c5692e131334dd429f40c0e212eac01178352fd17f4020a128f880d3a91dbd634500384d53752d4313a08de816112 WHIRLPOOL 1aa6919a461d5b02a43a4cdbd580a9e7fc9bdc3b048f467f082c4d053c83e5bae5f5777439870828d12153789aac2e4f3b4b6868732dd7c70b0baec3ad4d65c3
diff --git a/app-admin/calamares/calamares-2.4.2.ebuild b/app-admin/calamares/calamares-2.4.2.ebuild
new file mode 100644
index 00000000..bbe4dc24
--- /dev/null
+++ b/app-admin/calamares/calamares-2.4.2.ebuild
@@ -0,0 +1,78 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Header: $
+
+EAPI=5
+PYTHON_COMPAT=( python3_4 )
+
+inherit eutils cmake-utils python-r1
+
+SRC_URI="https://github.com/calamares/calamares/releases/download/v${PV}/${P}.tar.gz"
+
+DESCRIPTION="Distribution-independent installer framework"
+HOMEPAGE="http://calamares.io"
+
+LICENSE="GPL-3"
+SLOT="0"
+KEYWORDS="amd64"
+IUSE="+python"
+
+S="${WORKDIR}/${P}"
+
+DEPEND="
+ dev-vcs/git
+ python? (
+ >=dev-libs/boost-1.55.0-r2[python_targets_python3_4]
+ )
+ >=dev-qt/designer-5.6.0:5
+ >=dev-qt/linguist-tools-5.6.0:5
+ >=dev-qt/qtconcurrent-5.6.0:5
+ >=dev-qt/qtcore-5.6.0:5
+ >=dev-qt/qtdbus-5.6.0:5
+ >=dev-qt/qtdeclarative-5.6.0:5
+ >=dev-qt/qtgui-5.6.0:5
+ >=dev-qt/qtnetwork-5.6.0:5
+ >=dev-qt/qtopengl-5.6.0:5
+ >=dev-qt/qtprintsupport-5.6.0:5
+ >=dev-qt/qtscript-5.6.0:5
+ >=dev-qt/qtsvg-5.6.0:5
+ >=dev-qt/qttest-5.6.0:5
+ >=dev-qt/qtwebengine-5.6.0:5
+ >=dev-qt/qtwebchannel-5.6.0:5
+ >=dev-qt/qtwidgets-5.6.0:5
+ >=dev-qt/qtxml-5.6.0:5
+ >=dev-qt/qtxmlpatterns-5.6.0:5
+ >=dev-cpp/yaml-cpp-0.5.1
+ >=kde-frameworks/extra-cmake-modules-5.18.0
+ >=sys-libs/kpmcore-2.2.0"
+
+RDEPEND=">=app-misc/calamares-runtime-3.1[branding]"
+
+src_prepare() {
+ # patch dracut module to be called the way we want it, until the module becomes configurable
+ epatch ${FILESDIR}/${PN}-kogaion-dracut-call.patch
+ # calamares dracut luks patch
+ epatch ${FILESDIR}/${P}-dracut-luks-fde.patch
+ # replace calamares installer desktop icon
+ sed -i "s/Icon=calamares/Icon=start-here/g" "${S}/calamares.desktop"
+ # fix installer doesn't start from desktop launcher (IMPROVE THIS UGLY THINGY)
+ sed -i "s/pkexec //g" "${S}/calamares.desktop"
+ sed -i "s/calamares/calamares-pkexec/g" "${S}/calamares.desktop"
+ # If qtchooser is installed, it may break the build, because moc,rcc and uic binaries for wrong qt version may be used.
+ # Setting QT_SELECT environment variable will enforce correct binaries (fix taken from vlc ebuild)
+ export QT_SELECT=qt5
+}
+
+src_configure() {
+ local mycmakeargs=(
+ -DWITH_PARTITIONMANAGER=1
+ )
+ cmake-utils_src_configure
+}
+
+src_install() {
+ cmake-utils_src_install
+ insinto /usr/bin
+ insopts -m 755
+ doins ${FILESDIR}/calamares-pkexec
+}
diff --git a/app-admin/calamares/files/calamares-2.4.2-dracut-luks-fde.patch b/app-admin/calamares/files/calamares-2.4.2-dracut-luks-fde.patch
new file mode 100644
index 00000000..55669822
--- /dev/null
+++ b/app-admin/calamares/files/calamares-2.4.2-dracut-luks-fde.patch
@@ -0,0 +1,1918 @@
+From 03c7357dbcb70c047c0aac0a2566c50aaaed1168 Mon Sep 17 00:00:00 2001
+From: Kevin Kofler <kevin.kofler@chello.at>
+Date: Sun, 25 Sep 2016 03:20:50 +0200
+Subject: [PATCH] Add support for LUKS full disk encryption with dracut.
+
+Add support for C++/Qt batch job plugins
+
+These job plugins work similarly to view modules, with the following
+differences:
+
+* These jobs need to link only libcalamares, not libcalamaresui. For
+ this reason, PluginFactory was moved from libcalamaresui to
+ libcalamares. (It depends only on QtCore.)
+
+* Instead of deriving from ViewModule, derive from CppJob (which is a
+ subclass of Job).
+
+* Like process and Python jobs, a job plugin is a single job, whereas a
+ ViewModule can generate a whole list of jobs.
+
+The CppJob and CppJobModule classes are new. In Module::fromDescriptor,
+the combination type=job, intf=qtplugin is now supported and mapped to
+CppJobModule.
+
+[fstab] Do not omit "/" from crypttab.
+
+At least the Debian update-initramfs needs the entry to be there (see
+pull request #254). Dracut will probably need it too. And logically, it
+should be there.
+
+[fstab] Write configurable options to crypttab (default: luks).
+
+fstab.conf: Add a new "crypttabOptions" option that defaults to "luks".
+ Document that for Debian and Debian-based distributions, the
+ setting should be changed to "luks,keyscript=/bin/cat".
+
+main.py: Append the options from the above setting to the end of every
+ line in crypttab.
+
+At least the "luks" option should always be there, because there may be
+different encryption types. The Debian initramfs-tools also require the
+Debian-specific keyscript option and will otherwise ignore the keyfile
+entirely (see pull request #254).
+
+[dracutlukscfg] New module: pre-configuration for dracut+LUKS.
+
+Add a dracutlukscfg module to write a
+/etc/dracut.conf.d/calamares-luks.conf file for LUKS full disk
+encryption support with Dracut.
+
+You should run:
+
+* partition
+* luksbootkeyfile
+* dracutlukscfg
+* dracut
+
+in that order (not necessarily in immediate sequence). The
+luksopenswaphook module is not used with Dracut.
+---
+ settings.conf | 1 +
+ src/libcalamares/CMakeLists.txt | 2 +
+ src/libcalamares/CppJob.cpp | 45 +++
+ src/libcalamares/CppJob.h | 51 ++++
+ src/libcalamares/utils/PluginFactory.cpp | 123 ++++++++
+ src/libcalamares/utils/PluginFactory.h | 370 +++++++++++++++++++++++
+ src/libcalamares/utils/PluginFactory_p.h | 54 ++++
+ src/libcalamaresui/CMakeLists.txt | 3 +-
+ src/libcalamaresui/modulesystem/CppJobModule.cpp | 128 ++++++++
+ src/libcalamaresui/modulesystem/CppJobModule.h | 53 ++++
+ src/libcalamaresui/modulesystem/Module.cpp | 7 +-
+ src/libcalamaresui/utils/PluginFactory.cpp | 123 --------
+ src/libcalamaresui/utils/PluginFactory.h | 370 -----------------------
+ src/libcalamaresui/utils/PluginFactory_p.h | 54 ----
+ src/modules/dracutlukscfg/CMakeLists.txt | 9 +
+ src/modules/dracutlukscfg/DracutLuksCfgJob.cpp | 143 +++++++++
+ src/modules/dracutlukscfg/DracutLuksCfgJob.h | 56 ++++
+ src/modules/dracutlukscfg/module.desc | 7 +
+ src/modules/fstab/fstab.conf | 3 +
+ src/modules/fstab/main.py | 21 +-
+ 20 files changed, 1064 insertions(+), 559 deletions(-)
+ create mode 100644 src/libcalamares/CppJob.cpp
+ create mode 100644 src/libcalamares/CppJob.h
+ create mode 100644 src/libcalamares/utils/PluginFactory.cpp
+ create mode 100644 src/libcalamares/utils/PluginFactory.h
+ create mode 100644 src/libcalamares/utils/PluginFactory_p.h
+ create mode 100644 src/libcalamaresui/modulesystem/CppJobModule.cpp
+ create mode 100644 src/libcalamaresui/modulesystem/CppJobModule.h
+ delete mode 100644 src/libcalamaresui/utils/PluginFactory.cpp
+ delete mode 100644 src/libcalamaresui/utils/PluginFactory.h
+ delete mode 100644 src/libcalamaresui/utils/PluginFactory_p.h
+ create mode 100644 src/modules/dracutlukscfg/CMakeLists.txt
+ create mode 100644 src/modules/dracutlukscfg/DracutLuksCfgJob.cpp
+ create mode 100644 src/modules/dracutlukscfg/DracutLuksCfgJob.h
+ create mode 100644 src/modules/dracutlukscfg/module.desc
+
+diff --git a/settings.conf b/settings.conf
+index 0721098..d4439a7 100644
+--- a/settings.conf
++++ b/settings.conf
+@@ -79,6 +79,7 @@ sequence:
+ - localecfg
+ # - luksbootkeyfile
+ # - luksopenswaphookcfg
++# - dracutlukscfg
+ - initcpiocfg
+ - initcpio
+ - users
+diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt
+index 966ca9c..b1f6c48 100644
+--- a/src/libcalamares/CMakeLists.txt
++++ b/src/libcalamares/CMakeLists.txt
+@@ -11,6 +11,7 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../calamares/CalamaresVersion.h.in
+ ${CMAKE_CURRENT_BINARY_DIR}/CalamaresVersion.h )
+
+ set( libSources
++ CppJob.cpp
+ GlobalStorage.cpp
+ Job.cpp
+ JobQueue.cpp
+@@ -24,6 +25,7 @@ set( libSources
+ utils/CalamaresUtils.cpp
+ utils/CalamaresUtilsSystem.cpp
+ utils/Logger.cpp
++ utils/PluginFactory.cpp
+ utils/Retranslator.cpp
+ )
+
+diff --git a/src/libcalamares/CppJob.cpp b/src/libcalamares/CppJob.cpp
+new file mode 100644
+index 0000000..1925e39
+--- /dev/null
++++ b/src/libcalamares/CppJob.cpp
+@@ -0,0 +1,45 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2014, Teo Mrnjavac <teo@kde.org>
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "CppJob.h"
++
++namespace Calamares
++{
++
++CppJob::CppJob( QObject* parent )
++ : Job( parent )
++{}
++
++
++CppJob::~CppJob()
++{}
++
++
++void
++CppJob::setModuleInstanceKey( const QString& instanceKey )
++{
++ m_instanceKey = instanceKey;
++}
++
++
++void
++CppJob::setConfigurationMap( const QVariantMap& configurationMap )
++{}
++
++}
+diff --git a/src/libcalamares/CppJob.h b/src/libcalamares/CppJob.h
+new file mode 100644
+index 0000000..a6e6735
+--- /dev/null
++++ b/src/libcalamares/CppJob.h
+@@ -0,0 +1,51 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CALAMARES_CPPJOB_H
++#define CALAMARES_CPPJOB_H
++
++#include <QObject>
++#include <QVariant>
++
++#include "DllMacro.h"
++#include "Typedefs.h"
++#include "Job.h"
++
++namespace Calamares
++{
++
++class DLLEXPORT CppJob : public Job
++{
++ Q_OBJECT
++public:
++ explicit CppJob( QObject* parent = nullptr );
++ virtual ~CppJob();
++
++ void setModuleInstanceKey( const QString& instanceKey );
++ QString moduleInstanceKey() const { return m_instanceKey; }
++
++ virtual void setConfigurationMap( const QVariantMap& configurationMap );
++
++protected:
++ QString m_instanceKey;
++};
++
++}
++
++#endif // CALAMARES_CPPJOB_H
+diff --git a/src/libcalamares/utils/PluginFactory.cpp b/src/libcalamares/utils/PluginFactory.cpp
+new file mode 100644
+index 0000000..30a5bf4
+--- /dev/null
++++ b/src/libcalamares/utils/PluginFactory.cpp
+@@ -0,0 +1,123 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2015, Teo Mrnjavac <teo@kde.org>
++ *
++ * Based on KPluginFactory from KCoreAddons, KDE project
++ * Copyright 2007, Matthias Kretz <kretz@kde.org>
++ * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "PluginFactory.h"
++#include "PluginFactory_p.h"
++
++#include <QObjectCleanupHandler>
++#include <QDebug>
++
++Q_GLOBAL_STATIC(QObjectCleanupHandler, factorycleanup)
++
++extern int kLibraryDebugArea();
++
++namespace Calamares
++{
++
++PluginFactory::PluginFactory()
++ : d_ptr(new PluginFactoryPrivate)
++{
++ Q_D(PluginFactory);
++ d->q_ptr = this;
++
++ factorycleanup()->add(this);
++}
++
++PluginFactory::PluginFactory(PluginFactoryPrivate &d)
++ : d_ptr(&d)
++{
++ factorycleanup()->add(this);
++}
++
++PluginFactory::~PluginFactory()
++{
++ delete d_ptr;
++}
++
++void PluginFactory::doRegisterPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceFunction instanceFunction)
++{
++ Q_D(PluginFactory);
++
++ Q_ASSERT(metaObject);
++
++ // we allow different interfaces to be registered without keyword
++ if (!keyword.isEmpty()) {
++ if (d->createInstanceHash.contains(keyword)) {
++ qWarning() << "A plugin with the keyword" << keyword << "was already registered. A keyword must be unique!";
++ }
++ d->createInstanceHash.insert(keyword, PluginFactoryPrivate::Plugin(metaObject, instanceFunction));
++ } else {
++ const QList<PluginFactoryPrivate::Plugin> clashes(d->createInstanceHash.values(keyword));
++ const QMetaObject *superClass = metaObject->superClass();
++ if (superClass) {
++ for (const PluginFactoryPrivate::Plugin &plugin : clashes) {
++ for (const QMetaObject *otherSuper = plugin.first->superClass(); otherSuper;
++ otherSuper = otherSuper->superClass()) {
++ if (superClass == otherSuper) {
++ qWarning() << "Two plugins with the same interface(" << superClass->className() << ") were registered. Use keywords to identify the plugins.";
++ }
++ }
++ }
++ }
++ for (const PluginFactoryPrivate::Plugin &plugin : clashes) {
++ superClass = plugin.first->superClass();
++ if (superClass) {
++ for (const QMetaObject *otherSuper = metaObject->superClass(); otherSuper;
++ otherSuper = otherSuper->superClass()) {
++ if (superClass == otherSuper) {
++ qWarning() << "Two plugins with the same interface(" << superClass->className() << ") were registered. Use keywords to identify the plugins.";
++ }
++ }
++ }
++ }
++ d->createInstanceHash.insertMulti(keyword, PluginFactoryPrivate::Plugin(metaObject, instanceFunction));
++ }
++}
++
++QObject *PluginFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QString &keyword)
++{
++ Q_D(PluginFactory);
++
++ QObject *obj = 0;
++
++ const QList<PluginFactoryPrivate::Plugin> candidates(d->createInstanceHash.values(keyword));
++ // for !keyword.isEmpty() candidates.count() is 0 or 1
++
++ for (const PluginFactoryPrivate::Plugin &plugin : candidates) {
++ for (const QMetaObject *current = plugin.first; current; current = current->superClass()) {
++ if (0 == qstrcmp(iface, current->className())) {
++ if (obj) {
++ qWarning() << "ambiguous interface requested from a DSO containing more than one plugin";
++ }
++ obj = plugin.second(parentWidget, parent);
++ break;
++ }
++ }
++ }
++
++ if (obj) {
++ emit objectCreated(obj);
++ }
++ return obj;
++}
++
++}
+diff --git a/src/libcalamares/utils/PluginFactory.h b/src/libcalamares/utils/PluginFactory.h
+new file mode 100644
+index 0000000..c0053ba
+--- /dev/null
++++ b/src/libcalamares/utils/PluginFactory.h
+@@ -0,0 +1,370 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2015, Teo Mrnjavac <teo@kde.org>
++ *
++ * Based on KPluginFactory from KCoreAddons, KDE project
++ * Copyright 2007, Matthias Kretz <kretz@kde.org>
++ * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CALAMARESPLUGINFACTORY_H
++#define CALAMARESPLUGINFACTORY_H
++
++#include "DllMacro.h"
++
++#include <QtCore/QObject>
++#include <QtCore/QVariant>
++#include <QtCore/QStringList>
++
++namespace Calamares
++{
++class PluginFactoryPrivate;
++}
++
++#define CalamaresPluginFactory_iid "io.calamares.PluginFactory"
++
++#define CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY_SKEL(name, baseFactory, ...) \
++ class name : public Calamares::PluginFactory \
++ { \
++ Q_OBJECT \
++ Q_INTERFACES(Calamares::PluginFactory) \
++ __VA_ARGS__ \
++ public: \
++ explicit name(); \
++ ~name(); \
++ private: \
++ void init(); \
++ };
++
++#define CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, baseFactory) \
++ CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY_SKEL(name, baseFactory, Q_PLUGIN_METADATA(IID CalamaresPluginFactory_iid))
++
++#define CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations) \
++ name::name() \
++ { \
++ pluginRegistrations \
++ } \
++ name::~name() {}
++
++#define CALAMARES_PLUGIN_FACTORY_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations) \
++ CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, baseFactory) \
++ CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations)
++
++#define CALAMARES_PLUGIN_FACTORY_DECLARATION(name) CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, Calamares::PluginFactory)
++#define CALAMARES_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
++
++/**
++ * \relates PluginFactory
++ *
++ * Create a PluginFactory subclass and export it as the root plugin object.
++ *
++ * \param name The name of the PluginFactory derived class.
++ *
++ * \param pluginRegistrations Code to be inserted into the constructor of the
++ * class. Usually a series of registerPlugin() calls.
++ *
++ * Example:
++ * \code
++ * #include <PluginFactory.h>
++ * #include <plugininterface.h>
++ *
++ * class MyPlugin : public PluginInterface
++ * {
++ * public:
++ * MyPlugin(QObject *parent, const QVariantList &args)
++ * : PluginInterface(parent)
++ * {}
++ * };
++ *
++ * CALAMARES_PLUGIN_FACTORY(MyPluginFactory,
++ * registerPlugin<MyPlugin>();
++ * )
++ *
++ * #include <myplugin.moc>
++ * \endcode
++ *
++ * \see CALAMARES_PLUGIN_FACTORY_DECLARATION
++ * \see CALAMARES_PLUGIN_FACTORY_DEFINITION
++ */
++#define CALAMARES_PLUGIN_FACTORY(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
++
++/**
++ * \relates PluginFactory
++ *
++ * CALAMARES_PLUGIN_FACTORY_DECLARATION declares the PluginFactory subclass. This macro
++ * can be used in a header file.
++ *
++ * \param name The name of the PluginFactory derived class.
++ *
++ * \see CALAMARES_PLUGIN_FACTORY
++ * \see CALAMARES_PLUGIN_FACTORY_DEFINITION
++ */
++#define CALAMARES_PLUGIN_FACTORY_DECLARATION(name) CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, Calamares::PluginFactory)
++
++/**
++ * \relates PluginFactory
++ * CALAMARES_PLUGIN_FACTORY_DEFINITION defines the PluginFactory subclass. This macro
++ * can <b>not</b> be used in a header file.
++ *
++ * \param name The name of the PluginFactory derived class.
++ *
++ * \param pluginRegistrations Code to be inserted into the constructor of the
++ * class. Usually a series of registerPlugin() calls.
++ *
++ * \see CALAMARES_PLUGIN_FACTORY
++ * \see CALAMARES_PLUGIN_FACTORY_DECLARATION
++ */
++#define CALAMARES_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
++
++namespace Calamares
++{
++
++/**
++ * \class PluginFactory PluginFactory.h <PluginFactory.h>
++ *
++ * PluginFactory provides a convenient way to provide factory-style plugins.
++ * Qt plugins provide a singleton object, but a common pattern is for plugins
++ * to generate as many objects of a particular type as the application requires.
++ * By using PluginFactory, you can avoid implementing the factory pattern
++ * yourself.
++ *
++ * PluginFactory also allows plugins to provide multiple different object
++ * types, indexed by keywords.
++ *
++ * The objects created by PluginFactory must inherit QObject, and must have a
++ * standard constructor pattern:
++ * \li if the object is a KPart::Part, it must be of the form
++ * \code
++ * T(QWidget *parentWidget, QObject *parent, const QVariantList &args)
++ * \endcode
++ * \li if it is a QWidget, it must be of the form
++ * \code
++ * T(QWidget *parent, const QVariantList &args)
++ * \endcode
++ * \li otherwise it must be of the form
++ * \code
++ * T(QObject *parent, const QVariantList &args)
++ * \endcode
++ *
++ * You should typically use either CALAMARES_PLUGIN_FACTORY() or
++ * CALAMARES_PLUGIN_FACTORY_WITH_JSON() in your plugin code to create the factory. The
++ * typical pattern is
++ *
++ * \code
++ * #include <PluginFactory.h>
++ * #include <plugininterface.h>
++ *
++ * class MyPlugin : public PluginInterface
++ * {
++ * public:
++ * MyPlugin(QObject *parent, const QVariantList &args)
++ * : PluginInterface(parent)
++ * {}
++ * };
++ *
++ * CALAMARES_PLUGIN_FACTORY(MyPluginFactory,
++ * registerPlugin<MyPlugin>();
++ * )
++ * #include <myplugin.moc>
++ * \endcode
++ *
++ * If you want to load a library use KPluginLoader.
++ * The application that wants to instantiate plugin classes can do the following:
++ * \code
++ * PluginFactory *factory = KPluginLoader("libraryname").factory();
++ * if (factory) {
++ * PluginInterface *p1 = factory->create<PluginInterface>(parent);
++ * OtherInterface *p2 = factory->create<OtherInterface>(parent);
++ * NextInterface *p3 = factory->create<NextInterface>("keyword1", parent);
++ * NextInterface *p3 = factory->create<NextInterface>("keyword2", parent);
++ * }
++ * \endcode
++ *
++ * \author Matthias Kretz <kretz@kde.org>
++ * \author Bernhard Loos <nhuh.put@web.de>
++ */
++class DLLEXPORT PluginFactory : public QObject
++{
++ Q_OBJECT
++ Q_DECLARE_PRIVATE(PluginFactory)
++public:
++ /**
++ * This constructor creates a factory for a plugin.
++ */
++ explicit PluginFactory();
++
++ /**
++ * This destroys the PluginFactory.
++ */
++ virtual ~PluginFactory();
++
++ /**
++ * Use this method to create an object. It will try to create an object which inherits
++ * \p T. If it has multiple choices, you will get a fatal error (kFatal()), so be careful
++ * to request a unique interface or use keywords.
++ *
++ * \tparam T The interface for which an object should be created. The object will inherit \p T.
++ * \param parent The parent of the object. If \p parent is a widget type, it will also passed
++ * to the parentWidget argument of the CreateInstanceFunction for the object.
++ * \returns A pointer to the created object is returned, or 0 if an error occurred.
++ */
++ template<typename T>
++ T *create(QObject *parent = 0);
++
++ /**
++ * Use this method to create an object. It will try to create an object which inherits
++ * \p T and was registered with \p keyword.
++ *
++ * \tparam T The interface for which an object should be created. The object will inherit \p T.
++ * \param keyword The keyword of the object.
++ * \param parent The parent of the object. If \p parent is a widget type, it will also passed
++ * to the parentWidget argument of the CreateInstanceFunction for the object.
++ * \returns A pointer to the created object is returned, or 0 if an error occurred.
++ */
++ template<typename T>
++ T *create(const QString &keyword, QObject *parent = 0);
++
++Q_SIGNALS:
++ void objectCreated(QObject *object);
++
++protected:
++ /**
++ * Function pointer type to a function that instantiates a plugin.
++ */
++ typedef QObject *(*CreateInstanceFunction)(QWidget *, QObject *);
++
++ /**
++ * This is used to detect the arguments need for the constructor of plugin classes.
++ * You can inherit it, if you want to add new classes and still keep support for the old ones.
++ */
++ template<class impl>
++ struct InheritanceChecker {
++ CreateInstanceFunction createInstanceFunction(QWidget *)
++ {
++ return &createInstance<impl, QWidget>;
++ }
++ CreateInstanceFunction createInstanceFunction(...)
++ {
++ return &createInstance<impl, QObject>;
++ }
++ };
++
++ explicit PluginFactory(PluginFactoryPrivate &dd);
++
++ /**
++ * Registers a plugin with the factory. Call this function from the constructor of the
++ * PluginFactory subclass to make the create function able to instantiate the plugin when asked
++ * for an interface the plugin implements.
++ *
++ * \tparam T the name of the plugin class
++ *
++ * \param keyword An optional keyword as unique identifier for the plugin. This allows you to
++ * put more than one plugin with the same interface into the same library using the same
++ * factory. X-KDE-PluginKeyword is a convenient way to specify the keyword in a desktop file.
++ *
++ * \param instanceFunction A function pointer to a function that creates an instance of the
++ * plugin. The default function that will be used depends on the type of interface. If the
++ * interface inherits from
++ * \li \c KParts::Part the function will call
++ * \code
++ * new T(QWidget *parentWidget, QObject *parent)
++ * \endcode
++ * \li \c QWidget the function will call
++ * \code
++ * new T(QWidget *parent)
++ * \endcode
++ * \li else the function will call
++ * \code
++ * new T(QObject *parent)
++ * \endcode
++ */
++ template<class T>
++ void registerPlugin(const QString &keyword = QString(),
++ CreateInstanceFunction instanceFunction
++ = InheritanceChecker<T>().createInstanceFunction(reinterpret_cast<T *>(0)))
++ {
++ doRegisterPlugin(keyword, &T::staticMetaObject, instanceFunction);
++ }
++
++ PluginFactoryPrivate *const d_ptr;
++
++ /**
++ * This function is called when the factory asked to create an Object.
++ *
++ * You may reimplement it to provide a very flexible factory. This is especially useful to
++ * provide generic factories for plugins implemeted using a scripting language.
++ *
++ * \param iface The staticMetaObject::className() string identifying the plugin interface that
++ * was requested. E.g. for KCModule plugins this string will be "KCModule".
++ * \param parentWidget Only used if the requested plugin is a KPart.
++ * \param parent The parent object for the plugin object.
++ * \param args A plugin specific list of arbitrary arguments.
++ * \param keyword A string that uniquely identifies the plugin. If a KService is used this
++ * keyword is read from the X-KDE-PluginKeyword entry in the .desktop file.
++ */
++ virtual QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QString &keyword);
++
++ template<class impl, class ParentType>
++ static QObject *createInstance(QWidget *parentWidget, QObject *parent)
++ {
++ Q_UNUSED(parentWidget);
++ ParentType *p = 0;
++ if (parent) {
++ p = qobject_cast<ParentType *>(parent);
++ Q_ASSERT(p);
++ }
++ return new impl(p);
++ }
++
++private:
++ void doRegisterPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceFunction instanceFunction);
++};
++
++template<typename T>
++inline T *PluginFactory::create(QObject *parent)
++{
++ QObject *o = create(T::staticMetaObject.className(),
++ parent && parent->isWidgetType() ? reinterpret_cast<QWidget *>(parent) : 0,
++ parent,
++ QString());
++
++ T *t = qobject_cast<T *>(o);
++ if (!t) {
++ delete o;
++ }
++ return t;
++}
++
++template<typename T>
++inline T *PluginFactory::create(const QString &keyword, QObject *parent)
++{
++ QObject *o = create(T::staticMetaObject.className(),
++ parent && parent->isWidgetType() ? reinterpret_cast<QWidget *>(parent) : 0,
++ parent,
++ keyword);
++
++ T *t = qobject_cast<T *>(o);
++ if (!t) {
++ delete o;
++ }
++ return t;
++}
++
++}
++
++Q_DECLARE_INTERFACE(Calamares::PluginFactory, CalamaresPluginFactory_iid)
++
++#endif // CALAMARESPLUGINFACTORY_H
+diff --git a/src/libcalamares/utils/PluginFactory_p.h b/src/libcalamares/utils/PluginFactory_p.h
+new file mode 100644
+index 0000000..a0b4a1c
+--- /dev/null
++++ b/src/libcalamares/utils/PluginFactory_p.h
+@@ -0,0 +1,54 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2015, Teo Mrnjavac <teo@kde.org>
++ *
++ * Based on KPluginFactory from KCoreAddons, KDE project
++ * Copyright 2007, Matthias Kretz <kretz@kde.org>
++ * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CALAMARESPLUGINFACTORY_P_H
++#define CALAMARESPLUGINFACTORY_P_H
++
++#include "PluginFactory.h"
++
++#include <QtCore/QHash>
++
++namespace Calamares
++{
++
++class PluginFactoryPrivate
++{
++ Q_DECLARE_PUBLIC(PluginFactory)
++protected:
++ typedef QPair<const QMetaObject *, PluginFactory::CreateInstanceFunction> Plugin;
++
++ PluginFactoryPrivate()
++ : catalogInitialized( false )
++ , q_ptr( nullptr )
++ {}
++ ~PluginFactoryPrivate() {}
++
++ QHash<QString, Plugin> createInstanceHash;
++ QString catalogName;
++ bool catalogInitialized;
++
++ PluginFactory *q_ptr;
++};
++
++}
++
++#endif // CALAMARESPLUGINFACTORY_P_H
+diff --git a/src/libcalamaresui/CMakeLists.txt b/src/libcalamaresui/CMakeLists.txt
+index 939d05a..478034b 100644
+--- a/src/libcalamaresui/CMakeLists.txt
++++ b/src/libcalamaresui/CMakeLists.txt
+@@ -1,6 +1,7 @@
+ set( CALAMARESUI_LIBRARY_TARGET calamaresui )
+
+ list( APPEND ${CALAMARESUI_LIBRARY_TARGET}_SOURCES
++ modulesystem/CppJobModule.cpp
+ modulesystem/Module.cpp
+ modulesystem/ModuleManager.cpp
+ modulesystem/ProcessJobModule.cpp
+@@ -14,8 +15,6 @@ list( APPEND ${CALAMARESUI_LIBRARY_TARGET}_SOURCES
+ utils/qjsonmodel.cpp
+ utils/qjsonitem.cpp
+
+- utils/PluginFactory.cpp
+-
+ viewpages/AbstractPage.cpp
+ viewpages/ViewStep.cpp
+
+diff --git a/src/libcalamaresui/modulesystem/CppJobModule.cpp b/src/libcalamaresui/modulesystem/CppJobModule.cpp
+new file mode 100644
+index 0000000..15e41c2
+--- /dev/null
++++ b/src/libcalamaresui/modulesystem/CppJobModule.cpp
+@@ -0,0 +1,128 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2014, Teo Mrnjavac <teo@kde.org>
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "CppJobModule.h"
++
++#include "utils/PluginFactory.h"
++#include "utils/Logger.h"
++#include "CppJob.h"
++
++#include <QDir>
++#include <QPluginLoader>
++
++namespace Calamares {
++
++
++Module::Type
++CppJobModule::type() const
++{
++ return Job;
++}
++
++
++Module::Interface
++CppJobModule::interface() const
++{
++ return QtPlugin;
++}
++
++
++void
++CppJobModule::loadSelf()
++{
++ if ( m_loader )
++ {
++ PluginFactory* pf = qobject_cast< PluginFactory* >( m_loader->instance() );
++ if ( !pf )
++ {
++ cDebug() << Q_FUNC_INFO << m_loader->errorString();
++ return;
++ }
++
++ CppJob *cppJob = pf->create< Calamares::CppJob >();
++ if ( !cppJob )
++ {
++ cDebug() << Q_FUNC_INFO << m_loader->errorString();
++ return;
++ }
++// cDebug() << "CppJobModule loading self for instance" << instanceKey()
++// << "\nCppJobModule at address" << this
++// << "\nCalamares::PluginFactory at address" << pf
++// << "\nCppJob at address" << cppJob;
++
++ cppJob->setModuleInstanceKey( instanceKey() );
++ cppJob->setConfigurationMap( m_configurationMap );
++ m_job = Calamares::job_ptr( static_cast< Calamares::Job * >( cppJob ) );
++ m_loaded = true;
++ cDebug() << "CppJobModule" << instanceKey() << "loading complete.";
++ }
++}
++
++
++QList< job_ptr >
++CppJobModule::jobs() const
++{
++ return QList< job_ptr >() << m_job;
++}
++
++
++void
++CppJobModule::initFrom( const QVariantMap& moduleDescriptor )
++{
++ Module::initFrom( moduleDescriptor );
++ QDir directory( location() );
++ QString load;
++ if ( !moduleDescriptor.value( "load" ).toString().isEmpty() )
++ {
++ load = moduleDescriptor.value( "load" ).toString();
++ load = directory.absoluteFilePath( load );
++ }
++ // If a load path is not specified, we look for a plugin to load in the directory.
++ if ( load.isEmpty() || !QLibrary::isLibrary( load ) )
++ {
++ const QStringList ls = directory.entryList( QStringList{ "*.so" } );
++ if ( !ls.isEmpty() )
++ {
++ for ( QString entry : ls )
++ {
++ entry = directory.absoluteFilePath( entry );
++ if ( QLibrary::isLibrary( entry ) )
++ {
++ load = entry;
++ break;
++ }
++ }
++ }
++ }
++
++ m_loader = new QPluginLoader( load );
++}
++
++CppJobModule::CppJobModule()
++ : Module()
++ , m_loader( nullptr )
++{
++}
++
++CppJobModule::~CppJobModule()
++{
++ delete m_loader;
++}
++
++} // namespace Calamares
+diff --git a/src/libcalamaresui/modulesystem/CppJobModule.h b/src/libcalamaresui/modulesystem/CppJobModule.h
+new file mode 100644
+index 0000000..127614e
+--- /dev/null
++++ b/src/libcalamaresui/modulesystem/CppJobModule.h
+@@ -0,0 +1,53 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2014, Teo Mrnjavac <teo@kde.org>
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef CALAMARES_CPPJOBMODULE_H
++#define CALAMARES_CPPJOBMODULE_H
++
++#include "UiDllMacro.h"
++#include "Module.h"
++
++class QPluginLoader;
++
++namespace Calamares {
++
++class UIDLLEXPORT CppJobModule : public Module
++{
++public:
++ Type type() const override;
++ Interface interface() const override;
++
++ void loadSelf() override;
++ QList< job_ptr > jobs() const override;
++
++protected:
++ void initFrom( const QVariantMap& moduleDescriptor ) override;
++
++private:
++ friend class Module; //so only the superclass can instantiate
++ explicit CppJobModule();
++ virtual ~CppJobModule();
++
++ QPluginLoader* m_loader;
++ job_ptr m_job;
++};
++
++} // namespace Calamares
++
++#endif // CALAMARES_CPPJOBMODULE_H
+diff --git a/src/libcalamaresui/modulesystem/Module.cpp b/src/libcalamaresui/modulesystem/Module.cpp
+index 7809754..2a2fe77 100644
+--- a/src/libcalamaresui/modulesystem/Module.cpp
++++ b/src/libcalamaresui/modulesystem/Module.cpp
+@@ -19,6 +19,7 @@
+ #include "Module.h"
+
+ #include "ProcessJobModule.h"
++#include "CppJobModule.h"
+ #include "ViewModule.h"
+ #include "utils/CalamaresUtils.h"
+ #include "utils/YamlUtils.h"
+@@ -76,7 +77,11 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
+ }
+ else if ( typeString == "job" )
+ {
+- if ( intfString == "process" )
++ if ( intfString == "qtplugin" )
++ {
++ m = new CppJobModule();
++ }
++ else if ( intfString == "process" )
+ {
+ m = new ProcessJobModule();
+ }
+diff --git a/src/libcalamaresui/utils/PluginFactory.cpp b/src/libcalamaresui/utils/PluginFactory.cpp
+deleted file mode 100644
+index 30a5bf4..0000000
+--- a/src/libcalamaresui/utils/PluginFactory.cpp
++++ /dev/null
+@@ -1,123 +0,0 @@
+-/* === This file is part of Calamares - <http://github.com/calamares> ===
+- *
+- * Copyright 2015, Teo Mrnjavac <teo@kde.org>
+- *
+- * Based on KPluginFactory from KCoreAddons, KDE project
+- * Copyright 2007, Matthias Kretz <kretz@kde.org>
+- * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
+- *
+- * Calamares is free software: you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation, either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * Calamares is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#include "PluginFactory.h"
+-#include "PluginFactory_p.h"
+-
+-#include <QObjectCleanupHandler>
+-#include <QDebug>
+-
+-Q_GLOBAL_STATIC(QObjectCleanupHandler, factorycleanup)
+-
+-extern int kLibraryDebugArea();
+-
+-namespace Calamares
+-{
+-
+-PluginFactory::PluginFactory()
+- : d_ptr(new PluginFactoryPrivate)
+-{
+- Q_D(PluginFactory);
+- d->q_ptr = this;
+-
+- factorycleanup()->add(this);
+-}
+-
+-PluginFactory::PluginFactory(PluginFactoryPrivate &d)
+- : d_ptr(&d)
+-{
+- factorycleanup()->add(this);
+-}
+-
+-PluginFactory::~PluginFactory()
+-{
+- delete d_ptr;
+-}
+-
+-void PluginFactory::doRegisterPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceFunction instanceFunction)
+-{
+- Q_D(PluginFactory);
+-
+- Q_ASSERT(metaObject);
+-
+- // we allow different interfaces to be registered without keyword
+- if (!keyword.isEmpty()) {
+- if (d->createInstanceHash.contains(keyword)) {
+- qWarning() << "A plugin with the keyword" << keyword << "was already registered. A keyword must be unique!";
+- }
+- d->createInstanceHash.insert(keyword, PluginFactoryPrivate::Plugin(metaObject, instanceFunction));
+- } else {
+- const QList<PluginFactoryPrivate::Plugin> clashes(d->createInstanceHash.values(keyword));
+- const QMetaObject *superClass = metaObject->superClass();
+- if (superClass) {
+- for (const PluginFactoryPrivate::Plugin &plugin : clashes) {
+- for (const QMetaObject *otherSuper = plugin.first->superClass(); otherSuper;
+- otherSuper = otherSuper->superClass()) {
+- if (superClass == otherSuper) {
+- qWarning() << "Two plugins with the same interface(" << superClass->className() << ") were registered. Use keywords to identify the plugins.";
+- }
+- }
+- }
+- }
+- for (const PluginFactoryPrivate::Plugin &plugin : clashes) {
+- superClass = plugin.first->superClass();
+- if (superClass) {
+- for (const QMetaObject *otherSuper = metaObject->superClass(); otherSuper;
+- otherSuper = otherSuper->superClass()) {
+- if (superClass == otherSuper) {
+- qWarning() << "Two plugins with the same interface(" << superClass->className() << ") were registered. Use keywords to identify the plugins.";
+- }
+- }
+- }
+- }
+- d->createInstanceHash.insertMulti(keyword, PluginFactoryPrivate::Plugin(metaObject, instanceFunction));
+- }
+-}
+-
+-QObject *PluginFactory::create(const char *iface, QWidget *parentWidget, QObject *parent, const QString &keyword)
+-{
+- Q_D(PluginFactory);
+-
+- QObject *obj = 0;
+-
+- const QList<PluginFactoryPrivate::Plugin> candidates(d->createInstanceHash.values(keyword));
+- // for !keyword.isEmpty() candidates.count() is 0 or 1
+-
+- for (const PluginFactoryPrivate::Plugin &plugin : candidates) {
+- for (const QMetaObject *current = plugin.first; current; current = current->superClass()) {
+- if (0 == qstrcmp(iface, current->className())) {
+- if (obj) {
+- qWarning() << "ambiguous interface requested from a DSO containing more than one plugin";
+- }
+- obj = plugin.second(parentWidget, parent);
+- break;
+- }
+- }
+- }
+-
+- if (obj) {
+- emit objectCreated(obj);
+- }
+- return obj;
+-}
+-
+-}
+diff --git a/src/libcalamaresui/utils/PluginFactory.h b/src/libcalamaresui/utils/PluginFactory.h
+deleted file mode 100644
+index a77d959..0000000
+--- a/src/libcalamaresui/utils/PluginFactory.h
++++ /dev/null
+@@ -1,370 +0,0 @@
+-/* === This file is part of Calamares - <http://github.com/calamares> ===
+- *
+- * Copyright 2015, Teo Mrnjavac <teo@kde.org>
+- *
+- * Based on KPluginFactory from KCoreAddons, KDE project
+- * Copyright 2007, Matthias Kretz <kretz@kde.org>
+- * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
+- *
+- * Calamares is free software: you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation, either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * Calamares is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#ifndef CALAMARESPLUGINFACTORY_H
+-#define CALAMARESPLUGINFACTORY_H
+-
+-#include "UiDllMacro.h"
+-
+-#include <QtCore/QObject>
+-#include <QtCore/QVariant>
+-#include <QtCore/QStringList>
+-
+-namespace Calamares
+-{
+-class PluginFactoryPrivate;
+-}
+-
+-#define CalamaresPluginFactory_iid "io.calamares.PluginFactory"
+-
+-#define CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY_SKEL(name, baseFactory, ...) \
+- class name : public Calamares::PluginFactory \
+- { \
+- Q_OBJECT \
+- Q_INTERFACES(Calamares::PluginFactory) \
+- __VA_ARGS__ \
+- public: \
+- explicit name(); \
+- ~name(); \
+- private: \
+- void init(); \
+- };
+-
+-#define CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, baseFactory) \
+- CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY_SKEL(name, baseFactory, Q_PLUGIN_METADATA(IID CalamaresPluginFactory_iid))
+-
+-#define CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations) \
+- name::name() \
+- { \
+- pluginRegistrations \
+- } \
+- name::~name() {}
+-
+-#define CALAMARES_PLUGIN_FACTORY_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations) \
+- CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, baseFactory) \
+- CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, baseFactory, pluginRegistrations)
+-
+-#define CALAMARES_PLUGIN_FACTORY_DECLARATION(name) CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, Calamares::PluginFactory)
+-#define CALAMARES_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
+-
+-/**
+- * \relates PluginFactory
+- *
+- * Create a PluginFactory subclass and export it as the root plugin object.
+- *
+- * \param name The name of the PluginFactory derived class.
+- *
+- * \param pluginRegistrations Code to be inserted into the constructor of the
+- * class. Usually a series of registerPlugin() calls.
+- *
+- * Example:
+- * \code
+- * #include <PluginFactory.h>
+- * #include <plugininterface.h>
+- *
+- * class MyPlugin : public PluginInterface
+- * {
+- * public:
+- * MyPlugin(QObject *parent, const QVariantList &args)
+- * : PluginInterface(parent)
+- * {}
+- * };
+- *
+- * CALAMARES_PLUGIN_FACTORY(MyPluginFactory,
+- * registerPlugin<MyPlugin>();
+- * )
+- *
+- * #include <myplugin.moc>
+- * \endcode
+- *
+- * \see CALAMARES_PLUGIN_FACTORY_DECLARATION
+- * \see CALAMARES_PLUGIN_FACTORY_DEFINITION
+- */
+-#define CALAMARES_PLUGIN_FACTORY(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
+-
+-/**
+- * \relates PluginFactory
+- *
+- * CALAMARES_PLUGIN_FACTORY_DECLARATION declares the PluginFactory subclass. This macro
+- * can be used in a header file.
+- *
+- * \param name The name of the PluginFactory derived class.
+- *
+- * \see CALAMARES_PLUGIN_FACTORY
+- * \see CALAMARES_PLUGIN_FACTORY_DEFINITION
+- */
+-#define CALAMARES_PLUGIN_FACTORY_DECLARATION(name) CALAMARES_PLUGIN_FACTORY_DECLARATION_WITH_BASEFACTORY(name, Calamares::PluginFactory)
+-
+-/**
+- * \relates PluginFactory
+- * CALAMARES_PLUGIN_FACTORY_DEFINITION defines the PluginFactory subclass. This macro
+- * can <b>not</b> be used in a header file.
+- *
+- * \param name The name of the PluginFactory derived class.
+- *
+- * \param pluginRegistrations Code to be inserted into the constructor of the
+- * class. Usually a series of registerPlugin() calls.
+- *
+- * \see CALAMARES_PLUGIN_FACTORY
+- * \see CALAMARES_PLUGIN_FACTORY_DECLARATION
+- */
+-#define CALAMARES_PLUGIN_FACTORY_DEFINITION(name, pluginRegistrations) CALAMARES_PLUGIN_FACTORY_DEFINITION_WITH_BASEFACTORY(name, Calamares::PluginFactory, pluginRegistrations)
+-
+-namespace Calamares
+-{
+-
+-/**
+- * \class PluginFactory PluginFactory.h <PluginFactory.h>
+- *
+- * PluginFactory provides a convenient way to provide factory-style plugins.
+- * Qt plugins provide a singleton object, but a common pattern is for plugins
+- * to generate as many objects of a particular type as the application requires.
+- * By using PluginFactory, you can avoid implementing the factory pattern
+- * yourself.
+- *
+- * PluginFactory also allows plugins to provide multiple different object
+- * types, indexed by keywords.
+- *
+- * The objects created by PluginFactory must inherit QObject, and must have a
+- * standard constructor pattern:
+- * \li if the object is a KPart::Part, it must be of the form
+- * \code
+- * T(QWidget *parentWidget, QObject *parent, const QVariantList &args)
+- * \endcode
+- * \li if it is a QWidget, it must be of the form
+- * \code
+- * T(QWidget *parent, const QVariantList &args)
+- * \endcode
+- * \li otherwise it must be of the form
+- * \code
+- * T(QObject *parent, const QVariantList &args)
+- * \endcode
+- *
+- * You should typically use either CALAMARES_PLUGIN_FACTORY() or
+- * CALAMARES_PLUGIN_FACTORY_WITH_JSON() in your plugin code to create the factory. The
+- * typical pattern is
+- *
+- * \code
+- * #include <PluginFactory.h>
+- * #include <plugininterface.h>
+- *
+- * class MyPlugin : public PluginInterface
+- * {
+- * public:
+- * MyPlugin(QObject *parent, const QVariantList &args)
+- * : PluginInterface(parent)
+- * {}
+- * };
+- *
+- * CALAMARES_PLUGIN_FACTORY(MyPluginFactory,
+- * registerPlugin<MyPlugin>();
+- * )
+- * #include <myplugin.moc>
+- * \endcode
+- *
+- * If you want to load a library use KPluginLoader.
+- * The application that wants to instantiate plugin classes can do the following:
+- * \code
+- * PluginFactory *factory = KPluginLoader("libraryname").factory();
+- * if (factory) {
+- * PluginInterface *p1 = factory->create<PluginInterface>(parent);
+- * OtherInterface *p2 = factory->create<OtherInterface>(parent);
+- * NextInterface *p3 = factory->create<NextInterface>("keyword1", parent);
+- * NextInterface *p3 = factory->create<NextInterface>("keyword2", parent);
+- * }
+- * \endcode
+- *
+- * \author Matthias Kretz <kretz@kde.org>
+- * \author Bernhard Loos <nhuh.put@web.de>
+- */
+-class UIDLLEXPORT PluginFactory : public QObject
+-{
+- Q_OBJECT
+- Q_DECLARE_PRIVATE(PluginFactory)
+-public:
+- /**
+- * This constructor creates a factory for a plugin.
+- */
+- explicit PluginFactory();
+-
+- /**
+- * This destroys the PluginFactory.
+- */
+- virtual ~PluginFactory();
+-
+- /**
+- * Use this method to create an object. It will try to create an object which inherits
+- * \p T. If it has multiple choices, you will get a fatal error (kFatal()), so be careful
+- * to request a unique interface or use keywords.
+- *
+- * \tparam T The interface for which an object should be created. The object will inherit \p T.
+- * \param parent The parent of the object. If \p parent is a widget type, it will also passed
+- * to the parentWidget argument of the CreateInstanceFunction for the object.
+- * \returns A pointer to the created object is returned, or 0 if an error occurred.
+- */
+- template<typename T>
+- T *create(QObject *parent = 0);
+-
+- /**
+- * Use this method to create an object. It will try to create an object which inherits
+- * \p T and was registered with \p keyword.
+- *
+- * \tparam T The interface for which an object should be created. The object will inherit \p T.
+- * \param keyword The keyword of the object.
+- * \param parent The parent of the object. If \p parent is a widget type, it will also passed
+- * to the parentWidget argument of the CreateInstanceFunction for the object.
+- * \returns A pointer to the created object is returned, or 0 if an error occurred.
+- */
+- template<typename T>
+- T *create(const QString &keyword, QObject *parent = 0);
+-
+-Q_SIGNALS:
+- void objectCreated(QObject *object);
+-
+-protected:
+- /**
+- * Function pointer type to a function that instantiates a plugin.
+- */
+- typedef QObject *(*CreateInstanceFunction)(QWidget *, QObject *);
+-
+- /**
+- * This is used to detect the arguments need for the constructor of plugin classes.
+- * You can inherit it, if you want to add new classes and still keep support for the old ones.
+- */
+- template<class impl>
+- struct InheritanceChecker {
+- CreateInstanceFunction createInstanceFunction(QWidget *)
+- {
+- return &createInstance<impl, QWidget>;
+- }
+- CreateInstanceFunction createInstanceFunction(...)
+- {
+- return &createInstance<impl, QObject>;
+- }
+- };
+-
+- explicit PluginFactory(PluginFactoryPrivate &dd);
+-
+- /**
+- * Registers a plugin with the factory. Call this function from the constructor of the
+- * PluginFactory subclass to make the create function able to instantiate the plugin when asked
+- * for an interface the plugin implements.
+- *
+- * \tparam T the name of the plugin class
+- *
+- * \param keyword An optional keyword as unique identifier for the plugin. This allows you to
+- * put more than one plugin with the same interface into the same library using the same
+- * factory. X-KDE-PluginKeyword is a convenient way to specify the keyword in a desktop file.
+- *
+- * \param instanceFunction A function pointer to a function that creates an instance of the
+- * plugin. The default function that will be used depends on the type of interface. If the
+- * interface inherits from
+- * \li \c KParts::Part the function will call
+- * \code
+- * new T(QWidget *parentWidget, QObject *parent)
+- * \endcode
+- * \li \c QWidget the function will call
+- * \code
+- * new T(QWidget *parent)
+- * \endcode
+- * \li else the function will call
+- * \code
+- * new T(QObject *parent)
+- * \endcode
+- */
+- template<class T>
+- void registerPlugin(const QString &keyword = QString(),
+- CreateInstanceFunction instanceFunction
+- = InheritanceChecker<T>().createInstanceFunction(reinterpret_cast<T *>(0)))
+- {
+- doRegisterPlugin(keyword, &T::staticMetaObject, instanceFunction);
+- }
+-
+- PluginFactoryPrivate *const d_ptr;
+-
+- /**
+- * This function is called when the factory asked to create an Object.
+- *
+- * You may reimplement it to provide a very flexible factory. This is especially useful to
+- * provide generic factories for plugins implemeted using a scripting language.
+- *
+- * \param iface The staticMetaObject::className() string identifying the plugin interface that
+- * was requested. E.g. for KCModule plugins this string will be "KCModule".
+- * \param parentWidget Only used if the requested plugin is a KPart.
+- * \param parent The parent object for the plugin object.
+- * \param args A plugin specific list of arbitrary arguments.
+- * \param keyword A string that uniquely identifies the plugin. If a KService is used this
+- * keyword is read from the X-KDE-PluginKeyword entry in the .desktop file.
+- */
+- virtual QObject *create(const char *iface, QWidget *parentWidget, QObject *parent, const QString &keyword);
+-
+- template<class impl, class ParentType>
+- static QObject *createInstance(QWidget *parentWidget, QObject *parent)
+- {
+- Q_UNUSED(parentWidget);
+- ParentType *p = 0;
+- if (parent) {
+- p = qobject_cast<ParentType *>(parent);
+- Q_ASSERT(p);
+- }
+- return new impl(p);
+- }
+-
+-private:
+- void doRegisterPlugin(const QString &keyword, const QMetaObject *metaObject, CreateInstanceFunction instanceFunction);
+-};
+-
+-template<typename T>
+-inline T *PluginFactory::create(QObject *parent)
+-{
+- QObject *o = create(T::staticMetaObject.className(),
+- parent && parent->isWidgetType() ? reinterpret_cast<QWidget *>(parent) : 0,
+- parent,
+- QString());
+-
+- T *t = qobject_cast<T *>(o);
+- if (!t) {
+- delete o;
+- }
+- return t;
+-}
+-
+-template<typename T>
+-inline T *PluginFactory::create(const QString &keyword, QObject *parent)
+-{
+- QObject *o = create(T::staticMetaObject.className(),
+- parent && parent->isWidgetType() ? reinterpret_cast<QWidget *>(parent) : 0,
+- parent,
+- keyword);
+-
+- T *t = qobject_cast<T *>(o);
+- if (!t) {
+- delete o;
+- }
+- return t;
+-}
+-
+-}
+-
+-Q_DECLARE_INTERFACE(Calamares::PluginFactory, CalamaresPluginFactory_iid)
+-
+-#endif // CALAMARESPLUGINFACTORY_H
+diff --git a/src/libcalamaresui/utils/PluginFactory_p.h b/src/libcalamaresui/utils/PluginFactory_p.h
+deleted file mode 100644
+index a0b4a1c..0000000
+--- a/src/libcalamaresui/utils/PluginFactory_p.h
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/* === This file is part of Calamares - <http://github.com/calamares> ===
+- *
+- * Copyright 2015, Teo Mrnjavac <teo@kde.org>
+- *
+- * Based on KPluginFactory from KCoreAddons, KDE project
+- * Copyright 2007, Matthias Kretz <kretz@kde.org>
+- * Copyright 2007, Bernhard Loos <nhuh.put@web.de>
+- *
+- * Calamares is free software: you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation, either version 3 of the License, or
+- * (at your option) any later version.
+- *
+- * Calamares is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
+- */
+-
+-#ifndef CALAMARESPLUGINFACTORY_P_H
+-#define CALAMARESPLUGINFACTORY_P_H
+-
+-#include "PluginFactory.h"
+-
+-#include <QtCore/QHash>
+-
+-namespace Calamares
+-{
+-
+-class PluginFactoryPrivate
+-{
+- Q_DECLARE_PUBLIC(PluginFactory)
+-protected:
+- typedef QPair<const QMetaObject *, PluginFactory::CreateInstanceFunction> Plugin;
+-
+- PluginFactoryPrivate()
+- : catalogInitialized( false )
+- , q_ptr( nullptr )
+- {}
+- ~PluginFactoryPrivate() {}
+-
+- QHash<QString, Plugin> createInstanceHash;
+- QString catalogName;
+- bool catalogInitialized;
+-
+- PluginFactory *q_ptr;
+-};
+-
+-}
+-
+-#endif // CALAMARESPLUGINFACTORY_P_H
+diff --git a/src/modules/dracutlukscfg/CMakeLists.txt b/src/modules/dracutlukscfg/CMakeLists.txt
+new file mode 100644
+index 0000000..a239521
+--- /dev/null
++++ b/src/modules/dracutlukscfg/CMakeLists.txt
+@@ -0,0 +1,9 @@
++calamares_add_plugin( dracutlukscfg
++ TYPE job
++ EXPORT_MACRO PLUGINDLLEXPORT_PRO
++ SOURCES
++ DracutLuksCfgJob.cpp
++ LINK_LIBRARIES
++ calamares
++ SHARED_LIB
++)
+diff --git a/src/modules/dracutlukscfg/DracutLuksCfgJob.cpp b/src/modules/dracutlukscfg/DracutLuksCfgJob.cpp
+new file mode 100644
+index 0000000..273ff98
+--- /dev/null
++++ b/src/modules/dracutlukscfg/DracutLuksCfgJob.cpp
+@@ -0,0 +1,143 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include "DracutLuksCfgJob.h"
++
++#include <QDir>
++#include <QFile>
++#include <QFileInfo>
++#include <QTextStream>
++
++#include "CalamaresVersion.h"
++#include "JobQueue.h"
++#include "GlobalStorage.h"
++
++#include "utils/Logger.h"
++
++// static
++const QString DracutLuksCfgJob::CONFIG_FILE = QStringLiteral( "/etc/dracut.conf.d/calamares-luks.conf" );
++
++// static
++const char *DracutLuksCfgJob::CONFIG_FILE_CONTENTS =
++ "# Configuration file automatically written by the Calamares system installer\n"
++ "# (This file is written once at install time and should be safe to edit.)\n"
++ "# Enables support for LUKS full disk encryption with single sign on from GRUB.\n"
++ "\n"
++ "# force installing /etc/crypttab even if hostonly=\"no\", install the keyfile\n"
++ "install_items+=\" /etc/crypttab /crypto_keyfile.bin \"\n";
++
++// static
++const QString DracutLuksCfgJob::CONFIG_FILE_SWAPLINE = QStringLiteral( "# enable automatic resume from swap\nadd_device+=\" /dev/disk/by-uuid/%1 \"\n" );
++
++// static
++QString
++DracutLuksCfgJob::rootMountPoint()
++{
++ Calamares::GlobalStorage *globalStorage = Calamares::JobQueue::instance()->globalStorage();
++ return globalStorage->value( QStringLiteral( "rootMountPoint" ) ).toString();
++}
++
++// static
++QVariantList
++DracutLuksCfgJob::partitions()
++{
++ Calamares::GlobalStorage *globalStorage = Calamares::JobQueue::instance()->globalStorage();
++ return globalStorage->value( QStringLiteral( "partitions" ) ).toList();
++}
++
++// static
++bool
++DracutLuksCfgJob::isRootEncrypted()
++{
++ const QVariantList partitions = DracutLuksCfgJob::partitions();
++ for ( const QVariant &partition : partitions )
++ {
++ QVariantMap partitionMap = partition.toMap();
++ QString mountPoint = partitionMap.value( QStringLiteral( "mountPoint" ) ).toString();
++ if ( mountPoint == QStringLiteral( "/" ) )
++ return partitionMap.contains( QStringLiteral( "luksMapperName" ) );
++ }
++ return false;
++}
++
++// static
++QString
++DracutLuksCfgJob::swapOuterUuid()
++{
++ const QVariantList partitions = DracutLuksCfgJob::partitions();
++ for ( const QVariant &partition : partitions )
++ {
++ QVariantMap partitionMap = partition.toMap();
++ QString fsType = partitionMap.value( QStringLiteral( "fs" ) ).toString();
++ if ( fsType == QStringLiteral( "linuxswap" ) && partitionMap.contains( QStringLiteral( "luksMapperName" ) ) )
++ return partitionMap.value( QStringLiteral( "luksUuid" ) ).toString();
++ }
++ return QString();
++}
++
++DracutLuksCfgJob::DracutLuksCfgJob( QObject* parent )
++ : Calamares::CppJob( parent )
++{
++}
++
++
++DracutLuksCfgJob::~DracutLuksCfgJob()
++{
++}
++
++
++QString
++DracutLuksCfgJob::prettyName() const
++{
++ if ( isRootEncrypted() )
++ return tr( "Write LUKS configuration for Dracut to %1" ).arg( CONFIG_FILE );
++ else
++ return tr( "Skip writing LUKS configuration for Dracut: \"/\" partition is not encrypted" );
++}
++
++
++Calamares::JobResult
++DracutLuksCfgJob::exec()
++{
++ if ( isRootEncrypted() )
++ {
++ const QString realConfigFilePath = rootMountPoint() + CONFIG_FILE;
++ cDebug() << "[DRACUTLUKSCFG]: Writing" << realConfigFilePath;
++ QDir( QStringLiteral( "/" ) ).mkpath( QFileInfo( realConfigFilePath ).absolutePath() );
++ QFile configFile( realConfigFilePath );
++ if ( ! configFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
++ {
++ cDebug() << "[DRACUTLUKSCFG]: Failed to open" << realConfigFilePath;
++ return Calamares::JobResult::error( tr( "Failed to open %1" ).arg( realConfigFilePath ) );
++ }
++ QTextStream outStream( &configFile );
++ outStream << CONFIG_FILE_CONTENTS;
++ const QString swapOuterUuid = DracutLuksCfgJob::swapOuterUuid();
++ if ( ! swapOuterUuid.isEmpty() )
++ {
++ cDebug() << "[DRACUTLUKSCFG]: Swap outer UUID" << swapOuterUuid;
++ outStream << CONFIG_FILE_SWAPLINE.arg( swapOuterUuid ).toLatin1();
++ }
++ cDebug() << "[DRACUTLUKSCFG]: Wrote config to" << realConfigFilePath;
++ } else
++ cDebug() << "[DRACUTLUKSCFG]: / not encrypted, skipping";
++
++ return Calamares::JobResult::ok();
++}
++
++CALAMARES_PLUGIN_FACTORY_DEFINITION( DracutLuksCfgJobFactory, registerPlugin<DracutLuksCfgJob>(); )
+diff --git a/src/modules/dracutlukscfg/DracutLuksCfgJob.h b/src/modules/dracutlukscfg/DracutLuksCfgJob.h
+new file mode 100644
+index 0000000..bfedb85
+--- /dev/null
++++ b/src/modules/dracutlukscfg/DracutLuksCfgJob.h
+@@ -0,0 +1,56 @@
++/* === This file is part of Calamares - <http://github.com/calamares> ===
++ *
++ * Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
++ *
++ * Calamares is free software: you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation, either version 3 of the License, or
++ * (at your option) any later version.
++ *
++ * Calamares is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef DRACUTLUKSCFGJOB_H
++#define DRACUTLUKSCFGJOB_H
++
++#include <QObject>
++#include <QVariantMap>
++
++#include <CppJob.h>
++
++#include <utils/PluginFactory.h>
++
++#include <PluginDllMacro.h>
++
++class PLUGINDLLEXPORT DracutLuksCfgJob : public Calamares::CppJob
++{
++ Q_OBJECT
++
++public:
++ explicit DracutLuksCfgJob( QObject* parent = nullptr );
++ virtual ~DracutLuksCfgJob();
++
++ QString prettyName() const override;
++
++ Calamares::JobResult exec() override;
++
++private:
++ static const QString CONFIG_FILE;
++ static const char *CONFIG_FILE_CONTENTS;
++ static const QString CONFIG_FILE_SWAPLINE;
++
++ static QString rootMountPoint();
++ static QVariantList partitions();
++ static bool isRootEncrypted();
++ static QString swapOuterUuid();
++};
++
++CALAMARES_PLUGIN_FACTORY_DECLARATION( DracutLuksCfgJobFactory )
++
++#endif // DRACUTLUKSCFGJOB_H
+diff --git a/src/modules/dracutlukscfg/module.desc b/src/modules/dracutlukscfg/module.desc
+new file mode 100644
+index 0000000..10d9b78
+--- /dev/null
++++ b/src/modules/dracutlukscfg/module.desc
+@@ -0,0 +1,7 @@
++# Module metadata file for dracutlukscfg job
++# Syntax is YAML 1.2
++---
++type: "job"
++name: "dracutlukscfg"
++interface: "qtplugin"
++load: "libcalamares_job_dracutlukscfg.so"
+diff --git a/src/modules/fstab/fstab.conf b/src/modules/fstab/fstab.conf
+index 7dbf529..c3dbfc3 100644
+--- a/src/modules/fstab/fstab.conf
++++ b/src/modules/fstab/fstab.conf
+@@ -8,3 +8,6 @@ ssdExtraMountOptions:
+ xfs: discard
+ swap: discard
+ btrfs: discard,compress=lzo
++crypttabOptions: luks
++# For Debian and Debian-based distributions, change the above line to:
++# crypttabOptions: luks,keyscript=/bin/cat
+diff --git a/src/modules/fstab/main.py b/src/modules/fstab/main.py
+index 65f483b..05b094f 100644
+--- a/src/modules/fstab/main.py
++++ b/src/modules/fstab/main.py
+@@ -102,11 +102,13 @@ class FstabGenerator(object):
+ :param mount_options:
+ :param ssd_extra_mount_options:
+ """
+- def __init__(self, partitions, root_mount_point, mount_options, ssd_extra_mount_options):
++ def __init__(self, partitions, root_mount_point, mount_options,
++ ssd_extra_mount_options, crypttab_options):
+ self.partitions = partitions
+ self.root_mount_point = root_mount_point
+ self.mount_options = mount_options
+ self.ssd_extra_mount_options = ssd_extra_mount_options
++ self.crypttab_options = crypttab_options
+ self.ssd_disks = set()
+ self.root_is_ssd = False
+
+@@ -152,21 +154,20 @@ class FstabGenerator(object):
+ if not mapper_name or not luks_uuid:
+ return None
+
+- if mount_point == "/":
+- return None
+-
+ return dict(
+ name=mapper_name,
+ device="UUID=" + luks_uuid,
+ password="/crypto_keyfile.bin",
++ options=self.crypttab_options,
+ )
+
+ def print_crypttab_line(self, dct, file=None):
+ """ Prints line to '/etc/crypttab' file. """
+- line = "{:21} {:<45} {}".format(dct["name"],
+- dct["device"],
+- dct["password"],
+- )
++ line = "{:21} {:<45} {} {}".format(dct["name"],
++ dct["device"],
++ dct["password"],
++ dct["options"],
++ )
+
+ print(line, file=file)
+
+@@ -258,9 +259,11 @@ def run():
+ root_mount_point = global_storage.value("rootMountPoint")
+ mount_options = conf["mountOptions"]
+ ssd_extra_mount_options = conf.get("ssdExtraMountOptions", {})
++ crypttab_options = conf.get("crypttabOptions", "luks")
+ generator = FstabGenerator(partitions,
+ root_mount_point,
+ mount_options,
+- ssd_extra_mount_options)
++ ssd_extra_mount_options,
++ crypttab_options)
+
+ return generator.run()
+--
+2.1.0
+