Merge branch 'master' of https://github.com/calamares/calamares into development

This commit is contained in:
Philip Müller 2020-01-25 13:47:26 +01:00
commit 9c59e98f89
36 changed files with 410 additions and 266 deletions

View File

@ -18,6 +18,11 @@ This release contains contributions from (alphabetically by first name):
`branding.desc` specifies *center* or *free* placement.
## Modules ##
- All modules can now set a new key in `module.desc` called *noconfig*.
If this key is set to `true` (the default is `false), no configuration
file is searched-for or loaded, and no warning is printed if the
configuration is missing. This should tidy up some unnecessary warnings
on startup. #1302 #1301
- The *license* module has seen a significant change to its looks.
Actions are now labeled more clearly, and the URL (or filename)
for each license is displayed.

View File

@ -38,6 +38,7 @@
# [RESOURCES resource-file]
# [REQUIRES module-name...]
# [NO_INSTALL]
# [NO_CONFIG]
# [SHARED_LIB]
# [EMERGENCY]
# )
@ -71,7 +72,7 @@ include( CMakeColors )
function( calamares_add_plugin )
# parse arguments ( name needs to be saved before passing ARGN into the macro )
set( NAME ${ARGV0} )
set( options NO_INSTALL SHARED_LIB EMERGENCY )
set( options NO_CONFIG NO_INSTALL SHARED_LIB EMERGENCY )
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES )
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS REQUIRES )
cmake_parse_arguments( PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
@ -90,6 +91,9 @@ function( calamares_add_plugin )
message( " ${Green}LINK_PRIVATE_LIBRARIES:${ColorReset} ${PLUGIN_LINK_PRIVATE_LIBRARIES}" )
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
if( PLUGIN_CONFIG_FILES )
if( PLUGIN_NO_CONFIG )
message( FATAL_ERROR "${Red}NO_CONFIG${ColorReset} is set, with configuration ${Red}${PLUGIN_CONFIG_FILES}${ColorReset}" )
endif()
set( _destination "(unknown)" )
if ( INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL )
set( _destination "${PLUGIN_DATA_DESTINATION}" )
@ -100,6 +104,10 @@ function( calamares_add_plugin )
set( _destination "[Skipping installation]" )
endif()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${_destination}" )
else()
if( NOT PLUGIN_NO_CONFIG )
message( " ${Red}NO_CONFIG${ColorReset} should be set." )
endif()
endif()
if( PLUGIN_RESOURCES )
message( " ${Green}RESOURCES:${ColorReset} ${PLUGIN_RESOURCES}" )
@ -170,6 +178,9 @@ function( calamares_add_plugin )
if ( PLUGIN_EMERGENCY )
file( APPEND ${_file} "emergency: true\n" )
endif()
if ( PLUGIN_NO_CONFIG )
file( APPEND ${_file} "noconfig: true\n" )
endif()
endif()
if ( NOT PLUGIN_NO_INSTALL )

View File

@ -8,7 +8,7 @@
#
AS=$( which astyle )
for _cf in clang-format-7 clang-format-8 clang-format70 clang-format80
for _cf in clang-format-7 clang-format-8 clang-format70 clang-format80 clang-format
do
# Not an error if this particular clang-format isn't found
CF=$( which $_cf || true )

View File

@ -113,7 +113,13 @@ DebugWindow::DebugWindow()
} );
// Modules page
QStringListModel* modulesModel = new QStringListModel( ModuleManager::instance()->loadedInstanceKeys() );
QStringList modulesKeys;
for ( const auto& m : ModuleManager::instance()->loadedInstanceKeys() )
{
modulesKeys << m.toString();
}
QStringListModel* modulesModel = new QStringListModel( modulesKeys );
m_ui->modulesListView->setModel( modulesModel );
m_ui->modulesListView->setSelectionMode( QAbstractItemView::SingleSelection );

View File

@ -67,7 +67,7 @@ ViewStepItem::data( int role ) const
toolTip.append( QString( "<br/>Status:\t%1" ).arg( m_step->prettyStatus() ) );
toolTip.append(
QString( "<br/>Source:\t%1" )
.arg( m_step->moduleInstanceKey().isEmpty() ? "built-in" : m_step->moduleInstanceKey() ) );
.arg( m_step->moduleInstanceKey().isValid() ? m_step->moduleInstanceKey().toString() : QStringLiteral("built-in") ) );
}
else
{

View File

@ -37,6 +37,9 @@ set( libSources
locale/TimeZone.cpp
locale/TranslatableConfiguration.cpp
# Modules
modulesystem/InstanceKey.cpp
# Network service
network/Manager.cpp

View File

@ -32,7 +32,7 @@ CppJob::~CppJob() {}
void
CppJob::setModuleInstanceKey( const QString& instanceKey )
CppJob::setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey )
{
m_instanceKey = instanceKey;
}

View File

@ -2,6 +2,7 @@
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2016, Kevin Kofler <kevin.kofler@chello.at>
* Copyright 2020, Adriaan de Groor <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
@ -20,12 +21,14 @@
#ifndef CALAMARES_CPPJOB_H
#define CALAMARES_CPPJOB_H
#include <QObject>
#include <QVariant>
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/InstanceKey.h"
#include <QObject>
#include <QVariant>
namespace Calamares
{
@ -36,13 +39,13 @@ public:
explicit CppJob( QObject* parent = nullptr );
virtual ~CppJob();
void setModuleInstanceKey( const QString& instanceKey );
QString moduleInstanceKey() const { return m_instanceKey; }
void setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey );
Calamares::ModuleSystem::InstanceKey moduleInstanceKey() const { return m_instanceKey; }
virtual void setConfigurationMap( const QVariantMap& configurationMap );
protected:
QString m_instanceKey;
Calamares::ModuleSystem::InstanceKey m_instanceKey;
};
} // namespace Calamares

View File

@ -0,0 +1,36 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2020, 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 MODULESYSTEM_DESCRIPTOR_H
#define MODULESYSTEM_DESCRIPTOR_H
#include <QVariantMap>
namespace Calamares
{
namespace ModuleSystem
{
/* While this isn't a useful *using* right now, the intention is
* to create a more strongly-typed Module Descriptor that carries
* only the necessary information and no variants.
*/
using Descriptor = QVariantMap;
} // namespace ModuleSystem
} // namespace Calamares
#endif

View File

@ -0,0 +1,46 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2018-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 "InstanceKey.h"
namespace Calamares
{
namespace ModuleSystem
{
InstanceKey
InstanceKey::fromString( const QString& s )
{
QStringList moduleEntrySplit = s.split( '@' );
if ( moduleEntrySplit.length() < 1 || moduleEntrySplit.length() > 2 )
{
return InstanceKey();
}
// For length 1, first == last
return InstanceKey( moduleEntrySplit.first(), moduleEntrySplit.last() );
}
QDebug&
operator<<( QDebug& s, const Calamares::ModuleSystem::InstanceKey& i )
{
return s << i.toString();
}
} // namespace ModuleSystem
} // namespace Calamares

View File

@ -19,15 +19,9 @@
#ifndef MODULESYSTEM_INSTANCEKEY_H
#define MODULESYSTEM_INSTANCEKEY_H
#include <QList>
#include <QDebug>
#include <QPair>
#include <QString>
#include <QStringList>
namespace Logger
{
class CLog;
}
namespace Calamares
{
@ -77,16 +71,7 @@ public:
QString id() const { return second; }
/// @brief Create instance key from stringified version
static InstanceKey fromString( const QString& s )
{
QStringList moduleEntrySplit = s.split( '@' );
if ( moduleEntrySplit.length() < 1 || moduleEntrySplit.length() > 2 )
{
return InstanceKey();
}
// For length 1, first == last
return InstanceKey( moduleEntrySplit.first(), moduleEntrySplit.last() );
}
static InstanceKey fromString( const QString& s );
QString toString() const
{
@ -109,6 +94,9 @@ private:
}
};
QDebug&
operator <<( QDebug& s, const Calamares::ModuleSystem::InstanceKey& i );
} // namespace ModuleSystem
} // namespace Calamares

View File

@ -86,7 +86,6 @@ CppJobModule::jobs() const
void
CppJobModule::initFrom( const QVariantMap& moduleDescriptor )
{
Module::initFrom( moduleDescriptor );
QDir directory( location() );
QString load;
if ( !moduleDescriptor.value( "load" ).toString().isEmpty() )

View File

@ -27,6 +27,7 @@
#include "utils/Dirs.h"
#include "utils/Logger.h"
#include "utils/NamedEnum.h"
#include "utils/Yaml.h"
#ifdef WITH_PYTHON
@ -48,10 +49,25 @@ static const char EMERGENCY[] = "emergency";
namespace Calamares
{
Module::Module()
: m_loaded( false )
{
}
Module::~Module() {}
void
Module::initFrom( const Calamares::ModuleSystem::Descriptor& moduleDescriptor, const QString& id )
{
m_key = ModuleSystem::InstanceKey( moduleDescriptor.value( "name" ).toString(), id );
if ( moduleDescriptor.contains( EMERGENCY ) )
{
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
}
}
Module*
Module::fromDescriptor( const QVariantMap& moduleDescriptor,
Module::fromDescriptor( const Calamares::ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory )
@ -131,17 +147,25 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
return nullptr;
}
m->m_instanceId = instanceId;
m->initFrom( moduleDescriptor, instanceId );
if ( !m->m_key.isValid() )
{
cError() << "Module" << instanceId << "invalid ID";
return nullptr;
}
m->initFrom( moduleDescriptor );
try
if ( !configFileName.isEmpty() )
{
m->loadConfigurationFile( configFileName );
}
catch ( YAML::Exception& e )
{
cError() << "YAML parser error " << e.what();
return nullptr;
try
{
m->loadConfigurationFile( configFileName );
}
catch ( YAML::Exception& e )
{
cError() << "YAML parser error " << e.what();
return nullptr;
}
}
return m.release();
}
@ -190,7 +214,7 @@ moduleConfigurationCandidates( bool assumeBuildDir, const QString& moduleName, c
void Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Exception
{
QStringList configCandidates
= moduleConfigurationCandidates( Settings::instance()->debugMode(), m_name, configFileName );
= moduleConfigurationCandidates( Settings::instance()->debugMode(), name(), configFileName );
for ( const QString& path : configCandidates )
{
QFile configFile( path );
@ -219,67 +243,59 @@ void Module::loadConfigurationFile( const QString& configFileName ) //throws YA
return;
}
}
cDebug() << "No config file for" << m_name << "found anywhere at" << Logger::DebugList( configCandidates );
cDebug() << "No config file for" << name() << "found anywhere at" << Logger::DebugList( configCandidates );
}
QString
Module::name() const
static const NamedEnumTable< Module::Type >&
typeNames()
{
return m_name;
using Type = Module::Type;
// *INDENT-OFF*
// clang-format off
static const NamedEnumTable< Type > table{
{ QStringLiteral( "job" ), Type::Job },
{ QStringLiteral( "view" ), Type::View },
{ QStringLiteral( "viewmodule" ), Type::View },
{ QStringLiteral( "jobmodule" ), Type::Job }
};
// *INDENT-ON*
// clang-format on
return table;
}
QString
Module::instanceId() const
{
return m_instanceId;
}
QString
Module::instanceKey() const
{
return QString( "%1@%2" ).arg( m_name ).arg( m_instanceId );
}
QString
Module::location() const
{
return m_directory;
}
QString
Module::typeString() const
{
switch ( type() )
{
case Type::Job:
return "Job Module";
case Type::View:
return "View Module";
}
return QString();
bool ok = false;
QString v = typeNames().find( type(), ok );
return ok ? v : QString();
}
static const NamedEnumTable< Module::Interface >&
interfaceNames()
{
using Interface = Module::Interface;
// *INDENT-OFF*
// clang-format off
static const NamedEnumTable< Interface > table {
{ QStringLiteral("process"), Interface::Process },
{ QStringLiteral("qtplugin"), Interface::QtPlugin },
{ QStringLiteral("python"), Interface::Python },
{ QStringLiteral("pythonqt"), Interface::PythonQt }
};
// *INDENT-ON*
// clang-format on
return table;
}
QString
Module::interfaceString() const
{
switch ( interface() )
{
case Interface::Process:
return "External process";
case Interface::Python:
return "Python (Boost.Python)";
case Interface::PythonQt:
return "Python (experimental)";
case Interface::QtPlugin:
return "Qt Plugin";
}
return QString();
bool ok = false;
QString v = interfaceNames().find( interface(), ok );
return ok ? v : QString();
}
@ -290,22 +306,6 @@ Module::configurationMap()
}
Module::Module()
: m_loaded( false )
{
}
void
Module::initFrom( const QVariantMap& moduleDescriptor )
{
m_name = moduleDescriptor.value( "name" ).toString();
if ( moduleDescriptor.contains( EMERGENCY ) )
{
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
}
}
RequirementsList
Module::checkRequirements()
{

View File

@ -24,6 +24,9 @@
#include "Requirement.h"
#include "UiDllMacro.h"
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include <QStringList>
#include <QVariant>
@ -73,7 +76,7 @@ public:
* @param moduleDirectory the path to the directory with this module's files.
* @return a pointer to an object of a subtype of Module.
*/
static Module* fromDescriptor( const QVariantMap& moduleDescriptor,
static Module* fromDescriptor( const ModuleSystem::Descriptor& moduleDescriptor,
const QString& instanceId,
const QString& configFileName,
const QString& moduleDirectory );
@ -83,13 +86,13 @@ public:
* @brief name returns the name of this module.
* @return a string with this module's name.
*/
virtual QString name() const final;
QString name() const { return m_key.module(); }
/**
* @brief instanceId returns the instance id of this module.
* @return a string with this module's instance id.
*/
virtual QString instanceId() const final;
QString instanceId() const { return m_key.id(); }
/**
* @brief instanceKey returns the instance key of this module.
@ -98,49 +101,13 @@ public:
* For instance, "partition\@partition" (default configuration) or
* "locale\@someconfig" (custom configuration)
*/
virtual QString instanceKey() const final;
ModuleSystem::InstanceKey instanceKey() const { return m_key; }
/**
* @brief location returns the full path of this module's directory.
* @return the path.
*/
virtual QString location() const final;
/**
* @brief type returns the Type of this module object.
* @return the type enum value.
*/
virtual Type type() const = 0;
/**
* @brief typeString returns a user-visible string for the module's type.
* @return the type string.
*/
virtual QString typeString() const;
/**
* @brief interface the Interface used by this module.
* @return the interface enum value.
*/
virtual Interface interface() const = 0;
/**
* @brief interface returns a user-visible string for the module's interface.
* @return the interface string.
*/
virtual QString interfaceString() const;
/**
* @brief isLoaded reports on the loaded status of a module.
* @return true if the module's loading phase has finished, otherwise false.
*/
bool isLoaded() const { return m_loaded; }
/**
* @brief loadSelf initialized the module.
* Subclasses must reimplement this depending on the module type and interface.
*/
virtual void loadSelf() = 0;
QString location() const { return m_directory; }
/**
* @brief Is this an emergency module?
@ -154,10 +121,10 @@ public:
bool isEmergency() const { return m_emergency; }
/**
* @brief jobs returns any jobs exposed by this module.
* @return a list of jobs (can be empty).
* @brief isLoaded reports on the loaded status of a module.
* @return true if the module's loading phase has finished, otherwise false.
*/
virtual JobList jobs() const = 0;
bool isLoaded() const { return m_loaded; }
/**
* @brief configurationMap returns the contents of the configuration file for
@ -166,6 +133,42 @@ public:
*/
QVariantMap configurationMap();
/**
* @brief typeString returns a user-visible string for the module's type.
* @return the type string.
*/
QString typeString() const;
/**
* @brief interface returns a user-visible string for the module's interface.
* @return the interface string.
*/
QString interfaceString() const;
/**
* @brief loadSelf initialized the module.
* Subclasses must reimplement this depending on the module type and interface.
*/
virtual void loadSelf() = 0;
/**
* @brief jobs returns any jobs exposed by this module.
* @return a list of jobs (can be empty).
*/
virtual JobList jobs() const = 0;
/**
* @brief type returns the Type of this module object.
* @return the type enum value.
*/
virtual Type type() const = 0;
/**
* @brief interface the Interface used by this module.
* @return the interface enum value.
*/
virtual Interface interface() const = 0;
/**
* @brief Check the requirements of this module.
*/
@ -173,7 +176,12 @@ public:
protected:
explicit Module();
virtual void initFrom( const QVariantMap& moduleDescriptor );
/// @brief For subclasses to read their part of the descriptor
virtual void initFrom( const QVariantMap& moduleDescriptor ) = 0;
/// @brief Generic part of descriptor reading (and instance id)
void initFrom( const QVariantMap& moduleDescriptor, const QString& id );
QVariantMap m_configurationMap;
bool m_loaded = false;
@ -183,9 +191,8 @@ protected:
private:
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
QString m_name;
QString m_directory;
QString m_instanceId;
ModuleSystem::InstanceKey m_key;
};
} // namespace Calamares

View File

@ -95,16 +95,12 @@ ModuleManager::doInit()
QFileInfo descriptorFileInfo( currentDir.absoluteFilePath( QLatin1String( "module.desc" ) ) );
if ( !descriptorFileInfo.exists() )
{
cDebug() << bad_descriptor
<< descriptorFileInfo.absoluteFilePath()
<< "(missing)";
cDebug() << bad_descriptor << descriptorFileInfo.absoluteFilePath() << "(missing)";
continue;
}
if ( !descriptorFileInfo.isReadable() )
{
cDebug() << bad_descriptor
<< descriptorFileInfo.absoluteFilePath()
<< "(unreadable)";
cDebug() << bad_descriptor << descriptorFileInfo.absoluteFilePath() << "(unreadable)";
continue;
}
@ -131,28 +127,22 @@ ModuleManager::doInit()
cDebug() << "ModuleManager module search path does not exist:" << path;
}
}
// At this point m_availableDescriptorsByModuleName is filled with
// At this point m_availableDescriptorsByModuleName is filled with
// the modules that were found in the search paths.
cDebug() << "Found"
<< m_availableDescriptorsByModuleName.count() << "modules"
<< m_moduleDirectoriesByModuleName.count() << "names";
cDebug() << "Found" << m_availableDescriptorsByModuleName.count() << "modules"
<< m_moduleDirectoriesByModuleName.count() << "names";
emit initDone();
}
QStringList
QList< ModuleSystem::InstanceKey >
ModuleManager::loadedInstanceKeys()
{
QStringList l;
for ( const auto& m : m_loadedModulesByInstanceKey.keys() )
{
l << m.toString();
}
return l;
return m_loadedModulesByInstanceKey.keys();
}
QVariantMap
Calamares::ModuleSystem::Descriptor
ModuleManager::moduleDescriptor( const QString& name )
{
return m_availableDescriptorsByModuleName.value( name );
@ -184,19 +174,54 @@ findCustomInstance( const Settings::InstanceDescriptionList& customInstances, co
return -1;
}
/** @brief Returns the config file name for the fiven @p instanceKey
*
* Custom instances have custom config files, non-custom ones
* have a <modulename>.conf file. Returns an empty QString on
* errors.
*/
static QString
getConfigFileName( const Settings::InstanceDescriptionList& customInstances,
const ModuleSystem::InstanceKey& instanceKey,
const ModuleSystem::Descriptor& descriptor )
{
if ( instanceKey.isCustom() )
{
int found = findCustomInstance( customInstances, instanceKey );
if ( found < 0 )
{
// This should already have been checked and failed the module already
return QString();
}
return customInstances[ found ].value( "config" );
}
else
{
if ( descriptor.value( "noconfig", false ).toBool() )
{
// Explicitly set to no-configuration. This doesn't apply
// to custom instances (above) since the only reason to
// **have** a custom instance is to specify a different
// config file for more than one module.
return QString();
}
return QString( "%1.conf" ).arg( instanceKey.module() );
}
}
void
ModuleManager::loadModules()
{
if (checkDependencies())
if ( checkDependencies() )
{
cWarning() << "Some installed modules have unmet dependencies.";
}
Settings::InstanceDescriptionList customInstances = Settings::instance()->customModuleInstances();
QStringList failedModules;
const auto modulesSequence
= Settings::instance()->modulesSequence() ;
const auto modulesSequence = Settings::instance()->modulesSequence();
for ( const auto& modulePhase : modulesSequence )
{
ModuleSystem::Action currentAction = modulePhase.first;
@ -210,38 +235,29 @@ ModuleManager::loadModules()
failedModules.append( moduleEntry );
continue;
}
if ( !m_availableDescriptorsByModuleName.contains( instanceKey.module() )
|| m_availableDescriptorsByModuleName.value( instanceKey.module() ).isEmpty() )
{
cError() << "Module" << instanceKey.toString() << "not found in module search paths."
<< Logger::DebugList( m_paths );
failedModules.append( instanceKey.toString() );
continue;
}
QString configFileName;
if ( instanceKey.isCustom() )
{
int found = findCustomInstance( customInstances, instanceKey );
if ( found > -1 )
{
configFileName = customInstances[ found ].value( "config" );
}
else //ought to be a custom instance, but cannot find instance entry
if ( found < 0 )
{
cError() << "Custom instance" << moduleEntry << "not found in custom instances section.";
failedModules.append( moduleEntry );
continue;
}
}
else
ModuleSystem::Descriptor descriptor
= m_availableDescriptorsByModuleName.value( instanceKey.module(), ModuleSystem::Descriptor() );
if ( descriptor.isEmpty() )
{
configFileName = QString( "%1.conf" ).arg( instanceKey.module() );
cError() << "Module" << instanceKey.toString() << "not found in module search paths."
<< Logger::DebugList( m_paths );
failedModules.append( instanceKey.toString() );
continue;
}
QString configFileName = getConfigFileName( customInstances, instanceKey, descriptor );
// So now we can assume that the module entry is at least valid,
// that we have a descriptor on hand (and therefore that the
// module exists), and that the instance is either default or
@ -250,26 +266,33 @@ ModuleManager::loadModules()
// exists and is valid, but that's the only thing that could fail
// from this point on. -- Teo 8/2015
Module* thisModule = m_loadedModulesByInstanceKey.value( instanceKey, nullptr );
if ( thisModule && !thisModule->isLoaded() )
if ( thisModule )
{
cError() << "Module" << instanceKey.toString() << "exists but not loaded.";
failedModules.append( instanceKey.toString() );
continue;
}
if ( thisModule && thisModule->isLoaded() )
{
cDebug() << "Module" << instanceKey.toString() << "already loaded.";
if ( thisModule->isLoaded() )
{
// It's been listed before, don't bother loading again.
// This can happen for a module listed twice (e.g. with custom instances)
cDebug() << "Module" << instanceKey.toString() << "already loaded.";
}
else
{
// An attempt was made, earlier, and that failed.
// This can happen for a module listed twice (e.g. with custom instances)
cError() << "Module" << instanceKey.toString() << "exists but not loaded.";
failedModules.append( instanceKey.toString() );
continue;
}
}
else
{
thisModule = Module::fromDescriptor( m_availableDescriptorsByModuleName.value( instanceKey.module() ),
instanceKey.id(),
configFileName,
m_moduleDirectoriesByModuleName.value( instanceKey.module() ) );
thisModule = Module::fromDescriptor( descriptor,
instanceKey.id(),
configFileName,
m_moduleDirectoriesByModuleName.value( instanceKey.module() ) );
if ( !thisModule )
{
cError() << "Module" << instanceKey.toString() << "cannot be created from descriptor" << configFileName;
cError() << "Module" << instanceKey.toString() << "cannot be created from descriptor"
<< configFileName;
failedModules.append( instanceKey.toString() );
continue;
}

View File

@ -20,6 +20,7 @@
#ifndef MODULELOADER_H
#define MODULELOADER_H
#include "modulesystem/Descriptor.h"
#include "modulesystem/InstanceKey.h"
#include "Requirement.h"
@ -62,14 +63,14 @@ public:
* modules.
* @return a QStringList with the instance keys.
*/
QStringList loadedInstanceKeys();
QList< ModuleSystem::InstanceKey > loadedInstanceKeys();
/**
* @brief moduleDescriptor returns the module descriptor structure for a given module.
* @param name the name of the module for which to return the module descriptor.
* @return the module descriptor, as a variant map already parsed from YAML.
*/
QVariantMap moduleDescriptor( const QString& name );
ModuleSystem::Descriptor moduleDescriptor( const QString& name );
/**
* @brief moduleInstance returns a Module object for a given instance key.
@ -126,7 +127,7 @@ private:
*/
bool checkModuleDependencies( const Module& );
QMap< QString, QVariantMap > m_availableDescriptorsByModuleName;
QMap< QString, ModuleSystem::Descriptor > m_availableDescriptorsByModuleName;
QMap< QString, QString > m_moduleDirectoriesByModuleName;
QMap< ModuleSystem::InstanceKey, Module* > m_loadedModulesByInstanceKey;
const QStringList m_paths;

View File

@ -63,7 +63,6 @@ ProcessJobModule::jobs() const
void
ProcessJobModule::initFrom( const QVariantMap& moduleDescriptor )
{
Module::initFrom( moduleDescriptor );
QDir directory( location() );
m_workingPath = directory.absolutePath();

View File

@ -64,7 +64,6 @@ PythonJobModule::jobs() const
void
PythonJobModule::initFrom( const QVariantMap& moduleDescriptor )
{
Module::initFrom( moduleDescriptor );
QDir directory( location() );
m_workingPath = directory.absolutePath();

View File

@ -174,7 +174,6 @@ PythonQtViewModule::jobs() const
void
PythonQtViewModule::initFrom( const QVariantMap& moduleDescriptor )
{
Module::initFrom( moduleDescriptor );
QDir directory( location() );
m_workingPath = directory.absolutePath();

View File

@ -91,7 +91,6 @@ ViewModule::jobs() const
void
ViewModule::initFrom( const QVariantMap& moduleDescriptor )
{
Module::initFrom( moduleDescriptor );
QDir directory( location() );
QString load;
if ( !moduleDescriptor.value( "load" ).toString().isEmpty() )

View File

@ -66,7 +66,7 @@ ViewStep::back()
void
ViewStep::setModuleInstanceKey( const QString& instanceKey )
ViewStep::setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey )
{
m_instanceKey = instanceKey;
}

View File

@ -1,7 +1,7 @@
/* === This file is part of Calamares - <https://github.com/calamares> ===
*
* Copyright 2014-2015, Teo Mrnjavac <teo@kde.org>
* Copyright 2017, Adriaan de Groot <groot@kde.org>
* Copyright 2017, 2020, 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
@ -20,15 +20,16 @@
#ifndef VIEWSTEP_H
#define VIEWSTEP_H
#include <QList>
#include <QObject>
#include <QSize>
#include "Job.h"
#include "UiDllMacro.h"
#include "modulesystem/InstanceKey.h"
#include "modulesystem/Requirement.h"
#include <QList>
#include <QObject>
#include <QSize>
namespace Calamares
{
@ -36,9 +37,9 @@ namespace Calamares
* @brief The ViewStep class is the base class for all view modules.
* A view module is a Calamares module which has at least one UI page (exposed as
* ViewStep::widget), and can optionally create Calamares jobs at runtime.
* As of early 2017, a view module can be implemented by deriving from ViewStep
* in C++ (as a Qt Plugin) or in Python with the PythonQt interface (which also
* mimics the ViewStep class).
* As of early 2020, a view module can be implemented by deriving from ViewStep
* in C++ (as a Qt Plugin or a Qml ViewStep) or in Python with the PythonQt interface
* (which also mimics the ViewStep class).
*
* A ViewStep can describe itself in human-readable format for the SummaryPage
* (which shows all of the things which have been collected to be done in the
@ -129,8 +130,8 @@ public:
*/
virtual JobList jobs() const = 0;
void setModuleInstanceKey( const QString& instanceKey );
QString moduleInstanceKey() const { return m_instanceKey; }
void setModuleInstanceKey( const Calamares::ModuleSystem::InstanceKey& instanceKey );
Calamares::ModuleSystem::InstanceKey moduleInstanceKey() const { return m_instanceKey; }
virtual void setConfigurationMap( const QVariantMap& configurationMap );
@ -154,7 +155,7 @@ signals:
void enlarge( QSize enlarge ) const;
protected:
QString m_instanceKey;
Calamares::ModuleSystem::InstanceKey m_instanceKey;
};
using ViewStepList = QList< ViewStep* >;

View File

@ -54,10 +54,12 @@ Module descriptors for Python and PythonQt modules **must** have the following k
- *script* (the name of the Python script to load, nearly always `main.py`)
Module descriptors **may** have the following keys:
- *requiredModules* (a list of modules which are required for this module
to operate properly)
- *emergency* (a boolean value, set to true to mark the module
as an emergency module)
- *noconfig* (a boolean value, set to true to state that the module
has no configuration file; defaults to false)
- *requiredModules* (a list of modules which are required for this module
to operate properly)
### Required Modules
@ -96,6 +98,12 @@ named `<modulename>.conf`. If such a file is present in the
module's directory, it can be shipped as a *default* configuration file.
This only happens if the CMake-time option `INSTALL_CONFIG` is on.
Modules that have *noconfig* set to true will not attempt to
read a configuration file, and will not warn that one is missing;
conversely if *noconfig* is set to false (or is missing, since
the default value is false) if there is no configuration file,
a warning is printed during Calamares start-up.
The sample configuration files may work and may be suitable for
your distribution, but no guarantee is given about their stability
beyond syntactic correctness.
@ -122,7 +130,8 @@ to provide jobs.
To add a Qt plugin module, put it in a subdirectory and make sure it has
a `CMakeLists.txt` with a `calamares_add_plugin` call. It will be picked
up automatically by our CMake magic. The `module.desc` file is optional.
up automatically by our CMake magic. The `module.desc` file is not recommended:
nearly all cases can be described in CMake.

View File

@ -6,4 +6,5 @@ calamares_add_plugin( dracutlukscfg
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
NO_CONFIG
)

View File

@ -24,8 +24,8 @@
#include <QTextStream>
#include "CalamaresVersion.h"
#include "JobQueue.h"
#include "GlobalStorage.h"
#include "JobQueue.h"
#include "utils/Logger.h"
@ -33,30 +33,30 @@
const QLatin1String DracutLuksCfgJob::CONFIG_FILE( "/etc/dracut.conf.d/calamares-luks.conf" );
// static
const char *DracutLuksCfgJob::CONFIG_FILE_HEADER =
"# Configuration file automatically written by the Calamares system installer\n"
"# (This file is written once at install time and should be safe to edit.)\n"
"# Enables support for LUKS full disk encryption with single sign on from GRUB.\n"
"\n";
const char* DracutLuksCfgJob::CONFIG_FILE_HEADER
= "# Configuration file automatically written by the Calamares system installer\n"
"# (This file is written once at install time and should be safe to edit.)\n"
"# Enables support for LUKS full disk encryption with single sign on from GRUB.\n"
"\n";
// static
const char *DracutLuksCfgJob::CONFIG_FILE_CRYPTTAB_KEYFILE_LINE =
"# force installing /etc/crypttab even if hostonly=\"no\", install the keyfile\n"
"install_items+=\" /etc/crypttab /crypto_keyfile.bin \"\n";
const char* DracutLuksCfgJob::CONFIG_FILE_CRYPTTAB_KEYFILE_LINE
= "# force installing /etc/crypttab even if hostonly=\"no\", install the keyfile\n"
"install_items+=\" /etc/crypttab /crypto_keyfile.bin \"\n";
// static
const char *DracutLuksCfgJob::CONFIG_FILE_CRYPTTAB_LINE =
"# force installing /etc/crypttab even if hostonly=\"no\"\n"
"install_items+=\" /etc/crypttab \"\n";
const char* DracutLuksCfgJob::CONFIG_FILE_CRYPTTAB_LINE = "# force installing /etc/crypttab even if hostonly=\"no\"\n"
"install_items+=\" /etc/crypttab \"\n";
// static
const QLatin1String DracutLuksCfgJob::CONFIG_FILE_SWAPLINE( "# enable automatic resume from swap\nadd_device+=\" /dev/disk/by-uuid/%1 \"\n" );
const QLatin1String DracutLuksCfgJob::CONFIG_FILE_SWAPLINE(
"# enable automatic resume from swap\nadd_device+=\" /dev/disk/by-uuid/%1 \"\n" );
// static
QString
DracutLuksCfgJob::rootMountPoint()
{
Calamares::GlobalStorage *globalStorage = Calamares::JobQueue::instance()->globalStorage();
Calamares::GlobalStorage* globalStorage = Calamares::JobQueue::instance()->globalStorage();
return globalStorage->value( QStringLiteral( "rootMountPoint" ) ).toString();
}
@ -64,7 +64,7 @@ DracutLuksCfgJob::rootMountPoint()
QVariantList
DracutLuksCfgJob::partitions()
{
Calamares::GlobalStorage *globalStorage = Calamares::JobQueue::instance()->globalStorage();
Calamares::GlobalStorage* globalStorage = Calamares::JobQueue::instance()->globalStorage();
return globalStorage->value( QStringLiteral( "partitions" ) ).toList();
}
@ -73,12 +73,14 @@ bool
DracutLuksCfgJob::isRootEncrypted()
{
const QVariantList partitions = DracutLuksCfgJob::partitions();
for ( const QVariant &partition : partitions )
for ( const QVariant& partition : partitions )
{
QVariantMap partitionMap = partition.toMap();
QString mountPoint = partitionMap.value( QStringLiteral( "mountPoint" ) ).toString();
if ( mountPoint == QStringLiteral( "/" ) )
{
return partitionMap.contains( QStringLiteral( "luksMapperName" ) );
}
}
return false;
}
@ -88,12 +90,14 @@ bool
DracutLuksCfgJob::hasUnencryptedSeparateBoot()
{
const QVariantList partitions = DracutLuksCfgJob::partitions();
for ( const QVariant &partition : partitions )
for ( const QVariant& partition : partitions )
{
QVariantMap partitionMap = partition.toMap();
QString mountPoint = partitionMap.value( QStringLiteral( "mountPoint" ) ).toString();
if ( mountPoint == QStringLiteral( "/boot" ) )
{
return !partitionMap.contains( QStringLiteral( "luksMapperName" ) );
}
}
return false;
}
@ -103,12 +107,14 @@ QString
DracutLuksCfgJob::swapOuterUuid()
{
const QVariantList partitions = DracutLuksCfgJob::partitions();
for ( const QVariant &partition : partitions )
for ( const QVariant& partition : partitions )
{
QVariantMap partitionMap = partition.toMap();
QString fsType = partitionMap.value( QStringLiteral( "fs" ) ).toString();
if ( fsType == QStringLiteral( "linuxswap" ) && partitionMap.contains( QStringLiteral( "luksMapperName" ) ) )
{
return partitionMap.value( QStringLiteral( "luksUuid" ) ).toString();
}
}
return QString();
}
@ -119,18 +125,20 @@ DracutLuksCfgJob::DracutLuksCfgJob( QObject* parent )
}
DracutLuksCfgJob::~DracutLuksCfgJob()
{
}
DracutLuksCfgJob::~DracutLuksCfgJob() {}
QString
DracutLuksCfgJob::prettyName() const
{
if ( isRootEncrypted() )
{
return tr( "Write LUKS configuration for Dracut to %1" ).arg( CONFIG_FILE );
}
else
{
return tr( "Skip writing LUKS configuration for Dracut: \"/\" partition is not encrypted" );
}
}
@ -143,26 +151,28 @@ DracutLuksCfgJob::exec()
cDebug() << "[DRACUTLUKSCFG]: Writing" << realConfigFilePath;
QDir( QStringLiteral( "/" ) ).mkpath( QFileInfo( realConfigFilePath ).absolutePath() );
QFile configFile( realConfigFilePath );
if ( ! configFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
if ( !configFile.open( QIODevice::WriteOnly | QIODevice::Text ) )
{
cDebug() << "[DRACUTLUKSCFG]: Failed to open" << realConfigFilePath;
return Calamares::JobResult::error( tr( "Failed to open %1" ).arg( realConfigFilePath ) );
}
QTextStream outStream( &configFile );
outStream << CONFIG_FILE_HEADER
<< ( hasUnencryptedSeparateBoot() ? CONFIG_FILE_CRYPTTAB_LINE
: CONFIG_FILE_CRYPTTAB_KEYFILE_LINE );
<< ( hasUnencryptedSeparateBoot() ? CONFIG_FILE_CRYPTTAB_LINE : CONFIG_FILE_CRYPTTAB_KEYFILE_LINE );
const QString swapOuterUuid = DracutLuksCfgJob::swapOuterUuid();
if ( ! swapOuterUuid.isEmpty() )
if ( !swapOuterUuid.isEmpty() )
{
cDebug() << "[DRACUTLUKSCFG]: Swap outer UUID" << swapOuterUuid;
outStream << QString(CONFIG_FILE_SWAPLINE).arg( swapOuterUuid ).toLatin1();
outStream << QString( CONFIG_FILE_SWAPLINE ).arg( swapOuterUuid ).toLatin1();
}
cDebug() << "[DRACUTLUKSCFG]: Wrote config to" << realConfigFilePath;
} else
}
else
{
cDebug() << "[DRACUTLUKSCFG]: / not encrypted, skipping";
}
return Calamares::JobResult::ok();
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( DracutLuksCfgJobFactory, registerPlugin<DracutLuksCfgJob>(); )
CALAMARES_PLUGIN_FACTORY_DEFINITION( DracutLuksCfgJobFactory, registerPlugin< DracutLuksCfgJob >(); )

View File

@ -43,9 +43,9 @@ public:
private:
static const QLatin1String CONFIG_FILE;
static const char *CONFIG_FILE_HEADER;
static const char *CONFIG_FILE_CRYPTTAB_KEYFILE_LINE;
static const char *CONFIG_FILE_CRYPTTAB_LINE;
static const char* CONFIG_FILE_HEADER;
static const char* CONFIG_FILE_CRYPTTAB_KEYFILE_LINE;
static const char* CONFIG_FILE_CRYPTTAB_LINE;
static const QLatin1String CONFIG_FILE_SWAPLINE;
static QString rootMountPoint();
@ -57,4 +57,4 @@ private:
CALAMARES_PLUGIN_FACTORY_DECLARATION( DracutLuksCfgJobFactory )
#endif // DRACUTLUKSCFGJOB_H
#endif // DRACUTLUKSCFGJOB_H

View File

@ -25,6 +25,7 @@ calamares_add_plugin( hostinfo
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
NO_CONFIG
)
if ( KF5CoreAddons_FOUND AND KF5CoreAddons_VERSION VERSION_GREATER_EQUAL 5.58 )

View File

@ -165,9 +165,4 @@ HostInfoJob::exec()
return Calamares::JobResult::ok();
}
void
HostInfoJob::setConfigurationMap( const QVariantMap& )
{
}
CALAMARES_PLUGIN_FACTORY_DEFINITION( HostInfoJobFactory, registerPlugin< HostInfoJob >(); )

View File

@ -57,8 +57,6 @@ public:
QString prettyName() const override;
Calamares::JobResult exec() override;
void setConfigurationMap( const QVariantMap& configurationMap ) override;
};
CALAMARES_PLUGIN_FACTORY_DECLARATION( HostInfoJobFactory )

View File

@ -4,3 +4,4 @@ name: "hwclock"
interface: "python"
requires: []
script: "main.py"
noconfig: true

View File

@ -3,3 +3,4 @@ type: "job"
name: "initramfscfg"
interface: "python"
script: "main.py"
noconfig: true

View File

@ -6,3 +6,4 @@ type: "job"
name: "localecfg"
interface: "python"
script: "main.py"
noconfig: true

View File

@ -6,4 +6,5 @@ calamares_add_plugin( luksbootkeyfile
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
NO_CONFIG
)

View File

@ -4,3 +4,4 @@ name: "networkcfg"
interface: "python"
requires: []
script: "main.py"
noconfig: true

View File

@ -192,8 +192,7 @@ PackageChooserViewStep::setConfigurationMap( const QVariantMap& configurationMap
if ( m_id.isEmpty() )
{
// Not set, so use the instance id
// TODO: use a stronger type than QString for structured IDs
m_id = moduleInstanceKey().split( '@' ).last();
m_id = moduleInstanceKey().id();
}
bool labels_ok = false;

View File

@ -9,4 +9,5 @@ calamares_add_plugin( summary
LINK_PRIVATE_LIBRARIES
calamaresui
SHARED_LIB
NO_CONFIG
)