Compare commits

..

33 Commits

Author SHA1 Message Date
Adriaan de Groot
91454a71d0 [calamares] missing include
Include for getpid() is needed on FreeBSD.
2024-02-27 00:52:21 +01:00
Adriaan de Groot
6658708576 Changes: pre-release housekeeping 2024-02-27 00:33:06 +01:00
Adriaan de Groot
c4e0456acc [locale] avoid crash when there are no good locales
If the running locale doesn't match any locale in the list,
nothing is selected. Avoid a crash when referring to
first() of an empty list.
2024-02-27 00:28:36 +01:00
Adriaan de Groot
9925d6666f [calamares] Improve "crash self" functionality
Instead of UB, use POSIX signals and terminate the Calamares
process with a recognizable signal number (TRAP, which is
highly unusual).
2024-02-27 00:08:41 +01:00
Adriaan de Groot
2555b5baf4 [calamares] avoid double-quit message
In Qt5, QApplication::quit() was sufficient.
In Qt6, QApplication::quit() sends close events to top-level
windows, so we get a duplicate prompt for quit.

See https://blog.broulik.de/2023/11/on-the-road-to-plasma-6-vol-4/
2024-02-27 00:02:03 +01:00
Adriaan de Groot
f57ee158b7 Merge branch 'issue-2212' into calamares 2024-02-26 22:38:28 +01:00
Adriaan de Groot
028e9e68f9 [libcalamares] Add ${LANG} to process expansions 2024-02-26 22:37:20 +01:00
Adriaan de Groot
0f2bceb72f Docs: process jobmodules now expand variables 2024-02-26 21:58:40 +01:00
Adriaan de Groot
5eac7a021c Changes: document contributions 2024-02-26 21:42:06 +01:00
Adriaan de Groot
ab3612d18d [partition] tidy up constructor - use initializer-list 2024-02-26 21:39:37 +01:00
Adriaan de Groot
2fce6a3c44 Merge pull request #2292 from vlinkz/calamares
[partition] Make default partition entry have `partNoEncrypt` be false
2024-02-26 21:32:10 +01:00
Victor Fuentes
01cbe07641 Make default partition entry have partNoEncrypt be false 2024-02-26 01:55:26 -05:00
Adriaan de Groot
2697c35fc7 [libcalamares] Run ProcessJobs with CommandLine
This makes the behavior of process jobs and shellcommands the same.
2024-02-25 23:22:19 +01:00
Adriaan de Groot
4329b824d4 [libcalamares] Test command-expansion with environment 2024-02-25 23:22:19 +01:00
Adriaan de Groot
0ced01ddc3 [libcalamares] Test environment-setting for CommandLine 2024-02-25 23:22:19 +01:00
Adriaan de Groot
d5555eba32 [libcalamares] Add environment-setting to CommandLine
This class is shared -- used by shellprocess and contextualprocess --
to collect the command settings for a single shell invocation.
2024-02-25 23:22:19 +01:00
Adriaan de Groot
6770f781e3 [libcalamares] Tests for new CommandLine constructors 2024-02-25 23:22:19 +01:00
Adriaan de Groot
ae3e609024 [libcalamares] Get default timeout from CommandList 2024-02-25 23:22:19 +01:00
Adriaan de Groot
4aa2c4988c [libcalamares] Replace factory method with constructor 2024-02-25 23:22:19 +01:00
Adriaan de Groot
0d9d2ac59a [libcalamares] Extend CommandLine
- rename fields so they are meaningful (this is a leftover
  from it inheriting std::pair)
- add environment list member
- add constructor that consumes a QVariantMap
2024-02-25 23:22:19 +01:00
Adriaan de Groot
15c514326c [shellprocess] Improve config docs 2024-02-25 23:22:19 +01:00
Adriaan de Groot
b795fd82bb [contextualprocess] Improve config docs 2024-02-25 23:22:19 +01:00
Adriaan de Groot
dc91255ff5 Changes: document process changes
FIXES #2212
2024-02-25 23:22:19 +01:00
Adriaan de Groot
7379e7f28d Merge pull request #2288 from calamares/issue-2145
[packages] Add a DNF5 PM backend
2024-02-25 20:24:23 +01:00
Adriaan de Groot
633d6bda0d [libcalamaresui] Be more careful about which bindings are in use 2024-02-24 21:47:24 +01:00
Adriaan de Groot
dbddeaba68 CMake: be more noisy about python technologies
- log enabled and disabled features
- enabled python gets logged twice, that's fine
2024-02-24 21:27:45 +01:00
Adriaan de Groot
809d6cdda0 CMake: do not put PYBIND11 on the command-line
This is already stored in CalamaresConfig.hfor ABI purposes.
2024-02-24 18:54:33 +01:00
Adriaan de Groot
b37cf66acb CI: add a fedora-boost CI job, for better coverage
All other CI jobs use pybind11.
2024-02-24 13:46:16 +01:00
Adriaan de Groot
be5ce2e60f [libcalamares] repair boost / pybind split
The difference wasn't being recorded in the ABI-parts of
the CalamaresConfig.h header file, and it was unclear if
the two builds were "clean", e.g. no pybind11 stuff in a
boost build and vice-versa.

