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
This commit is contained in:
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,16 +138,21 @@ 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()
|
||||
|
||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
||||
DESTINATION ${PLUGIN_DESTINATION} )
|
||||
if ( NOT PLUGIN_NO_INSTALL )
|
||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
||||
DESTINATION ${PLUGIN_DESTINATION} )
|
||||
|
||||
if ( INSTALL_CONFIG )
|
||||
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
|
||||
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
|
||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE}
|
||||
DESTINATION ${PLUGIN_DATA_DESTINATION} )
|
||||
endforeach()
|
||||
if ( INSTALL_CONFIG )
|
||||
foreach( PLUGIN_CONFIG_FILE ${PLUGIN_CONFIG_FILES} )
|
||||
configure_file( ${PLUGIN_CONFIG_FILE} ${PLUGIN_CONFIG_FILE} COPYONLY )
|
||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_CONFIG_FILE}
|
||||
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,22 +51,36 @@ 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();
|
||||
}
|
||||
++m_jobIndex;
|
||||
if ( !anyFailed )
|
||||
++m_jobIndex;
|
||||
}
|
||||
emitProgress();
|
||||
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…
Reference in New Issue
Block a user