Merge branch 'emergency-modules'

Introduce the notion of emergency modules and emergency jobs.
Initial use will probably center around the preservefiles module,
and possibly umount.

FIXES #928
main
Adriaan de Groot 7 years ago
commit 374a9bdca6

@ -38,6 +38,7 @@
# RESOURCES resource-file
# [NO_INSTALL]
# [SHARED_LIB]
# [EMERGENCY]
# )
include( CMakeParseArguments )
@ -47,7 +48,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 )
set( options NO_INSTALL SHARED_LIB EMERGENCY )
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES )
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS )
cmake_parse_arguments( PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
@ -71,7 +72,7 @@ function( calamares_add_plugin )
# message( " ${Green}NO_INSTALL:${ColorReset} ${PLUGIN_NO_INSTALL}" )
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
if( PLUGIN_CONFIG_FILES )
if ( INSTALL_CONFIG )
if ( INSTALL_CONFIG AND NOT PLUGIN_NO_INSTALL )
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${PLUGIN_DATA_DESTINATION}" )
else()
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => [Skipping installation]" )
@ -92,7 +93,7 @@ function( calamares_add_plugin )
set( target_type "SHARED" )
endif()
list( APPEND calamares_add_library_args
set( calamares_add_library_args
"${target}"
"EXPORT_MACRO" "${PLUGIN_EXPORT_MACRO}"
"TARGET_TYPE" "${target_type}"
@ -115,9 +116,14 @@ function( calamares_add_plugin )
list( APPEND calamares_add_library_args "COMPILE_DEFINITIONS" ${PLUGIN_COMPILE_DEFINITIONS} )
endif()
list( APPEND calamares_add_library_args "NO_VERSION" )
if ( PLUGIN_NO_INSTALL )
list( APPEND calamares_add_library_args "NO_INSTALL" )
endif()
list( APPEND calamares_add_library_args "INSTALL_BINDIR" "${PLUGIN_DESTINATION}" )
list( APPEND calamares_add_library_args
"NO_VERSION"
"INSTALL_BINDIR" "${PLUGIN_DESTINATION}"
)
if( PLUGIN_RESOURCES )
list( APPEND calamares_add_library_args "RESOURCES" "${PLUGIN_RESOURCES}" )
@ -132,8 +138,12 @@ function( calamares_add_plugin )
set( _type ${PLUGIN_TYPE} )
file( WRITE ${_file} "# AUTO-GENERATED metadata file\n# Syntax is YAML 1.2\n---\n" )
file( APPEND ${_file} "type: \"${_type}\"\nname: \"${PLUGIN_NAME}\"\ninterface: \"qtplugin\"\nload: \"lib${target}.so\"\n" )
if ( PLUGIN_EMERGENCY )
file( APPEND ${_file} "emergency: true\n" )
endif()
endif()
if ( NOT PLUGIN_NO_INSTALL )
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
DESTINATION ${PLUGIN_DESTINATION} )
@ -144,4 +154,5 @@ function( calamares_add_plugin )
DESTINATION ${PLUGIN_DATA_DESTINATION} )
endforeach()
endif()
endif()
endfunction()

@ -66,8 +66,15 @@ public:
virtual QString prettyDescription() const;
virtual QString prettyStatusMessage() const;
virtual JobResult exec() = 0;
bool isEmergency() const { return m_emergency; }
void setEmergency( bool e ) { m_emergency = e; }
signals:
void progress( qreal percent );
private:
bool m_emergency = false;
};
} // namespace Calamares

@ -51,21 +51,35 @@ public:
void run() override
{
bool anyFailed = false;
QString message;
QString details;
m_jobIndex = 0;
for( auto job : m_jobs )
{
if ( anyFailed && !job->isEmergency() )
{
cDebug() << "Skipping non-emergency job" << job->prettyName();
continue;
}
emitProgress();
cDebug() << "Starting job" << job->prettyName();
cDebug() << "Starting" << ( anyFailed ? "EMERGENCY JOB" : "job" ) << job->prettyName();
connect( job.data(), &Job::progress, this, &JobThread::emitProgress );
JobResult result = job->exec();
if ( !result )
if ( !anyFailed && !result )
{
emitFailed( result.message(), result.details() );
emitFinished();
return;
anyFailed = true;
message = result.message();
details = result.details();
}
if ( !anyFailed )
++m_jobIndex;
}
if ( anyFailed )
emitFailed( message, details );
else
emitProgress();
emitFinished();
}

@ -21,6 +21,7 @@
#include <ExecutionViewStep.h>
#include "Branding.h"
#include "Job.h"
#include "JobQueue.h"
#include "modulesystem/Module.h"
#include "modulesystem/ModuleManager.h"
@ -142,7 +143,15 @@ ExecutionViewStep::onActivate()
Calamares::Module* module = Calamares::ModuleManager::instance()
->moduleInstance( instanceKey );
if ( module )
queue->enqueue( module->jobs() );
{
auto jl = module->jobs();
if ( module->isEmergency() )
{
for( auto& j : jl )
j->setEmergency( true );
}
queue->enqueue( jl );
}
}
queue->start();

