Merge branch 'master' into update-services

This commit is contained in:
Adriaan de Groot 2018-06-26 10:43:16 -04:00
commit 851d90508c
20 changed files with 219 additions and 48 deletions

View File

@ -36,13 +36,29 @@ cmake_minimum_required( VERSION 3.2 )
### OPTIONS ### OPTIONS
# #
option( INSTALL_CONFIG "Install configuration files" ON ) option( INSTALL_CONFIG "Install configuration files" OFF )
option( INSTALL_POLKIT "Install Polkit configuration" ON ) option( INSTALL_POLKIT "Install Polkit configuration" ON )
option( BUILD_TESTING "Build the testing tree." ON ) option( BUILD_TESTING "Build the testing tree." ON )
option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON ) option( WITH_PYTHON "Enable Python modules API (requires Boost.Python)." ON )
option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." ON ) option( WITH_PYTHONQT "Enable next generation Python modules API (experimental, requires PythonQt)." ON )
option( WITH_KF5Crash "Enable crash reporting with KCrash." ON ) option( WITH_KF5Crash "Enable crash reporting with KCrash." ON )
### USE_*
#
# By convention, when there are multiple modules that implement similar
# functionality, and it only makes sense to have **at most one** of them
# enabled at any time, those modules are named <foo>-<implementation>.
# For example, services-systemd and services-openrc.
#
# Setting up SKIP_MODULES to ignore "the ones you don't want" can be
# annoying and error-prone (e.g. if a new module shows up). The USE_*
# modules provide a way to do automatic selection. To pick exactly
# one of the implementations from group <foo>, set USE_<foo> to the
# name of the implementation. If USE_<foo> is unset, or empty, then
# all the implementations are enabled (this just means they are
# **available** to `settings.conf`, not that they are used).
#
# Currently, no USE_<foo> variables exist.
### Calamares application info ### Calamares application info
# #

View File

@ -212,7 +212,7 @@ Settings::customModuleInstances() const
} }
QList< QPair< ModuleAction, QStringList > > Settings::ModuleSequence
Settings::modulesSequence() const Settings::modulesSequence() const
{ {
return m_modulesSequence; return m_modulesSequence;

View File

@ -47,7 +47,8 @@ public:
using InstanceDescriptionList = QList< InstanceDescription >; using InstanceDescriptionList = QList< InstanceDescription >;
InstanceDescriptionList customModuleInstances() const; InstanceDescriptionList customModuleInstances() const;
QList< QPair< ModuleAction, QStringList > > modulesSequence() const; using ModuleSequence = QList< QPair< ModuleAction, QStringList > >;
ModuleSequence modulesSequence() const;
QString brandingComponentName() const; QString brandingComponentName() const;
@ -63,7 +64,7 @@ private:
QStringList m_modulesSearchPaths; QStringList m_modulesSearchPaths;
InstanceDescriptionList m_customModuleInstances; InstanceDescriptionList m_customModuleInstances;
QList< QPair< ModuleAction, QStringList > > m_modulesSequence; ModuleSequence m_modulesSequence;
QString m_brandingComponentName; QString m_brandingComponentName;

View File

@ -224,13 +224,6 @@ Module::instanceKey() const
} }
QStringList
Module::requiredModules() const
{
return m_requiredModules;
}
QString QString
Module::location() const Module::location() const
{ {
@ -286,7 +279,6 @@ 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 ) ) if ( moduleDescriptor.contains( EMERGENCY ) )
m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool(); m_maybe_emergency = moduleDescriptor[ EMERGENCY ].toBool();
} }

View File

