Lots of changes. Module search+load system is now working.

Moved module-related classes to src/calamares/modulesystem.
Fixes to startup code path.
Made ViewPlugins load into ViewManager.
Debug code: ViewManager currently only shows a plugin's prettyName.
Added ViewModule as a subclass of Module. Other kinds of plugins should
be supported in a similar way.
This commit is contained in:
Teo Mrnjavac 2014-06-27 13:58:53 +02:00
parent fae3284bb7
commit 23e91ee475
13 changed files with 333 additions and 49 deletions

View File

@ -10,12 +10,14 @@ set( calamaresSources
main.cpp main.cpp
CalamaresApplication.cpp CalamaresApplication.cpp
CalamaresWindow.cpp CalamaresWindow.cpp
Module.cpp
ModuleManager.cpp
ViewManager.cpp ViewManager.cpp
Settings.cpp Settings.cpp
YamlUtils.cpp YamlUtils.cpp
modulesystem/Module.cpp
modulesystem/ModuleManager.cpp
modulesystem/ViewModule.cpp
viewpages/ViewPlugin.cpp viewpages/ViewPlugin.cpp
viewpages/AbstractPage.cpp viewpages/AbstractPage.cpp
) )

View File

@ -20,7 +20,7 @@
#include "CalamaresWindow.h" #include "CalamaresWindow.h"
#include "CalamaresVersion.h" #include "CalamaresVersion.h"
#include "ModuleManager.h" #include "modulesystem/ModuleManager.h"
#include "Settings.h" #include "Settings.h"
#include "utils/CalamaresUtils.h" #include "utils/CalamaresUtils.h"
#include "utils/Logger.h" #include "utils/Logger.h"
@ -115,9 +115,9 @@ CalamaresApplication::initPlugins()
{ {
m_moduleManager = new Calamares::ModuleManager( m_moduleManager = new Calamares::ModuleManager(
Calamares::Settings::instance()->modulesSearchPaths(), this ); Calamares::Settings::instance()->modulesSearchPaths(), this );
connect( m_moduleManager, &Calamares::ModuleManager::ready, connect( m_moduleManager, &Calamares::ModuleManager::initDone,
this, &CalamaresApplication::onPluginsReady ); this, &CalamaresApplication::onPluginsReady );
m_moduleManager->start(); m_moduleManager->init();
} }
@ -128,13 +128,11 @@ CalamaresApplication::onPluginsReady()
m_mainwindow = new CalamaresWindow(); m_mainwindow = new CalamaresWindow();
// foreach ( QString moduleName, Calamares::Settings::instance()->viewModulesPrepare() ) m_moduleManager->loadRequiredModules();
// { connect( m_moduleManager, &Calamares::ModuleManager::modulesLoaded, [this]
// Q_ASSERT( m_moduleManager->availableModules().contains( moduleName ) ); {
// m_moduleManager->module( moduleName )->loadSelf(); m_mainwindow->show();
// } });
m_mainwindow->show();
} }

View File

@ -19,6 +19,7 @@
#include "ViewManager.h" #include "ViewManager.h"
#include <QApplication> #include <QApplication>
#include <QLabel>
#include <QBoxLayout> #include <QBoxLayout>
namespace Calamares namespace Calamares
@ -79,7 +80,9 @@ ViewManager::widget()
void void
ViewManager::addViewPlugin( ViewPlugin* plugin ) ViewManager::addViewPlugin( ViewPlugin* plugin )
{ {
plugin->setParent( this );
m_steps.append( plugin );
m_stack->addWidget( new QLabel( plugin->prettyName(), m_stack ) );
} }

View File