Tidy that up by writing more ABI info to the header and
double-checking defines when including Python-related
Calamares headers.
2024-02-24 13:27:44 +01:00
Adriaan de Groot
34888edae1 [libcalamares] repair visibility also for Boost::Python modules 2024-02-24 12:45:20 +01:00
Adriaan de Groot
7a3bff5117 [libcalamares] repair visibility also for Boost::Python modules 2024-02-24 12:28:36 +01:00
Adriaan de Groot
b7e34abeaa Changes: post-release housekeeping 2024-02-24 00:27:17 +01:00
Adriaan de Groot
8a5876410e [packages] Add a DNF5 PM backend
I just made this up, checked that the `dnf5` command
in Fedora 39 exists and can run the command-lines
created by this PM backend. (I did install dnf5 into
that Fedora 39 system first)
2024-02-20 13:54:45 +01:00
31 changed files with 447 additions and 92 deletions

View File

@@ -0,0 +1,36 @@
name: nightly-fedora-qt6
on:
schedule:
- cron: "52 2 * * *"
workflow_dispatch:
env:
BUILDDIR: /build
SRCDIR: ${{ github.workspace }}
CMAKE_ARGS: |
-DKDE_INSTALL_USE_QT_SYS_PATHS=ON
-DCMAKE_BUILD_TYPE=Debug
-DWITH_QT6=ON
-DBUILD_APPSTREAM=ON
-DBUILD_APPDATA=ON
-DWITH_PYBIND11=OFF
jobs:
build:
runs-on: ubuntu-latest
container:
image: docker://registry.fedoraproject.org/fedora:40
options: --tmpfs /build:rw --user 0:0
steps:
- name: "prepare git"
shell: bash
run: yum install -y git-core jq curl
- name: "prepare source"
uses: calamares/actions/generic-checkout@v5
- name: "install dependencies"
shell: bash
run: ./ci/deps-fedora-qt6-boost.sh
- name: "build"
shell: bash
run: ./ci/build.sh

View File

@@ -7,6 +7,37 @@ contributors are listed. Note that Calamares does not have a historical
changelog -- this log starts with version 3.3.0. See CHANGES-3.2 for
the history of the 3.2 series (2018-05 - 2022-08).
# 3.3.4 (2024-02-27)
In this release, process jobmodules -- a particular kind of module
recognizable by `type: job` and `interface: process` in the descriptor
file -- undergo a large change to resemble *shellprocess* more.
Users of process jobmodules are encouraged to double-check the Functionality
of those modules in this release.
This release contains contributions from (alphabetically by first name):
- Adriaan de Groot
- Victor Fuentes
## Core ##
- Process jobs (a job type provided by Calamares core) now share more
code with *contextualprocess* and *shellprocess* jobs. The execution
mechanism is the same, and always invokes the shell, whether the command
runs in the host or in the target system. It is no longer necessary to
add `/bin/sh` in the *command* key -- this is always present.
## Modules ##
- *contextualprocess* and *shellprocess* can now set environment variables
as part of the configuration. See *shellprocess* documentation for details.
This is optional, and does not do anything that could not already be done
by putting `export VAR=value ;` in front of the command before.
- *partition* fixed a bug with an uninitialized variable. (thanks Victor)
- *shellprocess* (and therefore also *contextualprocess* and process
jobmodules) now substitutes `${LANG}` in commands with the language
selected in the user-interface of Calamares.
# 3.3.3 (2024-02-24)
This release contains contributions from (alphabetically by first name):

View File

