Merge branch 'calamares' into work-3.3
This commit is contained in:
commit
24a881ad75
53
CHANGES-3.2
53
CHANGES-3.2
@ -7,7 +7,55 @@ 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
|
changelog -- this log starts with version 3.2.0. The release notes on the
|
||||||
website will have to do for older versions.
|
website will have to do for older versions.
|
||||||
|
|
||||||
# 3.2.48 (unreleased) #
|
# 3.2.50 (unreleased) #
|
||||||
|
|
||||||
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
- Erik Dubois
|
||||||
|
|
||||||
|
## Core ##
|
||||||
|
- No core changes yet
|
||||||
|
|
||||||
|
## Modules ##
|
||||||
|
- *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
|
||||||
|
- *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
|
||||||
|
|
||||||
|
|
||||||
|
# 3.2.49.1 (2021-12-11) #
|
||||||
|
|
||||||
|
This is a hot-fix release, to fix a regression in the calculation of
|
||||||
|
swap-size. Reported by EndeavourOS (Joe Kamprad) and Xero Linux.
|
||||||
|
|
||||||
|
|
||||||
|
# 3.2.49 (2021-12-10) #
|
||||||
|
|
||||||
|
This release contains contributions from (alphabetically by first name):
|
||||||
|
- Artem Grinev
|
||||||
|
- Evan James
|
||||||
|
|
||||||
|
Distributions are **specifically** reminded to update the *umount* module
|
||||||
|
configuration (and to use *preservefiles* if needed).
|
||||||
|
|
||||||
|
## Core ##
|
||||||
|
- Errors (e.g. when an installation fails for whatever reason) are displayed
|
||||||
|
in a dialog with a scrollable details panel, rather than growing up
|
||||||
|
to the size of the screen. (Thanks Artem)
|
||||||
|
|
||||||
|
## Modules ##
|
||||||
|
- *bootloader* better supports multiple installations of the same OS.
|
||||||
|
- *mount* supports btrfs subvolumes on subdirectories of / now.
|
||||||
|
- *partition* now supports "deep" btrfs subvolume names, e.g. a
|
||||||
|
separate subvolume for `/usr/local`. (Thanks Evan)
|
||||||
|
- The *umount* module now warns if the "preserve log file" feature is used.
|
||||||
|
This has been deprecated for a long time: use the *preservefiles* module
|
||||||
|
instead. A future release will turn this into an error.
|
||||||
|
|
||||||
|
|
||||||
|
# 3.2.48 (2021-12-03) #
|
||||||
|
|
||||||
This release contains contributions from (alphabetically by first name):
|
This release contains contributions from (alphabetically by first name):
|
||||||
- Evan James
|
- Evan James
|
||||||
@ -23,6 +71,9 @@ This release contains contributions from (alphabetically by first name):
|
|||||||
- *fstab* now has a separate, special, flags-setting for swap subvolumes
|
- *fstab* now has a separate, special, flags-setting for swap subvolumes
|
||||||
on btrfs. A swap subvolume is created if a swap **file** (not a separate
|
on btrfs. A swap subvolume is created if a swap **file** (not a separate
|
||||||
partition) is selected in the auto-partitioning page. (Thanks Evan)
|
partition) is selected in the auto-partitioning page. (Thanks Evan)
|
||||||
|
- When using btrfs, the *mount* module creates subvolumes. It was not
|
||||||
|
possible to **avoid** having a subvolume name created for the root.
|
||||||
|
This is now possible. #1837
|
||||||
- The *packages* module now has some special settings for the `pacman`
|
- The *packages* module now has some special settings for the `pacman`
|
||||||
package manager (generally used on Arch-derivatives). This allows
|
package manager (generally used on Arch-derivatives). This allows
|
||||||
tweaking of the installation process, if downloads are slow or
|
tweaking of the installation process, if downloads are slow or
|
||||||
|
@ -146,15 +146,15 @@ set( CALAMARES_DESCRIPTION_SUMMARY
|
|||||||
# NOTE: update these lines by running `txstats.py`, or for full automation
|
# NOTE: update these lines by running `txstats.py`, or for full automation
|
||||||
# `txstats.py -e`. See also
|
# `txstats.py -e`. See also
|
||||||
#
|
#
|
||||||
# Total 81 languages
|
# Total 74 languages
|
||||||
set( _tx_complete az az_AZ ca de fa fi_FI he hr ja ko lt pt_PT si
|
set( _tx_complete az az_AZ ca de fa fi_FI he hi hr ja ko lt pt_BR
|
||||||
sq tr_TR uk zh_TW )
|
pt_PT si sq sv tr_TR uk zh_TW )
|
||||||
set( _tx_good as be ca@valencia cs_CZ da fr fur hi it_IT ml nl
|
set( _tx_good as be ca@valencia cs_CZ da fr fur it_IT ml nl ru sk
|
||||||
pt_BR ru sk sv tg vi zh_CN )
|
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
|
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 )
|
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
|
set( _tx_incomplete eo es_PR gu ie kk kn lo lv mk ne ne_NP ta_IN te
|
||||||
ie kk kn ko_KR lo lv mk ne ne_NP te te_IN ur zh zh_HK )
|
ur zh zh_HK )
|
||||||
|
|
||||||
### Required versions
|
### Required versions
|
||||||
#
|
#
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
[](https://github.com/calamares/calamares/labels/hacking%3A%20in-progress)
|
[](https://github.com/calamares/calamares/labels/hacking%3A%20in-progress)
|
||||||
[](https://github.com/calamares/calamares/releases)
|
[](https://github.com/calamares/calamares/releases)
|
||||||
[](https://github.com/calamares/calamares/actions?query=workflow%3Aci)
|
[](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) |
|
| [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) |
|
||||||
|
@ -21,10 +21,18 @@ Name[as]=চিছটেম ইনস্তল কৰক
|
|||||||
Icon[as]=কেলামাৰেচ
|
Icon[as]=কেলামাৰেচ
|
||||||
GenericName[as]=চিছটেম ইনস্তলাৰ
|
GenericName[as]=চিছটেম ইনস্তলাৰ
|
||||||
Comment[as]=কেলামাৰেচ — চিছটেম ইনস্তলাৰ
|
Comment[as]=কেলামাৰেচ — চিছটেম ইনস্তলাৰ
|
||||||
|
Name[ast]=Instalar el sistema
|
||||||
|
Icon[ast]=calamares
|
||||||
|
GenericName[ast]=Instalador del sistema
|
||||||
|
Comment[ast]=Calamares — Instalador del sistema
|
||||||
Name[az]=Sistemi Quraşdırmaq
|
Name[az]=Sistemi Quraşdırmaq
|
||||||
Icon[az]=calamares
|
Icon[az]=calamares
|
||||||
GenericName[az]=Sistem Quraşdırıcısı
|
GenericName[az]=Sistem Quraşdırıcısı
|
||||||
Comment[az]=Calamares Sistem Quraşdırıcısı
|
Comment[az]=Calamares Sistem Quraşdırıcısı
|
||||||
|
Name[az_AZ]=Sistemi quraşdırmaq
|
||||||
|
Icon[az_AZ]=calamares
|
||||||
|
GenericName[az_AZ]=Sistem quraşdırcısı
|
||||||
|
Comment[az_AZ]=Calamares — Sistem Quraşdırıcısı
|
||||||
Name[be]=Усталяваць сістэму
|
Name[be]=Усталяваць сістэму
|
||||||
Icon[be]=calamares
|
Icon[be]=calamares
|
||||||
GenericName[be]=Усталёўшчык сістэмы
|
GenericName[be]=Усталёўшчык сістэмы
|
||||||
@ -41,6 +49,10 @@ Name[ca]=Instal·la el sistema
|
|||||||
Icon[ca]=calamares
|
Icon[ca]=calamares
|
||||||
GenericName[ca]=Instal·lador de sistema
|
GenericName[ca]=Instal·lador de sistema
|
||||||
Comment[ca]=Calamares — Instal·lador de sistema
|
Comment[ca]=Calamares — Instal·lador de sistema
|
||||||
|
Name[cs_CZ]=Nainstalovat systém
|
||||||
|
Icon[cs_CZ]=calamares
|
||||||
|
GenericName[cs_CZ]=Instalátor systému
|
||||||
|
Comment[cs_CZ]=Calamares – instalátor operačních systémů
|
||||||
Name[da]=Installér system
|
Name[da]=Installér system
|
||||||
Icon[da]=calamares
|
Icon[da]=calamares
|
||||||
GenericName[da]=Systeminstallationsprogram
|
GenericName[da]=Systeminstallationsprogram
|
||||||
@ -57,10 +69,19 @@ Name[en_GB]=Install System
|
|||||||
Icon[en_GB]=calamares
|
Icon[en_GB]=calamares
|
||||||
GenericName[en_GB]=System Installer
|
GenericName[en_GB]=System Installer
|
||||||
Comment[en_GB]=Calamares — System Installer
|
Comment[en_GB]=Calamares — System Installer
|
||||||
|
Name[eo]=Instali Sistemo
|
||||||
|
Icon[eo]=calamares
|
||||||
|
GenericName[eo]=Sistema Instalilo
|
||||||
|
Comment[eo]=Calamares — Sistema Instalilo
|
||||||
Name[es]=Instalar Sistema
|
Name[es]=Instalar Sistema
|
||||||
Icon[es]=calamares
|
Icon[es]=calamares
|
||||||
GenericName[es]=Instalador del Sistema
|
GenericName[es]=Instalador del Sistema
|
||||||
Comment[es]=Calamares — Instalador del Sistema
|
Comment[es]=Calamares — Instalador del Sistema
|
||||||
|
Name[es_MX]=Instalar el Sistema
|
||||||
|
Icon[es_MX]=calamares
|
||||||
|
GenericName[es_MX]=Instalador del sistema
|
||||||
|
Comment[es_MX]=Calamares - Instalador del sistema
|
||||||
|
Name[es_PR]=Instalar el sistema
|
||||||
Name[et]=Paigalda süsteem
|
Name[et]=Paigalda süsteem
|
||||||
Icon[et]=calamares
|
Icon[et]=calamares
|
||||||
GenericName[et]=Süsteemipaigaldaja
|
GenericName[et]=Süsteemipaigaldaja
|
||||||
@ -73,7 +94,10 @@ Name[fa]=نصب سامانه
|
|||||||
Icon[fa]=کالامارس
|
Icon[fa]=کالامارس
|
||||||
GenericName[fa]=نصبکننده سامانه
|
GenericName[fa]=نصبکننده سامانه
|
||||||
Comment[fa]=کالامارس — نصبکننده سامانه
|
Comment[fa]=کالامارس — نصبکننده سامانه
|
||||||
Name[es_PR]=Instalar el sistema
|
Name[fi_FI]=Asenna järjestelmä
|
||||||
|
Icon[fi_FI]=calamares
|
||||||
|
GenericName[fi_FI]=Järjestelmän asennusohjelma
|
||||||
|
Comment[fi_FI]=Calamares — Järjestelmän asentaja
|
||||||
Name[fr]=Installer le système
|
Name[fr]=Installer le système
|
||||||
Icon[fr]=calamares
|
Icon[fr]=calamares
|
||||||
GenericName[fr]=Installateur système
|
GenericName[fr]=Installateur système
|
||||||
@ -98,10 +122,6 @@ Name[hr]=Instaliraj sustav
|
|||||||
Icon[hr]=calamares
|
Icon[hr]=calamares
|
||||||
GenericName[hr]=Instalacija sustava
|
GenericName[hr]=Instalacija sustava
|
||||||
Comment[hr]=Calamares — Instalacija sustava
|
Comment[hr]=Calamares — Instalacija sustava
|
||||||
Name[ie]=Installar li sistema
|
|
||||||
Icon[ie]=calamares
|
|
||||||
GenericName[ie]=Installator del sistema
|
|
||||||
Comment[ie]=Calamares — Installator del sistema
|
|
||||||
Name[hu]=Rendszer telepítése
|
Name[hu]=Rendszer telepítése
|
||||||
Icon[hu]=calamares
|
Icon[hu]=calamares
|
||||||
GenericName[hu]=Rendszertelepítő
|
GenericName[hu]=Rendszertelepítő
|
||||||
@ -110,14 +130,18 @@ Name[id]=Instal Sistem
|
|||||||
Icon[id]=calamares
|
Icon[id]=calamares
|
||||||
GenericName[id]=Pemasang
|
GenericName[id]=Pemasang
|
||||||
Comment[id]=Calamares — Pemasang Sistem
|
Comment[id]=Calamares — Pemasang Sistem
|
||||||
|
Name[ie]=Installar li sistema
|
||||||
|
Icon[ie]=calamares
|
||||||
|
GenericName[ie]=Installator del sistema
|
||||||
|
Comment[ie]=Calamares — Installator del sistema
|
||||||
Name[is]=Setja upp kerfið
|
Name[is]=Setja upp kerfið
|
||||||
Icon[is]=calamares
|
Icon[is]=calamares
|
||||||
GenericName[is]=Kerfis uppsetning
|
GenericName[is]=Kerfis uppsetning
|
||||||
Comment[is]=Calamares — Kerfis uppsetning
|
Comment[is]=Calamares — Kerfis uppsetning
|
||||||
Name[cs_CZ]=Nainstalovat systém
|
Name[it_IT]=Installa il sistema
|
||||||
Icon[cs_CZ]=calamares
|
Icon[it_IT]=calamares
|
||||||
GenericName[cs_CZ]=Instalátor systému
|
GenericName[it_IT]=Programma d'installazione del sistema
|
||||||
Comment[cs_CZ]=Calamares – instalátor operačních systémů
|
Comment[it_IT]=Calamares — Programma d'installazione del sistema
|
||||||
Name[ja]=システムをインストール
|
Name[ja]=システムをインストール
|
||||||
Icon[ja]=calamares
|
Icon[ja]=calamares
|
||||||
GenericName[ja]=システムインストーラー
|
GenericName[ja]=システムインストーラー
|
||||||
@ -130,10 +154,6 @@ Name[lt]=Įdiegti Sistemą
|
|||||||
Icon[lt]=calamares
|
Icon[lt]=calamares
|
||||||
GenericName[lt]=Sistemos diegimas į kompiuterį
|
GenericName[lt]=Sistemos diegimas į kompiuterį
|
||||||
Comment[lt]=Calamares — Sistemos diegimo programa
|
Comment[lt]=Calamares — Sistemos diegimo programa
|
||||||
Name[it_IT]=Installa il sistema
|
|
||||||
Icon[it_IT]=calamares
|
|
||||||
GenericName[it_IT]=Programma d'installazione del sistema
|
|
||||||
Comment[it_IT]=Calamares — Programma d'installazione del sistema
|
|
||||||
Name[mk]=Инсталирај го системот
|
Name[mk]=Инсталирај го системот
|
||||||
Icon[mk]=calamares
|
Icon[mk]=calamares
|
||||||
GenericName[mk]=Системен Инсталер
|
GenericName[mk]=Системен Инсталер
|
||||||
@ -146,14 +166,14 @@ Name[nb]=Installer System
|
|||||||
Icon[nb]=calamares
|
Icon[nb]=calamares
|
||||||
GenericName[nb]=Systeminstallatør
|
GenericName[nb]=Systeminstallatør
|
||||||
Comment[nb]=Calamares-systeminstallatør
|
Comment[nb]=Calamares-systeminstallatør
|
||||||
|
Name[ne_NP]= सिस्टम इन्स्टल गर्नुहोस्
|
||||||
|
Icon[ne_NP]=Calamares
|
||||||
|
GenericName[ne_NP]=सिस्टम इन्स्टलर
|
||||||
|
Comment[ne_NP]=Calamares - सिस्टम इन्स्टलर
|
||||||
Name[nl]=Installeer systeem
|
Name[nl]=Installeer systeem
|
||||||
Icon[nl]=calamares
|
Icon[nl]=calamares
|
||||||
GenericName[nl]=Installatieprogramma
|
GenericName[nl]=Installatieprogramma
|
||||||
Comment[nl]=Calamares — Installatieprogramma
|
Comment[nl]=Calamares — Installatieprogramma
|
||||||
Name[az_AZ]=Sistemi quraşdırmaq
|
|
||||||
Icon[az_AZ]=calamares
|
|
||||||
GenericName[az_AZ]=Sistem quraşdırcısı
|
|
||||||
Comment[az_AZ]=Calamares — Sistem Quraşdırıcısı
|
|
||||||
Name[pl]=Zainstaluj system
|
Name[pl]=Zainstaluj system
|
||||||
Icon[pl]=calamares
|
Icon[pl]=calamares
|
||||||
GenericName[pl]=Instalator systemu
|
GenericName[pl]=Instalator systemu
|
||||||
@ -162,6 +182,10 @@ Name[pt_BR]=Sistema de Instalação
|
|||||||
Icon[pt_BR]=calamares
|
Icon[pt_BR]=calamares
|
||||||
GenericName[pt_BR]=Instalador de Sistema
|
GenericName[pt_BR]=Instalador de Sistema
|
||||||
Comment[pt_BR]=Calamares — Instalador de Sistema
|
Comment[pt_BR]=Calamares — Instalador de Sistema
|
||||||
|
Name[pt_PT]=Instalar Sistema
|
||||||
|
Icon[pt_PT]=calamares
|
||||||
|
GenericName[pt_PT]=Instalador de Sistema
|
||||||
|
Comment[pt_PT]=Instalador de Sistema - Calamares
|
||||||
Name[ro]=Instalează sistemul
|
Name[ro]=Instalează sistemul
|
||||||
Icon[ro]=calamares
|
Icon[ro]=calamares
|
||||||
GenericName[ro]=Instalator de sistem
|
GenericName[ro]=Instalator de sistem
|
||||||
@ -183,15 +207,11 @@ Name[sq]=Instalo Sistemin
|
|||||||
Icon[sq]=calamares
|
Icon[sq]=calamares
|
||||||
GenericName[sq]=Instalues Sistemi
|
GenericName[sq]=Instalues Sistemi
|
||||||
Comment[sq]=Calamares — Instalues Sistemi
|
Comment[sq]=Calamares — Instalues Sistemi
|
||||||
Name[fi_FI]=Asenna järjestelmä
|
|
||||||
Icon[fi_FI]=calamares
|
|
||||||
GenericName[fi_FI]=Järjestelmän asennusohjelma
|
|
||||||
Comment[fi_FI]=Calamares — Järjestelmän asentaja
|
|
||||||
Name[sr@latin]=Instaliraj sistem
|
|
||||||
Name[sr]=Инсталирај систем
|
Name[sr]=Инсталирај систем
|
||||||
Icon[sr]=calamares
|
Icon[sr]=calamares
|
||||||
GenericName[sr]=Инсталатер система
|
GenericName[sr]=Инсталатер система
|
||||||
Comment[sr]=Каламарес — инсталатер система
|
Comment[sr]=Каламарес — инсталатер система
|
||||||
|
Name[sr@latin]=Instaliraj sistem
|
||||||
Name[sv]=Installera system
|
Name[sv]=Installera system
|
||||||
Icon[sv]=calamares
|
Icon[sv]=calamares
|
||||||
GenericName[sv]=Systeminstallerare
|
GenericName[sv]=Systeminstallerare
|
||||||
@ -201,6 +221,10 @@ Icon[tg]=calamares
|
|||||||
GenericName[tg]=Насбкунандаи низомӣ
|
GenericName[tg]=Насбкунандаи низомӣ
|
||||||
Comment[tg]=Calamares — Насбкунандаи низомӣ
|
Comment[tg]=Calamares — Насбкунандаи низомӣ
|
||||||
Name[th]=ติดตั้งระบบ
|
Name[th]=ติดตั้งระบบ
|
||||||
|
Name[tr_TR]=Sistemi Yükle
|
||||||
|
Icon[tr_TR]=calamares
|
||||||
|
GenericName[tr_TR]=Sistem Yükleyici
|
||||||
|
Comment[tr_TR]=Calamares — Sistem Yükleyici
|
||||||
Name[uk]=Встановити Систему
|
Name[uk]=Встановити Систему
|
||||||
Icon[uk]=calamares
|
Icon[uk]=calamares
|
||||||
GenericName[uk]=Встановлювач системи
|
GenericName[uk]=Встановлювач системи
|
||||||
@ -217,27 +241,3 @@ Name[zh_TW]=安裝系統
|
|||||||
Icon[zh_TW]=calamares
|
Icon[zh_TW]=calamares
|
||||||
GenericName[zh_TW]=系統安裝程式
|
GenericName[zh_TW]=系統安裝程式
|
||||||
Comment[zh_TW]=Calamares ── 系統安裝程式
|
Comment[zh_TW]=Calamares ── 系統安裝程式
|
||||||
Name[ast]=Instalar el sistema
|
|
||||||
Icon[ast]=calamares
|
|
||||||
GenericName[ast]=Instalador del sistema
|
|
||||||
Comment[ast]=Calamares — Instalador del sistema
|
|
||||||
Name[eo]=Instali Sistemo
|
|
||||||
Icon[eo]=calamares
|
|
||||||
GenericName[eo]=Sistema Instalilo
|
|
||||||
Comment[eo]=Calamares — Sistema Instalilo
|
|
||||||
Name[ne_NP]= सिस्टम इन्स्टल गर्नुहोस्
|
|
||||||
Icon[ne_NP]=Calamares
|
|
||||||
GenericName[ne_NP]=सिस्टम इन्स्टलर
|
|
||||||
Comment[ne_NP]=Calamares - सिस्टम इन्स्टलर
|
|
||||||
Name[es_MX]=Instalar el Sistema
|
|
||||||
Icon[es_MX]=calamares
|
|
||||||
GenericName[es_MX]=Instalador del sistema
|
|
||||||
Comment[es_MX]=Calamares - Instalador del sistema
|
|
||||||
Name[pt_PT]=Instalar Sistema
|
|
||||||
Icon[pt_PT]=calamares
|
|
||||||
GenericName[pt_PT]=Instalador de Sistema
|
|
||||||
Comment[pt_PT]=Calamares - Instalador de Sistema
|
|
||||||
Name[tr_TR]=Sistemi Yükle
|
|
||||||
Icon[tr_TR]=calamares
|
|
||||||
GenericName[tr_TR]=Sistem Yükleyici
|
|
||||||
Comment[tr_TR]=Calamares — Sistem Yükleyici
|
|
||||||
|
32
ci/txpull.sh
32
ci/txpull.sh
@ -108,6 +108,21 @@ awk '
|
|||||||
skip=0; print $0;
|
skip=0; print $0;
|
||||||
}}' < calamares.desktop > calamares.desktop.new
|
}}' < calamares.desktop > calamares.desktop.new
|
||||||
mv calamares.desktop.new calamares.desktop
|
mv calamares.desktop.new calamares.desktop
|
||||||
|
# Now group translated key-names (Name, Icon, Description, ..) by sorted
|
||||||
|
# language key rather than random-ish language-key order (which shuffles
|
||||||
|
# entries around).
|
||||||
|
#
|
||||||
|
# First, the non-translated lines
|
||||||
|
grep -v '\[.*\]=' calamares.desktop > calamares.desktop.new
|
||||||
|
# The translated lines:
|
||||||
|
# - replace (the first) [] by | so we have a consistent field separator
|
||||||
|
# - sort based on field 2, then 1 (language code, then reversed key-name)
|
||||||
|
# - replace the first | by [, the first (remaining) | by ]
|
||||||
|
# Effectively this puts the fields in this order: Name, Icon, Generic Name,
|
||||||
|
# Comment -- within each language key. This keeps churn down since the
|
||||||
|
# language codes and key-names are constant.
|
||||||
|
grep '\[.*\]=' calamares.desktop | sed -e 's/\[/|/' -e 's/\]/|/' | sort -t '|' -k 2,2 -k 1,1r | sed -e 's/|/\[/' | sed -e 's/|/\]/' >> calamares.desktop.new
|
||||||
|
mv calamares.desktop.new calamares.desktop
|
||||||
git add --verbose calamares.desktop
|
git add --verbose calamares.desktop
|
||||||
git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true
|
git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true
|
||||||
|
|
||||||
@ -116,6 +131,19 @@ git commit "$AUTHOR" --message="i18n: [desktop] $BOILERPLATE" | true
|
|||||||
# PO-Created line). This applies only to modules which use po-files.
|
# PO-Created line). This applies only to modules which use po-files.
|
||||||
git diff --numstat src/modules | awk '($1==1 && $2==1){print $3}' | xargs git checkout --
|
git diff --numstat src/modules | awk '($1==1 && $2==1){print $3}' | xargs git checkout --
|
||||||
|
|
||||||
|
# sed either wants -i'' (GNU sed) or -i '' (BSD sed) to
|
||||||
|
# replace in a file, with no backup extension. Define
|
||||||
|
# a `reinplace` command to deal with the difference.
|
||||||
|
if test FreeBSD = `uname` ; then
|
||||||
|
reinplace() {
|
||||||
|
sed -i '' "$@"
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reinplace() {
|
||||||
|
sed -i'' "$@"
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
# Go through the Python modules; those with a lang/ subdir have their
|
# Go through the Python modules; those with a lang/ subdir have their
|
||||||
# own complete gettext-based setup.
|
# own complete gettext-based setup.
|
||||||
for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
|
for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
|
||||||
@ -125,7 +153,7 @@ for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
|
|||||||
if [ -d ${MODULE_DIR}/lang ]; then
|
if [ -d ${MODULE_DIR}/lang ]; then
|
||||||
# Convert PO files to MO files
|
# Convert PO files to MO files
|
||||||
for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do
|
for POFILE in $(find ${MODULE_DIR} -name "*.po") ; do
|
||||||
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
|
reinplace '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
|
||||||
# msgfmt -o ${POFILE%.po}.mo $POFILE
|
# msgfmt -o ${POFILE%.po}.mo $POFILE
|
||||||
done
|
done
|
||||||
git add --verbose ${MODULE_DIR}/lang/*
|
git add --verbose ${MODULE_DIR}/lang/*
|
||||||
@ -135,7 +163,7 @@ for MODULE_DIR in $(find src/modules -maxdepth 1 -mindepth 1 -type d) ; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
for POFILE in $(find lang -name "python.po") ; do
|
for POFILE in $(find lang -name "python.po") ; do
|
||||||
sed -i'' '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
|
reinplace '/^"Content-Type/s/CHARSET/UTF-8/' $POFILE
|
||||||
# msgfmt -o ${POFILE%.po}.mo $POFILE
|
# msgfmt -o ${POFILE%.po}.mo $POFILE
|
||||||
done
|
done
|
||||||
git add --verbose lang/python*
|
git add --verbose lang/python*
|
||||||
|
@ -1989,7 +1989,7 @@ The installer will quit and all changes will be lost.</translation>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||||
<source>Configuration Error</source>
|
<source>Configuration Error</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Configuration Error </translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
<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>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||||
<source>Successfully unmounted %1.</source>
|
<source>Successfully unmounted %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>%1 को माउंट से हटाना सफल।</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||||
<source>Successfully disabled swap %1.</source>
|
<source>Successfully disabled swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>%1 स्वैप निष्क्रिय करना सफल।</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||||
<source>Successfully cleared swap %1.</source>
|
<source>Successfully cleared swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>%1 स्वैप रिक्त करना सफल।</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||||
<source>Successfully closed mapper device %1.</source>
|
<source>Successfully closed mapper device %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>प्रतिचित्रण उपकरण %1 बंद करना सफल।</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||||
<source>Successfully disabled volume group %1.</source>
|
<source>Successfully disabled volume group %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>वॉल्यूम समूह %1 निष्क्रिय करना सफल।</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||||
<source>Manage auto-mount settings</source>
|
<source>Manage auto-mount settings</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Kelola pengaturan mount otomatis</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -114,12 +114,12 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||||
<source>Uploads the session log to the configured pastebin.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||||
<source>Send Session Log</source>
|
<source>Send Session Log</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Kirim Catatan Sesi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||||
@ -165,7 +165,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/JobExample.cpp" line="30"/>
|
<location filename="../src/libcalamares/JobExample.cpp" line="30"/>
|
||||||
<source>Programmed job failure was explicitly requested.</source>
|
<source>Programmed job failure was explicitly requested.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Kegagalan pekerjaan diprogram diminta secara eksplisit. </translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -189,7 +189,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||||
<source>Run command '%1' in target system.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||||
@ -245,7 +245,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/>
|
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="88"/>
|
||||||
<source>QML Step <i>%1</i>.</source>
|
<source>QML Step <i>%1</i>.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>QML Langkah <i>%1</i>.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/>
|
<location filename="../src/libcalamaresui/viewpages/QmlViewStep.cpp" line="268"/>
|
||||||
@ -277,7 +277,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/>
|
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="121"/>
|
||||||
<source>System-requirements checking is complete.</source>
|
<source>System-requirements checking is complete.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Pengecekan kebutuhan sistem telah selesai.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -295,7 +295,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="163"/>
|
||||||
<source>Would you like to paste the install log to the web?</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="179"/>
|
||||||
@ -429,7 +429,7 @@ Link copied to clipboard</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="425"/>
|
||||||
<source>&Done</source>
|
<source>&Done</source>
|
||||||
<translation>&Kelar</translation>
|
<translation>&Selesai</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/>
|
<location filename="../src/libcalamaresui/ViewManager.cpp" line="444"/>
|
||||||
@ -1054,12 +1054,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/>
|
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="231"/>
|
||||||
<source>Label for the filesystem</source>
|
<source>Label for the filesystem</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Label untuk filesystem</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/>
|
<location filename="../src/modules/partition/gui/CreatePartitionDialog.ui" line="241"/>
|
||||||
<source>FS Label:</source>
|
<source>FS Label:</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Label FS:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/>
|
<location filename="../src/modules/partition/gui/CreatePartitionDialog.cpp" line="65"/>
|
||||||
@ -1418,12 +1418,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/>
|
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="186"/>
|
||||||
<source>Label for the filesystem</source>
|
<source>Label for the filesystem</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Label untuk filesystem</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/>
|
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.ui" line="196"/>
|
||||||
<source>FS Label:</source>
|
<source>FS Label:</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Label FS:</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/>
|
<location filename="../src/modules/partition/gui/EditExistingPartitionDialog.cpp" line="291"/>
|
||||||
@ -1582,7 +1582,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/>
|
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="36"/>
|
||||||
<source>Format partition %1 (file system: %2, size: %3 MiB) on %4.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/>
|
<location filename="../src/modules/partition/jobs/FormatPartitionJob.cpp" line="47"/>
|
||||||
@ -1645,12 +1645,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/>
|
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="193"/>
|
||||||
<source>is running the installer as an administrator (root)</source>
|
<source>is running the installer as an administrator (root)</source>
|
||||||
<translation type="unfinished"/>
|
<translation>menjalankan installer sebagai administrator (root)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/>
|
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="196"/>
|
||||||
<source>The setup program is not running with administrator rights.</source>
|
<source>The setup program is not running with administrator rights.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Installer tidak dijalankan dengan kewenangan administrator.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/>
|
<location filename="../src/modules/welcome/checker/GeneralRequirements.cpp" line="197"/>
|
||||||
@ -1699,7 +1699,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/oemid/IDJob.cpp" line="53"/>
|
<location filename="../src/modules/oemid/IDJob.cpp" line="53"/>
|
||||||
<source>Could not open file <code>%1</code>.</source>
|
<source>Could not open file <code>%1</code>.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Tidak dapat membuka berkas <code>%1</code>.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/oemid/IDJob.cpp" line="60"/>
|
<location filename="../src/modules/oemid/IDJob.cpp" line="60"/>
|
||||||
@ -1712,7 +1712,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/>
|
<location filename="../src/modules/initcpio/InitcpioJob.cpp" line="31"/>
|
||||||
<source>Creating initramfs with mkinitcpio.</source>
|
<source>Creating initramfs with mkinitcpio.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Membuat initramfs menggunakan mkinitcpio.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1720,7 +1720,7 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/>
|
<location filename="../src/modules/initramfs/InitramfsJob.cpp" line="28"/>
|
||||||
<source>Creating initramfs.</source>
|
<source>Creating initramfs.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Membuat initramfs.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -2031,12 +2031,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/>
|
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="52"/>
|
||||||
<source>Browser software</source>
|
<source>Browser software</source>
|
||||||
<translation>Peramban perangkat lunak</translation>
|
<translation>Perangkat lunak peramban</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/>
|
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="53"/>
|
||||||
<source>Browser package</source>
|
<source>Browser package</source>
|
||||||
<translation>Peramban paket</translation>
|
<translation>Paket peramban</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/>
|
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="54"/>
|
||||||
@ -2046,12 +2046,12 @@ Instalasi dapat dilanjutkan, namun beberapa fitur akan dinonfungsikan.</translat
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/>
|
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="55"/>
|
||||||
<source>Kernel</source>
|
<source>Kernel</source>
|
||||||
<translation>Inti</translation>
|
<translation>Kernel</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/>
|
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="56"/>
|
||||||
<source>Services</source>
|
<source>Services</source>
|
||||||
<translation>Jasa</translation>
|
<translation>Servis</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/netinstall/NetInstallViewStep.cpp" line="57"/>
|
<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="380"/>
|
||||||
<location filename="../src/modules/users/page_usersetup.ui" line="550"/>
|
<location filename="../src/modules/users/page_usersetup.ui" line="550"/>
|
||||||
<source>Repeat Password</source>
|
<source>Repeat Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Ulangi Kata Sandi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/page_usersetup.ui" line="455"/>
|
<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>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/users/page_usersetup.ui" line="458"/>
|
<location filename="../src/modules/users/page_usersetup.ui" line="458"/>
|
||||||
@ -4252,7 +4252,7 @@ Keluaran:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="136"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="136"/>
|
||||||
<source>root is not allowed as username.</source>
|
<source>root is not allowed as username.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>root tidak boleh digunakan sebagai nama pengguna.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="145"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="145"/>
|
||||||
@ -4287,7 +4287,7 @@ Keluaran:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="234"/>
|
||||||
<source>Repeat Password</source>
|
<source>Repeat Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Ulangi Kata Sandi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="261"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="261"/>
|
||||||
@ -4297,27 +4297,27 @@ Keluaran:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="406"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="406"/>
|
||||||
<source>Validate passwords quality</source>
|
<source>Validate passwords quality</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Validasi kualitas kata sandi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="416"/>
|
<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>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="398"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="398"/>
|
||||||
<source>Log in automatically without asking for the password</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="190"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="190"/>
|
||||||
<source>Only letters, numbers, underscore and hyphen are allowed, minimal of two characters.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="293"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="293"/>
|
||||||
<source>Reuse user password as root password</source>
|
<source>Reuse user password as root password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Gunakan kata sandi pengguna sebagai kata sandi root</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="301"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="301"/>
|
||||||
@ -4332,12 +4332,12 @@ Keluaran:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="324"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="324"/>
|
||||||
<source>Root Password</source>
|
<source>Root Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Kata Sandi Root</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="342"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="342"/>
|
||||||
<source>Repeat Root Password</source>
|
<source>Repeat Root Password</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Ulangi Kata Sandi</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/usersq/usersq.qml" line="368"/>
|
<location filename="../src/modules/usersq/usersq.qml" line="368"/>
|
||||||
|
@ -689,27 +689,27 @@ O instalador será fechado e todas as alterações serão perdidas.</translation
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||||
<source>Successfully unmounted %1.</source>
|
<source>Successfully unmounted %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>%1 desmontado com sucesso.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||||
<source>Successfully disabled swap %1.</source>
|
<source>Successfully disabled swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Swap %1 desativada com sucesso.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||||
<source>Successfully cleared swap %1.</source>
|
<source>Successfully cleared swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Swap %1 limpa com sucesso.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||||
<source>Successfully closed mapper device %1.</source>
|
<source>Successfully closed mapper device %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Dispositivo de mapeamento %1 fechado com sucesso.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||||
<source>Successfully disabled volume group %1.</source>
|
<source>Successfully disabled volume group %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Grupo de volume %1 desativado com sucesso.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||||
|
@ -789,7 +789,7 @@ O instalador será encerrado e todas as alterações serão perdidas.</translati
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/locale/Config.cpp" line="380"/>
|
<location filename="../src/modules/locale/Config.cpp" line="380"/>
|
||||||
<source>The system language will be set to %1.</source>
|
<source>The system language will be set to %1.</source>
|
||||||
<translation>A linguagem do sistema será definida para %1.</translation>
|
<translation>O idioma do sistema será definido para %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/locale/Config.cpp" line="387"/>
|
<location filename="../src/modules/locale/Config.cpp" line="387"/>
|
||||||
@ -1684,7 +1684,7 @@ O instalador será encerrado e todas as alterações serão perdidas.</translati
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/hostinfo/HostInfoJob.cpp" line="42"/>
|
<location filename="../src/modules/hostinfo/HostInfoJob.cpp" line="42"/>
|
||||||
<source>Collecting information about your machine.</source>
|
<source>Collecting information about your machine.</source>
|
||||||
<translation>A recolher informação acerca da sua máquina.</translation>
|
<translation>A recolher informação sobre a sua máquina.</translation>
|
||||||
</message>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -3988,7 +3988,7 @@ Saída de Dados:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="228"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="228"/>
|
||||||
<source>%1 support</source>
|
<source>%1 support</source>
|
||||||
<translation>%1 suporte</translation>
|
<translation>Suporte do %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="235"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="235"/>
|
||||||
@ -3998,7 +3998,7 @@ Saída de Dados:
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="235"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="235"/>
|
||||||
<source>About %1 installer</source>
|
<source>About %1 installer</source>
|
||||||
<translation>Acerca %1 instalador</translation>
|
<translation>Acerca do instalador %1</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
<location filename="../src/modules/welcome/WelcomePage.cpp" line="238"/>
|
||||||
|
@ -1991,7 +1991,7 @@ Programul de instalare va ieși, iar toate modificările vor fi pierdute.</trans
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="53"/>
|
||||||
<source>Configuration Error</source>
|
<source>Configuration Error</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Eroare de configurare</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
<location filename="../src/modules/machineid/MachineIdJob.cpp" line="54"/>
|
||||||
|
@ -189,7 +189,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||||
<source>Run command '%1' in target system.</source>
|
<source>Run command '%1' in target system.</source>
|
||||||
<translation>Запустить комманду'%1'в целевой системе.</translation>
|
<translation>Запустить команду '%1' в целевой системе.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
<location filename="../src/libcalamares/ProcessJob.cpp" line="43"/>
|
||||||
@ -274,10 +274,10 @@
|
|||||||
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="116"/>
|
<location filename="../src/libcalamares/modulesystem/RequirementsChecker.cpp" line="116"/>
|
||||||
<source>(%n second(s))</source>
|
<source>(%n second(s))</source>
|
||||||
<translation>
|
<translation>
|
||||||
<numerusform>(% секунда)</numerusform>
|
<numerusform>(%n секунда)</numerusform>
|
||||||
<numerusform>(% секунд)</numerusform>
|
<numerusform>(%n секунды)</numerusform>
|
||||||
<numerusform>(% секунд)</numerusform>
|
|
||||||
<numerusform>(%n секунд)</numerusform>
|
<numerusform>(%n секунд)</numerusform>
|
||||||
|
<numerusform>(%n секунд(ы))</numerusform>
|
||||||
</translation>
|
</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
@ -2673,7 +2673,7 @@ The installer will quit and all changes will be lost.</source>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/PartitionLabelsView.cpp" line="203"/>
|
<location filename="../src/modules/partition/gui/PartitionLabelsView.cpp" line="203"/>
|
||||||
<source>EFI system</source>
|
<source>EFI system</source>
|
||||||
<translation>Система EFI</translation>
|
<translation>Системный раздел EFI</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/gui/PartitionLabelsView.cpp" line="207"/>
|
<location filename="../src/modules/partition/gui/PartitionLabelsView.cpp" line="207"/>
|
||||||
|
@ -688,27 +688,27 @@ Alla ändringar kommer att gå förlorade.</translation>
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="259"/>
|
||||||
<source>Successfully unmounted %1.</source>
|
<source>Successfully unmounted %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Framgångsrikt avmonterade %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="266"/>
|
||||||
<source>Successfully disabled swap %1.</source>
|
<source>Successfully disabled swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Framgångsrikt inaktiverade swap %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="292"/>
|
||||||
<source>Successfully cleared swap %1.</source>
|
<source>Successfully cleared swap %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Framgångsrikt rensade swap %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="306"/>
|
||||||
<source>Successfully closed mapper device %1.</source>
|
<source>Successfully closed mapper device %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Framgångsrikt stängde krypterad enhet %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="319"/>
|
||||||
<source>Successfully disabled volume group %1.</source>
|
<source>Successfully disabled volume group %1.</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Framgångsrikt inaktiverade volymgrupp %1.</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
<location filename="../src/modules/partition/jobs/ClearMountsJob.cpp" line="358"/>
|
||||||
|
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>
|
<message>
|
||||||
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
<location filename="../src/modules/partition/jobs/AutoMountManagementJob.cpp" line="22"/>
|
||||||
<source>Manage auto-mount settings</source>
|
<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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -104,22 +104,22 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="102"/>
|
||||||
<source>Crashes Calamares, so that Dr. Konqui can look at it.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="115"/>
|
||||||
<source>Reloads the stylesheet from the branding directory.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="141"/>
|
||||||
<source>Uploads the session log to the configured pastebin.</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="144"/>
|
||||||
<source>Send Session Log</source>
|
<source>Send Session Log</source>
|
||||||
<translation type="unfinished"/>
|
<translation>Gửi log của phiên này</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="118"/>
|
||||||
@ -129,7 +129,7 @@
|
|||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="128"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="128"/>
|
||||||
<source>Displays the tree of widget names in the log (for stylesheet debugging).</source>
|
<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>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
<location filename="../src/calamares/DebugWindow.ui" line="131"/>
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Jason Collins <JasonPCollins@protonmail.com>, 2018
|
# Jason Collins <JasonPCollins@protonmail.com>, 2018
|
||||||
|
# Karthik Balan, 2021
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -13,7 +14,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||||
"PO-Revision-Date: 2017-08-09 10:34+0000\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"
|
"Language-Team: English (United Kingdom) (https://www.transifex.com/calamares/teams/20061/en_GB/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\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:86
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||||
msgid "Configuration Error"
|
msgid "Configuration Error"
|
||||||
msgstr ""
|
msgstr "Configuration Error "
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
#: 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/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||||
@ -61,7 +62,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/bootloader/main.py:508
|
#: src/modules/bootloader/main.py:508
|
||||||
msgid "Bootloader installation error"
|
msgid "Bootloader installation error"
|
||||||
msgstr ""
|
msgstr "Bootloader installation error"
|
||||||
|
|
||||||
#: src/modules/bootloader/main.py:509
|
#: src/modules/bootloader/main.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -91,7 +92,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/displaymanager/main.py:526
|
#: src/modules/displaymanager/main.py:526
|
||||||
msgid "Cannot write KDM configuration file"
|
msgid "Cannot write KDM configuration file"
|
||||||
msgstr ""
|
msgstr "Cannot write KDM configuration file"
|
||||||
|
|
||||||
#: src/modules/displaymanager/main.py:527
|
#: src/modules/displaymanager/main.py:527
|
||||||
msgid "KDM config file {!s} does not exist"
|
msgid "KDM config file {!s} does not exist"
|
||||||
@ -145,7 +146,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/services-openrc/main.py:29
|
#: src/modules/services-openrc/main.py:29
|
||||||
msgid "Configure OpenRC services"
|
msgid "Configure OpenRC services"
|
||||||
msgstr ""
|
msgstr "Configure OpenRC services"
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:57
|
#: src/modules/services-openrc/main.py:57
|
||||||
msgid "Cannot add service {name!s} to run-level {level!s}."
|
msgid "Cannot add service {name!s} to run-level {level!s}."
|
||||||
@ -173,7 +174,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/services-openrc/main.py:101
|
#: src/modules/services-openrc/main.py:101
|
||||||
msgid "Target runlevel does not exist"
|
msgid "Target runlevel does not exist"
|
||||||
msgstr ""
|
msgstr "Target runlevel does not exist"
|
||||||
|
|
||||||
#: src/modules/services-openrc/main.py:102
|
#: src/modules/services-openrc/main.py:102
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -193,7 +194,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/networkcfg/main.py:29
|
#: src/modules/networkcfg/main.py:29
|
||||||
msgid "Saving network configuration."
|
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:50 src/modules/packages/main.py:59
|
||||||
#: src/modules/packages/main.py:69
|
#: 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:638 src/modules/packages/main.py:650
|
||||||
#: src/modules/packages/main.py:678
|
#: src/modules/packages/main.py:678
|
||||||
msgid "Package Manager error"
|
msgid "Package Manager error"
|
||||||
msgstr ""
|
msgstr "Package Manager error"
|
||||||
|
|
||||||
#: src/modules/packages/main.py:639
|
#: src/modules/packages/main.py:639
|
||||||
msgid ""
|
msgid ""
|
||||||
|
@ -319,7 +319,7 @@ msgstr "systemd लक्ष्य <code>{name!s}</code>सक्रिय क
|
|||||||
|
|
||||||
#: src/modules/services-systemd/main.py:67
|
#: src/modules/services-systemd/main.py:67
|
||||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||||
msgstr ""
|
msgstr "systemd टाइमर <code>{name!s}</code>सक्रिय करना विफल।"
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:71
|
#: src/modules/services-systemd/main.py:71
|
||||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
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 "
|
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||||
"installed."
|
"installed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"unsqaushfs खोजने में विफल, सुनिश्चित करें कि squashfs-tools पैकेज इंस्टॉल "
|
||||||
|
"है।"
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:479
|
#: src/modules/unpackfs/main.py:479
|
||||||
msgid "The destination \"{}\" in the target system is not a directory"
|
msgid "The destination \"{}\" in the target system is not a directory"
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# Marcin Mikołajczak <me@mkljczk.pl>, 2017
|
# marcin mikołajczak <me@mkljczk.pl>, 2017
|
||||||
# KagiSame, 2018
|
# KagiSame, 2018
|
||||||
# Piotr Strębski <strebski@gmail.com>, 2020
|
# Piotr Strębski <strebski@gmail.com>, 2020
|
||||||
# Jacob B. <brickminerplyt@gmail.com>, 2021
|
# Jacob B. <brickminerplyt@gmail.com>, 2021
|
||||||
|
@ -330,7 +330,7 @@ msgstr "Não é possível habilitar o alvo <code>{name!s}</code> do systemd."
|
|||||||
|
|
||||||
#: src/modules/services-systemd/main.py:67
|
#: src/modules/services-systemd/main.py:67
|
||||||
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
msgid "Cannot enable systemd timer <code>{name!s}</code>."
|
||||||
msgstr ""
|
msgstr "Não foi possível ativar o cronômetro systemd <code>{name!s}</code>."
|
||||||
|
|
||||||
#: src/modules/services-systemd/main.py:71
|
#: src/modules/services-systemd/main.py:71
|
||||||
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
msgid "Cannot disable systemd target <code>{name!s}</code>."
|
||||||
@ -410,6 +410,8 @@ msgid ""
|
|||||||
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
"Failed to find unsquashfs, make sure you have the squashfs-tools package "
|
||||||
"installed."
|
"installed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Não foi possível encontrar o unsquashfs, certifique-se de que o pacote "
|
||||||
|
"squashfs-tools foi instalado."
|
||||||
|
|
||||||
#: src/modules/unpackfs/main.py:479
|
#: src/modules/unpackfs/main.py:479
|
||||||
msgid "The destination \"{}\" in the target system is not a directory"
|
msgid "The destination \"{}\" in the target system is not a directory"
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
# Translators:
|
# Translators:
|
||||||
# Jobava Jobava <jobaval10n@gmail.com>, 2018
|
# Jobava Jobava <jobaval10n@gmail.com>, 2018
|
||||||
# Sebastian Brici <bricisebastian@gmail.com>, 2018
|
# Sebastian Brici <bricisebastian@gmail.com>, 2018
|
||||||
|
# Chele Ion <krovyoll@gmail.com>, 2021
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -14,7 +15,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||||
"PO-Revision-Date: 2017-08-09 10:34+0000\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"
|
"Language-Team: Romanian (https://www.transifex.com/calamares/teams/20061/ro/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -24,7 +25,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:32
|
#: src/modules/initramfscfg/main.py:32
|
||||||
msgid "Configuring initramfs."
|
msgid "Configuring initramfs."
|
||||||
msgstr ""
|
msgstr "Configurare initramfs"
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:85 src/modules/initramfscfg/main.py:89
|
#: 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:355 src/modules/fstab/main.py:361
|
||||||
@ -36,21 +37,21 @@ msgstr ""
|
|||||||
#: src/modules/luksopenswaphookcfg/main.py:86
|
#: src/modules/luksopenswaphookcfg/main.py:86
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:90
|
#: src/modules/luksopenswaphookcfg/main.py:90
|
||||||
msgid "Configuration Error"
|
msgid "Configuration Error"
|
||||||
msgstr ""
|
msgstr "Eroare de configurare"
|
||||||
|
|
||||||
#: src/modules/initramfscfg/main.py:86 src/modules/fstab/main.py:356
|
#: 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/initcpiocfg/main.py:228 src/modules/mount/main.py:145
|
||||||
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
#: src/modules/rawfs/main.py:165 src/modules/openrcdmcryptcfg/main.py:73
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:87
|
#: src/modules/luksopenswaphookcfg/main.py:87
|
||||||
msgid "No partitions are defined for <pre>{!s}</pre> to use."
|
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/initramfscfg/main.py:90 src/modules/fstab/main.py:362
|
||||||
#: src/modules/networkcfg/main.py:106 src/modules/initcpiocfg/main.py:232
|
#: 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/localecfg/main.py:136 src/modules/openrcdmcryptcfg/main.py:77
|
||||||
#: src/modules/luksopenswaphookcfg/main.py:91
|
#: src/modules/luksopenswaphookcfg/main.py:91
|
||||||
msgid "No root mount point is given for <pre>{!s}</pre> to use."
|
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
|
#: src/modules/grubcfg/main.py:28
|
||||||
msgid "Configure GRUB."
|
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,6 +5,7 @@
|
|||||||
#
|
#
|
||||||
# Translators:
|
# Translators:
|
||||||
# T. Tran <transifex@emiu.net>, 2020
|
# T. Tran <transifex@emiu.net>, 2020
|
||||||
|
# th1nhhdk <th1nhhdk@tutanota.com>, 2021
|
||||||
#
|
#
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
msgid ""
|
msgid ""
|
||||||
@ -13,7 +14,7 @@ msgstr ""
|
|||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
"POT-Creation-Date: 2021-11-02 15:45+0100\n"
|
||||||
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
"PO-Revision-Date: 2017-08-09 10:34+0000\n"
|
||||||
"Last-Translator: T. Tran <transifex@emiu.net>, 2020\n"
|
"Last-Translator: th1nhhdk <th1nhhdk@tutanota.com>, 2021\n"
|
||||||
"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n"
|
"Language-Team: Vietnamese (https://www.transifex.com/calamares/teams/20061/vi/)\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
@ -61,13 +62,15 @@ msgstr "Đang cài đặt bộ khởi động."
|
|||||||
|
|
||||||
#: src/modules/bootloader/main.py:508
|
#: src/modules/bootloader/main.py:508
|
||||||
msgid "Bootloader installation error"
|
msgid "Bootloader installation error"
|
||||||
msgstr ""
|
msgstr "Lỗi cài đặt trình khởi động(bootloader)"
|
||||||
|
|
||||||
#: src/modules/bootloader/main.py:509
|
#: src/modules/bootloader/main.py:509
|
||||||
msgid ""
|
msgid ""
|
||||||
"The bootloader could not be installed. The installation command "
|
"The bootloader could not be installed. The installation command "
|
||||||
"<pre>{!s}</pre> returned error code {!s}."
|
"<pre>{!s}</pre> returned error code {!s}."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
"Trình khởi động(bootloader) không thể được cài đặt. Lệnh cài đặt "
|
||||||
|
"<pre>{!s}</pre>đã trả mã lỗi {!s}."
|
||||||
|
|
||||||
#: src/modules/fstab/main.py:29
|
#: src/modules/fstab/main.py:29
|
||||||
msgid "Writing fstab."
|
msgid "Writing fstab."
|
||||||
|
@ -26,6 +26,11 @@ namespace CalamaresPython
|
|||||||
boost::python::object
|
boost::python::object
|
||||||
variantToPyObject( const QVariant& variant )
|
variantToPyObject( const QVariant& variant )
|
||||||
{
|
{
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||||
|
#endif
|
||||||
|
// 49 enumeration values not handled
|
||||||
switch ( variant.type() )
|
switch ( variant.type() )
|
||||||
{
|
{
|
||||||
case QVariant::Map:
|
case QVariant::Map:
|
||||||
@ -62,6 +67,9 @@ variantToPyObject( const QVariant& variant )
|
|||||||
default:
|
default:
|
||||||
return bp::object();
|
return bp::object();
|
||||||
}
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,6 +23,11 @@ static const char* s_preScript = nullptr;
|
|||||||
|
|
||||||
namespace bp = boost::python;
|
namespace bp = boost::python;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wdisabled-macro-expansion"
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 );
|
BOOST_PYTHON_FUNCTION_OVERLOADS( mount_overloads, CalamaresPython::mount, 2, 4 );
|
||||||
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_str_overloads, CalamaresPython::target_env_call, 1, 3 );
|
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_str_overloads, CalamaresPython::target_env_call, 1, 3 );
|
||||||
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_list_overloads, CalamaresPython::target_env_call, 1, 3 );
|
BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_call_list_overloads, CalamaresPython::target_env_call, 1, 3 );
|
||||||
@ -42,6 +47,10 @@ BOOST_PYTHON_FUNCTION_OVERLOADS( target_env_process_output_overloads,
|
|||||||
4 );
|
4 );
|
||||||
BOOST_PYTHON_FUNCTION_OVERLOADS( host_env_process_output_overloads, CalamaresPython::host_env_process_output, 1, 4 );
|
BOOST_PYTHON_FUNCTION_OVERLOADS( host_env_process_output_overloads, CalamaresPython::host_env_process_output, 1, 4 );
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
BOOST_PYTHON_MODULE( libcalamares )
|
BOOST_PYTHON_MODULE( libcalamares )
|
||||||
{
|
{
|
||||||
bp::object package = bp::scope();
|
bp::object package = bp::scope();
|
||||||
|
@ -22,6 +22,11 @@ namespace Partition
|
|||||||
QString
|
QString
|
||||||
prettyNameForFileSystemType( FileSystem::Type t )
|
prettyNameForFileSystemType( FileSystem::Type t )
|
||||||
{
|
{
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||||
|
#endif
|
||||||
|
// 13 enumeration values not handled
|
||||||
switch ( t )
|
switch ( t )
|
||||||
{
|
{
|
||||||
case FileSystem::Unknown:
|
case FileSystem::Unknown:
|
||||||
@ -60,11 +65,19 @@ prettyNameForFileSystemType( FileSystem::Type t )
|
|||||||
default:
|
default:
|
||||||
return FileSystem::nameForType( t );
|
return FileSystem::nameForType( t );
|
||||||
}
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
untranslatedFS( FileSystem::Type t )
|
untranslatedFS( FileSystem::Type t )
|
||||||
{
|
{
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic push
|
||||||
|
#pragma clang diagnostic ignored "-Wswitch-enum"
|
||||||
|
#endif
|
||||||
|
// 34 enumeration values not handled
|
||||||
switch ( t )
|
switch ( t )
|
||||||
{
|
{
|
||||||
case FileSystem::Type::ReiserFS:
|
case FileSystem::Type::ReiserFS:
|
||||||
@ -72,6 +85,9 @@ untranslatedFS( FileSystem::Type t )
|
|||||||
default:
|
default:
|
||||||
return FileSystem::nameForType( t, { QStringLiteral( "C" ) } );
|
return FileSystem::nameForType( t, { QStringLiteral( "C" ) } );
|
||||||
}
|
}
|
||||||
|
#ifdef __clang__
|
||||||
|
#pragma clang diagnostic pop
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Partition
|
} // namespace Partition
|
||||||
|
@ -115,12 +115,14 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
|||||||
QString completePath = targetPath( path );
|
QString completePath = targetPath( path );
|
||||||
if ( completePath.isEmpty() )
|
if ( completePath.isEmpty() )
|
||||||
{
|
{
|
||||||
|
cWarning() << "No target path for" << path;
|
||||||
return CreationResult( CreationResult::Code::Invalid );
|
return CreationResult( CreationResult::Code::Invalid );
|
||||||
}
|
}
|
||||||
|
|
||||||
QFile f( completePath );
|
QFile f( completePath );
|
||||||
if ( ( mode == WriteMode::KeepExisting ) && f.exists() )
|
if ( ( mode == WriteMode::KeepExisting ) && f.exists() )
|
||||||
{
|
{
|
||||||
|
cWarning() << "Target file" << completePath << "already exists";
|
||||||
return CreationResult( CreationResult::Code::AlreadyExists );
|
return CreationResult( CreationResult::Code::AlreadyExists );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,13 +135,16 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
|||||||
|
|
||||||
if ( !f.open( m ) )
|
if ( !f.open( m ) )
|
||||||
{
|
{
|
||||||
|
cWarning() << "Could not open target file" << completePath;
|
||||||
return CreationResult( CreationResult::Code::Failed );
|
return CreationResult( CreationResult::Code::Failed );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( f.write( contents ) != contents.size() )
|
auto written = f.write( contents );
|
||||||
|
if ( written != contents.size() )
|
||||||
{
|
{
|
||||||
f.close();
|
f.close();
|
||||||
f.remove();
|
f.remove();
|
||||||
|
cWarning() << "Short write (" << written << "out of" << contents.size() << "bytes) to" << completePath;
|
||||||
return CreationResult( CreationResult::Code::Failed );
|
return CreationResult( CreationResult::Code::Failed );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +152,30 @@ System::createTargetFile( const QString& path, const QByteArray& contents, Write
|
|||||||
return CreationResult( QFileInfo( f ).canonicalFilePath() );
|
return CreationResult( QFileInfo( f ).canonicalFilePath() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QStringList
|
||||||
|
System::readTargetFile( const QString& path ) const
|
||||||
|
{
|
||||||
|
const QString completePath = targetPath( path );
|
||||||
|
if ( completePath.isEmpty() )
|
||||||
|
{
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile f( completePath );
|
||||||
|
if ( !f.open( QIODevice::ReadOnly ) )
|
||||||
|
{
|
||||||
|
return QStringList();
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextStream in( &f );
|
||||||
|
QStringList l;
|
||||||
|
while ( !f.atEnd() )
|
||||||
|
{
|
||||||
|
l << in.readLine();
|
||||||
|
}
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
System::removeTargetFile( const QString& path ) const
|
System::removeTargetFile( const QString& path ) const
|
||||||
{
|
{
|
||||||
|
@ -287,6 +287,24 @@ public:
|
|||||||
*/
|
*/
|
||||||
DLLEXPORT void removeTargetFile( const QString& path ) const;
|
DLLEXPORT void removeTargetFile( const QString& path ) const;
|
||||||
|
|
||||||
|
/** @brief Reads a file from the target system.
|
||||||
|
*
|
||||||
|
* @param path Path to the file; this is interpreted from the root of
|
||||||
|
* the target system (@see targetPath()).
|
||||||
|
*
|
||||||
|
* Does no error checking, and returns an empty list if the file does
|
||||||
|
* not exist.
|
||||||
|
*
|
||||||
|
* NOTE: This function is now basically the same as QFile::readAll(),
|
||||||
|
* splitting into lines, but Calamares may need to change
|
||||||
|
* permissions or raise privileges to actually read the file,
|
||||||
|
* which is why there is an API.
|
||||||
|
*
|
||||||
|
* NOTE: Since this buffers the whole file in memory, reading big files
|
||||||
|
* is not recommended.
|
||||||
|
*/
|
||||||
|
DLLEXPORT QStringList readTargetFile( const QString& path ) const;
|
||||||
|
|
||||||
/** @brief Ensure that the directory @p path exists
|
/** @brief Ensure that the directory @p path exists
|
||||||
*
|
*
|
||||||
* @param path a full pathname to a desired directory.
|
* @param path a full pathname to a desired directory.
|
||||||
|
@ -224,5 +224,26 @@ truncateMultiLine( const QString& string, CalamaresUtils::LinesStartEnd lines, C
|
|||||||
return front + back.right( chars.total / 2 );
|
return front + back.right( chars.total / 2 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
removeLeading( QString& string, QChar c )
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
while ( string.length() > count && string[ count ] == c )
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
string.remove( 0, count );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
removeTrailing( QString& string, QChar c )
|
||||||
|
{
|
||||||
|
int lastIndex = string.length();
|
||||||
|
while ( lastIndex > 0 && string[ lastIndex - 1 ] == c )
|
||||||
|
{
|
||||||
|
lastIndex--;
|
||||||
|
}
|
||||||
|
string.remove( lastIndex, string.length() );
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
@ -100,6 +100,19 @@ DLLEXPORT QString truncateMultiLine( const QString& string,
|
|||||||
LinesStartEnd lines = LinesStartEnd { 3, 5 },
|
LinesStartEnd lines = LinesStartEnd { 3, 5 },
|
||||||
CharCount chars = CharCount { 812 } );
|
CharCount chars = CharCount { 812 } );
|
||||||
|
|
||||||
|
/** @brief Remove all @p c at the beginning of @p string
|
||||||
|
*
|
||||||
|
* Modifies the @p string in-place. If @p c is not the first character
|
||||||
|
* of @p string, the string is left unchanged; otherwise the first character
|
||||||
|
* is removed and the process repeats.
|
||||||
|
*/
|
||||||
|
DLLEXPORT void removeLeading( QString& string, QChar c );
|
||||||
|
/** @brief Remove all @p c at the end of @p string
|
||||||
|
*
|
||||||
|
* Like removeLeading(), but at the end of the string.
|
||||||
|
*/
|
||||||
|
DLLEXPORT void removeTrailing( QString& string, QChar c );
|
||||||
|
|
||||||
} // namespace CalamaresUtils
|
} // namespace CalamaresUtils
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -70,12 +70,19 @@ private Q_SLOTS:
|
|||||||
void testStringTruncation();
|
void testStringTruncation();
|
||||||
void testStringTruncationShorter();
|
void testStringTruncationShorter();
|
||||||
void testStringTruncationDegenerate();
|
void testStringTruncationDegenerate();
|
||||||
|
void testStringRemoveLeading_data();
|
||||||
|
void testStringRemoveLeading();
|
||||||
|
void testStringRemoveTrailing_data();
|
||||||
|
void testStringRemoveTrailing();
|
||||||
|
|
||||||
/** @section Test Runner directory-manipulation. */
|
/** @section Test Runner directory-manipulation. */
|
||||||
void testRunnerDirs();
|
void testRunnerDirs();
|
||||||
void testCalculateWorkingDirectory();
|
void testCalculateWorkingDirectory();
|
||||||
void testRunnerOutput();
|
void testRunnerOutput();
|
||||||
|
|
||||||
|
/** @section Test file-functions */
|
||||||
|
void testReadWriteFile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void recursiveCompareMap( const QVariantMap& a, const QVariantMap& b, int depth );
|
void recursiveCompareMap( const QVariantMap& a, const QVariantMap& b, int depth );
|
||||||
};
|
};
|
||||||
@ -751,6 +758,64 @@ LibCalamaresTests::testStringTruncationDegenerate()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibCalamaresTests::testStringRemoveLeading_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn< QString >( "string" );
|
||||||
|
QTest::addColumn< char >( "c" );
|
||||||
|
QTest::addColumn< QString >( "result" );
|
||||||
|
|
||||||
|
QTest::newRow( "empty" ) << QString() << '/' << QString();
|
||||||
|
QTest::newRow( "one-slash" ) << QStringLiteral( "/tmp" ) << '/' << QStringLiteral( "tmp" );
|
||||||
|
QTest::newRow( "two-slash" ) << QStringLiteral( "//tmp" ) << '/' << QStringLiteral( "tmp" );
|
||||||
|
QTest::newRow( "multi-slash" ) << QStringLiteral( "/tmp/p" ) << '/' << QStringLiteral( "tmp/p" );
|
||||||
|
QTest::newRow( "later-slash" ) << QStringLiteral( "@/tmp" ) << '/' << QStringLiteral( "@/tmp" );
|
||||||
|
QTest::newRow( "all-one-slash" ) << QStringLiteral( "/" ) << '/' << QString();
|
||||||
|
QTest::newRow( "all-many-slash" ) << QStringLiteral( "////////////////////" ) << '/' << QString();
|
||||||
|
QTest::newRow( "trailing" ) << QStringLiteral( "tmp/" ) << '/' << QStringLiteral( "tmp/" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibCalamaresTests::testStringRemoveLeading()
|
||||||
|
{
|
||||||
|
QFETCH( QString, string );
|
||||||
|
QFETCH( char, c );
|
||||||
|
QFETCH( QString, result );
|
||||||
|
|
||||||
|
const QString initial = string;
|
||||||
|
CalamaresUtils::removeLeading( string, c );
|
||||||
|
QCOMPARE( string, result );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibCalamaresTests::testStringRemoveTrailing_data()
|
||||||
|
{
|
||||||
|
QTest::addColumn< QString >( "string" );
|
||||||
|
QTest::addColumn< char >( "c" );
|
||||||
|
QTest::addColumn< QString >( "result" );
|
||||||
|
|
||||||
|
QTest::newRow( "empty" ) << QString() << '/' << QString();
|
||||||
|
QTest::newRow( "one-slash" ) << QStringLiteral( "/tmp" ) << '/' << QStringLiteral( "/tmp" );
|
||||||
|
QTest::newRow( "two-slash" ) << QStringLiteral( "//tmp" ) << '/' << QStringLiteral( "//tmp" );
|
||||||
|
QTest::newRow( "multi-slash" ) << QStringLiteral( "/tmp//p/" ) << '/' << QStringLiteral( "/tmp//p" );
|
||||||
|
QTest::newRow( "later-slash" ) << QStringLiteral( "@/tmp/@" ) << '/' << QStringLiteral( "@/tmp/@" );
|
||||||
|
QTest::newRow( "later-slash2" ) << QStringLiteral( "@/tmp/@//" ) << '/' << QStringLiteral( "@/tmp/@" );
|
||||||
|
QTest::newRow( "all-one-slash" ) << QStringLiteral( "/" ) << '/' << QString();
|
||||||
|
QTest::newRow( "all-many-slash" ) << QStringLiteral( "////////////////////" ) << '/' << QString();
|
||||||
|
QTest::newRow( "trailing" ) << QStringLiteral( "tmp/" ) << '/' << QStringLiteral( "tmp" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibCalamaresTests::testStringRemoveTrailing()
|
||||||
|
{
|
||||||
|
QFETCH( QString, string );
|
||||||
|
QFETCH( char, c );
|
||||||
|
QFETCH( QString, result );
|
||||||
|
|
||||||
|
const QString initial = string;
|
||||||
|
CalamaresUtils::removeTrailing( string, c );
|
||||||
|
QCOMPARE( string, result );
|
||||||
|
}
|
||||||
|
|
||||||
static QString
|
static QString
|
||||||
dirname( const QTemporaryDir& d )
|
dirname( const QTemporaryDir& d )
|
||||||
@ -950,6 +1015,84 @@ LibCalamaresTests::testRunnerOutput()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
LibCalamaresTests::testReadWriteFile()
|
||||||
|
{
|
||||||
|
static const QByteArray otherContents( "derp\n" );
|
||||||
|
|
||||||
|
QTemporaryDir tempRoot( QDir::tempPath() + QStringLiteral( "/test-job-XXXXXX" ) );
|
||||||
|
auto* ss = file_setup( tempRoot );
|
||||||
|
|
||||||
|
QVERIFY( ss );
|
||||||
|
{
|
||||||
|
auto fullPath = ss->createTargetFile( "test0", QByteArray(), CalamaresUtils::System::WriteMode::Overwrite );
|
||||||
|
QVERIFY( fullPath );
|
||||||
|
QVERIFY( !fullPath.path().isEmpty() );
|
||||||
|
|
||||||
|
QFileInfo fi( fullPath.path() );
|
||||||
|
QVERIFY( fi.exists() );
|
||||||
|
QVERIFY( fi.isFile() );
|
||||||
|
QCOMPARE( fi.size(), 0 );
|
||||||
|
}
|
||||||
|
// It won't overwrite unless you ask for it
|
||||||
|
{
|
||||||
|
auto fullPath = ss->createTargetFile( "test0", otherContents );
|
||||||
|
QVERIFY( !fullPath ); // Failed, because it won't overwrite
|
||||||
|
QCOMPARE( fullPath.code(), decltype( fullPath )::Code::AlreadyExists );
|
||||||
|
QVERIFY( fullPath.path().isEmpty() ); // Because it wasn't written
|
||||||
|
|
||||||
|
QFileInfo fi( tempRoot.filePath( "test0" ) ); // Compute the name some other way
|
||||||
|
QVERIFY( fi.exists() );
|
||||||
|
QVERIFY( fi.isFile() );
|
||||||
|
QCOMPARE( fi.size(), 0 );
|
||||||
|
}
|
||||||
|
// But it will if you say so explicitly
|
||||||
|
{
|
||||||
|
auto fullPath = ss->createTargetFile( "test0", otherContents, CalamaresUtils::System::WriteMode::Overwrite );
|
||||||
|
QVERIFY( fullPath );
|
||||||
|
QVERIFY( !fullPath.path().isEmpty() );
|
||||||
|
|
||||||
|
QFileInfo fi( fullPath.path() );
|
||||||
|
QVERIFY( fi.exists() );
|
||||||
|
QVERIFY( fi.isFile() );
|
||||||
|
QCOMPARE( fi.size(), 5 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now it's been written, we can read it, too
|
||||||
|
{
|
||||||
|
auto contents = ss->readTargetFile( "test0" );
|
||||||
|
QVERIFY( !contents.isEmpty() );
|
||||||
|
QCOMPARE( contents.count(), 1 );
|
||||||
|
QCOMPARE( contents[ 0 ], QStringLiteral( "derp" ) ); // No trailing \n
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN( LibCalamaresTests )
|
QTEST_GUILESS_MAIN( LibCalamaresTests )
|
||||||
|
|
||||||
#include "utils/moc-warnings.h"
|
#include "utils/moc-warnings.h"
|
||||||
|
@ -162,14 +162,15 @@ uploadServerFromMap( const QVariantMap& map )
|
|||||||
|
|
||||||
if ( typestring.isEmpty() || urlstring.isEmpty() )
|
if ( typestring.isEmpty() || urlstring.isEmpty() )
|
||||||
{
|
{
|
||||||
return Branding::UploadServerInfo( Branding::UploadServerType::None, QUrl(), 0 );
|
return Branding::UploadServerInfo { Branding::UploadServerType::None, QUrl(), 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bogus = false; // we don't care about type-name lookup success here
|
bool bogus = false; // we don't care about type-name lookup success here
|
||||||
return Branding::UploadServerInfo(
|
return Branding::UploadServerInfo {
|
||||||
names.find( typestring, bogus ),
|
names.find( typestring, bogus ),
|
||||||
QUrl( urlstring, QUrl::ParsingMode::StrictMode ),
|
QUrl( urlstring, QUrl::ParsingMode::StrictMode ),
|
||||||
sizeLimitKiB >= 0 ? CalamaresUtils::KiBtoBytes( static_cast< unsigned long long >( sizeLimitKiB ) ) : -1 );
|
sizeLimitKiB >= 0 ? CalamaresUtils::KiBtoBytes( static_cast< unsigned long long >( sizeLimitKiB ) ) : -1
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Load the @p map with strings from @p config
|
/** @brief Load the @p map with strings from @p config
|
||||||
|
@ -227,7 +227,14 @@ public:
|
|||||||
* is irrelevant and usually empty), the URL for the upload and the size limit of upload
|
* is irrelevant and usually empty), the URL for the upload and the size limit of upload
|
||||||
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
|
* in bytes (for configuration value < 0, it serves -1, which stands for having no limit).
|
||||||
*/
|
*/
|
||||||
using UploadServerInfo = std::tuple< UploadServerType, QUrl, qint64 >;
|
struct UploadServerInfo
|
||||||
|
{
|
||||||
|
UploadServerType type;
|
||||||
|
QUrl url;
|
||||||
|
qint64 size;
|
||||||
|
|
||||||
|
operator bool() const { return type != Calamares::Branding::UploadServerType::None && size != 0; }
|
||||||
|
};
|
||||||
UploadServerInfo uploadServer() const { return m_uploadServer; }
|
UploadServerInfo uploadServer() const { return m_uploadServer; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -27,6 +27,7 @@ set( calamaresui_SOURCES
|
|||||||
viewpages/ViewStep.cpp
|
viewpages/ViewStep.cpp
|
||||||
|
|
||||||
widgets/ClickableLabel.cpp
|
widgets/ClickableLabel.cpp
|
||||||
|
widgets/ErrorDialog.cpp
|
||||||
widgets/FixedAspectRatioLabel.cpp
|
widgets/FixedAspectRatioLabel.cpp
|
||||||
widgets/PrettyRadioButton.cpp
|
widgets/PrettyRadioButton.cpp
|
||||||
widgets/TranslationFix.cpp
|
widgets/TranslationFix.cpp
|
||||||
@ -39,8 +40,6 @@ set( calamaresui_SOURCES
|
|||||||
|
|
||||||
# Don't warn about third-party sources
|
# Don't warn about third-party sources
|
||||||
mark_thirdparty_code(
|
mark_thirdparty_code(
|
||||||
${CMAKE_SOURCE_DIR}/3rdparty/qjsonitem.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/3rdparty/qjsonmodel.cpp
|
|
||||||
${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp
|
${CMAKE_SOURCE_DIR}/3rdparty/waitingspinnerwidget.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,6 +63,8 @@ calamares_add_library( calamaresui
|
|||||||
Qt5::Svg
|
Qt5::Svg
|
||||||
RESOURCES libcalamaresui.qrc
|
RESOURCES libcalamaresui.qrc
|
||||||
EXPORT Calamares
|
EXPORT Calamares
|
||||||
|
UI
|
||||||
|
utils/ErrorDialog/ErrorDialog.ui
|
||||||
VERSION ${CALAMARES_VERSION_SHORT}
|
VERSION ${CALAMARES_VERSION_SHORT}
|
||||||
)
|
)
|
||||||
target_link_libraries( calamaresui PRIVATE yamlcpp::yamlcpp )
|
target_link_libraries( calamaresui PRIVATE yamlcpp::yamlcpp )
|
||||||
|
@ -24,11 +24,13 @@
|
|||||||
#include "viewpages/BlankViewStep.h"
|
#include "viewpages/BlankViewStep.h"
|
||||||
#include "viewpages/ExecutionViewStep.h"
|
#include "viewpages/ExecutionViewStep.h"
|
||||||
#include "viewpages/ViewStep.h"
|
#include "viewpages/ViewStep.h"
|
||||||
|
#include "widgets/ErrorDialog.h"
|
||||||
#include "widgets/TranslationFix.h"
|
#include "widgets/TranslationFix.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QMetaObject>
|
#include <QMetaObject>
|
||||||
@ -150,56 +152,32 @@ ViewManager::insertViewStep( int before, ViewStep* step )
|
|||||||
void
|
void
|
||||||
ViewManager::onInstallationFailed( const QString& message, const QString& details )
|
ViewManager::onInstallationFailed( const QString& message, const QString& details )
|
||||||
{
|
{
|
||||||
bool shouldOfferWebPaste = std::get< 0 >( Calamares::Branding::instance()->uploadServer() )
|
|
||||||
!= Calamares::Branding::UploadServerType::None
|
|
||||||
and std::get< 2 >( Calamares::Branding::instance()->uploadServer() ) != 0;
|
|
||||||
|
|
||||||
cError() << "Installation failed:" << message;
|
cError() << "Installation failed:" << message;
|
||||||
cDebug() << Logger::SubEntry << "- message:" << message;
|
cDebug() << Logger::SubEntry << "- message:" << message;
|
||||||
cDebug() << Logger::SubEntry << "- details:" << Logger::NoQuote << details;
|
cDebug() << Logger::SubEntry << "- details:" << Logger::NoQuote << details;
|
||||||
|
|
||||||
QString heading
|
QString heading
|
||||||
= Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" );
|
= Calamares::Settings::instance()->isSetupMode() ? tr( "Setup Failed" ) : tr( "Installation Failed" );
|
||||||
QString pasteMsg = tr( "Would you like to paste the install log to the web?" );
|
|
||||||
QString text = "<p>" + message + "</p>";
|
|
||||||
if ( !details.isEmpty() )
|
|
||||||
{
|
|
||||||
text += "<p>"
|
|
||||||
+ CalamaresUtils::truncateMultiLine( details, CalamaresUtils::LinesStartEnd { 6, 2 } )
|
|
||||||
.replace( '\n', QStringLiteral( "<br/>" ) )
|
|
||||||
+ "</p>";
|
|
||||||
}
|
|
||||||
if ( shouldOfferWebPaste )
|
|
||||||
{
|
|
||||||
text += "<p>" + pasteMsg + "</p>";
|
|
||||||
}
|
|
||||||
|
|
||||||
QMessageBox* msgBox = new QMessageBox();
|
ErrorDialog* errorDialog = new ErrorDialog();
|
||||||
msgBox->setIcon( QMessageBox::Critical );
|
errorDialog->setWindowTitle( tr( "Error" ) );
|
||||||
msgBox->setWindowTitle( tr( "Error" ) );
|
errorDialog->setHeading( "<strong>" + heading + "</strong>" );
|
||||||
msgBox->setText( "<strong>" + heading + "</strong>" );
|
errorDialog->setInformativeText( message );
|
||||||
msgBox->setInformativeText( text );
|
errorDialog->setShouldOfferWebPaste( Calamares::Branding::instance()->uploadServer() );
|
||||||
if ( shouldOfferWebPaste )
|
errorDialog->setDetails( details );
|
||||||
{
|
errorDialog->show();
|
||||||
msgBox->setStandardButtons( QMessageBox::Yes | QMessageBox::No );
|
|
||||||
msgBox->setDefaultButton( QMessageBox::No );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msgBox->setStandardButtons( QMessageBox::Close );
|
|
||||||
msgBox->setDefaultButton( QMessageBox::Close );
|
|
||||||
}
|
|
||||||
Calamares::fixButtonLabels( msgBox );
|
|
||||||
msgBox->show();
|
|
||||||
|
|
||||||
cDebug() << "Calamares will quit when the dialog closes.";
|
cDebug() << "Calamares will quit when the dialog closes.";
|
||||||
connect( msgBox, &QMessageBox::buttonClicked, [msgBox]( QAbstractButton* button ) {
|
connect( errorDialog,
|
||||||
if ( msgBox->buttonRole( button ) == QMessageBox::ButtonRole::YesRole )
|
&QDialog::finished,
|
||||||
{
|
[ errorDialog ]( int result )
|
||||||
CalamaresUtils::Paste::doLogUploadUI( msgBox );
|
{
|
||||||
}
|
if ( result == QDialog::Accepted && errorDialog->shouldOfferWebPaste() )
|
||||||
QApplication::quit();
|
{
|
||||||
} );
|
CalamaresUtils::Paste::doLogUploadUI( errorDialog );
|
||||||
|
}
|
||||||
|
QApplication::quit();
|
||||||
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,7 +69,8 @@ STATICTEST QString
|
|||||||
ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* parent )
|
ficheLogUpload( const QByteArray& pasteData, const QUrl& serverUrl, QObject* parent )
|
||||||
{
|
{
|
||||||
QTcpSocket* socket = new QTcpSocket( parent );
|
QTcpSocket* socket = new QTcpSocket( parent );
|
||||||
socket->connectToHost( serverUrl.host(), serverUrl.port() );
|
// 16 bits of port-number
|
||||||
|
socket->connectToHost( serverUrl.host(), quint16( serverUrl.port() ) );
|
||||||
|
|
||||||
if ( !socket->waitForConnected() )
|
if ( !socket->waitForConnected() )
|
||||||
{
|
{
|
||||||
|
106
src/libcalamaresui/widgets/ErrorDialog.cpp
Normal file
106
src/libcalamaresui/widgets/ErrorDialog.cpp
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Artem Grinev <agrinev@manjaro.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ErrorDialog.h"
|
||||||
|
#include "ui_ErrorDialog.h"
|
||||||
|
|
||||||
|
#include "widgets/TranslationFix.h"
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
namespace Calamares
|
||||||
|
{
|
||||||
|
|
||||||
|
ErrorDialog::ErrorDialog( QWidget* parent )
|
||||||
|
: QDialog( parent )
|
||||||
|
, ui( new Ui::ErrorDialog )
|
||||||
|
{
|
||||||
|
ui->setupUi( this );
|
||||||
|
ui->iconLabel->setPixmap( QIcon::fromTheme( "dialog-error" ).pixmap( 64 ) );
|
||||||
|
ui->detailsWidget->hide();
|
||||||
|
ui->offerWebPasteLabel->hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorDialog::~ErrorDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
ErrorDialog::heading() const
|
||||||
|
{
|
||||||
|
return ui->headingLabel->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
ErrorDialog::informativeText() const
|
||||||
|
{
|
||||||
|
return ui->informativeTextLabel->text();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString
|
||||||
|
ErrorDialog::details() const
|
||||||
|
{
|
||||||
|
return ui->detailsBrowser->toPlainText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ErrorDialog::setHeading( const QString& newHeading )
|
||||||
|
{
|
||||||
|
if ( ui->headingLabel->text() != newHeading )
|
||||||
|
{
|
||||||
|
ui->headingLabel->setText( newHeading );
|
||||||
|
emit headingChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ErrorDialog::setInformativeText( const QString& newInformativeText )
|
||||||
|
{
|
||||||
|
if ( ui->informativeTextLabel->text() != newInformativeText )
|
||||||
|
{
|
||||||
|
ui->informativeTextLabel->setText( newInformativeText );
|
||||||
|
emit informativeTextChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ErrorDialog::setDetails( const QString& newDetails )
|
||||||
|
{
|
||||||
|
if ( ui->detailsBrowser->toPlainText() != newDetails )
|
||||||
|
{
|
||||||
|
ui->detailsBrowser->setPlainText( newDetails );
|
||||||
|
ui->detailsWidget->setVisible( !ui->detailsBrowser->toPlainText().trimmed().isEmpty() );
|
||||||
|
emit detailsChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ErrorDialog::shouldOfferWebPaste() const
|
||||||
|
{
|
||||||
|
return m_shouldOfferWebPaste;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ErrorDialog::setShouldOfferWebPaste( bool newShouldOfferWebPaste )
|
||||||
|
{
|
||||||
|
if ( m_shouldOfferWebPaste != newShouldOfferWebPaste )
|
||||||
|
{
|
||||||
|
m_shouldOfferWebPaste = newShouldOfferWebPaste;
|
||||||
|
|
||||||
|
ui->offerWebPasteLabel->setVisible( m_shouldOfferWebPaste );
|
||||||
|
ui->buttonBox->setStandardButtons( m_shouldOfferWebPaste ? ( QDialogButtonBox::Yes | QDialogButtonBox::No )
|
||||||
|
: QDialogButtonBox::Close );
|
||||||
|
fixButtonLabels( ui->buttonBox );
|
||||||
|
|
||||||
|
emit shouldOfferWebPasteChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Calamares
|
83
src/libcalamaresui/widgets/ErrorDialog.h
Normal file
83
src/libcalamaresui/widgets/ErrorDialog.h
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
/* === This file is part of Calamares - <https://calamares.io> ===
|
||||||
|
*
|
||||||
|
* SPDX-FileCopyrightText: 2021 Artem Grinev <agrinev@manjaro.org>
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*
|
||||||
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBCALAMARESUI_ERRORDIALOG_H
|
||||||
|
#define LIBCALAMARESUI_ERRORDIALOG_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class ErrorDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Calamares
|
||||||
|
{
|
||||||
|
class ErrorDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( QString heading READ heading WRITE setHeading NOTIFY headingChanged )
|
||||||
|
Q_PROPERTY( QString informativeText READ informativeText WRITE setInformativeText NOTIFY informativeTextChanged )
|
||||||
|
Q_PROPERTY( QString details READ details WRITE setDetails NOTIFY detailsChanged )
|
||||||
|
Q_PROPERTY( bool shouldOfferWebPaste READ shouldOfferWebPaste WRITE setShouldOfferWebPaste NOTIFY
|
||||||
|
shouldOfferWebPasteChanged )
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ErrorDialog( QWidget* parent = nullptr );
|
||||||
|
~ErrorDialog() override;
|
||||||
|
|
||||||
|
/** @brief The heading (title) of the error dialog
|
||||||
|
*
|
||||||
|
* This is a short (one-line) title. It is human-readable, so should
|
||||||
|
* be translated at the time it is set.
|
||||||
|
*/
|
||||||
|
QString heading() const;
|
||||||
|
void setHeading( const QString& newHeading );
|
||||||
|
|
||||||
|
/** @brief The description of the problem
|
||||||
|
*
|
||||||
|
* Longer, human-readable, description of the problem. This text
|
||||||
|
* is word-wrapped as necessary.
|
||||||
|
*/
|
||||||
|
QString informativeText() const;
|
||||||
|
void setInformativeText( const QString& newInformativeText );
|
||||||
|
|
||||||
|
/** @brief Details of the problem
|
||||||
|
*
|
||||||
|
* This is generally command-output; it might not be translated
|
||||||
|
* when set. It should be considered "background to the informative
|
||||||
|
* text", or maybe "the reasons". Write the informative text for
|
||||||
|
* the end-user.
|
||||||
|
*/
|
||||||
|
QString details() const;
|
||||||
|
void setDetails( const QString& newDetails );
|
||||||
|
|
||||||
|
/** @brief Enable web-paste button
|
||||||
|
*
|
||||||
|
* The web-paste button can be configured at a global level,
|
||||||
|
* but each individual error dialog can be set separately.
|
||||||
|
*/
|
||||||
|
bool shouldOfferWebPaste() const;
|
||||||
|
void setShouldOfferWebPaste( bool newShouldOfferWebPaste );
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void headingChanged();
|
||||||
|
void informativeTextChanged();
|
||||||
|
void detailsChanged();
|
||||||
|
void shouldOfferWebPasteChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::ErrorDialog* ui;
|
||||||
|
bool m_shouldOfferWebPaste = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
}; // namespace Calamares
|
||||||
|
|
||||||
|
#endif // LIBCALAMARESUI_ERRORDIALOG_H
|
133
src/libcalamaresui/widgets/ErrorDialog.ui
Normal file
133
src/libcalamaresui/widgets/ErrorDialog.ui
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ErrorDialog</class>
|
||||||
|
<widget class="QDialog" name="ErrorDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>425</width>
|
||||||
|
<height>262</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string notr="true">Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="5" column="0" colspan="2">
|
||||||
|
<widget class="QWidget" name="detailsWidget" native="true">
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="informativeTextLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Details:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="detailsBrowser"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="0">
|
||||||
|
<widget class="QLabel" name="offerWebPasteLabel">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Would you like to paste the install log to the web?</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" colspan="2">
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="iconLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="headingLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true"/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>ErrorDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>ErrorDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@ -11,30 +11,34 @@
|
|||||||
|
|
||||||
#include <QAbstractButton>
|
#include <QAbstractButton>
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
|
|
||||||
|
//Using QMessageBox's StandardButton enum here but according to headers they should be kept in-sync between multiple classes.
|
||||||
|
static std::pair< decltype( QMessageBox::Ok ), const char* > maps[] = {
|
||||||
|
{ QMessageBox::Ok, QT_TRANSLATE_NOOP( "StandardButtons", "&OK" ) },
|
||||||
|
{ QMessageBox::Yes, QT_TRANSLATE_NOOP( "StandardButtons", "&Yes" ) },
|
||||||
|
{ QMessageBox::No, QT_TRANSLATE_NOOP( "StandardButtons", "&No" ) },
|
||||||
|
{ QMessageBox::Cancel, QT_TRANSLATE_NOOP( "StandardButtons", "&Cancel" ) },
|
||||||
|
{ QMessageBox::Close, QT_TRANSLATE_NOOP( "StandardButtons", "&Close" ) },
|
||||||
|
};
|
||||||
|
|
||||||
|
template < typename TButtonBox >
|
||||||
void
|
void
|
||||||
fixButtonLabels( QMessageBox* box )
|
fixButtonLabels( TButtonBox* box )
|
||||||
{
|
{
|
||||||
if ( !box )
|
if ( !box )
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::pair< decltype( QMessageBox::Ok ), const char* > maps[] = {
|
|
||||||
{ QMessageBox::Ok, QT_TRANSLATE_NOOP( "StandardButtons", "&OK" ) },
|
|
||||||
{ QMessageBox::Yes, QT_TRANSLATE_NOOP( "StandardButtons", "&Yes" ) },
|
|
||||||
{ QMessageBox::No, QT_TRANSLATE_NOOP( "StandardButtons", "&No" ) },
|
|
||||||
{ QMessageBox::Cancel, QT_TRANSLATE_NOOP( "StandardButtons", "&Cancel" ) },
|
|
||||||
{ QMessageBox::Close, QT_TRANSLATE_NOOP( "StandardButtons", "&Close" ) },
|
|
||||||
};
|
|
||||||
|
|
||||||
for ( auto [ sb, label ] : maps )
|
for ( auto [ sb, label ] : maps )
|
||||||
{
|
{
|
||||||
auto* button = box->button( sb );
|
auto* button = box->button( static_cast< typename TButtonBox::StandardButton >( int( sb ) ) );
|
||||||
if ( button )
|
if ( button )
|
||||||
{
|
{
|
||||||
button->setText( QCoreApplication::translate( "StandardButtons", label ) );
|
button->setText( QCoreApplication::translate( "StandardButtons", label ) );
|
||||||
@ -42,4 +46,16 @@ fixButtonLabels( QMessageBox* box )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fixButtonLabels( QMessageBox* box )
|
||||||
|
{
|
||||||
|
fixButtonLabels< QMessageBox >( box );
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fixButtonLabels( QDialogButtonBox* box )
|
||||||
|
{
|
||||||
|
fixButtonLabels< QDialogButtonBox >( box );
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Calamares
|
} // namespace Calamares
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
|
|
||||||
class QMessageBox;
|
class QMessageBox;
|
||||||
|
class QDialogButtonBox;
|
||||||
|
|
||||||
namespace Calamares
|
namespace Calamares
|
||||||
{
|
{
|
||||||
@ -26,6 +27,8 @@ namespace Calamares
|
|||||||
* guess the context.
|
* guess the context.
|
||||||
*/
|
*/
|
||||||
void UIDLLEXPORT fixButtonLabels( QMessageBox* );
|
void UIDLLEXPORT fixButtonLabels( QMessageBox* );
|
||||||
|
|
||||||
|
void UIDLLEXPORT fixButtonLabels( QDialogButtonBox* );
|
||||||
} // namespace Calamares
|
} // namespace Calamares
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -86,18 +86,18 @@ it needs those keys.
|
|||||||
|
|
||||||
### Emergency Modules
|
### Emergency Modules
|
||||||
|
|
||||||
Only C++ modules and job modules may be emergency modules. If, during an
|
If, during an *exec* step in the sequence, a module fails, installation as
|
||||||
*exec* step in the sequence, a module fails, installation as a whole fails
|
a whole fails and the install is aborted. If there are emergency modules
|
||||||
and the install is aborted. If there are emergency modules in the **same**
|
in the **same** exec block, those will be executed before the installation
|
||||||
exec block, those will be executed before the installation is aborted.
|
is aborted. Non-emergency modules are not executed.
|
||||||
Non-emergency modules are not executed.
|
|
||||||
|
|
||||||
If an emergency-module fails while processing emergency-modules for
|
If an emergency-module fails while processing emergency-modules for
|
||||||
another failed module, that failure is ignored and emergency-module
|
another failed module, that failure is ignored and emergency-module
|
||||||
processing continues.
|
processing continues.
|
||||||
|
|
||||||
Use the EMERGENCY keyword in the CMake description of a C++ module
|
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
|
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
|
must **also** set the *emergency* key to *true* in its configuration file
|
||||||
|
@ -18,10 +18,16 @@
|
|||||||
#
|
#
|
||||||
# btrfs_swap options are used when a swapfile is chosen with a btrfs root
|
# btrfs_swap options are used when a swapfile is chosen with a btrfs root
|
||||||
# the options are applied to the subvolume which holds the swap partition
|
# the options are applied to the subvolume which holds the swap partition
|
||||||
|
#
|
||||||
|
# The settings shown here apply only the btrfs defaults; these
|
||||||
|
# are generally the right ones. Commented-out lines show other
|
||||||
|
# options wich **might** be applicable for specific situations.
|
||||||
mountOptions:
|
mountOptions:
|
||||||
default: defaults,noatime
|
default: defaults,noatime
|
||||||
btrfs: defaults,noatime,autodefrag,compress=zstd
|
# btrfs: defaults,noatime,autodefrag,compress=zstd
|
||||||
btrfs_swap: defaults,noatime
|
btrfs: defaults
|
||||||
|
# btrfs_swap: defaults,noatime
|
||||||
|
btrfs_swap: defaults
|
||||||
|
|
||||||
# Mount options to use for the EFI System Partition. If not defined, the
|
# Mount options to use for the EFI System Partition. If not defined, the
|
||||||
# *mountOptions* for *vfat* are used, or if that is not set either,
|
# *mountOptions* for *vfat* are used, or if that is not set either,
|
||||||
|
@ -237,7 +237,7 @@ class FstabGenerator(object):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
# If this is btrfs subvol a dedicated to a swapfile, use different options than a normal btrfs subvol
|
# If this is btrfs subvol a dedicated to a swapfile, use different options than a normal btrfs subvol
|
||||||
if filesystem == "btrfs" and partition["subvol"] == "/@swap":
|
if filesystem == "btrfs" and partition.get("subvol", None) == "/@swap":
|
||||||
options = self.get_mount_options("btrfs_swap", mount_point)
|
options = self.get_mount_options("btrfs_swap", mount_point)
|
||||||
else:
|
else:
|
||||||
options = self.get_mount_options(filesystem, mount_point)
|
options = self.get_mount_options(filesystem, mount_point)
|
||||||
@ -258,7 +258,8 @@ class FstabGenerator(object):
|
|||||||
if mount_point == "/":
|
if mount_point == "/":
|
||||||
self.root_is_ssd = is_ssd
|
self.root_is_ssd = is_ssd
|
||||||
|
|
||||||
if filesystem == "btrfs" and "subvol" in partition:
|
# If there's a set-and-not-empty subvolume set, add it
|
||||||
|
if filesystem == "btrfs" and partition.get("subvol",None):
|
||||||
options = "subvol={},".format(partition["subvol"]) + options
|
options = "subvol={},".format(partition["subvol"]) + options
|
||||||
|
|
||||||
if has_luks:
|
if has_luks:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include <KParts/ReadOnlyPart>
|
#include <KParts/ReadOnlyPart>
|
||||||
#include <KParts/kde_terminal_interface.h>
|
#include <KParts/kde_terminal_interface.h>
|
||||||
#include <KService>
|
#include <KService>
|
||||||
|
#include <kcoreaddons_version.h>
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
@ -41,8 +42,10 @@ InteractiveTerminalPage::InteractiveTerminalPage( QWidget* parent )
|
|||||||
void
|
void
|
||||||
InteractiveTerminalPage::errorKonsoleNotInstalled()
|
InteractiveTerminalPage::errorKonsoleNotInstalled()
|
||||||
{
|
{
|
||||||
QMessageBox mb(QMessageBox::Critical,
|
QMessageBox mb( QMessageBox::Critical,
|
||||||
tr( "Konsole not installed" ), tr( "Please install KDE Konsole and try again!" ), QMessageBox::Ok );
|
tr( "Konsole not installed" ),
|
||||||
|
tr( "Please install KDE Konsole and try again!" ),
|
||||||
|
QMessageBox::Ok );
|
||||||
Calamares::fixButtonLabels( &mb );
|
Calamares::fixButtonLabels( &mb );
|
||||||
mb.exec();
|
mb.exec();
|
||||||
}
|
}
|
||||||
@ -54,20 +57,30 @@ InteractiveTerminalPage::onActivate()
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// For whatever reason, instead of simply linking against a library we
|
|
||||||
// need to do a runtime query to KService just to get a sodding terminal
|
#if KCOREADDONS_VERSION_MAJOR != 5
|
||||||
// widget.
|
#error Incompatible with not-KF5
|
||||||
|
#endif
|
||||||
|
#if KCOREADDONS_VERSION_MINOR >= 86
|
||||||
|
// 5.86 deprecated a bunch of KService and PluginFactory and related methods
|
||||||
|
auto md = KPluginMetaData::findPluginById( QString(), "konsolepart" );
|
||||||
|
if ( !md.isValid() )
|
||||||
|
{
|
||||||
|
errorKonsoleNotInstalled();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto* p = KPluginFactory::instantiatePlugin< KParts::ReadOnlyPart >( md, this ).plugin;
|
||||||
|
#else
|
||||||
KService::Ptr service = KService::serviceByDesktopName( "konsolepart" );
|
KService::Ptr service = KService::serviceByDesktopName( "konsolepart" );
|
||||||
if ( !service )
|
if ( !service )
|
||||||
{
|
{
|
||||||
// And all of this hoping the Konsole application is installed. If not,
|
|
||||||
// tough cookies.
|
|
||||||
errorKonsoleNotInstalled();
|
errorKonsoleNotInstalled();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create one instance of konsolepart.
|
// Create one instance of konsolepart.
|
||||||
KParts::ReadOnlyPart* p = service->createInstance< KParts::ReadOnlyPart >( this, this, {} );
|
KParts::ReadOnlyPart* p = service->createInstance< KParts::ReadOnlyPart >( this, this, {} );
|
||||||
|
#endif
|
||||||
if ( !p )
|
if ( !p )
|
||||||
{
|
{
|
||||||
// One more opportunity for the loading operation to fail.
|
// One more opportunity for the loading operation to fail.
|
||||||
@ -91,7 +104,6 @@ InteractiveTerminalPage::onActivate()
|
|||||||
|
|
||||||
m_termHostWidget = p->widget();
|
m_termHostWidget = p->widget();
|
||||||
m_layout->addWidget( m_termHostWidget );
|
m_layout->addWidget( m_termHostWidget );
|
||||||
cDebug() << "Part widget ought to be" << m_termHostWidget->metaObject()->className();
|
|
||||||
|
|
||||||
t->showShellInDir( QDir::home().path() );
|
t->showShellInDir( QDir::home().path() );
|
||||||
t->sendInput( QString( "%1\n" ).arg( m_command ) );
|
t->sendInput( QString( "%1\n" ).arg( m_command ) );
|
||||||
|
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( luksopenswaphook
|
||||||
|
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,95 +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"
|
|
||||||
|
|
||||||
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"
|
|
@ -191,6 +191,9 @@ def mount_partition(root_mount_point, partition, partitions):
|
|||||||
libcalamares.globalstorage.insert("btrfsSubvolumes", btrfs_subvolumes)
|
libcalamares.globalstorage.insert("btrfsSubvolumes", btrfs_subvolumes)
|
||||||
# Create the subvolumes that are in the completed list
|
# Create the subvolumes that are in the completed list
|
||||||
for s in btrfs_subvolumes:
|
for s in btrfs_subvolumes:
|
||||||
|
if not s["subvolume"]:
|
||||||
|
continue
|
||||||
|
os.makedirs(root_mount_point + os.path.dirname(s["subvolume"]), exist_ok=True)
|
||||||
subprocess.check_call(["btrfs", "subvolume", "create",
|
subprocess.check_call(["btrfs", "subvolume", "create",
|
||||||
root_mount_point + s["subvolume"]])
|
root_mount_point + s["subvolume"]])
|
||||||
if s["mountPoint"] == "/":
|
if s["mountPoint"] == "/":
|
||||||
|
@ -42,15 +42,24 @@ extraMountsEfi:
|
|||||||
mountPoint: /sys/firmware/efi/efivars
|
mountPoint: /sys/firmware/efi/efivars
|
||||||
|
|
||||||
# Btrfs subvolumes to create if root filesystem is on btrfs volume.
|
# Btrfs subvolumes to create if root filesystem is on btrfs volume.
|
||||||
# If mountpoint is mounted already to another partition, it is ignored.
|
# If *mountpoint* is mounted already to another partition, it is ignored.
|
||||||
# Separate subvolume for swapfile is handled separately and automatically.
|
# Separate subvolume for swapfile is handled separately and automatically.
|
||||||
|
#
|
||||||
|
# It is possible to prevent subvolume creation -- this is likely only relevant
|
||||||
|
# for the root (/) subvolume -- by giving an empty string as a subvolume
|
||||||
|
# name. In this case no subvolume will be created. When using snapper as
|
||||||
|
# a rollback mechanism, it is recommended to **not** create a subvolume
|
||||||
|
# for root.
|
||||||
|
|
||||||
btrfsSubvolumes:
|
btrfsSubvolumes:
|
||||||
- mountPoint: /
|
- mountPoint: /
|
||||||
subvolume: /@
|
subvolume: /@
|
||||||
|
# As an alternative:
|
||||||
|
#
|
||||||
|
# subvolume: ""
|
||||||
- mountPoint: /home
|
- mountPoint: /home
|
||||||
subvolume: /@home
|
subvolume: /@home
|
||||||
- mountPoint: /var/cache
|
- mountPoint: /var/cache
|
||||||
subvolume: /@cache
|
subvolume: /@cache
|
||||||
- mountPoint: /var/log
|
- mountPoint: /var/log
|
||||||
subvolume: /@log
|
subvolume: /@log
|
||||||
|
@ -73,12 +73,12 @@ def replace_username(nm_config_filename, live_user, target_user):
|
|||||||
if not os.path.exists(nm_config_filename):
|
if not os.path.exists(nm_config_filename):
|
||||||
return
|
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()
|
text = network_conf.readlines()
|
||||||
|
|
||||||
live_permissions = 'permissions=user:{}:;'.format(live_user)
|
live_permissions = 'permissions=user:{}:;'.format(live_user)
|
||||||
target_permissions = 'permissions=user:{}:;\n'.format(target_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:
|
for line in text:
|
||||||
if live_permissions in line:
|
if live_permissions in line:
|
||||||
line = target_permissions
|
line = target_permissions
|
||||||
|
@ -5,6 +5,6 @@ operations: []
|
|||||||
|
|
||||||
pacman:
|
pacman:
|
||||||
num_retries: 4
|
num_retries: 4
|
||||||
disable_download_timeout: yes
|
disable_download_timeout: true
|
||||||
needed_only: true
|
needed_only: true
|
||||||
|
|
||||||
|
@ -552,7 +552,7 @@ PartitionViewStep::onLeave()
|
|||||||
if ( !okSize )
|
if ( !okSize )
|
||||||
{
|
{
|
||||||
cDebug() << o << "ESP too small";
|
cDebug() << o << "ESP too small";
|
||||||
const auto atLeastBytes = PartUtils::efiFilesystemMinimumSize();
|
const qint64 atLeastBytes = static_cast< qint64 >( PartUtils::efiFilesystemMinimumSize() );
|
||||||
const auto atLeastMiB = CalamaresUtils::BytesToMiB( atLeastBytes );
|
const auto atLeastMiB = CalamaresUtils::BytesToMiB( atLeastBytes );
|
||||||
description.append( ' ' );
|
description.append( ' ' );
|
||||||
description.append( tr( "The filesystem must be at least %1 MiB in size." ).arg( atLeastMiB ) );
|
description.append( tr( "The filesystem must be at least %1 MiB in size." ).arg( atLeastMiB ) );
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "DeviceList.h"
|
#include "DeviceList.h"
|
||||||
|
|
||||||
#include "partition/PartitionIterator.h"
|
#include "partition/PartitionIterator.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
#include <kpmcore/backend/corebackend.h>
|
#include <kpmcore/backend/corebackend.h>
|
||||||
@ -43,11 +44,9 @@ hasRootPartition( Device* device )
|
|||||||
static bool
|
static bool
|
||||||
blkIdCheckIso9660( const QString& path )
|
blkIdCheckIso9660( const QString& path )
|
||||||
{
|
{
|
||||||
QProcess blkid;
|
// If blkid fails, there's no output, but we don't care
|
||||||
blkid.start( "blkid", { path } );
|
auto r = CalamaresUtils::System::runCommand( { "blkid", path }, std::chrono::seconds( 30 ) );
|
||||||
blkid.waitForFinished();
|
return r.getOutput().contains( "iso9660" );
|
||||||
QString output = QString::fromLocal8Bit( blkid.readAllStandardOutput() );
|
|
||||||
return output.contains( "iso9660" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
@ -8,9 +8,10 @@
|
|||||||
* Calamares is Free Software: see the License-Identifier above.
|
* Calamares is Free Software: see the License-Identifier above.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include "core/DeviceModel.h"
|
#include "DeviceModel.h"
|
||||||
|
|
||||||
#include "core/PartitionModel.h"
|
#include "core/PartitionModel.h"
|
||||||
|
#include "core/SizeUtils.h"
|
||||||
|
|
||||||
#include "utils/CalamaresUtilsGui.h"
|
#include "utils/CalamaresUtilsGui.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
@ -18,9 +19,6 @@
|
|||||||
// KPMcore
|
// KPMcore
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
|
|
||||||
// KF5
|
|
||||||
#include <KFormat>
|
|
||||||
|
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QStandardItemModel>
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
@ -83,7 +81,7 @@ DeviceModel::data( const QModelIndex& index, int role ) const
|
|||||||
//: device[name] - size[number] (device-node[name])
|
//: device[name] - size[number] (device-node[name])
|
||||||
return tr( "%1 - %2 (%3)" )
|
return tr( "%1 - %2 (%3)" )
|
||||||
.arg( device->name() )
|
.arg( device->name() )
|
||||||
.arg( KFormat().formatByteSize( device->capacity() ) )
|
.arg( formatByteSize( device->capacity() ) )
|
||||||
.arg( device->deviceNode() );
|
.arg( device->deviceNode() );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -15,8 +15,8 @@
|
|||||||
|
|
||||||
#include "partition/PartitionIterator.h"
|
#include "partition/PartitionIterator.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
#include "utils/String.h"
|
||||||
|
|
||||||
// KPMcore
|
|
||||||
#include <kpmcore/backend/corebackendmanager.h>
|
#include <kpmcore/backend/corebackendmanager.h>
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
@ -127,4 +127,23 @@ clonePartition( Device* device, Partition* partition )
|
|||||||
partition->activeFlags() );
|
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
|
} // namespace KPMHelpers
|
||||||
|
@ -11,11 +11,13 @@
|
|||||||
#ifndef KPMHELPERS_H
|
#ifndef KPMHELPERS_H
|
||||||
#define KPMHELPERS_H
|
#define KPMHELPERS_H
|
||||||
|
|
||||||
// KPMcore
|
#include "Job.h"
|
||||||
|
|
||||||
#include <kpmcore/core/partitiontable.h>
|
#include <kpmcore/core/partitiontable.h>
|
||||||
#include <kpmcore/fs/filesystem.h>
|
#include <kpmcore/fs/filesystem.h>
|
||||||
|
#include <kpmcore/ops/operation.h>
|
||||||
|
#include <kpmcore/util/report.h>
|
||||||
|
|
||||||
// Qt
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@ -72,6 +74,24 @@ Partition* createNewEncryptedPartition( PartitionNode* parent,
|
|||||||
|
|
||||||
Partition* clonePartition( Device* device, Partition* partition );
|
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
|
} // namespace KPMHelpers
|
||||||
|
|
||||||
#endif /* KPMHELPERS_H */
|
#endif /* KPMHELPERS_H */
|
||||||
|
@ -451,6 +451,8 @@ isEfiFilesystemSuitableType( const Partition* candidate )
|
|||||||
{
|
{
|
||||||
auto type = candidate->fileSystem().type();
|
auto type = candidate->fileSystem().type();
|
||||||
|
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_CLANG( "-Wswitch-enum" )
|
||||||
switch ( type )
|
switch ( type )
|
||||||
{
|
{
|
||||||
case FileSystem::Type::Fat32:
|
case FileSystem::Type::Fat32:
|
||||||
@ -465,6 +467,7 @@ isEfiFilesystemSuitableType( const Partition* candidate )
|
|||||||
cWarning() << "EFI boot partition must be FAT32";
|
cWarning() << "EFI boot partition must be FAT32";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -526,14 +529,15 @@ efiFilesystemMinimumSize()
|
|||||||
{
|
{
|
||||||
using CalamaresUtils::Units::operator""_MiB;
|
using CalamaresUtils::Units::operator""_MiB;
|
||||||
|
|
||||||
auto uefisys_part_sizeB = 300_MiB;
|
size_t uefisys_part_sizeB = 300_MiB;
|
||||||
|
|
||||||
// The default can be overridden; the key used here comes
|
// The default can be overridden; the key used here comes
|
||||||
// from the partition module Config.cpp
|
// from the partition module Config.cpp
|
||||||
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
auto* gs = Calamares::JobQueue::instance()->globalStorage();
|
||||||
if ( gs->contains( "efiSystemPartitionSize_i" ) )
|
if ( gs->contains( "efiSystemPartitionSize_i" ) )
|
||||||
{
|
{
|
||||||
uefisys_part_sizeB = gs->value( "efiSystemPartitionSize_i" ).toLongLong();
|
qint64 v = gs->value( "efiSystemPartitionSize_i" ).toLongLong();
|
||||||
|
uefisys_part_sizeB = v > 0 ? static_cast< size_t >( v ) : 0;
|
||||||
}
|
}
|
||||||
// There is a lower limit of what can be configured
|
// There is a lower limit of what can be configured
|
||||||
if ( uefisys_part_sizeB < 32_MiB )
|
if ( uefisys_part_sizeB < 32_MiB )
|
||||||
|
@ -71,15 +71,15 @@ swapSuggestion( const qint64 availableSpaceB, Config::SwapChoice swap )
|
|||||||
|
|
||||||
|
|
||||||
// Allow for a fudge factor
|
// Allow for a fudge factor
|
||||||
suggestedSwapSizeB *= overestimationFactor;
|
suggestedSwapSizeB = qRound64( suggestedSwapSizeB * overestimationFactor );
|
||||||
|
|
||||||
// don't use more than 10% of available space
|
// don't use more than 10% of available space
|
||||||
if ( !ensureSuspendToDisk )
|
if ( !ensureSuspendToDisk )
|
||||||
{
|
{
|
||||||
suggestedSwapSizeB = qMin( suggestedSwapSizeB, qint64( 0.10 * availableSpaceB ) );
|
suggestedSwapSizeB = qMin( suggestedSwapSizeB, availableSpaceB / 10 /* 10% is 0.1 */ );
|
||||||
}
|
}
|
||||||
|
|
||||||
cDebug() << "Suggested swap size:" << suggestedSwapSizeB / 1024. / 1024. / 1024. << "GiB";
|
cDebug() << "Suggested swap size:" << CalamaresUtils::BytesToGiB( suggestedSwapSizeB ) << "GiB";
|
||||||
|
|
||||||
return suggestedSwapSizeB;
|
return suggestedSwapSizeB;
|
||||||
}
|
}
|
||||||
|
@ -141,6 +141,8 @@ void
|
|||||||
PartitionLayout::setDefaultFsType( FileSystem::Type defaultFsType )
|
PartitionLayout::setDefaultFsType( FileSystem::Type defaultFsType )
|
||||||
{
|
{
|
||||||
using FileSystem = FileSystem::Type;
|
using FileSystem = FileSystem::Type;
|
||||||
|
QT_WARNING_PUSH
|
||||||
|
QT_WARNING_DISABLE_CLANG( "-Wswitch-enum" )
|
||||||
switch ( defaultFsType )
|
switch ( defaultFsType )
|
||||||
{
|
{
|
||||||
case FileSystem::Unknown:
|
case FileSystem::Unknown:
|
||||||
@ -196,6 +198,7 @@ PartitionLayout::setDefaultFsType( FileSystem::Type defaultFsType )
|
|||||||
<< "Using ext4 instead.";
|
<< "Using ext4 instead.";
|
||||||
defaultFsType = FileSystem::Ext4;
|
defaultFsType = FileSystem::Ext4;
|
||||||
}
|
}
|
||||||
|
QT_WARNING_POP
|
||||||
|
|
||||||
m_defaultFsType = defaultFsType;
|
m_defaultFsType = defaultFsType;
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "core/PartitionModel.h"
|
#include "PartitionModel.h"
|
||||||
|
|
||||||
#include "core/ColorUtils.h"
|
#include "core/ColorUtils.h"
|
||||||
#include "core/KPMHelpers.h"
|
#include "core/KPMHelpers.h"
|
||||||
#include "core/PartitionInfo.h"
|
#include "core/PartitionInfo.h"
|
||||||
|
#include "core/SizeUtils.h"
|
||||||
|
|
||||||
#include "partition/FileSystem.h"
|
#include "partition/FileSystem.h"
|
||||||
#include "partition/PartitionQuery.h"
|
#include "partition/PartitionQuery.h"
|
||||||
@ -24,9 +25,6 @@
|
|||||||
#include <kpmcore/core/partitiontable.h>
|
#include <kpmcore/core/partitiontable.h>
|
||||||
#include <kpmcore/fs/filesystem.h>
|
#include <kpmcore/fs/filesystem.h>
|
||||||
|
|
||||||
// KF5
|
|
||||||
#include <KFormat>
|
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
|
||||||
@ -178,7 +176,7 @@ PartitionModel::data( const QModelIndex& index, int role ) const
|
|||||||
if ( col == SizeColumn )
|
if ( col == SizeColumn )
|
||||||
{
|
{
|
||||||
qint64 size = ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize();
|
qint64 size = ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize();
|
||||||
return KFormat().formatByteSize( size );
|
return formatByteSize( size );
|
||||||
}
|
}
|
||||||
cDebug() << "Unknown column" << col;
|
cDebug() << "Unknown column" << col;
|
||||||
return QVariant();
|
return QVariant();
|
||||||
@ -210,7 +208,7 @@ PartitionModel::data( const QModelIndex& index, int role ) const
|
|||||||
QString prettyFileSystem
|
QString prettyFileSystem
|
||||||
= CalamaresUtils::Partition::prettyNameForFileSystemType( partition->fileSystem().type() );
|
= CalamaresUtils::Partition::prettyNameForFileSystemType( partition->fileSystem().type() );
|
||||||
qint64 size = ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize();
|
qint64 size = ( partition->lastSector() - partition->firstSector() + 1 ) * m_device->logicalSize();
|
||||||
QString prettySize = KFormat().formatByteSize( size );
|
QString prettySize = formatByteSize( size );
|
||||||
return QVariant( name + " " + prettyFileSystem + " " + prettySize );
|
return QVariant( name + " " + prettyFileSystem + " " + prettySize );
|
||||||
}
|
}
|
||||||
case SizeRole:
|
case SizeRole:
|
||||||
|
27
src/modules/partition/core/SizeUtils.h
Normal file
27
src/modules/partition/core/SizeUtils.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* === 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PARTITION_CORE_SIZEUTILS_H
|
||||||
|
#define PARTITION_CORE_SIZEUTILS_H
|
||||||
|
|
||||||
|
#include <kpmcore/util/capacity.h>
|
||||||
|
|
||||||
|
/** @brief Helper function for printing sizes consistently.
|
||||||
|
*
|
||||||
|
* Most of Calamares uses a qint64 for partition sizes, so use that
|
||||||
|
* parameter type. However, the human-visible formatting doesn't need
|
||||||
|
* to bother with one-byte accuracy (and anyway, a double has at least 50 bits
|
||||||
|
* at which point we're printing giga (or gibi) bytes).
|
||||||
|
*/
|
||||||
|
static inline QString formatByteSize( qint64 sizeValue )
|
||||||
|
{
|
||||||
|
return Capacity::formatByteSize( static_cast< double >( sizeValue ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PARTITION_CORE_SIZEUTILS_H
|
@ -68,7 +68,8 @@ DeviceInfoWidget::setPartitionTableType( PartitionTable::TableType type )
|
|||||||
void
|
void
|
||||||
DeviceInfoWidget::retranslateUi()
|
DeviceInfoWidget::retranslateUi()
|
||||||
{
|
{
|
||||||
QString typeString = PartitionTable::tableTypeToName( m_tableType ).toUpper();
|
QString typeString;
|
||||||
|
QString toolTipString;
|
||||||
|
|
||||||
// fix up if the name shouldn't be uppercase:
|
// fix up if the name shouldn't be uppercase:
|
||||||
switch ( m_tableType )
|
switch ( m_tableType )
|
||||||
@ -76,38 +77,34 @@ DeviceInfoWidget::retranslateUi()
|
|||||||
case PartitionTable::msdos:
|
case PartitionTable::msdos:
|
||||||
case PartitionTable::msdos_sectorbased:
|
case PartitionTable::msdos_sectorbased:
|
||||||
typeString = "MBR";
|
typeString = "MBR";
|
||||||
|
toolTipString += tr( "<br><br>This partition table type is only advisable on older "
|
||||||
|
"systems which start from a <strong>BIOS</strong> boot "
|
||||||
|
"environment. GPT is recommended in most other cases.<br><br>"
|
||||||
|
"<strong>Warning:</strong> the MBR partition table "
|
||||||
|
"is an obsolete MS-DOS era standard.<br>"
|
||||||
|
"Only 4 <em>primary</em> partitions may be created, and of "
|
||||||
|
"those 4, one can be an <em>extended</em> partition, which "
|
||||||
|
"may in turn contain many <em>logical</em> partitions." );
|
||||||
|
break;
|
||||||
|
case PartitionTable::gpt:
|
||||||
|
// TypeString is ok
|
||||||
|
toolTipString += tr( "<br><br>This is the recommended partition table type for modern "
|
||||||
|
"systems which start from an <strong>EFI</strong> boot "
|
||||||
|
"environment." );
|
||||||
break;
|
break;
|
||||||
case PartitionTable::loop:
|
case PartitionTable::loop:
|
||||||
typeString = "loop";
|
typeString = "loop";
|
||||||
break;
|
|
||||||
case PartitionTable::mac:
|
|
||||||
typeString = "Mac";
|
|
||||||
break;
|
|
||||||
case PartitionTable::amiga:
|
|
||||||
typeString = "Amiga";
|
|
||||||
break;
|
|
||||||
case PartitionTable::sun:
|
|
||||||
typeString = "Sun";
|
|
||||||
break;
|
|
||||||
case PartitionTable::unknownTableType:
|
|
||||||
typeString = " ? ";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
QString toolTipString = tr( "This device has a <strong>%1</strong> partition "
|
|
||||||
"table." )
|
|
||||||
.arg( typeString );
|
|
||||||
|
|
||||||
switch ( m_tableType )
|
|
||||||
{
|
|
||||||
case PartitionTable::loop:
|
|
||||||
toolTipString = tr( "This is a <strong>loop</strong> "
|
toolTipString = tr( "This is a <strong>loop</strong> "
|
||||||
"device.<br><br>"
|
"device.<br><br>"
|
||||||
"It is a pseudo-device with no partition table "
|
"It is a pseudo-device with no partition table "
|
||||||
"that makes a file accessible as a block device. "
|
"that makes a file accessible as a block device. "
|
||||||
"This kind of setup usually only contains a single filesystem." );
|
"This kind of setup usually only contains a single filesystem." );
|
||||||
break;
|
break;
|
||||||
|
#if defined( WITH_KPMCORE42API )
|
||||||
|
case PartitionTable::none:
|
||||||
|
#endif
|
||||||
case PartitionTable::unknownTableType:
|
case PartitionTable::unknownTableType:
|
||||||
|
typeString = " ? ";
|
||||||
toolTipString = tr( "This installer <strong>cannot detect a partition table</strong> on the "
|
toolTipString = tr( "This installer <strong>cannot detect a partition table</strong> on the "
|
||||||
"selected storage device.<br><br>"
|
"selected storage device.<br><br>"
|
||||||
"The device either has no partition "
|
"The device either has no partition "
|
||||||
@ -117,21 +114,35 @@ DeviceInfoWidget::retranslateUi()
|
|||||||
"either automatically, or through the manual partitioning "
|
"either automatically, or through the manual partitioning "
|
||||||
"page." );
|
"page." );
|
||||||
break;
|
break;
|
||||||
case PartitionTable::gpt:
|
// The next ones need to have the name adjusted, but the default tooltip is OK
|
||||||
toolTipString += tr( "<br><br>This is the recommended partition table type for modern "
|
case PartitionTable::mac:
|
||||||
"systems which start from an <strong>EFI</strong> boot "
|
typeString = "Mac";
|
||||||
"environment." );
|
|
||||||
break;
|
break;
|
||||||
case PartitionTable::msdos:
|
case PartitionTable::amiga:
|
||||||
case PartitionTable::msdos_sectorbased:
|
typeString = "Amiga";
|
||||||
toolTipString += tr( "<br><br>This partition table type is only advisable on older "
|
break;
|
||||||
"systems which start from a <strong>BIOS</strong> boot "
|
case PartitionTable::sun:
|
||||||
"environment. GPT is recommended in most other cases.<br><br>"
|
typeString = "Sun";
|
||||||
"<strong>Warning:</strong> the MBR partition table "
|
break;
|
||||||
"is an obsolete MS-DOS era standard.<br>"
|
// Peculiar tables, do nothing and use default type and tooltip strings
|
||||||
"Only 4 <em>primary</em> partitions may be created, and of "
|
case PartitionTable::aix:
|
||||||
"those 4, one can be an <em>extended</em> partition, which "
|
case PartitionTable::bsd:
|
||||||
"may in turn contain many <em>logical</em> partitions." );
|
case PartitionTable::dasd:
|
||||||
|
case PartitionTable::dvh:
|
||||||
|
case PartitionTable::pc98:
|
||||||
|
case PartitionTable::vmd:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( typeString.isEmpty() )
|
||||||
|
{
|
||||||
|
typeString = PartitionTable::tableTypeToName( m_tableType ).toUpper();
|
||||||
|
}
|
||||||
|
if ( toolTipString.isEmpty() )
|
||||||
|
{
|
||||||
|
toolTipString = tr( "This device has a <strong>%1</strong> partition "
|
||||||
|
"table." )
|
||||||
|
.arg( typeString );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ptLabel->setText( typeString );
|
m_ptLabel->setText( typeString );
|
||||||
|
@ -9,11 +9,10 @@
|
|||||||
|
|
||||||
#include "ListPhysicalVolumeWidgetItem.h"
|
#include "ListPhysicalVolumeWidgetItem.h"
|
||||||
|
|
||||||
#include <kpmcore/util/capacity.h>
|
#include "core/SizeUtils.h"
|
||||||
|
|
||||||
ListPhysicalVolumeWidgetItem::ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked )
|
ListPhysicalVolumeWidgetItem::ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked )
|
||||||
: QListWidgetItem(
|
: QListWidgetItem( QString( "%1 | %2" ).arg( partition->deviceNode(), formatByteSize( partition->capacity() ) ) )
|
||||||
QString( "%1 | %2" ).arg( partition->deviceNode(), Capacity::formatByteSize( partition->capacity() ) ) )
|
|
||||||
, m_partition( partition )
|
, m_partition( partition )
|
||||||
{
|
{
|
||||||
setToolTip( partition->deviceNode() );
|
setToolTip( partition->deviceNode() );
|
||||||
@ -26,3 +25,5 @@ ListPhysicalVolumeWidgetItem::partition() const
|
|||||||
{
|
{
|
||||||
return m_partition;
|
return m_partition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ListPhysicalVolumeWidgetItem::~ListPhysicalVolumeWidgetItem() {}
|
||||||
|
@ -18,6 +18,7 @@ class ListPhysicalVolumeWidgetItem : public QListWidgetItem
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked );
|
ListPhysicalVolumeWidgetItem( const Partition* partition, bool checked );
|
||||||
|
~ListPhysicalVolumeWidgetItem() override;
|
||||||
|
|
||||||
const Partition* partition() const;
|
const Partition* partition() const;
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "core/ColorUtils.h"
|
#include "core/ColorUtils.h"
|
||||||
#include "core/PartitionModel.h"
|
#include "core/PartitionModel.h"
|
||||||
|
#include "core/SizeUtils.h"
|
||||||
|
|
||||||
#include "utils/CalamaresUtilsGui.h"
|
#include "utils/CalamaresUtilsGui.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
@ -20,8 +21,6 @@
|
|||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
#include <kpmcore/fs/filesystem.h>
|
#include <kpmcore/fs/filesystem.h>
|
||||||
|
|
||||||
#include <KFormat>
|
|
||||||
|
|
||||||
// Qt
|
// Qt
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
@ -39,7 +38,7 @@ static QStringList
|
|||||||
buildUnknownDisklabelTexts( Device* dev )
|
buildUnknownDisklabelTexts( Device* dev )
|
||||||
{
|
{
|
||||||
QStringList texts = { QObject::tr( "Unpartitioned space or unknown partition table" ),
|
QStringList texts = { QObject::tr( "Unpartitioned space or unknown partition table" ),
|
||||||
KFormat().formatByteSize( dev->totalLogical() * dev->logicalSize() ) };
|
formatByteSize( dev->totalLogical() * dev->logicalSize() ) };
|
||||||
return texts;
|
return texts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,8 @@ ReplaceWidget::onPartitionSelected()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( partition->capacity() < requiredSpaceB )
|
// The loss of precision is ok; we're not going to fall over from a single byte
|
||||||
|
if ( static_cast< double >( partition->capacity() ) < requiredSpaceB )
|
||||||
{
|
{
|
||||||
updateStatus( CalamaresUtils::Fail,
|
updateStatus( CalamaresUtils::Fail,
|
||||||
tr( "<strong>%4</strong><br/><br/>"
|
tr( "<strong>%4</strong><br/><br/>"
|
||||||
|
@ -10,10 +10,9 @@
|
|||||||
#include "VolumeGroupBaseDialog.h"
|
#include "VolumeGroupBaseDialog.h"
|
||||||
#include "ui_VolumeGroupBaseDialog.h"
|
#include "ui_VolumeGroupBaseDialog.h"
|
||||||
|
|
||||||
|
#include "core/SizeUtils.h"
|
||||||
#include "gui/ListPhysicalVolumeWidgetItem.h"
|
#include "gui/ListPhysicalVolumeWidgetItem.h"
|
||||||
|
|
||||||
#include <kpmcore/util/capacity.h>
|
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
@ -100,7 +99,7 @@ VolumeGroupBaseDialog::setUsedSizeValue( qint64 usedSize )
|
|||||||
{
|
{
|
||||||
m_usedSizeValue = usedSize;
|
m_usedSizeValue = usedSize;
|
||||||
|
|
||||||
ui->usedSize->setText( Capacity::formatByteSize( m_usedSizeValue ) );
|
ui->usedSize->setText( formatByteSize( m_usedSizeValue ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -121,7 +120,7 @@ VolumeGroupBaseDialog::updateTotalSize()
|
|||||||
% ( ui->peSize->value() * Capacity::unitFactor( Capacity::Unit::Byte, Capacity::Unit::MiB ) );
|
% ( ui->peSize->value() * Capacity::unitFactor( Capacity::Unit::Byte, Capacity::Unit::MiB ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->totalSize->setText( Capacity::formatByteSize( m_totalSizeValue ) );
|
ui->totalSize->setText( formatByteSize( m_totalSizeValue ) );
|
||||||
|
|
||||||
updateTotalSectors();
|
updateTotalSectors();
|
||||||
}
|
}
|
||||||
|
@ -243,14 +243,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
#if ( QT_VERSION < QT_VERSION_CHECK( 5, 15, 0 ) )
|
|
||||||
// TODO: 3.3 remove because newer Qt does support constness
|
|
||||||
const char* m_message = nullptr;
|
const char* m_message = nullptr;
|
||||||
QString m_path;
|
QString m_path;
|
||||||
#else
|
|
||||||
const char* const m_message = nullptr;
|
|
||||||
QString const m_path;
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATICTEST inline QDebug&
|
STATICTEST inline QDebug&
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
|
|
||||||
#include "CreatePartitionJob.h"
|
#include "CreatePartitionJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
#include "core/PartitionInfo.h"
|
#include "core/PartitionInfo.h"
|
||||||
|
|
||||||
#include "partition/FileSystem.h"
|
#include "partition/FileSystem.h"
|
||||||
#include "partition/PartitionQuery.h"
|
#include "partition/PartitionQuery.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
@ -60,24 +62,24 @@ createZfs( Partition* partition, Device* device )
|
|||||||
// Now we need to do some things that would normally be done by kpmcore
|
// Now we need to do some things that would normally be done by kpmcore
|
||||||
|
|
||||||
// First we get the device node from the output and set it as the partition path
|
// First we get the device node from the output and set it as the partition path
|
||||||
QRegularExpression re( QStringLiteral( "Created a new partition (\\d+)" ) );
|
|
||||||
QRegularExpressionMatch rem = re.match( r.getOutput() );
|
|
||||||
|
|
||||||
QString deviceNode;
|
QString deviceNode;
|
||||||
if ( rem.hasMatch() )
|
|
||||||
{
|
{
|
||||||
if ( partition->devicePath().back().isDigit() )
|
QRegularExpression re( QStringLiteral( "Created a new partition (\\d+)" ) );
|
||||||
|
QRegularExpressionMatch rem = re.match( r.getOutput() );
|
||||||
|
|
||||||
|
if ( rem.hasMatch() )
|
||||||
{
|
{
|
||||||
deviceNode = partition->devicePath() + QLatin1Char( 'p' ) + rem.captured( 1 );
|
if ( partition->devicePath().back().isDigit() )
|
||||||
}
|
{
|
||||||
else
|
deviceNode = partition->devicePath() + QLatin1Char( 'p' ) + rem.captured( 1 );
|
||||||
{
|
}
|
||||||
deviceNode = partition->devicePath() + rem.captured( 1 );
|
else
|
||||||
|
{
|
||||||
|
deviceNode = partition->devicePath() + rem.captured( 1 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
partition->setPartitionPath( deviceNode );
|
||||||
}
|
}
|
||||||
|
|
||||||
partition->setPartitionPath( deviceNode );
|
|
||||||
|
|
||||||
// If it is a gpt device, set the partition UUID
|
// If it is a gpt device, set the partition UUID
|
||||||
if ( device->partitionTable()->type() == PartitionTable::gpt && partition->uuid().isEmpty() )
|
if ( device->partitionTable()->type() == PartitionTable::gpt && partition->uuid().isEmpty() )
|
||||||
{
|
{
|
||||||
@ -273,17 +275,9 @@ CreatePartitionJob::exec()
|
|||||||
return createZfs( m_partition, m_device );
|
return createZfs( m_partition, m_device );
|
||||||
}
|
}
|
||||||
|
|
||||||
Report report( nullptr );
|
return KPMHelpers::execute(
|
||||||
NewOperation op( *m_device, m_partition );
|
NewOperation( *m_device, m_partition ),
|
||||||
op.setStatus( Operation::StatusRunning );
|
tr( "The installer failed to create partition on disk '%1'." ).arg( m_device->name() ) );
|
||||||
|
|
||||||
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() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -12,9 +12,11 @@
|
|||||||
#include "CreatePartitionTableJob.h"
|
#include "CreatePartitionTableJob.h"
|
||||||
|
|
||||||
#include "partition/PartitionIterator.h"
|
#include "partition/PartitionIterator.h"
|
||||||
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
// KPMcore
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
#include <kpmcore/core/partitiontable.h>
|
#include <kpmcore/core/partitiontable.h>
|
||||||
@ -63,8 +65,6 @@ CreatePartitionTableJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
CreatePartitionTableJob::exec()
|
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();
|
PartitionTable* table = m_device->partitionTable();
|
||||||
|
|
||||||
@ -76,30 +76,16 @@ CreatePartitionTableJob::exec()
|
|||||||
cDebug() << Logger::SubEntry << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
cDebug() << Logger::SubEntry << ( ( *it ) ? ( *it )->deviceNode() : QString( "<null device>" ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QProcess lsblk;
|
auto lsblkResult = CalamaresUtils::System::runCommand( { "lsblk" }, std::chrono::seconds( 30 ) );
|
||||||
lsblk.setProgram( "lsblk" );
|
cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblkResult.getOutput();
|
||||||
lsblk.setProcessChannelMode( QProcess::MergedChannels );
|
|
||||||
lsblk.start();
|
|
||||||
lsblk.waitForFinished();
|
|
||||||
cDebug() << Logger::SubEntry << "lsblk output:\n" << Logger::NoQuote << lsblk.readAllStandardOutput();
|
|
||||||
|
|
||||||
QProcess mount;
|
auto mountResult = CalamaresUtils::System::runCommand( { "mount" }, std::chrono::seconds( 30 ) );
|
||||||
mount.setProgram( "mount" ); // Debug output only, not mounting something
|
cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mountResult.getOutput();
|
||||||
mount.setProcessChannelMode( QProcess::MergedChannels );
|
|
||||||
mount.start();
|
|
||||||
mount.waitForFinished();
|
|
||||||
cDebug() << Logger::SubEntry << "mount output:\n" << Logger::NoQuote << mount.readAllStandardOutput();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CreatePartitionTableOperation op( *m_device, table );
|
return KPMHelpers::execute(
|
||||||
op.setStatus( Operation::StatusRunning );
|
CreatePartitionTableOperation( *m_device, table ),
|
||||||
|
tr( "The installer failed to create a partition table on %1." ).arg( m_device->name() ) );
|
||||||
if ( op.execute( report ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Calamares::JobResult::error( message, report.toText() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
#include "CreateVolumeGroupJob.h"
|
#include "CreateVolumeGroupJob.h"
|
||||||
|
|
||||||
// KPMcore
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include <kpmcore/core/lvmdevice.h>
|
#include <kpmcore/core/lvmdevice.h>
|
||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
#include <kpmcore/ops/createvolumegroupoperation.h>
|
#include <kpmcore/ops/createvolumegroupoperation.h>
|
||||||
@ -46,19 +47,8 @@ CreateVolumeGroupJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
CreateVolumeGroupJob::exec()
|
CreateVolumeGroupJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr );
|
return KPMHelpers::execute( CreateVolumeGroupOperation( m_vgName, m_pvList, m_peSize ),
|
||||||
|
tr( "The installer failed to create a volume group named '%1'." ).arg( m_vgName ) );
|
||||||
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() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include "DeactivateVolumeGroupJob.h"
|
#include "DeactivateVolumeGroupJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include <kpmcore/core/lvmdevice.h>
|
#include <kpmcore/core/lvmdevice.h>
|
||||||
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
|
#include <kpmcore/ops/deactivatevolumegroupoperation.h>
|
||||||
#include <kpmcore/util/report.h>
|
#include <kpmcore/util/report.h>
|
||||||
@ -39,18 +41,12 @@ DeactivateVolumeGroupJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
DeactivateVolumeGroupJob::exec()
|
DeactivateVolumeGroupJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr );
|
|
||||||
|
|
||||||
DeactivateVolumeGroupOperation op( *m_device );
|
DeactivateVolumeGroupOperation op( *m_device );
|
||||||
|
auto r = KPMHelpers::execute(
|
||||||
op.setStatus( Operation::OperationStatus::StatusRunning );
|
op, tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() ) );
|
||||||
|
if ( r )
|
||||||
QString message = tr( "The installer failed to deactivate a volume group named %1." ).arg( m_device->name() );
|
|
||||||
if ( op.execute( report ) )
|
|
||||||
{
|
{
|
||||||
op.preview();
|
op.preview();
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
}
|
||||||
|
return r;
|
||||||
return Calamares::JobResult::error( message, report.toText() );
|
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "DeletePartitionJob.h"
|
#include "DeletePartitionJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
|
|
||||||
// KPMcore
|
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
#include <kpmcore/core/partitiontable.h>
|
#include <kpmcore/core/partitiontable.h>
|
||||||
@ -45,7 +47,7 @@ removePartition( Partition* partition )
|
|||||||
auto r = CalamaresUtils::System::instance()->runCommand(
|
auto r = CalamaresUtils::System::instance()->runCommand(
|
||||||
{ "sfdisk", "--delete", "--force", partition->devicePath(), QString::number( partition->number() ) },
|
{ "sfdisk", "--delete", "--force", partition->devicePath(), QString::number( partition->number() ) },
|
||||||
std::chrono::seconds( 5 ) );
|
std::chrono::seconds( 5 ) );
|
||||||
if ( r.getExitCode() !=0 || r.getOutput().contains("failed") )
|
if ( r.getExitCode() != 0 || r.getOutput().contains( "failed" ) )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error(
|
return Calamares::JobResult::error(
|
||||||
QCoreApplication::translate( DeletePartitionJob::staticMetaObject.className(), "Deletion Failed" ),
|
QCoreApplication::translate( DeletePartitionJob::staticMetaObject.className(), "Deletion Failed" ),
|
||||||
@ -96,17 +98,8 @@ DeletePartitionJob::exec()
|
|||||||
return removePartition( m_partition );
|
return removePartition( m_partition );
|
||||||
}
|
}
|
||||||
|
|
||||||
Report report( nullptr );
|
return KPMHelpers::execute( DeleteOperation( *m_device, m_partition ),
|
||||||
DeleteOperation op( *m_device, m_partition );
|
tr( "The installer failed to delete partition %1." ).arg( m_partition->devicePath() ) );
|
||||||
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() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "FormatPartitionJob.h"
|
#include "FormatPartitionJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include "partition/FileSystem.h"
|
#include "partition/FileSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
|
|
||||||
@ -65,17 +67,7 @@ FormatPartitionJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
FormatPartitionJob::exec()
|
FormatPartitionJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr ); // Root of the report tree, no parent
|
return KPMHelpers::execute( CreateFileSystemOperation( *m_device, *m_partition, m_partition->fileSystem().type() ),
|
||||||
CreateFileSystemOperation op( *m_device, *m_partition, m_partition->fileSystem().type() );
|
tr( "The installer failed to format partition %1 on disk '%2'." )
|
||||||
op.setStatus( Operation::StatusRunning );
|
.arg( m_partition->partitionPath(), m_device->name() ) );
|
||||||
|
|
||||||
QString message = tr( "The installer failed to format partition %1 on disk '%2'." )
|
|
||||||
.arg( m_partition->partitionPath(), m_device->name() );
|
|
||||||
|
|
||||||
if ( op.execute( report ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Calamares::JobResult::error( message, report.toText() );
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include "RemoveVolumeGroupJob.h"
|
#include "RemoveVolumeGroupJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include <kpmcore/core/lvmdevice.h>
|
#include <kpmcore/core/lvmdevice.h>
|
||||||
#include <kpmcore/ops/removevolumegroupoperation.h>
|
#include <kpmcore/ops/removevolumegroupoperation.h>
|
||||||
#include <kpmcore/util/report.h>
|
#include <kpmcore/util/report.h>
|
||||||
@ -39,17 +41,7 @@ RemoveVolumeGroupJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
RemoveVolumeGroupJob::exec()
|
RemoveVolumeGroupJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr );
|
return KPMHelpers::execute(
|
||||||
|
RemoveVolumeGroupOperation( *m_device ),
|
||||||
RemoveVolumeGroupOperation op( *m_device );
|
tr( "The installer failed to remove a volume group named '%1'." ).arg( m_device->name() ) );
|
||||||
|
|
||||||
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() );
|
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
#include "ResizePartitionJob.h"
|
#include "ResizePartitionJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include "utils/Units.h"
|
#include "utils/Units.h"
|
||||||
|
|
||||||
// KPMcore
|
|
||||||
#include <kpmcore/core/device.h>
|
#include <kpmcore/core/device.h>
|
||||||
#include <kpmcore/ops/resizeoperation.h>
|
#include <kpmcore/ops/resizeoperation.h>
|
||||||
#include <kpmcore/util/report.h>
|
#include <kpmcore/util/report.h>
|
||||||
@ -66,23 +67,16 @@ ResizePartitionJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
ResizePartitionJob::exec()
|
ResizePartitionJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr );
|
|
||||||
// Restore partition sectors that were modified for preview
|
// Restore partition sectors that were modified for preview
|
||||||
m_partition->setFirstSector( m_oldFirstSector );
|
m_partition->setFirstSector( m_oldFirstSector );
|
||||||
m_partition->setLastSector( m_oldLastSector );
|
m_partition->setLastSector( m_oldLastSector );
|
||||||
|
|
||||||
ResizeOperation op( *m_device, *m_partition, m_newFirstSector, m_newLastSector );
|
ResizeOperation op( *m_device, *m_partition, m_newFirstSector, m_newLastSector );
|
||||||
op.setStatus( Operation::StatusRunning );
|
|
||||||
connect( &op, &Operation::progress, this, &ResizePartitionJob::iprogress );
|
connect( &op, &Operation::progress, this, &ResizePartitionJob::iprogress );
|
||||||
|
return KPMHelpers::execute( op,
|
||||||
QString errorMessage = tr( "The installer failed to resize partition %1 on disk '%2'." )
|
tr( "The installer failed to resize partition %1 on disk '%2'." )
|
||||||
.arg( m_partition->partitionPath() )
|
.arg( m_partition->partitionPath() )
|
||||||
.arg( m_device->name() );
|
.arg( m_device->name() ) );
|
||||||
if ( op.execute( report ) )
|
|
||||||
{
|
|
||||||
return Calamares::JobResult::ok();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Calamares::JobResult::error( errorMessage, report.toText() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
#include "ResizeVolumeGroupJob.h"
|
#include "ResizeVolumeGroupJob.h"
|
||||||
|
|
||||||
// KPMcore
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include <kpmcore/core/lvmdevice.h>
|
#include <kpmcore/core/lvmdevice.h>
|
||||||
#include <kpmcore/core/partition.h>
|
#include <kpmcore/core/partition.h>
|
||||||
#include <kpmcore/ops/resizevolumegroupoperation.h>
|
#include <kpmcore/ops/resizevolumegroupoperation.h>
|
||||||
@ -51,19 +52,9 @@ ResizeVolumeGroupJob::prettyStatusMessage() const
|
|||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
ResizeVolumeGroupJob::exec()
|
ResizeVolumeGroupJob::exec()
|
||||||
{
|
{
|
||||||
Report report( nullptr );
|
return KPMHelpers::execute(
|
||||||
|
ResizeVolumeGroupOperation( *m_device, m_partitionList ),
|
||||||
ResizeVolumeGroupOperation op( *m_device, m_partitionList );
|
tr( "The installer failed to resize a volume group named '%1'." ).arg( m_device->name() ) );
|
||||||
|
|
||||||
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() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
|
|
||||||
#include "SetPartitionFlagsJob.h"
|
#include "SetPartitionFlagsJob.h"
|
||||||
|
|
||||||
|
#include "core/KPMHelpers.h"
|
||||||
|
|
||||||
#include "partition/FileSystem.h"
|
#include "partition/FileSystem.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/Units.h"
|
#include "utils/Units.h"
|
||||||
@ -148,17 +150,8 @@ SetPartFlagsJob::exec()
|
|||||||
cDebug() << "Setting flags on" << m_device->deviceNode() << "partition" << partition()->deviceNode()
|
cDebug() << "Setting flags on" << m_device->deviceNode() << "partition" << partition()->deviceNode()
|
||||||
<< Logger::DebugList( flagsList );
|
<< Logger::DebugList( flagsList );
|
||||||
|
|
||||||
Report report( nullptr );
|
|
||||||
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
|
SetPartFlagsOperation op( *m_device, *partition(), m_flags );
|
||||||
op.setStatus( Operation::StatusRunning );
|
|
||||||
connect( &op, &Operation::progress, this, &SetPartFlagsJob::iprogress );
|
connect( &op, &Operation::progress, this, &SetPartFlagsJob::iprogress );
|
||||||
|
return KPMHelpers::execute(
|
||||||
QString errorMessage
|
op, tr( "The installer failed to set flags on partition %1." ).arg( m_partition->partitionPath() ) );
|
||||||
= 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() );
|
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ calamares_add_test(
|
|||||||
SOURCES
|
SOURCES
|
||||||
${PartitionModule_SOURCE_DIR}/jobs/AutoMountManagementJob.cpp
|
${PartitionModule_SOURCE_DIR}/jobs/AutoMountManagementJob.cpp
|
||||||
AutoMountTests.cpp
|
AutoMountTests.cpp
|
||||||
|
DEFINITIONS ${_partition_defs}
|
||||||
)
|
)
|
||||||
|
|
||||||
calamares_add_test(
|
calamares_add_test(
|
||||||
@ -70,4 +71,5 @@ calamares_add_test(
|
|||||||
${PartitionModule_SOURCE_DIR}/core/DeviceList.cpp
|
${PartitionModule_SOURCE_DIR}/core/DeviceList.cpp
|
||||||
LIBRARIES
|
LIBRARIES
|
||||||
kpmcore
|
kpmcore
|
||||||
|
DEFINITIONS ${_partition_defs}
|
||||||
)
|
)
|
||||||
|
@ -3,14 +3,20 @@
|
|||||||
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
# SPDX-FileCopyrightText: 2020 Adriaan de Groot <groot@kde.org>
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
#
|
#
|
||||||
include_directories( ${PROJECT_BINARY_DIR}/src/libcalamaresui )
|
|
||||||
|
|
||||||
calamares_add_plugin( preservefiles
|
calamares_add_plugin( preservefiles
|
||||||
TYPE job
|
TYPE job
|
||||||
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
EXPORT_MACRO PLUGINDLLEXPORT_PRO
|
||||||
SOURCES
|
SOURCES
|
||||||
|
Item.cpp
|
||||||
PreserveFiles.cpp
|
PreserveFiles.cpp
|
||||||
# REQUIRES mount # To set the rootMountPoint
|
# REQUIRES mount # To set the rootMountPoint
|
||||||
SHARED_LIB
|
SHARED_LIB
|
||||||
EMERGENCY
|
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 "PreserveFiles.h"
|
||||||
|
|
||||||
|
#include "Item.h"
|
||||||
|
|
||||||
#include "CalamaresVersion.h"
|
#include "CalamaresVersion.h"
|
||||||
#include "GlobalStorage.h"
|
#include "GlobalStorage.h"
|
||||||
#include "JobQueue.h"
|
#include "JobQueue.h"
|
||||||
#include "utils/CalamaresUtilsSystem.h"
|
#include "utils/CalamaresUtilsSystem.h"
|
||||||
#include "utils/CommandList.h"
|
#include "utils/CommandList.h"
|
||||||
#include "utils/Logger.h"
|
#include "utils/Logger.h"
|
||||||
#include "utils/Permissions.h"
|
|
||||||
#include "utils/Units.h"
|
#include "utils/Units.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|
||||||
using namespace CalamaresUtils::Units;
|
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
|
QString
|
||||||
atReplacements( QString s )
|
atReplacements( QString s )
|
||||||
{
|
{
|
||||||
@ -79,95 +53,34 @@ PreserveFiles::prettyName() const
|
|||||||
return tr( "Saving files for later ..." );
|
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
|
Calamares::JobResult
|
||||||
PreserveFiles::exec()
|
PreserveFiles::exec()
|
||||||
{
|
{
|
||||||
if ( m_items.isEmpty() )
|
if ( m_items.empty() )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error( tr( "No files configured to save for later." ) );
|
return Calamares::JobResult::error( tr( "No files configured to save for later." ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString prefix = targetPrefix();
|
|
||||||
if ( !prefix.endsWith( '/' ) )
|
|
||||||
{
|
|
||||||
prefix.append( '/' );
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for ( const auto& it : m_items )
|
for ( const auto& it : qAsConst( m_items ) )
|
||||||
{
|
{
|
||||||
QString source = it.source;
|
if ( !it )
|
||||||
QString bare_dest = atReplacements( it.dest );
|
|
||||||
QString dest = prefix + bare_dest;
|
|
||||||
|
|
||||||
if ( it.type == ItemType::Log )
|
|
||||||
{
|
{
|
||||||
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 ) )
|
++count;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return count == m_items.count()
|
return count == m_items.size()
|
||||||
? Calamares::JobResult::ok()
|
? Calamares::JobResult::ok()
|
||||||
: Calamares::JobResult::error( tr( "Not all of the configured files could be preserved." ) );
|
: 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" );
|
defaultPermissions = QStringLiteral( "root:root:0400" );
|
||||||
}
|
}
|
||||||
|
CalamaresUtils::Permissions perm( defaultPermissions );
|
||||||
|
|
||||||
QVariantList l = files.toList();
|
for ( const auto& li : files.toList() )
|
||||||
unsigned int c = 0;
|
|
||||||
for ( const auto& li : l )
|
|
||||||
{
|
{
|
||||||
if ( li.type() == QVariant::String )
|
m_items.push_back( Item::fromVariant( li, perm ) );
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,33 +10,14 @@
|
|||||||
|
|
||||||
#include "CppJob.h"
|
#include "CppJob.h"
|
||||||
#include "DllMacro.h"
|
#include "DllMacro.h"
|
||||||
#include "utils/Permissions.h"
|
|
||||||
#include "utils/PluginFactory.h"
|
#include "utils/PluginFactory.h"
|
||||||
|
|
||||||
#include <QList>
|
class Item;
|
||||||
#include <QObject>
|
|
||||||
#include <QVariantMap>
|
|
||||||
|
|
||||||
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
class PLUGINDLLEXPORT PreserveFiles : public Calamares::CppJob
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
enum class ItemType
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
Path,
|
|
||||||
Log,
|
|
||||||
Config
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Item
|
|
||||||
{
|
|
||||||
QString source;
|
|
||||||
QString dest;
|
|
||||||
CalamaresUtils::Permissions perm;
|
|
||||||
ItemType type;
|
|
||||||
};
|
|
||||||
|
|
||||||
using ItemList = QList< Item >;
|
using ItemList = QList< Item >;
|
||||||
|
|
||||||
public:
|
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:
|
# the list should have one of these forms:
|
||||||
#
|
#
|
||||||
# - an absolute path (probably within the host system). This will be preserved
|
# - an absolute path (probably within the host system). This will be preserved
|
||||||
# as the same path within the target system (chroot). If, globally, dontChroot
|
# as the same path within the target system (chroot). If, globally,
|
||||||
# is true, then these items are ignored (since the destination is the same
|
# *dontChroot* is true, then these items will be ignored (since the
|
||||||
# as the source).
|
# destination is the same as the source).
|
||||||
# - a map with a *dest* key. The *dest* value is a path interpreted in the
|
# - 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
|
# target system (if the global *dontChroot* is true, then the host is the
|
||||||
# are not recommended. There are three possible other keys in the map:
|
# 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
|
# - *from*, which must have one of the values, below; it is used to
|
||||||
# preserve files whose pathname is known to Calamares internally.
|
# preserve files whose pathname is known to Calamares internally.
|
||||||
# - *src*, to refer to a path interpreted in the host system. Relative
|
# - *src*, to refer to a path interpreted in the host system. Relative
|
||||||
# paths are not recommended, and are interpreted relative to where
|
# paths are not recommended, and are interpreted relative to where
|
||||||
# Calamares is being run.
|
# 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>
|
# - *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
|
# 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
|
# by owner). If set, the file's ownership and permissions are set to
|
||||||
# those values within the target system; if not set, no permissions
|
# those values within the target system; if not set, no permissions
|
||||||
# are changed.
|
# 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:
|
# The target path (*dest*) is modified as follows:
|
||||||
# - `@@ROOT@@` is replaced by the path to the target root (may be /)
|
# - `@@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
|
# - `@@USER@@` is replaced by the username entered by on the user
|
||||||
# page (may be empty, for instance if no user page is enabled)
|
# 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:
|
files:
|
||||||
- /etc/oem-information
|
|
||||||
- from: log
|
- from: log
|
||||||
dest: /root/install.log
|
dest: /var/log/Calamares.log
|
||||||
perm: root:wheel:644
|
perm: root:wheel:600
|
||||||
- from: config
|
- from: config
|
||||||
dest: /root/install.json
|
dest: /var/log/Calamares-install.json
|
||||||
perm: root:wheel:400
|
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
|
# 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,
|
# 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
|
@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
#include <KMacroExpander>
|
#include <KMacroExpander>
|
||||||
|
|
||||||
|
#include <QCoreApplication>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +39,6 @@ namespace
|
|||||||
*/
|
*/
|
||||||
class TrackingInstallJob : public Calamares::Job
|
class TrackingInstallJob : public Calamares::Job
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
TrackingInstallJob( const QString& url );
|
TrackingInstallJob( const QString& url );
|
||||||
~TrackingInstallJob() override;
|
~TrackingInstallJob() override;
|
||||||
@ -58,7 +59,6 @@ private:
|
|||||||
*/
|
*/
|
||||||
class TrackingMachineUpdateManagerJob : public Calamares::Job
|
class TrackingMachineUpdateManagerJob : public Calamares::Job
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
~TrackingMachineUpdateManagerJob() override;
|
~TrackingMachineUpdateManagerJob() override;
|
||||||
|
|
||||||
@ -75,7 +75,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
class TrackingKUserFeedbackJob : public Calamares::Job
|
class TrackingKUserFeedbackJob : public Calamares::Job
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
|
||||||
public:
|
public:
|
||||||
TrackingKUserFeedbackJob( const QString& username, const QStringList& areas );
|
TrackingKUserFeedbackJob( const QString& username, const QStringList& areas );
|
||||||
~TrackingKUserFeedbackJob() override;
|
~TrackingKUserFeedbackJob() override;
|
||||||
@ -99,13 +98,13 @@ TrackingInstallJob::~TrackingInstallJob() {}
|
|||||||
QString
|
QString
|
||||||
TrackingInstallJob::prettyName() const
|
TrackingInstallJob::prettyName() const
|
||||||
{
|
{
|
||||||
return tr( "Installation feedback" );
|
return QCoreApplication::translate( "TrackingInstallJob", "Installation feedback" );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TrackingInstallJob::prettyStatusMessage() const
|
TrackingInstallJob::prettyStatusMessage() const
|
||||||
{
|
{
|
||||||
return tr( "Sending installation feedback." );
|
return QCoreApplication::translate( "TrackingInstallJob", "Sending installation feedback." );
|
||||||
}
|
}
|
||||||
|
|
||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
@ -122,8 +121,9 @@ TrackingInstallJob::exec()
|
|||||||
if ( result.status == RequestStatus::Timeout )
|
if ( result.status == RequestStatus::Timeout )
|
||||||
{
|
{
|
||||||
cWarning() << "install-tracking request timed out.";
|
cWarning() << "install-tracking request timed out.";
|
||||||
return Calamares::JobResult::error( tr( "Internal error in install-tracking." ),
|
return Calamares::JobResult::error(
|
||||||
tr( "HTTP request timed out." ) );
|
QCoreApplication::translate( "TrackingInstallJob", "Internal error in install-tracking." ),
|
||||||
|
QCoreApplication::translate( "TrackingInstallJob", "HTTP request timed out." ) );
|
||||||
}
|
}
|
||||||
return Calamares::JobResult::ok();
|
return Calamares::JobResult::ok();
|
||||||
}
|
}
|
||||||
@ -133,13 +133,13 @@ TrackingMachineUpdateManagerJob::~TrackingMachineUpdateManagerJob() {}
|
|||||||
QString
|
QString
|
||||||
TrackingMachineUpdateManagerJob::prettyName() const
|
TrackingMachineUpdateManagerJob::prettyName() const
|
||||||
{
|
{
|
||||||
return tr( "Machine feedback" );
|
return QCoreApplication::translate( "TrackingMachineUpdateManagerJob", "Machine feedback" );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TrackingMachineUpdateManagerJob::prettyStatusMessage() const
|
TrackingMachineUpdateManagerJob::prettyStatusMessage() const
|
||||||
{
|
{
|
||||||
return tr( "Configuring machine feedback." );
|
return QCoreApplication::translate( "TrackingMachineUpdateManagerJob", "Configuring machine feedback." );
|
||||||
}
|
}
|
||||||
|
|
||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
@ -162,14 +162,20 @@ TrackingMachineUpdateManagerJob::exec()
|
|||||||
else if ( r > 0 )
|
else if ( r > 0 )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error(
|
return Calamares::JobResult::error(
|
||||||
tr( "Error in machine feedback configuration." ),
|
QCoreApplication::translate( "TrackingMachineUpdateManagerJob",
|
||||||
tr( "Could not configure machine feedback correctly, script error %1." ).arg( r ) );
|
"Error in machine feedback configuration." ),
|
||||||
|
QCoreApplication::translate( "TrackingMachineUpdateManagerJob",
|
||||||
|
"Could not configure machine feedback correctly, script error %1." )
|
||||||
|
.arg( r ) );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error(
|
return Calamares::JobResult::error(
|
||||||
tr( "Error in machine feedback configuration." ),
|
QCoreApplication::translate( "TrackingMachineUpdateManagerJob",
|
||||||
tr( "Could not configure machine feedback correctly, Calamares error %1." ).arg( r ) );
|
"Error in machine feedback configuration." ),
|
||||||
|
QCoreApplication::translate( "TrackingMachineUpdateManagerJob",
|
||||||
|
"Could not configure machine feedback correctly, Calamares error %1." )
|
||||||
|
.arg( r ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,13 +190,13 @@ TrackingKUserFeedbackJob::~TrackingKUserFeedbackJob() {}
|
|||||||
QString
|
QString
|
||||||
TrackingKUserFeedbackJob::prettyName() const
|
TrackingKUserFeedbackJob::prettyName() const
|
||||||
{
|
{
|
||||||
return tr( "KDE user feedback" );
|
return QCoreApplication::translate( "TrackingKUserFeedbackJob", "KDE user feedback" );
|
||||||
}
|
}
|
||||||
|
|
||||||
QString
|
QString
|
||||||
TrackingKUserFeedbackJob::prettyStatusMessage() const
|
TrackingKUserFeedbackJob::prettyStatusMessage() const
|
||||||
{
|
{
|
||||||
return tr( "Configuring KDE user feedback." );
|
return QCoreApplication::translate( "TrackingKUserFeedbackJob", "Configuring KDE user feedback." );
|
||||||
}
|
}
|
||||||
|
|
||||||
Calamares::JobResult
|
Calamares::JobResult
|
||||||
@ -212,21 +218,25 @@ FeedbackLevel=16
|
|||||||
if ( r > 0 )
|
if ( r > 0 )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error(
|
return Calamares::JobResult::error(
|
||||||
tr( "Error in KDE user feedback configuration." ),
|
QCoreApplication::translate( "TrackingKUserFeedbackJob", "Error in KDE user feedback configuration." ),
|
||||||
tr( "Could not configure KDE user feedback correctly, script error %1." ).arg( r ) );
|
QCoreApplication::translate( "TrackingKUserFeedbackJob",
|
||||||
|
"Could not configure KDE user feedback correctly, script error %1." )
|
||||||
|
.arg( r ) );
|
||||||
}
|
}
|
||||||
else if ( r < 0 )
|
else if ( r < 0 )
|
||||||
{
|
{
|
||||||
return Calamares::JobResult::error(
|
return Calamares::JobResult::error(
|
||||||
tr( "Error in KDE user feedback configuration." ),
|
QCoreApplication::translate( "TrackingKUserFeedbackJob", "Error in KDE user feedback configuration." ),
|
||||||
tr( "Could not configure KDE user feedback correctly, Calamares error %1." ).arg( r ) );
|
QCoreApplication::translate( "TrackingKUserFeedbackJob",
|
||||||
|
"Could not configure KDE user feedback correctly, Calamares error %1." )
|
||||||
|
.arg( r ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Calamares::JobResult::ok();
|
return Calamares::JobResult::ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void
|
void
|
||||||
addJob( Calamares::JobList& list, InstallTrackingConfig* config )
|
addJob( Calamares::JobList& list, InstallTrackingConfig* config )
|
||||||
@ -290,7 +300,3 @@ addJob( Calamares::JobList& list, UserTrackingConfig* config )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "utils/moc-warnings.h"
|
|
||||||
|
|
||||||
#include "TrackingJobs.moc"
|
|
||||||
|
@ -80,6 +80,7 @@ def run():
|
|||||||
if(libcalamares.job.configuration and
|
if(libcalamares.job.configuration and
|
||||||
"srcLog" in libcalamares.job.configuration and
|
"srcLog" in libcalamares.job.configuration and
|
||||||
"destLog" in libcalamares.job.configuration):
|
"destLog" in libcalamares.job.configuration):
|
||||||
|
libcalamares.utils.warning("Log-file preserving is **deprecated** in the *umount* module")
|
||||||
log_source = libcalamares.job.configuration["srcLog"]
|
log_source = libcalamares.job.configuration["srcLog"]
|
||||||
log_destination = libcalamares.job.configuration["destLog"]
|
log_destination = libcalamares.job.configuration["destLog"]
|
||||||
# Relocate log_destination into target system
|
# Relocate log_destination into target system
|
||||||
|
@ -10,16 +10,21 @@
|
|||||||
# The "copy log files" functionality is deprecated; use the *preservefiles*
|
# The "copy log files" functionality is deprecated; use the *preservefiles*
|
||||||
# module instead, which is more flexible.
|
# module instead, which is more flexible.
|
||||||
#
|
#
|
||||||
# This module has two configuration keys:
|
|
||||||
# srcLog location in the live system where the log is
|
|
||||||
# destLog location in the target system to copy the log
|
|
||||||
#
|
#
|
||||||
|
|
||||||
---
|
---
|
||||||
# example when using the normal Calamares log:
|
# This is a **deprecated** example. Use the *preservefiles* module
|
||||||
srcLog: "/root/.cache/calamares/session.log"
|
# instead, where the equivalent configuration is this:
|
||||||
destLog: "/var/log/Calamares.log"
|
#
|
||||||
|
# files:
|
||||||
|
# - from: log
|
||||||
|
# dest: /var/log/installation.log
|
||||||
|
#
|
||||||
|
# Note that the "equivalent configuration" always finds the log,
|
||||||
|
# and is not dependent on specific user names or the vagaries of
|
||||||
|
# polkit configuration -- so it is a **better** "equivalent".
|
||||||
|
#
|
||||||
# example when using a log created by `sudo calamares -d`:
|
# example when using a log created by `sudo calamares -d`:
|
||||||
#srcLog: "/home/live/installation.log"
|
#srcLog: "/home/live/installation.log"
|
||||||
#destLog: "/var/log/installation.log"
|
#destLog: "/var/log/installation.log"
|
||||||
|
srcLog: "/bogus/just/do/not/use/this/anymore.txt"
|
||||||
|
Loading…
Reference in New Issue
Block a user