to use."
-msgstr ""
+msgstr "Nu sunt partiţii definite ca 1{!s}1 ."
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
#: src/modules/luksopenswaphookcfg/main.py:91
msgid "No root mount point is given for
{!s}
to use."
-msgstr ""
+msgstr "Nu este definită o partiţie rădăcină pentru 1{!s}1 ."
#: src/modules/grubcfg/main.py:28
msgid "Configure GRUB."
diff --git a/lang/python/ta_IN/LC_MESSAGES/python.po b/lang/python/ta_IN/LC_MESSAGES/python.po
new file mode 100644
index 000000000..666703faf
--- /dev/null
+++ b/lang/python/ta_IN/LC_MESSAGES/python.po
@@ -0,0 +1,387 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR , YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2021-11-02 15:45+0100\n"
+"PO-Revision-Date: 2017-08-09 10:34+0000\n"
+"Language-Team: Tamil (India) (https://www.transifex.com/calamares/teams/20061/ta_IN/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: ta_IN\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: src/modules/initramfscfg/main.py:32
+msgid "Configuring initramfs."
+msgstr ""
+
+#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
+#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
+#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
+#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
+#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
+#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
+#: src/modules/openrcdmcryptcfg/main.py:76
+#: src/modules/luksopenswaphookcfg/main.py:86
+#: src/modules/luksopenswaphookcfg/main.py:90
+msgid "Configuration Error"
+msgstr ""
+
+#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
+#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
+#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
+#: src/modules/luksopenswaphookcfg/main.py:87
+msgid "No partitions are defined for
{!s}
to use."
+msgstr ""
+
+#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
+#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
+#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
+#: src/modules/luksopenswaphookcfg/main.py:91
+msgid "No root mount point is given for
{!s}
to use."
+msgstr ""
+
+#: src/modules/grubcfg/main.py:28
+msgid "Configure GRUB."
+msgstr ""
+
+#: src/modules/bootloader/main.py:43
+msgid "Install bootloader."
+msgstr ""
+
+#: src/modules/bootloader/main.py:508
+msgid "Bootloader installation error"
+msgstr ""
+
+#: src/modules/bootloader/main.py:509
+msgid ""
+"The bootloader could not be installed. The installation command "
+"
{!s}
returned error code {!s}."
+msgstr ""
+
+#: src/modules/fstab/main.py:29
+msgid "Writing fstab."
+msgstr ""
+
+#: src/modules/fstab/main.py:389
+msgid "No
{!s}
configuration is given for
{!s}
to use."
+msgstr ""
+
+#: src/modules/dracut/main.py:27
+msgid "Creating initramfs with dracut."
+msgstr ""
+
+#: src/modules/dracut/main.py:49
+msgid "Failed to run dracut on the target"
+msgstr ""
+
+#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
+msgid "The exit code was {}"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:526
+msgid "Cannot write KDM configuration file"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:527
+msgid "KDM config file {!s} does not exist"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:588
+msgid "Cannot write LXDM configuration file"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:589
+msgid "LXDM config file {!s} does not exist"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:672
+msgid "Cannot write LightDM configuration file"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:673
+msgid "LightDM config file {!s} does not exist"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:747
+msgid "Cannot configure LightDM"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:748
+msgid "No LightDM greeter installed."
+msgstr ""
+
+#: src/modules/displaymanager/main.py:779
+msgid "Cannot write SLIM configuration file"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:780
+msgid "SLIM config file {!s} does not exist"
+msgstr ""
+
+#: src/modules/displaymanager/main.py:906
+msgid "No display managers selected for the displaymanager module."
+msgstr ""
+
+#: src/modules/displaymanager/main.py:907
+msgid ""
+"The displaymanagers list is empty or undefined in both globalstorage and "
+"displaymanager.conf."
+msgstr ""
+
+#: src/modules/displaymanager/main.py:989
+msgid "Display manager configuration was incomplete"
+msgstr ""
+
+#: src/modules/services-openrc/main.py:29
+msgid "Configure OpenRC services"
+msgstr ""
+
+#: src/modules/services-openrc/main.py:57
+msgid "Cannot add service {name!s} to run-level {level!s}."
+msgstr ""
+
+#: src/modules/services-openrc/main.py:59
+msgid "Cannot remove service {name!s} from run-level {level!s}."
+msgstr ""
+
+#: src/modules/services-openrc/main.py:61
+msgid ""
+"Unknown service-action {arg!s} for service {name!s} in run-"
+"level {level!s}."
+msgstr ""
+
+#: src/modules/services-openrc/main.py:93
+#: src/modules/services-systemd/main.py:59
+msgid "Cannot modify service"
+msgstr ""
+
+#: src/modules/services-openrc/main.py:94
+msgid ""
+"rc-update {arg!s} call in chroot returned error code {num!s}."
+msgstr ""
+
+#: src/modules/services-openrc/main.py:101
+msgid "Target runlevel does not exist"
+msgstr ""
+
+#: src/modules/services-openrc/main.py:102
+msgid ""
+"The path for runlevel {level!s} is {path!s}, which does not "
+"exist."
+msgstr ""
+
+#: src/modules/services-openrc/main.py:110
+msgid "Target service does not exist"
+msgstr ""
+
+#: src/modules/services-openrc/main.py:111
+msgid ""
+"The path for service {name!s} is {path!s}, which does not "
+"exist."
+msgstr ""
+
+#: src/modules/networkcfg/main.py:29
+msgid "Saving network configuration."
+msgstr ""
+
+#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
+#: src/modules/packages/main.py:69
+msgid "Install packages."
+msgstr ""
+
+#: src/modules/packages/main.py:57
+#, python-format
+msgid "Processing packages (%(count)d / %(total)d)"
+msgstr ""
+
+#: src/modules/packages/main.py:62
+#, python-format
+msgid "Installing one package."
+msgid_plural "Installing %(num)d packages."
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/modules/packages/main.py:65
+#, python-format
+msgid "Removing one package."
+msgid_plural "Removing %(num)d packages."
+msgstr[0] ""
+msgstr[1] ""
+
+#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
+#: src/modules/packages/main.py:678
+msgid "Package Manager error"
+msgstr ""
+
+#: src/modules/packages/main.py:639
+msgid ""
+"The package manager could not prepare updates. The command
{!s}
"
+"returned error code {!s}."
+msgstr ""
+
+#: src/modules/packages/main.py:651
+msgid ""
+"The package manager could not update the system. The command
{!s}
"
+" returned error code {!s}."
+msgstr ""
+
+#: src/modules/packages/main.py:679
+msgid ""
+"The package manager could not make changes to the installed system. The "
+"command
{!s}
returned error code {!s}."
+msgstr ""
+
+#: src/modules/plymouthcfg/main.py:27
+msgid "Configure Plymouth theme"
+msgstr ""
+
+#: src/modules/initcpiocfg/main.py:28
+msgid "Configuring mkinitcpio."
+msgstr ""
+
+#: src/modules/localecfg/main.py:30
+msgid "Configuring locales."
+msgstr ""
+
+#: src/modules/mount/main.py:30
+msgid "Mounting partitions."
+msgstr ""
+
+#: src/modules/rawfs/main.py:26
+msgid "Installing data."
+msgstr ""
+
+#: src/modules/dummypython/main.py:35
+msgid "Dummy python job."
+msgstr ""
+
+#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
+#: src/modules/dummypython/main.py:94
+msgid "Dummy python step {}"
+msgstr ""
+
+#: src/modules/hwclock/main.py:26
+msgid "Setting hardware clock."
+msgstr ""
+
+#: src/modules/umount/main.py:31
+msgid "Unmount file systems."
+msgstr ""
+
+#: src/modules/openrcdmcryptcfg/main.py:26
+msgid "Configuring OpenRC dmcrypt service."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:26
+msgid "Configure systemd services"
+msgstr ""
+
+#: src/modules/services-systemd/main.py:60
+msgid ""
+"systemctl {arg!s} call in chroot returned error code {num!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:63
+#: src/modules/services-systemd/main.py:69
+msgid "Cannot enable systemd service {name!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:65
+msgid "Cannot enable systemd target {name!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:67
+msgid "Cannot enable systemd timer {name!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:71
+msgid "Cannot disable systemd target {name!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:73
+msgid "Cannot mask systemd unit {name!s}."
+msgstr ""
+
+#: src/modules/services-systemd/main.py:75
+msgid ""
+"Unknown systemd commands {command!s} and "
+"{suffix!s} for unit {name!s}."
+msgstr ""
+
+#: src/modules/mkinitfs/main.py:27
+msgid "Creating initramfs with mkinitfs."
+msgstr ""
+
+#: src/modules/mkinitfs/main.py:49
+msgid "Failed to run mkinitfs on the target"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:34
+msgid "Filling up filesystems."
+msgstr ""
+
+#: src/modules/unpackfs/main.py:254
+msgid "rsync failed with error code {}."
+msgstr ""
+
+#: src/modules/unpackfs/main.py:299
+msgid "Unpacking image {}/{}, file {}/{}"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:314
+msgid "Starting to unpack {}"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
+msgid "Failed to unpack image \"{}\""
+msgstr ""
+
+#: src/modules/unpackfs/main.py:430
+msgid "No mount point for root partition"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:431
+msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:436
+msgid "Bad mount point for root partition"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:437
+msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
+#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
+msgid "Bad unsquash configuration"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:454
+msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:458
+msgid "The source filesystem \"{}\" does not exist"
+msgstr ""
+
+#: src/modules/unpackfs/main.py:464
+msgid ""
+"Failed to find unsquashfs, make sure you have the squashfs-tools package "
+"installed."
+msgstr ""
+
+#: src/modules/unpackfs/main.py:479
+msgid "The destination \"{}\" in the target system is not a directory"
+msgstr ""
+
+#: src/modules/luksopenswaphookcfg/main.py:26
+msgid "Configuring encrypted swap."
+msgstr ""
diff --git a/lang/python/vi/LC_MESSAGES/python.po b/lang/python/vi/LC_MESSAGES/python.po
index 900b99454..8948806ae 100644
--- a/lang/python/vi/LC_MESSAGES/python.po
+++ b/lang/python/vi/LC_MESSAGES/python.po
@@ -5,7 +5,7 @@
#
# Translators:
# T. Tran , 2020
-# Th1nhhdk, 2021
+# th1nhhdk , 2021
#
#, fuzzy
msgid ""
@@ -14,7 +14,7 @@ msgstr ""
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
-"Last-Translator: Th1nhhdk, 2021\n"
+"Last-Translator: th1nhhdk , 2021\n"
"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
diff --git a/src/modules/README.md b/src/modules/README.md
index 7b4d4b3a3..09696e66b 100644
--- a/src/modules/README.md
+++ b/src/modules/README.md
@@ -86,18 +86,18 @@ it needs those keys.
### Emergency Modules
-Only C++ modules and job modules may be emergency modules. If, during an
-*exec* step in the sequence, a module fails, installation as a whole fails
-and the install is aborted. If there are emergency modules in the **same**
-exec block, those will be executed before the installation is aborted.
-Non-emergency modules are not executed.
+If, during an *exec* step in the sequence, a module fails, installation as
+a whole fails and the install is aborted. If there are emergency modules
+in the **same** exec block, those will be executed before the installation
+is aborted. Non-emergency modules are not executed.
If an emergency-module fails while processing emergency-modules for
another failed module, that failure is ignored and emergency-module
processing continues.
Use the EMERGENCY keyword in the CMake description of a C++ module
-to generate a suitable `module.desc`.
+to generate a suitable `module.desc`. For Python modules, manually add
+`emergency: true` to `module.desc`.
A module that is marked as an emergency module in its module.desc
must **also** set the *emergency* key to *true* in its configuration file
diff --git a/src/modules/luksopenswaphookcfg/CMakeLists.txt b/src/modules/luksopenswaphookcfg/CMakeLists.txt
new file mode 100644
index 000000000..caede06a7
--- /dev/null
+++ b/src/modules/luksopenswaphookcfg/CMakeLists.txt
@@ -0,0 +1,22 @@
+# === This file is part of Calamares - ===
+#
+# SPDX-FileCopyrightText: 2021 Adriaan de Groot
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
+# use LOSH all over the place as a shorthand.
+calamares_add_plugin( luksopenswaphookcfg
+ TYPE job
+ EXPORT_MACRO PLUGINDLLEXPORT_PRO
+ SOURCES
+ LOSHJob.cpp
+ SHARED_LIB
+)
+
+calamares_add_test(
+ luksopenswaphooktest
+ SOURCES
+ LOSHJob.cpp
+ Tests.cpp
+)
diff --git a/src/modules/luksopenswaphookcfg/LOSHInfo.h b/src/modules/luksopenswaphookcfg/LOSHInfo.h
new file mode 100644
index 000000000..1a87f4e61
--- /dev/null
+++ b/src/modules/luksopenswaphookcfg/LOSHInfo.h
@@ -0,0 +1,66 @@
+/* === This file is part of Calamares - ===
+ *
+ * SPDX-FileCopyrightText: 2021 Adriaan de Groot
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+#ifndef LUKSOPENSWAPHOOKCFG_LOSHINFO_H
+#define LUKSOPENSWAPHOOKCFG_LOSHINFO_H
+
+#include
+
+/** @brief Information needed to create a suitable config file
+ *
+ * The LUKS swap configuration has a handful of keys that need to
+ * be written to the config file. This struct holds those keys
+ * and can find the key values from Global Storage (where the
+ * *partition* module sets them).
+ */
+struct LOSHInfo
+{
+ // Member names copied from Python code
+ QString swap_outer_uuid;
+ QString swap_mapper_name;
+ QString mountable_keyfile_device;
+ QString swap_device_path;
+ QString keyfile_device_mount_options;
+
+ bool isValid() const { return !swap_device_path.isEmpty(); }
+
+ /** @brief Helper method for doing key-value replacements
+ *
+ * Given a named @p key (e.g. "duck", or "swap_device"), returns the
+ * value set for that key. Invalid keys (e.g. "duck") return an empty string.
+ */
+ QString replacementFor( const QString& key ) const
+ {
+ if ( key == QStringLiteral( "swap_device" ) )
+ {
+ return swap_device_path;
+ }
+ if ( key == QStringLiteral( "crypt_swap_name" ) )
+ {
+ return swap_mapper_name;
+ }
+ if ( key == QStringLiteral( "keyfile_device" ) )
+ {
+ return mountable_keyfile_device;
+ }
+ if ( key == QStringLiteral( "keyfile_filename" ) )
+ {
+ return QStringLiteral( "crypto_keyfile.bin" );
+ }
+ if ( key == QStringLiteral( "keyfile_device_mount_options" ) )
+ {
+ return keyfile_device_mount_options;
+ }
+ return QString();
+ }
+
+ /** @brief Creates a struct from information already set in GS
+ *
+ */
+ static LOSHInfo fromGlobalStorage();
+};
+
+#endif
diff --git a/src/modules/luksopenswaphookcfg/LOSHJob.cpp b/src/modules/luksopenswaphookcfg/LOSHJob.cpp
new file mode 100644
index 000000000..42f160460
--- /dev/null
+++ b/src/modules/luksopenswaphookcfg/LOSHJob.cpp
@@ -0,0 +1,181 @@
+/* === This file is part of Calamares - ===
+ *
+ * SPDX-FileCopyrightText: 2021 Adriaan de Groot
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+#include "LOSHJob.h"
+
+#include "LOSHInfo.h"
+
+#include "GlobalStorage.h"
+#include "JobQueue.h"
+#include "utils/CalamaresUtilsSystem.h"
+#include "utils/Logger.h"
+#include "utils/Permissions.h"
+#include "utils/PluginFactory.h"
+#include "utils/String.h"
+#include "utils/Variant.h"
+
+#include
+#include
+#include
+#include
+
+LOSHJob::LOSHJob( QObject* parent )
+ : Calamares::CppJob( parent )
+{
+}
+
+LOSHJob::~LOSHJob() {}
+
+
+QString
+LOSHJob::prettyName() const
+{
+ return tr( "Configuring encrypted swap." );
+}
+
+STATICTEST QString
+get_assignment_part( const QString& line )
+{
+ static QRegularExpression re( "^[# \\t]*([A-Za-z_]+)[ \\t]*=" );
+ auto m = re.match( line );
+ if ( m.hasMatch() )
+ {
+ return m.captured( 1 );
+ }
+ return QString();
+}
+
+/** Writes the config file at @p path
+ *
+ * NOTE: @p path is relative to the target system, not an absolute path.
+ */
+STATICTEST void
+write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info )
+{
+ if ( info.isValid() )
+ {
+ for ( auto& line : contents )
+ {
+ const QString key = get_assignment_part( line );
+ QString replacement = info.replacementFor( key );
+ if ( !replacement.isEmpty() )
+ {
+ line.clear();
+ line.append( QStringLiteral( "%1=%2" ).arg( key, replacement ) );
+ }
+ }
+ cDebug() << "Writing" << contents.length() << "line configuration to" << path;
+ // \n between each two lines, and a \n at the end
+ CalamaresUtils::System::instance()->createTargetFile(
+ path, contents.join( '\n' ).append( '\n' ).toUtf8(), CalamaresUtils::System::WriteMode::Overwrite );
+ }
+ else
+ {
+ cDebug() << "Will not write an invalid configuration to" << path;
+ }
+}
+
+Calamares::JobResult
+LOSHJob::exec()
+{
+ const auto* sys = CalamaresUtils::System::instance();
+ if ( !sys )
+ {
+ return Calamares::JobResult::internalError(
+ "LuksOpenSwapHook", tr( "No target system available." ), Calamares::JobResult::InvalidConfiguration );
+ }
+
+ Calamares::GlobalStorage* gs
+ = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
+ if ( !gs || gs->value( "rootMountPoint" ).toString().isEmpty() )
+ {
+ return Calamares::JobResult::internalError(
+ "LuksOpenSwapHook", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
+ }
+ if ( m_configFilePath.isEmpty() )
+ {
+ return Calamares::JobResult::internalError(
+ "LuksOpenSwapHook", tr( "No configFilePath is set." ), Calamares::JobResult::InvalidConfiguration );
+ }
+
+ QStringList contents = sys->readTargetFile( m_configFilePath );
+ if ( contents.isEmpty() )
+ {
+ contents << QStringLiteral( "# swap_device=" ) << QStringLiteral( "# crypt_swap_name=" )
+ << QStringLiteral( "# keyfile_device=" ) << QStringLiteral( "# keyfile_filename=" )
+ << QStringLiteral( "# keyfile_device_mount_options" );
+ }
+
+ write_openswap_conf( m_configFilePath, contents, LOSHInfo::fromGlobalStorage() );
+ return Calamares::JobResult::ok();
+}
+
+void
+LOSHJob::setConfigurationMap( const QVariantMap& configurationMap )
+{
+ m_configFilePath = CalamaresUtils::getString(
+ configurationMap, QStringLiteral( "configFilePath" ), QStringLiteral( "/etc/openswap.conf" ) );
+}
+
+STATICTEST void
+globalStoragePartitionInfo( Calamares::GlobalStorage* gs, LOSHInfo& info )
+{
+ if ( !gs )
+ {
+ return;
+ }
+ QVariantList l = gs->value( "partitions" ).toList();
+ if ( l.isEmpty() )
+ {
+ return;
+ }
+
+ for ( const auto& pv : l )
+ {
+ const QVariantMap partition = pv.toMap();
+ if ( !partition.isEmpty() )
+ {
+ QString mountPoint = partition.value( "mountPoint" ).toString();
+ QString fileSystem = partition.value( "fs" ).toString();
+ QString luksMapperName = partition.value( "luksMapperName" ).toString();
+ // if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
+ if ( fileSystem == QStringLiteral( "linuxswap" ) && !luksMapperName.isEmpty() )
+ {
+ info.swap_outer_uuid = partition.value( "luksUuid" ).toString();
+ info.swap_mapper_name = luksMapperName;
+ }
+ else if ( mountPoint == QStringLiteral( "/" ) && !luksMapperName.isEmpty() )
+ {
+
+ info.mountable_keyfile_device = QStringLiteral( "/dev/mapper/" ) + luksMapperName;
+ }
+ }
+ }
+
+ if ( !info.mountable_keyfile_device.isEmpty() && !info.swap_outer_uuid.isEmpty() )
+ {
+ info.swap_device_path = QStringLiteral( "/dev/disk/by-uuid/" ) + info.swap_outer_uuid;
+ }
+
+ QString btrfsRootSubvolume = gs->value( "btrfsRootSubvolume" ).toString();
+ if ( !btrfsRootSubvolume.isEmpty() )
+ {
+ CalamaresUtils::removeLeading( btrfsRootSubvolume, '/' );
+ info.keyfile_device_mount_options
+ = QStringLiteral( "keyfile_device_mount_options=--options=subvol=" ) + btrfsRootSubvolume;
+ }
+}
+
+LOSHInfo
+LOSHInfo::fromGlobalStorage()
+{
+ LOSHInfo i {};
+ globalStoragePartitionInfo(
+ Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr, i );
+ return i;
+}
+
+CALAMARES_PLUGIN_FACTORY_DEFINITION( LOSHJobFactory, registerPlugin< LOSHJob >(); )
diff --git a/src/modules/luksopenswaphookcfg/LOSHJob.h b/src/modules/luksopenswaphookcfg/LOSHJob.h
new file mode 100644
index 000000000..4a435a935
--- /dev/null
+++ b/src/modules/luksopenswaphookcfg/LOSHJob.h
@@ -0,0 +1,37 @@
+/* === This file is part of Calamares - ===
+ *
+ * SPDX-FileCopyrightText: 2021 Adriaan de Groot
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+#ifndef LUKSOPENSWAPHOOKCFG_LOSHJOB_H
+#define LUKSOPENSWAPHOOKCFG_LOSHJOB_H
+
+#include "CppJob.h"
+#include "DllMacro.h"
+#include "utils/PluginFactory.h"
+
+#include
+#include
+
+class PLUGINDLLEXPORT LOSHJob : public Calamares::CppJob
+{
+ Q_OBJECT
+
+public:
+ explicit LOSHJob( QObject* parent = nullptr );
+ ~LOSHJob() override;
+
+ QString prettyName() const override;
+
+ Calamares::JobResult exec() override;
+
+ void setConfigurationMap( const QVariantMap& configurationMap ) override;
+
+private:
+ QString m_configFilePath;
+};
+
+CALAMARES_PLUGIN_FACTORY_DECLARATION( LOSHJobFactory )
+
+#endif
diff --git a/src/modules/luksopenswaphookcfg/Tests.cpp b/src/modules/luksopenswaphookcfg/Tests.cpp
new file mode 100644
index 000000000..840bd9355
--- /dev/null
+++ b/src/modules/luksopenswaphookcfg/Tests.cpp
@@ -0,0 +1,253 @@
+/* === This file is part of Calamares - ===
+ *
+ * SPDX-FileCopyrightText: 2021 Adriaan de Groot
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ */
+
+#include "LOSHInfo.h"
+#include "LOSHJob.h"
+
+#include "GlobalStorage.h"
+#include "JobQueue.h"
+#include "utils/CalamaresUtilsSystem.h"
+#include "utils/Logger.h"
+
+#include
+
+// LOSH = LUKS Open Swap Hook (Job)
+
+// Implementation details
+extern QString get_assignment_part( const QString& line );
+extern void write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info );
+
+class LOSHTests : public QObject
+{
+ Q_OBJECT
+public:
+ LOSHTests();
+ ~LOSHTests() override {}
+
+private Q_SLOTS:
+ void initTestCase();
+
+ void testAssignmentExtraction_data();
+ void testAssignmentExtraction();
+
+ void testLOSHInfo();
+ void testConfigWriting();
+ void testJob();
+};
+
+LOSHTests::LOSHTests() {}
+
+void
+LOSHTests::initTestCase()
+{
+ Logger::setupLogLevel( Logger::LOGDEBUG );
+ cDebug() << "LOSH test started.";
+}
+
+
+void
+LOSHTests::testAssignmentExtraction_data()
+{
+ QTest::addColumn< QString >( "line" );
+ QTest::addColumn< QString >( "match" );
+
+ QTest::newRow( "empty" ) << QString() << QString();
+ QTest::newRow( "comment-only1" ) << QStringLiteral( "# " ) << QString();
+ QTest::newRow( "comment-only2" ) << QStringLiteral( "###" ) << QString();
+ QTest::newRow( "comment-only3" ) << QStringLiteral( "# # #" ) << QString();
+
+ QTest::newRow( "comment-text" ) << QStringLiteral( "# NOTE:" ) << QString();
+ QTest::newRow( "comment-story" ) << QStringLiteral( "# This is a shell comment" ) << QString();
+ // We look for assignments, but only for single-words
+ QTest::newRow( "comment-space-eq" ) << QStringLiteral( "# Check that a = b" ) << QString();
+
+
+ QTest::newRow( "assignment1" ) << QStringLiteral( "a=1" ) << QStringLiteral( "a" );
+ QTest::newRow( "assignment2" ) << QStringLiteral( "a = 1" ) << QStringLiteral( "a" );
+ QTest::newRow( "assignment3" ) << QStringLiteral( "# a=1" ) << QStringLiteral( "a" );
+ QTest::newRow( "assignment4" ) << QStringLiteral( "cows = 12" ) << QStringLiteral( "cows" );
+ QTest::newRow( "assignment5" ) << QStringLiteral( "# # cows=1" ) << QStringLiteral( "cows" );
+ QTest::newRow( "assignment6" ) << QStringLiteral( "# moose='cool' # not cows" ) << QStringLiteral( "moose" );
+ QTest::newRow( "assignment7" ) << QStringLiteral( " moose=cows=42" ) << QStringLiteral( "moose" );
+ QTest::newRow( "assignment8" ) << QStringLiteral( "#swap_device=/dev/something" )
+ << QStringLiteral( "swap_device" );
+ QTest::newRow( "assignment9" ) << QStringLiteral( "# swap_device=/dev/something" )
+ << QStringLiteral( "swap_device" );
+ QTest::newRow( "assignment10" ) << QStringLiteral( "swap_device=/dev/something" )
+ << QStringLiteral( "swap_device" );
+}
+
+void
+LOSHTests::testAssignmentExtraction()
+{
+ QFETCH( QString, line );
+ QFETCH( QString, match );
+
+ QCOMPARE( get_assignment_part( line ), match );
+}
+
+static CalamaresUtils::System*
+file_setup( const QTemporaryDir& tempRoot )
+{
+ CalamaresUtils::System* ss = CalamaresUtils::System::instance();
+ if ( !ss )
+ {
+ ss = new CalamaresUtils::System( true );
+ }
+
+ Calamares::GlobalStorage* gs
+ = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
+ if ( !gs )
+ {
+ cDebug() << "Creating new JobQueue";
+ (void)new Calamares::JobQueue();
+ gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
+ }
+ if ( gs )
+ {
+ // Working with a rootMountPoint set
+ gs->insert( "rootMountPoint", tempRoot.path() );
+ }
+ return ss;
+}
+
+static void
+make_valid_loshinfo( LOSHInfo& i )
+{
+ i.swap_outer_uuid = QStringLiteral( "UUID-0000" );
+ i.swap_mapper_name = QStringLiteral( "/dev/mapper/0000" );
+ i.swap_device_path = QStringLiteral( "/dev/sda0" );
+ i.mountable_keyfile_device = QStringLiteral( "/dev/ada0p0s0" );
+}
+
+void
+LOSHTests::testLOSHInfo()
+{
+ LOSHInfo i {};
+ QVERIFY( !i.isValid() );
+
+ make_valid_loshinfo( i );
+ QVERIFY( i.isValid() );
+ QCOMPARE( i.replacementFor( QStringLiteral( "swap_device" ) ), QStringLiteral( "/dev/sda0" ) );
+ QCOMPARE( i.replacementFor( QStringLiteral( "duck" ) ), QString() );
+}
+
+
+void
+LOSHTests::testConfigWriting()
+{
+ QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
+ QVERIFY( tempRoot.isValid() );
+ auto* ss = file_setup( tempRoot );
+ QVERIFY( ss );
+ QVERIFY( Calamares::JobQueue::instance()->globalStorage() );
+ QVERIFY( QFile::exists( tempRoot.path() ) );
+ QVERIFY( QFileInfo( tempRoot.path() ).isDir() );
+
+ const QString targetFilePath = QStringLiteral( "losh.conf" );
+ const QString filePath = tempRoot.filePath( targetFilePath );
+ QStringList contents { QStringLiteral( "# Calamares demo" ),
+ QStringLiteral( "# swap_device=a thing" ),
+ QStringLiteral( "# duck duck swap_device=another" ) };
+
+ // When the information is invalid, file contents are unchanged,
+ // and no file is written either.
+ LOSHInfo i {};
+ QVERIFY( !i.isValid() );
+ QVERIFY( !QFile::exists( filePath ) );
+ write_openswap_conf( targetFilePath, contents, i ); // Invalid i
+ QVERIFY( !QFile::exists( filePath ) );
+ QCOMPARE( contents.length(), 3 );
+ QCOMPARE( contents.at( 1 ).left( 4 ), QStringLiteral( "# s" ) );
+
+ // Can we write there at all?
+ QFile derp( filePath );
+ QVERIFY( derp.open( QIODevice::WriteOnly ) );
+ QVERIFY( derp.write( "xx", 2 ) );
+ derp.close();
+ QVERIFY( QFile::exists( filePath ) );
+ QVERIFY( QFile::remove( filePath ) );
+
+ // Once the information is valid, though, the file is written
+ make_valid_loshinfo( i );
+ QVERIFY( i.isValid() );
+ QVERIFY( !QFile::exists( filePath ) );
+ write_openswap_conf( targetFilePath, contents, i ); // Now it is valid
+ QVERIFY( QFile::exists( filePath ) );
+ QCOMPARE( contents.length(), 3 );
+ QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/sda0" ) ); // expected key value
+ QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/sda0" ) ); // expected line
+
+ // readLine() returns with newlines-added
+ QFile f( filePath );
+ QVERIFY( f.open( QIODevice::ReadOnly ) );
+ QCOMPARE( f.readLine(), QStringLiteral( "# Calamares demo\n" ) );
+ QCOMPARE( f.readLine(), QStringLiteral( "swap_device=/dev/sda0\n" ) );
+ QCOMPARE( f.readLine(), QStringLiteral( "# duck duck swap_device=another\n" ) );
+ QCOMPARE( f.readLine(), QString() );
+ QVERIFY( f.atEnd() );
+
+ // Note how the contents is updated on every write_openswap_conf()
+ i.swap_device_path = QStringLiteral( "/dev/zram/0.zram" );
+ write_openswap_conf( targetFilePath, contents, i ); // Still valid
+ QCOMPARE( contents.length(), 3 );
+ QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/zram/0.zram" ) ); // expected key value
+ QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/zram/0.zram" ) ); // expected line
+}
+
+
+void
+LOSHTests::testJob()
+{
+ QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
+ QVERIFY( tempRoot.isValid() );
+ auto* ss = file_setup( tempRoot );
+ QVERIFY( ss );
+ Calamares::GlobalStorage* gs
+ = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
+ QVERIFY( gs );
+
+ {
+ QDir d( tempRoot.path() );
+ d.mkdir( "etc" );
+ }
+
+ QVERIFY( !LOSHInfo::fromGlobalStorage().isValid() );
+ QVariantList outerPartition;
+ QVariantMap innerPartition;
+ innerPartition.insert( "mountPoint", "/" );
+ innerPartition.insert( "fs", "ext4" );
+ innerPartition.insert( "luksMapperName", "root" );
+ innerPartition.insert( "luksUUID", "0000" );
+ outerPartition.append( innerPartition );
+ innerPartition.remove( "mountPoint" );
+ innerPartition.insert( "fs", "linuxswap" );
+ innerPartition.insert( "luksMapperName", "swap" );
+ innerPartition.insert( "luksUuid", "0001" );
+ outerPartition.append( innerPartition );
+ gs->insert( "partitions", outerPartition );
+ QVERIFY( LOSHInfo::fromGlobalStorage().isValid() );
+
+ LOSHJob j;
+ j.setConfigurationMap( QVariantMap() );
+ auto jobresult = j.exec();
+ QVERIFY( jobresult );
+
+ {
+ QFile f( tempRoot.filePath( "etc/openswap.conf" ) );
+ QVERIFY( f.exists() );
+ QVERIFY( f.open( QIODevice::ReadOnly ) );
+ cDebug() << f.readAll();
+ }
+}
+
+
+QTEST_GUILESS_MAIN( LOSHTests )
+
+#include "utils/moc-warnings.h"
+
+#include "Tests.moc"
diff --git a/src/modules/luksopenswaphookcfg/main.py b/src/modules/luksopenswaphookcfg/main.py
deleted file mode 100644
index aaac8a31a..000000000
--- a/src/modules/luksopenswaphookcfg/main.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
-#
-# === This file is part of Calamares - ===
-#
-# SPDX-FileCopyrightText: 2016 Teo Mrnjavac
-# SPDX-FileCopyrightText: 2017 Alf Gaida
-# SPDX-FileCopyrightText: 2019 Adriaan de Groot
-# SPDX-License-Identifier: GPL-3.0-or-later
-#
-# Calamares is Free Software: see the License-Identifier above.
-#
-
-import libcalamares
-import os.path
-
-
-import gettext
-_ = gettext.translation("calamares-python",
- localedir=libcalamares.utils.gettext_path(),
- languages=libcalamares.utils.gettext_languages(),
- fallback=True).gettext
-
-
-def pretty_name():
- return _("Configuring encrypted swap.")
-
-
-def write_openswap_conf(partitions, root_mount_point, openswap_conf_path):
- swap_outer_uuid = ""
- swap_mapper_name = ""
- mountable_keyfile_device = ""
-
- for partition in partitions:
- if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
- swap_outer_uuid = partition["luksUuid"]
- swap_mapper_name = partition["luksMapperName"]
-
- elif partition["mountPoint"] == "/" and "luksMapperName" in partition:
- mountable_keyfile_device = (
- "/dev/mapper/{!s}".format(partition["luksMapperName"])
- )
-
- if not mountable_keyfile_device or not swap_outer_uuid:
- return None
-
- swap_device_path = "/dev/disk/by-uuid/{!s}".format(swap_outer_uuid)
-
- lines = []
- with open(os.path.join(root_mount_point,
- openswap_conf_path), 'r') as openswap_file:
- lines = [x.strip() for x in openswap_file.readlines()]
-
- for i in range(len(lines)):
- if lines[i].startswith("swap_device"):
- lines[i] = "swap_device={!s}".format(swap_device_path)
-
- elif lines[i].startswith("crypt_swap_name"):
- lines[i] = "crypt_swap_name={!s}".format(swap_mapper_name)
-
- elif lines[i].startswith("keyfile_device"):
- lines[i] = "keyfile_device={!s}".format(mountable_keyfile_device)
-
- elif lines[i].startswith("keyfile_filename"):
- lines[i] = "keyfile_filename=crypto_keyfile.bin"
-
- elif lines[i].startswith("#keyfile_device_mount_options"):
- if libcalamares.globalstorage.contains("btrfsRootSubvolume"):
- btrfs_root_subvolume = libcalamares.globalstorage.value("btrfsRootSubvolume")
- lines[i] = "keyfile_device_mount_options=--options=subvol=" + btrfs_root_subvolume.lstrip("/")
-
- with open(os.path.join(root_mount_point,
- openswap_conf_path), 'w') as openswap_file:
- openswap_file.write("\n".join(lines) + "\n")
-
- return None
-
-
-def run():
- """
- This module sets up the openswap hook for a resumable encrypted swap.
- :return:
- """
-
- root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
- openswap_conf_path = libcalamares.job.configuration["configFilePath"]
- partitions = libcalamares.globalstorage.value("partitions")
-
- if not partitions:
- libcalamares.utils.warning("partitions is empty, {!s}".format(partitions))
- return (_("Configuration Error"),
- _("No partitions are defined for
{!s}
to use.").format("luksopenswaphookcfg"))
- if not root_mount_point:
- libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
- return (_("Configuration Error"),
- _("No root mount point is given for
{!s}
to use.").format("luksopenswaphookcfg"))
-
- openswap_conf_path = openswap_conf_path.lstrip('/')
-
- return write_openswap_conf(partitions, root_mount_point, openswap_conf_path)
diff --git a/src/modules/luksopenswaphookcfg/module.desc b/src/modules/luksopenswaphookcfg/module.desc
deleted file mode 100644
index 919a92792..000000000
--- a/src/modules/luksopenswaphookcfg/module.desc
+++ /dev/null
@@ -1,7 +0,0 @@
-# SPDX-FileCopyrightText: no
-# SPDX-License-Identifier: CC0-1.0
----
-type: "job"
-name: "luksopenswaphookcfg"
-interface: "python"
-script: "main.py"
diff --git a/src/modules/partition/core/DeviceList.cpp b/src/modules/partition/core/DeviceList.cpp
index c7de12e88..adbbddd68 100644
--- a/src/modules/partition/core/DeviceList.cpp
+++ b/src/modules/partition/core/DeviceList.cpp
@@ -11,6 +11,7 @@
#include "DeviceList.h"
#include "partition/PartitionIterator.h"
+#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
#include
@@ -40,16 +41,30 @@ hasRootPartition( Device* device )
return false;
}
+/** @brief Check if @p path holds an iso9660 filesystem
+ *
+ * The @p path should point to a device; blkid is used to check the FS type.
+ */
static bool
blkIdCheckIso9660( const QString& path )
{
- QProcess blkid;
- blkid.start( "blkid", { path } );
- blkid.waitForFinished();
- QString output = QString::fromLocal8Bit( blkid.readAllStandardOutput() );
- return output.contains( "iso9660" );
+ // If blkid fails, there's no output, but we don't care
+ auto r = CalamaresUtils::System::runCommand( { "blkid", path }, std::chrono::seconds( 30 ) );
+ return r.getOutput().contains( "iso9660" );
}
+/// @brief Convenience to check if @p partition holds an iso9660 filesystem
+static bool
+blkIdCheckIso9660P( const Partition* partition )
+{
+ return blkIdCheckIso9660( partition->partitionPath() );
+}
+
+/** @brief Check if the @p device is an iso9660 device
+ *
+ * An iso9660 device is **probably** a CD-ROM. If the device holds an
+ * iso9660 FS, or any of its partitions do, then we call it an iso9660 device.
+ */
static bool
isIso9660( const Device* device )
{
@@ -65,13 +80,8 @@ isIso9660( const Device* device )
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
{
- for ( const Partition* partition : device->partitionTable()->children() )
- {
- if ( blkIdCheckIso9660( partition->partitionPath() ) )
- {
- return true;
- }
- }
+ const auto& p = device->partitionTable()->children();
+ return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P );
}
return false;
}
diff --git a/src/modules/partition/core/KPMHelpers.cpp b/src/modules/partition/core/KPMHelpers.cpp
index ed105e28b..d5086ef21 100644
--- a/src/modules/partition/core/KPMHelpers.cpp
+++ b/src/modules/partition/core/KPMHelpers.cpp
@@ -15,8 +15,8 @@
#include "partition/PartitionIterator.h"
#include "utils/Logger.h"
+#include "utils/String.h"
-// KPMcore
#include
#include
#include
@@ -127,4 +127,23 @@ clonePartition( Device* device, Partition* partition )
partition->activeFlags() );
}
+Calamares::JobResult
+execute( Operation& operation, const QString& failureMessage )
+{
+ operation.setStatus( Operation::StatusRunning );
+
+ Report report( nullptr );
+ if ( operation.execute( report ) )
+ {
+ return Calamares::JobResult::ok();
+ }
+
+ // Remove the === lines from the report by trimming them to empty
+ QStringList l = report.toText().split( '\n' );
+ std::for_each( l.begin(), l.end(), []( QString& s ) { CalamaresUtils::removeLeading( s, '=' ); } );
+
+ return Calamares::JobResult::error( failureMessage, l.join( '\n' ) );
+}
+
+
} // namespace KPMHelpers
diff --git a/src/modules/partition/core/KPMHelpers.h b/src/modules/partition/core/KPMHelpers.h
index 89a019f6c..2f867bc25 100644
--- a/src/modules/partition/core/KPMHelpers.h
+++ b/src/modules/partition/core/KPMHelpers.h
@@ -11,11 +11,13 @@
#ifndef KPMHELPERS_H
#define KPMHELPERS_H
-// KPMcore
+#include "Job.h"
+
#include
#include
+#include
+#include
-// Qt
#include
#include
@@ -72,6 +74,24 @@ Partition* createNewEncryptedPartition( PartitionNode* parent,
Partition* clonePartition( Device* device, Partition* partition );
+/** @brief Return a result for an @p operation
+ *
+ * Executes the operation, and if successful, returns a success result.
+ * Otherwise returns an error using @p failureMessage as the primary part
+ * of the error, and details obtained from the operation.
+ */
+Calamares::JobResult execute( Operation& operation, const QString& failureMessage );
+/** @brief Return a result for an @p operation
+ *
+ * It's acceptable to use an rvalue: the operation-running is the effect
+ * you're interested in, rather than keeping the temporary around.
+ */
+static inline Calamares::JobResult
+execute( Operation&& operation, const QString& failureMessage )
+{
+ return execute( operation, failureMessage );
+}
+
} // namespace KPMHelpers
#endif /* KPMHELPERS_H */
diff --git a/src/modules/partition/jobs/CreatePartitionJob.cpp b/src/modules/partition/jobs/CreatePartitionJob.cpp
index 3e51ed598..fe7c6f350 100644
--- a/src/modules/partition/jobs/CreatePartitionJob.cpp
+++ b/src/modules/partition/jobs/CreatePartitionJob.cpp
@@ -11,7 +11,9 @@
#include "CreatePartitionJob.h"
+#include "core/KPMHelpers.h"
#include "core/PartitionInfo.h"
+
#include "partition/FileSystem.h"
#include "partition/PartitionQuery.h"
#include "utils/CalamaresUtilsSystem.h"
@@ -273,17 +275,9 @@ CreatePartitionJob::exec()
return createZfs( m_partition, m_device );
}
- Report report( nullptr );
- NewOperation op( *m_device, m_partition );
- op.setStatus( Operation::StatusRunning );
-
- QString message = tr( "The installer failed to create partition on disk '%1'." ).arg( m_device->name() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute(
+ NewOperation( *m_device, m_partition ),
+ tr( "The installer failed to create partition on disk '%1'." ).arg( m_device->name() ) );
}
void
diff --git a/src/modules/partition/jobs/CreatePartitionTableJob.cpp b/src/modules/partition/jobs/CreatePartitionTableJob.cpp
index 118ec8823..3b9415d1a 100644
--- a/src/modules/partition/jobs/CreatePartitionTableJob.cpp
+++ b/src/modules/partition/jobs/CreatePartitionTableJob.cpp
@@ -12,9 +12,11 @@
#include "CreatePartitionTableJob.h"
#include "partition/PartitionIterator.h"
+#include "utils/CalamaresUtilsSystem.h"
#include "utils/Logger.h"
-// KPMcore
+#include "core/KPMHelpers.h"
+
#include
#include
#include
@@ -63,8 +65,6 @@ CreatePartitionTableJob::prettyStatusMessage() const
Calamares::JobResult
CreatePartitionTableJob::exec()
{
- Report report( nullptr );
- QString message = tr( "The installer failed to create a partition table on %1." ).arg( m_device->name() );
PartitionTable* table = m_device->partitionTable();
@@ -76,30 +76,16 @@ CreatePartitionTableJob::exec()
cDebug() << Logger::SubEntry << ( ( *it ) ? ( *it )->deviceNode() : QString( "" ) );
}
- QProcess lsblk;
- lsblk.setProgram( "lsblk" );
- lsblk.setProcessChannelMode( QProcess::MergedChannels );
- lsblk.start();
- lsblk.waitForFinished();
- cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblk.readAllStandardOutput();
+ auto lsblkResult = CalamaresUtils::System::runCommand( { "lsblk" }, std::chrono::seconds( 30 ) );
+ cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblkResult.getOutput();
- QProcess mount;
- mount.setProgram( "mount" ); // Debug output only, not mounting something
- mount.setProcessChannelMode( QProcess::MergedChannels );
- mount.start();
- mount.waitForFinished();
- cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mount.readAllStandardOutput();
+ auto mountResult = CalamaresUtils::System::runCommand( { "mount" }, std::chrono::seconds( 30 ) );
+ cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mountResult.getOutput();
}
- CreatePartitionTableOperation op( *m_device, table );
- op.setStatus( Operation::StatusRunning );
-
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute(
+ CreatePartitionTableOperation( *m_device, table ),
+ tr( "The installer failed to create a partition table on %1." ).arg( m_device->name() ) );
}
void
diff --git a/src/modules/partition/jobs/CreateVolumeGroupJob.cpp b/src/modules/partition/jobs/CreateVolumeGroupJob.cpp
index 36d79b7b7..683913b7f 100644
--- a/src/modules/partition/jobs/CreateVolumeGroupJob.cpp
+++ b/src/modules/partition/jobs/CreateVolumeGroupJob.cpp
@@ -9,7 +9,8 @@
#include "CreateVolumeGroupJob.h"
-// KPMcore
+#include "core/KPMHelpers.h"
+
#include
#include
#include
@@ -46,19 +47,8 @@ CreateVolumeGroupJob::prettyStatusMessage() const
Calamares::JobResult
CreateVolumeGroupJob::exec()
{
- Report report( nullptr );
-
- CreateVolumeGroupOperation op( m_vgName, m_pvList, m_peSize );
-
- op.setStatus( Operation::StatusRunning );
-
- QString message = tr( "The installer failed to create a volume group named '%1'." ).arg( m_vgName );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute( CreateVolumeGroupOperation( m_vgName, m_pvList, m_peSize ),
+ tr( "The installer failed to create a volume group named '%1'." ).arg( m_vgName ) );
}
void
diff --git a/src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp b/src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp
index 92086015d..65920a84e 100644
--- a/src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp
+++ b/src/modules/partition/jobs/DeactivateVolumeGroupJob.cpp
@@ -9,6 +9,8 @@
#include "DeactivateVolumeGroupJob.h"
+#include "core/KPMHelpers.h"
+
#include
#include
#include
@@ -39,18 +41,12 @@ DeactivateVolumeGroupJob::prettyStatusMessage() const
Calamares::JobResult
DeactivateVolumeGroupJob::exec()
{
- Report report( nullptr );
-
DeactivateVolumeGroupOperation op( *m_device );
-
- op.setStatus( Operation::OperationStatus::StatusRunning );
-
- QString message = tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() );
- if ( op.execute( report ) )
+ auto r = KPMHelpers::execute(
+ op, tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() ) );
+ if ( r )
{
op.preview();
- return Calamares::JobResult::ok();
}
-
- return Calamares::JobResult::error( message, report.toText() );
+ return r;
}
diff --git a/src/modules/partition/jobs/DeletePartitionJob.cpp b/src/modules/partition/jobs/DeletePartitionJob.cpp
index a678b5e90..d61bb955e 100644
--- a/src/modules/partition/jobs/DeletePartitionJob.cpp
+++ b/src/modules/partition/jobs/DeletePartitionJob.cpp
@@ -10,9 +10,11 @@
*/
#include "DeletePartitionJob.h"
+
+#include "core/KPMHelpers.h"
+
#include "utils/CalamaresUtilsSystem.h"
-// KPMcore
#include
#include
#include
@@ -45,7 +47,7 @@ removePartition( Partition* partition )
auto r = CalamaresUtils::System::instance()->runCommand(
{ "sfdisk", "--delete", "--force", partition->devicePath(), QString::number( partition->number() ) },
std::chrono::seconds( 5 ) );
- if ( r.getExitCode() !=0 || r.getOutput().contains("failed") )
+ if ( r.getExitCode() != 0 || r.getOutput().contains( "failed" ) )
{
return Calamares::JobResult::error(
QCoreApplication::translate( DeletePartitionJob::staticMetaObject.className(), "Deletion Failed" ),
@@ -96,17 +98,8 @@ DeletePartitionJob::exec()
return removePartition( m_partition );
}
- Report report( nullptr );
- DeleteOperation op( *m_device, m_partition );
- op.setStatus( Operation::StatusRunning );
-
- QString message = tr( "The installer failed to delete partition %1." ).arg( m_partition->devicePath() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute( DeleteOperation( *m_device, m_partition ),
+ tr( "The installer failed to delete partition %1." ).arg( m_partition->devicePath() ) );
}
void
diff --git a/src/modules/partition/jobs/FormatPartitionJob.cpp b/src/modules/partition/jobs/FormatPartitionJob.cpp
index 4dadacf9c..1ccc6e617 100644
--- a/src/modules/partition/jobs/FormatPartitionJob.cpp
+++ b/src/modules/partition/jobs/FormatPartitionJob.cpp
@@ -11,6 +11,8 @@
#include "FormatPartitionJob.h"
+#include "core/KPMHelpers.h"
+
#include "partition/FileSystem.h"
#include "utils/Logger.h"
@@ -65,17 +67,7 @@ FormatPartitionJob::prettyStatusMessage() const
Calamares::JobResult
FormatPartitionJob::exec()
{
- Report report( nullptr ); // Root of the report tree, no parent
- CreateFileSystemOperation op( *m_device, *m_partition, m_partition->fileSystem().type() );
- op.setStatus( Operation::StatusRunning );
-
- QString message = tr( "The installer failed to format partition %1 on disk '%2'." )
- .arg( m_partition->partitionPath(), m_device->name() );
-
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, m_partition->fileSystem().type() ),
+ tr( "The installer failed to format partition %1 on disk '%2'." )
+ .arg( m_partition->partitionPath(), m_device->name() ) );
}
diff --git a/src/modules/partition/jobs/RemoveVolumeGroupJob.cpp b/src/modules/partition/jobs/RemoveVolumeGroupJob.cpp
index 3c4e7b036..227351064 100644
--- a/src/modules/partition/jobs/RemoveVolumeGroupJob.cpp
+++ b/src/modules/partition/jobs/RemoveVolumeGroupJob.cpp
@@ -9,6 +9,8 @@
#include "RemoveVolumeGroupJob.h"
+#include "core/KPMHelpers.h"
+
#include
#include
#include
@@ -39,17 +41,7 @@ RemoveVolumeGroupJob::prettyStatusMessage() const
Calamares::JobResult
RemoveVolumeGroupJob::exec()
{
- Report report( nullptr );
-
- RemoveVolumeGroupOperation op( *m_device );
-
- op.setStatus( Operation::OperationStatus::StatusRunning );
-
- QString message = tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute(
+ RemoveVolumeGroupOperation( *m_device ),
+ tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() ) );
}
diff --git a/src/modules/partition/jobs/ResizePartitionJob.cpp b/src/modules/partition/jobs/ResizePartitionJob.cpp
index 87b87c1c0..fe1ceca4c 100644
--- a/src/modules/partition/jobs/ResizePartitionJob.cpp
+++ b/src/modules/partition/jobs/ResizePartitionJob.cpp
@@ -11,9 +11,10 @@
#include "ResizePartitionJob.h"
+#include "core/KPMHelpers.h"
+
#include "utils/Units.h"
-// KPMcore
#include
#include
#include
@@ -66,23 +67,16 @@ ResizePartitionJob::prettyStatusMessage() const
Calamares::JobResult
ResizePartitionJob::exec()
{
- Report report( nullptr );
// Restore partition sectors that were modified for preview
m_partition->setFirstSector( m_oldFirstSector );
m_partition->setLastSector( m_oldLastSector );
+
ResizeOperation op( *m_device, *m_partition, m_newFirstSector, m_newLastSector );
- op.setStatus( Operation::StatusRunning );
connect( &op, &Operation::progress, this, &ResizePartitionJob::iprogress );
-
- QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
- .arg( m_partition->partitionPath() )
- .arg( m_device->name() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( errorMessage, report.toText() );
+ return KPMHelpers::execute( op,
+ tr( "The installer failed to resize partition %1 on disk '%2'." )
+ .arg( m_partition->partitionPath() )
+ .arg( m_device->name() ) );
}
void
diff --git a/src/modules/partition/jobs/ResizeVolumeGroupJob.cpp b/src/modules/partition/jobs/ResizeVolumeGroupJob.cpp
index 1aa4541b8..f7a21d80d 100644
--- a/src/modules/partition/jobs/ResizeVolumeGroupJob.cpp
+++ b/src/modules/partition/jobs/ResizeVolumeGroupJob.cpp
@@ -9,7 +9,8 @@
#include "ResizeVolumeGroupJob.h"
-// KPMcore
+#include "core/KPMHelpers.h"
+
#include
#include
#include
@@ -51,19 +52,9 @@ ResizeVolumeGroupJob::prettyStatusMessage() const
Calamares::JobResult
ResizeVolumeGroupJob::exec()
{
- Report report( nullptr );
-
- ResizeVolumeGroupOperation op( *m_device, m_partitionList );
-
- op.setStatus( Operation::OperationStatus::StatusRunning );
-
- QString message = tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( message, report.toText() );
+ return KPMHelpers::execute(
+ ResizeVolumeGroupOperation( *m_device, m_partitionList ),
+ tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() ) );
}
QString
diff --git a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
index de77d86f8..507773288 100644
--- a/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
+++ b/src/modules/partition/jobs/SetPartitionFlagsJob.cpp
@@ -13,6 +13,8 @@
#include "SetPartitionFlagsJob.h"
+#include "core/KPMHelpers.h"
+
#include "partition/FileSystem.h"
#include "utils/Logger.h"
#include "utils/Units.h"
@@ -148,17 +150,8 @@ SetPartFlagsJob::exec()
cDebug() << "Setting flags on" << m_device->deviceNode() << "partition" << partition()->deviceNode()
<< Logger::DebugList( flagsList );
- Report report( nullptr );
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
- op.setStatus( Operation::StatusRunning );
connect( &op, &Operation::progress, this, &SetPartFlagsJob::iprogress );
-
- QString errorMessage
- = tr( "The installer failed to set flags on partition %1." ).arg( m_partition->partitionPath() );
- if ( op.execute( report ) )
- {
- return Calamares::JobResult::ok();
- }
-
- return Calamares::JobResult::error( errorMessage, report.toText() );
+ return KPMHelpers::execute(
+ op, tr( "The installer failed to set flags on partition %1." ).arg( m_partition->partitionPath() ) );
}