Merge branch 'calamares' of https://github.com/calamares/calamares into development

This commit is contained in:
Philip Mueller 2024-10-09 11:33:13 +07:00
commit df37ae610b
27 changed files with 493 additions and 146 deletions

View File

@ -10,13 +10,21 @@ the history of the 3.2 series (2018-05 - 2022-08).
# 3.3.10 (unreleased) # 3.3.10 (unreleased)
This release contains contributions from (alphabetically by given name): This release contains contributions from (alphabetically by given name):
- Nobody yet - Adriaan de Groot
- Evan James
- Neal Gompa
## Core ## ## Core ##
- Nothing yet - Nothing yet
## Modules ## ## Modules ##
- Nothing yet - *keyboard* Repaired summary messages with strange formatting. (#2364)
- *keyboard* Can update KDE Plasma configuration in Wayland. (thanks Neal, #2264)
- *locale* Repaired summary messages with strange formatting. (#2364)
- *umount* Correctly unmounts the root filesystem of the target. (thanks Evan)
- *users* Supports a new `home_permissions` setting to override the
distro's `useradd` configuration of the umask. (#2362)
- *welcome* Follows system styling colors (e.g. Dark Mode).
# 3.3.9 (2024-08-12) # 3.3.9 (2024-08-12)

View File

@ -5,7 +5,9 @@
# There is no docker image for EndeavoudOS, and the live ISO # There is no docker image for EndeavoudOS, and the live ISO
# for Cassini Nova is KF5 / Qt5 based, but we can build there. # for Cassini Nova is KF5 / Qt5 based, but we can build there.
# It even has most of the build-deps already installed. # It even has most of the build-deps already installed.
pacman -Syu --noconfirm git cmake ninja jq pacman -Syu --noconfirm jq
pacman -S --noconfirm gcc yaml-cpp icu pacman -S --noconfirm git cmake ninja jq || exit 1
pacman -S --noconfirm extra-cmake-modules pacman -S --noconfirm gcc yaml-cpp icu || exit 1
pacman -S --noconfirm extra-cmake-modules || exit 1
pacman -S --noconfirm python-jsonschema || exit 1

View File

@ -378,18 +378,18 @@
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="124"/> <location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="124"/>
<source>Waiting for %n module(s)</source> <source>Waiting for %n module(s)</source>
<comment>@status</comment> <comment>@status</comment>
<translation type="unfinished"> <translation>
<numerusform/> <numerusform>Waiting for %n module<EFBFBD>~@<EFBFBD></numerusform>
<numerusform/> <numerusform>Waiting for %n modules<EFBFBD>~@<EFBFBD></numerusform>
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="125"/> <location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="125"/>
<source>(%n second(s))</source> <source>(%n second(s))</source>
<comment>@status</comment> <comment>@status</comment>
<translation type="unfinished"> <translation type="unfinished">
<numerusform/> <numerusform>(%n second)</numerusform>
<numerusform/> <numerusform>(%n seconds)</numerusform>
</translation> </translation>
</message> </message>
<message> <message>
@ -965,31 +965,31 @@ The installer will quit and all changes will be lost.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/keyboard/Config.cpp" line="506"/> <location filename="../src/modules/keyboard/Config.cpp" line="504"/>
<source>Keyboard model has been set to %1&lt;br/&gt;.</source> <source>Keyboard model has been set to %1.</source>
<comment>@label, %1 is keyboard model, as in Apple Magic Keyboard</comment> <comment>@label, %1 is keyboard model, as in Apple Magic Keyboard</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/keyboard/Config.cpp" line="513"/> <location filename="../src/modules/keyboard/Config.cpp" line="512"/>
<source>Keyboard layout has been set to %1/%2.</source> <source>Keyboard layout has been set to %1/%2.</source>
<comment>@label, %1 is layout, %2 is layout variant</comment> <comment>@label, %1 is layout, %2 is layout variant</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/locale/Config.cpp" line="379"/> <location filename="../src/modules/locale/Config.cpp" line="381"/>
<source>Set timezone to %1/%2</source> <source>Set timezone to %1.</source>
<comment>@action</comment> <comment>@action</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/locale/Config.cpp" line="416"/> <location filename="../src/modules/locale/Config.cpp" line="418"/>
<source>The system language will be set to %1.</source> <source>The system language will be set to %1.</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/locale/Config.cpp" line="423"/> <location filename="../src/modules/locale/Config.cpp" line="425"/>
<source>The numbers and dates locale will be set to %1.</source> <source>The numbers and dates locale will be set to %1.</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
@ -2281,7 +2281,7 @@ The installer will quit and all changes will be lost.</source>
<context> <context>
<name>LocaleTests</name> <name>LocaleTests</name>
<message> <message>
<location filename="../src/libcalamares/locale/Tests.cpp" line="266"/> <location filename="../src/libcalamares/locale/Tests.cpp" line="272"/>
<source>Quit</source> <source>Quit</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
@ -3246,174 +3246,179 @@ The installer will quit and all changes will be lost.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="143"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="144"/>
<source>Install %1 &lt;strong&gt;alongside&lt;/strong&gt; another operating system</source> <source>Install %1 &lt;strong&gt;alongside&lt;/strong&gt; another operating system</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="147"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="148"/>
<source>&lt;strong&gt;Erase&lt;/strong&gt; disk and install %1</source> <source>&lt;strong&gt;Erase&lt;/strong&gt; disk and install %1</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="151"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="152"/>
<source>&lt;strong&gt;Replace&lt;/strong&gt; a partition with %1</source> <source>&lt;strong&gt;Replace&lt;/strong&gt; a partition with %1</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="156"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="157"/>
<source>&lt;strong&gt;Manual&lt;/strong&gt; partitioning</source> <source>&lt;strong&gt;Manual&lt;/strong&gt; partitioning</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="178"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="179"/>
<source>Install %1 &lt;strong&gt;alongside&lt;/strong&gt; another operating system on disk &lt;strong&gt;%2&lt;/strong&gt; (%3)</source> <source>Install %1 &lt;strong&gt;alongside&lt;/strong&gt; another operating system on disk &lt;strong&gt;%2&lt;/strong&gt; (%3)</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="187"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="188"/>
<source>&lt;strong&gt;Erase&lt;/strong&gt; disk &lt;strong&gt;%2&lt;/strong&gt; (%3) and install %1</source> <source>&lt;strong&gt;Erase&lt;/strong&gt; disk &lt;strong&gt;%2&lt;/strong&gt; (%3) and install %1</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="194"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="195"/>
<source>&lt;strong&gt;Replace&lt;/strong&gt; a partition on disk &lt;strong&gt;%2&lt;/strong&gt; (%3) with %1</source> <source>&lt;strong&gt;Replace&lt;/strong&gt; a partition on disk &lt;strong&gt;%2&lt;/strong&gt; (%3) with %1</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="203"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="204"/>
<source>&lt;strong&gt;Manual&lt;/strong&gt; partitioning on disk &lt;strong&gt;%1&lt;/strong&gt; (%2)</source> <source>&lt;strong&gt;Manual&lt;/strong&gt; partitioning on disk &lt;strong&gt;%1&lt;/strong&gt; (%2)</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="213"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="214"/>
<source>Disk &lt;strong&gt;%1&lt;/strong&gt; (%2)</source> <source>Disk &lt;strong&gt;%1&lt;/strong&gt; (%2)</source>
<comment>@info</comment> <comment>@info</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="263"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="239"/>
<source>Create a swap file.</source>
<translation type="unfinished"/>
</message>
<message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="268"/>
<source>Unsafe partition actions are enabled.</source> <source>Unsafe partition actions are enabled.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="266"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="271"/>
<source>Partitioning is configured to &lt;b&gt;always&lt;/b&gt; fail.</source> <source>Partitioning is configured to &lt;b&gt;always&lt;/b&gt; fail.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="269"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="274"/>
<source>No partitions will be changed.</source> <source>No partitions will be changed.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="309"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="314"/>
<source>Current:</source> <source>Current:</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="327"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="332"/>
<source>After:</source> <source>After:</source>
<comment>@label</comment> <comment>@label</comment>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="550"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="555"/>
<source>An EFI system partition is necessary to start %1.&lt;br/&gt;&lt;br/&gt;To configure an EFI system partition, go back and select or create a suitable filesystem.</source> <source>An EFI system partition is necessary to start %1.&lt;br/&gt;&lt;br/&gt;To configure an EFI system partition, go back and select or create a suitable filesystem.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="556"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="561"/>
<source>An EFI system partition is necessary to start %1.&lt;br/&gt;&lt;br/&gt;The EFI system partition does not meet recommendations. It is recommended to go back and select or create a suitable filesystem.</source> <source>An EFI system partition is necessary to start %1.&lt;br/&gt;&lt;br/&gt;The EFI system partition does not meet recommendations. It is recommended to go back and select or create a suitable filesystem.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="564"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="569"/>
<source>The filesystem must be mounted on &lt;strong&gt;%1&lt;/strong&gt;.</source> <source>The filesystem must be mounted on &lt;strong&gt;%1&lt;/strong&gt;.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="565"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="570"/>
<source>The filesystem must have type FAT32.</source> <source>The filesystem must have type FAT32.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="566"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="571"/>
<source>The filesystem must have flag &lt;strong&gt;%1&lt;/strong&gt; set.</source> <source>The filesystem must have flag &lt;strong&gt;%1&lt;/strong&gt; set.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="574"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="579"/>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="576"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="581"/>
<source>The filesystem must be at least %1 MiB in size.</source> <source>The filesystem must be at least %1 MiB in size.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="578"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="583"/>
<source>The minimum recommended size for the filesystem is %1 MiB.</source> <source>The minimum recommended size for the filesystem is %1 MiB.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="580"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="585"/>
<source>You can continue without setting up an EFI system partition but your system may fail to start.</source> <source>You can continue without setting up an EFI system partition but your system may fail to start.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="582"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="587"/>
<source>You can continue with this EFI system partition configuration but your system may fail to start.</source> <source>You can continue with this EFI system partition configuration but your system may fail to start.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="594"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="599"/>
<source>No EFI system partition configured</source> <source>No EFI system partition configured</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="602"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="607"/>
<source>EFI system partition configured incorrectly</source> <source>EFI system partition configured incorrectly</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="622"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="627"/>
<source>EFI system partition recommendation</source> <source>EFI system partition recommendation</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="641"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="646"/>
<source>Option to use GPT on BIOS</source> <source>Option to use GPT on BIOS</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="642"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="647"/>
<source>A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.&lt;br/&gt;&lt;br/&gt;To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the &lt;strong&gt;%2&lt;/strong&gt; flag enabled.&lt;br/&gt;&lt;br/&gt;An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT.</source> <source>A GPT partition table is the best option for all systems. This installer supports such a setup for BIOS systems too.&lt;br/&gt;&lt;br/&gt;To configure a GPT partition table on BIOS, (if not done so already) go back and set the partition table to GPT, next create a 8 MB unformatted partition with the &lt;strong&gt;%2&lt;/strong&gt; flag enabled.&lt;br/&gt;&lt;br/&gt;An unformatted 8 MB partition is necessary to start %1 on a BIOS system with GPT.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="664"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="669"/>
<source>Boot partition not encrypted</source> <source>Boot partition not encrypted</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="665"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="670"/>
<source>A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.&lt;br/&gt;&lt;br/&gt;There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.&lt;br/&gt;You may continue if you wish, but filesystem unlocking will happen later during system startup.&lt;br/&gt;To encrypt the boot partition, go back and recreate it, selecting &lt;strong&gt;Encrypt&lt;/strong&gt; in the partition creation window.</source> <source>A separate boot partition was set up together with an encrypted root partition, but the boot partition is not encrypted.&lt;br/&gt;&lt;br/&gt;There are security concerns with this kind of setup, because important system files are kept on an unencrypted partition.&lt;br/&gt;You may continue if you wish, but filesystem unlocking will happen later during system startup.&lt;br/&gt;To encrypt the boot partition, go back and recreate it, selecting &lt;strong&gt;Encrypt&lt;/strong&gt; in the partition creation window.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="757"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="762"/>
<source>has at least one disk device available.</source> <source>has at least one disk device available.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>
<message> <message>
<location filename="../src/modules/partition/PartitionViewStep.cpp" line="758"/> <location filename="../src/modules/partition/PartitionViewStep.cpp" line="763"/>
<source>There are no partitions to install on.</source> <source>There are no partitions to install on.</source>
<translation type="unfinished"/> <translation type="unfinished"/>
</message> </message>

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-07-03 22:44+0200\n" "POT-Creation-Date: 2024-09-06 14:34+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -230,24 +230,24 @@ msgid_plural "Removing %(num)d packages."
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
#: src/modules/packages/main.py:769 src/modules/packages/main.py:781 #: src/modules/packages/main.py:775 src/modules/packages/main.py:787
#: src/modules/packages/main.py:809 #: src/modules/packages/main.py:815
msgid "Package Manager error" msgid "Package Manager error"
msgstr "" msgstr ""
#: src/modules/packages/main.py:770 #: src/modules/packages/main.py:776
msgid "" msgid ""
"The package manager could not prepare updates. The command <pre>{!s}</pre> " "The package manager could not prepare updates. The command <pre>{!s}</pre> "
"returned error code {!s}." "returned error code {!s}."
msgstr "" msgstr ""
#: src/modules/packages/main.py:782 #: src/modules/packages/main.py:788
msgid "" msgid ""
"The package manager could not update the system. The command <pre>{!s}</pre> " "The package manager could not update the system. The command <pre>{!s}</pre> "
"returned error code {!s}." "returned error code {!s}."
msgstr "" msgstr ""
#: src/modules/packages/main.py:810 #: src/modules/packages/main.py:816
msgid "" msgid ""
"The package manager could not make changes to the installed system. The " "The package manager could not make changes to the installed system. The "
"command <pre>{!s}</pre> returned error code {!s}." "command <pre>{!s}</pre> returned error code {!s}."

View File

@ -236,7 +236,7 @@ if(KPMcore_FOUND)
calamares_add_test(libcalamarespartitionkpmtest SOURCES partition/KPMTests.cpp LIBRARIES calamares::kpmcore) calamares_add_test(libcalamarespartitionkpmtest SOURCES partition/KPMTests.cpp LIBRARIES calamares::kpmcore)
endif() endif()
calamares_add_test(libcalamaresutilstest SOURCES utils/Tests.cpp utils/Runner.cpp) calamares_add_test(libcalamaresutilstest SOURCES utils/Tests.cpp utils/Permissions.cpp utils/Runner.cpp)
calamares_add_test(libcalamaresutilspathstest SOURCES utils/TestPaths.cpp) calamares_add_test(libcalamaresutilspathstest SOURCES utils/TestPaths.cpp)

View File

@ -60,9 +60,12 @@ public:
TimeZoneData( const TimeZoneData& ) = delete; TimeZoneData( const TimeZoneData& ) = delete;
TimeZoneData( TimeZoneData&& ) = delete; TimeZoneData( TimeZoneData&& ) = delete;
///@brief Returns a translated, human-readable form of region/zone (e.g. "America/New York")
QString translated() const override; QString translated() const override;
///@brief Returns the region key (e.g. "Europe") with no translation and no human-readable tweaks
QString region() const { return m_region; } QString region() const { return m_region; }
///@brief Returns the zone key (e.g. "New_York") with no translation and no human-readable tweaks
QString zone() const { return key(); } QString zone() const { return key(); }
QString country() const { return m_country; } QString country() const { return m_country; }

View File

@ -50,9 +50,8 @@ Permissions::parsePermissions( QString const& p )
return; return;
} }
bool ok; const auto octal = parseFileMode( segments[ 2 ] );
int octal = segments[ 2 ].toInt( &ok, 8 ); if ( octal <= 0 )
if ( !ok || octal == 0 )
{ {
m_valid = false; m_valid = false;
return; return;
@ -120,4 +119,24 @@ Permissions::apply( const QString& path, const Calamares::Permissions& p )
return r; return r;
} }
int
parseFileMode( const QString& mode )
{
bool ok;
int octal = mode.toInt( &ok, 8 );
if ( !ok )
{
return -1;
}
if ( 0777 < octal )
{
return -1;
}
if ( octal < 0 )
{
return -1;
}
return octal;
}
} // namespace Calamares } // namespace Calamares

