Merge branch 'requirements-checking'

This commit is contained in:
Adriaan de Groot 2019-02-25 10:00:43 -05:00
commit 8cf3c217f7
29 changed files with 805 additions and 285 deletions

View File

@ -348,6 +348,7 @@ void
CalamaresApplication::initViewSteps() CalamaresApplication::initViewSteps()
{ {
cDebug() << "STARTUP: loadModules for all modules done"; cDebug() << "STARTUP: loadModules for all modules done";
m_moduleManager->checkRequirements();
if ( Calamares::Branding::instance()->windowMaximize() ) if ( Calamares::Branding::instance()->windowMaximize() )
{ {
m_mainwindow->setWindowFlag( Qt::FramelessWindowHint ); m_mainwindow->setWindowFlag( Qt::FramelessWindowHint );
@ -355,6 +356,7 @@ CalamaresApplication::initViewSteps()
} }
else else
m_mainwindow->show(); m_mainwindow->show();
ProgressTreeModel* m = new ProgressTreeModel( nullptr ); ProgressTreeModel* m = new ProgressTreeModel( nullptr );
ProgressTreeView::instance()->setModel( m ); ProgressTreeView::instance()->setModel( m );
cDebug() << "STARTUP: Window now visible and ProgressTreeView populated"; cDebug() << "STARTUP: Window now visible and ProgressTreeView populated";

View File

@ -5,6 +5,8 @@ set( calamaresui_SOURCES
modulesystem/Module.cpp modulesystem/Module.cpp
modulesystem/ModuleManager.cpp modulesystem/ModuleManager.cpp
modulesystem/ProcessJobModule.cpp modulesystem/ProcessJobModule.cpp
modulesystem/Requirement.cpp
modulesystem/RequirementsChecker.cpp
modulesystem/ViewModule.cpp modulesystem/ViewModule.cpp
utils/CalamaresUtilsGui.cpp utils/CalamaresUtilsGui.cpp

View File

@ -281,4 +281,10 @@ Module::initFrom( const QVariantMap& moduleDescriptor )
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool(); m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
} }
RequirementsList
Module::checkRequirements()
{
return RequirementsList();
}
} //ns } //ns

View File

@ -1,6 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> === /* === This file is part of Calamares - <https://github.com/calamares> ===
* *
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org> * Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* *
* Calamares is free software: you can redistribute it and/or modify * Calamares is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -19,6 +20,7 @@
#ifndef CALAMARES_MODULE_H #ifndef CALAMARES_MODULE_H
#define CALAMARES_MODULE_H #define CALAMARES_MODULE_H
#include "Requirement.h"
#include "UiDllMacro.h" #include "UiDllMacro.h"
#include <Typedefs.h> #include <Typedefs.h>
@ -178,6 +180,11 @@ public:
*/ */
QVariantMap configurationMap(); QVariantMap configurationMap();
/**
* @brief Check the requirements of this module.
*/
virtual RequirementsList checkRequirements();
protected: protected:
explicit Module(); explicit Module();
virtual void initFrom( const QVariantMap& moduleDescriptor ); virtual void initFrom( const QVariantMap& moduleDescriptor );

View File

@ -21,26 +21,23 @@
#include "ExecutionViewStep.h" #include "ExecutionViewStep.h"
#include "Module.h" #include "Module.h"
#include "utils/Logger.h" #include "RequirementsChecker.h"
#include "utils/YamlUtils.h"
#include "Settings.h" #include "Settings.h"
#include "ViewManager.h" #include "ViewManager.h"
#include "utils/Logger.h"
#include "utils/YamlUtils.h"
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <QApplication> #include <QApplication>
#include <QDir> #include <QDir>
#include <QTimer> #include <QTimer>
#define MODULE_CONFIG_FILENAME "module.desc"
namespace Calamares namespace Calamares
{ {
ModuleManager* ModuleManager::s_instance = nullptr; ModuleManager* ModuleManager::s_instance = nullptr;
ModuleManager* ModuleManager*
ModuleManager::instance() ModuleManager::instance()
{ {
@ -94,7 +91,7 @@ ModuleManager::doInit()
bool success = currentDir.cd( subdir ); bool success = currentDir.cd( subdir );
if ( success ) if ( success )
{ {
QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( MODULE_CONFIG_FILENAME ) ); QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( QLatin1Literal( "module.desc") ) );
if ( ! ( descriptorFileInfo.exists() && descriptorFileInfo.isReadable() ) ) if ( ! ( descriptorFileInfo.exists() && descriptorFileInfo.isReadable() ) )
{ {
cDebug() << Q_FUNC_INFO << "unreadable file: " cDebug() << Q_FUNC_INFO << "unreadable file: "
@ -307,6 +304,26 @@ ModuleManager::loadModules()
} ); } );
} }
void
ModuleManager::checkRequirements()
{
cDebug() << "Checking module requirements ..";
QVector< Module* > modules( m_loadedModulesByInstanceKey.count() );
int count = 0;
for (const auto& module : m_loadedModulesByInstanceKey )
{
modules[count++] = module;
}
RequirementsChecker *rq = new RequirementsChecker( modules, this );
connect( rq, &RequirementsChecker::requirementsResult, this, &ModuleManager::requirementsResult );
connect( rq, &RequirementsChecker::requirementsComplete, this, &ModuleManager::requirementsComplete );
connect( rq, &RequirementsChecker::requirementsProgress, this, &ModuleManager::requirementsProgress );
connect( rq, &RequirementsChecker::done, rq, &RequirementsChecker::deleteLater );
QTimer::singleShot( 0, rq, &RequirementsChecker::run );
}
QStringList QStringList
ModuleManager::checkDependencies() ModuleManager::checkDependencies()
@ -334,8 +351,6 @@ ModuleManager::checkDependencies()
break; break;
} }
} }
if ( somethingWasRemovedBecauseOfUnmetDependencies )
break;
} }
if ( !somethingWasRemovedBecauseOfUnmetDependencies ) if ( !somethingWasRemovedBecauseOfUnmetDependencies )
break; break;
@ -369,4 +384,4 @@ ModuleManager::checkDependencies( const Module& m )
return allRequirementsFound; return allRequirementsFound;
} }
} } // namespace

View File

