From d6cbda5ed72ee8069049c084e6193ac251c97dac Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Mon, 15 Jan 2018 08:57:34 -0500 Subject: [PATCH] [contextualprocess] Implement contextual processes Allow running one or more commands based on the value of a global configuration variable. This could, of course, be done in a Python module with some custom code, but for simple cases this is more straightforward to configure through module instances. Uses the CommandList developed for the ShellProcess module to do the actual work. FIXES #874 --- .../ContextualProcessJob.cpp | 79 ++++++++++++++++++- .../contextualprocess/ContextualProcessJob.h | 12 +-- .../contextualprocess/contextualprocess.conf | 17 ++++ 3 files changed, 100 insertions(+), 8 deletions(-) diff --git a/src/modules/contextualprocess/ContextualProcessJob.cpp b/src/modules/contextualprocess/ContextualProcessJob.cpp index 131a42fca..50a28f417 100644 --- a/src/modules/contextualprocess/ContextualProcessJob.cpp +++ b/src/modules/contextualprocess/ContextualProcessJob.cpp @@ -1,6 +1,6 @@ /* === This file is part of Calamares - === * - * Copyright 2017, Adriaan de Groot + * Copyright 2017-2018, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,8 +26,37 @@ #include "JobQueue.h" #include "GlobalStorage.h" +#include "utils/CalamaresUtils.h" +#include "utils/CommandList.h" #include "utils/Logger.h" +struct ContextualProcessBinding +{ + ContextualProcessBinding( const QString& _n, const QString& _v, CalamaresUtils::CommandList* _c ) + : variable( _n ) + , value( _v ) + , commands( _c ) + { + } + + ~ContextualProcessBinding(); + + int count() const + { + return commands ? commands->count() : 0; + } + + QString variable; + QString value; + CalamaresUtils::CommandList* commands; +} ; + + +ContextualProcessBinding::~ContextualProcessBinding() +{ + delete commands; +} + ContextualProcessJob::ContextualProcessJob( QObject* parent ) : Calamares::CppJob( parent ) { @@ -36,6 +65,7 @@ ContextualProcessJob::ContextualProcessJob( QObject* parent ) ContextualProcessJob::~ContextualProcessJob() { + qDeleteAll( m_commands ); } @@ -49,8 +79,17 @@ ContextualProcessJob::prettyName() const Calamares::JobResult ContextualProcessJob::exec() { - QThread::sleep( 3 ); + Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage(); + for ( const ContextualProcessBinding* binding : m_commands ) + { + if ( gs->contains( binding->variable ) && ( gs->value( binding->variable ).toString() == binding->value ) ) + { + Calamares::JobResult r = binding->commands->run( this ); + if ( !r ) + return r; + } + } return Calamares::JobResult::ok(); } @@ -58,7 +97,41 @@ ContextualProcessJob::exec() void ContextualProcessJob::setConfigurationMap( const QVariantMap& configurationMap ) { - m_configurationMap = configurationMap; + m_dontChroot = CalamaresUtils::getBool( configurationMap, "dontChroot", false ); + + for ( QVariantMap::const_iterator iter = configurationMap.cbegin(); iter != configurationMap.cend(); ++iter ) + { + QString variableName = iter.key(); + if ( variableName.isEmpty() || ( variableName == "dontChroot" ) ) + continue; + + if ( iter.value().type() != QVariant::Map ) + { + cDebug() << "WARNING:" << moduleInstanceKey() << "bad configuration values for" << variableName; + continue; + } + + QVariantMap values = iter.value().toMap(); + for ( QVariantMap::const_iterator valueiter = values.cbegin(); valueiter != values.cend(); ++valueiter ) + { + QString valueString = valueiter.key(); + if ( variableName.isEmpty() ) + { + cDebug() << "WARNING:" << moduleInstanceKey() << "variable" << variableName << "unrecognized value" << valueiter.key(); + continue; + } + + CalamaresUtils::CommandList* commands = new CalamaresUtils::CommandList( valueiter.value(), !m_dontChroot ); + + if ( commands->count() > 0 ) + { + m_commands.append( new ContextualProcessBinding( variableName, valueString, commands ) ); + cDebug() << variableName << '=' << valueString << "will execute" << commands->count() << "commands"; + } + else + delete commands; + } + } } CALAMARES_PLUGIN_FACTORY_DEFINITION( ContextualProcessJobFactory, registerPlugin(); ) diff --git a/src/modules/contextualprocess/ContextualProcessJob.h b/src/modules/contextualprocess/ContextualProcessJob.h index d12dff91d..aea09aa9b 100644 --- a/src/modules/contextualprocess/ContextualProcessJob.h +++ b/src/modules/contextualprocess/ContextualProcessJob.h @@ -1,6 +1,6 @@ /* === This file is part of Calamares - === * - * Copyright 2017, Adriaan de Groot + * Copyright 2017-2018, Adriaan de Groot * * Calamares is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,11 +22,12 @@ #include #include -#include +#include "CppJob.h" +#include "PluginDllMacro.h" -#include +#include "utils/PluginFactory.h" -#include +struct ContextualProcessBinding; class PLUGINDLLEXPORT ContextualProcessJob : public Calamares::CppJob { @@ -43,7 +44,8 @@ public: void setConfigurationMap( const QVariantMap& configurationMap ) override; private: - QVariantMap m_configurationMap; + QList m_commands; + bool m_dontChroot; }; CALAMARES_PLUGIN_FACTORY_DECLARATION( ContextualProcessJobFactory ) diff --git a/src/modules/contextualprocess/contextualprocess.conf b/src/modules/contextualprocess/contextualprocess.conf index 832613080..4e9ddea7f 100644 --- a/src/modules/contextualprocess/contextualprocess.conf +++ b/src/modules/contextualprocess/contextualprocess.conf @@ -9,11 +9,28 @@ # If the variable has that particular value, the corresponding # value is executed as a shell command in the target environment. # +# You can check for an empty value with "". +# +# The special configuration key *dontChroot* specifies whether +# the commands are run in the target system (default, value *false*), +# or in the host system. This key is not used for comparisons +# with global configuration values. +# # If a command starts with "-" (a single minus sign), then the # return value of the command following the - is ignored; otherwise, # a failing command will abort the installation. This is much like # make's use of - in a command. +# +# Global configuration variables are not checked in a deterministic +# order, so do not rely on commands from one variable-check to +# always happen before (or after) checks on another +# variable. Similarly, the value-equality checks are not +# done in a deterministic order, but all of the value-checks +# for a given variable happen together. +# --- +dontChroot: false firmwareType: efi: "-pkg remove efi-firmware" bios: "-pkg remove bios-firmware" + "": "/bin/false no-firmware-type-set"