Merge remote-tracking branch 'origin/issue-1701' into calamares

FIXES #1701

There's now a check in place that suppresses the GPT-for-BIOS
message if the user is going to follow its advice already.
This commit is contained in:
Adriaan de Groot 2021-05-25 15:45:07 +02:00
commit e2d6e63fe6
5 changed files with 102 additions and 44 deletions

View File

@ -18,6 +18,7 @@
// KPMcore // KPMcore
#include <kpmcore/core/device.h> #include <kpmcore/core/device.h>
#include <kpmcore/core/partition.h>
#include <QComboBox> #include <QComboBox>
@ -148,28 +149,39 @@ BootLoaderModel::data( const QModelIndex& index, int role ) const
return QStandardItemModel::data( index, role ); return QStandardItemModel::data( index, role );
} }
namespace Calamares std::pair< int, Device* >
BootLoaderModel::findBootLoader( const QString& path ) const
{ {
int int r = 0;
findBootloader( const QAbstractItemModel* model, const QString& path ) for ( Device* d : m_devices )
{
for ( int i = 0; i < model->rowCount(); ++i )
{ {
const auto index = model->index( i, 0, QModelIndex() ); if ( d && d->deviceNode() == path )
if ( !index.isValid() )
{ {
continue; return std::make_pair( r, d );
}
QVariant var = model->data( index, BootLoaderModel::BootLoaderPathRole );
if ( var.isValid() && var.toString() == path )
{
return i;
} }
r++;
} }
return -1; Partition* partition = KPMHelpers::findPartitionByMountPoint( m_devices, path );
if ( partition )
{
const QString partition_device_path = partition->deviceNode();
r = 0;
for ( Device* d : m_devices )
{
if ( d && d->deviceNode() == partition_device_path )
{
return std::make_pair( r, d );
}
r++;
}
}
return std::make_pair( -1, nullptr );
} }
namespace Calamares
{
void void
restoreSelectedBootLoader( QComboBox& combo, const QString& path ) restoreSelectedBootLoader( QComboBox& combo, const QString& path )
{ {
@ -180,12 +192,16 @@ restoreSelectedBootLoader( QComboBox& combo, const QString& path )
return; return;
} }
int r = -1;
if ( path.isEmpty() ) if ( path.isEmpty() )
{ {
cDebug() << "No path to restore, choosing default";
combo.setCurrentIndex( 0 ); combo.setCurrentIndex( 0 );
return;
} }
else if ( ( r = findBootloader( model, path ) ) >= 0 )
const BootLoaderModel* bmodel = qobject_cast< const BootLoaderModel* >( model );
int r = bmodel ? bmodel->findBootLoader( path ).first : -1;
if ( r >= 0 )
{ {
combo.setCurrentIndex( r ); combo.setCurrentIndex( r );
} }

View File

@ -26,6 +26,8 @@ class BootLoaderModel : public QStandardItemModel
{ {
Q_OBJECT Q_OBJECT
public: public:
using DeviceList = QList< Device* >;
enum enum
{ {
BootLoaderPathRole = Qt::UserRole + 1, BootLoaderPathRole = Qt::UserRole + 1,
@ -39,13 +41,19 @@ public:
* Init the model with the list of devices. Does *not* take ownership of the * Init the model with the list of devices. Does *not* take ownership of the
* devices. * devices.
*/ */
void init( const QList< Device* >& devices ); void init( const DeviceList& devices );
void update(); void update();
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override; QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const override;
using DeviceList = QList< Device* >; /** @brief Looks up a boot-loader by device-name @p path (e.g. /dev/sda)
*
* Returns a row number (index) in the model and a Device*: if there **is** a
* device for the given @p path, index will be in range of the model and
* Device* non-null. Returns (-1, nullptr) otherwise.
*/
std::pair< int, Device* > findBootLoader( const QString& path ) const;
private: private:
DeviceList m_devices; DeviceList m_devices;
@ -57,13 +65,6 @@ private:
namespace Calamares namespace Calamares
{ {
/** @brief Returns the row number of boot-loader @p path (e.g. /dev/sda)
*
* Assuming the @p model is a BootLoaderModel, will return a row number
* in the model. Returns -1 otherwise.
*/
int findBootloader( const QAbstractItemModel* model, const QString& path );
/** @brief Tries to set @p path as selected item in @p combo /** @brief Tries to set @p path as selected item in @p combo
* *
* Matches a boot-loader install path (e.g. /dev/sda) with a model * Matches a boot-loader install path (e.g. /dev/sda) with a model

View File

@ -340,7 +340,7 @@ PartitionCoreModule::deviceModel() const
return m_deviceModel; return m_deviceModel;
} }
QAbstractItemModel* BootLoaderModel*
PartitionCoreModule::bootLoaderModel() const PartitionCoreModule::bootLoaderModel() const
{ {
return m_bootLoaderModel; return m_bootLoaderModel;

View File

@ -122,7 +122,7 @@ public:
* The single BootLoaderModel instance belongs to the PCM. * The single BootLoaderModel instance belongs to the PCM.
* @return the BootLoaderModel. * @return the BootLoaderModel.
*/ */
QAbstractItemModel* bootLoaderModel() const; BootLoaderModel* bootLoaderModel() const;
void createPartitionTable( Device* device, PartitionTable::TableType type ); void createPartitionTable( Device* device, PartitionTable::TableType type );

View File

@ -13,6 +13,7 @@
#include "gui/PartitionViewStep.h" #include "gui/PartitionViewStep.h"
#include "core/BootLoaderModel.h"
#include "core/Config.h" #include "core/Config.h"
#include "core/DeviceModel.h" #include "core/DeviceModel.h"
#include "core/KPMHelpers.h" #include "core/KPMHelpers.h"
@ -36,6 +37,7 @@
#include "utils/NamedEnum.h" #include "utils/NamedEnum.h"
#include "utils/QtCompat.h" #include "utils/QtCompat.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "utils/Units.h"
#include "utils/Variant.h" #include "utils/Variant.h"
#include "widgets/WaitingWidget.h" #include "widgets/WaitingWidget.h"
@ -395,6 +397,44 @@ PartitionViewStep::onActivate()
} }
} }
static bool
shouldWarnForGPTOnBIOS( const PartitionCoreModule* core )
{
if ( PartUtils::isEfiSystem() )
{
return false;
}
auto [ r, device ] = core->bootLoaderModel()->findBootLoader( core->bootLoaderInstallPath() );
if ( device )
{
auto* table = device->partitionTable();
cDebug() << "Found device for bootloader" << device->deviceNode();
if ( table && table->type() == PartitionTable::TableType::gpt )
{
// So this is a BIOS system, and the bootloader will be installed on a GPT system
for ( const auto& partition : qAsConst( table->children() ) )
{
using CalamaresUtils::Units::operator""_MiB;
if ( ( partition->activeFlags() & PartitionTable::Flag::BiosGrub )
&& ( partition->fileSystem().type() == FileSystem::Unformatted )
&& ( partition->capacity() >= 8_MiB ) )
{
cDebug() << Logger::SubEntry << "Partition" << partition->devicePath()
<< partition->partitionPath()
<< "is a suitable bios_grub partition";
return false;
}
}
}
cDebug() << Logger::SubEntry << "No suitable partition for bios_grub found";
}
else
{
cDebug() << "Found no device for" << core->bootLoaderInstallPath();
}
return true;
}
void void
PartitionViewStep::onLeave() PartitionViewStep::onLeave()
@ -462,9 +502,9 @@ PartitionViewStep::onLeave()
{ {
cDebug() << "device: BIOS"; cDebug() << "device: BIOS";
// TODO: this *always* warns, which might be annoying, so it'd be
// best to find a way to detect that bios_grub partition.
if ( shouldWarnForGPTOnBIOS( m_core ) )
{
QString message = tr( "Option to use GPT on BIOS" ); QString message = tr( "Option to use GPT on BIOS" );
QString description = tr( "A GPT partition table is the best option for all " QString description = tr( "A GPT partition table is the best option for all "
"systems. This installer supports such a setup for " "systems. This installer supports such a setup for "
@ -481,6 +521,7 @@ PartitionViewStep::onLeave()
QMessageBox::information( m_manualPartitionPage, message, description ); QMessageBox::information( m_manualPartitionPage, message, description );
} }
}
Partition* root_p = m_core->findPartitionByMountPoint( "/" ); Partition* root_p = m_core->findPartitionByMountPoint( "/" );
Partition* boot_p = m_core->findPartitionByMountPoint( "/boot" ); Partition* boot_p = m_core->findPartitionByMountPoint( "/boot" );
@ -593,7 +634,7 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// because it could take a while. Then when it's done, we can set up the widgets // because it could take a while. Then when it's done, we can set up the widgets
// and remove the spinner. // and remove the spinner.
m_future = new QFutureWatcher< void >(); m_future = new QFutureWatcher< void >();
connect( m_future, &QFutureWatcher< void >::finished, this, [this] { connect( m_future, &QFutureWatcher< void >::finished, this, [ this ] {
continueLoading(); continueLoading();
this->m_future->deleteLater(); this->m_future->deleteLater();
this->m_future = nullptr; this->m_future = nullptr;