@ -106,13 +106,6 @@ public:
*/ */
virtual QString instanceKey() const final; virtual QString instanceKey() const final;
/**
* @brief requiredModules a list of names of modules required by this one.
* @return the list of names.
* The module dependencies system is currently incomplete and unused.
*/
virtual QStringList requiredModules() const;
/** /**
* @brief location returns the full path of this module's directory. * @brief location returns the full path of this module's directory.
* @return the path. * @return the path.
@ -198,7 +191,6 @@ 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;
QString m_directory; QString m_directory;
QString m_instanceId; QString m_instanceId;

View File

@ -126,7 +126,6 @@ ModuleManager::doInit()
} }
// At this point m_availableModules is filled with whatever was found in the // At this point m_availableModules is filled with whatever was found in the
// search paths. // search paths.
checkDependencies();
emit initDone(); emit initDone();
} }
@ -176,11 +175,11 @@ ModuleManager::loadModules()
{ {
QTimer::singleShot( 0, this, [ this ]() QTimer::singleShot( 0, this, [ this ]()
{ {
QStringList failedModules; QStringList failedModules = checkDependencies();
Settings::InstanceDescriptionList customInstances = Settings::InstanceDescriptionList customInstances =
Settings::instance()->customModuleInstances(); Settings::instance()->customModuleInstances();
const auto modulesSequence = Settings::instance()->modulesSequence(); const auto modulesSequence = failedModules.isEmpty() ? Settings::instance()->modulesSequence() : Settings::ModuleSequence();
for ( const auto& modulePhase : modulesSequence ) for ( const auto& modulePhase : modulesSequence )
{ {
ModuleAction currentAction = modulePhase.first; ModuleAction currentAction = modulePhase.first;
@ -262,6 +261,14 @@ ModuleManager::loadModules()
failedModules.append( instanceKey ); failedModules.append( instanceKey );
continue; continue;
} }
if ( !checkDependencies( *thisModule ) )
{
// Error message is already printed
failedModules.append( instanceKey );
continue;
}
// If it's a ViewModule, it also appends the ViewStep to the ViewManager. // If it's a ViewModule, it also appends the ViewStep to the ViewManager.
thisModule->loadSelf(); thisModule->loadSelf();
m_loadedModulesByInstanceKey.insert( instanceKey, thisModule ); m_loadedModulesByInstanceKey.insert( instanceKey, thisModule );
@ -301,24 +308,29 @@ ModuleManager::loadModules()
} }
void QStringList
ModuleManager::checkDependencies() ModuleManager::checkDependencies()
{ {
QStringList failed;
// This goes through the map of available modules, and deletes those whose // This goes through the map of available modules, and deletes those whose
// dependencies are not met, if any. // dependencies are not met, if any.
bool somethingWasRemovedBecauseOfUnmetDependencies = false;
forever forever
{ {
bool somethingWasRemovedBecauseOfUnmetDependencies = false;
for ( auto it = m_availableDescriptorsByModuleName.begin(); for ( auto it = m_availableDescriptorsByModuleName.begin();
it != m_availableDescriptorsByModuleName.end(); ++it ) it != m_availableDescriptorsByModuleName.end(); ++it )
{ {
foreach ( const QString& depName, foreach ( const QString& depName,
( *it ).value( "requiredModules" ).toStringList() ) it->value( "requiredModules" ).toStringList() )
{ {
if ( !m_availableDescriptorsByModuleName.contains( depName ) ) if ( !m_availableDescriptorsByModuleName.contains( depName ) )
{ {
QString moduleName = it->value( "name" ).toString();
somethingWasRemovedBecauseOfUnmetDependencies = true; somethingWasRemovedBecauseOfUnmetDependencies = true;
m_availableDescriptorsByModuleName.erase( it ); m_availableDescriptorsByModuleName.erase( it );
failed << moduleName;
cWarning() << "Module" << moduleName << "has unknown requirement" << depName;
break; break;
} }
} }
@ -328,7 +340,33 @@ ModuleManager::checkDependencies()
if ( !somethingWasRemovedBecauseOfUnmetDependencies ) if ( !somethingWasRemovedBecauseOfUnmetDependencies )
break; break;
} }
return failed;
} }
bool
ModuleManager::checkDependencies( const Module& m )
{
bool allRequirementsFound = true;
QStringList requiredModules = m_availableDescriptorsByModuleName[ m.name() ].value( "requiredModules" ).toStringList();
for ( const QString& required : requiredModules )
{
bool requirementFound = false;
for( const Module* v : m_loadedModulesByInstanceKey )
if ( required == v->name() )
{
requirementFound = true;
break;
}
if ( !requirementFound )
{
cError() << "Module" << m.name() << "requires" << required << "before it in sequence.";
allRequirementsFound = false;
}
}
return allRequirementsFound;
}
} }

View File

@ -90,7 +90,25 @@ private slots:
void doInit(); void doInit();
private: private:
void checkDependencies(); /**
* Check in a general sense whether the dependencies between
* modules are valid. Returns a list of module names that
* do **not** have their requirements met.
*
* Returns an empty list on success.
*
* Also modifies m_availableDescriptorsByModuleName to remove
* all the entries that fail.
*/
QStringList checkDependencies();
/**
* Check for this specific module if its required modules have
* already been loaded (i.e. are in sequence before it).
*
* Returns true if the requirements are met.
*/
bool checkDependencies( const Module& );
QMap< QString, QVariantMap > m_availableDescriptorsByModuleName; QMap< QString, QVariantMap > m_availableDescriptorsByModuleName;
QMap< QString, QString > m_moduleDirectoriesByModuleName; QMap< QString, QString > m_moduleDirectoriesByModuleName;

