diff --git a/src/libcalamares/CMakeLists.txt b/src/libcalamares/CMakeLists.txt index a084c120d..69533cfff 100644 --- a/src/libcalamares/CMakeLists.txt +++ b/src/libcalamares/CMakeLists.txt @@ -63,6 +63,7 @@ set( libSources packages/Globals.cpp # Partition service + partition/Global.cpp partition/Mount.cpp partition/PartitionSize.cpp partition/Sync.cpp @@ -241,7 +242,10 @@ calamares_add_test( calamares_add_test( libcalamarespartitiontest SOURCES + partition/Global.cpp partition/Tests.cpp + LIBRARIES + ${OPTIONAL_PRIVATE_LIBRARIES} ) if( KPMcore_FOUND ) diff --git a/src/libcalamares/partition/Global.cpp b/src/libcalamares/partition/Global.cpp new file mode 100644 index 000000000..fb7b09aaf --- /dev/null +++ b/src/libcalamares/partition/Global.cpp @@ -0,0 +1,56 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + * + */ +#include "Global.h" + +#include "FileSystem.h" +#include "GlobalStorage.h" +#include "JobQueue.h" + +#include + +static const QString fsUse_key = QStringLiteral( "filesystem_use" ); + +bool +CalamaresUtils::Partition::isFilesystemUsedGS( const Calamares::GlobalStorage* gs, const QString& filesystemType ) +{ + if ( !gs ) + { + return false; + } + const QVariantMap fsUse = gs->value( fsUse_key ).toMap(); + QString key = filesystemType.toLower(); + if ( fsUse.contains( key ) ) + { + const auto v = fsUse.value( key ); + return v.toBool(); + } + return false; +} + +void +CalamaresUtils::Partition::useFilesystemGS( Calamares::GlobalStorage* gs, const QString& filesystemType, bool used ) +{ + if ( gs ) + { + QVariantMap existingMap = gs->contains( fsUse_key ) ? gs->value( fsUse_key ).toMap() : QVariantMap(); + QString key = filesystemType.toLower(); + existingMap.insert( key, used ); + gs->insert( fsUse_key, existingMap ); + } +} + +void +CalamaresUtils::Partition::clearFilesystemGS( Calamares::GlobalStorage* gs ) +{ + if ( gs ) + { + gs->remove( fsUse_key ); + } +} diff --git a/src/libcalamares/partition/Global.h b/src/libcalamares/partition/Global.h new file mode 100644 index 000000000..733e2f69c --- /dev/null +++ b/src/libcalamares/partition/Global.h @@ -0,0 +1,107 @@ +/* === This file is part of Calamares - === + * + * SPDX-FileCopyrightText: 2021 Adriaan de Groot + * SPDX-License-Identifier: GPL-3.0-or-later + * + * Calamares is Free Software: see the License-Identifier above. + * + * + */ + +/* + * This is the API for manipulating Global Storage keys related to + * filesystems and partitions. + */ + +#ifndef PARTITION_GLOBAL_H +#define PARTITION_GLOBAL_H + +#include "DllMacro.h" +#include "JobQueue.h" + +#ifdef WITH_KPMCORE4API +#include "FileSystem.h" + +#include +#endif + +namespace CalamaresUtils +{ +namespace Partition +{ +/** @brief Mark a particular filesystem type as used (or not) + * + * Filesystems are marked used (or not) in the global storage + * key *filesystem_use*. Sub-keys are the filesystem name, + * and the values are boolean; filesystems that are used in + * the target system are marked with @c true. Unused filesystems + * may be unmarked, or may be marked @c false. + * + * The filesystem name should be the untranslated name. Filesystem + * names are **lower**cased when used as keys. + */ +void DLLEXPORT useFilesystemGS( Calamares::GlobalStorage* gs, const QString& filesystemType, bool used ); +/** @brief Reads from global storage whether the filesystem type is used + * + * Reads from the global storage key *filesystem_use* and returns + * the boolean value stored in subkey @p filesystemType. Returns + * @c false if the subkey is not set at all. + * + * The filesystem name should be the untranslated name. Filesystem + * names are **lower**cased when used as keys. + */ +bool DLLEXPORT isFilesystemUsedGS( const Calamares::GlobalStorage* gs, const QString& filesystemType ); + +/** @brief Clears the usage data for filesystems + * + * This removes the internal key *filesystem_use*. + */ +void DLLEXPORT clearFilesystemGS( Calamares::GlobalStorage* gs ); + +/** @brief Convenience function for using "the" Global Storage + * + * @see useFilesystemGS(const QString&, bool) + */ +inline void +useFilesystemGS( const QString& filesystemType, bool used ) +{ + useFilesystemGS( Calamares::JobQueue::instanceGlobalStorage(), filesystemType, used ); +} + +/** @brief Convenience function for using "the" Global Storage + * + * @see isFilesystemUsedGS(const QString&); + */ +inline bool +isFilesystemUsedGS( const QString& filesystemType ) +{ + return isFilesystemUsedGS( Calamares::JobQueue::instanceGlobalStorage(), filesystemType ); +} + +#ifdef WITH_KPMCORE4API +/** @brief Mark a particular filesystem type as used (or not) + * + * See useFilesystemGS(const QString&, bool); this method uses the filesystem type + * enumeration to pick the name. + */ +inline void +useFilesystemGS( FileSystem::Type filesystem, bool used ) +{ + useFilesystemGS( untranslatedFS( filesystem ), used ); +} + +/* @brief Reads from global storage whether the typesystem type is used + * + * See isFilesystemUsedGS(const QString&). + */ +inline bool +isFilesystemUsedGS( FileSystem::Type filesystem ) +{ + return isFilesystemUsedGS( untranslatedFS( filesystem ) ); +} + +#endif +} // namespace Partition +} // namespace CalamaresUtils + +#endif diff --git a/src/libcalamares/partition/Tests.cpp b/src/libcalamares/partition/Tests.cpp index cd2922ee2..16f7d78c2 100644 --- a/src/libcalamares/partition/Tests.cpp +++ b/src/libcalamares/partition/Tests.cpp @@ -8,32 +8,50 @@ * */ -#include "Tests.h" - +#include "Global.h" #include "PartitionSize.h" +#include "GlobalStorage.h" +#include "utils/Logger.h" + +#include +#include + using SizeUnit = CalamaresUtils::Partition::SizeUnit; using PartitionSize = CalamaresUtils::Partition::PartitionSize; Q_DECLARE_METATYPE( SizeUnit ) -#include "utils/Logger.h" +class PartitionServiceTests : public QObject +{ + Q_OBJECT +public: + PartitionServiceTests(); + ~PartitionServiceTests() override; -#include +private Q_SLOTS: + void initTestCase(); -QTEST_GUILESS_MAIN( PartitionSizeTests ) + void testUnitComparison_data(); + void testUnitComparison(); -PartitionSizeTests::PartitionSizeTests() {} + void testUnitNormalisation_data(); + void testUnitNormalisation(); -PartitionSizeTests::~PartitionSizeTests() {} + void testFilesystemGS(); +}; + +PartitionServiceTests::PartitionServiceTests() {} + +PartitionServiceTests::~PartitionServiceTests() {} void -PartitionSizeTests::initTestCase() +PartitionServiceTests::initTestCase() { } void -PartitionSizeTests::testUnitComparison_data() +PartitionServiceTests::testUnitComparison_data() { QTest::addColumn< SizeUnit >( "u1" ); QTest::addColumn< SizeUnit >( "u2" ); @@ -71,7 +89,7 @@ original_compare( SizeUnit m_unit, SizeUnit other_m_unit ) } void -PartitionSizeTests::testUnitComparison() +PartitionServiceTests::testUnitComparison() { QFETCH( SizeUnit, u1 ); QFETCH( SizeUnit, u2 ); @@ -98,7 +116,7 @@ constexpr qint64 operator""_qi( unsigned long long m ) } void -PartitionSizeTests::testUnitNormalisation_data() +PartitionServiceTests::testUnitNormalisation_data() { QTest::addColumn< SizeUnit >( "u1" ); QTest::addColumn< int >( "v" ); @@ -131,7 +149,7 @@ PartitionSizeTests::testUnitNormalisation_data() } void -PartitionSizeTests::testUnitNormalisation() +PartitionServiceTests::testUnitNormalisation() { QFETCH( SizeUnit, u1 ); QFETCH( int, v ); @@ -139,3 +157,70 @@ PartitionSizeTests::testUnitNormalisation() QCOMPARE( PartitionSize( v, u1 ).toBytes(), bytes ); } + +void +PartitionServiceTests::testFilesystemGS() +{ + using CalamaresUtils::Partition::isFilesystemUsedGS; + using CalamaresUtils::Partition::useFilesystemGS; + + // Some filesystems names, they don't have to be real + const QStringList fsNames { "ext4", "zfs", "berries", "carrot" }; + // Predicate to return whether we consider this FS in use + auto pred = []( const QString& s ) { return !s.startsWith( 'z' ); }; + + // Fill the GS + Calamares::GlobalStorage gs; + for ( const auto& s : fsNames ) + { + useFilesystemGS( &gs, s, pred( s ) ); + } + + QVERIFY( gs.contains( "filesystem_use" ) ); + { + const auto map = gs.value( "filesystem_use" ).toMap(); + QCOMPARE( map.count(), fsNames.count() ); + } + + for ( const auto& s : fsNames ) + { + QCOMPARE( isFilesystemUsedGS( &gs, s ), pred( s ) ); + } + QCOMPARE( isFilesystemUsedGS( &gs, QStringLiteral( "derp" ) ), false ); + QCOMPARE( isFilesystemUsedGS( &gs, QString() ), false ); + // But I can set a value for QString! + useFilesystemGS( &gs, QString(), true ); + QCOMPARE( isFilesystemUsedGS( &gs, QString() ), true ); + // .. and replace it again + useFilesystemGS( &gs, QString(), false ); + QCOMPARE( isFilesystemUsedGS( &gs, QString() ), false ); + // Now there is one more key + { + const auto map = gs.value( "filesystem_use" ).toMap(); + QCOMPARE( map.count(), fsNames.count() + 1 ); + } + + // The API says that it it case-insensitive + QVERIFY( !isFilesystemUsedGS( &gs, "ZFS" ) ); + QVERIFY( isFilesystemUsedGS( &gs, "EXT4" ) ); + QCOMPARE( isFilesystemUsedGS( &gs, "ZFS" ), isFilesystemUsedGS( &gs, "zfs" ) ); + QCOMPARE( isFilesystemUsedGS( &gs, "EXT4" ), isFilesystemUsedGS( &gs, "ext4" ) ); + + useFilesystemGS( &gs, "EXT4", false ); + QVERIFY( !isFilesystemUsedGS( &gs, "EXT4" ) ); + QCOMPARE( isFilesystemUsedGS( &gs, "EXT4" ), isFilesystemUsedGS( &gs, "ext4" ) ); + useFilesystemGS( &gs, "ext4", true ); + QVERIFY( isFilesystemUsedGS( &gs, "EXT4" ) ); + + CalamaresUtils::Partition::clearFilesystemGS( &gs ); + QVERIFY( !isFilesystemUsedGS( &gs, "ZFS" ) ); + QVERIFY( !isFilesystemUsedGS( &gs, "EXT4" ) ); + QVERIFY( !isFilesystemUsedGS( &gs, "ext4" ) ); +} + + +QTEST_GUILESS_MAIN( PartitionServiceTests ) + +#include "utils/moc-warnings.h" + +#include "Tests.moc" diff --git a/src/libcalamares/partition/Tests.h b/src/libcalamares/partition/Tests.h deleted file mode 100644 index 0d6f77a76..000000000 --- a/src/libcalamares/partition/Tests.h +++ /dev/null @@ -1,33 +0,0 @@ -/* === This file is part of Calamares - === - * - * SPDX-FileCopyrightText: 2019 Adriaan de Groot - * SPDX-License-Identifier: GPL-3.0-or-later - * - * Calamares is Free Software: see the License-Identifier above. - * - * - */ - -#ifndef LIBCALAMARES_PARTITION_TESTS_H -#define LIBCALAMARES_PARTITION_TESTS_H - -#include - -class PartitionSizeTests : public QObject -{ - Q_OBJECT -public: - PartitionSizeTests(); - ~PartitionSizeTests() override; - -private Q_SLOTS: - void initTestCase(); - - void testUnitComparison_data(); - void testUnitComparison(); - - void testUnitNormalisation_data(); - void testUnitNormalisation(); -}; - -#endif diff --git a/src/modules/partition/jobs/FillGlobalStorageJob.cpp b/src/modules/partition/jobs/FillGlobalStorageJob.cpp index 1660dbb54..f79918e64 100644 --- a/src/modules/partition/jobs/FillGlobalStorageJob.cpp +++ b/src/modules/partition/jobs/FillGlobalStorageJob.cpp @@ -18,6 +18,7 @@ #include "GlobalStorage.h" #include "JobQueue.h" #include "partition/FileSystem.h" +#include "partition/Global.h" #include "partition/PartitionIterator.h" #include "utils/Logger.h" @@ -291,35 +292,29 @@ FillGlobalStorageJob::prettyStatusMessage() const * .. mark as "1" if it's on the system, somewhere * .. mark as "2" if it's one of the claimed / in-use FSses * - * Stores a GS key called "filesystems_use" with this mapping. + * Stores a GS key called "filesystem_use" with this mapping. + * @see CalamaresUtils::Partition::useFilesystemGS() */ static void storeFSUse( Calamares::GlobalStorage* storage, const QVariantList& partitions ) { - QMap< QString, int > fsUses; - for ( const auto& p : partitions ) + if ( storage ) { - const auto pmap = p.toMap(); - - QString fs = pmap.value( "fs" ).toString(); - int thisUse = pmap.value( "claimed" ).toBool() ? 2 : 1; - - if ( fs.isEmpty() ) + CalamaresUtils::Partition::clearFilesystemGS( storage ); + for ( const auto& p : partitions ) { - continue; + const auto pmap = p.toMap(); + + QString fs = pmap.value( "fs" ).toString(); + + if ( fs.isEmpty() ) + { + continue; + } + + CalamaresUtils::Partition::useFilesystemGS( storage, fs, true ); } - - int newUse = qMax( fsUses.value( fs ), thisUse ); // value() is 0 if not present - fsUses.insert( fs, newUse ); } - - QVariantMap fsUsesVariant; - for ( auto it = fsUses.cbegin(); it != fsUses.cend(); ++it ) - { - fsUsesVariant.insert( it.key(), it.value() ); - } - - storage->insert( "filesystems_use", fsUsesVariant ); } Calamares::JobResult