@@ -47,7 +47,7 @@
cmake_minimum_required(VERSION 3.16 FATAL_ERROR)
set(CALAMARES_VERSION 3.3.3)
set(CALAMARES_VERSION 3.3.4)
set(CALAMARES_RELEASE_MODE ON) # Set to ON during a release
if(CMAKE_SCRIPT_MODE_FILE)
@@ -455,9 +455,11 @@ if(NOT Python_Development_FOUND)
message(STATUS "Disabling Python modules")
set(WITH_PYTHON OFF)
set(WITH_PYBIND11 OFF)
set(WITH_BOOST_PYTHON OFF)
endif()
if(WITH_PYTHON AND NOT WITH_PYBIND11)
set(WITH_BOOST_PYTHON ON)
find_package(boost_python)
if(NOT TARGET Boost::python)
find_package(Boost ${BOOSTPYTHON_VERSION} COMPONENTS python)
@@ -470,12 +472,16 @@ if(WITH_PYTHON AND NOT WITH_PYBIND11)
set(Boost_FOUND ON)
endif()
endif()
add_feature_info(python WITH_PYTHON "Enable Python-modules")
add_feature_info(python-pybind11 WITH_PYBIND11 "Python-modules through pybind11")
add_feature_info(python-boost WITH_BOOST_PYTHON "Python-modules through Boost::Python")
# Now we know the state of the ABI-options, copy them into "Calamares_"
# prefixed variables, to match how the variables would-be-named
# when building out-of-tree.
set(Calamares_WITH_PYBIND11 ${WITH_PYBIND11})
set(Calamares_WITH_PYTHON ${WITH_PYTHON})
set(Calamares_WITH_PYBIND11 ${WITH_PYBIND11})
set(Calamares_WITH_BOOST_PYTHON ${WITH_BOOST_PYTHON})
set(Calamares_WITH_QML ${WITH_QML})
set(Calamares_WITH_QT6 ${WITH_QT6})
@@ -715,6 +721,7 @@ endif()
get_directory_property(SKIPPED_MODULES DIRECTORY src/modules DEFINITION LIST_SKIPPED_MODULES)
calamares_explain_skipped_modules( ${SKIPPED_MODULES} )
feature_summary(WHAT ENABLED_FEATURES DESCRIPTION "The following features are enabled" QUIET_ON_EMPTY)
feature_summary(WHAT DISABLED_FEATURES DESCRIPTION "The following features have been disabled:" QUIET_ON_EMPTY)
feature_summary(
WHAT OPTIONAL_PACKAGES_NOT_FOUND

View File

@@ -94,4 +94,7 @@ include(CalamaresAddPlugin)
# This list should match the one in libcalamares/CalamaresConfig.h,
# which is the C++-language side of the same configuration.
set(Calamares_WITH_PYTHON @WITH_PYTHON@)
set(Calamares_WITH_PYBIND11 @WITH_PYBIND11@)
set(Calamares_WITH_BOOST_PYTHON @WITH_BOOST_PYTHON@)
set(Calamares_WITH_QML @WITH_QML@)
set(Calamares_WITH_QT6 @WITH_QT6@)

18
ci/deps-fedora-qt6-boost.sh Executable file
View File

@@ -0,0 +1,18 @@
#! /bin/sh
#
# Install dependencies for the nightly-fedora-qt6-boost build
#
yum install -y bison flex git make cmake gcc-c++ ninja-build
yum install -y yaml-cpp-devel libpwquality-devel parted-devel python-devel gettext gettext-devel
yum install -y libicu-devel libatasmart-devel
yum install -y boost-devel
# Qt6/KF6 dependencies
yum install -y qt6-qtbase-devel qt6-linguist qt6-qtbase-private-devel qt6-qtdeclarative-devel qt6-qtsvg-devel qt6-qttools-devel
yum install -y extra-cmake-modules kf6-kcoreaddons-devel kf6-kdbusaddons-devel kf6-kcrash-devel
yum install -y kf6-kconfig-devel kf6-ki18n-devel kf6-kwidgetsaddons-devel kf6-kservice-devel
yum install -y polkit-qt6-1-devel appstream-qt-devel
# Runtime dependencies for QML modules
yum install -y kf6-kirigami2-devel || true
yum install -y qt6-qt5compat-devel || true
true

View File

@@ -64,9 +64,4 @@ if(BUILD_TESTING)
add_executable(test_conf test_conf.cpp)
target_link_libraries(test_conf PUBLIC yamlcpp::yamlcpp ${qtname}::Core)
if(WITH_PYBIND11)
target_compile_definitions(loadmodule PRIVATE WITH_PYBIND11=1)
endif()
endif()

View File

@@ -537,7 +537,11 @@ CalamaresWindow::closeEvent( QCloseEvent* event )
if ( ( !m_viewManager ) || m_viewManager->confirmCancelInstallation() )
{
event->accept();
qApp->quit();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QApplication::quit();
#else
QApplication::exit( EXIT_SUCCESS );
#endif
}
else
{

View File

@@ -33,14 +33,16 @@
#include <QTreeView>
#include <QWidget>
#include <signal.h>
#include <unistd.h>
/**
* @brief crash makes Calamares crash immediately.
*/
static void
crash()
{
volatile int* a = nullptr;
*a = 1;
kill(getpid(), SIGTRAP);
}
/// @brief Print out the widget tree (names) in indented form.

View File

@@ -34,7 +34,7 @@
// - Python support with older Boost implementation
// - QML support
#ifdef WITH_PYTHON
#if WITH_PYBIND11
#ifdef WITH_PYBIND11
#include "python/PythonJob.h"
#else
#include "PythonJob.h"
@@ -486,7 +486,7 @@ main( int argc, char* argv[] )
#ifdef WITH_PYTHON
if ( module.m_pythonInjection )
{
#if WITH_PYBIND11
#ifdef WITH_PYBIND11
Calamares::Python::Job::setInjectedPreScript( pythonPreScript );
#else
// Old Boost approach

View File

@@ -25,6 +25,9 @@
* which is the CMake-time side of the same configuration.
*/
#cmakedefine WITH_PYTHON
#cmakedefine WITH_PYBIND11
#cmakedefine WITH_BOOST_PYTHON
#cmakedefine WITH_QML
#cmakedefine WITH_QT6
#endif // CALAMARESCONFIG_H

View File

@@ -10,8 +10,8 @@
#include "ProcessJob.h"
#include "utils/CommandList.h"
#include "utils/Logger.h"
#include "utils/System.h"
#include <QDir>
@@ -57,23 +57,9 @@ ProcessJob::prettyStatusMessage() const
JobResult
ProcessJob::exec()
{
using Calamares::System;
if ( m_runInChroot )
{
return Calamares::System::instance()
->targetEnvCommand( { m_command }, m_workingPath, QString(), m_timeoutSec )
.explainProcess( m_command, m_timeoutSec );
}
else
{
return System::runCommand( System::RunLocation::RunInHost,
{ "/bin/sh", "-c", m_command },
m_workingPath,
QString(),
m_timeoutSec )
.explainProcess( m_command, m_timeoutSec );
}
Calamares::CommandList l( m_runInChroot, m_timeoutSec );
l.push_back( Calamares::CommandLine { m_command } );
return l.run();
}
} // namespace Calamares

View File

@@ -11,6 +11,7 @@
#ifndef CALAMARES_PYTHONJOBHELPER_H
#define CALAMARES_PYTHONJOBHELPER_H
#include "DllMacro.h"
#include "PythonJob.h"
#include "utils/BoostPython.h"
@@ -24,20 +25,20 @@ class GlobalStorage;
namespace CalamaresPython
{
boost::python::object variantToPyObject( const QVariant& variant );
QVariant variantFromPyObject( const boost::python::object& pyObject );
DLLEXPORT boost::python::object variantToPyObject( const QVariant& variant );
DLLEXPORT QVariant variantFromPyObject( const boost::python::object& pyObject );
boost::python::list variantListToPyList( const QVariantList& variantList );
QVariantList variantListFromPyList( const boost::python::list& pyList );
DLLEXPORT boost::python::list variantListToPyList( const QVariantList& variantList );
DLLEXPORT QVariantList variantListFromPyList( const boost::python::list& pyList );
boost::python::dict variantMapToPyDict( const QVariantMap& variantMap );
QVariantMap variantMapFromPyDict( const boost::python::dict& pyDict );
DLLEXPORT boost::python::dict variantMapToPyDict( const QVariantMap& variantMap );
DLLEXPORT QVariantMap variantMapFromPyDict( const boost::python::dict& pyDict );
boost::python::dict variantHashToPyDict( const QVariantHash& variantHash );
QVariantHash variantHashFromPyDict( const boost::python::dict& pyDict );
DLLEXPORT boost::python::dict variantHashToPyDict( const QVariantHash& variantHash );
DLLEXPORT QVariantHash variantHashFromPyDict( const boost::python::dict& pyDict );
class Helper : public QObject
class DLLEXPORT Helper : public QObject
{
Q_OBJECT
public:

View File

@@ -19,6 +19,11 @@
#include <QDir>
#ifdef WITH_PYBIND11
#error Source only for Boost::Python
#else
#endif
static const char* s_preScript = nullptr;
namespace bp = boost::python;

View File

@@ -11,6 +11,7 @@
#ifndef CALAMARES_PYTHONJOB_H
#define CALAMARES_PYTHONJOB_H
#include "DllMacro.h"
#include "Job.h"
#include "modulesystem/InstanceKey.h"
@@ -18,6 +19,11 @@
#include <memory>
#ifdef WITH_PYBIND11
#error Source only for Boost::Python
#else
#endif
namespace CalamaresPython
{
class PythonJobInterface;
@@ -27,7 +33,7 @@ class Helper;
namespace Calamares
{
class PythonJob : public Job
class DLLEXPORT PythonJob : public Job
{
Q_OBJECT
public:

View File

@@ -20,6 +20,11 @@
#include <QFileInfo>
#include <QString>
#ifdef WITH_PYBIND11
#else
#error Source only for pybind11
#endif
namespace py = pybind11;
// Forward-declare function generated by PYBIND11_MODULE

View File

@@ -11,7 +11,9 @@
#define CALAMARES_PYTHON_PYTHONJOB_H
// This file is called PythonJob.h because it would otherwise
// clashwith the Job.h in libcalamares proper.
// clash with the Job.h in libcalamares proper.
#include "CalamaresConfig.h"
#include "DllMacro.h"
#include "Job.h"
@@ -19,6 +21,11 @@
#include <memory>
#ifdef WITH_PYBIND11
#else
#error Source only for pybind11
#endif
namespace Calamares
{
namespace Python

View File

@@ -14,6 +14,7 @@
#include "JobQueue.h"
#include "compat/Variant.h"
#include "locale/Global.h"
#include "utils/Logger.h"
#include "utils/StringExpander.h"
#include "utils/System.h"
@@ -25,20 +26,6 @@
namespace Calamares
{
static CommandLine
get_variant_object( const QVariantMap& m )
{
QString command = Calamares::getString( m, "command" );
qint64 timeout = Calamares::getInteger( m, "timeout", -1 );
if ( !command.isEmpty() )
{
return CommandLine( command, timeout >= 0 ? std::chrono::seconds( timeout ) : CommandLine::TimeoutNotSet() );
}
cWarning() << "Bad CommandLine element" << m;
return CommandLine();
}
static CommandList_t
get_variant_stringlist( const QVariantList& l )
{
@@ -52,7 +39,7 @@ get_variant_stringlist( const QVariantList& l )
}
else if ( Calamares::typeOf( v ) == Calamares::MapVariantType )
{
auto command( get_variant_object( v.toMap() ) );
CommandLine command( v.toMap() );
if ( command.isValid() )
{
retl.append( command );
@@ -91,15 +78,48 @@ get_gs_expander( System::RunLocation location )
expander.insert( QStringLiteral( "USER" ), gs->value( "username" ).toString() );
}
if ( gs )
{
const auto key = QStringLiteral( "LANG" );
const QString lang = Calamares::Locale::readGS( *gs, key );
if ( !lang.isEmpty() )
{
expander.insert( key, lang );
}
}
return expander;
}
CommandLine::CommandLine( const QVariantMap& m )
{
const QString command = Calamares::getString( m, "command" );
const qint64 timeout = Calamares::getInteger( m, "timeout", -1 );
if ( !command.isEmpty() )
{
m_command = command;
m_timeout = timeout >= 0 ? std::chrono::seconds( timeout ) : CommandLine::TimeoutNotSet();
m_environment = Calamares::getStringList( m, "environment" );
}
else
{
cWarning() << "Bad CommandLine element" << m;
// this CommandLine is invalid
}
}
CommandLine
CommandLine::expand( KMacroExpanderBase& expander ) const
{
QString c = first;
// Calamares variable expansion in the command
QString c = m_command;
expander.expandMacrosShellQuote( c );
return { c, second };
// .. and expand in each environment key=value string.
QStringList e = m_environment;
std::for_each( e.begin(), e.end(), [ &expander ]( QString& s ) { expander.expandMacrosShellQuote( s ); } );
return { c, m_environment, m_timeout };
}
Calamares::CommandLine
@@ -136,7 +156,7 @@ CommandList::CommandList::CommandList( const QVariant& v, bool doChroot, std::ch
}
else if ( Calamares::typeOf( v ) == Calamares::MapVariantType )
{
auto c( get_variant_object( v.toMap() ) );
CommandLine c( v.toMap() );
if ( c.isValid() )
{
append( c );
@@ -178,8 +198,18 @@ CommandList::run()
processed_cmd.remove( 0, 1 ); // Drop the -
}
const QString environmentSetting = []( const QStringList& l ) -> QString
{
if ( l.isEmpty() )
{
return {};
}
return QStringLiteral( "export " ) + l.join( " " ) + QStringLiteral( " ; " );
}( i->environment() );
QStringList shell_cmd { "/bin/sh", "-c" };
shell_cmd << processed_cmd;
shell_cmd << ( environmentSetting + processed_cmd );
std::chrono::seconds timeout = i->timeout() >= std::chrono::seconds::zero() ? i->timeout() : m_timeout;
ProcessResult r = System::runCommand( location, shell_cmd, QString(), QString(), timeout );

View File

@@ -28,30 +28,43 @@ namespace Calamares
* Each command can have an associated timeout in seconds. The timeout
* defaults to 10 seconds. Provide some convenience naming and construction.
*/
struct CommandLine
class CommandLine
{
public:
static inline constexpr std::chrono::seconds TimeoutNotSet() { return std::chrono::seconds( -1 ); }
/// An invalid command line
CommandLine() = default;
CommandLine( const QString& s )
: first( s )
, second( TimeoutNotSet() )
: m_command( s )
{
}
CommandLine( const QString& s, std::chrono::seconds t )
: first( s )
, second( t )
: m_command( s )
, m_timeout( t )
{
}
QString command() const { return first; }
CommandLine( const QString& s, const QStringList& env, std::chrono::seconds t )
: m_command( s )
, m_environment( env )
, m_timeout( t )
{
}
std::chrono::seconds timeout() const { return second; }
/** @brief Constructs a CommandLine from a map with keys
*
* Relevant keys are *command*, *environment* and *timeout*.
*/
CommandLine( const QVariantMap& m );
bool isValid() const { return !first.isEmpty(); }
QString command() const { return m_command; }
[[nodiscard]] QStringList environment() const { return m_environment; }
std::chrono::seconds timeout() const { return m_timeout; }
bool isValid() const { return !m_command.isEmpty(); }
/** @brief Returns a copy of this one command, with variables expanded
*
@@ -60,6 +73,7 @@ struct CommandLine
* instance, which handles the ROOT and USER variables.
*/
DLLEXPORT CommandLine expand( KMacroExpanderBase& expander ) const;
/** @brief As above, with a default macro-expander.
*
* The default macro-expander assumes RunInHost (e.g. ROOT will
@@ -68,8 +82,9 @@ struct CommandLine
DLLEXPORT CommandLine expand() const;
private:
QString first;
std::chrono::seconds second = std::chrono::seconds( -1 );
QString m_command;
QStringList m_environment;
std::chrono::seconds m_timeout = TimeoutNotSet();
};
/** @brief Abbreviation, used internally. */
@@ -91,6 +106,7 @@ public:
CommandList( const QVariant& v, bool doChroot = true, std::chrono::seconds timeout = std::chrono::seconds( 10 ) );
bool doChroot() const { return m_doChroot; }
std::chrono::seconds defaultTimeout() const { return m_timeout; }
Calamares::JobResult run();
@@ -109,6 +125,7 @@ public:
* @see CommandLine::expand() for details.
*/
CommandList expand( KMacroExpanderBase& expander ) const;
/** @brief As above, with a default macro-expander.
*
* Each command-line in the list is expanded with that default macro-expander.

View File

@@ -12,6 +12,7 @@
#include "CommandList.h"
#include "Entropy.h"
#include "Logger.h"
#include "Permissions.h"
#include "RAII.h"
#include "Runner.h"
#include "String.h"
@@ -52,6 +53,9 @@ private Q_SLOTS:
void testCommands();
void testCommandExpansion_data();
void testCommandExpansion(); // See also shellprocess tests
void testCommandConstructors();
void testCommandConstructorsYAML();
void testCommandRunning();
/** @section Test that all the UMask objects work correctly. */
void testUmask();
@@ -300,6 +304,136 @@ LibCalamaresTests::testCommandExpansion()
QCOMPARE( e.command(), expected );
}
void
LibCalamaresTests::testCommandConstructors()
{
const QString command( "do this" );
Calamares::CommandLine c0( command );
QCOMPARE( c0.command(), command );
QCOMPARE( c0.timeout(), Calamares::CommandLine::TimeoutNotSet() );
QVERIFY( c0.environment().isEmpty() );
const QStringList env { "-la", "/tmp" };
Calamares::CommandLine c1( command, env, Calamares::CommandLine::TimeoutNotSet() );
QCOMPARE( c1.command(), command );
QCOMPARE( c1.timeout(), Calamares::CommandLine::TimeoutNotSet() );
QVERIFY( !c1.environment().isEmpty() );
QCOMPARE( c1.environment().count(), 2 );
QCOMPARE( c1.environment(), env );
}
void
LibCalamaresTests::testCommandConstructorsYAML()
{
QTemporaryFile f;
QVERIFY( f.open() );
f.write( R"(---
commands:
- one-string-command
- command: only-command
- command: with-timeout
timeout: 12
- command: all-three
timeout: 20
environment:
- PATH=/USER
- DISPLAY=:0
)" );
f.close();
bool ok = false;
QVariantMap m = Calamares::YAML::load( f.fileName(), &ok );
QVERIFY( ok );
QCOMPARE( m.count(), 1 );
QCOMPARE( m[ "commands" ].toList().count(), 4 );
{
// Take care! The second parameter is a bool, so "3" here means "true"
Calamares::CommandList cmds( m[ "commands" ], 3 );
QCOMPARE( cmds.defaultTimeout(), std::chrono::seconds( 10 ) );
// But the 4 commands are there anyway
QCOMPARE( cmds.count(), 4 );
QCOMPARE( cmds.at( 0 ).command(), QString( "one-string-command" ) );
QCOMPARE( cmds.at( 0 ).environment(), QStringList() );
QCOMPARE( cmds.at( 0 ).timeout(), Calamares::CommandLine::TimeoutNotSet() );
QCOMPARE( cmds.at( 1 ).command(), QString( "only-command" ) );
QCOMPARE( cmds.at( 2 ).command(), QString( "with-timeout" ) );
QCOMPARE( cmds.at( 2 ).environment(), QStringList() );
QCOMPARE( cmds.at( 2 ).timeout(), std::chrono::seconds( 12 ) );
QStringList expectedEnvironment = { "PATH=/USER", "DISPLAY=:0" };
QCOMPARE( cmds.at( 3 ).command(), QString( "all-three" ) );
QCOMPARE( cmds.at( 3 ).environment(), expectedEnvironment );
QCOMPARE( cmds.at( 3 ).timeout(), std::chrono::seconds( 20 ) );
}
{
Calamares::CommandList cmds( m[ "commands" ], true, std::chrono::seconds( 3 ) );
QCOMPARE( cmds.defaultTimeout(), std::chrono::seconds( 3 ) );
QCOMPARE( cmds.at( 0 ).timeout(), Calamares::CommandLine::TimeoutNotSet() );
QCOMPARE( cmds.at( 2 ).timeout(), std::chrono::seconds( 12 ) );
}
}
void
LibCalamaresTests::testCommandRunning()
{
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
tempRoot.setAutoRemove( false );
const QString testExecutable = tempRoot.filePath( "example.sh" );
const QString testFile = tempRoot.filePath( "example.txt" );
{
QFile f( testExecutable );
QVERIFY( f.open( QIODevice::WriteOnly ) );
f.write( "#! /bin/sh\necho \"$calamares_test_variable\"\n" );
f.close();
Calamares::Permissions::apply( testExecutable, 0755 );
}
const QString echoCommand = testExecutable + QStringLiteral( " > " ) + testFile;
// Without an environment, the variable echoed in the example
// executable is empty, and we write a single newline to stdout,
// which is redirected to testFile.
{
Calamares::CommandList l( false ); // no chroot
Calamares::CommandLine c( echoCommand, {}, std::chrono::seconds( 2 ) );
l.push_back( c );
const auto r = l.run();
QVERIFY( bool( r ) );
QCOMPARE( QFileInfo( testFile ).size(), 1 ); // single newline
}
// With an environment, echoes the value of the variable and a newline
{
const QString world = QStringLiteral( "Hello world" );
Calamares::CommandList l( false ); // no chroot
Calamares::CommandLine c(
echoCommand,
{ QStringLiteral( "calamares_test_variable=" ) + QChar( '"' ) + world + QChar( '"' ) },
std::chrono::seconds( 2 ) );
l.push_back( c );
const auto r = l.run();
QVERIFY( bool( r ) );
QCOMPARE( QFileInfo( testFile ).size(), world.length() + 1 ); // plus newline
QFile f( testFile );
QVERIFY( f.open( QIODevice::ReadOnly ) );
QCOMPARE( f.readAll(), world + QChar( '\n' ) );
}
tempRoot.setAutoRemove( true );
}
void
LibCalamaresTests::testUmask()
{

View File

@@ -63,9 +63,6 @@ if(WITH_QML)
target_link_libraries(calamaresui PUBLIC ${qtname}::QuickWidgets)
endif()
if(WITH_PYBIND11)
target_compile_definitions(calamaresui PRIVATE WITH_PYBIND11=1)
endif()
set_target_properties(
calamaresui
PROPERTIES

View File

@@ -172,7 +172,11 @@ ViewManager::onInstallationFailed( const QString& message, const QString& detail
{
Calamares::Paste::doLogUploadUI( errorDialog );
}
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QApplication::quit();
#else
QApplication::exit( EXIT_SUCCESS );
#endif
} );
}
@@ -487,7 +491,11 @@ ViewManager::quit()
{
if ( confirmCancelInstallation() )
{
qApp->quit();
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
QApplication::quit();
#else
QApplication::exit( EXIT_SUCCESS );
#endif
}
}

View File

@@ -10,13 +10,16 @@
#include "PythonJobModule.h"
#if WITH_PYBIND11
#include "CalamaresConfig.h"
#ifdef WITH_PYBIND11
#include "python/PythonJob.h"
using JobType = Calamares::Python::Job;
#else
#elif defined(WITH_BOOST_PYTHON)
// Old Boost::Python version
#include "PythonJob.h"
using JobType = Calamares::PythonJob;
#else
#error Python without bindings
#endif
#include <QDir>

View File

@@ -497,7 +497,8 @@ LC_ALL and LANG to "C" for the called command.
## Process modules
Use of this kind of module is **not** recommended.
Use of this kind of module is **not** recommended. Use *shellprocess*
instead, which is more configurable.
> Type: jobmodule
> Interface: process
@@ -506,9 +507,14 @@ A process jobmodule runs a (single) command. The interface is *process*,
while the module type must be *job* or *jobmodule*.
The module-descriptor key *command* should have a string as value, which is
passed to the shell -- remember to quote it properly. It is generally
passed to the shell -- remember to quote it properly in YAML. It is generally
recommended to use a *shellprocess* job module instead (less configuration,
easier to have multiple instances).
easier to have multiple instances). There is no configuration outside
of the module-descriptor. The *command* undergoes Calamares variable-
expansion (e.g. replacing `${ROOT}` by the target of the installation).
See *shellprocess* documentation for details.
Optional keys are *timeout* and *chroot*.
`CMakeLists.txt` is *not* used for process jobmodules.

View File

@@ -7,14 +7,13 @@
# When a given global value (string) equals a given value, then
# the associated command is executed.
#
# The special top-level keys *dontChroot* and *timeout* have
# meaning just like in shellprocess.conf. They are excluded from
# the comparison with global variables.
#
# Configuration consists of keys for global variable names (except
# *dontChroot* and *timeout*), and the sub-keys are strings to compare
# to the variable's value. If the variable has that particular value, the
# corresponding value (script) is executed.
# corresponding value (script) is executed. The top-level keys *dontChroot*
# and *timeout* are not global variable names. They have
# meaning just like in shellprocess.conf, that is they
# determine **where** the command runs and how long it has.
#
# The variable **may** contain dots, in which case the dot is used
# to select into maps inside global storage, e.g.

View File

@@ -84,5 +84,6 @@ LCLocaleDialog::LCLocaleDialog( const QString& guessedLCLocale, const QStringLis
QString
LCLocaleDialog::selectedLCLocale()
{
return m_localesWidget->selectedItems().first()->text();
const auto items = m_localesWidget->selectedItems();
return items.isEmpty() ? QString{} : items.first()->text();
}

View File

@@ -279,6 +279,11 @@ class PMApt(PackageManager):
class PMDnf(PackageManager):
"""
This is "legacy" DNF, called DNF-4 even though the
executable is dnf-3 in modern Fedora. Executable dnf
is a symlink to dnf-3 in systems that use it.
"""
backend = "dnf"
def install(self, pkgs, from_local=False):
@@ -298,6 +303,30 @@ class PMDnf(PackageManager):
check_target_env_call(["dnf-3", "-y", "upgrade"])
class PMDnf5(PackageManager):
"""
This is "modern" DNF, DNF-5 which is for Fedora 41 (presumably)
and later. Executable dnf is a symlink to dnf5 in systems that use it.
"""
backend = "dnf5"
def install(self, pkgs, from_local=False):
check_target_env_call(["dnf5", "-y", "install"] + pkgs)
def remove(self, pkgs):
# ignore the error code for now because dnf thinks removing a
# nonexistent package is an error
target_env_call(["dnf5", "--disablerepo=*", "-C", "-y",
"remove"] + pkgs)
def update_db(self):
# Doesn't need updates
pass
def update_system(self):
check_target_env_call(["dnf5", "-y", "upgrade"])
class PMDummy(PackageManager):
backend = "dummy"

View File

@@ -23,6 +23,7 @@
# - apk - Alpine Linux package manager
# - apt - APT frontend for DEB and RPM
# - dnf - DNF, the new RPM frontend
# - dnf5 - DNF5, the newer new RPM frontend
# - entropy - Sabayon package manager (is being deprecated)
# - luet - Sabayon package manager (next-gen)
# - packagekit - PackageKit CLI tool

View File

@@ -12,6 +12,7 @@ properties:
- apk
- apt
- dnf
- dnf5
- entropy
- luet
- packagekit

View File

@@ -71,13 +71,13 @@ PartitionLayout::PartitionEntry::PartitionEntry( const QString& label,
, partType( type )
, partAttributes( attributes )
, partMountPoint( mountPoint )
, partNoEncrypt( noEncrypt )
, partFeatures( features )
, partSize( size )
, partMinSize( minSize )
, partMaxSize( maxSize )
{
PartUtils::canonicalFilesystemName( fs, &partFileSystem );
partNoEncrypt = noEncrypt;
}
bool

View File

@@ -37,7 +37,7 @@ public:
quint64 partAttributes = 0;
QString partMountPoint;
FileSystem::Type partFileSystem = FileSystem::Unknown;
bool partNoEncrypt;
bool partNoEncrypt = false;
QVariantMap partFeatures;
Calamares::Partition::PartitionSize partSize;
Calamares::Partition::PartitionSize partMinSize;

View File

@@ -12,8 +12,15 @@
# system from the point of view of the command (when run in the target
# system, e.g. when *dontChroot* is false, that will be `/`).
# - `USER` is replaced by the username, set on the user page.
# - `LANG` is replaced by the language chosen for the user-interface
# of Calamares, set on the welcome page. This may not reflect the
# chosen system language from the locale page.
#
# Variables are written as `${var}`, e.g. `${ROOT}`.
# Write `$$` to get a shell-escaped `\$` in the shell command.
# It is not possible to get an un-escaped `$` in the shell command
# (either the command will fail because of undefined variables, or
# you get a shell-escaped `\$`).
#
# The (global) timeout for the command list can be set with
# the *timeout* key. The value is a time in seconds, default
@@ -35,20 +42,33 @@
#
# The value of *script* may be:
# - a single string; this is one command that is executed.
# - a single object (this is not useful).
# - a single object (see below).
# - a list of items; these are executed one at a time, by
# separate shells (/bin/sh -c is invoked for each command).
# Each list item may be:
# - a single string; this is one command that is executed.
# - a single object, specifying a key *command* and (optionally)
# a key *timeout* to set the timeout for this specific
# command differently from the global setting.
# command differently from the global setting. An optional
# key *environment* is a list of strings to put into the
# environment of the command.
#
# Using a single object is not useful because the same effect can
# be obtained with a single string and a global timeout, but when
# there are multiple commands to execute, one of them might have
# Using a single object is not generally useful because the same effect
# can be obtained with a single string and a global timeout, except
# when the command needs environment-settings. When there are
# multiple commands to execute, one of them might have
# a different timeout than the others.
#
# The environment strings should all be "KEY='some value'" strings,
# as if they can be typed into the shell. Quoting the environment
# strings with "" in YAML is recommended. Adding the '' quotes ensures
# that the value will not be interpreted by the shell. Writing
# environment strings is the same as placing `export KEY='some value' ;`
# in front of the *command*.
#
# Calamares variable expansion is **also** done on the environment strings.
# Write `$$` to get a literal `$` in the shell command.
#
# To change the description of the job, set the *name* entries in *i18n*.
---
# Set to true to run in host, rather than target system