View File

@ -15,13 +15,34 @@ string( REPLACE " " ";" SKIP_LIST "${SKIP_MODULES}" )
file( GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" ) file( GLOB SUBDIRECTORIES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*" )
list( SORT SUBDIRECTORIES ) list( SORT SUBDIRECTORIES )
set( _use_categories "" )
set( _found_categories "" )
foreach( SUBDIRECTORY ${SUBDIRECTORIES} ) foreach( SUBDIRECTORY ${SUBDIRECTORIES} )
list( FIND SKIP_LIST ${SUBDIRECTORY} DO_SKIP ) list( FIND SKIP_LIST ${SUBDIRECTORY} DO_SKIP )
set( _skip_reason "user request" )
# Handle the USE_<foo> variables by looking for subdirectories
# with a <foo>-<implementation> kind of name.
if( SUBDIRECTORY MATCHES "^[a-zA-Z0-9_]+-" )
string( REGEX REPLACE "^[^-]+-" "" _implementation ${SUBDIRECTORY} )
string( REGEX REPLACE "-.*" "" _category ${SUBDIRECTORY} )
if( USE_${_category} )
list( APPEND _use_categories ${_category} )
if( "${_implementation}" STREQUAL "${USE_${_category}}" )
list( APPEND _found_categories ${_category} )
else()
list( APPEND SKIP_LIST ${SUBDIRECTORY} )
set( _skip_reason "USE_${_category}=${USE_${_category}}" )
set( DO_SKIP 1 )
endif()
endif()
endif()
if( NOT DO_SKIP EQUAL -1 ) if( NOT DO_SKIP EQUAL -1 )
message( "${ColorReset}-- Skipping module ${BoldRed}${SUBDIRECTORY}${ColorReset}." ) message( "${ColorReset}-- Skipping module ${BoldRed}${SUBDIRECTORY}${ColorReset}." )
message( "" ) message( "" )
list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (user request)" ) list( APPEND LIST_SKIPPED_MODULES "${SUBDIRECTORY} (${_skip_reason})" )
elseif( ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) AND elseif( ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${SUBDIRECTORY}" ) AND
( DO_SKIP EQUAL -1 ) ) ( DO_SKIP EQUAL -1 ) )
set( SKIPPED_MODULES ) set( SKIPPED_MODULES )
@ -36,5 +57,12 @@ endforeach()
# both before and after the feature summary. # both before and after the feature summary.
calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} ) calamares_explain_skipped_modules( ${LIST_SKIPPED_MODULES} )
foreach( _category ${_use_categories} )
list( FIND _found_categories ${_category} _found )
if ( _found EQUAL -1 )
message( FATAL_ERROR "USE_${_category} is set to ${USE_${_category}} and no module matches." )
endif()
endforeach()
include( CalamaresAddTranslations ) include( CalamaresAddTranslations )
add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} ) add_calamares_python_translations( ${CALAMARES_TRANSLATION_LANGUAGES} )