@ -23,8 +23,10 @@
#include "viewpages/ViewPlugin.h" #include "viewpages/ViewPlugin.h"
#include <QPushButton> #include <QPushButton>
#include <QQueue>
#include <QStackedWidget> #include <QStackedWidget>
namespace Calamares namespace Calamares
{ {
@ -52,6 +54,8 @@ public slots:
private: private:
static ViewManager* s_instance; static ViewManager* s_instance;
QQueue< ViewPlugin* > m_steps;
QWidget* m_widget; QWidget* m_widget;
QStackedWidget* m_stack; QStackedWidget* m_stack;
QPushButton* m_back; QPushButton* m_back;

View File

@ -18,13 +18,15 @@
#include "Module.h" #include "Module.h"
#include "ViewModule.h"
#include "YamlUtils.h" #include "YamlUtils.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <QDir>
#include <QFile> #include <QFile>
#include <QFileInfo>
#include <QString> #include <QString>
@ -40,49 +42,55 @@ requires: [] #list of module names that must also be loaded. only appli
*/ */
void void
operator>>( const YAML::Node& node, Calamares::Module& m ) operator>>( const YAML::Node& node, Calamares::Module* m )
{ {
m.m_name = QString::fromStdString( node[ "name" ].as< std::string >() ); m->m_name = QString::fromStdString( node[ "name" ].as< std::string >() );
QString typeString = QString::fromStdString( node[ "type" ].as< std::string >() ); QString typeString = QString::fromStdString( node[ "type" ].as< std::string >() );
if ( typeString == "core" ) if ( typeString == "core" )
{ {
m.m_type = Calamares::Module::Core; m->m_type = Calamares::Module::Core;
} }
else if ( typeString == "view" ) else if ( typeString == "view" )
{ {
m.m_type = Calamares::Module::View; m->m_type = Calamares::Module::View;
m.m_interface = Calamares::Module::QtPlugin; m->m_interface = Calamares::Module::QtPlugin;
} }
if ( m.m_type != Calamares::Module::View ) if ( m->m_type != Calamares::Module::View )
{ {
QString interfaceString = QString::fromStdString( node[ "interface" ].as< std::string >() ); QString interfaceString = QString::fromStdString( node[ "interface" ].as< std::string >() );
if ( interfaceString == "qtplugin" ) if ( interfaceString == "qtplugin" )
{ {
m.m_interface = Calamares::Module::QtPlugin; m->m_interface = Calamares::Module::QtPlugin;
} }
else if ( interfaceString == "python" ) else if ( interfaceString == "python" )
{ {
m.m_interface = Calamares::Module::Python; m->m_interface = Calamares::Module::Python;
} }
else if ( interfaceString == "process" ) else if ( interfaceString == "process" )
{ {
m.m_interface = Calamares::Module::Process; m->m_interface = Calamares::Module::Process;
} }
} }
if ( node[ "requires" ] && node[ "requires" ].IsSequence() ) if ( node[ "requires" ] && node[ "requires" ].IsSequence() )
{ {
node[ "requires" ] >> m.m_requiredModules; node[ "requires" ] >> m->m_requiredModules;
} }
} }
namespace Calamares
Calamares::Module*
Calamares::Module::fromConfigFile( const QString& path )
{ {
Module::~Module()
{}
Module*
Module::fromConfigFile( const QString& path )
{
Module* m = nullptr;
QFile metadataFile( path ); QFile metadataFile( path );
if ( metadataFile.exists() && metadataFile.open( QFile::ReadOnly | QFile::Text ) ) if ( metadataFile.exists() && metadataFile.open( QFile::ReadOnly | QFile::Text ) )
{ {
@ -99,13 +107,18 @@ Calamares::Module::fromConfigFile( const QString& path )
return nullptr; return nullptr;
} }
Module* m = new Module(); m = new ViewModule();
moduleDocument >> *m;
QFileInfo mfi( path );
m->m_directory = mfi.absoluteDir().absolutePath();
m->initFrom( moduleDocument );
return m; return m;
} }
catch ( YAML::Exception& e ) catch ( YAML::Exception& e )
{ {
cDebug() << "WARNING: YAML parser error " << e.what(); cDebug() << "WARNING: YAML parser error " << e.what();
delete m;
return nullptr; return nullptr;
} }
} }
@ -114,14 +127,42 @@ Calamares::Module::fromConfigFile( const QString& path )
} }
QString QString
Calamares::Module::name() Module::name()
{ {
return m_name; return m_name;
} }
QStringList QStringList
Calamares::Module::requiredModules() Module::requiredModules()
{ {
return m_requiredModules; return m_requiredModules;
} }
QString
Module::location()
{
return m_directory;
}
bool
Module::isLoaded()
{
return m_loaded;
}
Module::Module()
: m_loaded( false )
{}
void
Module::initFrom( const YAML::Node& node )
{
node >> this;
}
} //ns

View File

