Merge branch 'improve-moduleloading'
This is code that was written as part of the fix-pythonqt branch, but which isn't really PythonQt-related at all. That branch will be abandoned soon, since it wasn't sufficiently well-thought-out enough at the beginning.
This commit is contained in:
commit
1ad2d365f5
@ -141,7 +141,7 @@ endif()
|
||||
|
||||
option( INSTALL_CONFIG "Install configuration files" ON )
|
||||
option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON )
|
||||
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." OFF )
|
||||
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." ON )
|
||||
option( WITH_KF5Crash "Enable crash reporting with KCrash." ON )
|
||||
option( BUILD_TESTING "Build the testing tree." ON )
|
||||
|
||||
|
@ -68,3 +68,9 @@ install( FILES ${CMAKE_SOURCE_DIR}/data/images/squid.svg
|
||||
RENAME calamares.svg
|
||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/hicolor/scalable/apps
|
||||
)
|
||||
|
||||
if( BUILD_TESTING )
|
||||
add_executable( loadmodule testmain.cpp )
|
||||
target_link_libraries( loadmodule ${CALAMARES_LIBRARIES} Qt5::Core Qt5::Widgets calamaresui )
|
||||
# Don't install, it's just for enable_testing
|
||||
endif()
|
||||
|
192
src/calamares/testmain.cpp
Normal file
192
src/calamares/testmain.cpp
Normal file
@ -0,0 +1,192 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2018, 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/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This executable loads and runs a Calamares Python module
|
||||
* within a C++ application, in order to test the different
|
||||
* bindings.
|
||||
*/
|
||||
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/YamlUtils.h"
|
||||
#include "modulesystem/Module.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "Job.h"
|
||||
#include "JobQueue.h"
|
||||
|
||||
#include <QCommandLineOption>
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct ModuleConfig : public QPair< QString, QString >
|
||||
{
|
||||
ModuleConfig( const QString& a, const QString& b ) : QPair< QString, QString >(a, b) { }
|
||||
ModuleConfig() : QPair< QString, QString >( QString(), QString() ) { }
|
||||
|
||||
QString moduleName() const { return first; }
|
||||
QString configFile() const { return second; }
|
||||
} ;
|
||||
|
||||
static ModuleConfig
|
||||
handle_args( QCoreApplication& a )
|
||||
{
|
||||
QCommandLineOption debugLevelOption( QStringLiteral("D"),
|
||||
"Verbose output for debugging purposes (0-8).", "level" );
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.setApplicationDescription( "Calamares module tester" );
|
||||
parser.addHelpOption();
|
||||
parser.addVersionOption();
|
||||
|
||||
parser.addOption( debugLevelOption );
|
||||
parser.addPositionalArgument( "module", "Path or name of module to run." );
|
||||
|
||||
parser.process( a );
|
||||
|
||||
if ( parser.isSet( debugLevelOption ) )
|
||||
{
|
||||
bool ok = true;
|
||||
int l = parser.value( debugLevelOption ).toInt( &ok );
|
||||
unsigned int dlevel = 0;
|
||||
if ( !ok || ( l < 0 ) )
|
||||
dlevel = Logger::LOGVERBOSE;
|
||||
else
|
||||
dlevel = l;
|
||||
Logger::setupLogLevel( dlevel );
|
||||
}
|
||||
|
||||
const QStringList args = parser.positionalArguments();
|
||||
if ( args.isEmpty() )
|
||||
{
|
||||
cError() << "Missing <module> path.\n";
|
||||
parser.showHelp();
|
||||
return ModuleConfig(); // NOTREACHED
|
||||
}
|
||||
if ( args.size() > 2 )
|
||||
{
|
||||
cError() << "More than one <module> path.\n";
|
||||
parser.showHelp();
|
||||
return ModuleConfig(); // NOTREACHED
|
||||
}
|
||||
|
||||
return ModuleConfig( args.first(), args.size() == 2 ? args.at(1) : QString() );
|
||||
}
|
||||
|
||||
|
||||
static Calamares::Module*
|
||||
load_module( const ModuleConfig& moduleConfig )
|
||||
{
|
||||
QString moduleName = moduleConfig.moduleName();
|
||||
QFileInfo fi;
|
||||
|
||||
bool ok = false;
|
||||
QVariantMap descriptor;
|
||||
|
||||
for ( const QString& prefix : QStringList{ "./", "src/modules/", "modules/" } )
|
||||
{
|
||||
// Could be a complete path, eg. src/modules/dummycpp/module.desc
|
||||
fi = QFileInfo( prefix + moduleName );
|
||||
if ( fi.exists() && fi.isFile() )
|
||||
descriptor = CalamaresUtils::loadYaml( fi, &ok );
|
||||
if ( ok )
|
||||
break;
|
||||
|
||||
// Could be a path without module.desc
|
||||
fi = QFileInfo( prefix + moduleName );
|
||||
if ( fi.exists() && fi.isDir() )
|
||||
{
|
||||
fi = QFileInfo( prefix + moduleName + "/module.desc" );
|
||||
if ( fi.exists() && fi.isFile() )
|
||||
descriptor = CalamaresUtils::loadYaml( fi, &ok );
|
||||
if ( ok ) break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
cWarning() << "No suitable module descriptor found.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString name = descriptor.value( "name" ).toString();
|
||||
if ( name.isEmpty() )
|
||||
{
|
||||
cWarning() << "No name found in module descriptor" << fi.absoluteFilePath();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QString moduleDirectory = fi.absolutePath();
|
||||
QString configFile(
|
||||
moduleConfig.configFile().isEmpty()
|
||||
? moduleDirectory + '/' + name + ".conf"
|
||||
: moduleConfig.configFile() );
|
||||
|
||||
Calamares::Module* module = Calamares::Module::fromDescriptor(
|
||||
descriptor, name, configFile, moduleDirectory );
|
||||
|
||||
return module;
|
||||
}
|
||||
|
||||
int
|
||||
main( int argc, char* argv[] )
|
||||
{
|
||||
QCoreApplication a( argc, argv );
|
||||
|
||||
ModuleConfig module = handle_args( a );
|
||||
if ( module.moduleName().isEmpty() )
|
||||
return 1;
|
||||
|
||||
std::unique_ptr< Calamares::Settings > settings_p( new Calamares::Settings( QString(), true ) );
|
||||
std::unique_ptr< Calamares::JobQueue > jobqueue_p( new Calamares::JobQueue( nullptr ) );
|
||||
|
||||
cDebug() << "Calamares test module-loader" << module.moduleName();
|
||||
Calamares::Module* m = load_module( module );
|
||||
if ( !m )
|
||||
{
|
||||
cError() << "Could not load module" << module.moduleName();
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( !m->isLoaded() )
|
||||
m->loadSelf();
|
||||
|
||||
if ( !m->isLoaded() )
|
||||
{
|
||||
cError() << "Module" << module.moduleName() << "could not be loaded.";
|
||||
return 1;
|
||||
}
|
||||
|
||||
cDebug() << "Module" << m->name() << m->typeString() << m->interfaceString();
|
||||
|
||||
Calamares::JobList jobList = m->jobs();
|
||||
unsigned int count = 1;
|
||||
for ( const auto& p : jobList )
|
||||
{
|
||||
cDebug() << count << p->prettyName();
|
||||
Calamares::JobResult r = p->exec();
|
||||
if ( !r )
|
||||
cDebug() << count << ".. failed" << r;
|
||||
++count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -156,12 +156,12 @@ Settings::Settings( const QString& settingsFilePath,
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
{
|
||||
cWarning() << "YAML parser error " << e.what() << "in" << file.fileName();
|
||||
CalamaresUtils::explainYamlException( e, ba, file.fileName() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Cannot read " << file.fileName();
|
||||
cWarning() << "Cannot read settings file" << file.fileName();
|
||||
}
|
||||
|
||||
s_instance = this;
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2017, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2017-2018, 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
|
||||
@ -23,6 +23,8 @@
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QRegExp>
|
||||
|
||||
void
|
||||
@ -112,6 +114,19 @@ void
|
||||
explainYamlException( const YAML::Exception& e, const QByteArray& yamlData, const char *label )
|
||||
{
|
||||
cWarning() << "YAML error " << e.what() << "in" << label << '.';
|
||||
explainYamlException( e, yamlData );
|
||||
}
|
||||
|
||||
void
|
||||
explainYamlException( const YAML::Exception& e, const QByteArray& yamlData, const QString& label )
|
||||
{
|
||||
cWarning() << "YAML error " << e.what() << "in" << label << '.';
|
||||
explainYamlException( e, yamlData );
|
||||
}
|
||||
|
||||
void
|
||||
explainYamlException( const YAML::Exception& e, const QByteArray& yamlData )
|
||||
{
|
||||
if ( ( e.mark.line >= 0 ) && ( e.mark.column >= 0 ) )
|
||||
{
|
||||
// Try to show the line where it happened.
|
||||
@ -146,4 +161,46 @@ explainYamlException( const YAML::Exception& e, const QByteArray& yamlData, cons
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap
|
||||
loadYaml(const QFileInfo& fi, bool* ok)
|
||||
{
|
||||
return loadYaml( fi.absoluteFilePath(), ok );
|
||||
}
|
||||
|
||||
QVariantMap
|
||||
loadYaml(const QString& filename, bool* ok)
|
||||
{
|
||||
if ( ok )
|
||||
*ok = false;
|
||||
|
||||
QFile descriptorFile( filename );
|
||||
QVariant moduleDescriptor;
|
||||
if ( descriptorFile.exists() && descriptorFile.open( QFile::ReadOnly | QFile::Text ) )
|
||||
{
|
||||
QByteArray ba = descriptorFile.readAll();
|
||||
try
|
||||
{
|
||||
YAML::Node doc = YAML::Load( ba.constData() );
|
||||
moduleDescriptor = CalamaresUtils::yamlToVariant( doc );
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
{
|
||||
explainYamlException( e, ba, filename );
|
||||
return QVariantMap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( moduleDescriptor.isValid() &&
|
||||
!moduleDescriptor.isNull() &&
|
||||
moduleDescriptor.type() == QVariant::Map )
|
||||
{
|
||||
if ( ok )
|
||||
*ok = true;
|
||||
return moduleDescriptor.toMap();
|
||||
}
|
||||
|
||||
return QVariantMap();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://github.com/calamares> ===
|
||||
*
|
||||
* Copyright 2014, Teo Mrnjavac <teo@kde.org>
|
||||
* Copyright 2017, Adriaan de Groot <groot@kde.org>
|
||||
* Copyright 2017-2018, 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
|
||||
@ -24,6 +24,7 @@
|
||||
#include <QVariant>
|
||||
|
||||
class QByteArray;
|
||||
class QFileInfo;
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
@ -35,6 +36,15 @@ void operator>>( const YAML::Node& node, QStringList& v );
|
||||
|
||||
namespace CalamaresUtils
|
||||
{
|
||||
/**
|
||||
* Loads a given @p filename and returns the YAML data
|
||||
* as a QVariantMap. If filename doesn't exist, or is
|
||||
* malformed in some way, returns an empty map and sets
|
||||
* @p *ok to false. Otherwise sets @p *ok to true.
|
||||
*/
|
||||
QVariantMap loadYaml( const QString& filename, bool* ok = nullptr );
|
||||
/** Convenience overload. */
|
||||
QVariantMap loadYaml( const QFileInfo&, bool* ok = nullptr );
|
||||
|
||||
QVariant yamlToVariant( const YAML::Node& node );
|
||||
QVariant yamlScalarToVariant( const YAML::Node& scalarNode );
|
||||
@ -47,6 +57,8 @@ QVariant yamlMapToVariant( const YAML::Node& mapNode );
|
||||
* Uses @p label when labeling the data source (e.g. "netinstall data")
|
||||
*/
|
||||
void explainYamlException( const YAML::Exception& e, const QByteArray& data, const char *label );
|
||||
void explainYamlException( const YAML::Exception& e, const QByteArray& data, const QString& label );
|
||||
void explainYamlException( const YAML::Exception& e, const QByteArray& data );
|
||||
|
||||
} //ns
|
||||
|
||||
|
@ -179,7 +179,7 @@ Branding::Branding( const QString& brandingFilePath,
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
{
|
||||
cWarning() << "YAML parser error " << e.what() << "in" << file.fileName();
|
||||
CalamaresUtils::explainYamlException( e, ba, file.fileName() );
|
||||
}
|
||||
|
||||
QDir translationsDir( componentDir.filePath( "lang" ) );
|
||||
@ -192,7 +192,7 @@ Branding::Branding( const QString& brandingFilePath,
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Cannot read " << file.fileName();
|
||||
cWarning() << "Cannot read branding file" << file.fileName();
|
||||
}
|
||||
|
||||
s_instance = this;
|
||||
|
@ -86,7 +86,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
||||
#ifdef WITH_PYTHONQT
|
||||
m = new PythonQtViewModule();
|
||||
#else
|
||||
cError() << "PythonQt modules are not supported in this version of Calamares.";
|
||||
cError() << "PythonQt view modules are not supported in this version of Calamares.";
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -118,7 +118,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
||||
|
||||
if ( !m )
|
||||
{
|
||||
cDebug() << "Bad module type (" << typeString
|
||||
cError() << "Bad module type (" << typeString
|
||||
<< ") or interface string (" << intfString
|
||||
<< ") for module " << instanceId;
|
||||
return nullptr;
|
||||
@ -129,8 +129,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
||||
m->m_directory = moduleDir.absolutePath();
|
||||
else
|
||||
{
|
||||
cError() << "Bad module directory" << moduleDirectory
|
||||
<< "for" << instanceId;
|
||||
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
|
||||
delete m;
|
||||
return nullptr;
|
||||
}
|
||||
@ -144,7 +143,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
{
|
||||
cWarning() << "YAML parser error " << e.what();
|
||||
cError() << "YAML parser error " << e.what();
|
||||
delete m;
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -103,41 +103,18 @@ ModuleManager::doInit()
|
||||
continue;
|
||||
}
|
||||
|
||||
QFile descriptorFile( descriptorFileInfo.absoluteFilePath() );
|
||||
QVariant moduleDescriptor;
|
||||
if ( descriptorFile.exists() && descriptorFile.open( QFile::ReadOnly | QFile::Text ) )
|
||||
{
|
||||
QByteArray ba = descriptorFile.readAll();
|
||||
try
|
||||
{
|
||||
YAML::Node doc = YAML::Load( ba.constData() );
|
||||
bool ok = false;
|
||||
QVariantMap moduleDescriptorMap = CalamaresUtils::loadYaml( descriptorFileInfo, &ok );
|
||||
QString moduleName = ok ? moduleDescriptorMap.value( "name" ).toString() : QString();
|
||||
|
||||
moduleDescriptor = CalamaresUtils::yamlToVariant( doc );
|
||||
}
|
||||
catch ( YAML::Exception& e )
|
||||
if ( ok && ( moduleName == currentDir.dirName() ) &&
|
||||
!m_availableDescriptorsByModuleName.contains( moduleName ) )
|
||||
{
|
||||
cWarning() << "YAML parser error " << e.what();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( moduleDescriptor.isValid() &&
|
||||
!moduleDescriptor.isNull() &&
|
||||
moduleDescriptor.type() == QVariant::Map )
|
||||
{
|
||||
QVariantMap moduleDescriptorMap = moduleDescriptor.toMap();
|
||||
|
||||
if ( moduleDescriptorMap.value( "name" ) == currentDir.dirName() &&
|
||||
!m_availableDescriptorsByModuleName.contains( moduleDescriptorMap.value( "name" ).toString() ) )
|
||||
{
|
||||
m_availableDescriptorsByModuleName.insert( moduleDescriptorMap.value( "name" ).toString(),
|
||||
moduleDescriptorMap );
|
||||
m_moduleDirectoriesByModuleName.insert( moduleDescriptorMap.value( "name" ).toString(),
|
||||
m_availableDescriptorsByModuleName.insert( moduleName, moduleDescriptorMap );
|
||||
m_moduleDirectoriesByModuleName.insert( moduleName,
|
||||
descriptorFileInfo.absoluteDir().absolutePath() );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Cannot cd into module directory "
|
||||
|
@ -143,12 +143,12 @@ PythonQtViewModule::loadSelf()
|
||||
return;
|
||||
}
|
||||
|
||||
QString calamares_module_annotation =
|
||||
static const QLatin1Literal calamares_module_annotation(
|
||||
"_calamares_module_typename = ''\n"
|
||||
"def calamares_module(viewmodule_type):\n"
|
||||
" global _calamares_module_typename\n"
|
||||
" _calamares_module_typename = viewmodule_type.__name__\n"
|
||||
" return viewmodule_type\n";
|
||||
" return viewmodule_type\n");
|
||||
|
||||
// Load in the decorator
|
||||
PythonQt::self()->evalScript( cxt, calamares_module_annotation );
|
||||
|
Loading…
Reference in New Issue
Block a user