View File

@ -12,8 +12,10 @@ kernel: "/vmlinuz-linux"
img: "/initramfs-linux.img" img: "/initramfs-linux.img"
fallback: "/initramfs-linux-fallback.img" fallback: "/initramfs-linux-fallback.img"
timeout: "10" timeout: "10"
# Optionally set the menu entry name and kernel name to use in systemd-boot. # Optionally set the menu entry name and kernel name to use in systemd-boot.
# If not specified here, these settings will be taken from branding.desc. # If not specified here, these settings will be taken from branding.desc.
#
# bootloaderEntryName: "Generic GNU/Linux" # bootloaderEntryName: "Generic GNU/Linux"
# kernelLine: ", with Stable-Kernel" # kernelLine: ", with Stable-Kernel"
# fallbackKernelLine: ", with Stable-Kernel (fallback initramfs)" # fallbackKernelLine: ", with Stable-Kernel (fallback initramfs)"

View File

@ -1,3 +1,5 @@
# Configure one or more display managers (e.g. SDDM)
# with a "best effort" approach.
--- ---
#The DM module attempts to set up all the DMs found in this list, in that precise order. #The DM module attempts to set up all the DMs found in this list, in that precise order.
#It also sets up autologin, if the feature is enabled in globalstorage. #It also sets up autologin, if the feature is enabled in globalstorage.

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for C++ Jobs.
#
# The code is the documentation for the configuration file.
--- ---
syntax: "YAML map of anything" syntax: "YAML map of anything"
example: example:
@ -15,4 +18,4 @@ a_list_of_maps:
- "another element" - "another element"
- name: "another item" - name: "another item"
contents: contents:
- "not much" - "not much"

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for a Python Job Module.
#
# The code is the documentation for the configuration file.
--- ---
syntax: "YAML map of anything" syntax: "YAML map of anything"
example: example:
@ -15,4 +18,4 @@ a_list_of_maps:
- "another element" - "another element"
- name: "another item" - name: "another item"
contents: contents:
- "not much" - "not much"

View File

@ -1,3 +1,6 @@
# This is a dummy (example) module for PythonQt.
#
# The code is the documentation for the configuration file.
--- ---
syntax: "YAML map of anything" syntax: "YAML map of anything"
example: example:

View File

@ -1,13 +1,28 @@
# Creates /etc/fstab and /etc/crypttab in the target system.
# Also creates mount points for all the filesystems.
#
# When creating fstab entries for a filesystem, this module
# uses the options for the filesystem type to write to the
# options field of the file.
--- ---
# Mount options to use for all filesystems. If a specific filesystem
# is listed here, use those options, otherwise use the *default*
# options from this mapping.
mountOptions: mountOptions:
default: defaults,noatime default: defaults,noatime
btrfs: defaults,noatime,space_cache,autodefrag btrfs: defaults,noatime,space_cache,autodefrag
# If a filesystem is on an SSD, add the following options. If a specific
# filesystem is listed here, use those options, otherwise no additional
# options are set (i.e. there is no *default* like in *mountOptions*).
ssdExtraMountOptions: ssdExtraMountOptions:
ext4: discard ext4: discard
jfs: discard jfs: discard
xfs: discard xfs: discard
swap: discard swap: discard
btrfs: discard,compress=lzo btrfs: discard,compress=lzo
# Additional options added to each line in /etc/crypttab
crypttabOptions: luks crypttabOptions: luks
# For Debian and Debian-based distributions, change the above line to: # For Debian and Debian-based distributions, change the above line to:
# crypttabOptions: luks,keyscript=/bin/cat # crypttabOptions: luks,keyscript=/bin/cat

View File