@ -16,8 +16,8 @@
* along with Calamares. If not, see <http://www.gnu.org/licenses/>. * along with Calamares. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef CALAMARESMODULE_H #ifndef CALAMARES_MODULE_H
#define CALAMARESMODULE_H #define CALAMARES_MODULE_H
#include "UiDllMacro.h" #include "UiDllMacro.h"
@ -34,7 +34,7 @@ namespace Calamares
class Module; class Module;
} }
void operator>>( const YAML::Node& node, Calamares::Module& m ); void operator>>( const YAML::Node& node, Calamares::Module* m );
namespace Calamares namespace Calamares
{ {
@ -42,11 +42,6 @@ namespace Calamares
class UIDLLEXPORT Module class UIDLLEXPORT Module
{ {
public: public:
static Module* fromConfigFile( const QString& path );
QString name();
QStringList requiredModules();
enum Type enum Type
{ {
Core, Core,
@ -59,15 +54,35 @@ public:
Python, Python,
Process Process
}; };
virtual ~Module();
static Module* fromConfigFile( const QString& path );
virtual QString name();
virtual QStringList requiredModules();
virtual QString location();
virtual Type type() = 0;
virtual Interface interface() = 0;
virtual bool isLoaded();
virtual void loadSelf() = 0;
protected:
explicit Module();
virtual void initFrom( const YAML::Node& node );
bool m_loaded;
private: private:
QString m_name; QString m_name;
Type m_type; Type m_type;
Interface m_interface; Interface m_interface;
QStringList m_requiredModules; QStringList m_requiredModules;
QString m_directory;
friend void ::operator>>( const YAML::Node& node, Calamares::Module& m ); friend void ::operator>>( const YAML::Node& node, Calamares::Module* m );
}; };
} }
#endif // CALAMARESMODULE_H #endif // CALAMARES_MODULE_H

View File

@ -19,9 +19,11 @@
#include "ModuleManager.h" #include "ModuleManager.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "Settings.h"
#include <yaml-cpp/yaml.h> #include <yaml-cpp/yaml.h>
#include <QApplication>
#include <QDir> #include <QDir>
#include <QTimer> #include <QTimer>
@ -46,9 +48,9 @@ ModuleManager::~ModuleManager()
void void
ModuleManager::start() ModuleManager::init()
{ {
QTimer::singleShot( 0, this, SLOT( doWork() ) ); QTimer::singleShot( 0, this, SLOT( doInit() ) );
} }
@ -67,7 +69,14 @@ ModuleManager::module( const QString& name )
void void
ModuleManager::doWork() ModuleManager::loadRequiredModules()
{
QTimer::singleShot( 0, this, SLOT( doLoadModules() ) );
}
void
ModuleManager::doInit()
{ {
// We start from a list of paths in m_paths. Each of those is a directory that // We start from a list of paths in m_paths. Each of those is a directory that
// might (should) contain Calamares modules of any type/interface. // might (should) contain Calamares modules of any type/interface.
@ -120,7 +129,46 @@ ModuleManager::doWork()
// At this point m_availableModules is filled with whatever was found in the // At this point m_availableModules is filled with whatever was found in the
// search paths. // search paths.
checkDependencies(); checkDependencies();
emit ready(); emit initDone();
}
void
ModuleManager::doLoadModules()
{
foreach ( const QString& moduleName, Settings::instance()->viewModulesPrepare() )
{
if ( !m_availableModules.contains( moduleName ) )
{
cDebug() << "Module" << moduleName << "not found in module search paths."
<< "\nCalamares will now quit.";
qApp->quit();
}
recursiveLoad( moduleName );
}
emit modulesLoaded();
//IDEA:
// 1) deps are already fine. check if we have all the modules needed by the roster
// 2) ask MM to load them from the list provided by Settings
// 3) MM must load them asyncly but one at a time, by calling Module::loadSelf
// 4) Module must have subclasses that reimplement loadSelf for various module types
}
void
ModuleManager::recursiveLoad( const QString& moduleName )
{
Module* thisModule = m_availableModules.value( moduleName );
foreach ( const QString& module, thisModule->requiredModules() )
{
if ( !m_availableModules.value( module )->isLoaded() )
{
recursiveLoad( module );
}
}
thisModule->loadSelf();
cDebug() << ( thisModule->isLoaded() ? "SUCCESS" : "FAILURE" );
} }
@ -152,4 +200,5 @@ ModuleManager::checkDependencies()
} }
} }
} }

View File

@ -37,18 +37,23 @@ public:
explicit ModuleManager( const QStringList& paths, QObject* parent = 0 ); explicit ModuleManager( const QStringList& paths, QObject* parent = 0 );
virtual ~ModuleManager(); virtual ~ModuleManager();
void start(); void init();
QStringList availableModules(); QStringList availableModules();
Module* module( const QString& name ); Module* module( const QString& name );
void loadRequiredModules();
signals: signals:
void ready(); void initDone();
void modulesLoaded();
private slots: private slots:
void doWork(); void doInit();
void doLoadModules();
private: private:
void recursiveLoad( const QString& moduleName );
void checkDependencies(); void checkDependencies();
QMap< QString, Module* > m_availableModules; QMap< QString, Module* > m_availableModules;