@ -20,6 +20,7 @@
#ifndef MODULELOADER_H #ifndef MODULELOADER_H
#define MODULELOADER_H #define MODULELOADER_H
#include "Requirement.h"
#include "Typedefs.h" #include "Typedefs.h"
#include <QObject> #include <QObject>
@ -30,6 +31,7 @@ namespace Calamares
{ {
class Module; class Module;
struct RequirementEntry; // from Requirement.h
/** /**
* @brief The ModuleManager class is a singleton which manages Calamares modules. * @brief The ModuleManager class is a singleton which manages Calamares modules.
@ -81,10 +83,20 @@ public:
*/ */
void loadModules(); void loadModules();
/**
* @brief Starts asynchronous requirements checking for each module.
* When this is done, the signal modulesChecked is emitted.
*/
void checkRequirements();
signals: signals:
void initDone(); void initDone();
void modulesLoaded(); /// All of the modules were loaded successfully void modulesLoaded(); /// All of the modules were loaded successfully
void modulesFailed( QStringList ); /// .. or not void modulesFailed( QStringList ); /// .. or not
// Below, see RequirementsChecker documentation
void requirementsComplete( bool );
void requirementsResult( RequirementsList );
void requirementsProgress( const QString& );
private slots: private slots:
void doInit(); void doInit();

View File

@ -0,0 +1,19 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, Adriaan de Groot <groot@kde.org>
*
* 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 "Requirement.h"

View File

@ -0,0 +1,64 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2017, Adriaan de Groot <groot@kde.org>
*
* 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_REQUIREMENT_H
#define CALAMARES_REQUIREMENT_H
#include <QList>
#include <QMetaType>
#include <QString>
#include <functional>
namespace Calamares
{
/**
* An indication of a requirement, which is checked in preparation
* for system installation. An entry has a name and some explanation functions
* (functions, because they need to respond to translations).
*
* A requirement can be *satisfied* or not.
* A requirement can be optional (i.e. a "good to have") or mandatory.
*
* Requirements which are not satisfied, and also mandatory, will prevent the
* installation from proceeding.
*/
struct RequirementEntry
{
using TextFunction = std::function< QString() >;
/// @brief name of this requirement; not shown to user and used as ID
QString name;
/// @brief Description of this requirement, for use in user-visible lists
TextFunction enumerationText;
/// @brief User-visible string to show that the requirement is not met
TextFunction negatedText;
bool satisfied;
bool mandatory;
};
using RequirementsList = QList< RequirementEntry >;
} // namespace Calamares
Q_DECLARE_METATYPE(Calamares::RequirementEntry)
#endif

View File

@ -0,0 +1,154 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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 "RequirementsChecker.h"
#include "Module.h"
#include "Requirement.h"
#include "utils/Logger.h"
#include <algorithm>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
#include <QFutureWatcher>
#include <QTimer>
namespace Calamares
{
static void
registerMetatypes()
{
static bool done = false;
if ( !done )
{
qRegisterMetaType< RequirementEntry >( "RequirementEntry" );
// It's sensitive to the names of types in parameters; in particular
// althrough QList<RequirementEntry> is the same as RequirementsList,
// because we *name* the type as RequirementsList in the parameters,
// we need to register that (as well). Here, be safe and register
// both names.
qRegisterMetaType< QList< RequirementEntry > >( "QList<RequirementEntry>" );
qRegisterMetaType< RequirementsList >( "RequirementsList" );
done = true;
}
}
static void
check( Module * const &m, RequirementsChecker *c )
{
RequirementsList l = m->checkRequirements();
if ( l.count() > 0 )
c->addCheckedRequirements( l );
c->requirementsProgress( QObject::tr( "Requirements checking for module <i>%1</i> is complete." ).arg( m->name() ) );
}
RequirementsChecker::RequirementsChecker( QVector< Module* > modules, QObject* parent )
: QObject( parent )
, m_modules( std::move( modules ) )
, m_progressTimer( nullptr )
, m_progressTimeouts( 0 )
{
m_watchers.reserve( m_modules.count() );
m_collectedRequirements.reserve( m_modules.count() );
registerMetatypes();
}
RequirementsChecker::~RequirementsChecker()
{
}
void
RequirementsChecker::run()
{
m_progressTimer = new QTimer( this );
connect( m_progressTimer, &QTimer::timeout, this, &RequirementsChecker::reportProgress );
m_progressTimer->start( 1200 ); // msec
for (const auto& module : m_modules )
{
Watcher *watcher = new Watcher( this );
watcher->setFuture( QtConcurrent::run( check, module, this ) );
m_watchers.append( watcher );
connect( watcher, &Watcher::finished, this, &RequirementsChecker::finished );
}
QTimer::singleShot( 0, this, &RequirementsChecker::finished );
}
void
RequirementsChecker::finished()
{
if ( std::all_of( m_watchers.cbegin(), m_watchers.cend(), []( const Watcher *w ) { return w && w->isFinished(); } ) )
{
cDebug() << "All requirements have been checked.";
if ( m_progressTimer )
m_progressTimer->stop();
bool acceptable = true;
int count = 0;
for ( const auto& r : m_collectedRequirements )
{
if ( r.mandatory && !r.satisfied )
{
cDebug() << " .. requirement" << count << r.name << "is not satisfied.";
acceptable = false;
}
++count;
}
emit requirementsComplete( acceptable );
QTimer::singleShot(0, this, &RequirementsChecker::done );
}
}
void
RequirementsChecker::addCheckedRequirements( RequirementsList l )
{
static QMutex addMutex;
{
QMutexLocker lock( &addMutex );
m_collectedRequirements.append( l );
}
cDebug() << "Added" << l.count() << "requirement results";
emit requirementsResult( l );
}
void
RequirementsChecker::reportProgress()
{
m_progressTimeouts++;
auto remaining = std::count_if( m_watchers.cbegin(), m_watchers.cend(), []( const Watcher *w ) { return w && !w->isFinished(); } );
if ( remaining > 0 )
{
QString waiting = tr( "Waiting for %n module(s).", "", remaining );
QString elapsed = tr( "(%n second(s))", "", m_progressTimeouts * m_progressTimer->interval() / 1000 );
emit requirementsProgress( waiting + QString( " " ) + elapsed );
}
else
emit requirementsProgress( tr( "System-requirements checking is complete." ) );
}
}

View File

@ -0,0 +1,87 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2019, Adriaan de Groot <groot@kde.org>
*
* 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_REQUIREMENTSCHECKER_H
#define CALAMARES_REQUIREMENTSCHECKER_H
#include "Requirement.h"
#include <QFutureWatcher>
#include <QObject>
#include <QTimer>
#include <QVector>
namespace Calamares
{
class Module;
/** @brief A manager-class that checks all the module requirements
*
* Asynchronously checks the requirements for each module, and
* emits progress signals as appropriate.
*/
class RequirementsChecker : public QObject
{
Q_OBJECT
public:
RequirementsChecker( QVector< Module* > modules, QObject* parent = nullptr );
virtual ~RequirementsChecker() override;
public slots:
/// @brief Start checking all the requirements
void run();
/// @brief Called when requirements are reported by a module
void addCheckedRequirements( RequirementsList );
/// @brief Called when all requirements have been checked
void finished();
/// @brief Called periodically while requirements are being checked
void reportProgress();
signals:
/// @brief Human-readable progress message
void requirementsProgress( const QString& );
/// @brief Requirements from a single module
void requirementsResult( RequirementsList );
/** @brief When all requirements are collected
*
* The argument indicates if all mandatory requirements are satisfied.
*/
void requirementsComplete( bool );
/// @brief Emitted after requirementsComplete
void done();
private:
QVector< Module* > m_modules;
using Watcher = QFutureWatcher< void >;
QVector< Watcher* > m_watchers;
RequirementsList m_collectedRequirements;
QTimer *m_progressTimer;
unsigned m_progressTimeouts;
} ;
}
#endif

View File

@ -132,4 +132,10 @@ ViewModule::~ViewModule()
delete m_loader; delete m_loader;
} }
RequirementsList
ViewModule::checkRequirements()
{
return m_viewStep->checkRequirements();
}
} // namespace Calamares } // namespace Calamares

