diff --git a/src/calamares/testmain.cpp b/src/calamares/testmain.cpp index e038b5a2f..6dae0af68 100644 --- a/src/calamares/testmain.cpp +++ b/src/calamares/testmain.cpp @@ -18,6 +18,7 @@ #include "GlobalStorage.h" #include "Job.h" #include "JobQueue.h" +#include "PythonJob.h" #include "Settings.h" #include "ViewManager.h" #include "modulesystem/Module.h" @@ -321,7 +322,7 @@ load_module( const ModuleConfig& moduleConfig ) QString configFile( moduleConfig.configFile().isEmpty() ? moduleDirectory + '/' + name + ".conf" : moduleConfig.configFile() ); - cDebug() << "Module" << moduleName << "job-configuration:" << configFile; + cDebug() << Logger::SubEntry << "Module" << moduleName << "job-configuration:" << configFile; Calamares::Module* module = Calamares::moduleFromDescriptor( Calamares::ModuleSystem::Descriptor::fromDescriptorData( descriptor ), name, configFile, moduleDirectory ); @@ -365,6 +366,27 @@ createApplication( int& argc, char* argv[] ) return new QCoreApplication( argc, argv ); } +static const char pythonPreScript[] = R"( +# This is Python code executed by Python modules *before* the +# script file (e.g. main.py) is executed. Beware " before ) +# because it's a C++ raw-string. +_calamares_subprocess = __import__("subprocess", globals(), locals(), [], 0) +import sys +import libcalamares +class fake_subprocess(object): + @staticmethod + def call(*args, **kwargs): + libcalamares.utils.debug("subprocess.call(%r,%r) X run normally" % (args, kwargs)) + return 0 + @staticmethod + def check_call(*args, **kwargs): + libcalamares.utils.debug("subprocess.check_call(%r,%r) X subverted to call" % (args, kwargs)) + return 0 +sys.modules["subprocess"] = fake_subprocess +libcalamares.utils.debug('pre-script for testing purposes injected') + +)"; + int main( int argc, char* argv[] ) { @@ -397,6 +419,7 @@ main( int argc, char* argv[] ) #ifdef WITH_QML CalamaresUtils::initQmlModulesDir(); // don't care if failed #endif + Calamares::PythonJob::setInjectedPreScript(pythonPreScript); cDebug() << "Calamares module-loader testing" << module.moduleName(); Calamares::Module* m = load_module( module ); @@ -406,7 +429,7 @@ main( int argc, char* argv[] ) return 1; } - cDebug() << " .. got" << m->name() << m->typeString() << m->interfaceString(); + cDebug() << Logger::SubEntry << " .. got" << m->name() << m->typeString() << m->interfaceString(); if ( m->type() == Calamares::Module::Type::View ) { // If we forgot the --ui, any ViewModule will core dump as it @@ -455,7 +478,6 @@ main( int argc, char* argv[] ) cDebug() << "Module metadata" << TR( "name", m->name() ) << TR( "type", m->typeString() ) << TR( "interface", m->interfaceString() ); - cDebug() << "Job outputs:"; Calamares::JobList jobList = m->jobs(); unsigned int failure_count = 0; unsigned int count = 1; diff --git a/src/libcalamares/PythonJob.cpp b/src/libcalamares/PythonJob.cpp index 98f284ecc..1a4683c29 100644 --- a/src/libcalamares/PythonJob.cpp +++ b/src/libcalamares/PythonJob.cpp @@ -19,6 +19,8 @@ #include +static const char* s_preScript = nullptr; + namespace bp = boost::python; BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 ); @@ -242,6 +244,11 @@ PythonJob::exec() calamaresNamespace[ "globalstorage" ] = CalamaresPython::GlobalStoragePythonWrapper( JobQueue::instance()->globalStorage() ); + if ( s_preScript ) + { + bp::exec( s_preScript, scriptNamespace, scriptNamespace ); + } + cDebug() << "Job file" << scriptFI.absoluteFilePath(); bp::object execResult = bp::exec_file( scriptFI.absoluteFilePath().toLocal8Bit().data(), scriptNamespace, scriptNamespace ); @@ -319,4 +326,11 @@ PythonJob::emitProgress( qreal progressValue ) emit progress( progressValue ); } +void +PythonJob::setInjectedPreScript( const char* preScript ) +{ + s_preScript = preScript; + cDebug() << "Python pre-script set to" << Logger::Pointer( preScript ); +} + } // namespace Calamares diff --git a/src/libcalamares/PythonJob.h b/src/libcalamares/PythonJob.h index 04a0645ea..af77d741d 100644 --- a/src/libcalamares/PythonJob.h +++ b/src/libcalamares/PythonJob.h @@ -41,6 +41,19 @@ public: QString prettyStatusMessage() const override; JobResult exec() override; + /** @brief Sets the pre-run Python code for all PythonJobs + * + * A PythonJob runs the code from the scriptFile parameter to + * the constructor; the pre-run code is **also** run, before + * even the scriptFile code. Use this in testing mode + * to modify Python internals. + * + * No ownership of @p script is taken: pass in a pointer to + * a character literal or something that lives longer than the + * job. Pass in @c nullptr to switch off pre-run code. + */ + static void setInjectedPreScript( const char* script ); + private: struct Private; diff --git a/src/modules/mount/main.py b/src/modules/mount/main.py index 07166dd75..5e5233935 100644 --- a/src/modules/mount/main.py +++ b/src/modules/mount/main.py @@ -74,7 +74,14 @@ def mount_partition(root_mount_point, partition, partitions): # Special handling for btrfs subvolumes. Create the subvolumes listed in mount.conf if fstype == "btrfs" and partition["mountPoint"] == '/': # Root has been mounted to btrfs volume -> create subvolumes from configuration - btrfs_subvolumes = libcalamares.job.configuration.get("btrfsSubvolumes") or [] + btrfs_subvolumes = libcalamares.job.configuration.get("btrfsSubvolumes", None) + # Warn if there's no configuration at all, and empty configurations are + # replaced by a simple root-only layout. + if btrfs_subvolumes is None: + libcalamares.utils.warning("No configuration for btrfsSubvolumes") + if not btrfs_subvolumes: + btrfs_subvolumes = [ dict(mountPoint="/", subvolume="/@") ] + subvolume_mountpoints = [d['mountPoint'] for d in btrfs_subvolumes] # Check if listed mountpoints besides / are already present and don't create subvolume for those for p in partitions: diff --git a/src/modules/mount/test.yaml b/src/modules/mount/tests/1.global similarity index 100% rename from src/modules/mount/test.yaml rename to src/modules/mount/tests/1.global diff --git a/src/modules/mount/tests/1.job b/src/modules/mount/tests/1.job new file mode 100644 index 000000000..94b3a1492 --- /dev/null +++ b/src/modules/mount/tests/1.job @@ -0,0 +1,6 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +bogus: true + +# No configuration needed because the partitions are +# all filesystems that require no special handling. diff --git a/src/modules/mount/tests/2.global b/src/modules/mount/tests/2.global new file mode 100644 index 000000000..20aba89ec --- /dev/null +++ b/src/modules/mount/tests/2.global @@ -0,0 +1,8 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 +partitions: + - device: "/dev/sdb1" + mountPoint: "/" + fs: "btrfs" + +# Expect a complaint and a default btrfs layout diff --git a/src/modules/mount/tests/2.job b/src/modules/mount/tests/2.job new file mode 100644 index 000000000..40d8c6171 --- /dev/null +++ b/src/modules/mount/tests/2.job @@ -0,0 +1,5 @@ +# SPDX-FileCopyrightText: no +# SPDX-License-Identifier: CC0-1.0 + +# Expect a complaint and a default btrfs layout because the +# partitions use btrfs