View File

@ -16,8 +16,10 @@ namespace Calamares
{ {
/** /**
* @brief The Permissions class takes a QString @p in the form of * @brief Represents a <user>:<group>:<file-mode>
* <user>:<group>:<permissions>, checks it for validity, and makes the three *
* The Permissions class takes a QString @p in the form of
* <user>:<group>:<file-mode>, checks it for validity, and makes the three
* components available indivdually. * components available indivdually.
*/ */
class DLLEXPORT Permissions class DLLEXPORT Permissions
@ -27,8 +29,9 @@ public:
/** @brief Constructor /** @brief Constructor
* *
* Splits the string @p at the colon (":") into separate elements for * Splits the string @p at the colon (":") into separate elements for
* <user>, <group>, and <value> (permissions), where <value> is interpreted * <user>, <group>, and <file-mode> (permissions), where <file-mode> is any
* as an **octal** integer. That is, "root:wheel:755" will give * value that can be parsed by parseFileMode() . One valid form
* is an **octal** integer. That is, "root:wheel:755" will give
* you an integer value of four-hundred-ninety-three (493), * you an integer value of four-hundred-ninety-three (493),
* corresponding to the UNIX file permissions rwxr-xr-x, * corresponding to the UNIX file permissions rwxr-xr-x,
* as one would expect from chmod and other command-line utilities. * as one would expect from chmod and other command-line utilities.
@ -90,6 +93,17 @@ private:
bool m_valid; bool m_valid;
}; };
/**
* @brief Parses a file-mode and returns it as an integer
*
* Returns -1 on error.
*
* Valid forms of @p mode are:
* - octal representation, with an optional leading 0 and at most three
* octal digits (e.g. 0755 or 644)
*/
DLLEXPORT int parseFileMode( const QString& mode );
} // namespace Calamares } // namespace Calamares
#endif // LIBCALAMARES_PERMISSIONS_H #endif // LIBCALAMARES_PERMISSIONS_H

View File

@ -63,6 +63,7 @@ private Q_SLOTS:
/** @section Test that all the UMask objects work correctly. */ /** @section Test that all the UMask objects work correctly. */
void testUmask(); void testUmask();
void testPermissions();
/** @section Tests the entropy functions. */ /** @section Tests the entropy functions. */
void testEntropy(); void testEntropy();
@ -571,6 +572,24 @@ LibCalamaresTests::testUmask()
QCOMPARE( Calamares::setUMask( m ), mode_t( 022 ) ); QCOMPARE( Calamares::setUMask( m ), mode_t( 022 ) );
} }
void
LibCalamaresTests::testPermissions()
{
for ( int i = 0; i <= 0777; ++i )
{
const QString repr = QString::number( i, 8 );
QCOMPARE( Calamares::parseFileMode( repr ), i );
QCOMPARE( Calamares::parseFileMode( QChar( '0' ) + repr ), i );
QCOMPARE( Calamares::parseFileMode( QStringLiteral( " %1\n" ).arg( repr ) ), i );
}
// Failures
QCOMPARE( Calamares::parseFileMode( QStringLiteral( "1024" ) ), -1 );
QCOMPARE( Calamares::parseFileMode( QStringLiteral( "rwxr-----" ) ), -1 );
QCOMPARE( Calamares::parseFileMode( QStringLiteral( "o644" ) ), -1 );
QCOMPARE( Calamares::parseFileMode( QStringLiteral( "O_WRONLY" ) ), -1 );
}
void void
LibCalamaresTests::testEntropy() LibCalamaresTests::testEntropy()
{ {

View File

@ -11,19 +11,37 @@
#include "WaitingWidget.h" #include "WaitingWidget.h"
#include "utils/Gui.h" #include "utils/Gui.h"
#include "utils/Logger.h"
#include <QBoxLayout> #include <QBoxLayout>
#include <QEvent>
#include <QLabel> #include <QLabel>
#include <QTimer> #include <QTimer>
static void
colorSpinner( WaitingSpinnerWidget* spinner )
{
const auto color = spinner->palette().text().color();
spinner->setTextColor( color );
spinner->setColor( color );
}
static void
styleSpinner( WaitingSpinnerWidget* spinner, int size )
{
spinner->setFixedSize( size, size );
spinner->setInnerRadius( size / 2 );
spinner->setLineLength( size / 2 );
spinner->setLineWidth( size / 8 );
colorSpinner( spinner );
}
WaitingWidget::WaitingWidget( const QString& text, QWidget* parent ) WaitingWidget::WaitingWidget( const QString& text, QWidget* parent )
: WaitingSpinnerWidget( parent, false, false ) : WaitingSpinnerWidget( parent, false, false )
{ {
int spnrSize = Calamares::defaultFontHeight() * 4; int spnrSize = Calamares::defaultFontHeight() * 4;
setFixedSize( spnrSize, spnrSize ); styleSpinner( this, spnrSize );
setInnerRadius( spnrSize / 2 );
setLineLength( spnrSize / 2 );
setLineWidth( spnrSize / 8 );
setAlignment( Qt::AlignmentFlag::AlignBottom ); setAlignment( Qt::AlignmentFlag::AlignBottom );
setText( text ); setText( text );
start(); start();
@ -31,6 +49,16 @@ WaitingWidget::WaitingWidget( const QString& text, QWidget* parent )
WaitingWidget::~WaitingWidget() {} WaitingWidget::~WaitingWidget() {}
void
WaitingWidget::changeEvent( QEvent* event )
{
if ( event->type() == QEvent::PaletteChange )
{
colorSpinner( this );
}
WaitingSpinnerWidget::changeEvent( event );
}
struct CountdownWaitingWidget::Private struct CountdownWaitingWidget::Private
{ {
std::chrono::seconds duration; std::chrono::seconds duration;
@ -52,13 +80,8 @@ CountdownWaitingWidget::CountdownWaitingWidget( std::chrono::seconds duration, Q
{ {
// Set up the label first for sizing // Set up the label first for sizing
const int labelHeight = qBound( 16, Calamares::defaultFontHeight() * 3 / 2, 64 ); const int labelHeight = qBound( 16, Calamares::defaultFontHeight() * 3 / 2, 64 );
styleSpinner( this, labelHeight );
// Set up the spinner
setFixedSize( labelHeight, labelHeight );
setRevolutionsPerSecond( 1.0 / double( duration.count() ) ); setRevolutionsPerSecond( 1.0 / double( duration.count() ) );
setInnerRadius( labelHeight / 2 );
setLineLength( labelHeight / 2 );
setLineWidth( labelHeight / 8 );
setAlignment( Qt::AlignmentFlag::AlignVCenter ); setAlignment( Qt::AlignmentFlag::AlignVCenter );
// Last because it updates the text // Last because it updates the text
@ -117,3 +140,13 @@ CountdownWaitingWidget::tick()
timeout(); timeout();
} }
} }
void
CountdownWaitingWidget::changeEvent( QEvent* event )
{
if ( event->type() == QEvent::PaletteChange )
{
colorSpinner( this );
}
WaitingSpinnerWidget::changeEvent( event );
}

View File

@ -32,6 +32,9 @@ public:
/// Create a WaitingWidget with initial @p text label. /// Create a WaitingWidget with initial @p text label.
explicit WaitingWidget( const QString& text, QWidget* parent = nullptr ); explicit WaitingWidget( const QString& text, QWidget* parent = nullptr );
~WaitingWidget() override; ~WaitingWidget() override;
protected:
void changeEvent( QEvent* event ) override;
}; };
/** @brief A spinner and a countdown inside it /** @brief A spinner and a countdown inside it
@ -64,6 +67,9 @@ Q_SIGNALS:
protected Q_SLOTS: protected Q_SLOTS:
void tick(); void tick();
protected:
void changeEvent( QEvent* event ) override;
private: private:
struct Private; struct Private;
std::unique_ptr< Private > d; std::unique_ptr< Private > d;

View File

@ -11,7 +11,6 @@
#include "Config.h" #include "Config.h"
#include "SetKeyboardLayoutJob.h" #include "SetKeyboardLayoutJob.h"
#include "keyboardwidget/keyboardpreview.h"
#include "GlobalStorage.h" #include "GlobalStorage.h"
#include "JobQueue.h" #include "JobQueue.h"
@ -27,6 +26,7 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QProcess> #include <QProcess>
#include <QRegularExpression> #include <QRegularExpression>
#include <QStandardPaths>
#include <QTimer> #include <QTimer>
#include <QDBusConnection> #include <QDBusConnection>
@ -36,7 +36,7 @@
/* Returns stringlist with suitable setxkbmap command-line arguments /* Returns stringlist with suitable setxkbmap command-line arguments
* to set the given @p model. * to set the given @p model.
*/ */
static inline QStringList static QStringList
xkbmap_model_args( const QString& model ) xkbmap_model_args( const QString& model )
{ {
QStringList r { "-model", model }; QStringList r { "-model", model };
@ -46,7 +46,7 @@ xkbmap_model_args( const QString& model )
/* Returns stringlist with suitable setxkbmap command-line arguments /* Returns stringlist with suitable setxkbmap command-line arguments
* to set the given @p layout and @p variant. * to set the given @p layout and @p variant.
*/ */
static inline QStringList static QStringList
xkbmap_layout_args( const QString& layout, const QString& variant ) xkbmap_layout_args( const QString& layout, const QString& variant )
{ {
QStringList r { "-layout", layout }; QStringList r { "-layout", layout };
@ -57,10 +57,10 @@ xkbmap_layout_args( const QString& layout, const QString& variant )
return r; return r;
} }
static inline QStringList static QStringList
xkbmap_layout_args( const QStringList& layouts, xkbmap_layout_args_with_group_switch( const QStringList& layouts,
const QStringList& variants, const QStringList& variants,
const QString& switchOption = "grp:alt_shift_toggle" ) const QString& switchOption )
{ {
if ( layouts.size() != variants.size() ) if ( layouts.size() != variants.size() )
{ {
@ -161,24 +161,16 @@ Config::Config( QObject* parent )
, m_keyboardVariantsModel( new KeyboardVariantsModel( this ) ) , m_keyboardVariantsModel( new KeyboardVariantsModel( this ) )
, m_KeyboardGroupSwitcherModel( new KeyboardGroupsSwitchersModel( this ) ) , m_KeyboardGroupSwitcherModel( new KeyboardGroupsSwitchersModel( this ) )
{ {
m_setxkbmapTimer.setSingleShot( true ); m_applyTimer.setSingleShot( true );
connect( &m_applyTimer, &QTimer::timeout, this, &Config::apply );
// Connect signals and slots // Connect signals and slots
connect( m_keyboardModelsModel, connect( m_keyboardModelsModel,
&KeyboardModelsModel::currentIndexChanged, &KeyboardModelsModel::currentIndexChanged,
[ & ]( int index ) [ & ]( int index )
{ {
// Set Xorg keyboard model
m_selectedModel = m_keyboardModelsModel->key( index ); m_selectedModel = m_keyboardModelsModel->key( index );
if ( m_useLocale1 ) somethingChanged();
{
locale1Apply();
}
else
{
QProcess::execute( "setxkbmap", xkbmap_model_args( m_selectedModel ) );
}
emit prettyStatusChanged();
} ); } );
connect( m_keyboardLayoutsModel, connect( m_keyboardLayoutsModel,
@ -195,16 +187,14 @@ Config::Config( QObject* parent )
[ & ]( int index ) [ & ]( int index )
{ {
m_selectedVariant = m_keyboardVariantsModel->key( index ); m_selectedVariant = m_keyboardVariantsModel->key( index );
xkbChanged(); somethingChanged();
emit prettyStatusChanged();
} ); } );
connect( m_KeyboardGroupSwitcherModel, connect( m_KeyboardGroupSwitcherModel,
&KeyboardGroupsSwitchersModel::currentIndexChanged, &KeyboardGroupsSwitchersModel::currentIndexChanged,
[ & ]( int index ) [ & ]( int index )
{ {
m_selectedGroup = m_KeyboardGroupSwitcherModel->key( index ); m_selectedGroup = m_KeyboardGroupSwitcherModel->key( index );
xkbChanged(); somethingChanged();
emit prettyStatusChanged();
} ); } );
// If the user picks something explicitly -- not a consequence of // If the user picks something explicitly -- not a consequence of
@ -224,30 +214,36 @@ Config::Config( QObject* parent )
} }
void void
Config::xkbChanged() Config::somethingChanged()
{ {
// Set Xorg keyboard layout + variant if ( m_applyTimer.isActive() )
if ( m_setxkbmapTimer.isActive() )
{ {
m_setxkbmapTimer.stop(); m_applyTimer.stop();
m_setxkbmapTimer.disconnect( this );
} }
m_applyTimer.start( QApplication::keyboardInputInterval() );
if ( m_useLocale1 )
{
connect( &m_setxkbmapTimer, &QTimer::timeout, this, &Config::locale1Apply );
}
else
{
connect( &m_setxkbmapTimer, &QTimer::timeout, this, &Config::xkbApply );
}
m_setxkbmapTimer.start( QApplication::keyboardInputInterval() );
emit prettyStatusChanged(); emit prettyStatusChanged();
} }
void void
Config::locale1Apply() Config::apply()
{
if ( m_configureXkb )
{
applyXkb();
}
if ( m_configureLocale1 )
{
applyLocale1();
}
if ( m_configureKWin )
{
applyKWin();
}
// Writing /etc/ files is not needed "live"
}
void
Config::applyLocale1()
{ {
m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout ); m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout );
@ -283,10 +279,11 @@ Config::locale1Apply()
} }
void void
Config::xkbApply() Config::applyXkb()
{ {
m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout ); m_additionalLayoutInfo = getAdditionalLayoutInfo( m_selectedLayout );
QStringList basicArguments = xkbmap_model_args( m_selectedModel );
if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() ) if ( !m_additionalLayoutInfo.additionalLayout.isEmpty() )
{ {
if ( !m_selectedGroup.isEmpty() ) if ( !m_selectedGroup.isEmpty() )
@ -303,10 +300,11 @@ Config::xkbApply()
m_additionalLayoutInfo.groupSwitcher = "grp:alt_shift_toggle"; m_additionalLayoutInfo.groupSwitcher = "grp:alt_shift_toggle";
} }
QProcess::execute( "setxkbmap", basicArguments.append(
xkbmap_layout_args( { m_additionalLayoutInfo.additionalLayout, m_selectedLayout }, xkbmap_layout_args_with_group_switch( { m_additionalLayoutInfo.additionalLayout, m_selectedLayout },
{ m_additionalLayoutInfo.additionalVariant, m_selectedVariant }, { m_additionalLayoutInfo.additionalVariant, m_selectedVariant },
m_additionalLayoutInfo.groupSwitcher ) ); m_additionalLayoutInfo.groupSwitcher ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant << "(added " cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant << "(added "
<< m_additionalLayoutInfo.additionalLayout << "-" << m_additionalLayoutInfo.additionalVariant << m_additionalLayoutInfo.additionalLayout << "-" << m_additionalLayoutInfo.additionalVariant
@ -314,12 +312,92 @@ Config::xkbApply()
} }
else else
{ {
QProcess::execute( "setxkbmap", xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) ); basicArguments.append( xkbmap_layout_args( m_selectedLayout, m_selectedVariant ) );
QProcess::execute( "setxkbmap", basicArguments );
cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant; cDebug() << "xkbmap selection changed to: " << m_selectedLayout << '-' << m_selectedVariant;
} }
m_setxkbmapTimer.disconnect( this ); m_applyTimer.stop();
} }
// In a config-file's list of lines, replace lines <key>=<something> by <key>=<value>
static void
replaceKey( QStringList& content, const QString& key, const QString& value )
{
for ( int i = 0; i < content.length(); ++i )
{
if ( content.at( i ).startsWith( key ) )
{
content[ i ] = key + value;
}
}
}
static bool
rewriteKWin( const QString& path, const QString& model, const QString& layouts, const QString& variants )
{
if ( !QFile::exists( path ) )
{
return false;
}
QFile config( path );
if ( !config.open( QIODevice::ReadOnly ) )
{
return false;
}
QStringList content = []( QFile& f )
{
QTextStream s( &f );
return s.readAll().split( '\n' );
}( config );
config.close();
if ( !config.open( QIODevice::WriteOnly ) )
{
return false;
}
replaceKey( content, QStringLiteral( "Model=" ), model );
replaceKey( content, QStringLiteral( "LayoutList=" ), layouts );
replaceKey( content, QStringLiteral( "VariantList=" ), variants );
config.write( content.join( '\n' ).toUtf8() );
config.close();
return true;
}
void
Config::applyKWin()
{
const auto paths = QStandardPaths::standardLocations( QStandardPaths::ConfigLocation );
auto join = [ &additional = m_additionalLayoutInfo.additionalLayout ]( const QString& s1, const QString& s2 )
{ return additional.isEmpty() ? s1 : QStringLiteral( "%1,%2" ).arg( s1, s2 ); };
const QString layouts = join( m_selectedLayout, m_additionalLayoutInfo.additionalLayout );
const QString variants = join( m_selectedVariant, m_additionalLayoutInfo.additionalVariant );
bool updated = false;
for ( const auto& path : paths )
{
const QString candidate = path + QStringLiteral( "/kxkbrc" );
if ( rewriteKWin( candidate, m_selectedModel, layouts, variants ) )
{
updated = true;
break;
}
}
if ( updated )
{
auto kwin = QDBusMessage::createSignal(
QStringLiteral( "/Layouts" ), QStringLiteral( "org.kde.keyboard" ), QStringLiteral( "reloadConfig" ) );
QDBusConnection::sessionBus().send( kwin );
}
}
KeyboardModelsModel* KeyboardModelsModel*
Config::keyboardModels() const Config::keyboardModels() const
{ {
@ -455,7 +533,7 @@ Config::detectCurrentKeyboardLayout()
QString currentVariant; QString currentVariant;
QString currentModel; QString currentModel;
if ( m_useLocale1 ) if ( m_configureLocale1 )
{ {
getCurrentKeyboardLayoutLocale1( currentLayout, currentVariant, currentModel ); getCurrentKeyboardLayoutLocale1( currentLayout, currentVariant, currentModel );
} }
@ -501,10 +579,10 @@ Config::detectCurrentKeyboardLayout()
QString QString
Config::prettyStatus() const Config::prettyStatus() const
{ {
QString status; QString status
status = tr( "Keyboard model has been set to %1.", "@label, %1 is keyboard model, as in Apple Magic Keyboard" )
+= tr( "Keyboard model has been set to %1<br/>.", "@label, %1 is keyboard model, as in Apple Magic Keyboard" ) .arg( m_keyboardModelsModel->label( m_keyboardModelsModel->currentIndex() ) );
.arg( m_keyboardModelsModel->label( m_keyboardModelsModel->currentIndex() ) ); status += QStringLiteral( "<br/>" );
QString layout = m_keyboardLayoutsModel->item( m_keyboardLayoutsModel->currentIndex() ).second.description; QString layout = m_keyboardLayoutsModel->item( m_keyboardLayoutsModel->currentIndex() ).second.description;
QString variant = m_keyboardVariantsModel->currentIndex() >= 0 QString variant = m_keyboardVariantsModel->currentIndex() >= 0
@ -527,8 +605,8 @@ Config::createJobs()
m_additionalLayoutInfo, m_additionalLayoutInfo,
m_xOrgConfFileName, m_xOrgConfFileName,
m_convertedKeymapPath, m_convertedKeymapPath,
m_writeEtcDefaultKeyboard, m_configureEtcDefaultKeyboard,
m_useLocale1 ); m_configureLocale1 );
list.append( Calamares::job_ptr( j ) ); list.append( Calamares::job_ptr( j ) );
return list; return list;
@ -718,8 +796,13 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
m_xOrgConfFileName = xorgConfDefault; m_xOrgConfFileName = xorgConfDefault;
} }
m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" ); m_convertedKeymapPath = getString( configurationMap, "convertedKeymapPath" );
m_writeEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true ); m_configureEtcDefaultKeyboard = getBool( configurationMap, "writeEtcDefaultKeyboard", true );
m_useLocale1 = getBool( configurationMap, "useLocale1", !isX11 ); m_configureLocale1 = getBool( configurationMap, "useLocale1", !isX11 );
bool bogus = false;
const auto configureItems = getSubMap( configurationMap, "configure", bogus );
m_configureKWin = getBool( configureItems, "kwin", false );
m_guessLayout = getBool( configurationMap, "guessLayout", true ); m_guessLayout = getBool( configurationMap, "guessLayout", true );
} }

View File

@ -86,14 +86,17 @@ private:
* keyboard layout. This introduces a slight delay between selecting * keyboard layout. This introduces a slight delay between selecting
* a keyboard, and applying it to the system -- so that if you * a keyboard, and applying it to the system -- so that if you
* scroll through or down-arrow through the list of keyboards, * scroll through or down-arrow through the list of keyboards,
* you don't get buried under xkbset processes. * you don't get buried under updates which might take some time.
* *
* xkbChanged() is called when the selection changes, and triggers * somethingChanged() is called when the selection changes, and triggers
* a delayed call to xkbApply() which does the actual work. * a delayed call to apply() which does the actual work by calling the
* relevant apply*() functions.
*/ */
void xkbChanged(); void somethingChanged();
void xkbApply(); void apply();
void locale1Apply(); void applyLocale1();
void applyXkb();
void applyKWin();
void getCurrentKeyboardLayoutXkb( QString& currentLayout, QString& currentVariant, QString& currentModel ); void getCurrentKeyboardLayoutXkb( QString& currentLayout, QString& currentVariant, QString& currentModel );
void getCurrentKeyboardLayoutLocale1( QString& currentLayout, QString& currentVariant, QString& currentModel ); void getCurrentKeyboardLayoutLocale1( QString& currentLayout, QString& currentVariant, QString& currentModel );
@ -111,13 +114,15 @@ private:
// Layout (and corresponding info) added if current one doesn't support ASCII (e.g. Russian or Japanese) // Layout (and corresponding info) added if current one doesn't support ASCII (e.g. Russian or Japanese)
AdditionalLayoutInfo m_additionalLayoutInfo; AdditionalLayoutInfo m_additionalLayoutInfo;
QTimer m_setxkbmapTimer; QTimer m_applyTimer;
// From configuration // From configuration
QString m_xOrgConfFileName; QString m_xOrgConfFileName;
QString m_convertedKeymapPath; QString m_convertedKeymapPath;
bool m_writeEtcDefaultKeyboard = true; bool m_configureXkb = true;
bool m_useLocale1 = false; bool m_configureEtcDefaultKeyboard = true;
bool m_configureLocale1 = false;
bool m_configureKWin = false;
bool m_guessLayout = false; bool m_guessLayout = false;
// The state determines whether we guess settings or preserve them: // The state determines whether we guess settings or preserve them:

View File

@ -31,3 +31,15 @@ convertedKeymapPath: "/lib/kbd/keymaps/xkb"
# Guess the default layout from the user locale. If false, keeps the current # Guess the default layout from the user locale. If false, keeps the current
# OS keyboard layout as the default (useful if the layout is pre-configured). # OS keyboard layout as the default (useful if the layout is pre-configured).
#guessLayout: true #guessLayout: true
# Things that should be configured.
configure:
# Configure KWin (KDE Plasma) directly by editing the
# configuration file and informing KWin over DBus. This is
# useful in a system that uses Wayland but does **not** connect
# locale1 with KWin.
#
# Systems that use KDE Plasma Wayland and locale1 can instead start the
# compositor KWin with command-line argument `--locale1`. That
# argument makes this configuration option unnecessary.
kwin: false

View File

@ -11,4 +11,9 @@ properties:
writeEtcDefaultKeyboard: { type: boolean, default: true } writeEtcDefaultKeyboard: { type: boolean, default: true }
useLocale1: { type: boolean, default: false } useLocale1: { type: boolean, default: false }
guessLayout: { type: boolean, default: true } guessLayout: { type: boolean, default: true }
configure:
additionalProperties: false
type: object
properties:
kwin: { type: boolean, default: false }
required: [ xOrgConfFileName, convertedKeymapPath ] required: [ xOrgConfFileName, convertedKeymapPath ]

View File

@ -376,9 +376,11 @@ Config::setLCLocaleExplicitly( const QString& locale )
QString QString
Config::currentLocationStatus() const Config::currentLocationStatus() const
{ {
return tr( "Set timezone to %1/%2", "@action" ) if ( m_currentLocation )
.arg( m_currentLocation ? m_currentLocation->region() : QString(), {
m_currentLocation ? m_currentLocation->zone() : QString() ); return tr( "Set timezone to %1.", "@action" ).arg( currentTimezoneName());
}
return QString();
} }
QString QString

View File

@ -78,6 +78,18 @@ unmountTargetMounts( const QString& rootMountPoint )
.arg( m.device, m.mountPoint ) ); .arg( m.device, m.mountPoint ) );
} }
} }
// Last we unmount the root
if ( Calamares::Partition::unmount( rootMountPoint, { "-lv" } ) )
{
return Calamares::JobResult::error(
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
"Could not unmount the root of the target system." ),
QCoreApplication::translate( UmountJob::staticMetaObject.className(),
"The device mounted at '%1' could not be unmounted." )
.arg( rootMountPoint ) );
}
return Calamares::JobResult::ok(); return Calamares::JobResult::ok();
} }
@ -139,6 +151,7 @@ UmountJob::exec()
return r; return r;
} }
} }
// For ZFS systems, export the pools // For ZFS systems, export the pools
{ {
auto r = exportZFSPools(); auto r = exportZFSPools();

View File

@ -19,6 +19,7 @@
#include "JobQueue.h" #include "JobQueue.h"
#include "compat/Variant.h" #include "compat/Variant.h"
#include "utils/Logger.h" #include "utils/Logger.h"
#include "utils/Permissions.h"
#include "utils/String.h" #include "utils/String.h"
#include "utils/StringExpander.h" #include "utils/StringExpander.h"
#include "utils/Variant.h" #include "utils/Variant.h"
@ -946,6 +947,21 @@ Config::setConfigurationMap( const QVariantMap& configurationMap )
m_forbiddenLoginNames = Calamares::getStringList( userSettings, "forbidden_names" ); m_forbiddenLoginNames = Calamares::getStringList( userSettings, "forbidden_names" );
m_forbiddenLoginNames << alwaysForbiddenLoginNames(); m_forbiddenLoginNames << alwaysForbiddenLoginNames();
tidy( m_forbiddenLoginNames ); tidy( m_forbiddenLoginNames );
const auto permissionKey = QStringLiteral( "home_permissions" );
if ( userSettings.contains( permissionKey ) )
{
const auto value = Calamares::getString( userSettings, permissionKey );
m_homeDirPermissions = Calamares::parseFileMode( value );
if ( m_homeDirPermissions < 0 )
{
cWarning() << "Setting for" << permissionKey << '(' << value << userSettings[permissionKey] << ") is invalid.";
}
}
else
{
m_homeDirPermissions = -1;
}
} }
setAutoLoginGroup( either< QString, const QString& >( setAutoLoginGroup( either< QString, const QString& >(

View File

@ -259,6 +259,9 @@ public:
const QStringList& forbiddenLoginNames() const; const QStringList& forbiddenLoginNames() const;
const QStringList& forbiddenHostNames() const; const QStringList& forbiddenHostNames() const;
int homePermissions() const { return m_homeDirPermissions; }
int homeUMask() const { return m_homeDirPermissions >= 0 ? ( ( ~m_homeDirPermissions ) & 0777 ) : -1; }
public Q_SLOTS: public Q_SLOTS:
/** @brief Sets the user's shell if possible /** @brief Sets the user's shell if possible
* *
@ -368,6 +371,8 @@ private:
QStringList m_forbiddenLoginNames; QStringList m_forbiddenLoginNames;
PasswordCheckList m_passwordChecks; PasswordCheckList m_passwordChecks;
int m_homeDirPermissions = -1;
}; };
#endif #endif

View File

@ -46,7 +46,7 @@ CreateUserJob::prettyStatusMessage() const
} }
static Calamares::JobResult static Calamares::JobResult
createUser( const QString& loginName, const QString& fullName, const QString& shell ) createUser( const QString& loginName, const QString& fullName, const QString& shell, int umask )
{ {
QStringList useraddCommand; QStringList useraddCommand;
#ifdef __FreeBSD__ #ifdef __FreeBSD__
@ -67,6 +67,10 @@ createUser( const QString& loginName, const QString& fullName, const QString& sh
useraddCommand << "-s" << shell; useraddCommand << "-s" << shell;
} }
useraddCommand << "-c" << fullName; useraddCommand << "-c" << fullName;
if ( umask >= 0 )
{
useraddCommand << "-K" << ( QStringLiteral( "UMASK=" ) + QString::number( umask, 8 ) );
}
useraddCommand << loginName; useraddCommand << loginName;
#endif #endif
@ -136,7 +140,8 @@ CreateUserJob::exec()
m_status = tr( "Creating user %1…", "@status" ).arg( m_config->loginName() ); m_status = tr( "Creating user %1…", "@status" ).arg( m_config->loginName() );
emit progress( 0.5 ); emit progress( 0.5 );
auto useraddResult = createUser( m_config->loginName(), m_config->fullName(), m_config->userShell() ); auto useraddResult
= createUser( m_config->loginName(), m_config->fullName(), m_config->userShell(), m_config->homeUMask() );
if ( !useraddResult ) if ( !useraddResult )
{ {
return useraddResult; return useraddResult;

View File

@ -56,6 +56,8 @@ private Q_SLOTS:
void testUserYAML_data(); void testUserYAML_data();
void testUserYAML(); void testUserYAML();
void testUserUmask_data();
void testUserUmask();
}; };
UserTests::UserTests() {} UserTests::UserTests() {}
@ -511,6 +513,56 @@ UserTests::testUserYAML()
QCOMPARE( c.userShell(), shell ); QCOMPARE( c.userShell(), shell );
} }
void
UserTests::testUserUmask_data()
{
QTest::addColumn< QString >( "filename" );
QTest::addColumn< int >( "permission" );
QTest::addColumn< int >( "umask" );
QTest::newRow( "good " ) << "tests/8a-issue-2362.conf" << 0700 << 0077;
QTest::newRow( "open " ) << "tests/8b-issue-2362.conf" << 0755 << 0022;
QTest::newRow( "weird" ) << "tests/8c-issue-2362.conf" << 0126 << 0651;
}
void
UserTests::testUserUmask()
{
static constexpr int no_permissions = -1;
const QString old_shell = QStringLiteral( "/bin/ls" );
const QString new_shell = QStringLiteral( "/usr/bin/new" );
const QStringList forbidden { QStringLiteral( "me" ), QStringLiteral( "myself" ), QStringLiteral( "moi" ) };
Config c;
c.setUserShell( old_shell );
QCOMPARE( c.homePermissions(), no_permissions );
QCOMPARE( c.homeUMask(), no_permissions );
QFETCH( QString, filename );
QFETCH( int, permission );
QFETCH( int, umask );
QCOMPARE( permission & umask, 0 );
QCOMPARE( permission | umask, 0777 );
QFileInfo fi( QString( "%1/%2" ).arg( BUILD_AS_TEST, filename ) );
QVERIFY( fi.exists() );
bool ok = false;
const auto map = Calamares::YAML::load( fi, &ok );
QVERIFY( ok );
QVERIFY( map.count() > 0 );
QCOMPARE( c.userShell(), old_shell );
c.setConfigurationMap( map );
QCOMPARE( c.userShell(), new_shell );
QCOMPARE( c.homePermissions(), permission );
QCOMPARE( c.homeUMask(), umask );
QCOMPARE( c.forbiddenLoginNames(), forbidden );
}
QTEST_GUILESS_MAIN( UserTests ) QTEST_GUILESS_MAIN( UserTests )
#include "utils/moc-warnings.h" #include "utils/moc-warnings.h"

View File

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
#
---
user:
shell: /usr/bin/new
forbidden_names:
- me
- myself
- moi
home_permissions: "700"

View File

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
#
---
user:
shell: /usr/bin/new
forbidden_names:
- me
- myself
- moi
home_permissions: "755"

View File

@ -0,0 +1,11 @@
# SPDX-FileCopyrightText: no
# SPDX-License-Identifier: CC0-1.0
#
---
user:
shell: /usr/bin/new
forbidden_names:
- me
- myself
- moi
home_permissions: "126"

View File

@ -214,9 +214,15 @@ allowWeakPasswordsDefault: false
# contains "root" and "nobody", but may be extended to list other special # contains "root" and "nobody", but may be extended to list other special
# names for a given distro (eg. "video", or "mysql" might not be a valid # names for a given distro (eg. "video", or "mysql" might not be a valid
# end-user login name). # end-user login name).
# - *home_permissions* Home directory of the user is given **approximately**
# this set of permissions. Write the permissions in octal. If not set,
# there is no default and no permission-setting is done (uses defaults of
# `useradd` in the target). A umask is computed from these permissions
# and passed to `useradd`. Take care to quote the numeric value.
user: user:
shell: /bin/bash shell: /bin/bash
forbidden_names: [ root ] forbidden_names: [ root ]
home_permissions: "0700"
# Hostname settings # Hostname settings

View File

@ -13,6 +13,7 @@ properties:
# User shell, should be path to /bin/sh or so # User shell, should be path to /bin/sh or so
shell: { type: string } shell: { type: string }
forbidden_names: { type: array, items: { type: string } } forbidden_names: { type: array, items: { type: string } }
home_permissions: { type: string }
# Group settings # Group settings
defaultGroups: defaultGroups:
type: array type: array

View File

@ -35,7 +35,7 @@ paintRequirement( QPainter* painter, const QStyleOptionViewItem& option, const Q
Calamares::ImageType statusImage = Calamares::StatusOk; Calamares::ImageType statusImage = Calamares::StatusOk;
painter->setPen( Qt::black ); painter->setPen( option.palette.text().color() );
if ( index.data( Calamares::RequirementsModel::Satisfied ).toBool() ) if ( index.data( Calamares::RequirementsModel::Satisfied ).toBool() )
{ {
painter->fillRect( textRect, option.palette.window().color() ); painter->fillRect( textRect, option.palette.window().color() );