View File

@ -0,0 +1,106 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@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 "ViewModule.h"
#include "utils/Logger.h"
#include "viewpages/ViewPlugin.h"
#include "ViewManager.h"
#include <yaml-cpp/yaml.h>
#include <QDir>
#include <QPluginLoader>
namespace Calamares {
Module::Type
ViewModule::type()
{
return View;
}
Module::Interface
ViewModule::interface()
{
return QtPlugin;
}
void
ViewModule::loadSelf()
{
cDebug() << Q_FUNC_INFO << "for module" << name();
if ( m_loader )
{
ViewPlugin *vp = qobject_cast< ViewPlugin* >( m_loader->instance() );
if ( vp )
{
ViewManager::instance()->addViewPlugin( vp );
m_loaded = true;
}
}
}
void
ViewModule::initFrom( const YAML::Node& node )
{
Module::initFrom( node );
QDir directory( location() );
QString load;
if ( node[ "load" ] )
{
load = QString::fromStdString( node[ "load" ].as<std::string>() );
load = directory.absoluteFilePath( load );
}
// If a load path is not specified, we look for a plugin to load in the directory.
if ( load.isEmpty() || !QLibrary::isLibrary( load ) )
{
QStringList ls = directory.entryList( QStringList() = { "*.so" } );
if ( !ls.isEmpty() )
{
foreach ( QString entry, ls )
{
entry = directory.absoluteFilePath( entry );
if ( QLibrary::isLibrary( entry ) )
{
load = entry;
break;
}
}
}
}
m_loader = new QPluginLoader( load );
}
ViewModule::ViewModule()
: Module()
, m_loader( nullptr )
{
}
ViewModule::~ViewModule()
{
delete m_loader;
}
} // namespace Calamares

View File

@ -0,0 +1,50 @@
/* === This file is part of Calamares - <http://github.com/calamares> ===
*
* Copyright 2014, Teo Mrnjavac <teo@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_VIEWMODULE_H
#define CALAMARES_VIEWMODULE_H
#include "UiDllMacro.h"
#include "Module.h"
class QPluginLoader;
namespace Calamares {
class UIDLLEXPORT ViewModule : public Module
{
public:
Type type() override;
Interface interface() override;
void loadSelf() override;
protected:
void initFrom( const YAML::Node &node ) override;
private:
friend class Module; //so only the superclass can instantiate
explicit ViewModule();
virtual ~ViewModule();
QPluginLoader *m_loader;
};
} // namespace Calamares
#endif // CALAMARES_VIEWMODULE_H

View File

@ -35,6 +35,8 @@ public:
explicit ViewPlugin( QObject *parent = 0 ); explicit ViewPlugin( QObject *parent = 0 );
virtual ~ViewPlugin() {} virtual ~ViewPlugin() {}
virtual QString prettyName() = 0;
signals: signals:
void done(); void done();

View File

@ -18,7 +18,15 @@
#include "GreetingViewPlugin.h" #include "GreetingViewPlugin.h"
GreetingViewPlugin::GreetingViewPlugin( QObject *parent ) GreetingViewPlugin::GreetingViewPlugin( QObject *parent )
: Calamares::ViewPlugin( parent ) : Calamares::ViewPlugin( parent )
{ {
} }
QString
GreetingViewPlugin::prettyName()
{
return tr( "Welcome" );
}

View File

@ -30,10 +30,11 @@ class PLUGINDLLEXPORT GreetingViewPlugin : public Calamares::ViewPlugin
Q_PLUGIN_METADATA( IID "calamares.ViewPlugin/1.0" ) Q_PLUGIN_METADATA( IID "calamares.ViewPlugin/1.0" )
//FILE "module.json" ) //FILE "module.json" )
Q_INTERFACES( Calamares::ViewPlugin ) Q_INTERFACES( Calamares::ViewPlugin )
public: public:
explicit GreetingViewPlugin(QObject *parent = 0); explicit GreetingViewPlugin(QObject *parent = 0);
QString prettyName() override;
}; };
#endif // GREETINGPAGEPLUGIN_H #endif // GREETINGPAGEPLUGIN_H