@ -52,6 +52,8 @@ name: "foo" #the module name. must be unique and same as the parent di
interface: "qtplugin" #can be: qtplugin, python, process, ...
*/
static const char EMERGENCY[] = "emergency";
namespace Calamares
{
@ -64,7 +66,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
const QString& configFileName,
const QString& moduleDirectory )
{
Module* m = nullptr;
std::unique_ptr<Module> m;
QString typeString = moduleDescriptor.value( "type" ).toString();
QString intfString = moduleDescriptor.value( "interface" ).toString();
@ -79,12 +81,12 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
{
if ( intfString == "qtplugin" )
{
m = new ViewModule();
m.reset( new ViewModule() );
}
else if ( intfString == "pythonqt" )
{
#ifdef WITH_PYTHONQT
m = new PythonQtViewModule();
m.reset( new PythonQtViewModule() );
#else
cError() << "PythonQt view modules are not supported in this version of Calamares.";
#endif
@ -96,16 +98,16 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
{
if ( intfString == "qtplugin" )
{
m = new CppJobModule();
m.reset( new CppJobModule() );
}
else if ( intfString == "process" )
{
m = new ProcessJobModule();
m.reset( new ProcessJobModule() );
}
else if ( intfString == "python" )
{
#ifdef WITH_PYTHON
m = new PythonJobModule();
m.reset( new PythonJobModule() );
#else
cError() << "Python modules are not supported in this version of Calamares.";
#endif
@ -130,7 +132,6 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
else
{
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
delete m;
return nullptr;
}
@ -144,10 +145,9 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
catch ( YAML::Exception& e )
{
cError() << "YAML parser error " << e.what();
delete m;
return nullptr;
}
return m;
return m.release();
}
@ -200,6 +200,9 @@ Module::loadConfigurationFile( const QString& configFileName ) //throws YAML::Ex
}
m_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap();
m_emergency = m_maybe_emergency
&& m_configurationMap.contains( EMERGENCY )
&& m_configurationMap[ EMERGENCY ].toBool();
return;
}
else
@ -276,13 +279,6 @@ Module::interfaceString() const
}
bool
Module::isLoaded() const
{
return m_loaded;
}
QVariantMap
Module::configurationMap()
{
@ -299,6 +295,11 @@ void
Module::initFrom( const QVariantMap& moduleDescriptor )
{
m_name = moduleDescriptor.value( "name" ).toString();
if ( moduleDescriptor.contains( EMERGENCY ) )
{
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
}
}
} //ns

@ -147,7 +147,7 @@ public:
* @brief isLoaded reports on the loaded status of a module.
* @return true if the module's loading phase has finished, otherwise false.
*/
virtual bool isLoaded() const;
bool isLoaded() const { return m_loaded; }
/**
* @brief loadSelf initialized the module.
@ -155,6 +155,17 @@ public:
*/
virtual void loadSelf() = 0;
/**
* @brief Is this an emergency module?
*
* An emergency module is run even if an error occurs
* which would terminate Calamares earlier in the same
* *exec* block. Emergency modules in later exec blocks
* are not run (in the common case where there is only
* one exec block, this doesn't really matter).
*/
bool isEmergency() const { return m_emergency; }
/**
* @brief jobs returns any jobs exposed by this module.
* @return a list of jobs (can be empty).
@ -171,11 +182,15 @@ public:
protected:
explicit Module();
virtual void initFrom( const QVariantMap& moduleDescriptor );
bool m_loaded;
QVariantMap m_configurationMap;
bool m_loaded = false;
bool m_emergency = false; // Based on module and local config
bool m_maybe_emergency = false; // Based on the module.desc
private:
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
QString m_name;
QStringList m_requiredModules;
QString m_directory;

@ -43,15 +43,21 @@ module's name, type, interface and possibly other properties. The name
of the module as defined in `module.desc` must be the same as the name
of the module's directory.
Module descriptors must have the following keys:
Module descriptors **must** have the following keys:
- *name* (an identifier; must be the same as the directory name)
- *type* ("job" or "view")
- *interface* (see below for the different interfaces; generally we
refer to the kinds of modules by their interface)
Module descriptors **may** have the following keys:
- *required* **unimplemented** (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)
## Module-specific configuration
A Calamares module *may* read a module configuration file,
A Calamares module **may** read a module configuration file,
named `<modulename>.conf`. If such a file is present in the
module's directory, it is shipped as a *default* configuration file.
The module configuration file, if it exists, is a YAML 1.2 document
@ -125,3 +131,23 @@ while the module type must be "job" or "jobmodule".
The key *command* should have a string as value, which is passed to the
shell -- remember to quote it properly.
## Emergency Modules
Only C++ modules and job modules may be emergency modules. If, during an
*exec* step in the sequence, a module fails, installation as a whole fails
and the install is aborted. If there are emergency modules in the **same**
exec block, those will be executed before the installation is aborted.
Non-emergency modules are not executed.
If an emergency-module fails while processing emergency-modules for
another failed module, that failure is ignored and emergency-module
processing continues.
Use the EMERGENCY keyword in the CMake description of a C++ module
to generate a suitable `module.desc`.
A module that is marked as an emergency module in its module.desc
must **also** set the *emergency* key to *true* in its configuration file.
If it does not, the module is not considered to be an emergency module
after all (this is so that you can have modules that have several
instances, only some of which are actually needed for emergencies.

@ -8,4 +8,5 @@ calamares_add_plugin( preservefiles
LINK_PRIVATE_LIBRARIES
calamares
SHARED_LIB
EMERGENCY
)

@ -1,5 +0,0 @@
---
type: "job"
name: "preservefiles"
interface: "qtplugin"
load: "libcalamares_job_preservefiles.so"
Loading…
Cancel
Save