@ -1,10 +1,22 @@
# Write lines to /etc/default/grub (in the target system) based
# on calculated values and the values set in the *defaults* key
# in this configuration file.
#
# Calculated values are:
# - GRUB_DISTRIBUTOR, branding module, *bootloaderEntryName*
# - GRUB_ENABLE_CRYPTODISK, based on the presence of filesystems
# that use LUKS
# - GRUB_CMDLINE_LINUX_DEFAULT, adding LUKS setup and plymouth
# support to the kernel.
--- ---
# If set to true, always creates /etc/default/grub from scratch even if the file # If set to true, always creates /etc/default/grub from scratch even if the file
# already existed. If set to false, edits the existing file instead. # already existed. If set to false, edits the existing file instead.
overwrite: false overwrite: false
# Default entries to write to /etc/default/grub if it does not exist yet or if # Default entries to write to /etc/default/grub if it does not exist yet or if
# we are overwriting it. Note that in addition, GRUB_CMDLINE_LINUX_DEFAULT and # we are overwriting it.
# GRUB_DISTRIBUTOR will always be written, with automatically detected values. #
defaults: defaults:
GRUB_TIMEOUT: 5 GRUB_TIMEOUT: 5
GRUB_DEFAULT: "saved" GRUB_DEFAULT: "saved"

View File

@ -1,2 +1,3 @@
# Run mkinitcpio(8) with the given preset value
--- ---
kernel: linux312 kernel: linux312

View File

@ -1,2 +1,4 @@
# Writes an openswap configuration with LUKS settings to the given path
--- ---
# Path of the configuration file to write (in the target system)
configFilePath: /etc/openswap.conf configFilePath: /etc/openswap.conf

View File

@ -1,4 +1,18 @@
# Mount filesystems in the target (generally, before treating the
# target as a usable chroot / "live" system). Filesystems are
# automatically mounted from the partitioning module. Filesystems
# listed here are **extra**. The filesystems listed in *extraMounts*
# are mounted in all target systems. The filesystems listed in
# *extraMountsEfi* are mounted in the target system **only** if
# the host machine uses UEFI.
--- ---
# Extra filesystems to mount. The key's value is a list of entries; each
# entry has four keys:
# - device The device node to mount
# - fs The filesystem type to use
# - mountPoint Where to mount the filesystem
# - options (optional) Extra options to pass to mount(8)
#
extraMounts: extraMounts:
- device: proc - device: proc
fs: proc fs: proc

View File

@ -1,2 +1,6 @@
# Removes a single user (with userdel) from the system.
# This is typically used in OEM setups or if the live user
# spills into the target system.
--- ---
# Username in the target system to be removed.
username: live username: live

View File

@ -1,20 +1,45 @@
# Systemd services manipulation.
#
# This module can enable services and targets for systemd
# (if packaging doesn't already do that). It can calso
# disable services (but not targets).
#
# First, services are enabled; then targets; then services
# are disabled -- this order of operations is fixed.
--- ---
#systemd services and targets are enabled in this precise order
services: # There are three configuration keys for this module:
- name: "NetworkManager" #name of the service file # *services*, *targets* and *disable*. The value of each
mandatory: false #true=> if enabling fails the installer errors out and quits # key is a list of entries. Each entry has two keys:
#false=>if enabling fails print warning to console and continue # - *name* is the (string) name of the service or target that is being
- name: "cups" # changed. Use quotes.
mandatory: false # - *mandatory* is a boolean option, which states whether the change
# must be done successfully. If systemd reports an error while changing
# a mandatory entry, the installation will fail. When mandatory is false,
# errors for that entry (service or target) are ignored.
#
# Use [] to express an empty list.
targets: # # This example enables NetworkManager (and fails if it can't),
- name: "graphical" # # disables cups (and ignores failure). Then it enables the
mandatory: true # # graphical target (e.g. so that SDDM runs for login), and
# # finally disables pacman-init (an ArchLinux-only service).
# #
# services:
# - name: "NetworkManager"
# mandatory: true
# - name: "cups"
# mandatory: false
#
# targets:
# - name: "graphical"
# mandatory: true
#
# disable:
# - name: "pacman-init"
# mandatory: false
disable: # By default, no changes are made.
- name: "pacman-init" services: []
mandatory: false targets: []
disable: []
# Example to express an empty list:
# disable: []