Compare commits
78 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5d6375dab7 | ||
![]() |
546780d7a8 | ||
![]() |
ac083f787d | ||
![]() |
bca4b73677 | ||
![]() |
da2612d2d9 | ||
![]() |
08cd79f0c2 | ||
![]() |
4811c59e33 | ||
![]() |
11f3f938d8 | ||
![]() |
85a3d1dc84 | ||
![]() |
6101dd9079 | ||
![]() |
79a91b486a | ||
![]() |
2aaaabe152 | ||
![]() |
a93126a6d0 | ||
![]() |
112d0b2e90 | ||
![]() |
98bbc222cb | ||
![]() |
fad23c9ac6 | ||
![]() |
e6813949af | ||
![]() |
4be932ff9d | ||
![]() |
8eb7eb8b1f | ||
![]() |
a8f6596d38 | ||
![]() |
b227419f01 | ||
![]() |
da03e12b7b | ||
![]() |
f349a9c864 | ||
![]() |
624bb13736 | ||
![]() |
94bca61491 | ||
![]() |
ee2fea74df | ||
![]() |
1f9ae6cae6 | ||
![]() |
e14fa5de75 | ||
![]() |
626ab98949 | ||
![]() |
3be6946d93 | ||
![]() |
475c0d21a1 | ||
![]() |
c2ae5fad96 | ||
![]() |
4fe5f1c06f | ||
![]() |
4e61f24960 | ||
![]() |
1c853941dc | ||
![]() |
7cfa654a68 | ||
![]() |
7864ab5cfa | ||
![]() |
905f1241e3 | ||
![]() |
f0aba5db96 | ||
![]() |
480fe56ae3 | ||
![]() |
728315d3cc | ||
![]() |
da72e815dc | ||
![]() |
0145f6fe7d | ||
![]() |
cfeba736d5 | ||
![]() |
be18e51bc9 | ||
![]() |
7fc2859f23 | ||
![]() |
587a18a6fa | ||
![]() |
043619cd4b | ||
![]() |
f04394d014 | ||
![]() |
07354a26a9 | ||
![]() |
fdf0f208f0 | ||
![]() |
6680584724 | ||
![]() |
c5573a1997 | ||
![]() |
b8ce21d572 | ||
![]() |
1356012fb4 | ||
![]() |
8bb2c5fc6b | ||
![]() |
dc7a1e43b7 | ||
![]() |
53c90516b2 | ||
![]() |
d3ed5663d0 | ||
![]() |
778c2855f4 | ||
![]() |
445ed870cc | ||
![]() |
3be52f8b37 | ||
![]() |
a1b7ba0dc5 | ||
![]() |
8b5e49d980 | ||
![]() |
90f6ea1fc8 | ||
![]() |
238672ef78 | ||
![]() |
b1ecbb4151 | ||
![]() |
795b2c88e8 | ||
![]() |
becb1d5710 | ||
![]() |
5b225cf960 | ||
![]() |
6261f8a5cb | ||
![]() |
132ebd2c2d | ||
![]() |
3870851074 | ||
![]() |
046a228d62 | ||
![]() |
2c20a00cc3 | ||
![]() |
45d6eb36fb | ||
![]() |
7ea21663ca | ||
![]() |
5ca029df25 |
38
CHANGES-3.2
38
CHANGES-3.2
@@ -7,6 +7,44 @@ contributors are listed. Note that Calamares does not have a historical
|
||||
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||
website will have to do for older versions.
|
||||
|
||||
# 3.2.50 (2022-01-18) #
|
||||
|
||||
This release contains contributions from (alphabetically by first name):
|
||||
- Anke Boersma
|
||||
- Erik Dubois
|
||||
- Evan James
|
||||
- Johannes Kamprad
|
||||
- Taejun Park (new contributor, welcome!)
|
||||
|
||||
**Replacement notice:** The *umount* module will be replaced by a C++
|
||||
implementation in the next release. The "preserve log file" feature
|
||||
will be removed in that release. Use the *preservefiles* module instead.
|
||||
|
||||
## Core ##
|
||||
- No core changes yet
|
||||
|
||||
## Modules ##
|
||||
- *initcpiocfg* mentioned a special kernel-name "all", which did not work,
|
||||
and a special kernel-name "$uname" which cannot work. Fixed the former
|
||||
and removed the "$uname" special key. (Thanks Evan)
|
||||
- *luksswaphookcfg* has been converted to a C++ module.
|
||||
- *networkcfg* could fail to update the NetworkManager configuration
|
||||
if the SSID or username contained non-ASCII characters **and** the
|
||||
default Python text-file encoding was set to ASCII. The files are
|
||||
now read and written in UTF-8, explicitly. #1848
|
||||
- *partition* always sets *bigtime* option on XFS filesystems, if possible.
|
||||
Requires sufficiently-recent xfsprogs. #1874
|
||||
- *preservefiles* was missing some necessary features, needed for it
|
||||
to replace the deprecated log-file-saving functionality in the *umount*
|
||||
module. (Thanks Erik and Joe for testing) #1851
|
||||
- *umount* is now marked as an emergency module in the example configuration,
|
||||
since it should **probably** be run as a cleanup. (Thanks Evan)
|
||||
- *welcome* and *locale* could be confusing, together, and configure
|
||||
the target system with a language that does not match the installer
|
||||
language, even though the user did not make any explicit choice.
|
||||
(Thanks Taejun) #1864
|
||||
|
||||
|
||||
# 3.2.49.1 (2021-12-11) #
|
||||
|
||||
This is a hot-fix release, to fix a regression in the calculation of
|
||||
|
@@ -41,7 +41,7 @@
|
||||
# TODO:3.3: Require CMake 3.12
|
||||
cmake_minimum_required( VERSION 3.3 FATAL_ERROR )
|
||||
project( CALAMARES
|
||||
VERSION 3.2.49.1
|
||||
VERSION 3.2.50
|
||||
LANGUAGES C CXX
|
||||
)
|
||||
|
||||
@@ -135,15 +135,15 @@ set( CALAMARES_DESCRIPTION_SUMMARY
|
||||
# NOTE: update these lines by running `txstats.py`, or for full automation
|
||||
# `txstats.py -e`. See also
|
||||
#
|
||||
# Total 81 languages
|
||||
set( _tx_complete az az_AZ ca de fa fi_FI he hr ja ko lt pt_PT si
|
||||
sq tr_TR uk zh_TW )
|
||||
set( _tx_good as be ca@valencia cs_CZ da fr fur hi it_IT ml nl
|
||||
pt_BR ru sk sv tg vi zh_CN )
|
||||
# Total 74 languages
|
||||
set( _tx_complete az az_AZ ca de fa fi_FI he hi hr ja ko lt pt_BR
|
||||
pt_PT si sq sv tr_TR uk zh_TW )
|
||||
set( _tx_good as be ca@valencia cs_CZ da fr fur it_IT ml nl ru sk
|
||||
tg vi zh_CN )
|
||||
set( _tx_ok ar ast bg bn el en_GB es es_MX et eu gl hu id is mr nb
|
||||
pl ro sl sr sr@latin th )
|
||||
set( _tx_incomplete en_HK en_IN eo es_PE es_PR fr_CH gu hi_IN id_ID
|
||||
ie kk kn ko_KR lo lv mk ne ne_NP te te_IN ur zh zh_HK )
|
||||
set( _tx_incomplete eo es_PR gu ie kk kn lo lv mk ne ne_NP ta_IN te
|
||||
ur zh zh_HK )
|
||||
|
||||
### Required versions
|
||||
#
|
||||
|
@@ -8,7 +8,7 @@
|
||||
[](https://github.com/calamares/calamares/labels/hacking%3A%20in-progress)
|
||||
[](https://github.com/calamares/calamares/releases)
|
||||
[](https://github.com/calamares/calamares/actions?query=workflow%3Aci)
|
||||
[](https://github.com/calamares/calamares/blob/calamares/LICENSE)
|
||||
[](https://github.com/calamares/calamares/blob/calamares/LICENSES/GPL-3.0-or-later.txt)
|
||||
|
||||
|
||||
| [Report a Bug](https://github.com/calamares/calamares/issues/new) | [Translate](https://www.transifex.com/projects/p/calamares/) | [Contribute](CONTRIBUTING.md) | [Matrix: #calamares:kde.org](https://webchat.kde.org/#/room/%23calamares:kde.org) | [IRC: Libera.Chat #calamares](https://kiwiirc.com/client/irc.libera.chat/#calamares) | [Wiki](https://github.com/calamares/calamares/wiki) |
|
||||
|
@@ -693,27 +693,27 @@ Instalační program bude ukončen a všechny změny ztraceny.</translation>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně odpojeno %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vypnut swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vyčištěn swap %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně zavřeno mapper zařízení %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Úspěšně vypnuta skupina svazků %1.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
@@ -1989,7 +1989,7 @@ The installer will quit and all changes will be lost.</translation>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||
<source>Configuration Error</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Configuration Error </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
||||
|
@@ -689,27 +689,27 @@ The installer will quit and all changes will be lost.</source>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 को माउंट से हटाना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 स्वैप निष्क्रिय करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 स्वैप रिक्त करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>प्रतिचित्रण उपकरण %1 बंद करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>वॉल्यूम समूह %1 निष्क्रिय करना सफल।</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kelola pengaturan mount otomatis</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -114,12 +114,12 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<source>Uploads the session log to the configured pastebin.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Unggah catatan sesi ke pastebin yang telah dikonfigurasi.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
<source>Send Session Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kirim Catatan Sesi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||
@@ -165,7 +165,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/JobExample.cpp" line="30"/>
|
||||
<source>Programmed job failure was explicitly requested.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kegagalan pekerjaan diprogram diminta secara eksplisit. </translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -189,7 +189,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||
<source>Run command '%1' in target system.</source>
|
||||
<translation>Jalankan perintah '%1' di dalam sistem target.</translation>
|
||||
<translation>Jalankan perintah '%1' pada sistem target.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||
@@ -245,7 +245,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/>
|
||||
<source>QML Step <i>%1</i>.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>QML Langkah <i>%1</i>.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/>
|
||||
@@ -277,7 +277,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/>
|
||||
<source>System-requirements checking is complete.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Pengecekan kebutuhan sistem telah selesai.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -295,7 +295,7 @@
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
|
||||
<source>Would you like to paste the install log to the web?</source>
|
||||
<translation>Maukah anda untuk menempelkan log instalasi ke situs?</translation>
|
||||
<translation>Maukah anda menempelkan log instalasi ke situs?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
|
||||
@@ -429,7 +429,7 @@ Link copied to clipboard</source>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/>
|
||||
<source>&Done</source>
|
||||
<translation>&Kelar</translation>
|
||||
<translation>&Selesai</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/>
|
||||
@@ -1054,12 +1054,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/>
|
||||
<source>Label for the filesystem</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label untuk filesystem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/>
|
||||
<source>FS Label:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label FS:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/>
|
||||
@@ -1418,12 +1418,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/>
|
||||
<source>Label for the filesystem</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label untuk filesystem</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/>
|
||||
<source>FS Label:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Label FS:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/>
|
||||
@@ -1582,7 +1582,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/>
|
||||
<source>Format partition %1 (file system: %2, size: %3 MiB) on %4.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Format partisi %1 (file system: %2, ukuran %3 MiB) pada %4.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/>
|
||||
@@ -1645,12 +1645,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/>
|
||||
<source>is running the installer as an administrator (root)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>menjalankan installer sebagai administrator (root)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/>
|
||||
<source>The setup program is not running with administrator rights.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Installer tidak dijalankan dengan kewenangan administrator.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/>
|
||||
@@ -1699,7 +1699,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/oemid/IDJob.cpp" line="53"/>
|
||||
<source>Could not open file <code>%1</code>.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tidak dapat membuka berkas <code>%1</code>.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/oemid/IDJob.cpp" line="60"/>
|
||||
@@ -1712,7 +1712,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/>
|
||||
<source>Creating initramfs with mkinitcpio.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Membuat initramfs menggunakan mkinitcpio.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -1720,7 +1720,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/>
|
||||
<source>Creating initramfs.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Membuat initramfs.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -2031,12 +2031,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/>
|
||||
<source>Browser software</source>
|
||||
<translation>Peramban perangkat lunak</translation>
|
||||
<translation>Perangkat lunak peramban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/>
|
||||
<source>Browser package</source>
|
||||
<translation>Peramban paket</translation>
|
||||
<translation>Paket peramban</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/>
|
||||
@@ -2046,12 +2046,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/>
|
||||
<source>Kernel</source>
|
||||
<translation>Inti</translation>
|
||||
<translation>Kernel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/>
|
||||
<source>Services</source>
|
||||
<translation>Jasa</translation>
|
||||
<translation>Servis</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="57"/>
|
||||
@@ -2587,12 +2587,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
||||
<location filename="../src/modules/users/page_usersetup.ui" line="380"/>
|
||||
<location filename="../src/modules/users/page_usersetup.ui" line="550"/>
|
||||
<source>Repeat Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/users/page_usersetup.ui" line="455"/>
|
||||
<source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ketikan kotak ini dicentang, pengecekan kekuatan kata sandi akan dilakukan dan anda tidak akan dapat menggunakan kata sandi yang lemah.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/users/page_usersetup.ui" line="458"/>
|
||||
@@ -4252,7 +4252,7 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="136"/>
|
||||
<source>root is not allowed as username.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>root tidak boleh digunakan sebagai nama pengguna.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="145"/>
|
||||
@@ -4287,7 +4287,7 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
||||
<source>Repeat Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="261"/>
|
||||
@@ -4297,27 +4297,27 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="406"/>
|
||||
<source>Validate passwords quality</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Validasi kualitas kata sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="416"/>
|
||||
<source>When this box is checked, password-strength checking is done and you will not be able to use a weak password.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ketikan kotak ini dicentang, pengecekan kekuatan kata sandi akan dilakukan dan anda tidak akan dapat menggunakan kata sandi yang lemah.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="398"/>
|
||||
<source>Log in automatically without asking for the password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Masuk ke dalam sesi secara otomatis tanpa menanyakan kata sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="190"/>
|
||||
<source>Only letters, numbers, underscore and hyphen are allowed, minimal of two characters.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Hanya huruf, angka, garis bawah, dan tanda hubung yang diperbolehkan, minimal dua karakter.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="293"/>
|
||||
<source>Reuse user password as root password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gunakan kata sandi pengguna sebagai kata sandi root</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="301"/>
|
||||
@@ -4332,12 +4332,12 @@ Keluaran:
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="324"/>
|
||||
<source>Root Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Kata Sandi Root</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="342"/>
|
||||
<source>Repeat Root Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ulangi Kata Sandi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/usersq/usersq.qml" line="368"/>
|
||||
|
4366
lang/calamares_ja-Hira.ts
Normal file
4366
lang/calamares_ja-Hira.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2014,7 +2014,7 @@ O instalador será encerrado e todas as alterações serão perdidas.</translati
|
||||
<source>Please select your preferred location on the map so the installer can suggest the locale
|
||||
and timezone settings for you. You can fine-tune the suggested settings below. Search the map by dragging
|
||||
to move and using the +/- buttons to zoom in/out or use mouse scrolling for zooming.</source>
|
||||
<translation>Por favor selecione o seu local preferido no mapa para que o instalador possa sugerir a localização
|
||||
<translation>Selecione o seu local preferido no mapa para que o instalador possa sugerir a localização
|
||||
e fuso horário para si. Pode ajustar as definições sugeridas abaixo. Procure no mapa arrastando
|
||||
para mover e utilizando os botões +/- para aumentar/diminuir ou utilize a roda do rato para dar zoom.</translation>
|
||||
</message>
|
||||
@@ -4003,7 +4003,7 @@ Saída de Dados:
|
||||
<message>
|
||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
||||
<source><h1>%1</h1><br/><strong>%2<br/>for %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Thanks to <a href="https://calamares.io/team/">the Calamares team</a> and the <a href="https://www.transifex.com/calamares/calamares/">Calamares translators team</a>.<br/><br/><a href="https://calamares.io/">Calamares</a> development is sponsored by <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</source>
|
||||
<translation><h1>%1</h1><br/><strong>%2<br/>para %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Obrigado à <a href="https://calamares.io/team/">equipa Calamares</a> e à <a href="https://www.transifex.com/calamares/calamares/">equipa de tradutores do Calamares</a>.<br/><br/>O desenvolvimento do <a href="https://calamares.io/">Calamares</a> é patrocinado pela <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</translation>
|
||||
<translation><h1>%1</h1><br/><strong>%2<br/>para o %3</strong><br/><br/>Copyright 2014-2017 Teo Mrnjavac &lt;teo@kde.org&gt;<br/>Copyright 2017-2020 Adriaan de Groot &lt;groot@kde.org&gt;<br/>Obrigado à <a href="https://calamares.io/team/">equipa Calamares</a> e à <a href="https://www.transifex.com/calamares/calamares/">equipa de tradutores do Calamares</a>.<br/><br/>O desenvolvimento do <a href="https://calamares.io/">Calamares</a> é patrocinado pela <br/><a href="http://www.blue-systems.com/">Blue Systems</a> - Liberating Software.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@@ -104,17 +104,17 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dă crash lui Calamares, pentru ca doctorul Konqui să se uite la el.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||
<source>Reloads the stylesheet from the branding directory.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Reîncarcă foaia de stil din directorul branding.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<source>Uploads the session log to the configured pastebin.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Încarcă jurnalul sesiunii pe pastebin-ul configurat.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
@@ -134,7 +134,7 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||
<source>Widget Tree</source>
|
||||
<translation>Lista widget</translation>
|
||||
<translation>Arborele de widget</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.cpp" line="221"/>
|
||||
@@ -1991,7 +1991,7 @@ Programul de instalare va ieși, iar toate modificările vor fi pierdute.</trans
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||
<source>Configuration Error</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Eroare de configurare</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
||||
|
4377
lang/calamares_ta_IN.ts
Normal file
4377
lang/calamares_ta_IN.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Идора кардани танзимоти васлкунии худкор</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||
<source>Manage auto-mount settings</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Quản lý cài đặt tự động gắn kết(auto-mount)</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -104,22 +104,22 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gây crash Calamares, để Dr. Konqui có thể xem nó.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||
<source>Reloads the stylesheet from the branding directory.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tải lại stylesheet từ thư mục branding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||
<source>Uploads the session log to the configured pastebin.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Đăng tải log của phiên này lên pastebin đã được cấu hình</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||
<source>Send Session Log</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gửi log của phiên này</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||
@@ -129,7 +129,7 @@
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="128"/>
|
||||
<source>Displays the tree of widget names in the log (for stylesheet debugging).</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Hiễn thị cây của tên widget trong log(để gỡ lỗi stylesheet)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||
|
@@ -688,27 +688,27 @@ The installer will quit and all changes will be lost.</source>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||
<source>Successfully unmounted %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功卸载了 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||
<source>Successfully disabled swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功禁用了交换空间 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||
<source>Successfully cleared swap %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功清理了交换空间 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||
<source>Successfully closed mapper device %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功关闭了映射设备 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||
<source>Successfully disabled volume group %1.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>成功禁用了卷组 %1。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# Translators:
|
||||
# pavelrz, 2017
|
||||
# LiberteCzech <martin.kriz.czech@gmail.com>, 2020
|
||||
# Pavel Borecki <pavel.borecki@gmail.com>, 2021
|
||||
# Pavel Borecki <pavel.borecki@gmail.com>, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -15,7 +15,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2021\n"
|
||||
"Last-Translator: Pavel Borecki <pavel.borecki@gmail.com>, 2022\n"
|
||||
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/calamares/teams/20061/cs_CZ/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -331,7 +331,7 @@ msgstr "Nedaří se zapnout systemd službu <code>{name!s}</code>."
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
msgstr "Nedaří se zapnout systemd časovač <code>{name!s}</code>."
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
@@ -413,6 +413,8 @@ msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
"Nepodařilo se nalézt nástroj unsquashfs – ověřte, že je nainstalovaný "
|
||||
"balíček squashfs-tools."
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
@@ -5,6 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# Jason Collins <JasonPCollins@protonmail.com>, 2018
|
||||
# Karthik Balan, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -13,7 +14,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Last-Translator: Jason Collins <JasonPCollins@protonmail.com>, 2018\n"
|
||||
"Last-Translator: Karthik Balan, 2021\n"
|
||||
"Language-Team: English (United Kingdom) (https://www.transifex.com/calamares/teams/20061/en_GB/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -35,7 +36,7 @@ msgstr ""
|
||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
msgstr "Configuration Error "
|
||||
|
||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||
@@ -61,7 +62,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:508
|
||||
msgid "Bootloader installation error"
|
||||
msgstr ""
|
||||
msgstr "Bootloader installation error"
|
||||
|
||||
#: src/modules/bootloader/main.py:509
|
||||
msgid ""
|
||||
@@ -91,7 +92,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:526
|
||||
msgid "Cannot write KDM configuration file"
|
||||
msgstr ""
|
||||
msgstr "Cannot write KDM configuration file"
|
||||
|
||||
#: src/modules/displaymanager/main.py:527
|
||||
msgid "KDM config file {!s} does not exist"
|
||||
@@ -145,7 +146,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:29
|
||||
msgid "Configure OpenRC services"
|
||||
msgstr ""
|
||||
msgstr "Configure OpenRC services"
|
||||
|
||||
#: src/modules/services-openrc/main.py:57
|
||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||
@@ -173,7 +174,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:101
|
||||
msgid "Target runlevel does not exist"
|
||||
msgstr ""
|
||||
msgstr "Target runlevel does not exist"
|
||||
|
||||
#: src/modules/services-openrc/main.py:102
|
||||
msgid ""
|
||||
@@ -193,7 +194,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/networkcfg/main.py:29
|
||||
msgid "Saving network configuration."
|
||||
msgstr ""
|
||||
msgstr "Saving network configuration "
|
||||
|
||||
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
|
||||
#: src/modules/packages/main.py:69
|
||||
@@ -222,7 +223,7 @@ msgstr[1] "Removing %(num)d packages."
|
||||
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
|
||||
#: src/modules/packages/main.py:678
|
||||
msgid "Package Manager error"
|
||||
msgstr ""
|
||||
msgstr "Package Manager error"
|
||||
|
||||
#: src/modules/packages/main.py:639
|
||||
msgid ""
|
||||
|
@@ -319,7 +319,7 @@ msgstr "systemd लक्ष्य <code>{name!s}</code>सक्रिय क
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
msgstr "systemd टाइमर <code>{name!s}</code>सक्रिय करना विफल।"
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
@@ -399,6 +399,8 @@ msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
"unsqaushfs खोजने में विफल, सुनिश्चित करें कि squashfs-tools पैकेज इंस्टॉल "
|
||||
"है।"
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
385
lang/python/ja-Hira/LC_MESSAGES/python.po
Normal file
385
lang/python/ja-Hira/LC_MESSAGES/python.po
Normal file
@@ -0,0 +1,385 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Language-Team: Japanese (Hiragana) (https://www.transifex.com/calamares/teams/20061/ja-Hira/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ja-Hira\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:32
|
||||
msgid "Configuring initramfs."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
||||
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
|
||||
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
|
||||
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
|
||||
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
|
||||
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
|
||||
#: src/modules/openrcdmcryptcfg/main.py:76
|
||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
||||
#: src/modules/luksopenswaphookcfg/main.py:87
|
||||
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
|
||||
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
||||
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
||||
#: src/modules/luksopenswaphookcfg/main.py:91
|
||||
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/grubcfg/main.py:28
|
||||
msgid "Configure GRUB."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:43
|
||||
msgid "Install bootloader."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:508
|
||||
msgid "Bootloader installation error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:509
|
||||
msgid ""
|
||||
"The bootloader could not be installed. The installation command "
|
||||
"<pre>{!s}</pre> returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/fstab/main.py:29
|
||||
msgid "Writing fstab."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/fstab/main.py:389
|
||||
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:27
|
||||
msgid "Creating initramfs with dracut."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:49
|
||||
msgid "Failed to run dracut on the target"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
|
||||
msgid "The exit code was {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:526
|
||||
msgid "Cannot write KDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:527
|
||||
msgid "KDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:588
|
||||
msgid "Cannot write LXDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:589
|
||||
msgid "LXDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:672
|
||||
msgid "Cannot write LightDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:673
|
||||
msgid "LightDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:747
|
||||
msgid "Cannot configure LightDM"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:748
|
||||
msgid "No LightDM greeter installed."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:779
|
||||
msgid "Cannot write SLIM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:780
|
||||
msgid "SLIM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:906
|
||||
msgid "No display managers selected for the displaymanager module."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:907
|
||||
msgid ""
|
||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||
"displaymanager.conf."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:989
|
||||
msgid "Display manager configuration was incomplete"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:29
|
||||
msgid "Configure OpenRC services"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:57
|
||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:59
|
||||
msgid "Cannot remove service {name!s} from run-level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:61
|
||||
msgid ""
|
||||
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
||||
"level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:93
|
||||
#: src/modules/services-systemd/main.py:59
|
||||
msgid "Cannot modify service"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:94
|
||||
msgid ""
|
||||
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:101
|
||||
msgid "Target runlevel does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:102
|
||||
msgid ""
|
||||
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:110
|
||||
msgid "Target service does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:111
|
||||
msgid ""
|
||||
"The path for service {name!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/networkcfg/main.py:29
|
||||
msgid "Saving network configuration."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
|
||||
#: src/modules/packages/main.py:69
|
||||
msgid "Install packages."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:57
|
||||
#, python-format
|
||||
msgid "Processing packages (%(count)d / %(total)d)"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:62
|
||||
#, python-format
|
||||
msgid "Installing one package."
|
||||
msgid_plural "Installing %(num)d packages."
|
||||
msgstr[0] ""
|
||||
|
||||
#: src/modules/packages/main.py:65
|
||||
#, python-format
|
||||
msgid "Removing one package."
|
||||
msgid_plural "Removing %(num)d packages."
|
||||
msgstr[0] ""
|
||||
|
||||
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
|
||||
#: src/modules/packages/main.py:678
|
||||
msgid "Package Manager error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:639
|
||||
msgid ""
|
||||
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
||||
"returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:651
|
||||
msgid ""
|
||||
"The package manager could not update the system. The command <pre>{!s}</pre>"
|
||||
" returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:679
|
||||
msgid ""
|
||||
"The package manager could not make changes to the installed system. The "
|
||||
"command <pre>{!s}</pre> returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/plymouthcfg/main.py:27
|
||||
msgid "Configure Plymouth theme"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initcpiocfg/main.py:28
|
||||
msgid "Configuring mkinitcpio."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/localecfg/main.py:30
|
||||
msgid "Configuring locales."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mount/main.py:30
|
||||
msgid "Mounting partitions."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/rawfs/main.py:26
|
||||
msgid "Installing data."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dummypython/main.py:35
|
||||
msgid "Dummy python job."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
|
||||
#: src/modules/dummypython/main.py:94
|
||||
msgid "Dummy python step {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/hwclock/main.py:26
|
||||
msgid "Setting hardware clock."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/umount/main.py:31
|
||||
msgid "Unmount file systems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/openrcdmcryptcfg/main.py:26
|
||||
msgid "Configuring OpenRC dmcrypt service."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:26
|
||||
msgid "Configure systemd services"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:60
|
||||
msgid ""
|
||||
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:63
|
||||
#: src/modules/services-systemd/main.py:69
|
||||
msgid "Cannot enable systemd service <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:65
|
||||
msgid "Cannot enable systemd target <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:73
|
||||
msgid "Cannot mask systemd unit <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:75
|
||||
msgid ""
|
||||
"Unknown systemd commands <code>{command!s}</code> and "
|
||||
"<code>{suffix!s}</code> for unit {name!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mkinitfs/main.py:27
|
||||
msgid "Creating initramfs with mkinitfs."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mkinitfs/main.py:49
|
||||
msgid "Failed to run mkinitfs on the target"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:34
|
||||
msgid "Filling up filesystems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:254
|
||||
msgid "rsync failed with error code {}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:299
|
||||
msgid "Unpacking image {}/{}, file {}/{}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:314
|
||||
msgid "Starting to unpack {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
|
||||
msgid "Failed to unpack image \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:430
|
||||
msgid "No mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:431
|
||||
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:436
|
||||
msgid "Bad mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:437
|
||||
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
|
||||
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
|
||||
msgid "Bad unsquash configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:454
|
||||
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:458
|
||||
msgid "The source filesystem \"{}\" does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:464
|
||||
msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/luksopenswaphookcfg/main.py:26
|
||||
msgid "Configuring encrypted swap."
|
||||
msgstr ""
|
@@ -4,7 +4,7 @@
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
# Translators:
|
||||
# Marcin Mikołajczak <me@mkljczk.pl>, 2017
|
||||
# marcin mikołajczak <me@mkljczk.pl>, 2017
|
||||
# KagiSame, 2018
|
||||
# Piotr Strębski <strebski@gmail.com>, 2020
|
||||
# Jacob B. <brickminerplyt@gmail.com>, 2021
|
||||
|
@@ -6,6 +6,7 @@
|
||||
# Translators:
|
||||
# Jobava Jobava <jobaval10n@gmail.com>, 2018
|
||||
# Sebastian Brici <bricisebastian@gmail.com>, 2018
|
||||
# Chele Ion <krovyoll@gmail.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -14,7 +15,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Last-Translator: Sebastian Brici <bricisebastian@gmail.com>, 2018\n"
|
||||
"Last-Translator: Chele Ion <krovyoll@gmail.com>, 2021\n"
|
||||
"Language-Team: Romanian (https://www.transifex.com/calamares/teams/20061/ro/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -24,7 +25,7 @@ msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:32
|
||||
msgid "Configuring initramfs."
|
||||
msgstr ""
|
||||
msgstr "Configurare initramfs"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
||||
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
|
||||
@@ -36,21 +37,21 @@ msgstr ""
|
||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
msgstr "Eroare de configurare"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
||||
#: src/modules/luksopenswaphookcfg/main.py:87
|
||||
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
msgstr "Nu sunt partiţii definite ca 1{!s}1 ."
|
||||
|
||||
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
|
||||
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
||||
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
||||
#: src/modules/luksopenswaphookcfg/main.py:91
|
||||
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
msgstr "Nu este definită o partiţie rădăcină pentru 1{!s}1 ."
|
||||
|
||||
#: src/modules/grubcfg/main.py:28
|
||||
msgid "Configure GRUB."
|
||||
|
387
lang/python/ta_IN/LC_MESSAGES/python.po
Normal file
387
lang/python/ta_IN/LC_MESSAGES/python.po
Normal file
@@ -0,0 +1,387 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Language-Team: Tamil (India) (https://www.transifex.com/calamares/teams/20061/ta_IN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: ta_IN\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: src/modules/initramfscfg/main.py:32
|
||||
msgid "Configuring initramfs."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
||||
#: src/modules/fstab/main.py:355 src/modules/fstab/main.py:361
|
||||
#: src/modules/fstab/main.py:388 src/modules/networkcfg/main.py:105
|
||||
#: src/modules/initcpiocfg/main.py:227 src/modules/initcpiocfg/main.py:231
|
||||
#: src/modules/localecfg/main.py:135 src/modules/mount/main.py:144
|
||||
#: src/modules/rawfs/main.py:164 src/modules/openrcdmcryptcfg/main.py:72
|
||||
#: src/modules/openrcdmcryptcfg/main.py:76
|
||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||
msgid "Configuration Error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
||||
#: src/modules/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
||||
#: src/modules/luksopenswaphookcfg/main.py:87
|
||||
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initramfscfg/main.py:90 src/modules/fstab/main.py:362
|
||||
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
||||
#: src/modules/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
||||
#: src/modules/luksopenswaphookcfg/main.py:91
|
||||
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/grubcfg/main.py:28
|
||||
msgid "Configure GRUB."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:43
|
||||
msgid "Install bootloader."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:508
|
||||
msgid "Bootloader installation error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/bootloader/main.py:509
|
||||
msgid ""
|
||||
"The bootloader could not be installed. The installation command "
|
||||
"<pre>{!s}</pre> returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/fstab/main.py:29
|
||||
msgid "Writing fstab."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/fstab/main.py:389
|
||||
msgid "No <pre>{!s}</pre> configuration is given for <pre>{!s}</pre> to use."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:27
|
||||
msgid "Creating initramfs with dracut."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:49
|
||||
msgid "Failed to run dracut on the target"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dracut/main.py:50 src/modules/mkinitfs/main.py:50
|
||||
msgid "The exit code was {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:526
|
||||
msgid "Cannot write KDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:527
|
||||
msgid "KDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:588
|
||||
msgid "Cannot write LXDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:589
|
||||
msgid "LXDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:672
|
||||
msgid "Cannot write LightDM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:673
|
||||
msgid "LightDM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:747
|
||||
msgid "Cannot configure LightDM"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:748
|
||||
msgid "No LightDM greeter installed."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:779
|
||||
msgid "Cannot write SLIM configuration file"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:780
|
||||
msgid "SLIM config file {!s} does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:906
|
||||
msgid "No display managers selected for the displaymanager module."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:907
|
||||
msgid ""
|
||||
"The displaymanagers list is empty or undefined in both globalstorage and "
|
||||
"displaymanager.conf."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/displaymanager/main.py:989
|
||||
msgid "Display manager configuration was incomplete"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:29
|
||||
msgid "Configure OpenRC services"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:57
|
||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:59
|
||||
msgid "Cannot remove service {name!s} from run-level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:61
|
||||
msgid ""
|
||||
"Unknown service-action <code>{arg!s}</code> for service {name!s} in run-"
|
||||
"level {level!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:93
|
||||
#: src/modules/services-systemd/main.py:59
|
||||
msgid "Cannot modify service"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:94
|
||||
msgid ""
|
||||
"<code>rc-update {arg!s}</code> call in chroot returned error code {num!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:101
|
||||
msgid "Target runlevel does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:102
|
||||
msgid ""
|
||||
"The path for runlevel {level!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:110
|
||||
msgid "Target service does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-openrc/main.py:111
|
||||
msgid ""
|
||||
"The path for service {name!s} is <code>{path!s}</code>, which does not "
|
||||
"exist."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/networkcfg/main.py:29
|
||||
msgid "Saving network configuration."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:50 src/modules/packages/main.py:59
|
||||
#: src/modules/packages/main.py:69
|
||||
msgid "Install packages."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:57
|
||||
#, python-format
|
||||
msgid "Processing packages (%(count)d / %(total)d)"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:62
|
||||
#, python-format
|
||||
msgid "Installing one package."
|
||||
msgid_plural "Installing %(num)d packages."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: src/modules/packages/main.py:65
|
||||
#, python-format
|
||||
msgid "Removing one package."
|
||||
msgid_plural "Removing %(num)d packages."
|
||||
msgstr[0] ""
|
||||
msgstr[1] ""
|
||||
|
||||
#: src/modules/packages/main.py:638 src/modules/packages/main.py:650
|
||||
#: src/modules/packages/main.py:678
|
||||
msgid "Package Manager error"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:639
|
||||
msgid ""
|
||||
"The package manager could not prepare updates. The command <pre>{!s}</pre> "
|
||||
"returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:651
|
||||
msgid ""
|
||||
"The package manager could not update the system. The command <pre>{!s}</pre>"
|
||||
" returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/packages/main.py:679
|
||||
msgid ""
|
||||
"The package manager could not make changes to the installed system. The "
|
||||
"command <pre>{!s}</pre> returned error code {!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/plymouthcfg/main.py:27
|
||||
msgid "Configure Plymouth theme"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/initcpiocfg/main.py:28
|
||||
msgid "Configuring mkinitcpio."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/localecfg/main.py:30
|
||||
msgid "Configuring locales."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mount/main.py:30
|
||||
msgid "Mounting partitions."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/rawfs/main.py:26
|
||||
msgid "Installing data."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dummypython/main.py:35
|
||||
msgid "Dummy python job."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/dummypython/main.py:37 src/modules/dummypython/main.py:93
|
||||
#: src/modules/dummypython/main.py:94
|
||||
msgid "Dummy python step {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/hwclock/main.py:26
|
||||
msgid "Setting hardware clock."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/umount/main.py:31
|
||||
msgid "Unmount file systems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/openrcdmcryptcfg/main.py:26
|
||||
msgid "Configuring OpenRC dmcrypt service."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:26
|
||||
msgid "Configure systemd services"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:60
|
||||
msgid ""
|
||||
"<code>systemctl {arg!s}</code> call in chroot returned error code {num!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:63
|
||||
#: src/modules/services-systemd/main.py:69
|
||||
msgid "Cannot enable systemd service <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:65
|
||||
msgid "Cannot enable systemd target <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:73
|
||||
msgid "Cannot mask systemd unit <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/services-systemd/main.py:75
|
||||
msgid ""
|
||||
"Unknown systemd commands <code>{command!s}</code> and "
|
||||
"<code>{suffix!s}</code> for unit {name!s}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mkinitfs/main.py:27
|
||||
msgid "Creating initramfs with mkinitfs."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/mkinitfs/main.py:49
|
||||
msgid "Failed to run mkinitfs on the target"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:34
|
||||
msgid "Filling up filesystems."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:254
|
||||
msgid "rsync failed with error code {}."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:299
|
||||
msgid "Unpacking image {}/{}, file {}/{}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:314
|
||||
msgid "Starting to unpack {}"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:323 src/modules/unpackfs/main.py:465
|
||||
msgid "Failed to unpack image \"{}\""
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:430
|
||||
msgid "No mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:431
|
||||
msgid "globalstorage does not contain a \"rootMountPoint\" key, doing nothing"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:436
|
||||
msgid "Bad mount point for root partition"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:437
|
||||
msgid "rootMountPoint is \"{}\", which does not exist, doing nothing"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:453 src/modules/unpackfs/main.py:457
|
||||
#: src/modules/unpackfs/main.py:463 src/modules/unpackfs/main.py:478
|
||||
msgid "Bad unsquash configuration"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:454
|
||||
msgid "The filesystem for \"{}\" ({}) is not supported by your current kernel"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:458
|
||||
msgid "The source filesystem \"{}\" does not exist"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:464
|
||||
msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
msgstr ""
|
||||
|
||||
#: src/modules/luksopenswaphookcfg/main.py:26
|
||||
msgid "Configuring encrypted swap."
|
||||
msgstr ""
|
@@ -5,7 +5,7 @@
|
||||
#
|
||||
# Translators:
|
||||
# T. Tran <transifex@emiu.net>, 2020
|
||||
# Th1nhhdk, 2021
|
||||
# th1nhhdk <th1nhhdk@tutanota.com>, 2021
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -14,7 +14,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Last-Translator: Th1nhhdk, 2021\n"
|
||||
"Last-Translator: th1nhhdk <th1nhhdk@tutanota.com>, 2021\n"
|
||||
"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
|
@@ -9,6 +9,7 @@
|
||||
# Feng Chao <chaofeng111@qq.com>, 2020
|
||||
# Bobby Rong <admin@bobby285271.top>, 2020
|
||||
# 玉堂白鹤 <yjwork@qq.com>, 2021
|
||||
# Giovanni Schiano-Moriello, 2022
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
@@ -17,7 +18,7 @@ msgstr ""
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||
"Last-Translator: 玉堂白鹤 <yjwork@qq.com>, 2021\n"
|
||||
"Last-Translator: Giovanni Schiano-Moriello, 2022\n"
|
||||
"Language-Team: Chinese (China) (https://www.transifex.com/calamares/teams/20061/zh_CN/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@@ -305,7 +306,7 @@ msgstr "无法启用 systemd 目标 <code>{name!s}</code>."
|
||||
|
||||
#: src/modules/services-systemd/main.py:67
|
||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||
msgstr ""
|
||||
msgstr "无法启用 systemd 计时器 <code>{name!s}</code>。"
|
||||
|
||||
#: src/modules/services-systemd/main.py:71
|
||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||
@@ -384,7 +385,7 @@ msgstr "源文件系统 \"{}\" 不存在"
|
||||
msgid ""
|
||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||
"installed."
|
||||
msgstr ""
|
||||
msgstr "寻找 unsquashfs 失败,请确定您已安装 squashfs-tools 软体包。"
|
||||
|
||||
#: src/modules/unpackfs/main.py:479
|
||||
msgid "The destination \"{}\" in the target system is not a directory"
|
||||
|
@@ -47,7 +47,7 @@ public:
|
||||
|
||||
/** @brief Is this JobResult a success?
|
||||
*
|
||||
* Equivalent to errorCode() == 0, might be named isValid().
|
||||
* Equivalent to errorCode() == 0, see succeeded().
|
||||
*/
|
||||
virtual operator bool() const;
|
||||
|
||||
@@ -58,6 +58,11 @@ public:
|
||||
virtual void setDetails( const QString& details );
|
||||
|
||||
int errorCode() const { return m_number; }
|
||||
/** @brief Is this JobResult a success?
|
||||
*
|
||||
* Equivalent to errorCode() == 0.
|
||||
*/
|
||||
bool succeeded() const { return this->operator bool(); }
|
||||
|
||||
/// @brief an "ok status" result
|
||||
static JobResult ok();
|
||||
|
@@ -100,7 +100,7 @@ BOOST_PYTHON_MODULE( libcalamares )
|
||||
bp::args( "s" ),
|
||||
"Writes the given string to the Calamares warning stream." );
|
||||
bp::def(
|
||||
"error", &CalamaresPython::warning, bp::args( "s" ), "Writes the given string to the Calamares error stream." );
|
||||
"error", &CalamaresPython::error, bp::args( "s" ), "Writes the given string to the Calamares error stream." );
|
||||
|
||||
|
||||
// .. YAML functions
|
||||
|
@@ -67,7 +67,7 @@ Note that process modules are not recommended.
|
||||
|
||||
Module descriptors **may** have the following keys:
|
||||
- *emergency* (a boolean value, set to true to mark the module
|
||||
as an emergency module)
|
||||
as an emergency module; see the section *Emergency Modules*, below)
|
||||
- *noconfig* (a boolean value, set to true to state that the module
|
||||
has no configuration file; defaults to false)
|
||||
- *requiredModules* (a list of modules which are required for this module
|
||||
@@ -86,24 +86,30 @@ it needs those keys.
|
||||
|
||||
### Emergency Modules
|
||||
|
||||
Only C++ modules and job modules may be emergency modules. If, during an
|
||||
*exec* step in the sequence, a module fails, installation as a whole fails
|
||||
and the install is aborted. If there are emergency modules in the **same**
|
||||
exec block, those will be executed before the installation is aborted.
|
||||
Non-emergency modules are not executed.
|
||||
If, during an *exec* step in the sequence, a module fails, installation as
|
||||
a whole fails and the install is aborted. If there are emergency modules
|
||||
in the **same** exec block, those will be executed before the installation
|
||||
is aborted. Non-emergency modules are not executed.
|
||||
|
||||
If an emergency-module fails while processing emergency-modules for
|
||||
another failed module, that failure is ignored and emergency-module
|
||||
processing continues.
|
||||
|
||||
Use the EMERGENCY keyword in the CMake description of a C++ module
|
||||
to generate a suitable `module.desc`.
|
||||
to generate a suitable `module.desc`. For Python modules, manually add
|
||||
`emergency: true` to `module.desc`.
|
||||
|
||||
A module that is marked as an emergency module in its module.desc
|
||||
must **also** set the *emergency* key to *true* in its configuration file
|
||||
(see below). If it does not, the module is not considered to be an emergency
|
||||
module after all (this is so that you can have modules that have several
|
||||
instances, only some of which are actually needed for emergencies).
|
||||
module after all. This is so that you can have modules that have several
|
||||
instances, only some of which are actually needed for emergencies.
|
||||
|
||||
In summary:
|
||||
- in `module.desc`, write `emergency: true` to make it **possible** to
|
||||
run the module in emergency mode,
|
||||
- in `<modulename>.conf`, write `emergency: true` to make that specific
|
||||
module run in emergency mode.
|
||||
|
||||
### Module-specific configuration
|
||||
|
||||
@@ -112,6 +118,10 @@ named `<modulename>.conf`. If such a file is present in the
|
||||
module's directory, it can be shipped as a *default* configuration file.
|
||||
This only happens if the CMake-time option `INSTALL_CONFIG` is on.
|
||||
|
||||
The name of the configuration file for a given module can be
|
||||
influenced by the `settings.conf` of the overall Calamares configuration.
|
||||
By default, though, the module's own name is used.
|
||||
|
||||
Modules that have *noconfig* set to true will not attempt to
|
||||
read a configuration file, and will not warn that one is missing;
|
||||
conversely if *noconfig* is set to false (or is missing, since
|
||||
|
@@ -1,6 +1,7 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-FileCopyrightText: 2022 Evan James <dalto@fastmail.com>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
@@ -31,15 +32,22 @@ InitcpioJob::prettyName() const
|
||||
return tr( "Creating initramfs with mkinitcpio." );
|
||||
}
|
||||
|
||||
/** @brief Sets secure permissions on each initramfs
|
||||
*
|
||||
* Iterates over each initramfs contained directly in the directory @p d.
|
||||
* For each initramfs found, the permissions are set to owner read/write only.
|
||||
*
|
||||
*/
|
||||
void
|
||||
fixPermissions( const QDir& d )
|
||||
{
|
||||
for ( const auto& fi : d.entryInfoList( { "initramfs*" }, QDir::Files ) )
|
||||
const auto initramList = d.entryInfoList( { "initramfs*" }, QDir::Files );
|
||||
for ( const auto& fi : initramList )
|
||||
{
|
||||
QFile f( fi.absoluteFilePath() );
|
||||
if ( f.exists() )
|
||||
{
|
||||
cDebug() << "initcpio fixing permissions for" << f.fileName();
|
||||
cDebug() << "initcpio setting permissions for" << f.fileName();
|
||||
f.setPermissions( QFileDevice::ReadOwner | QFileDevice::WriteOwner );
|
||||
}
|
||||
}
|
||||
@@ -63,9 +71,19 @@ InitcpioJob::exec()
|
||||
}
|
||||
}
|
||||
|
||||
// If the kernel option isn't set to a specific kernel, run mkinitcpio on all kernels
|
||||
QStringList command = { "mkinitcpio" };
|
||||
if ( m_kernel.isEmpty() || m_kernel == "all" )
|
||||
{
|
||||
command.append( "-P" );
|
||||
}
|
||||
else
|
||||
{
|
||||
command.append( { "-p", m_kernel } );
|
||||
}
|
||||
|
||||
cDebug() << "Updating initramfs with kernel" << m_kernel;
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand(
|
||||
{ "mkinitcpio", "-p", m_kernel }, QString(), QString() /* no timeout , 0 */ );
|
||||
auto r = CalamaresUtils::System::instance()->targetEnvCommand( command, QString(), QString() /* no timeout , 0 */ );
|
||||
return r.explainProcess( "mkinitcpio", std::chrono::seconds( 10 ) /* fake timeout */ );
|
||||
}
|
||||
|
||||
@@ -73,28 +91,6 @@ void
|
||||
InitcpioJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_kernel = CalamaresUtils::getString( configurationMap, "kernel" );
|
||||
if ( m_kernel.isEmpty() )
|
||||
{
|
||||
m_kernel = QStringLiteral( "all" );
|
||||
}
|
||||
else if ( m_kernel == "$uname" )
|
||||
{
|
||||
auto r = CalamaresUtils::System::runCommand( CalamaresUtils::System::RunLocation::RunInHost,
|
||||
{ "/bin/uname", "-r" },
|
||||
QString(),
|
||||
QString(),
|
||||
std::chrono::seconds( 3 ) );
|
||||
if ( r.getExitCode() == 0 )
|
||||
{
|
||||
m_kernel = r.getOutput();
|
||||
cDebug() << "*initcpio* using running kernel" << m_kernel;
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "*initcpio* could not determine running kernel, using 'all'." << Logger::Continuation
|
||||
<< r.getExitCode() << r.getOutput();
|
||||
}
|
||||
}
|
||||
|
||||
m_unsafe = CalamaresUtils::getBool( configurationMap, "be_unsafe", false );
|
||||
}
|
||||
|
@@ -5,21 +5,22 @@
|
||||
---
|
||||
# This key defines the kernel to be loaded.
|
||||
# It can have the following values:
|
||||
# - empty or unset, interpreted as "all"
|
||||
# - the literal string "$uname" (without quotes, with dollar),
|
||||
# which will use the output of `uname -r` to determine the
|
||||
# running kernel, and use that.
|
||||
# - any other string.
|
||||
# - the name of a single mkinitcpio preset
|
||||
# - empty or unset
|
||||
# - the literal string "all"
|
||||
#
|
||||
# Whatever is set, that string is passed as *preset* argument to the
|
||||
# `-p` option of *mkinitcpio*. Take care that both "$uname" operates
|
||||
# in the host system, and might not be correct if the target system is
|
||||
# updated (to a newer kernel) as part of the installation.
|
||||
# If kernel is set to "all" or empty/unset then mkinitpio is called for all
|
||||
# kernels. Otherwise it is called with a single preset with the value
|
||||
# contained in kernel.
|
||||
#
|
||||
# Note that "all" is probably not a good preset to use either.
|
||||
kernel: linux312
|
||||
kernel: linux
|
||||
|
||||
# Set this to true to turn off mitigations for lax file
|
||||
# permissions on initramfs (which, in turn, can compromise
|
||||
# your LUKS encryption keys, CVS-2019-13179).
|
||||
#
|
||||
# If your initramfs are stored in the EFI partition or another non-POSIX
|
||||
# filesystem, this has no effect as the file permissions cannot be changed.
|
||||
# In this case, ensure the partition is mounted securely.
|
||||
#
|
||||
be_unsafe: false
|
||||
|
@@ -173,7 +173,8 @@ def find_initcpio_features(partitions, root_mount_point):
|
||||
if partition["fs"] == "btrfs":
|
||||
uses_btrfs = True
|
||||
|
||||
if partition["fs"] == "zfs":
|
||||
# In addition to checking the filesystem, check to ensure that zfs is enabled
|
||||
if partition["fs"] == "zfs" and libcalamares.globalstorage.contains("zfsPoolInfo"):
|
||||
uses_zfs = True
|
||||
|
||||
if "lvm2" in partition["fs"]:
|
||||
|
@@ -81,6 +81,7 @@ InitramfsJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
}
|
||||
else
|
||||
{
|
||||
m_kernel = QStringLiteral( "all" );
|
||||
cWarning() << "*initramfs* could not determine running kernel, using 'all'." << Logger::Continuation
|
||||
<< r.getExitCode() << r.getOutput();
|
||||
}
|
||||
|
@@ -221,6 +221,11 @@ Config::setCurrentLocation()
|
||||
{
|
||||
setCurrentLocation( m_startingTimezone.first, m_startingTimezone.second );
|
||||
}
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -252,15 +257,21 @@ Config::setCurrentLocation( const QString& regionName, const QString& zoneName )
|
||||
void
|
||||
Config::setCurrentLocation( const CalamaresUtils::Locale::TimeZoneData* location )
|
||||
{
|
||||
if ( location != m_currentLocation )
|
||||
const bool updateLocation = ( location != m_currentLocation );
|
||||
if ( updateLocation )
|
||||
{
|
||||
m_currentLocation = location;
|
||||
// Overwrite those settings that have not been made explicit.
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
}
|
||||
|
||||
// lang should be always be updated
|
||||
auto newLocale = automaticLocaleConfiguration();
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lang )
|
||||
{
|
||||
setLanguage( newLocale.language() );
|
||||
}
|
||||
|
||||
if ( updateLocation )
|
||||
{
|
||||
if ( !m_selectedLocaleConfiguration.explicit_lc )
|
||||
{
|
||||
m_selectedLocaleConfiguration.lc_numeric = newLocale.lc_numeric;
|
||||
|
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal file
22
src/modules/luksopenswaphookcfg/CMakeLists.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
# === This file is part of Calamares - <https://calamares.io> ===
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
|
||||
# Because LUKS Open Swap Hook (Job) is such a mouthful, we'll
|
||||
# use LOSH all over the place as a shorthand.
|
||||
calamares_add_plugin( luksopenswaphookcfg
|
||||
TYPE job
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
LOSHJob.cpp
|
||||
SHARED_LIB
|
||||
)
|
||||
|
||||
calamares_add_test(
|
||||
luksopenswaphooktest
|
||||
SOURCES
|
||||
LOSHJob.cpp
|
||||
Tests.cpp
|
||||
)
|
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal file
66
src/modules/luksopenswaphookcfg/LOSHInfo.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
#ifndef LUKSOPENSWAPHOOKCFG_LOSHINFO_H
|
||||
#define LUKSOPENSWAPHOOKCFG_LOSHINFO_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
/** @brief Information needed to create a suitable config file
|
||||
*
|
||||
* The LUKS swap configuration has a handful of keys that need to
|
||||
* be written to the config file. This struct holds those keys
|
||||
* and can find the key values from Global Storage (where the
|
||||
* *partition* module sets them).
|
||||
*/
|
||||
struct LOSHInfo
|
||||
{
|
||||
// Member names copied from Python code
|
||||
QString swap_outer_uuid;
|
||||
QString swap_mapper_name;
|
||||
QString mountable_keyfile_device;
|
||||
QString swap_device_path;
|
||||
QString keyfile_device_mount_options;
|
||||
|
||||
bool isValid() const { return !swap_device_path.isEmpty(); }
|
||||
|
||||
/** @brief Helper method for doing key-value replacements
|
||||
*
|
||||
* Given a named @p key (e.g. "duck", or "swap_device"), returns the
|
||||
* value set for that key. Invalid keys (e.g. "duck") return an empty string.
|
||||
*/
|
||||
QString replacementFor( const QString& key ) const
|
||||
{
|
||||
if ( key == QStringLiteral( "swap_device" ) )
|
||||
{
|
||||
return swap_device_path;
|
||||
}
|
||||
if ( key == QStringLiteral( "crypt_swap_name" ) )
|
||||
{
|
||||
return swap_mapper_name;
|
||||
}
|
||||
if ( key == QStringLiteral( "keyfile_device" ) )
|
||||
{
|
||||
return mountable_keyfile_device;
|
||||
}
|
||||
if ( key == QStringLiteral( "keyfile_filename" ) )
|
||||
{
|
||||
return QStringLiteral( "crypto_keyfile.bin" );
|
||||
}
|
||||
if ( key == QStringLiteral( "keyfile_device_mount_options" ) )
|
||||
{
|
||||
return keyfile_device_mount_options;
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
/** @brief Creates a struct from information already set in GS
|
||||
*
|
||||
*/
|
||||
static LOSHInfo fromGlobalStorage();
|
||||
};
|
||||
|
||||
#endif
|
181
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal file
181
src/modules/luksopenswaphookcfg/LOSHJob.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
#include "LOSHJob.h"
|
||||
|
||||
#include "LOSHInfo.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Permissions.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
#include "utils/String.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QVariantMap>
|
||||
|
||||
LOSHJob::LOSHJob( QObject* parent )
|
||||
: Calamares::CppJob( parent )
|
||||
{
|
||||
}
|
||||
|
||||
LOSHJob::~LOSHJob() {}
|
||||
|
||||
|
||||
QString
|
||||
LOSHJob::prettyName() const
|
||||
{
|
||||
return tr( "Configuring encrypted swap." );
|
||||
}
|
||||
|
||||
STATICTEST QString
|
||||
get_assignment_part( const QString& line )
|
||||
{
|
||||
static QRegularExpression re( "^[# \\t]*([A-Za-z_]+)[ \\t]*=" );
|
||||
auto m = re.match( line );
|
||||
if ( m.hasMatch() )
|
||||
{
|
||||
return m.captured( 1 );
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
/** Writes the config file at @p path
|
||||
*
|
||||
* NOTE: @p path is relative to the target system, not an absolute path.
|
||||
*/
|
||||
STATICTEST void
|
||||
write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info )
|
||||
{
|
||||
if ( info.isValid() )
|
||||
{
|
||||
for ( auto& line : contents )
|
||||
{
|
||||
const QString key = get_assignment_part( line );
|
||||
QString replacement = info.replacementFor( key );
|
||||
if ( !replacement.isEmpty() )
|
||||
{
|
||||
line.clear();
|
||||
line.append( QStringLiteral( "%1=%2" ).arg( key, replacement ) );
|
||||
}
|
||||
}
|
||||
cDebug() << "Writing" << contents.length() << "line configuration to" << path;
|
||||
// \n between each two lines, and a \n at the end
|
||||
CalamaresUtils::System::instance()->createTargetFile(
|
||||
path, contents.join( '\n' ).append( '\n' ).toUtf8(), CalamaresUtils::System::WriteMode::Overwrite );
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "Will not write an invalid configuration to" << path;
|
||||
}
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
LOSHJob::exec()
|
||||
{
|
||||
const auto* sys = CalamaresUtils::System::instance();
|
||||
if ( !sys )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
"LuksOpenSwapHook", tr( "No target system available." ), Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
Calamares::GlobalStorage* gs
|
||||
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||
if ( !gs || gs->value( "rootMountPoint" ).toString().isEmpty() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
"LuksOpenSwapHook", tr( "No rootMountPoint is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
if ( m_configFilePath.isEmpty() )
|
||||
{
|
||||
return Calamares::JobResult::internalError(
|
||||
"LuksOpenSwapHook", tr( "No configFilePath is set." ), Calamares::JobResult::InvalidConfiguration );
|
||||
}
|
||||
|
||||
QStringList contents = sys->readTargetFile( m_configFilePath );
|
||||
if ( contents.isEmpty() )
|
||||
{
|
||||
contents << QStringLiteral( "# swap_device=" ) << QStringLiteral( "# crypt_swap_name=" )
|
||||
<< QStringLiteral( "# keyfile_device=" ) << QStringLiteral( "# keyfile_filename=" )
|
||||
<< QStringLiteral( "# keyfile_device_mount_options" );
|
||||
}
|
||||
|
||||
write_openswap_conf( m_configFilePath, contents, LOSHInfo::fromGlobalStorage() );
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
void
|
||||
LOSHJob::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
m_configFilePath = CalamaresUtils::getString(
|
||||
configurationMap, QStringLiteral( "configFilePath" ), QStringLiteral( "/etc/openswap.conf" ) );
|
||||
}
|
||||
|
||||
STATICTEST void
|
||||
globalStoragePartitionInfo( Calamares::GlobalStorage* gs, LOSHInfo& info )
|
||||
{
|
||||
if ( !gs )
|
||||
{
|
||||
return;
|
||||
}
|
||||
QVariantList l = gs->value( "partitions" ).toList();
|
||||
if ( l.isEmpty() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for ( const auto& pv : l )
|
||||
{
|
||||
const QVariantMap partition = pv.toMap();
|
||||
if ( !partition.isEmpty() )
|
||||
{
|
||||
QString mountPoint = partition.value( "mountPoint" ).toString();
|
||||
QString fileSystem = partition.value( "fs" ).toString();
|
||||
QString luksMapperName = partition.value( "luksMapperName" ).toString();
|
||||
// if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
|
||||
if ( fileSystem == QStringLiteral( "linuxswap" ) && !luksMapperName.isEmpty() )
|
||||
{
|
||||
info.swap_outer_uuid = partition.value( "luksUuid" ).toString();
|
||||
info.swap_mapper_name = luksMapperName;
|
||||
}
|
||||
else if ( mountPoint == QStringLiteral( "/" ) && !luksMapperName.isEmpty() )
|
||||
{
|
||||
|
||||
info.mountable_keyfile_device = QStringLiteral( "/dev/mapper/" ) + luksMapperName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !info.mountable_keyfile_device.isEmpty() && !info.swap_outer_uuid.isEmpty() )
|
||||
{
|
||||
info.swap_device_path = QStringLiteral( "/dev/disk/by-uuid/" ) + info.swap_outer_uuid;
|
||||
}
|
||||
|
||||
QString btrfsRootSubvolume = gs->value( "btrfsRootSubvolume" ).toString();
|
||||
if ( !btrfsRootSubvolume.isEmpty() )
|
||||
{
|
||||
CalamaresUtils::removeLeading( btrfsRootSubvolume, '/' );
|
||||
info.keyfile_device_mount_options
|
||||
= QStringLiteral( "keyfile_device_mount_options=--options=subvol=" ) + btrfsRootSubvolume;
|
||||
}
|
||||
}
|
||||
|
||||
LOSHInfo
|
||||
LOSHInfo::fromGlobalStorage()
|
||||
{
|
||||
LOSHInfo i {};
|
||||
globalStoragePartitionInfo(
|
||||
Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr, i );
|
||||
return i;
|
||||
}
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DEFINITION( LOSHJobFactory, registerPlugin< LOSHJob >(); )
|
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal file
37
src/modules/luksopenswaphookcfg/LOSHJob.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
#ifndef LUKSOPENSWAPHOOKCFG_LOSHJOB_H
|
||||
#define LUKSOPENSWAPHOOKCFG_LOSHJOB_H
|
||||
|
||||
#include "CppJob.h"
|
||||
#include "DllMacro.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
|
||||
class PLUGINDLLEXPORT LOSHJob : public Calamares::CppJob
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit LOSHJob( QObject* parent = nullptr );
|
||||
~LOSHJob() override;
|
||||
|
||||
QString prettyName() const override;
|
||||
|
||||
Calamares::JobResult exec() override;
|
||||
|
||||
void setConfigurationMap( const QVariantMap& configurationMap ) override;
|
||||
|
||||
private:
|
||||
QString m_configFilePath;
|
||||
};
|
||||
|
||||
CALAMARES_PLUGIN_FACTORY_DECLARATION( LOSHJobFactory )
|
||||
|
||||
#endif
|
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal file
253
src/modules/luksopenswaphookcfg/Tests.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#include "LOSHInfo.h"
|
||||
#include "LOSHJob.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
// LOSH = LUKS Open Swap Hook (Job)
|
||||
|
||||
// Implementation details
|
||||
extern QString get_assignment_part( const QString& line );
|
||||
extern void write_openswap_conf( const QString& path, QStringList& contents, const LOSHInfo& info );
|
||||
|
||||
class LOSHTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
LOSHTests();
|
||||
~LOSHTests() override {}
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void testAssignmentExtraction_data();
|
||||
void testAssignmentExtraction();
|
||||
|
||||
void testLOSHInfo();
|
||||
void testConfigWriting();
|
||||
void testJob();
|
||||
};
|
||||
|
||||
LOSHTests::LOSHTests() {}
|
||||
|
||||
void
|
||||
LOSHTests::initTestCase()
|
||||
{
|
||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||
cDebug() << "LOSH test started.";
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LOSHTests::testAssignmentExtraction_data()
|
||||
{
|
||||
QTest::addColumn< QString >( "line" );
|
||||
QTest::addColumn< QString >( "match" );
|
||||
|
||||
QTest::newRow( "empty" ) << QString() << QString();
|
||||
QTest::newRow( "comment-only1" ) << QStringLiteral( "# " ) << QString();
|
||||
QTest::newRow( "comment-only2" ) << QStringLiteral( "###" ) << QString();
|
||||
QTest::newRow( "comment-only3" ) << QStringLiteral( "# # #" ) << QString();
|
||||
|
||||
QTest::newRow( "comment-text" ) << QStringLiteral( "# NOTE:" ) << QString();
|
||||
QTest::newRow( "comment-story" ) << QStringLiteral( "# This is a shell comment" ) << QString();
|
||||
// We look for assignments, but only for single-words
|
||||
QTest::newRow( "comment-space-eq" ) << QStringLiteral( "# Check that a = b" ) << QString();
|
||||
|
||||
|
||||
QTest::newRow( "assignment1" ) << QStringLiteral( "a=1" ) << QStringLiteral( "a" );
|
||||
QTest::newRow( "assignment2" ) << QStringLiteral( "a = 1" ) << QStringLiteral( "a" );
|
||||
QTest::newRow( "assignment3" ) << QStringLiteral( "# a=1" ) << QStringLiteral( "a" );
|
||||
QTest::newRow( "assignment4" ) << QStringLiteral( "cows = 12" ) << QStringLiteral( "cows" );
|
||||
QTest::newRow( "assignment5" ) << QStringLiteral( "# # cows=1" ) << QStringLiteral( "cows" );
|
||||
QTest::newRow( "assignment6" ) << QStringLiteral( "# moose='cool' # not cows" ) << QStringLiteral( "moose" );
|
||||
QTest::newRow( "assignment7" ) << QStringLiteral( " moose=cows=42" ) << QStringLiteral( "moose" );
|
||||
QTest::newRow( "assignment8" ) << QStringLiteral( "#swap_device=/dev/something" )
|
||||
<< QStringLiteral( "swap_device" );
|
||||
QTest::newRow( "assignment9" ) << QStringLiteral( "# swap_device=/dev/something" )
|
||||
<< QStringLiteral( "swap_device" );
|
||||
QTest::newRow( "assignment10" ) << QStringLiteral( "swap_device=/dev/something" )
|
||||
<< QStringLiteral( "swap_device" );
|
||||
}
|
||||
|
||||
void
|
||||
LOSHTests::testAssignmentExtraction()
|
||||
{
|
||||
QFETCH( QString, line );
|
||||
QFETCH( QString, match );
|
||||
|
||||
QCOMPARE( get_assignment_part( line ), match );
|
||||
}
|
||||
|
||||
static CalamaresUtils::System*
|
||||
file_setup( const QTemporaryDir& tempRoot )
|
||||
{
|
||||
CalamaresUtils::System* ss = CalamaresUtils::System::instance();
|
||||
if ( !ss )
|
||||
{
|
||||
ss = new CalamaresUtils::System( true );
|
||||
}
|
||||
|
||||
Calamares::GlobalStorage* gs
|
||||
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||
if ( !gs )
|
||||
{
|
||||
cDebug() << "Creating new JobQueue";
|
||||
(void)new Calamares::JobQueue();
|
||||
gs = Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||
}
|
||||
if ( gs )
|
||||
{
|
||||
// Working with a rootMountPoint set
|
||||
gs->insert( "rootMountPoint", tempRoot.path() );
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
static void
|
||||
make_valid_loshinfo( LOSHInfo& i )
|
||||
{
|
||||
i.swap_outer_uuid = QStringLiteral( "UUID-0000" );
|
||||
i.swap_mapper_name = QStringLiteral( "/dev/mapper/0000" );
|
||||
i.swap_device_path = QStringLiteral( "/dev/sda0" );
|
||||
i.mountable_keyfile_device = QStringLiteral( "/dev/ada0p0s0" );
|
||||
}
|
||||
|
||||
void
|
||||
LOSHTests::testLOSHInfo()
|
||||
{
|
||||
LOSHInfo i {};
|
||||
QVERIFY( !i.isValid() );
|
||||
|
||||
make_valid_loshinfo( i );
|
||||
QVERIFY( i.isValid() );
|
||||
QCOMPARE( i.replacementFor( QStringLiteral( "swap_device" ) ), QStringLiteral( "/dev/sda0" ) );
|
||||
QCOMPARE( i.replacementFor( QStringLiteral( "duck" ) ), QString() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LOSHTests::testConfigWriting()
|
||||
{
|
||||
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
|
||||
QVERIFY( tempRoot.isValid() );
|
||||
auto* ss = file_setup( tempRoot );
|
||||
QVERIFY( ss );
|
||||
QVERIFY( Calamares::JobQueue::instance()->globalStorage() );
|
||||
QVERIFY( QFile::exists( tempRoot.path() ) );
|
||||
QVERIFY( QFileInfo( tempRoot.path() ).isDir() );
|
||||
|
||||
const QString targetFilePath = QStringLiteral( "losh.conf" );
|
||||
const QString filePath = tempRoot.filePath( targetFilePath );
|
||||
QStringList contents { QStringLiteral( "# Calamares demo" ),
|
||||
QStringLiteral( "# swap_device=a thing" ),
|
||||
QStringLiteral( "# duck duck swap_device=another" ) };
|
||||
|
||||
// When the information is invalid, file contents are unchanged,
|
||||
// and no file is written either.
|
||||
LOSHInfo i {};
|
||||
QVERIFY( !i.isValid() );
|
||||
QVERIFY( !QFile::exists( filePath ) );
|
||||
write_openswap_conf( targetFilePath, contents, i ); // Invalid i
|
||||
QVERIFY( !QFile::exists( filePath ) );
|
||||
QCOMPARE( contents.length(), 3 );
|
||||
QCOMPARE( contents.at( 1 ).left( 4 ), QStringLiteral( "# s" ) );
|
||||
|
||||
// Can we write there at all?
|
||||
QFile derp( filePath );
|
||||
QVERIFY( derp.open( QIODevice::WriteOnly ) );
|
||||
QVERIFY( derp.write( "xx", 2 ) );
|
||||
derp.close();
|
||||
QVERIFY( QFile::exists( filePath ) );
|
||||
QVERIFY( QFile::remove( filePath ) );
|
||||
|
||||
// Once the information is valid, though, the file is written
|
||||
make_valid_loshinfo( i );
|
||||
QVERIFY( i.isValid() );
|
||||
QVERIFY( !QFile::exists( filePath ) );
|
||||
write_openswap_conf( targetFilePath, contents, i ); // Now it is valid
|
||||
QVERIFY( QFile::exists( filePath ) );
|
||||
QCOMPARE( contents.length(), 3 );
|
||||
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/sda0" ) ); // expected key value
|
||||
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/sda0" ) ); // expected line
|
||||
|
||||
// readLine() returns with newlines-added
|
||||
QFile f( filePath );
|
||||
QVERIFY( f.open( QIODevice::ReadOnly ) );
|
||||
QCOMPARE( f.readLine(), QStringLiteral( "# Calamares demo\n" ) );
|
||||
QCOMPARE( f.readLine(), QStringLiteral( "swap_device=/dev/sda0\n" ) );
|
||||
QCOMPARE( f.readLine(), QStringLiteral( "# duck duck swap_device=another\n" ) );
|
||||
QCOMPARE( f.readLine(), QString() );
|
||||
QVERIFY( f.atEnd() );
|
||||
|
||||
// Note how the contents is updated on every write_openswap_conf()
|
||||
i.swap_device_path = QStringLiteral( "/dev/zram/0.zram" );
|
||||
write_openswap_conf( targetFilePath, contents, i ); // Still valid
|
||||
QCOMPARE( contents.length(), 3 );
|
||||
QCOMPARE( i.swap_device_path, QStringLiteral( "/dev/zram/0.zram" ) ); // expected key value
|
||||
QCOMPARE( contents.at( 1 ), QStringLiteral( "swap_device=/dev/zram/0.zram" ) ); // expected line
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
LOSHTests::testJob()
|
||||
{
|
||||
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
|
||||
QVERIFY( tempRoot.isValid() );
|
||||
auto* ss = file_setup( tempRoot );
|
||||
QVERIFY( ss );
|
||||
Calamares::GlobalStorage* gs
|
||||
= Calamares::JobQueue::instance() ? Calamares::JobQueue::instance()->globalStorage() : nullptr;
|
||||
QVERIFY( gs );
|
||||
|
||||
{
|
||||
QDir d( tempRoot.path() );
|
||||
d.mkdir( "etc" );
|
||||
}
|
||||
|
||||
QVERIFY( !LOSHInfo::fromGlobalStorage().isValid() );
|
||||
QVariantList outerPartition;
|
||||
QVariantMap innerPartition;
|
||||
innerPartition.insert( "mountPoint", "/" );
|
||||
innerPartition.insert( "fs", "ext4" );
|
||||
innerPartition.insert( "luksMapperName", "root" );
|
||||
innerPartition.insert( "luksUUID", "0000" );
|
||||
outerPartition.append( innerPartition );
|
||||
innerPartition.remove( "mountPoint" );
|
||||
innerPartition.insert( "fs", "linuxswap" );
|
||||
innerPartition.insert( "luksMapperName", "swap" );
|
||||
innerPartition.insert( "luksUuid", "0001" );
|
||||
outerPartition.append( innerPartition );
|
||||
gs->insert( "partitions", outerPartition );
|
||||
QVERIFY( LOSHInfo::fromGlobalStorage().isValid() );
|
||||
|
||||
LOSHJob j;
|
||||
j.setConfigurationMap( QVariantMap() );
|
||||
auto jobresult = j.exec();
|
||||
QVERIFY( jobresult );
|
||||
|
||||
{
|
||||
QFile f( tempRoot.filePath( "etc/openswap.conf" ) );
|
||||
QVERIFY( f.exists() );
|
||||
QVERIFY( f.open( QIODevice::ReadOnly ) );
|
||||
cDebug() << f.readAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QTEST_GUILESS_MAIN( LOSHTests )
|
||||
|
||||
#include "utils/moc-warnings.h"
|
||||
|
||||
#include "Tests.moc"
|
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# === This file is part of Calamares - <https://calamares.io> ===
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2016 Teo Mrnjavac <teo@kde.org>
|
||||
# SPDX-FileCopyrightText: 2017 Alf Gaida <agaida@siduction.org>
|
||||
# SPDX-FileCopyrightText: 2019 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
#
|
||||
# Calamares is Free Software: see the License-Identifier above.
|
||||
#
|
||||
|
||||
import libcalamares
|
||||
import os.path
|
||||
|
||||
|
||||
import gettext
|
||||
_ = gettext.translation("calamares-python",
|
||||
localedir=libcalamares.utils.gettext_path(),
|
||||
languages=libcalamares.utils.gettext_languages(),
|
||||
fallback=True).gettext
|
||||
|
||||
|
||||
def pretty_name():
|
||||
return _("Configuring encrypted swap.")
|
||||
|
||||
|
||||
def write_openswap_conf(partitions, root_mount_point, openswap_conf_path):
|
||||
swap_outer_uuid = ""
|
||||
swap_mapper_name = ""
|
||||
mountable_keyfile_device = ""
|
||||
|
||||
for partition in partitions:
|
||||
if partition["fs"] == "linuxswap" and "luksMapperName" in partition:
|
||||
swap_outer_uuid = partition["luksUuid"]
|
||||
swap_mapper_name = partition["luksMapperName"]
|
||||
|
||||
elif partition["mountPoint"] == "/" and "luksMapperName" in partition:
|
||||
mountable_keyfile_device = (
|
||||
"/dev/mapper/{!s}".format(partition["luksMapperName"])
|
||||
)
|
||||
|
||||
if not mountable_keyfile_device or not swap_outer_uuid:
|
||||
return None
|
||||
|
||||
swap_device_path = "/dev/disk/by-uuid/{!s}".format(swap_outer_uuid)
|
||||
|
||||
lines = []
|
||||
with open(os.path.join(root_mount_point,
|
||||
openswap_conf_path), 'r') as openswap_file:
|
||||
lines = [x.strip() for x in openswap_file.readlines()]
|
||||
|
||||
for i in range(len(lines)):
|
||||
if lines[i].startswith("swap_device"):
|
||||
lines[i] = "swap_device={!s}".format(swap_device_path)
|
||||
|
||||
elif lines[i].startswith("crypt_swap_name"):
|
||||
lines[i] = "crypt_swap_name={!s}".format(swap_mapper_name)
|
||||
|
||||
elif lines[i].startswith("keyfile_device"):
|
||||
lines[i] = "keyfile_device={!s}".format(mountable_keyfile_device)
|
||||
|
||||
elif lines[i].startswith("keyfile_filename"):
|
||||
lines[i] = "keyfile_filename=crypto_keyfile.bin"
|
||||
|
||||
elif lines[i].startswith("#keyfile_device_mount_options"):
|
||||
if libcalamares.globalstorage.contains("btrfsRootSubvolume"):
|
||||
btrfs_root_subvolume = libcalamares.globalstorage.value("btrfsRootSubvolume")
|
||||
lines[i] = "keyfile_device_mount_options=--options=subvol=" + btrfs_root_subvolume.lstrip("/")
|
||||
|
||||
with open(os.path.join(root_mount_point,
|
||||
openswap_conf_path), 'w') as openswap_file:
|
||||
openswap_file.write("\n".join(lines) + "\n")
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def run():
|
||||
"""
|
||||
This module sets up the openswap hook for a resumable encrypted swap.
|
||||
:return:
|
||||
"""
|
||||
|
||||
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
|
||||
openswap_conf_path = libcalamares.job.configuration["configFilePath"]
|
||||
partitions = libcalamares.globalstorage.value("partitions")
|
||||
|
||||
if not partitions:
|
||||
libcalamares.utils.warning("partitions is empty, {!s}".format(partitions))
|
||||
return (_("Configuration Error"),
|
||||
_("No partitions are defined for <pre>{!s}</pre> to use.").format("luksopenswaphookcfg"))
|
||||
if not root_mount_point:
|
||||
libcalamares.utils.warning("rootMountPoint is empty, {!s}".format(root_mount_point))
|
||||
return (_("Configuration Error"),
|
||||
_("No root mount point is given for <pre>{!s}</pre> to use.").format("luksopenswaphookcfg"))
|
||||
|
||||
openswap_conf_path = openswap_conf_path.lstrip('/')
|
||||
|
||||
return write_openswap_conf(partitions, root_mount_point, openswap_conf_path)
|
@@ -1,7 +0,0 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
---
|
||||
type: "job"
|
||||
name: "luksopenswaphookcfg"
|
||||
interface: "python"
|
||||
script: "main.py"
|
@@ -73,12 +73,12 @@ def replace_username(nm_config_filename, live_user, target_user):
|
||||
if not os.path.exists(nm_config_filename):
|
||||
return
|
||||
|
||||
with open(nm_config_filename, "r") as network_conf:
|
||||
with open(nm_config_filename, "r", encoding="UTF-8") as network_conf:
|
||||
text = network_conf.readlines()
|
||||
|
||||
live_permissions = 'permissions=user:{}:;'.format(live_user)
|
||||
target_permissions = 'permissions=user:{}:;\n'.format(target_user)
|
||||
with open(nm_config_filename, "w") as network_conf:
|
||||
with open(nm_config_filename, "w", encoding="UTF-8") as network_conf:
|
||||
for line in text:
|
||||
if live_permissions in line:
|
||||
line = target_permissions
|
||||
|
@@ -382,7 +382,7 @@ class PMPacman(PackageManager):
|
||||
|
||||
def line_cb(line):
|
||||
if line.startswith(":: "):
|
||||
self.in_package_changes = "package changes" in line
|
||||
self.in_package_changes = "package" in line or "hooks" in line
|
||||
else:
|
||||
if self.in_package_changes and line.endswith("...\n"):
|
||||
# Update the message, untranslated; do not change the
|
||||
@@ -392,7 +392,7 @@ class PMPacman(PackageManager):
|
||||
global custom_status_message
|
||||
custom_status_message = "pacman: " + line.strip()
|
||||
libcalamares.job.setprogress(self.progress_fraction)
|
||||
libcalamares.utils.debug(line)
|
||||
libcalamares.utils.debug(line)
|
||||
|
||||
self.in_package_changes = False
|
||||
self.line_cb = line_cb
|
||||
@@ -444,8 +444,12 @@ class PMPacman(PackageManager):
|
||||
else:
|
||||
command.append("-S")
|
||||
|
||||
# Don't ask for user intervention, take the default action
|
||||
command.append("--noconfirm")
|
||||
|
||||
# Don't report download progress for each file
|
||||
command.append("--noprogressbar")
|
||||
|
||||
if self.pacman_needed_only is True:
|
||||
command.append("--needed")
|
||||
|
||||
|
@@ -11,6 +11,7 @@
|
||||
#include "DeviceList.h"
|
||||
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <kpmcore/backend/corebackend.h>
|
||||
@@ -40,16 +41,30 @@ hasRootPartition( Device* device )
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @brief Check if @p path holds an iso9660 filesystem
|
||||
*
|
||||
* The @p path should point to a device; blkid is used to check the FS type.
|
||||
*/
|
||||
static bool
|
||||
blkIdCheckIso9660( const QString& path )
|
||||
{
|
||||
QProcess blkid;
|
||||
blkid.start( "blkid", { path } );
|
||||
blkid.waitForFinished();
|
||||
QString output = QString::fromLocal8Bit( blkid.readAllStandardOutput() );
|
||||
return output.contains( "iso9660" );
|
||||
// If blkid fails, there's no output, but we don't care
|
||||
auto r = CalamaresUtils::System::runCommand( { "blkid", path }, std::chrono::seconds( 30 ) );
|
||||
return r.getOutput().contains( "iso9660" );
|
||||
}
|
||||
|
||||
/// @brief Convenience to check if @p partition holds an iso9660 filesystem
|
||||
static bool
|
||||
blkIdCheckIso9660P( const Partition* partition )
|
||||
{
|
||||
return blkIdCheckIso9660( partition->partitionPath() );
|
||||
}
|
||||
|
||||
/** @brief Check if the @p device is an iso9660 device
|
||||
*
|
||||
* An iso9660 device is **probably** a CD-ROM. If the device holds an
|
||||
* iso9660 FS, or any of its partitions do, then we call it an iso9660 device.
|
||||
*/
|
||||
static bool
|
||||
isIso9660( const Device* device )
|
||||
{
|
||||
@@ -65,13 +80,8 @@ isIso9660( const Device* device )
|
||||
|
||||
if ( device->partitionTable() && !device->partitionTable()->children().isEmpty() )
|
||||
{
|
||||
for ( const Partition* partition : device->partitionTable()->children() )
|
||||
{
|
||||
if ( blkIdCheckIso9660( partition->partitionPath() ) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
const auto& p = device->partitionTable()->children();
|
||||
return std::any_of( p.cbegin(), p.cend(), blkIdCheckIso9660P );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@@ -15,8 +15,8 @@
|
||||
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/String.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/backend/corebackendmanager.h>
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
@@ -127,4 +127,23 @@ clonePartition( Device* device, Partition* partition )
|
||||
partition->activeFlags() );
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
execute( Operation& operation, const QString& failureMessage )
|
||||
{
|
||||
operation.setStatus( Operation::StatusRunning );
|
||||
|
||||
Report report( nullptr );
|
||||
if ( operation.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
// Remove the === lines from the report by trimming them to empty
|
||||
QStringList l = report.toText().split( '\n' );
|
||||
std::for_each( l.begin(), l.end(), []( QString& s ) { CalamaresUtils::removeLeading( s, '=' ); } );
|
||||
|
||||
return Calamares::JobResult::error( failureMessage, l.join( '\n' ) );
|
||||
}
|
||||
|
||||
|
||||
} // namespace KPMHelpers
|
||||
|
@@ -11,11 +11,13 @@
|
||||
#ifndef KPMHELPERS_H
|
||||
#define KPMHELPERS_H
|
||||
|
||||
// KPMcore
|
||||
#include "Job.h"
|
||||
|
||||
#include <kpmcore/core/partitiontable.h>
|
||||
#include <kpmcore/fs/filesystem.h>
|
||||
#include <kpmcore/ops/operation.h>
|
||||
#include <kpmcore/util/report.h>
|
||||
|
||||
// Qt
|
||||
#include <QList>
|
||||
|
||||
#include <functional>
|
||||
@@ -72,6 +74,24 @@ Partition* createNewEncryptedPartition( PartitionNode* parent,
|
||||
|
||||
Partition* clonePartition( Device* device, Partition* partition );
|
||||
|
||||
/** @brief Return a result for an @p operation
|
||||
*
|
||||
* Executes the operation, and if successful, returns a success result.
|
||||
* Otherwise returns an error using @p failureMessage as the primary part
|
||||
* of the error, and details obtained from the operation.
|
||||
*/
|
||||
Calamares::JobResult execute( Operation& operation, const QString& failureMessage );
|
||||
/** @brief Return a result for an @p operation
|
||||
*
|
||||
* It's acceptable to use an rvalue: the operation-running is the effect
|
||||
* you're interested in, rather than keeping the temporary around.
|
||||
*/
|
||||
static inline Calamares::JobResult
|
||||
execute( Operation&& operation, const QString& failureMessage )
|
||||
{
|
||||
return execute( operation, failureMessage );
|
||||
}
|
||||
|
||||
} // namespace KPMHelpers
|
||||
|
||||
#endif /* KPMHELPERS_H */
|
||||
|
@@ -11,7 +11,9 @@
|
||||
|
||||
#include "CreatePartitionJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
#include "core/PartitionInfo.h"
|
||||
|
||||
#include "partition/FileSystem.h"
|
||||
#include "partition/PartitionQuery.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
@@ -273,17 +275,9 @@ CreatePartitionJob::exec()
|
||||
return createZfs( m_partition, m_device );
|
||||
}
|
||||
|
||||
Report report( nullptr );
|
||||
NewOperation op( *m_device, m_partition );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to create partition on disk '%1'." ).arg( m_device->name() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute(
|
||||
NewOperation( *m_device, m_partition ),
|
||||
tr( "The installer failed to create partition on disk '%1'." ).arg( m_device->name() ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -12,9 +12,11 @@
|
||||
#include "CreatePartitionTableJob.h"
|
||||
|
||||
#include "partition/PartitionIterator.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
// KPMcore
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#include <kpmcore/core/partitiontable.h>
|
||||
@@ -63,8 +65,6 @@ CreatePartitionTableJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
CreatePartitionTableJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
QString message = tr( "The installer failed to create a partition table on %1." ).arg( m_device->name() );
|
||||
|
||||
PartitionTable* table = m_device->partitionTable();
|
||||
|
||||
@@ -76,30 +76,16 @@ CreatePartitionTableJob::exec()
|
||||
cDebug() << Logger::SubEntry << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
||||
}
|
||||
|
||||
QProcess lsblk;
|
||||
lsblk.setProgram( "lsblk" );
|
||||
lsblk.setProcessChannelMode( QProcess::MergedChannels );
|
||||
lsblk.start();
|
||||
lsblk.waitForFinished();
|
||||
cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblk.readAllStandardOutput();
|
||||
auto lsblkResult = CalamaresUtils::System::runCommand( { "lsblk" }, std::chrono::seconds( 30 ) );
|
||||
cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblkResult.getOutput();
|
||||
|
||||
QProcess mount;
|
||||
mount.setProgram( "mount" ); // Debug output only, not mounting something
|
||||
mount.setProcessChannelMode( QProcess::MergedChannels );
|
||||
mount.start();
|
||||
mount.waitForFinished();
|
||||
cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mount.readAllStandardOutput();
|
||||
auto mountResult = CalamaresUtils::System::runCommand( { "mount" }, std::chrono::seconds( 30 ) );
|
||||
cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mountResult.getOutput();
|
||||
}
|
||||
|
||||
CreatePartitionTableOperation op( *m_device, table );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute(
|
||||
CreatePartitionTableOperation( *m_device, table ),
|
||||
tr( "The installer failed to create a partition table on %1." ).arg( m_device->name() ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -9,7 +9,8 @@
|
||||
|
||||
#include "CreateVolumeGroupJob.h"
|
||||
|
||||
// KPMcore
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include <kpmcore/core/lvmdevice.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#include <kpmcore/ops/createvolumegroupoperation.h>
|
||||
@@ -46,19 +47,8 @@ CreateVolumeGroupJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
CreateVolumeGroupJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
|
||||
CreateVolumeGroupOperation op( m_vgName, m_pvList, m_peSize );
|
||||
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to create a volume group named '%1'." ).arg( m_vgName );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute( CreateVolumeGroupOperation( m_vgName, m_pvList, m_peSize ),
|
||||
tr( "The installer failed to create a volume group named '%1'." ).arg( m_vgName ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "DeactivateVolumeGroupJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include <kpmcore/core/lvmdevice.h>
|
||||
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
|
||||
#include <kpmcore/util/report.h>
|
||||
@@ -39,18 +41,12 @@ DeactivateVolumeGroupJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
DeactivateVolumeGroupJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
|
||||
DeactivateVolumeGroupOperation op( *m_device );
|
||||
|
||||
op.setStatus( Operation::OperationStatus::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() );
|
||||
if ( op.execute( report ) )
|
||||
auto r = KPMHelpers::execute(
|
||||
op, tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() ) );
|
||||
if ( r )
|
||||
{
|
||||
op.preview();
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return r;
|
||||
}
|
||||
|
@@ -10,9 +10,11 @@
|
||||
*/
|
||||
|
||||
#include "DeletePartitionJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#include <kpmcore/core/partitiontable.h>
|
||||
@@ -45,7 +47,7 @@ removePartition( Partition* partition )
|
||||
auto r = CalamaresUtils::System::instance()->runCommand(
|
||||
{ "sfdisk", "--delete", "--force", partition->devicePath(), QString::number( partition->number() ) },
|
||||
std::chrono::seconds( 5 ) );
|
||||
if ( r.getExitCode() !=0 || r.getOutput().contains("failed") )
|
||||
if ( r.getExitCode() != 0 || r.getOutput().contains( "failed" ) )
|
||||
{
|
||||
return Calamares::JobResult::error(
|
||||
QCoreApplication::translate( DeletePartitionJob::staticMetaObject.className(), "Deletion Failed" ),
|
||||
@@ -96,17 +98,8 @@ DeletePartitionJob::exec()
|
||||
return removePartition( m_partition );
|
||||
}
|
||||
|
||||
Report report( nullptr );
|
||||
DeleteOperation op( *m_device, m_partition );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to delete partition %1." ).arg( m_partition->devicePath() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute( DeleteOperation( *m_device, m_partition ),
|
||||
tr( "The installer failed to delete partition %1." ).arg( m_partition->devicePath() ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -11,7 +11,10 @@
|
||||
|
||||
#include "FormatPartitionJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include "partition/FileSystem.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
|
||||
#include <kpmcore/core/device.h>
|
||||
@@ -65,17 +68,18 @@ FormatPartitionJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
FormatPartitionJob::exec()
|
||||
{
|
||||
Report report( nullptr ); // Root of the report tree, no parent
|
||||
CreateFileSystemOperation op( *m_device, *m_partition, m_partition->fileSystem().type() );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to format partition %1 on disk '%2'." )
|
||||
.arg( m_partition->partitionPath(), m_device->name() );
|
||||
|
||||
if ( op.execute( report ) )
|
||||
const auto fsType = m_partition->fileSystem().type();
|
||||
auto r = KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, fsType ),
|
||||
tr( "The installer failed to format partition %1 on disk '%2'." )
|
||||
.arg( m_partition->partitionPath(), m_device->name() ) );
|
||||
if ( fsType == FileSystem::Xfs && r.succeeded() )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
// We are going to try to set modern timestamps for the filesystem,
|
||||
// (ignoring whether this succeeds). Requires a sufficiently-new
|
||||
// xfs_admin and xfs_repair and might be made obsolete by newer
|
||||
// kpmcore releases.
|
||||
CalamaresUtils::System::runCommand( { "xfs_admin", "-O", "bigtime=1", m_partition->partitionPath() },
|
||||
std::chrono::seconds( 60 ) );
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return r;
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@
|
||||
|
||||
#include "RemoveVolumeGroupJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include <kpmcore/core/lvmdevice.h>
|
||||
#include <kpmcore/ops/removevolumegroupoperation.h>
|
||||
#include <kpmcore/util/report.h>
|
||||
@@ -39,17 +41,7 @@ RemoveVolumeGroupJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
RemoveVolumeGroupJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
|
||||
RemoveVolumeGroupOperation op( *m_device );
|
||||
|
||||
op.setStatus( Operation::OperationStatus::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute(
|
||||
RemoveVolumeGroupOperation( *m_device ),
|
||||
tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() ) );
|
||||
}
|
||||
|
@@ -11,9 +11,10 @@
|
||||
|
||||
#include "ResizePartitionJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include "utils/Units.h"
|
||||
|
||||
// KPMcore
|
||||
#include <kpmcore/core/device.h>
|
||||
#include <kpmcore/ops/resizeoperation.h>
|
||||
#include <kpmcore/util/report.h>
|
||||
@@ -66,23 +67,16 @@ ResizePartitionJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
ResizePartitionJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
// Restore partition sectors that were modified for preview
|
||||
m_partition->setFirstSector( m_oldFirstSector );
|
||||
m_partition->setLastSector( m_oldLastSector );
|
||||
|
||||
ResizeOperation op( *m_device, *m_partition, m_newFirstSector, m_newLastSector );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
connect( &op, &Operation::progress, this, &ResizePartitionJob::iprogress );
|
||||
|
||||
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
|
||||
.arg( m_partition->partitionPath() )
|
||||
.arg( m_device->name() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( errorMessage, report.toText() );
|
||||
return KPMHelpers::execute( op,
|
||||
tr( "The installer failed to resize partition %1 on disk '%2'." )
|
||||
.arg( m_partition->partitionPath() )
|
||||
.arg( m_device->name() ) );
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -9,7 +9,8 @@
|
||||
|
||||
#include "ResizeVolumeGroupJob.h"
|
||||
|
||||
// KPMcore
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include <kpmcore/core/lvmdevice.h>
|
||||
#include <kpmcore/core/partition.h>
|
||||
#include <kpmcore/ops/resizevolumegroupoperation.h>
|
||||
@@ -51,19 +52,9 @@ ResizeVolumeGroupJob::prettyStatusMessage() const
|
||||
Calamares::JobResult
|
||||
ResizeVolumeGroupJob::exec()
|
||||
{
|
||||
Report report( nullptr );
|
||||
|
||||
ResizeVolumeGroupOperation op( *m_device, m_partitionList );
|
||||
|
||||
op.setStatus( Operation::OperationStatus::StatusRunning );
|
||||
|
||||
QString message = tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( message, report.toText() );
|
||||
return KPMHelpers::execute(
|
||||
ResizeVolumeGroupOperation( *m_device, m_partitionList ),
|
||||
tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() ) );
|
||||
}
|
||||
|
||||
QString
|
||||
|
@@ -13,6 +13,8 @@
|
||||
|
||||
#include "SetPartitionFlagsJob.h"
|
||||
|
||||
#include "core/KPMHelpers.h"
|
||||
|
||||
#include "partition/FileSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Units.h"
|
||||
@@ -148,17 +150,8 @@ SetPartFlagsJob::exec()
|
||||
cDebug() << "Setting flags on" << m_device->deviceNode() << "partition" << partition()->deviceNode()
|
||||
<< Logger::DebugList( flagsList );
|
||||
|
||||
Report report( nullptr );
|
||||
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
|
||||
op.setStatus( Operation::StatusRunning );
|
||||
connect( &op, &Operation::progress, this, &SetPartFlagsJob::iprogress );
|
||||
|
||||
QString errorMessage
|
||||
= tr( "The installer failed to set flags on partition %1." ).arg( m_partition->partitionPath() );
|
||||
if ( op.execute( report ) )
|
||||
{
|
||||
return Calamares::JobResult::ok();
|
||||
}
|
||||
|
||||
return Calamares::JobResult::error( errorMessage, report.toText() );
|
||||
return KPMHelpers::execute(
|
||||
op, tr( "The installer failed to set flags on partition %1." ).arg( m_partition->partitionPath() ) );
|
||||
}
|
||||
|
@@ -3,14 +3,20 @@
|
||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-License-Identifier: BSD-2-Clause
|
||||
#
|
||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
||||
|
||||
calamares_add_plugin( preservefiles
|
||||
TYPE job
|
||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||
SOURCES
|
||||
Item.cpp
|
||||
PreserveFiles.cpp
|
||||
# REQUIRES mount # To set the rootMountPoint
|
||||
SHARED_LIB
|
||||
EMERGENCY
|
||||
)
|
||||
|
||||
calamares_add_test(
|
||||
preservefilestest
|
||||
SOURCES
|
||||
Item.cpp
|
||||
Tests.cpp
|
||||
)
|
||||
|
159
src/modules/preservefiles/Item.cpp
Normal file
159
src/modules/preservefiles/Item.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2018, 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Units.h"
|
||||
#include "utils/Variant.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
using namespace CalamaresUtils::Units;
|
||||
|
||||
static bool
|
||||
copy_file( const QString& source, const QString& dest )
|
||||
{
|
||||
QFile sourcef( source );
|
||||
if ( !sourcef.open( QFile::ReadOnly ) )
|
||||
{
|
||||
cWarning() << "Could not read" << source;
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile destf( dest );
|
||||
if ( !destf.open( QFile::WriteOnly ) )
|
||||
{
|
||||
sourcef.close();
|
||||
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray b;
|
||||
do
|
||||
{
|
||||
b = sourcef.read( 1_MiB );
|
||||
destf.write( b );
|
||||
} while ( b.count() > 0 );
|
||||
|
||||
sourcef.close();
|
||||
destf.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Item
|
||||
Item::fromVariant( const QVariant& v, const CalamaresUtils::Permissions& defaultPermissions )
|
||||
{
|
||||
if ( v.type() == QVariant::String )
|
||||
{
|
||||
QString filename = v.toString();
|
||||
if ( !filename.isEmpty() )
|
||||
{
|
||||
return { filename, filename, defaultPermissions, ItemType::Path, false };
|
||||
}
|
||||
else
|
||||
{
|
||||
cWarning() << "Empty filename for preservefiles, item" << v;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
else if ( v.type() == QVariant::Map )
|
||||
{
|
||||
const auto map = v.toMap();
|
||||
|
||||
CalamaresUtils::Permissions perm( defaultPermissions );
|
||||
ItemType t = ItemType::None;
|
||||
bool optional = CalamaresUtils::getBool( map, "optional", false );
|
||||
|
||||
{
|
||||
QString perm_string = map[ "perm" ].toString();
|
||||
if ( !perm_string.isEmpty() )
|
||||
{
|
||||
perm = CalamaresUtils::Permissions( perm_string );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
QString from = map[ "from" ].toString();
|
||||
t = ( from == "log" ) ? ItemType::Log : ( from == "config" ) ? ItemType::Config : ItemType::None;
|
||||
|
||||
if ( t == ItemType::None && !map[ "src" ].toString().isEmpty() )
|
||||
{
|
||||
t = ItemType::Path;
|
||||
}
|
||||
}
|
||||
|
||||
QString dest = map[ "dest" ].toString();
|
||||
if ( dest.isEmpty() )
|
||||
{
|
||||
cWarning() << "Empty dest for preservefiles, item" << v;
|
||||
return {};
|
||||
}
|
||||
|
||||
switch ( t )
|
||||
{
|
||||
case ItemType::Config:
|
||||
return { QString(), dest, perm, t, optional };
|
||||
case ItemType::Log:
|
||||
return { QString(), dest, perm, t, optional };
|
||||
case ItemType::Path:
|
||||
return { map[ "src" ].toString(), dest, perm, t, optional };
|
||||
case ItemType::None:
|
||||
cWarning() << "Invalid type for preservefiles, item" << v;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
cWarning() << "Invalid type for preservefiles, item" << v;
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Item::exec( const std::function< QString( QString ) >& replacements ) const
|
||||
{
|
||||
QString expanded_dest = replacements( dest );
|
||||
QString full_dest = CalamaresUtils::System::instance()->targetPath( expanded_dest );
|
||||
|
||||
bool success = false;
|
||||
switch ( m_type )
|
||||
{
|
||||
case ItemType::None:
|
||||
cWarning() << "Invalid item for preservefiles skipped.";
|
||||
return false;
|
||||
case ItemType::Config:
|
||||
if ( !( success = Calamares::JobQueue::instance()->globalStorage()->saveJson( full_dest ) ) )
|
||||
{
|
||||
cWarning() << "Could not write a JSON dump of global storage to" << full_dest;
|
||||
}
|
||||
break;
|
||||
case ItemType::Log:
|
||||
if ( !( success = copy_file( Logger::logFile(), full_dest ) ) )
|
||||
{
|
||||
cWarning() << "Could not preserve log file to" << full_dest;
|
||||
}
|
||||
break;
|
||||
case ItemType::Path:
|
||||
if ( !( success = copy_file( source, full_dest ) ) )
|
||||
{
|
||||
cWarning() << "Could not preserve" << source << "to" << full_dest;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if ( !success )
|
||||
{
|
||||
CalamaresUtils::System::instance()->removeTargetFile( expanded_dest );
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return perm.apply( full_dest );
|
||||
}
|
||||
}
|
76
src/modules/preservefiles/Item.h
Normal file
76
src/modules/preservefiles/Item.h
Normal file
@@ -0,0 +1,76 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2018, 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
*/
|
||||
#ifndef PRESERVEFILES_ITEM_H
|
||||
#define PRESERVEFILES_ITEM_H
|
||||
|
||||
#include "utils/Permissions.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QVariant>
|
||||
|
||||
#include <memory>
|
||||
|
||||
enum class ItemType
|
||||
{
|
||||
None,
|
||||
Path,
|
||||
Log,
|
||||
Config
|
||||
};
|
||||
|
||||
/** @brief Represents one item to copy
|
||||
*
|
||||
* All item types need a destination (to place the data), this is
|
||||
* intepreted within the target system. All items need a permission,
|
||||
* which is applied to the data once written.
|
||||
*
|
||||
* The source may be a path, but not all types need a source.
|
||||
*/
|
||||
class Item
|
||||
{
|
||||
QString source;
|
||||
QString dest;
|
||||
CalamaresUtils::Permissions perm;
|
||||
ItemType m_type = ItemType::None;
|
||||
bool m_optional = false;
|
||||
|
||||
public:
|
||||
Item( const QString& src, const QString& d, CalamaresUtils::Permissions p, ItemType t, bool optional )
|
||||
: source( src )
|
||||
, dest( d )
|
||||
, perm( std::move( p ) )
|
||||
, m_type( t )
|
||||
, m_optional( optional )
|
||||
{
|
||||
}
|
||||
|
||||
Item()
|
||||
: m_type( ItemType::None )
|
||||
{
|
||||
}
|
||||
|
||||
operator bool() const { return m_type != ItemType::None; }
|
||||
ItemType type() const { return m_type; }
|
||||
bool isOptional() const { return m_optional; }
|
||||
|
||||
bool exec( const std::function< QString( QString ) >& replacements ) const;
|
||||
|
||||
|
||||
/** @brief Create an Item -- or one of its subclasses -- from @p v
|
||||
*
|
||||
* Depending on the structure and contents of @p v, a pointer
|
||||
* to an Item is returned. If @p v cannot be interpreted meaningfully,
|
||||
* then a nullptr is returned.
|
||||
*
|
||||
* When the entry contains a *perm* key, use that permission, otherwise
|
||||
* apply @p defaultPermissions to the item.
|
||||
*/
|
||||
static Item fromVariant( const QVariant& v, const CalamaresUtils::Permissions& defaultPermissions );
|
||||
};
|
||||
|
||||
|
||||
#endif
|
@@ -7,46 +7,20 @@
|
||||
|
||||
#include "PreserveFiles.h"
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
#include "CalamaresVersion.h"
|
||||
#include "GlobalStorage.h"
|
||||
#include "JobQueue.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/CommandList.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/Permissions.h"
|
||||
#include "utils/Units.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
using namespace CalamaresUtils::Units;
|
||||
|
||||
QString
|
||||
targetPrefix()
|
||||
{
|
||||
if ( CalamaresUtils::System::instance()->doChroot() )
|
||||
{
|
||||
Calamares::GlobalStorage* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||
if ( gs && gs->contains( "rootMountPoint" ) )
|
||||
{
|
||||
QString r = gs->value( "rootMountPoint" ).toString();
|
||||
if ( !r.isEmpty() )
|
||||
{
|
||||
return r;
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "RootMountPoint is empty";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "No rootMountPoint defined, preserving files to '/'";
|
||||
}
|
||||
}
|
||||
|
||||
return QLatin1String( "/" );
|
||||
}
|
||||
|
||||
QString
|
||||
atReplacements( QString s )
|
||||
{
|
||||
@@ -79,95 +53,34 @@ PreserveFiles::prettyName() const
|
||||
return tr( "Saving files for later ..." );
|
||||
}
|
||||
|
||||
static bool
|
||||
copy_file( const QString& source, const QString& dest )
|
||||
{
|
||||
QFile sourcef( source );
|
||||
if ( !sourcef.open( QFile::ReadOnly ) )
|
||||
{
|
||||
cWarning() << "Could not read" << source;
|
||||
return false;
|
||||
}
|
||||
|
||||
QFile destf( dest );
|
||||
if ( !destf.open( QFile::WriteOnly ) )
|
||||
{
|
||||
sourcef.close();
|
||||
cWarning() << "Could not open" << destf.fileName() << "for writing; could not copy" << source;
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray b;
|
||||
do
|
||||
{
|
||||
b = sourcef.read( 1_MiB );
|
||||
destf.write( b );
|
||||
} while ( b.count() > 0 );
|
||||
|
||||
sourcef.close();
|
||||
destf.close();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Calamares::JobResult
|
||||
PreserveFiles::exec()
|
||||
{
|
||||
if ( m_items.isEmpty() )
|
||||
if ( m_items.empty() )
|
||||
{
|
||||
return Calamares::JobResult::error( tr( "No files configured to save for later." ) );
|
||||
}
|
||||
|
||||
QString prefix = targetPrefix();
|
||||
if ( !prefix.endsWith( '/' ) )
|
||||
{
|
||||
prefix.append( '/' );
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
for ( const auto& it : m_items )
|
||||
for ( const auto& it : qAsConst( m_items ) )
|
||||
{
|
||||
QString source = it.source;
|
||||
QString bare_dest = atReplacements( it.dest );
|
||||
QString dest = prefix + bare_dest;
|
||||
|
||||
if ( it.type == ItemType::Log )
|
||||
if ( !it )
|
||||
{
|
||||
source = Logger::logFile();
|
||||
// Invalid entries are nullptr, ignore them but count as a success
|
||||
// because they shouldn't block the installation. There are
|
||||
// warnings in the log showing what the configuration problem is.
|
||||
++count;
|
||||
continue;
|
||||
}
|
||||
if ( it.type == ItemType::Config )
|
||||
// Try to preserve the file. If it's marked as optional, count it
|
||||
// as a success regardless.
|
||||
if ( it.exec( atReplacements ) || it.isOptional() )
|
||||
{
|
||||
if ( !Calamares::JobQueue::instance()->globalStorage()->saveJson( dest ) )
|
||||
{
|
||||
cWarning() << "Could not write a JSON dump of global storage to" << dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
else if ( source.isEmpty() )
|
||||
{
|
||||
cWarning() << "Skipping unnamed source file for" << dest;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( copy_file( source, dest ) )
|
||||
{
|
||||
if ( it.perm.isValid() )
|
||||
{
|
||||
if ( !it.perm.apply( CalamaresUtils::System::instance()->targetPath( bare_dest ) ) )
|
||||
{
|
||||
cWarning() << "Could not set attributes of" << bare_dest;
|
||||
}
|
||||
}
|
||||
|
||||
++count;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count == m_items.count()
|
||||
return count == m_items.size()
|
||||
? Calamares::JobResult::ok()
|
||||
: Calamares::JobResult::error( tr( "Not all of the configured files could be preserved." ) );
|
||||
}
|
||||
@@ -193,53 +106,11 @@ PreserveFiles::setConfigurationMap( const QVariantMap& configurationMap )
|
||||
{
|
||||
defaultPermissions = QStringLiteral( "root:root:0400" );
|
||||
}
|
||||
CalamaresUtils::Permissions perm( defaultPermissions );
|
||||
|
||||
QVariantList l = files.toList();
|
||||
unsigned int c = 0;
|
||||
for ( const auto& li : l )
|
||||
for ( const auto& li : files.toList() )
|
||||
{
|
||||
if ( li.type() == QVariant::String )
|
||||
{
|
||||
QString filename = li.toString();
|
||||
if ( !filename.isEmpty() )
|
||||
m_items.append(
|
||||
Item { filename, filename, CalamaresUtils::Permissions( defaultPermissions ), ItemType::Path } );
|
||||
else
|
||||
{
|
||||
cDebug() << "Empty filename for preservefiles, item" << c;
|
||||
}
|
||||
}
|
||||
else if ( li.type() == QVariant::Map )
|
||||
{
|
||||
const auto map = li.toMap();
|
||||
QString dest = map[ "dest" ].toString();
|
||||
QString from = map[ "from" ].toString();
|
||||
ItemType t = ( from == "log" ) ? ItemType::Log : ( from == "config" ) ? ItemType::Config : ItemType::None;
|
||||
QString perm = map[ "perm" ].toString();
|
||||
if ( perm.isEmpty() )
|
||||
{
|
||||
perm = defaultPermissions;
|
||||
}
|
||||
|
||||
if ( dest.isEmpty() )
|
||||
{
|
||||
cDebug() << "Empty dest for preservefiles, item" << c;
|
||||
}
|
||||
else if ( t == ItemType::None )
|
||||
{
|
||||
cDebug() << "Invalid type for preservefiles, item" << c;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_items.append( Item { QString(), dest, CalamaresUtils::Permissions( perm ), t } );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cDebug() << "Invalid type for preservefiles, item" << c;
|
||||
}
|
||||
|
||||
++c;
|
||||
m_items.push_back( Item::fromVariant( li, perm ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -10,33 +10,14 @@
|
||||
|
||||
#include "CppJob.h"
|
||||
#include "DllMacro.h"
|
||||
#include "utils/Permissions.h"
|
||||
#include "utils/PluginFactory.h"
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
#include <QVariantMap>
|
||||
class Item;
|
||||
|
||||
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
enum class ItemType
|
||||
{
|
||||
None,
|
||||
Path,
|
||||
Log,
|
||||
Config
|
||||
};
|
||||
|
||||
struct Item
|
||||
{
|
||||
QString source;
|
||||
QString dest;
|
||||
CalamaresUtils::Permissions perm;
|
||||
ItemType type;
|
||||
};
|
||||
|
||||
using ItemList = QList< Item >;
|
||||
|
||||
public:
|
||||
|
93
src/modules/preservefiles/Tests.cpp
Normal file
93
src/modules/preservefiles/Tests.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2021 Adriaan de Groot <groot@kde.org>
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Calamares is Free Software: see the License-Identifier above.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
#include "Settings.h"
|
||||
#include "utils/CalamaresUtilsSystem.h"
|
||||
#include "utils/Logger.h"
|
||||
#include "utils/NamedEnum.h"
|
||||
#include "utils/Yaml.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class PreserveFilesTests : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PreserveFilesTests();
|
||||
~PreserveFilesTests() override {}
|
||||
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
|
||||
void testItems_data();
|
||||
void testItems();
|
||||
};
|
||||
|
||||
PreserveFilesTests::PreserveFilesTests() {}
|
||||
|
||||
void
|
||||
PreserveFilesTests::initTestCase()
|
||||
{
|
||||
Logger::setupLogLevel( Logger::LOGDEBUG );
|
||||
cDebug() << "PreserveFiles test started.";
|
||||
|
||||
// Ensure we have a system object, expect it to be a "bogus" one
|
||||
CalamaresUtils::System* system = CalamaresUtils::System::instance();
|
||||
QVERIFY( system );
|
||||
cDebug() << Logger::SubEntry << "System @" << Logger::Pointer( system );
|
||||
|
||||
const auto* settings = Calamares::Settings::instance();
|
||||
if ( !settings )
|
||||
{
|
||||
(void)new Calamares::Settings( true );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PreserveFilesTests::testItems_data()
|
||||
{
|
||||
QTest::addColumn< QString >( "filename" );
|
||||
QTest::addColumn< bool >( "ok" );
|
||||
QTest::addColumn< int >( "type_i" );
|
||||
|
||||
QTest::newRow( "log " ) << QString( "1a-log.conf" ) << true << smash( ItemType::Log );
|
||||
QTest::newRow( "config " ) << QString( "1b-config.conf" ) << true << smash( ItemType::Config );
|
||||
QTest::newRow( "src " ) << QString( "1c-src.conf" ) << true << smash( ItemType::Path );
|
||||
QTest::newRow( "filename" ) << QString( "1d-filename.conf" ) << true << smash( ItemType::Path );
|
||||
QTest::newRow( "empty " ) << QString( "1e-empty.conf" ) << false << smash( ItemType::None );
|
||||
QTest::newRow( "bad " ) << QString( "1f-bad.conf" ) << false << smash( ItemType::None );
|
||||
}
|
||||
|
||||
void
|
||||
PreserveFilesTests::testItems()
|
||||
{
|
||||
QFETCH( QString, filename );
|
||||
QFETCH( bool, ok );
|
||||
QFETCH( int, type_i );
|
||||
|
||||
QFile fi( QString( "%1/tests/%2" ).arg( BUILD_AS_TEST, filename ) );
|
||||
QVERIFY( fi.exists() );
|
||||
|
||||
bool config_file_ok = false;
|
||||
const auto map = CalamaresUtils::loadYaml( fi, &config_file_ok );
|
||||
QVERIFY( config_file_ok );
|
||||
|
||||
CalamaresUtils::Permissions perm( QStringLiteral( "adridg:adridg:0750" ) );
|
||||
auto i = Item::fromVariant( map[ "item" ], perm );
|
||||
QCOMPARE( bool( i ), ok );
|
||||
QCOMPARE( smash( i.type() ), type_i );
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN( PreserveFilesTests )
|
||||
|
||||
#include "utils/moc-warnings.h"
|
||||
|
||||
#include "Tests.moc"
|
@@ -7,42 +7,58 @@
|
||||
# the list should have one of these forms:
|
||||
#
|
||||
# - an absolute path (probably within the host system). This will be preserved
|
||||
# as the same path within the target system (chroot). If, globally, dontChroot
|
||||
# is true, then these items are ignored (since the destination is the same
|
||||
# as the source).
|
||||
# as the same path within the target system (chroot). If, globally,
|
||||
# *dontChroot* is true, then these items will be ignored (since the
|
||||
# destination is the same as the source).
|
||||
# - a map with a *dest* key. The *dest* value is a path interpreted in the
|
||||
# target system (if dontChroot is true, in the host system). Relative paths
|
||||
# are not recommended. There are three possible other keys in the map:
|
||||
# target system (if the global *dontChroot* is true, then the host is the
|
||||
# target as well). Relative paths are not recommended. There are two
|
||||
# ways to select the source data for the file:
|
||||
# - *from*, which must have one of the values, below; it is used to
|
||||
# preserve files whose pathname is known to Calamares internally.
|
||||
# - *src*, to refer to a path interpreted in the host system. Relative
|
||||
# paths are not recommended, and are interpreted relative to where
|
||||
# Calamares is being run.
|
||||
# Exactly one of the two source keys (either *from* or *src*) must be set.
|
||||
#
|
||||
# Special values for the key *from* are:
|
||||
# - *log*, for the complete log file (up to the moment the preservefiles
|
||||
# module is run),
|
||||
# - *config*, for a JSON dump of the contents of global storage.
|
||||
# Note that this may contain sensitive information, and should be
|
||||
# given restrictive permissions.
|
||||
#
|
||||
# A map with a *dest* key can have these additional fields:
|
||||
# - *perm*, is a colon-separated tuple of <user>:<group>:<mode>
|
||||
# where <mode> is in octal (e.g. 4777 for wide-open, 0400 for read-only
|
||||
# by owner). If set, the file's ownership and permissions are set to
|
||||
# those values within the target system; if not set, no permissions
|
||||
# are changed.
|
||||
# Only one of the two source keys (either *from* or *src*) may be set.
|
||||
# - *optional*, is a boolean; if this is set to `true` then failure to
|
||||
# preserve the file will **not** be counted as a failure of the
|
||||
# module, and installation will proceed. Set this for files that might
|
||||
# not exist in the host system (e.g. nvidia configuration files that
|
||||
# are created in some boot scenarios and not in others).
|
||||
#
|
||||
# The target filename is modified as follows:
|
||||
# - `@@ROOT@@` is replaced by the path to the target root (may be /)
|
||||
# The target path (*dest*) is modified as follows:
|
||||
# - `@@ROOT@@` is replaced by the path to the target root (may be /).
|
||||
# There is never any reason to use this, since the *dest* is already
|
||||
# interpreted in the target system.
|
||||
# - `@@USER@@` is replaced by the username entered by on the user
|
||||
# page (may be empty, for instance if no user page is enabled)
|
||||
#
|
||||
# Special values for the key *from* are:
|
||||
# - *log*, for the complete log file (up to the moment the preservefiles
|
||||
# module is run),
|
||||
# - *config*, for a JSON dump of the contents of global storage
|
||||
---
|
||||
#
|
||||
#
|
||||
files:
|
||||
- /etc/oem-information
|
||||
- from: log
|
||||
dest: /root/install.log
|
||||
perm: root:wheel:644
|
||||
dest: /var/log/Calamares.log
|
||||
perm: root:wheel:600
|
||||
- from: config
|
||||
dest: /root/install.json
|
||||
perm: root:wheel:400
|
||||
dest: /var/log/Calamares-install.json
|
||||
perm: root:wheel:600
|
||||
# - src: /var/log/nvidia.conf
|
||||
# dest: /var/log/Calamares-nvidia.conf
|
||||
# optional: true
|
||||
|
||||
# The *perm* key contains a default value to apply to all files listed
|
||||
# above that do not have a *perm* key of their own. If not set,
|
||||
|
37
src/modules/preservefiles/preservefiles.schema.yaml
Normal file
37
src/modules/preservefiles/preservefiles.schema.yaml
Normal file
@@ -0,0 +1,37 @@
|
||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
---
|
||||
$schema: https://json-schema.org/schema#
|
||||
$id: https://calamares.io/schemas/preservefiles
|
||||
additionalProperties: false
|
||||
type: object
|
||||
properties:
|
||||
# TODO: it's a particularly-formatted string
|
||||
perm: { type: string }
|
||||
files:
|
||||
type: array
|
||||
items:
|
||||
# There are three entries here because: string, or an entry with
|
||||
# a src (but no from) or an entry with from (but no src).
|
||||
anyOf:
|
||||
- type: string
|
||||
- type: object
|
||||
properties:
|
||||
dest: { type: string }
|
||||
src: { type: string }
|
||||
# TODO: it's a particularly-formatted string
|
||||
perm: { type: string }
|
||||
optional: { type: boolean }
|
||||
required: [ dest ]
|
||||
additionalProperties: false
|
||||
- type: object
|
||||
properties:
|
||||
dest: { type: string }
|
||||
from: { type: string, enum: [config, log] }
|
||||
# TODO: it's a particularly-formatted string
|
||||
perm: { type: string }
|
||||
optional: { type: boolean }
|
||||
required: [ dest ]
|
||||
additionalProperties: false
|
||||
|
||||
required: [ files ]
|
7
src/modules/preservefiles/tests/1a-log.conf
Normal file
7
src/modules/preservefiles/tests/1a-log.conf
Normal file
@@ -0,0 +1,7 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
item:
|
||||
from: log
|
||||
dest: /var/log/Calamares.log
|
||||
perm: root:wheel:601
|
6
src/modules/preservefiles/tests/1b-config.conf
Normal file
6
src/modules/preservefiles/tests/1b-config.conf
Normal file
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
item:
|
||||
from: config
|
||||
dest: /var/log/Calamares-install.json
|
||||
perm: root:wheel:600
|
6
src/modules/preservefiles/tests/1c-src.conf
Normal file
6
src/modules/preservefiles/tests/1c-src.conf
Normal file
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
item:
|
||||
src: /root/.cache/calamares/session.log
|
||||
dest: /var/log/Calamares.log
|
||||
perm: root:wheel:600
|
6
src/modules/preservefiles/tests/1d-filename.conf
Normal file
6
src/modules/preservefiles/tests/1d-filename.conf
Normal file
@@ -0,0 +1,6 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
item:
|
||||
src: /root/.cache/calamares/session.log
|
||||
dest: /var/log/Calamares.log
|
||||
perm: root:wheel:600
|
3
src/modules/preservefiles/tests/1e-empty.conf
Normal file
3
src/modules/preservefiles/tests/1e-empty.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
item: []
|
4
src/modules/preservefiles/tests/1f-bad.conf
Normal file
4
src/modules/preservefiles/tests/1f-bad.conf
Normal file
@@ -0,0 +1,4 @@
|
||||
# SPDX-FileCopyrightText: no
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
item:
|
||||
bop: 1
|
@@ -77,10 +77,13 @@ def run():
|
||||
"""
|
||||
root_mount_point = libcalamares.globalstorage.value("rootMountPoint")
|
||||
|
||||
if(libcalamares.job.configuration and
|
||||
"srcLog" in libcalamares.job.configuration or
|
||||
"destLog" in libcalamares.job.configuration):
|
||||
libcalamares.utils.error("Log-file preserving is **deprecated** in the *umount* module and removed in the next release")
|
||||
if(libcalamares.job.configuration and
|
||||
"srcLog" in libcalamares.job.configuration and
|
||||
"destLog" in libcalamares.job.configuration):
|
||||
libcalamares.utils.warning("Log-file preserving is **deprecated** in the *umount* module")
|
||||
log_source = libcalamares.job.configuration["srcLog"]
|
||||
log_destination = libcalamares.job.configuration["destLog"]
|
||||
# Relocate log_destination into target system
|
||||
|
@@ -5,3 +5,4 @@ type: "job"
|
||||
name: "umount"
|
||||
interface: "python"
|
||||
script: "main.py"
|
||||
emergency: true
|
@@ -28,3 +28,7 @@
|
||||
#srcLog: "/home/live/installation.log"
|
||||
#destLog: "/var/log/installation.log"
|
||||
srcLog: "/bogus/just/do/not/use/this/anymore.txt"
|
||||
|
||||
# Setting emergency to true will make it so this module is still run
|
||||
# when a prior module fails
|
||||
# emergency: true
|
||||
|
@@ -428,14 +428,16 @@ def run():
|
||||
if not root_mount_point:
|
||||
libcalamares.utils.warning("No mount point for root partition")
|
||||
return (_("No mount point for root partition"),
|
||||
_("globalstorage does not contain a \"rootMountPoint\" key, "
|
||||
"doing nothing"))
|
||||
|
||||
_("globalstorage does not contain a \"rootMountPoint\" key."))
|
||||
if not os.path.exists(root_mount_point):
|
||||
libcalamares.utils.warning("Bad root mount point \"{}\"".format(root_mount_point))
|
||||
return (_("Bad mount point for root partition"),
|
||||
_("rootMountPoint is \"{}\", which does not "
|
||||
"exist, doing nothing").format(root_mount_point))
|
||||
_("rootMountPoint is \"{}\", which does not exist.".format(root_mount_point)))
|
||||
|
||||
if libcalamares.job.configuration.get("unpack", None) is None:
|
||||
libcalamares.utils.warning("No *unpack* key in job configuration.")
|
||||
return (_("Bad unpackfs configuration"),
|
||||
_("There is no configuration information."))
|
||||
|
||||
supported_filesystems = get_supported_filesystems()
|
||||
|
||||
@@ -450,17 +452,17 @@ def run():
|
||||
if sourcefs not in supported_filesystems:
|
||||
libcalamares.utils.warning("The filesystem for \"{}\" ({}) is not supported by your current kernel".format(source, sourcefs))
|
||||
libcalamares.utils.warning(" ... modprobe {} may solve the problem".format(sourcefs))
|
||||
return (_("Bad unsquash configuration"),
|
||||
return (_("Bad unpackfs configuration"),
|
||||
_("The filesystem for \"{}\" ({}) is not supported by your current kernel").format(source, sourcefs))
|
||||
if not os.path.exists(source):
|
||||
libcalamares.utils.warning("The source filesystem \"{}\" does not exist".format(source))
|
||||
return (_("Bad unsquash configuration"),
|
||||
return (_("Bad unpackfs configuration"),
|
||||
_("The source filesystem \"{}\" does not exist").format(source))
|
||||
if sourcefs == "squashfs":
|
||||
if shutil.which("unsquashfs") is None:
|
||||
libcalamares.utils.warning("Failed to find unsquashfs")
|
||||
|
||||
return (_("Bad unsquash configuration"),
|
||||
return (_("Bad unpackfs configuration"),
|
||||
_("Failed to find unsquashfs, make sure you have the squashfs-tools package installed.") +
|
||||
" " + _("Failed to unpack image \"{}\"").format(source))
|
||||
|
||||
@@ -475,7 +477,7 @@ def run():
|
||||
if not os.path.isdir(destination) and sourcefs != "file":
|
||||
libcalamares.utils.warning(("The destination \"{}\" in the target system is not a directory").format(destination))
|
||||
if is_first:
|
||||
return (_("Bad unsquash configuration"),
|
||||
return (_("Bad unpackfs configuration"),
|
||||
_("The destination \"{}\" in the target system is not a directory").format(destination))
|
||||
else:
|
||||
libcalamares.utils.debug(".. assuming that the previous targets will create that directory.")
|
||||
|
Reference in New Issue
Block a user