View File

@ -39,6 +39,8 @@ public:
void loadSelf() override; void loadSelf() override;
JobList jobs() const override; JobList jobs() const override;
RequirementsList checkRequirements() override;
protected: protected:
void initFrom( const QVariantMap& moduleDescriptor ) override; void initFrom( const QVariantMap& moduleDescriptor ) override;

View File

@ -74,4 +74,10 @@ ViewStep::setConfigurationMap( const QVariantMap& configurationMap )
Q_UNUSED( configurationMap ); Q_UNUSED( configurationMap );
} }
RequirementsList ViewStep::checkRequirements()
{
return RequirementsList();
}
} }

View File

@ -22,6 +22,7 @@
#include <QObject> #include <QObject>
#include "modulesystem/Requirement.h"
#include "../UiDllMacro.h" #include "../UiDllMacro.h"
#include "Typedefs.h" #include "Typedefs.h"
@ -117,6 +118,12 @@ public:
*/ */
virtual void onLeave(); virtual void onLeave();
/**
* @brief Jobs needed to run this viewstep
*
* When a ViewStep is listed in the exec section, its jobs are executed instead.
* This function returns that list of jobs; an empty list is ok.
*/
virtual JobList jobs() const = 0; virtual JobList jobs() const = 0;
void setModuleInstanceKey( const QString& instanceKey ); void setModuleInstanceKey( const QString& instanceKey );
@ -127,7 +134,17 @@ public:
virtual void setConfigurationMap( const QVariantMap& configurationMap ); virtual void setConfigurationMap( const QVariantMap& configurationMap );
/**
* @brief Can this module proceed, on this machine?
*
* This is called asynchronously at startup, and returns a list of
* the requirements that the module has checked, and their status.
* See Calamares::RequirementEntry for details.
*/
virtual RequirementsList checkRequirements();
signals: signals:
/// @brief Tells the viewmanager to enable the *next* button according to @p status
void nextStatusChanged( bool status ); void nextStatusChanged( bool status );
/* Emitted when the viewstep thinks it needs more space than is currently /* Emitted when the viewstep thinks it needs more space than is currently

View File

@ -882,11 +882,6 @@ ChoicePage::updateDeviceStatePreview()
PartitionModel* model = new PartitionModel( m_beforePartitionBarsView ); PartitionModel* model = new PartitionModel( m_beforePartitionBarsView );
model->init( deviceBefore, m_core->osproberEntries() ); model->init( deviceBefore, m_core->osproberEntries() );
// The QObject parents tree is meaningful for memory management here,
// see qDeleteAll above.
deviceBefore->setParent( model ); // Can't reparent across threads
model->setParent( m_beforePartitionBarsView );
m_beforePartitionBarsView->setModel( model ); m_beforePartitionBarsView->setModel( model );
m_beforePartitionLabelsView->setModel( model ); m_beforePartitionLabelsView->setModel( model );

View File

@ -60,6 +60,8 @@
#include <QtConcurrent/QtConcurrent> #include <QtConcurrent/QtConcurrent>
#include <QFutureWatcher> #include <QFutureWatcher>
#include <unistd.h> // For sleep(3)
PartitionViewStep::PartitionViewStep( QObject* parent ) PartitionViewStep::PartitionViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
, m_core( nullptr ) , m_core( nullptr )
@ -584,17 +586,18 @@ PartitionViewStep::setConfigurationMap( const QVariantMap& configurationMap )
// Now that we have the config, we load the PartitionCoreModule in the background // Now that we have the config, we load the PartitionCoreModule in the background
// 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.
QFutureWatcher< void >* watcher = new QFutureWatcher< void >(); m_future = new QFutureWatcher< void >();
connect( watcher, &QFutureWatcher< void >::finished, connect( m_future, &QFutureWatcher< void >::finished,
this, [ this, watcher, choices ] this, [ this ]
{ {
continueLoading(); continueLoading();
watcher->deleteLater(); this->m_future->deleteLater();
this->m_future = nullptr;
} ); } );
QFuture< void > future = QFuture< void > future =
QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule ); QtConcurrent::run( this, &PartitionViewStep::initPartitionCoreModule );
watcher->setFuture( future ); m_future->setFuture( future );
if ( configurationMap.contains( "partitionLayout" ) ) if ( configurationMap.contains( "partitionLayout" ) )
{ {
@ -613,5 +616,24 @@ PartitionViewStep::jobs() const
return m_core->jobs(); return m_core->jobs();
} }
Calamares::RequirementsList
PartitionViewStep::checkRequirements()
{
if ( m_future )
m_future->waitForFinished();
Calamares::RequirementsList l;
l.append(
{
QLatin1Literal( "partitions" ),
[]{ return tr( "has at least one disk device available." ); },
[]{ return tr( "There are no partitons to install on." ); },
m_core->deviceModel()->rowCount() > 0, // satisfied
true // required
} );
return l;
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin<PartitionViewStep>(); ) CALAMARES_PLUGIN_FACTORY_DEFINITION( PartitionViewStepFactory, registerPlugin<PartitionViewStep>(); )

View File

@ -36,6 +36,8 @@ class PartitionPage;
class PartitionCoreModule; class PartitionCoreModule;
class QStackedWidget; class QStackedWidget;
template<typename T> class QFutureWatcher;
/** /**
* The starting point of the module. Instantiates PartitionCoreModule, * The starting point of the module. Instantiates PartitionCoreModule,
* ChoicePage and PartitionPage, then connects them. * ChoicePage and PartitionPage, then connects them.
@ -69,6 +71,8 @@ public:
QList< Calamares::job_ptr > jobs() const override; QList< Calamares::job_ptr > jobs() const override;
Calamares::RequirementsList checkRequirements() override;
private: private:
void initPartitionCoreModule(); void initPartitionCoreModule();
void continueLoading(); void continueLoading();
@ -79,6 +83,7 @@ private:
PartitionPage* m_manualPartitionPage; PartitionPage* m_manualPartitionPage;
QWidget* m_waitingWidget; QWidget* m_waitingWidget;
QFutureWatcher<void>* m_future;
QSet< PartitionActions::Choices::SwapChoice > m_swapChoices; QSet< PartitionActions::Choices::SwapChoice > m_swapChoices;
}; };

View File

@ -15,9 +15,10 @@ endif()
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui ) include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
set( CHECKER_SOURCES set( CHECKER_SOURCES
checker/CheckItemWidget.cpp checker/CheckerContainer.cpp
checker/CheckerWidget.cpp checker/CheckerWidget.cpp
checker/RequirementsChecker.cpp checker/CheckItemWidget.cpp
checker/GeneralRequirements.cpp
${PARTMAN_SRC} ${PARTMAN_SRC}
) )

View File

@ -22,10 +22,12 @@
#include "ui_WelcomePage.h" #include "ui_WelcomePage.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "checker/RequirementsChecker.h" #include "checker/CheckerContainer.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Retranslator.h" #include "utils/Retranslator.h"
#include "modulesystem/ModuleManager.h"
#include "ViewManager.h" #include "ViewManager.h"
#include <QApplication> #include <QApplication>
@ -39,11 +41,14 @@
#include "Branding.h" #include "Branding.h"
WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* parent ) WelcomePage::WelcomePage( QWidget* parent )
: QWidget( parent ) : QWidget( parent )
, ui( new Ui::WelcomePage ) , ui( new Ui::WelcomePage )
, m_requirementsChecker( requirementsChecker ) , m_checkingWidget( new CheckerContainer( this ) )
{ {
connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsResult, m_checkingWidget, &CheckerContainer::requirementsChecked );
connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, m_checkingWidget, &CheckerContainer::requirementsComplete );
connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsProgress, m_checkingWidget, &CheckerContainer::requirementsProgress );
ui->setupUi( this ); ui->setupUi( this );
ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 ); ui->verticalLayout->insertSpacing( 1, CalamaresUtils::defaultFontHeight() * 2 );
@ -102,7 +107,7 @@ WelcomePage::WelcomePage( RequirementsChecker* requirementsChecker, QWidget* par
mb.exec(); mb.exec();
} ); } );
ui->verticalLayout->insertWidget( 3, m_requirementsChecker->widget() ); ui->verticalLayout->insertWidget( 3, m_checkingWidget);
} }
@ -277,3 +282,8 @@ WelcomePage::focusInEvent( QFocusEvent* e )
ui->languageWidget->setFocus(); ui->languageWidget->setFocus();
e->accept(); e->accept();
} }
bool WelcomePage::verdict() const
{
return m_checkingWidget->verdict();
}

View File

@ -26,26 +26,27 @@ namespace Ui
class WelcomePage; class WelcomePage;
} }
class RequirementsChecker; class CheckerContainer;
class WelcomePage : public QWidget class WelcomePage : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit WelcomePage( RequirementsChecker* requirementsChecker, explicit WelcomePage( QWidget* parent = nullptr );
QWidget* parent = nullptr );
void setUpLinks( bool showSupportUrl, void setUpLinks( bool showSupportUrl,
bool showKnownIssuesUrl, bool showKnownIssuesUrl,
bool showReleaseNotesUrl ); bool showReleaseNotesUrl );
bool verdict() const;
protected: protected:
void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus void focusInEvent( QFocusEvent* e ) override; //choose the child widget to focus
private: private:
void initLanguages(); void initLanguages();
Ui::WelcomePage* ui; Ui::WelcomePage* ui;
RequirementsChecker* m_requirementsChecker; CheckerContainer* m_checkingWidget;
}; };
#endif // WELCOMEPAGE_H #endif // WELCOMEPAGE_H

View File

@ -20,9 +20,10 @@
#include "WelcomeViewStep.h" #include "WelcomeViewStep.h"
#include "WelcomePage.h" #include "WelcomePage.h"
#include "checker/RequirementsChecker.h" #include "checker/GeneralRequirements.h"
#include "utils/Logger.h"
#include "modulesystem/ModuleManager.h"
#include "utils/Logger.h"
#include <QVariant> #include <QVariant>
@ -30,12 +31,10 @@ CALAMARES_PLUGIN_FACTORY_DEFINITION( WelcomeViewStepFactory, registerPlugin<Welc
WelcomeViewStep::WelcomeViewStep( QObject* parent ) WelcomeViewStep::WelcomeViewStep( QObject* parent )
: Calamares::ViewStep( parent ) : Calamares::ViewStep( parent )
, m_requirementsChecker( new RequirementsChecker( this ) ) , m_requirementsChecker( new GeneralRequirements( this ) )
{ {
emit nextStatusChanged( true ); connect( Calamares::ModuleManager::instance(), &Calamares::ModuleManager::requirementsComplete, this, &WelcomeViewStep::nextStatusChanged );
m_widget = new WelcomePage( m_requirementsChecker ); m_widget = new WelcomePage();
connect( m_requirementsChecker, &RequirementsChecker::verdictChanged,
this, &WelcomeViewStep::nextStatusChanged );
} }
@ -63,7 +62,7 @@ WelcomeViewStep::widget()
bool bool
WelcomeViewStep::isNextEnabled() const WelcomeViewStep::isNextEnabled() const
{ {
return m_requirementsChecker->verdict(); return m_widget->verdict();
} }
@ -88,10 +87,10 @@ WelcomeViewStep::isAtEnd() const
} }
QList< Calamares::job_ptr > Calamares::JobList
WelcomeViewStep::jobs() const WelcomeViewStep::jobs() const
{ {
return QList< Calamares::job_ptr >(); return Calamares::JobList();
} }
@ -123,3 +122,7 @@ WelcomeViewStep::setConfigurationMap( const QVariantMap& configurationMap )
"module configuration."; "module configuration.";
} }
Calamares::RequirementsList WelcomeViewStep::checkRequirements()
{
return m_requirementsChecker->checkRequirements();
}

View File

@ -21,6 +21,7 @@
#include <QObject> #include <QObject>
#include <modulesystem/Requirement.h>
#include <utils/PluginFactory.h> #include <utils/PluginFactory.h>
#include <viewpages/ViewStep.h> #include <viewpages/ViewStep.h>
@ -29,7 +30,7 @@
#include <QVariantMap> #include <QVariantMap>
class WelcomePage; class WelcomePage;
class RequirementsChecker; class GeneralRequirements;
class PLUGINDLLEXPORT WelcomeViewStep : public Calamares::ViewStep class PLUGINDLLEXPORT WelcomeViewStep : public Calamares::ViewStep
{ {
@ -49,14 +50,15 @@ public:
bool isAtBeginning() const override; bool isAtBeginning() const override;
bool isAtEnd() const override; bool isAtEnd() const override;
QList< Calamares::job_ptr > jobs() const override; Calamares::JobList jobs() const override;
void setConfigurationMap( const QVariantMap& configurationMap ) override; void setConfigurationMap( const QVariantMap& configurationMap ) override;
Calamares::RequirementsList checkRequirements() override;
private: private:
WelcomePage* m_widget; WelcomePage* m_widget;
GeneralRequirements* m_requirementsChecker;
RequirementsChecker* m_requirementsChecker;
}; };
CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory ) CALAMARES_PLUGIN_FACTORY_DECLARATION( WelcomeViewStepFactory )

View File

@ -0,0 +1,78 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
*
* 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/>.
*/
/* Based on code extracted from RequirementsChecker.cpp */
#include "CheckerContainer.h"
#include "CheckerWidget.h"
#include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h"
#include "utils/Retranslator.h"
#include "widgets/WaitingWidget.h"
CheckerContainer::CheckerContainer(QWidget* parent)
: QWidget( parent )
, m_waitingWidget( new WaitingWidget( QString() ) )
, m_checkerWidget( new CheckerWidget() )
, m_verdict( false )
{
QBoxLayout* mainLayout = new QHBoxLayout;
setLayout( mainLayout );
CalamaresUtils::unmarginLayout( mainLayout );
mainLayout->addWidget( m_waitingWidget );
CALAMARES_RETRANSLATE( m_waitingWidget->setText( tr( "Gathering system information..." ) ); )
}
CheckerContainer::~CheckerContainer()
{
delete m_waitingWidget;
delete m_checkerWidget;
}
void CheckerContainer::requirementsComplete( bool ok )
{
m_checkerWidget->init( m_requirements );
layout()->removeWidget( m_waitingWidget );
m_waitingWidget->deleteLater();
m_waitingWidget = nullptr; // Don't delete in destructor
m_checkerWidget->setParent( this );
layout()->addWidget( m_checkerWidget );
m_verdict = ok;
}
void CheckerContainer::requirementsChecked(const Calamares::RequirementsList& l)
{
m_requirements.append( l );
}
void CheckerContainer::requirementsProgress(const QString& message)
{
if ( m_waitingWidget )
m_waitingWidget->setText( message );
}
bool CheckerContainer::verdict() const
{
return m_verdict;
}

