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
|
# RESOURCES resource-file
|
||||||
# [NO_INSTALL]
|
# [NO_INSTALL]
|
||||||
# [SHARED_LIB]
|
# [SHARED_LIB]
|
||||||
|
# [EMERGENCY]
|
||||||
# )
|
# )
|
||||||
|
|
||||||
include( CMakeParseArguments )
|
include( CMakeParseArguments )
|
||||||
@ -47,7 +48,7 @@ include( CMakeColors )
|
|||||||
function( calamares_add_plugin )
|
function( calamares_add_plugin )
|
||||||
# parse arguments ( name needs to be saved before passing ARGN into the macro )
|
# parse arguments ( name needs to be saved before passing ARGN into the macro )
|
||||||
set( NAME ${ARGV0} )
|
set( NAME ${ARGV0} )
|
||||||
set( options NO_INSTALL SHARED_LIB )
|
set( options NO_INSTALL SHARED_LIB EMERGENCY )
|
||||||
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES )
|
set( oneValueArgs NAME TYPE EXPORT_MACRO RESOURCES )
|
||||||
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS )
|
set( multiValueArgs SOURCES UI LINK_LIBRARIES LINK_PRIVATE_LIBRARIES COMPILE_DEFINITIONS )
|
||||||
cmake_parse_arguments( PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
|
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}NO_INSTALL:${ColorReset} ${PLUGIN_NO_INSTALL}" )
|
||||||
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
|
message( " ${Green}PLUGIN_DESTINATION:${ColorReset} ${PLUGIN_DESTINATION}" )
|
||||||
if( PLUGIN_CONFIG_FILES )
|
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}" )
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => ${PLUGIN_DATA_DESTINATION}" )
|
||||||
else()
|
else()
|
||||||
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => [Skipping installation]" )
|
message( " ${Green}CONFIGURATION_FILES:${ColorReset} ${PLUGIN_CONFIG_FILES} => [Skipping installation]" )
|
||||||
@ -92,7 +93,7 @@ function( calamares_add_plugin )
|
|||||||
set( target_type "SHARED" )
|
set( target_type "SHARED" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
list( APPEND calamares_add_library_args
|
set( calamares_add_library_args
|
||||||
"${target}"
|
"${target}"
|
||||||
"EXPORT_MACRO" "${PLUGIN_EXPORT_MACRO}"
|
"EXPORT_MACRO" "${PLUGIN_EXPORT_MACRO}"
|
||||||
"TARGET_TYPE" "${target_type}"
|
"TARGET_TYPE" "${target_type}"
|
||||||
@ -115,9 +116,14 @@ function( calamares_add_plugin )
|
|||||||
list( APPEND calamares_add_library_args "COMPILE_DEFINITIONS" ${PLUGIN_COMPILE_DEFINITIONS} )
|
list( APPEND calamares_add_library_args "COMPILE_DEFINITIONS" ${PLUGIN_COMPILE_DEFINITIONS} )
|
||||||
endif()
|
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 )
|
if( PLUGIN_RESOURCES )
|
||||||
list( APPEND calamares_add_library_args "RESOURCES" "${PLUGIN_RESOURCES}" )
|
list( APPEND calamares_add_library_args "RESOURCES" "${PLUGIN_RESOURCES}" )
|
||||||
@ -132,8 +138,12 @@ function( calamares_add_plugin )
|
|||||||
set( _type ${PLUGIN_TYPE} )
|
set( _type ${PLUGIN_TYPE} )
|
||||||
file( WRITE ${_file} "# AUTO-GENERATED metadata file\n# Syntax is YAML 1.2\n---\n" )
|
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" )
|
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()
|
endif()
|
||||||
|
|
||||||
|
if ( NOT PLUGIN_NO_INSTALL )
|
||||||
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${PLUGIN_DESC_FILE}
|
||||||
DESTINATION ${PLUGIN_DESTINATION} )
|
DESTINATION ${PLUGIN_DESTINATION} )
|
||||||
|
|
||||||
@ -144,4 +154,5 @@ function( calamares_add_plugin )
|
|||||||
DESTINATION ${PLUGIN_DATA_DESTINATION} )
|
DESTINATION ${PLUGIN_DATA_DESTINATION} )
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
@ -66,8 +66,15 @@ public:
|
|||||||
virtual QString prettyDescription() const;
|
virtual QString prettyDescription() const;
|
||||||
virtual QString prettyStatusMessage() const;
|
virtual QString prettyStatusMessage() const;
|
||||||
virtual JobResult exec() = 0;
|
virtual JobResult exec() = 0;
|
||||||
|
|
||||||
|
bool isEmergency() const { return m_emergency; }
|
||||||
|
void setEmergency( bool e ) { m_emergency = e; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void progress( qreal percent );
|
void progress( qreal percent );
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_emergency = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Calamares
|
} // namespace Calamares
|
||||||
|
@ -51,21 +51,35 @@ public:
|
|||||||
|
|
||||||
void run() override
|
void run() override
|
||||||
{
|
{
|
||||||
|
bool anyFailed = false;
|
||||||
|
QString message;
|
||||||
|
QString details;
|
||||||
|
|
||||||
m_jobIndex = 0;
|
m_jobIndex = 0;
|
||||||
for( auto job : m_jobs )
|
for( auto job : m_jobs )
|
||||||
{
|
{
|
||||||
|
if ( anyFailed && !job->isEmergency() )
|
||||||
|
{
|
||||||
|
cDebug() << "Skipping non-emergency job" << job->prettyName();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
emitProgress();
|
emitProgress();
|
||||||
cDebug() << "Starting job" << job->prettyName();
|
cDebug() << "Starting" << ( anyFailed ? "EMERGENCY JOB" : "job" ) << job->prettyName();
|
||||||
connect( job.data(), &Job::progress, this, &JobThread::emitProgress );
|
connect( job.data(), &Job::progress, this, &JobThread::emitProgress );
|
||||||
JobResult result = job->exec();
|
JobResult result = job->exec();
|
||||||
if ( !result )
|
if ( !anyFailed && !result )
|
||||||
{
|
{
|
||||||
emitFailed( result.message(), result.details() );
|
anyFailed = true;
|
||||||
emitFinished();
|
message = result.message();
|
||||||
return;
|
details = result.details();
|
||||||
}
|
}
|
||||||
|
if ( !anyFailed )
|
||||||
++m_jobIndex;
|
++m_jobIndex;
|
||||||
}
|
}
|
||||||
|
if ( anyFailed )
|
||||||
|
emitFailed( message, details );
|
||||||
|
else
|
||||||
emitProgress();
|
emitProgress();
|
||||||
emitFinished();
|
emitFinished();
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <ExecutionViewStep.h>
|
#include <ExecutionViewStep.h>
|
||||||
|
|
||||||
#include "Branding.h"
|
#include "Branding.h"
|
||||||
|
#include "Job.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "modulesystem/Module.h"
|
#include "modulesystem/Module.h"
|
||||||
#include "modulesystem/ModuleManager.h"
|
#include "modulesystem/ModuleManager.h"
|
||||||
@ -142,7 +143,15 @@ ExecutionViewStep::onActivate()
|
|||||||
Calamares::Module* module = Calamares::ModuleManager::instance()
|
Calamares::Module* module = Calamares::ModuleManager::instance()
|
||||||
->moduleInstance( instanceKey );
|
->moduleInstance( instanceKey );
|
||||||
if ( module )
|
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();
|
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, ...
|
interface: "qtplugin" #can be: qtplugin, python, process, ...
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
static const char EMERGENCY[] = "emergency";
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -64,7 +66,7 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
|||||||
const QString& configFileName,
|
const QString& configFileName,
|
||||||
const QString& moduleDirectory )
|
const QString& moduleDirectory )
|
||||||
{
|
{
|
||||||
Module* m = nullptr;
|
std::unique_ptr<Module> m;
|
||||||
|
|
||||||
QString typeString = moduleDescriptor.value( "type" ).toString();
|
QString typeString = moduleDescriptor.value( "type" ).toString();
|
||||||
QString intfString = moduleDescriptor.value( "interface" ).toString();
|
QString intfString = moduleDescriptor.value( "interface" ).toString();
|
||||||
@ -79,12 +81,12 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
|||||||
{
|
{
|
||||||
if ( intfString == "qtplugin" )
|
if ( intfString == "qtplugin" )
|
||||||
{
|
{
|
||||||
m = new ViewModule();
|
m.reset( new ViewModule() );
|
||||||
}
|
}
|
||||||
else if ( intfString == "pythonqt" )
|
else if ( intfString == "pythonqt" )
|
||||||
{
|
{
|
||||||
#ifdef WITH_PYTHONQT
|
#ifdef WITH_PYTHONQT
|
||||||
m = new PythonQtViewModule();
|
m.reset( new PythonQtViewModule() );
|
||||||
#else
|
#else
|
||||||
cError() << "PythonQt view modules are not supported in this version of Calamares.";
|
cError() << "PythonQt view modules are not supported in this version of Calamares.";
|
||||||
#endif
|
#endif
|
||||||
@ -96,16 +98,16 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
|||||||
{
|
{
|
||||||
if ( intfString == "qtplugin" )
|
if ( intfString == "qtplugin" )
|
||||||
{
|
{
|
||||||
m = new CppJobModule();
|
m.reset( new CppJobModule() );
|
||||||
}
|
}
|
||||||
else if ( intfString == "process" )
|
else if ( intfString == "process" )
|
||||||
{
|
{
|
||||||
m = new ProcessJobModule();
|
m.reset( new ProcessJobModule() );
|
||||||
}
|
}
|
||||||
else if ( intfString == "python" )
|
else if ( intfString == "python" )
|
||||||
{
|
{
|
||||||
#ifdef WITH_PYTHON
|
#ifdef WITH_PYTHON
|
||||||
m = new PythonJobModule();
|
m.reset( new PythonJobModule() );
|
||||||
#else
|
#else
|
||||||
cError() << "Python modules are not supported in this version of Calamares.";
|
cError() << "Python modules are not supported in this version of Calamares.";
|
||||||
#endif
|
#endif
|
||||||
@ -130,7 +132,6 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
|
cError() << "Bad module directory" << moduleDirectory << "for" << instanceId;
|
||||||
delete m;
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,10 +145,9 @@ Module::fromDescriptor( const QVariantMap& moduleDescriptor,
|
|||||||
catch ( YAML::Exception& e )
|
catch ( YAML::Exception& e )
|
||||||
{
|
{
|
||||||
cError() << "YAML parser error " << e.what();
|
cError() << "YAML parser error " << e.what();
|
||||||
delete m;
|
|
||||||
return nullptr;
|
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_configurationMap = CalamaresUtils::yamlMapToVariant( doc ).toMap();
|
||||||
|
m_emergency = m_maybe_emergency
|
||||||
|
&& m_configurationMap.contains( EMERGENCY )
|
||||||
|
&& m_configurationMap[ EMERGENCY ].toBool();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -276,13 +279,6 @@ Module::interfaceString() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
|
||||||
Module::isLoaded() const
|
|
||||||
{
|
|
||||||
return m_loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QVariantMap
|
QVariantMap
|
||||||
Module::configurationMap()
|
Module::configurationMap()
|
||||||
{
|
{
|
||||||
@ -299,6 +295,11 @@ void
|
|||||||
Module::initFrom( const QVariantMap& moduleDescriptor )
|
Module::initFrom( const QVariantMap& moduleDescriptor )
|
||||||
{
|
{
|
||||||
m_name = moduleDescriptor.value( "name" ).toString();
|
m_name = moduleDescriptor.value( "name" ).toString();
|
||||||
|
|
||||||
|
if ( moduleDescriptor.contains( EMERGENCY ) )
|
||||||
|
{
|
||||||
|
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} //ns
|
} //ns
|
||||||
|
@ -147,7 +147,7 @@ public:
|
|||||||
* @brief isLoaded reports on the loaded status of a module.
|
* @brief isLoaded reports on the loaded status of a module.
|
||||||
* @return true if the module's loading phase has finished, otherwise false.
|
* @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.
|
* @brief loadSelf initialized the module.
|
||||||
@ -155,6 +155,17 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual void loadSelf() = 0;
|
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.
|
* @brief jobs returns any jobs exposed by this module.
|
||||||
* @return a list of jobs (can be empty).
|
* @return a list of jobs (can be empty).
|
||||||
@ -171,11 +182,15 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
explicit Module();
|
explicit Module();
|
||||||
virtual void initFrom( const QVariantMap& moduleDescriptor );
|
virtual void initFrom( const QVariantMap& moduleDescriptor );
|
||||||
bool m_loaded;
|
|
||||||
QVariantMap m_configurationMap;
|
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:
|
private:
|
||||||
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
|
void loadConfigurationFile( const QString& configFileName ); //throws YAML::Exception
|
||||||
|
|
||||||
QString m_name;
|
QString m_name;
|
||||||
QStringList m_requiredModules;
|
QStringList m_requiredModules;
|
||||||
QString m_directory;
|
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 as defined in `module.desc` must be the same as the name
|
||||||
of the module's directory.
|
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)
|
- *name* (an identifier; must be the same as the directory name)
|
||||||
- *type* ("job" or "view")
|
- *type* ("job" or "view")
|
||||||
- *interface* (see below for the different interfaces; generally we
|
- *interface* (see below for the different interfaces; generally we
|
||||||
refer to the kinds of modules by their interface)
|
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
|
## 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
|
named `<modulename>.conf`. If such a file is present in the
|
||||||
module's directory, it is shipped as a *default* configuration file.
|
module's directory, it is shipped as a *default* configuration file.
|
||||||
The module configuration file, if it exists, is a YAML 1.2 document
|
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
|
The key *command* should have a string as value, which is passed to the
|
||||||
shell -- remember to quote it properly.
|
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
|
LINK_PRIVATE_LIBRARIES
|
||||||
calamares
|
calamares
|
||||||
SHARED_LIB
|
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