View File

@ -0,0 +1,64 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2017, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, Gabriel Craciunescu <crazy@frugalware.org>
*
* 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/>.
*/
/* Based on code extracted from RequirementsChecker.cpp */
#ifndef CHECKERCONTAINER_H
#define CHECKERCONTAINER_H
#include <QWidget>
#include "modulesystem/Requirement.h"
class CheckerWidget;
class WaitingWidget;
/**
* A widget that collects requirements results; until the results are
* all in, displays a spinner / waiting widget. Then it switches to
* a (list) diplay of the results, plus some explanation of the
* overall state of the entire list of results.
*/
class CheckerContainer : public QWidget
{
Q_OBJECT
public:
explicit CheckerContainer( QWidget* parent = nullptr );
virtual ~CheckerContainer();
bool verdict() const;
public slots:
void requirementsChecked( const Calamares::RequirementsList& );
/** @brief All the requirements are complete, switch to list view */
void requirementsComplete( bool );
void requirementsProgress( const QString& message );
protected:
WaitingWidget *m_waitingWidget;
CheckerWidget *m_checkerWidget;
Calamares::RequirementsList m_requirements;
bool m_verdict;
} ;
#endif

View File

@ -53,22 +53,22 @@ CheckerWidget::CheckerWidget( QWidget* parent )
void void
CheckerWidget::init( const QList< PrepareEntry >& checkEntries ) CheckerWidget::init( const Calamares::RequirementsList& checkEntries )
{ {
bool allChecked = true; bool allChecked = true;
bool requirementsSatisfied = true; bool requirementsSatisfied = true;
for ( const PrepareEntry& entry : checkEntries ) for ( const auto& entry : checkEntries )
{ {
if ( !entry.checked ) if ( !entry.satisfied )
{ {
CheckItemWidget* ciw = new CheckItemWidget( entry.checked, entry.required ); CheckItemWidget* ciw = new CheckItemWidget( entry.satisfied, entry.mandatory );
CALAMARES_RETRANSLATE( ciw->setText( entry.negatedText() ); ) CALAMARES_RETRANSLATE( ciw->setText( entry.negatedText() ); )
m_entriesLayout->addWidget( ciw ); m_entriesLayout->addWidget( ciw );
ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
allChecked = false; allChecked = false;
if ( entry.required ) if ( entry.mandatory )
{ {
requirementsSatisfied = false; requirementsSatisfied = false;
} }
@ -162,7 +162,7 @@ CheckerWidget::init( const QList< PrepareEntry >& checkEntries )
void void
CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries ) CheckerWidget::showDetailsDialog( const Calamares::RequirementsList& checkEntries )
{ {
QDialog* detailsDialog = new QDialog( this ); QDialog* detailsDialog = new QDialog( this );
QBoxLayout* mainLayout = new QVBoxLayout; QBoxLayout* mainLayout = new QVBoxLayout;
@ -177,12 +177,12 @@ CheckerWidget::showDetailsDialog( const QList< PrepareEntry >& checkEntries )
CalamaresUtils::unmarginLayout( entriesLayout ); CalamaresUtils::unmarginLayout( entriesLayout );
mainLayout->addLayout( entriesLayout ); mainLayout->addLayout( entriesLayout );
for ( const PrepareEntry& entry : checkEntries ) for ( const auto& entry : checkEntries )
{ {
if ( entry.enumerationText().isEmpty() ) if ( entry.enumerationText().isEmpty() )
continue; continue;
CheckItemWidget* ciw = new CheckItemWidget( entry.checked, entry.required ); CheckItemWidget* ciw = new CheckItemWidget( entry.satisfied, entry.mandatory );
CALAMARES_RETRANSLATE( ciw->setText( entry.enumerationText() ); ) CALAMARES_RETRANSLATE( ciw->setText( entry.enumerationText() ); )
entriesLayout->addWidget( ciw ); entriesLayout->addWidget( ciw );
ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred ); ciw->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );

View File

@ -19,7 +19,7 @@
#ifndef CHECKERWIDGET_H #ifndef CHECKERWIDGET_H
#define CHECKERWIDGET_H #define CHECKERWIDGET_H
#include "RequirementsChecker.h" #include "modulesystem/Requirement.h"
#include <QBoxLayout> #include <QBoxLayout>
#include <QWidget> #include <QWidget>
@ -30,10 +30,10 @@ class CheckerWidget : public QWidget
public: public:
explicit CheckerWidget( QWidget* parent = nullptr ); explicit CheckerWidget( QWidget* parent = nullptr );
void init( const QList< PrepareEntry >& checkEntries ); void init( const Calamares::RequirementsList& checkEntries );
private: private:
void showDetailsDialog( const QList< PrepareEntry >& checkEntries ); void showDetailsDialog( const Calamares::RequirementsList& checkEntries );
QBoxLayout* m_mainLayout; QBoxLayout* m_mainLayout;
QBoxLayout* m_entriesLayout; QBoxLayout* m_entriesLayout;

View File

@ -18,11 +18,12 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "RequirementsChecker.h" #include "GeneralRequirements.h"
#include "CheckerWidget.h" #include "CheckerContainer.h"
#include "partman_devices.h" #include "partman_devices.h"
#include "modulesystem/Requirement.h"
#include "widgets/WaitingWidget.h" #include "widgets/WaitingWidget.h"
#include "utils/CalamaresUtilsGui.h" #include "utils/CalamaresUtilsGui.h"
#include "utils/Logger.h" #include "utils/Logger.h"
@ -30,6 +31,7 @@
#include "utils/CalamaresUtilsSystem.h" #include "utils/CalamaresUtilsSystem.h"
#include "utils/Units.h" #include "utils/Units.h"
#include "JobQueue.h" #include "JobQueue.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
@ -51,29 +53,17 @@
#include <unistd.h> //geteuid #include <unistd.h> //geteuid
RequirementsChecker::RequirementsChecker( QObject* parent ) GeneralRequirements::GeneralRequirements( QObject* parent )
: QObject( parent ) : QObject( parent )
, m_widget( new QWidget() )
, m_requiredStorageGB( -1 ) , m_requiredStorageGB( -1 )
, m_requiredRamGB( -1 ) , m_requiredRamGB( -1 )
, m_actualWidget( new CheckerWidget() )
, m_verdict( false )
{ {
QBoxLayout* mainLayout = new QHBoxLayout; }
m_widget->setLayout( mainLayout );
CalamaresUtils::unmarginLayout( mainLayout );
WaitingWidget* waitingWidget = new WaitingWidget( QString() ); Calamares::RequirementsList GeneralRequirements::checkRequirements()
mainLayout->addWidget( waitingWidget );
CALAMARES_RETRANSLATE( waitingWidget->setText( tr( "Gathering system information..." ) ); )
QSize availableSize = qApp->desktop()->availableGeometry( m_widget ).size();
QTimer* timer = new QTimer;
timer->setSingleShot( true );
connect( timer, &QTimer::timeout,
[=]()
{ {
QSize availableSize = qApp->desktop()->availableGeometry().size();
bool enoughStorage = false; bool enoughStorage = false;
bool enoughRam = false; bool enoughRam = false;
bool hasPower = false; bool hasPower = false;
@ -101,15 +91,14 @@ RequirementsChecker::RequirementsChecker( QObject* parent )
isRoot = checkIsRoot(); isRoot = checkIsRoot();
using TR = Logger::DebugRow<const char *, bool>; using TR = Logger::DebugRow<const char *, bool>;
cDebug() << "GeneralRequirements output:"
cDebug() << "RequirementsChecker output:"
<< TR("enoughStorage", enoughStorage) << TR("enoughStorage", enoughStorage)
<< TR("enoughRam", enoughRam) << TR("enoughRam", enoughRam)
<< TR("hasPower", hasPower) << TR("hasPower", hasPower)
<< TR("hasInternet", hasInternet) << TR("hasInternet", hasInternet)
<< TR("isRoot", isRoot); << TR("isRoot", isRoot);
QList< PrepareEntry > checkEntries; Calamares::RequirementsList checkEntries;
foreach ( const QString& entry, m_entriesToCheck ) foreach ( const QString& entry, m_entriesToCheck )
{ {
if ( entry == "storage" ) if ( entry == "storage" )
@ -165,52 +154,12 @@ RequirementsChecker::RequirementsChecker( QObject* parent )
false false
} ); } );
} }
return checkEntries;
m_actualWidget->init( checkEntries );
m_widget->layout()->removeWidget( waitingWidget );
waitingWidget->deleteLater();
m_actualWidget->setParent( m_widget );
m_widget->layout()->addWidget( m_actualWidget );
bool canGoNext = true;
foreach ( const PrepareEntry& entry, checkEntries )
{
if ( !entry.checked && entry.required )
{
canGoNext = false;
break;
}
}
m_verdict = canGoNext;
emit verdictChanged( m_verdict );
if ( canGoNext )
detectFirmwareType();
timer->deleteLater();
} );
timer->start( 0 );
emit verdictChanged( true );
}
RequirementsChecker::~RequirementsChecker()
{
if ( m_widget && m_widget->parent() == nullptr )
m_widget->deleteLater();
}
QWidget*
RequirementsChecker::widget() const
{
return m_widget;
} }
void void
RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap ) GeneralRequirements::setConfigurationMap( const QVariantMap& configurationMap )
{ {
bool incompleteConfiguration = false; bool incompleteConfiguration = false;
@ -222,7 +171,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'check' is incomplete."; cWarning() << "GeneralRequirements entry 'check' is incomplete.";
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -234,14 +183,26 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'required' is incomplete."; cWarning() << "GeneralRequirements entry 'required' is incomplete.";
incompleteConfiguration = true; incompleteConfiguration = true;
} }
#ifdef WITHOUT_LIBPARTED
if ( m_entriesToCheck.contains( "storage" ) )
cWarning() << "GeneralRequirements checks 'storage' but libparted is disabled.";
if ( m_entriesToRequire.contains( "storage" ) )
{
// Warn, but also drop the required bit because otherwise installation
// will be impossible (because the check always returns false).
cWarning() << "GeneralRequirements requires 'storage' check but libparted is disabled.";
m_entriesToRequire.removeAll( "storage" );
}
#endif
// Help out with consistency, but don't fix // Help out with consistency, but don't fix
for ( const auto& r : m_entriesToRequire ) for ( const auto& r : m_entriesToRequire )
if ( !m_entriesToCheck.contains( r ) ) if ( !m_entriesToCheck.contains( r ) )
cWarning() << "RequirementsChecker requires" << r << "but does not check it."; cWarning() << "GeneralRequirements requires" << r << "but does not check it.";
if ( configurationMap.contains( "requiredStorage" ) && if ( configurationMap.contains( "requiredStorage" ) &&
( configurationMap.value( "requiredStorage" ).type() == QVariant::Double || ( configurationMap.value( "requiredStorage" ).type() == QVariant::Double ||
@ -251,7 +212,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok ); m_requiredStorageGB = configurationMap.value( "requiredStorage" ).toDouble( &ok );
if ( !ok ) if ( !ok )
{ {
cWarning() << "RequirementsChecker entry 'requiredStorage' is invalid."; cWarning() << "GeneralRequirements entry 'requiredStorage' is invalid.";
m_requiredStorageGB = 3.; m_requiredStorageGB = 3.;
} }
@ -259,7 +220,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'requiredStorage' is missing."; cWarning() << "GeneralRequirements entry 'requiredStorage' is missing.";
m_requiredStorageGB = 3.; m_requiredStorageGB = 3.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -272,14 +233,14 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok ); m_requiredRamGB = configurationMap.value( "requiredRam" ).toDouble( &ok );
if ( !ok ) if ( !ok )
{ {
cWarning() << "RequirementsChecker entry 'requiredRam' is invalid."; cWarning() << "GeneralRequirements entry 'requiredRam' is invalid.";
m_requiredRamGB = 1.; m_requiredRamGB = 1.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'requiredRam' is missing."; cWarning() << "GeneralRequirements entry 'requiredRam' is missing.";
m_requiredRamGB = 1.; m_requiredRamGB = 1.;
incompleteConfiguration = true; incompleteConfiguration = true;
} }
@ -291,7 +252,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
if ( m_checkHasInternetUrl.isEmpty() || if ( m_checkHasInternetUrl.isEmpty() ||
!QUrl( m_checkHasInternetUrl ).isValid() ) !QUrl( m_checkHasInternetUrl ).isValid() )
{ {
cWarning() << "RequirementsChecker entry 'internetCheckUrl' is invalid in welcome.conf" << m_checkHasInternetUrl cWarning() << "GeneralRequirements entry 'internetCheckUrl' is invalid in welcome.conf" << m_checkHasInternetUrl
<< "reverting to default (http://example.com)."; << "reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com"; m_checkHasInternetUrl = "http://example.com";
incompleteConfiguration = true; incompleteConfiguration = true;
@ -299,7 +260,7 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
} }
else else
{ {
cWarning() << "RequirementsChecker entry 'internetCheckUrl' is undefined in welcome.conf," cWarning() << "GeneralRequirements entry 'internetCheckUrl' is undefined in welcome.conf,"
"reverting to default (http://example.com)."; "reverting to default (http://example.com).";
m_checkHasInternetUrl = "http://example.com"; m_checkHasInternetUrl = "http://example.com";
@ -308,24 +269,17 @@ RequirementsChecker::setConfigurationMap( const QVariantMap& configurationMap )
if ( incompleteConfiguration ) if ( incompleteConfiguration )
{ {
cWarning() << "RequirementsChecker configuration map:" << Logger::DebugMap( configurationMap ); cWarning() << "GeneralRequirements configuration map:" << Logger::DebugMap( configurationMap );
} }
} }
bool bool
RequirementsChecker::verdict() const GeneralRequirements::checkEnoughStorage( qint64 requiredSpace )
{
return m_verdict;
}
bool
RequirementsChecker::checkEnoughStorage( qint64 requiredSpace )
{ {
#ifdef WITHOUT_LIBPARTED #ifdef WITHOUT_LIBPARTED
Q_UNUSED( requiredSpace ); Q_UNUSED( requiredSpace );
cWarning() << "RequirementsChecker is configured without libparted."; cWarning() << "GeneralRequirements is configured without libparted.";
return false; return false;
#else #else
return check_big_enough( requiredSpace ); return check_big_enough( requiredSpace );
@ -334,7 +288,7 @@ RequirementsChecker::checkEnoughStorage( qint64 requiredSpace )
bool bool
RequirementsChecker::checkEnoughRam( qint64 requiredRam ) GeneralRequirements::checkEnoughRam( qint64 requiredRam )
{ {
// Ignore the guesstimate-factor; we get an under-estimate // Ignore the guesstimate-factor; we get an under-estimate
// which is probably the usable RAM for programs. // which is probably the usable RAM for programs.
@ -344,7 +298,7 @@ RequirementsChecker::checkEnoughRam( qint64 requiredRam )
bool bool
RequirementsChecker::checkBatteryExists() GeneralRequirements::checkBatteryExists()
{ {
const QFileInfo basePath( "/sys/class/power_supply" ); const QFileInfo basePath( "/sys/class/power_supply" );
@ -370,7 +324,7 @@ RequirementsChecker::checkBatteryExists()
bool bool
RequirementsChecker::checkHasPower() GeneralRequirements::checkHasPower()
{ {
const QString UPOWER_SVC_NAME( "org.freedesktop.UPower" ); const QString UPOWER_SVC_NAME( "org.freedesktop.UPower" );
const QString UPOWER_INTF_NAME( "org.freedesktop.UPower" ); const QString UPOWER_INTF_NAME( "org.freedesktop.UPower" );
@ -401,10 +355,10 @@ RequirementsChecker::checkHasPower()
bool bool
RequirementsChecker::checkHasInternet() GeneralRequirements::checkHasInternet()
{ {
// default to true in the QNetworkAccessManager::UnknownAccessibility case // default to true in the QNetworkAccessManager::UnknownAccessibility case
QNetworkAccessManager qnam( this ); QNetworkAccessManager qnam;
bool hasInternet = qnam.networkAccessible() == QNetworkAccessManager::Accessible; bool hasInternet = qnam.networkAccessible() == QNetworkAccessManager::Accessible;
if ( !hasInternet && qnam.networkAccessible() == QNetworkAccessManager::UnknownAccessibility ) if ( !hasInternet && qnam.networkAccessible() == QNetworkAccessManager::UnknownAccessibility )
@ -425,14 +379,14 @@ RequirementsChecker::checkHasInternet()
bool bool
RequirementsChecker::checkIsRoot() GeneralRequirements::checkIsRoot()
{ {
return !geteuid(); return !geteuid();
} }
void void
RequirementsChecker::detectFirmwareType() GeneralRequirements::detectFirmwareType()
{ {
QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios"; QString fwType = QFile::exists( "/sys/firmware/efi/efivars" ) ? "efi" : "bios";
Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType ); Calamares::JobQueue::instance()->globalStorage()->insert( "firmwareType", fwType );

View File

@ -17,52 +17,23 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef REQUIREMENTSCHECKER_H #ifndef GENERALREQUIREMENTS_H
#define REQUIREMENTSCHECKER_H #define GENERALREQUIREMENTS_H
#include <QObject> #include <QObject>
#include <QStringList> #include <QStringList>
#include <functional> #include "modulesystem/Requirement.h"
class CheckerWidget; class GeneralRequirements : public QObject
class QWidget;
/**
* An indication of a requirement, which is checked in preparation
* for system installation. An entry has a name and some explanation,
* as well as three meaningful states:
* - checked = true, the requirement is met (green)
* - checked = false, the requirement is not met
* - required = false, warn about it (yellow), no failure
* - required = true, prohibit installation (red)
*/
struct PrepareEntry
{
QString name;
std::function< QString() > enumerationText; //Partial string, inserted in a
//list of requirements to satisfy.
std::function< QString() > negatedText; //Complete sentence about this requirement
//not having been met.
bool checked;
bool required;
};
class RequirementsChecker : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit RequirementsChecker( QObject* parent = nullptr ); explicit GeneralRequirements( QObject* parent = nullptr );
virtual ~RequirementsChecker();
QWidget* widget() const;
void setConfigurationMap( const QVariantMap& configurationMap ); void setConfigurationMap( const QVariantMap& configurationMap );
bool verdict() const; Calamares::RequirementsList checkRequirements();
signals:
void verdictChanged( bool );
private: private:
QStringList m_entriesToCheck; QStringList m_entriesToCheck;
@ -76,13 +47,9 @@ private:
bool checkIsRoot(); bool checkIsRoot();
void detectFirmwareType(); void detectFirmwareType();
QWidget* m_widget;
qreal m_requiredStorageGB; qreal m_requiredStorageGB;
qreal m_requiredRamGB; qreal m_requiredRamGB;
QString m_checkHasInternetUrl; QString m_checkHasInternetUrl;
CheckerWidget* m_actualWidget;
bool m_verdict;
}; };
#endif // REQUIREMENTSCHECKER_H #endif // REQUIREMENTSCHECKER_H

View File

@ -1,18 +1,37 @@
# Configuration for the welcome module. The welcome page
# displays some information from the branding file.
# Which parts it displays can be configured through
# the show* variables.
#
# In addition to displaying the welcome page, this module
# can check requirements for installation.
--- ---
# Display settings for various buttons on the welcome page.
showSupportUrl: true showSupportUrl: true
showKnownIssuesUrl: true showKnownIssuesUrl: true
showReleaseNotesUrl: true showReleaseNotesUrl: true
# Requirements checking. These are general, generic, things
# that are checked. They may not match with the actual requirements
# imposed by other modules in the system.
requirements: requirements:
# Amount of available disk, in GB. Floating-point is allowed here.
# Note that this does not account for *usable* disk, so it is possible
# to pass this requirement, yet have no space to install to.
requiredStorage: 5.5 requiredStorage: 5.5
# Amount of available RAM, in GB. Floating-point is allowed here.
requiredRam: 1.0 requiredRam: 1.0
# To check for internet connectivity, Calamares does a HTTP GET
# on this URL; on success (e.g. HTTP code 200) internet is OK.
internetCheckUrl: http://google.com internetCheckUrl: http://google.com
# List conditions to check. Each listed condition will be # List conditions to check. Each listed condition will be
# probed in some way, and yields true or false according to # probed in some way, and yields true or false according to
# the host system satisfying the condition. # the host system satisfying the condition.
# #
# This sample file lists all the conditions that are know. # This sample file lists all the conditions that are known.
check: check:
- storage - storage
- ram - ram
@ -20,7 +39,7 @@ requirements:
- internet - internet
- root - root
- screen - screen
# List conditions that must be satisfied (from the list # List conditions that **must** be satisfied (from the list
# of conditions, above) for installation to proceed. # of conditions, above) for installation to proceed.
# If any of these conditions are not met, the user cannot # If any of these conditions are not met, the user cannot
# continue past the welcome page. # continue past the welcome page.